Skip to content

Commit 16a2df0

Browse files
authored
fix Issue 22263 - ImportC: function and variable re-declarations should be allowed (#13085)
1 parent 3dd351f commit 16a2df0

File tree

4 files changed

+138
-4
lines changed

4 files changed

+138
-4
lines changed

src/dmd/cparse.d

+3-1
Original file line numberDiff line numberDiff line change
@@ -4166,8 +4166,10 @@ final class CParser(AST) : Parser!AST
41664166
{
41674167
if (specifier.scw & SCW.xextern)
41684168
stc = AST.STC.extern_ | AST.STC.gshared;
4169+
else if (specifier.scw & SCW.xstatic)
4170+
stc = AST.STC.gshared | AST.STC.static_;
41694171
else
4170-
stc = AST.STC.gshared;
4172+
stc = AST.STC.gshared;
41714173
}
41724174
else if (level == LVL.local)
41734175
{

src/dmd/dsymbol.d

+88-2
Original file line numberDiff line numberDiff line change
@@ -795,10 +795,18 @@ extern (C++) class Dsymbol : ASTNode
795795
Dsymbol s2 = sds.symtabLookup(this,ident);
796796

797797
// 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))
800803
return;
801804

805+
sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading
806+
errors = true;
807+
return;
808+
}
809+
802810
if (!s2.overloadInsert(this))
803811
{
804812
sds.multiplyDefined(Loc.initial, this, s2);
@@ -2386,3 +2394,81 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
23862394
}
23872395

23882396

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+
}

src/dmd/semantic2.d

+1-1
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
363363
assert(fd.semanticRun <= PASS.semantic2);
364364
fd.semanticRun = PASS.semantic2;
365365

366-
//printf("FuncDeclaration::semantic2 [%s] fd0 = %s %s\n", loc.toChars(), toChars(), type.toChars());
366+
//printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr);
367367

368368
// Only check valid functions which have a body to avoid errors
369369
// for multiple declarations, e.g.

test/fail_compilation/fix22263.c

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* TEST_OUTPUT:
2+
---
3+
fail_compilation/fix22263.c(108): Error: function `fix22263.f3` conflicts with function `fix22263.f3` at fail_compilation/fix22263.c(107)
4+
fail_compilation/fix22263.c(127): Error: variable `fix22263.x4` conflicts with variable `fix22263.x4` at fail_compilation/fix22263.c(126)
5+
fail_compilation/fix22263.c(133): Error: variable `fix22263.x6` conflicts with variable `fix22263.x6` at fail_compilation/fix22263.c(132)
6+
---
7+
*/
8+
9+
// https://issues.dlang.org/show_bug.cgi?id=22263
10+
11+
#line 100
12+
13+
extern void f1(int);
14+
void f1(int a) { }
15+
16+
static void f2(int);
17+
static void f2(int a) { }
18+
19+
static void f3(int) { }
20+
static void f3(int a) { }
21+
22+
void foo()
23+
{
24+
f1(42);
25+
f2(42);
26+
f3(42);
27+
}
28+
29+
extern const int x1;
30+
const int x1 = 1;
31+
32+
int x2 = 2;
33+
extern int x2;
34+
35+
static int x3;
36+
static int x3 = 3;
37+
38+
static int x4;
39+
int x4;
40+
41+
int x5;
42+
int x5;
43+
44+
int x6 = 6;
45+
int x6 = 6;
46+

0 commit comments

Comments
 (0)