Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix bugzilla Issue 24397 ImportC: support function-like macros #16199

Merged
merged 1 commit into from
Feb 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
150 changes: 125 additions & 25 deletions compiler/src/dmd/cparse.d
Original file line number Diff line number Diff line change
Expand Up @@ -1682,9 +1682,12 @@
AST.ParameterList parameterList;
StorageClass stc = 0;
const loc = token.loc;
auto symbolsSave = symbols;
symbols = new AST.Dsymbols();
typedefTab.push(null);
auto fbody = cparseStatement(ParseStatementFlags.scope_);
typedefTab.pop(); // end of function scope
symbols = symbolsSave;

// Rewrite last ExpStatement (if there is one) as a ReturnStatement
auto ss = fbody.isScopeStatement();
Expand All @@ -1693,8 +1696,11 @@
if (const len = (*cs.statements).length)
{
auto s = (*cs.statements)[len - 1];
if (auto es = s.isExpStatement())
(*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp);
if (s) // error recovery should be with ErrorStatement, not null
{
if (auto es = s.isExpStatement())
(*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp);
}
}

auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
Expand Down Expand Up @@ -5520,7 +5526,7 @@
defines.writeByte('#');
defines.writestring(n.ident.toString());
skipToNextLine(defines);
defines.writeByte('\n');
defines.writeByte(0); // each #define line is 0 terminated
return true;
}
else if (n.ident == Id.__pragma)
Expand Down Expand Up @@ -5840,7 +5846,8 @@
const length = buf.length;
buf.writeByte(0);
auto slice = buf.peekChars()[0 .. length];
resetDefineLines(slice); // reset lexer
auto scanlocSave = scanloc;
resetDefineLines(slice); // reset lexer
auto save = eSink;
auto eLatch = new ErrorSinkLatch();
eSink = eLatch;
Expand All @@ -5865,12 +5872,14 @@
(*symbols)[*pd] = s;
return;
}
assert(symbols, "symbols is null");
defineTab[cast(void*)s.ident] = symbols.length;
symbols.push(s);
}

while (p < endp)
{
//printf("|%s|\n", p);
if (p[0 .. 7] == "#define")
{
p += 7;
Expand All @@ -5884,10 +5893,11 @@

AST.Type t;

Lswitch:
switch (token.value)
{
case TOK.endOfLine: // #define identifier
nextDefineLine();
case TOK.endOfFile: // #define identifier
++p;
continue;

case TOK.int32Literal:
Expand All @@ -5901,15 +5911,15 @@
Linteger:
const intvalue = token.intvalue;
nextToken();
if (token.value == TOK.endOfLine)
if (token.value == TOK.endOfFile)
{
/* Declare manifest constant:
* enum id = intvalue;
*/
AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
nextDefineLine();
++p;
continue;
}
break;
Expand All @@ -5924,15 +5934,15 @@
Lfloat:
const floatvalue = token.floatvalue;
nextToken();
if (token.value == TOK.endOfLine)
if (token.value == TOK.endOfFile)
{
/* Declare manifest constant:
* enum id = floatvalue;
*/
AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
nextDefineLine();
++p;
continue;
}
break;
Expand All @@ -5942,27 +5952,28 @@
const len = token.len;
const postfix = token.postfix;
nextToken();
if (token.value == TOK.endOfLine)
if (token.value == TOK.endOfFile)
{
/* Declare manifest constant:
* enum id = "string";
*/
AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
addVar(v);
nextDefineLine();
++p;
continue;
}
break;

case TOK.leftParenthesis:
{
/* Look for:
* #define ID ( expression )
* and rewrite it to a template function:
* auto ID()() { return expression; }
*/
if (params)
break; // no parameters
goto caseFunctionLike; // version with parameters
nextToken();
eLatch.sawErrors = false;
auto exp = cparseExpression();
Expand All @@ -5971,7 +5982,7 @@
if (token.value != TOK.rightParenthesis)
break;
nextToken();
if (token.value != TOK.endOfLine)
if (token.value != TOK.endOfFile)
break;
auto ret = new AST.ReturnStatement(exp.loc, exp);
auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0);
Expand All @@ -5985,26 +5996,115 @@
AST.Expression constraint = null;
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
addVar(tempdecl);
nextDefineLine();
++p;
continue;
}

caseFunctionLike:
{
/* Parse `( a, b ) expression`
* Create template function:
* auto id(__MP1, __MP2)(__MP1 a, __MP1 b) { return expression; }
*/
//printf("functionlike %s\n", id.toChars());

// Capture the parameter list
VarArg varargs = VarArg.none;
auto parameters = new AST.Parameters();
nextToken(); // skip past `(`
Lwhile:
while (1)
{
if (token.value == TOK.rightParenthesis)
break;
if (token.value == TOK.dotDotDot)
{
static if (0) // variadic macros not supported yet
{
varargs = AST.VarArg.variadic; // C-style variadics
nextToken();
if (token.value == TOK.rightParenthesis)
break Lwhile;
}
break Lswitch;
}

if (token.value != TOK.identifier)
break Lswitch;
auto param = new AST.Parameter(token.loc, 0, null, token.ident, null, null);
parameters.push(param);
nextToken();
if (token.value == TOK.comma)
{
nextToken();
continue;
}
break;
}
if (token.value != TOK.rightParenthesis)
break;

Check warning on line 6045 in compiler/src/dmd/cparse.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/cparse.d#L6045

Added line #L6045 was not covered by tests

//auto pstart = p;
nextToken();
auto parameterList = AST.ParameterList(parameters, varargs, 0);
/* Create a type for each parameter. Add it to the template parameter list,
* and the parameter list.
*/
auto tpl = new AST.TemplateParameters();
foreach (param; (*parameters)[])
{
auto idtype = Identifier.generateId("__MP");
auto loc = param.loc;
auto tp = new AST.TemplateTypeParameter(loc, idtype, null, null);
tpl.push(tp);

auto at = new AST.TypeIdentifier(loc, idtype);
param.type = at;
}

eLatch.sawErrors = false;
auto exp = cparseExpression();
ibuclaw marked this conversation as resolved.
Show resolved Hide resolved

//printf("exp: %s tok: %s\n", exp.toChars(), Token.toChars(token.value));
//printf("parsed: '%.*s'\n", cast(int)(p - pstart), pstart);
assert(symbols);

if (eLatch.sawErrors) // parsing errors
break; // abandon this #define

if (token.value != TOK.endOfFile) // did not consume the entire line
break;

// Generate function
auto ret = new AST.ReturnStatement(exp.loc, exp);
StorageClass stc = STC.auto_;
auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0);
fd.fbody = ret;

// Wrap it in an eponymous template
AST.Dsymbols* decldefs = new AST.Dsymbols();
decldefs.push(fd);
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false);
addVar(tempdecl);

++p;
continue;
}

default:
break;
}
}
skipToNextLine();
}
else
{
scan(&token);
if (token.value != TOK.endOfLine)
{
skipToNextLine();
}
}
nextDefineLine();
// scan to end of line
while (*p)
++p;
++p; // advance to start of next line
scanloc.linnum = scanloc.linnum + 1;
}

scanloc = scanlocSave;
eSink = save;
defines = buf;
}
Expand Down
12 changes: 9 additions & 3 deletions compiler/src/dmd/link.d
Original file line number Diff line number Diff line change
Expand Up @@ -1255,9 +1255,16 @@
break;

case S.hash:
defines.writeByte(c);
if (c == '\n')
if (c == '\r')

Check warning on line 1258 in compiler/src/dmd/link.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/link.d#L1258

Added line #L1258 was not covered by tests
{
}
else if (c == '\n')
{
defines.writeByte(0); // 0-terminate lines in defines[]

Check warning on line 1263 in compiler/src/dmd/link.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/link.d#L1262-L1263

Added lines #L1262 - L1263 were not covered by tests
state = S.start;
}

Check warning on line 1265 in compiler/src/dmd/link.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/link.d#L1265

Added line #L1265 was not covered by tests
else
defines.writeByte(c);

Check warning on line 1267 in compiler/src/dmd/link.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/link.d#L1267

Added line #L1267 was not covered by tests
break;

case S.other:
Expand All @@ -1267,7 +1274,6 @@
break;
}
}
//printf("%.*s", cast(int)data.length, data.ptr);
}

// Convert command to wchar
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/toir.d
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ extern (D) elem *incUsageElem(ref IRState irs, const ref Loc loc)
uint linnum = loc.linnum;

Module m = cast(Module)irs.blx._module;
//printf("m.cov %p linnum %d filename %s srcfile %s\n", m.cov, linnum, loc.filename, m.srcfile.toChars());
//printf("m.cov %p linnum %d filename %s srcfile %s numlines %d\n", m.cov, linnum, loc.filename, m.srcfile.toChars(), m.numlines);
if (!m.cov || !linnum ||
strcmp(loc.filename, m.srcfile.toChars()))
return null;
Expand Down
25 changes: 25 additions & 0 deletions compiler/test/compilable/imports/defines.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,28 @@ _Static_assert(SSS[0] == 'h', "10");
#define ABC 12
#define GHI (size) abbadabba
#define DEF (ABC + 5)

#define ADD(a, b) a + b
#define SUB() 3 - 2
WalterBright marked this conversation as resolved.
Show resolved Hide resolved

#define NO_BODY()
#define NO_BODY_PARAMS(a, b)
#define DO_WHILE() do { } while(0)

#define pr16199_trigger(cond,func,args) _Generic (cond, default: func args)
#define pr16199_skipped1(a) (1)
#define pr16199_skipped2(b) (2)
#define pr16199_ice 0x3

#define M16199Ea(TYPE) (TYPE __x;)
#define M16199E(X,S,M) ({ M16199Ea(S *); })

#define M16199Da(TYPE,VAR) ((TYPE)(VAR))
#define M16199D(X,S,M) ({ int *__x = (X); M16199Da(S *, __x); })
int pr16199d() { return 7; }

#define M16199C(X,S,M) ({ int __x; })
int pr16199c()
{
return 8;
}
10 changes: 10 additions & 0 deletions compiler/test/compilable/testdefines.d
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,13 @@ static assert(SSS == "hello");

static assert(ABC == 12);
static assert(DEF == 17);

static assert(ADD(3, 4) == 7);
static assert(SUB() == 1);

static assert(pr16199_skipped1(5) == 1);
static assert(pr16199_skipped2(6) == 2);
static assert(pr16199_ice == 3);

static assert(pr16199d() == 7);
static assert(pr16199c() == 8);