Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 106 additions & 1 deletion compiler/src/dmd/cparse.d
Original file line number Diff line number Diff line change
Expand Up @@ -5548,6 +5548,9 @@ final class CParser(AST) : Parser!AST
v.isCmacro = true; // mark it as coming from a C #define
if (auto td = s.isTemplateDeclaration())
td.isCmacro = true; // mark as coming from a C #define
if (auto ad = s.isAliasDeclaration())
ad.isCmacro = true; // ditto for vars and templates

/* If it's already defined, replace the earlier
* definition
*/
Expand Down Expand Up @@ -5702,6 +5705,65 @@ final class CParser(AST) : Parser!AST
}
break;

case TOK.identifier:
{
/* check for compiler builtins macros/ or specifier references.
* this is a workaround to avoid trying to resolve macros that
* reference other identifiers or functions
* so D users should avoid using custom macros beginning with __
* to reference identifers
*/
auto ident = token.ident;
Specifier sp;
sp.packalign = this.packalign;
auto tspec = cparseDeclarationSpecifiers(LVL.global, sp);
const idx = id.toString();
auto identx = ident.toString();

if (!tspec.isTypeIdentifier() || isCBuiltin(identx) || isCBuiltin(idx) ||
isCmacrosame(identx, idx) || (identx.length > 2 && identx[0] == '_' && identx[1] == '_')
|| (idx.length > 2 && idx[0] == '_' && idx[1] == '_'))
{
++p;
continue;
}

/*
* macros can also refer to functions
* #define test func(2,3)
* where func has its definition elsewhere
* don't treat them as manifest constants because functions can be eval at runtime
* eg. zlibversion() in zlib where its macro is resolved at runtime
*/
if (token.value == TOK.leftParenthesis)
{
auto call = new AST.CallExp(loc, new AST.IdentifierExp(loc, ident), cparseArguments()); // right paren checked here
auto decl = new AST.VarDeclaration(loc, null, id, new AST.ExpInitializer(loc, call), STC.extern_ | STC.static_);
addSym(decl);

++p;
continue;
}

nextToken();

if (token.value != TOK.endOfFile)
{
++p;
continue;
}

/*
* #define identifier value where value can be an identifier.
* The identifier can be anything, so treat it as an AliasDeclaration.
* Mark it as coming from a C file to skip semantic resolution later.
*/
auto als = new AST.AliasDeclaration(scanloc, id, tspec);
addSym(als);
++p;
continue;
}

case TOK.leftParenthesis:
{
/* Look for:
Expand Down Expand Up @@ -5828,7 +5890,6 @@ final class CParser(AST) : Parser!AST
++p;
continue;
}

default:
break;
}
Expand Down Expand Up @@ -5862,3 +5923,47 @@ final class CParser(AST) : Parser!AST

//}
}

/*
* for few compiler intrinsics the compiler cannot resolve
* that we have no knowledge of in D,
* set them rawly and don't allow them for now
* long term, any user of a C header that is being bocked by an intrinsic,
* append to this table
*/
immutable string[] builtins = [
"_Pre_",
"_Maybevalid_impl_",
"_Pre_z_",
"_Notref_impl_",
"_Post_",
"X",
"_Use_decl_anno_impl_",
"vector_size",
"INTMAX_C",
"UINTMAX_C",
"_SAL_L_Source_",
"_SAL1_1_Source_",
"_SAL2_Source_",
"_Pre_equal_to_",
"_CRT_DEPRECATE_TEXT",
"throw",
"complex" // stay away from the C99 _complex keyword that share diffs on windows/POSIX
];

bool isCBuiltin(const(char)[] name)
{
foreach (b; builtins)
{
if (b == name)
return true;
}
return false;
}

bool isCmacrosame(const(char)[] idx, const(char)[] ident)
{
if (idx == ident)
return true;
return false;
}
1 change: 1 addition & 0 deletions compiler/src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ extern (C++) final class AliasDeclaration : Declaration

Dsymbol overnext; // next in overload list
Dsymbol _import; // !=null if unresolved internal alias for selective import
bool isCmacro; // check whether it is coming from a C macro

extern (D) this(Loc loc, Identifier ident, Type type) @safe
{
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ class AliasDeclaration final : public Declaration
Dsymbol *aliassym;
Dsymbol *overnext; // next in overload list
Dsymbol *_import; // !=NULL if unresolved internal alias for selective import
bool isCmacro;

static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
AliasDeclaration *syntaxCopy(Dsymbol *) override;
Expand Down
28 changes: 22 additions & 6 deletions compiler/src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1182,7 +1182,7 @@ Dsymbol toAlias2(Dsymbol s)
{
if (auto ad = s.isAliasDeclaration())
{
if (ad.inuse)
if (ad.inuse && !ad.isCmacro) // c amcro can refer to itself and compile
{
.error(ad.loc, "%s `%s` recursive alias declaration", ad.kind, ad.toPrettyChars);
return ad;
Expand Down Expand Up @@ -1257,7 +1257,7 @@ private Dsymbol toAliasImpl(AliasDeclaration ad)
ad.inuse = 0;
}
}
if (ad.inuse)
if (ad.inuse && !ad.isCmacro) // C macros can refer to itself and compile
{
.error(ad.loc, "%s `%s` recursive alias declaration", ad.kind, ad.toPrettyChars);
return err();
Expand Down Expand Up @@ -5820,8 +5820,9 @@ private extern(C++) class AddMemberVisitor : Visitor
}

// If using C tag/prototype/forward declaration rules
// remember, C allows rdececlarations of macros too
//(!sc.inCfie && dsym.isAliasDeclaration().isCmacro && s2.isAliasDeclaration().isCmacro)))
if (sc && sc.inCfile && !dsym.isImport())
// When merging master, replace with: if (sc && sc.inCfile && !dsym.isImport())
{
if (handleTagSymbols(*sc, dsym, s2, sds))
return;
Expand Down Expand Up @@ -6323,15 +6324,30 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
// Detect `alias sym = sym;` to prevent creating loops in overload overnext lists.
if (auto tident = ds.type.isTypeIdentifier())
{
if (sc.hasEdition(Edition.v2024) && tident.idents.length)
if ((sc.hasEdition(Edition.v2024) && tident.idents.length) || ds.isCmacro)
{
alias mt = tident;
Dsymbol pscopesym;
Dsymbol s = sc.search(ds.loc, mt.ident, pscopesym);
/* if the imported macro from C doesn't exist,
* probably a builtin one we don't define
* stop processing it. C macro refering identifiers
* can point to absolutely anything either defined or not
* #ifdefine hsgshsh hsshhshs is a valid C compile but emit on usage
* then we implement the ones we need
*/
if (!s && sc.inCfile && ds.isCmacro)
{
ds.aliassym = null;
ds.errors = false; // no error flag
ds.semanticRun = PASS.semanticdone; // mark semantic as complete
ds.inuse = 0; // clear recursion flag
return;
}
// detect `alias a = var1.member_var;` which confusingly resolves to
// `typeof(var1).member_var`, which can be valid inside the aggregate type
if (s && s.isVarDeclaration() &&
mt.ident != Id.This && mt.ident != Id._super)
mt.ident != Id.This && mt.ident != Id._super && (!ds.isCmacro && !sc.inCfile)) // don't let a C macro alias pass here
{
s = tident.toDsymbol(sc);
// don't error for `var1.static_symbol`
Expand All @@ -6345,7 +6361,7 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
}
}
// Selective imports are allowed to alias to the same name `import mod : sym=sym`.
if (!ds._import)
if (!ds._import && (!ds.isCmacro && !sc.inCfile)) // C identifier macros are not allowed here
{
if (tident.ident is ds.ident && !tident.idents.length)
{
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -6719,6 +6719,7 @@ class AliasDeclaration final : public Declaration
Dsymbol* aliassym;
Dsymbol* overnext;
Dsymbol* _import_;
bool isCmacro;
static AliasDeclaration* create(Loc loc, Identifier* id, Type* type);
AliasDeclaration* syntaxCopy(Dsymbol* s) override;
const char* kind() const override;
Expand Down
6 changes: 6 additions & 0 deletions compiler/src/dmd/importc.d
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,12 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
if (td.isCmacro) return s2;
}

if (auto ad = s.isAliasDeclaration())
{
if (ad.isCmacro)
return s2;
}

auto vd = s.isVarDeclaration(); // new declaration
auto vd2 = s2.isVarDeclaration(); // existing declaration

Expand Down
23 changes: 23 additions & 0 deletions compiler/test/runnable/fix20410.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
REQUIRED_ARGS: runnable/imports/imp20410.c
*/
//https://github.com/dlang/dmd/issues/20410
import imp20410;

void main()
{
const _ = _RAX;

assert(num == 5);
assert(func() == 9);

//https://github.com/dlang/dmd/issues/20478

static assert(A == B);
static assert(A == C);
static assert(A == D);

//https://github.com/dlang/dmd/issues/20194
assert(test == 9);
assert(ABOLD == 7);
}
31 changes: 31 additions & 0 deletions compiler/test/runnable/imports/imp20410.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// https://issues.dlang.org/show_bug.cgi?id=24419

typedef enum {
#define R0 _RAX
_RAX,
} reg;


int number = 5;
#define num number;


int function()
{
return 9;
}
#define func function

//https://github.com/dlang/dmd/issues/20478
// similar issue

#define A 1
#define B A
#define C (A)
#define D (B)

//https://github.com/dlang/dmd/issues/20194

#define test_func(x, y) (x + y)
#define ABOLD test_func(2,5)
#define test test_func(5,4)
Loading