Skip to content

Commit

Permalink
Merge pull request #3839 from kinke/stable
Browse files Browse the repository at this point in the history
Merge upstream stable
  • Loading branch information
kinke authored Sep 25, 2021
2 parents 8bb19a3 + f4ea32e commit 98bbfd8
Show file tree
Hide file tree
Showing 15 changed files with 306 additions and 29 deletions.
13 changes: 13 additions & 0 deletions dmd/clone.d
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,19 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
if (!needToHash(sd))
return null;

/* The trouble is that the following code relies on .tupleof, but .tupleof
* is not allowed for C files. If we allow it for C files, then that turns on
* the other D properties, too, such as .dup which will then conflict with allowed
* field names.
* One way to fix it is to replace the following foreach and .tupleof with C
* statements and expressions.
* But, it's debatable whether C structs should even need toHash().
* Note that it would only be necessary if it has floating point fields.
* For now, we'll just not generate a toHash() for C files.
*/
if (sc.flags & SCOPE.Cfile)
return null;

//printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars());
Loc declLoc; // loc is unnecessary so __xtoHash is never called directly
Loc loc; // internal code should have no loc to prevent coverage
Expand Down
54 changes: 41 additions & 13 deletions dmd/cparse.d
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,7 @@ final class CParser(AST) : Parser!AST
nextToken();
auto t = cparseTypeName();
check(TOK.rightParenthesis);
pt = &token;

if (token.value == TOK.leftCurly)
{
Expand All @@ -969,6 +970,17 @@ final class CParser(AST) : Parser!AST
auto ce = new AST.CompoundLiteralExp(loc, t, ci);
return cparsePostfixOperators(ce);
}
else if (t.isTypeIdentifier() &&
token.value == TOK.leftParenthesis &&
!isCastExpression(pt))
{
/* this might actually be a function
* call that looks like `(a)(b)` or even `(a)(b,c)`
*/
auto ie = new AST.IdentifierExp(loc, t.isTypeIdentifier().ident);
ie.parens = true; // disambiguate it from being a declaration
return new AST.CallExp(loc, ie, cparseArguments());
}
else
{
// ( type-name ) cast-expression
Expand Down Expand Up @@ -1471,7 +1483,8 @@ final class CParser(AST) : Parser!AST
{
nextToken();
auto tt = tspec.isTypeTag();
if (!tt || !tt.id)
if (!tt ||
!tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_))
return; // legal but meaningless empty declaration, ignore it

/* `struct tag;` and `struct tag { ... };`
Expand Down Expand Up @@ -1505,7 +1518,7 @@ final class CParser(AST) : Parser!AST
{
Identifier id;
AST.Expression asmname;
auto dt = cparseDeclarator(DTR.xdirect, tspec, id);
auto dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
if (!dt)
{
panic();
Expand Down Expand Up @@ -2258,14 +2271,14 @@ final class CParser(AST) : Parser!AST
* declarator = declarator kind
* t = base type to start with
* pident = set to Identifier if there is one, null if not
* storageClass = any storage classes seen so far that apply to a function
* specifier = specifiers in and out
* Returns:
* type declared. If a TypeFunction is returned, this.symbols is the
* symbol table for the parameter-type-list, which will contain any
* declared struct, union or enum tags.
*/
private AST.Type cparseDeclarator(DTR declarator, AST.Type t,
out Identifier pident, StorageClass storageClass = 0)
out Identifier pident, ref Specifier specifier)
{
//printf("cparseDeclarator(%d)\n", declarator);
AST.Types constTypes; // all the Types that will need `const` applied to them
Expand Down Expand Up @@ -2303,6 +2316,8 @@ final class CParser(AST) : Parser!AST
const mod = cparseTypeQualifierList();
if (mod & MOD.xconst)
constTypes.push(t);
if (token.value == TOK.__attribute__)
cparseGnuAttributes(specifier);
continue;

default:
Expand Down Expand Up @@ -2370,8 +2385,9 @@ final class CParser(AST) : Parser!AST
}
else
{
// An array of unknown size, fake it with a DArray
ta = new AST.TypeDArray(t); // []
/* C11 6.7.6.2-4 An [ ] array is an incomplete array type
*/
ta = new AST.TypeSArray(t);
}
check(TOK.rightBracket);

Expand Down Expand Up @@ -2406,7 +2422,7 @@ final class CParser(AST) : Parser!AST
/* C11 6.7.6.2-1: the element type shall not be an incomplete or
* function type.
*/
if (ta.isTypeDArray() && !isVLA)
if (ta.isTypeSArray() && ta.isTypeSArray().isIncomplete() && !isVLA)
error("array type has incomplete element type `%s`", ta.toChars());
}

Expand Down Expand Up @@ -2509,7 +2525,7 @@ final class CParser(AST) : Parser!AST
Specifier specifier;
auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
Identifier id;
return cparseDeclarator(DTR.xabstract, tspec, id);
return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
}

/***********************************
Expand Down Expand Up @@ -2569,7 +2585,7 @@ final class CParser(AST) : Parser!AST
auto tspec = cparseDeclarationSpecifiers(LVL.prototype, specifier);

Identifier id;
auto t = cparseDeclarator(DTR.xparameter, tspec, id);
auto t = cparseDeclarator(DTR.xparameter, tspec, id, specifier);
if (specifier.mod & MOD.xconst)
t = toConst(t);
auto param = new AST.Parameter(STC.parameter, t, id, null, null);
Expand Down Expand Up @@ -2976,6 +2992,15 @@ final class CParser(AST) : Parser!AST
// TODO C11 6.7.2.2-2 value must fit into an int
}

if (token.value == TOK.__attribute__)
{
/* gnu-attributes can appear here, but just scan and ignore them
* https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
*/
Specifier specifierx;
cparseGnuAttributes(specifierx);
}

auto em = new AST.EnumMember(mloc, ident, value, null, 0, null, null);
members.push(em);

Expand Down Expand Up @@ -3156,7 +3181,7 @@ final class CParser(AST) : Parser!AST
}
else
{
dt = cparseDeclarator(DTR.xdirect, tspec, id);
dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
if (!dt)
{
panic();
Expand Down Expand Up @@ -3252,8 +3277,8 @@ final class CParser(AST) : Parser!AST
*/
private bool isCDeclaration(ref Token* pt)
{
//printf("isCDeclaration()\n");
auto t = pt;
//printf("isCDeclaration() %s\n", t.toChars());
if (!isDeclarationSpecifiers(t))
return false;

Expand Down Expand Up @@ -3378,8 +3403,8 @@ final class CParser(AST) : Parser!AST
*/
private bool isAssignmentExpression(ref Token* pt)
{
//printf("isAssignmentExpression()\n");
auto t = pt;
//printf("isAssignmentExpression() %s\n", t.toChars());

/* This doesn't actually check for grammar matching an
* assignment-expression. It just matches ( ) [ ] looking for
Expand All @@ -3402,6 +3427,7 @@ final class CParser(AST) : Parser!AST
case TOK.leftParenthesis:
if (!skipParens(t, &t))
return false;
any = true;
continue;

case TOK.leftBracket:
Expand Down Expand Up @@ -4141,8 +4167,10 @@ final class CParser(AST) : Parser!AST
{
if (specifier.scw & SCW.xextern)
stc = AST.STC.extern_ | AST.STC.gshared;
else if (specifier.scw & SCW.xstatic)
stc = AST.STC.gshared | AST.STC.static_;
else
stc = AST.STC.gshared;
stc = AST.STC.gshared;
}
else if (level == LVL.local)
{
Expand Down
8 changes: 8 additions & 0 deletions dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import dmd.func;
import dmd.globals;
import dmd.impcnvtab;
import dmd.id;
import dmd.importc;
import dmd.init;
import dmd.intrange;
import dmd.mtype;
Expand Down Expand Up @@ -2813,6 +2814,13 @@ Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
Expression e1 = pe1;
Expression e2 = pe2;

// ImportC: do array/function conversions
if (sc)
{
e1 = e1.arrayFuncConv(sc);
e2 = e2.arrayFuncConv(sc);
}

Type Lret(Type result)
{
pe1 = e1;
Expand Down
90 changes: 88 additions & 2 deletions dmd/dsymbol.d
Original file line number Diff line number Diff line change
Expand Up @@ -831,10 +831,18 @@ version (IN_LLVM)
Dsymbol s2 = sds.symtabLookup(this,ident);

// If using C tag/prototype/forward declaration rules
if (sc.flags & SCOPE.Cfile &&
handleTagSymbols(*sc, this, s2, sds))
if (sc.flags & SCOPE.Cfile)
{
if (handleTagSymbols(*sc, this, s2, sds))
return;
if (handleSymbolRedeclarations(*sc, this, s2, sds))
return;

sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading
errors = true;
return;
}

if (!s2.overloadInsert(this))
{
sds.multiplyDefined(Loc.initial, this, s2);
Expand Down Expand Up @@ -2422,3 +2430,81 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
}


/**********************************************
* ImportC allows redeclarations of variables and functions.
* extern int x;
* int x = 3;
* and:
* extern void f();
* void f() { }
* Attempt to merge them.
* Params:
* sc = context
* s = symbol to add to symbol table
* s2 = existing declaration
* sds = symbol table
* Returns:
* if s and s2 are successfully put in symbol table then return the merged symbol,
* null if they conflict
*/
Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
{
enum log = false;
if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());

static Dsymbol collision()
{
if (log) printf(" collision\n");
return null;
}

auto vd = s.isVarDeclaration(); // new declaration
auto vd2 = s2.isVarDeclaration(); // existing declaration
if (vd && vd2)
{
// if one is `static` and the other isn't
if ((vd.storage_class ^ vd2.storage_class) & STC.static_)
return collision();

const i1 = vd._init && ! vd._init.isVoidInitializer();
const i2 = vd2._init && !vd2._init.isVoidInitializer();

if (i1 && i2)
return collision(); // can't both have initializers

if (i1)
return vd;

/* BUG: the types should match, which needs semantic() to be run on it
* extern int x;
* int x; // match
* typedef int INT;
* INT x; // match
* long x; // collision
* We incorrectly ignore these collisions
*/
return vd2;
}

auto fd = s.isFuncDeclaration(); // new declaration
auto fd2 = s2.isFuncDeclaration(); // existing declaration
if (fd && fd2)
{
// if one is `static` and the other isn't
if ((fd.storage_class ^ fd2.storage_class) & STC.static_)
return collision();

if (fd.fbody && fd2.fbody)
return collision(); // can't both have bodies

if (fd.fbody)
return fd;

/* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
* FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
*/
return fd2;
}

return collision();
}
33 changes: 32 additions & 1 deletion dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -4430,14 +4430,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (exp.e1.op == TOK.type && (sc && sc.flags & SCOPE.Cfile))
{
const numArgs = exp.arguments ? exp.arguments.length : 0;
if (e1org.parens && numArgs >= 1)
{
/* Ambiguous cases arise from CParser where there is not enough
* information to determine if we have a function call or a cast.
* ( type-name ) ( identifier ) ;
* ( identifier ) ( identifier ) ;
* If exp.e1 is a type-name, then this is a cast.
*/
Expression arg;
foreach (a; (*exp.arguments)[])
{
arg = arg ? new CommaExp(a.loc, arg, a) : a;
}
auto t = exp.e1.isTypeExp().type;
auto e = new CastExp(exp.loc, arg, t);
result = e.expressionSemantic(sc);
return;
}

/* Ambiguous cases arise from CParser where there is not enough
* information to determine if we have a function call or declaration.
* type-name ( identifier ) ;
* identifier ( identifier ) ;
* If exp.e1 is a type-name, then this is a declaration. C11 does not
* have type construction syntax, so don't convert this to a cast().
*/
if (exp.arguments && exp.arguments.dim == 1)
if (numArgs == 1)
{
Expression arg = (*exp.arguments)[0];
if (auto ie = (*exp.arguments)[0].isIdentifierExp())
Expand Down Expand Up @@ -6417,6 +6437,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}

if (sc.flags & SCOPE.Cfile && exp.ident != Id.__sizeof)
{
result = fieldLookup(exp.e1, sc, exp.ident);
return;
}

Expression e = exp.semanticY(sc, 1);

if (e && isDotOpDispatch(e))
Expand Down Expand Up @@ -8722,6 +8748,11 @@ version (IN_LLVM)

e1x = e;
}
else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
{
auto die = e1x.isDotIdExp();
e1x = fieldLookup(die.e1, sc, die.ident);
}
else if (auto die = e1x.isDotIdExp())
{
Expression e = die.semanticY(sc, 1);
Expand Down
1 change: 1 addition & 0 deletions dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ immutable Msgtable[] msgtable =
{ "vector_size" },
{ "__func__" },
{ "noreturn" },
{ "__pragma", "pragma" },

// IN_LLVM: LDC-specific pragmas
{ "LDC_intrinsic" },
Expand Down
Loading

0 comments on commit 98bbfd8

Please sign in to comment.