Skip to content

Commit

Permalink
fix bugzilla Issue 24397 ImportC: support function-like macros
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Feb 18, 2024
1 parent e9cacc3 commit 7f66ec3
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 24 deletions.
141 changes: 118 additions & 23 deletions compiler/src/dmd/cparse.d
Original file line number Diff line number Diff line change
Expand Up @@ -5520,7 +5520,7 @@ final class CParser(AST) : Parser!AST
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 @@ -5834,13 +5834,16 @@ final class CParser(AST) : Parser!AST
{
if (!defines || defines.length < 10) // minimum length of a #define line
return;
if (!symbols)
symbols = new AST.Dsymbols();

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

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/cparse.d#L5838

Added line #L5838 was not covered by tests
OutBuffer* buf = defines;
defines = null; // prevent skipToNextLine() and parseSpecialTokenSequence()
// from appending to slice[]
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,6 +5868,7 @@ final class CParser(AST) : Parser!AST
(*symbols)[*pd] = s;
return;
}
assert(symbols, "symbols is null");
defineTab[cast(void*)s.ident] = symbols.length;
symbols.push(s);
}
Expand All @@ -5884,10 +5888,11 @@ final class CParser(AST) : Parser!AST

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 +5906,15 @@ final class CParser(AST) : Parser!AST
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 +5929,15 @@ final class CParser(AST) : Parser!AST
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 +5947,28 @@ final class CParser(AST) : Parser!AST
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 +5977,7 @@ final class CParser(AST) : Parser!AST
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 +5991,115 @@ final class CParser(AST) : Parser!AST
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 6040 in compiler/src/dmd/cparse.d

View check run for this annotation

Codecov / codecov/patch

compiler/src/dmd/cparse.d#L6040

Added line #L6040 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();

//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
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
12 changes: 12 additions & 0 deletions compiler/test/compilable/imports/defines.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,15 @@ _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

#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
7 changes: 7 additions & 0 deletions compiler/test/compilable/testdefines.d
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,10 @@ 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);

0 comments on commit 7f66ec3

Please sign in to comment.