@@ -795,10 +795,18 @@ extern (C++) class Dsymbol : ASTNode
795
795
Dsymbol s2 = sds.symtabLookup(this ,ident);
796
796
797
797
// If using C tag/prototype/forward declaration rules
798
- if (sc.flags & SCOPE .Cfile &&
799
- handleTagSymbols(* sc, this , s2, sds))
798
+ if (sc.flags & SCOPE .Cfile)
799
+ {
800
+ if (handleTagSymbols(* sc, this , s2, sds))
801
+ return ;
802
+ if (handleSymbolRedeclarations(* sc, this , s2, sds))
800
803
return ;
801
804
805
+ sds.multiplyDefined(Loc.initial, this , s2); // ImportC doesn't allow overloading
806
+ errors = true ;
807
+ return ;
808
+ }
809
+
802
810
if (! s2.overloadInsert(this ))
803
811
{
804
812
sds.multiplyDefined(Loc.initial, this , s2);
@@ -2386,3 +2394,81 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2386
2394
}
2387
2395
2388
2396
2397
+ /* *********************************************
2398
+ * ImportC allows redeclarations of variables and functions.
2399
+ * extern int x;
2400
+ * int x = 3;
2401
+ * and:
2402
+ * extern void f();
2403
+ * void f() { }
2404
+ * Attempt to merge them.
2405
+ * Params:
2406
+ * sc = context
2407
+ * s = symbol to add to symbol table
2408
+ * s2 = existing declaration
2409
+ * sds = symbol table
2410
+ * Returns:
2411
+ * if s and s2 are successfully put in symbol table then return the merged symbol,
2412
+ * null if they conflict
2413
+ */
2414
+ Dsymbol handleSymbolRedeclarations (ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
2415
+ {
2416
+ enum log = false ;
2417
+ if (log) printf(" handleSymbolRedeclarations('%s')\n " , s.toChars());
2418
+
2419
+ static Dsymbol collision ()
2420
+ {
2421
+ if (log) printf(" collision\n " );
2422
+ return null ;
2423
+ }
2424
+
2425
+ auto vd = s.isVarDeclaration(); // new declaration
2426
+ auto vd2 = s2.isVarDeclaration(); // existing declaration
2427
+ if (vd && vd2)
2428
+ {
2429
+ // if one is `static` and the other isn't
2430
+ if ((vd.storage_class ^ vd2.storage_class) & STC .static_)
2431
+ return collision ();
2432
+
2433
+ const i1 = vd._init && ! vd._init.isVoidInitializer();
2434
+ const i2 = vd2._init && ! vd2._init.isVoidInitializer();
2435
+
2436
+ if (i1 && i2)
2437
+ return collision (); // can't both have initializers
2438
+
2439
+ if (i1)
2440
+ return vd;
2441
+
2442
+ /* BUG: the types should match, which needs semantic() to be run on it
2443
+ * extern int x;
2444
+ * int x; // match
2445
+ * typedef int INT;
2446
+ * INT x; // match
2447
+ * long x; // collision
2448
+ * We incorrectly ignore these collisions
2449
+ */
2450
+ return vd2;
2451
+ }
2452
+
2453
+ auto fd = s.isFuncDeclaration(); // new declaration
2454
+ auto fd2 = s2.isFuncDeclaration(); // existing declaration
2455
+ if (fd && fd2)
2456
+ {
2457
+ // if one is `static` and the other isn't
2458
+ if ((fd.storage_class ^ fd2.storage_class) & STC .static_)
2459
+ return collision ();
2460
+
2461
+ if (fd.fbody && fd2.fbody)
2462
+ return collision (); // can't both have bodies
2463
+
2464
+ if (fd.fbody)
2465
+ return fd;
2466
+
2467
+ /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
2468
+ * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
2469
+ */
2470
+ return fd2;
2471
+ }
2472
+
2473
+ return collision ();
2474
+ }
0 commit comments