aboutsummaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2024-01-16 19:57:40 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2024-02-03 00:16:55 +0100
commit838e706fa55b1798fb5f0242dbd90cd4d9817bbe (patch)
treeba9e9519442f8edea295b389e77e1183403d87d8 /gcc/d
parentcfc6d9ae8143cf0e903384bc63e8d659ca1c9fe7 (diff)
downloadgcc-838e706fa55b1798fb5f0242dbd90cd4d9817bbe.zip
gcc-838e706fa55b1798fb5f0242dbd90cd4d9817bbe.tar.gz
gcc-838e706fa55b1798fb5f0242dbd90cd4d9817bbe.tar.bz2
d: Merge upstream dmd, druntime f1a045928e
D front-end changes: - Import dmd v2.106.1-rc.1. - Unrecognized pragmas are no longer an error by default. D runtime changes: - Import druntime v2.106.1-rc.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd f1a045928e. * dmd/VERSION: Bump version to v2.106.1-rc.1. * gdc.texi (fignore-unknown-pragmas): Update documentation. * d-builtins.cc (covariant_with_builtin_type_p): Update for new front-end interface. * d-lang.cc (d_parse_file): Likewise. * typeinfo.cc (make_frontend_typeinfo): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime f1a045928e. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/stdc/stdatomic.d. * libdruntime/Makefile.in: Regenerate.
Diffstat (limited to 'gcc/d')
-rw-r--r--gcc/d/d-builtins.cc2
-rw-r--r--gcc/d/d-lang.cc3
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/aliasthis.d166
-rw-r--r--gcc/d/dmd/astcodegen.d2
-rw-r--r--gcc/d/dmd/attrib.d103
-rw-r--r--gcc/d/dmd/attrib.h5
-rw-r--r--gcc/d/dmd/cparse.d113
-rw-r--r--gcc/d/dmd/ctfeexpr.d3
-rw-r--r--gcc/d/dmd/dcast.d1
-rw-r--r--gcc/d/dmd/dclass.d5
-rw-r--r--gcc/d/dmd/declaration.d287
-rw-r--r--gcc/d/dmd/declaration.h1
-rw-r--r--gcc/d/dmd/dimport.d42
-rw-r--r--gcc/d/dmd/dmodule.d118
-rw-r--r--gcc/d/dmd/doc.d11
-rw-r--r--gcc/d/dmd/dscope.d37
-rw-r--r--gcc/d/dmd/dstruct.d2
-rw-r--r--gcc/d/dmd/dsymbol.d75
-rw-r--r--gcc/d/dmd/dsymbol.h35
-rw-r--r--gcc/d/dmd/dsymbolsem.d749
-rw-r--r--gcc/d/dmd/dtemplate.d11
-rw-r--r--gcc/d/dmd/dtoh.d2
-rw-r--r--gcc/d/dmd/errorsink.d14
-rw-r--r--gcc/d/dmd/expression.d3
-rw-r--r--gcc/d/dmd/expressionsem.d32
-rw-r--r--gcc/d/dmd/func.d5
-rw-r--r--gcc/d/dmd/globals.d2
-rw-r--r--gcc/d/dmd/import.h1
-rw-r--r--gcc/d/dmd/init.d6
-rw-r--r--gcc/d/dmd/initsem.d77
-rw-r--r--gcc/d/dmd/lambdacomp.d2
-rw-r--r--gcc/d/dmd/lexer.d35
-rw-r--r--gcc/d/dmd/module.h5
-rw-r--r--gcc/d/dmd/mtype.d834
-rw-r--r--gcc/d/dmd/mtype.h4
-rw-r--r--gcc/d/dmd/nspace.d16
-rw-r--r--gcc/d/dmd/nspace.h1
-rw-r--r--gcc/d/dmd/scope.h2
-rw-r--r--gcc/d/dmd/semantic3.d3
-rw-r--r--gcc/d/dmd/statement.d8
-rw-r--r--gcc/d/dmd/statement.h2
-rw-r--r--gcc/d/dmd/statementsem.d22
-rw-r--r--gcc/d/dmd/staticassert.d3
-rw-r--r--gcc/d/dmd/template.h1
-rw-r--r--gcc/d/dmd/traits.d6
-rw-r--r--gcc/d/dmd/typesem.d802
-rw-r--r--gcc/d/gdc.texi6
-rw-r--r--gcc/d/typeinfo.cc3
50 files changed, 1890 insertions, 1782 deletions
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 59a1b4c..9d60497 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -724,7 +724,7 @@ static bool
covariant_with_builtin_type_p (Type *t1, Type *t2)
{
/* Check whether the declared function matches the built-in. */
- if (same_type_p (t1, t2) || t1->covariant (t2) == Covariant::yes)
+ if (same_type_p (t1, t2) || covariant (t1, t2) == Covariant::yes)
return true;
/* May not be covariant because of D attributes applied on t1.
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 7840cf8..a25d031 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/cond.h"
#include "dmd/declaration.h"
#include "dmd/doc.h"
+#include "dmd/dsymbol.h"
#include "dmd/errors.h"
#include "dmd/expression.h"
#include "dmd/hdrgen.h"
@@ -1226,7 +1227,7 @@ d_parse_file (void)
if (global.params.v.verbose)
message ("importall %s", m->toChars ());
- m->importAll (NULL);
+ importAll (m, NULL);
}
if (global.errors)
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 5edcee1..fa7004b 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-2bbf64907cbbb483d003e0a8fcf8b502e4883799
+f1a045928e03239b9477f9497f43f2cf0e61e959
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 8c95cd0..9d7be5b 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.106.0
+v2.106.1-rc.1
diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d
index a8933f6..0c15636 100644
--- a/gcc/d/dmd/aliasthis.d
+++ b/gcc/d/dmd/aliasthis.d
@@ -14,16 +14,10 @@
module dmd.aliasthis;
import core.stdc.stdio;
-import dmd.aggregate;
-import dmd.dscope;
+
import dmd.dsymbol;
-import dmd.expression;
-import dmd.expressionsem;
-import dmd.globals;
import dmd.identifier;
import dmd.location;
-import dmd.mtype;
-import dmd.tokens;
import dmd.visitor;
/***********************************************************
@@ -71,161 +65,3 @@ extern (C++) final class AliasThis : Dsymbol
return this.isDeprecated_;
}
}
-
-/*************************************
- * Find the `alias this` symbol of e's type.
- * Params:
- * sc = context
- * e = expression forming the `this`
- * gag = do not print errors, return `null` instead
- * findOnly = don't do further processing like resolving properties,
- * i.e. just return plain dotExp() result.
- * Returns:
- * Expression that is `e.aliasthis`
- */
-Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
-{
- import dmd.typesem : dotExp;
- for (AggregateDeclaration ad = isAggregate(e.type); ad;)
- {
- if (ad.aliasthis)
- {
- Loc loc = e.loc;
- Type tthis = (e.op == EXP.type ? e.type : null);
- const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag));
- uint olderrors = gag ? global.startGagging() : 0;
- e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags);
- if (!e || findOnly)
- return gag && global.endGagging(olderrors) ? null : e;
-
- if (tthis && ad.aliasthis.sym.needThis())
- {
- if (auto ve = e.isVarExp())
- {
- if (auto fd = ve.var.isFuncDeclaration())
- {
- // https://issues.dlang.org/show_bug.cgi?id=13009
- // Support better match for the overloaded alias this.
- bool hasOverloads;
- if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
- {
- if (!hasOverloads)
- fd = f; // use exact match
- e = new VarExp(loc, fd, hasOverloads);
- e.type = f.type;
- e = new CallExp(loc, e);
- goto L1;
- }
- }
- }
- /* non-@property function is not called inside typeof(),
- * so resolve it ahead.
- */
- {
- int save = sc.intypeof;
- sc.intypeof = 1; // bypass "need this" error check
- e = resolveProperties(sc, e);
- sc.intypeof = save;
- }
- L1:
- e = new TypeExp(loc, new TypeTypeof(loc, e));
- e = e.expressionSemantic(sc);
- }
- e = resolveProperties(sc, e);
- if (!gag)
- ad.aliasthis.checkDeprecatedAliasThis(loc, sc);
- else if (global.endGagging(olderrors))
- e = null;
- }
-
- import dmd.dclass : ClassDeclaration;
- auto cd = ad.isClassDeclaration();
- if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
- {
- ad = cd.baseClass;
- continue;
- }
- break;
- }
- return e;
-}
-
-/**
- * Check if an `alias this` is deprecated
- *
- * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to
- * check if `expression` uses a deprecated `aliasthis`, but this calls
- * `toPrettyChars` which lead to the following message:
- * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated"
- *
- * Params:
- * at = The `AliasThis` object to check
- * loc = `Loc` of the expression triggering the access to `at`
- * sc = `Scope` of the expression
- * (deprecations do not trigger in deprecated scopes)
- *
- * Returns:
- * Whether the alias this was reported as deprecated.
- */
-bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
-{
- import dmd.errors : deprecation, Classification;
- import dmd.dsymbolsem : getMessage;
-
- if (global.params.useDeprecated != DiagnosticReporting.off
- && at.isDeprecated() && !sc.isDeprecated())
- {
- const(char)* message = null;
- for (Dsymbol p = at; p; p = p.parent)
- {
- message = p.depdecl ? p.depdecl.getMessage() : null;
- if (message)
- break;
- }
- if (message)
- deprecation(loc, "`alias %s this` is deprecated - %s",
- at.sym.toChars(), message);
- else
- deprecation(loc, "`alias %s this` is deprecated",
- at.sym.toChars());
-
- if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
- ti.printInstantiationTrace(Classification.deprecation);
-
- return true;
- }
- return false;
-}
-
-/**************************************
- * Check and set 'att' if 't' is a recursive 'alias this' type
- *
- * The goal is to prevent endless loops when there is a cycle in the alias this chain.
- * Since there is no multiple `alias this`, the chain either ends in a leaf,
- * or it loops back on itself as some point.
- *
- * Example: S0 -> (S1 -> S2 -> S3 -> S1)
- *
- * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
- * `S1` is a recursive alias this type, but since `att` is initialized to `null`,
- * this still returns `false`, but `att1` is set to `S1`.
- * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
- * we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
- *
- * Params:
- * att = type reference used to detect recursion. Should be initialized to `null`.
- * t = type of 'alias this' rewrite to attempt
- *
- * Returns:
- * `false` if the rewrite is safe, `true` if it would loop back around
- */
-bool isRecursiveAliasThis(ref Type att, Type t)
-{
- //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
- auto tb = t.toBasetype();
- if (att && tb.equivalent(att))
- return true;
- else if (!att && tb.checkAliasThisRec())
- att = tb;
- return false;
-}
diff --git a/gcc/d/dmd/astcodegen.d b/gcc/d/dmd/astcodegen.d
index d40f836..f179077 100644
--- a/gcc/d/dmd/astcodegen.d
+++ b/gcc/d/dmd/astcodegen.d
@@ -97,6 +97,6 @@ struct ASTCodegen
alias isExpression = dmd.dtemplate.isExpression;
alias isTuple = dmd.dtemplate.isTuple;
- alias IgnoreErrors = dmd.dsymbol.IgnoreErrors;
+ alias SearchOpt = dmd.dsymbol.SearchOpt;
alias PASS = dmd.dsymbol.PASS;
}
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index faf0489..cc6ef9c 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -123,19 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
return sc;
}
- override void importAll(Scope* sc)
- {
- Dsymbols* d = include(sc);
- //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
- if (d)
- {
- Scope* sc2 = newScope(sc);
- d.foreachDsymbol( s => s.importAll(sc2) );
- if (sc2 != sc)
- sc2.pop();
- }
- }
-
override void addComment(const(char)* comment)
{
//printf("AttribDeclaration::addComment %s\n", comment);
@@ -156,11 +143,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
return Dsymbol.oneMembers(d, ps, ident);
}
- override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
- {
- include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
- }
-
override final bool hasPointers()
{
return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
@@ -675,81 +657,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration
return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
}
- override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
- {
- //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
- if (decl)
- {
- /* This works by treating an AnonDeclaration as an aggregate 'member',
- * so in order to place that member we need to compute the member's
- * size and alignment.
- */
- size_t fieldstart = ad.fields.length;
-
- /* Hackishly hijack ad's structsize and alignsize fields
- * for use in our fake anon aggregate member.
- */
- uint savestructsize = ad.structsize;
- uint savealignsize = ad.alignsize;
- ad.structsize = 0;
- ad.alignsize = 0;
-
- FieldState fs;
- decl.foreachDsymbol( (s)
- {
- s.setFieldOffset(ad, fs, this.isunion);
- if (this.isunion)
- fs.offset = 0;
- });
-
- /* https://issues.dlang.org/show_bug.cgi?id=13613
- * If the fields in this.members had been already
- * added in ad.fields, just update *poffset for the subsequent
- * field offset calculation.
- */
- if (fieldstart == ad.fields.length)
- {
- ad.structsize = savestructsize;
- ad.alignsize = savealignsize;
- fieldState.offset = ad.structsize;
- return;
- }
-
- anonstructsize = ad.structsize;
- anonalignsize = ad.alignsize;
- ad.structsize = savestructsize;
- ad.alignsize = savealignsize;
-
- // 0 sized structs are set to 1 byte
- if (anonstructsize == 0)
- {
- anonstructsize = 1;
- anonalignsize = 1;
- }
-
- assert(_scope);
- auto alignment = _scope.alignment();
-
- /* Given the anon 'member's size and alignment,
- * go ahead and place it.
- */
- anonoffset = placeField(
- fieldState.offset,
- anonstructsize, anonalignsize, alignment,
- ad.structsize, ad.alignsize,
- isunion);
-
- // Add to the anon fields the base offset of this anonymous aggregate
- //printf("anon fields, anonoffset = %d\n", anonoffset);
- foreach (const i; fieldstart .. ad.fields.length)
- {
- VarDeclaration v = ad.fields[i];
- //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
- v.offset += anonoffset;
- }
- }
- }
-
override const(char)* kind() const
{
return (isunion ? "anonymous union" : "anonymous struct");
@@ -943,11 +850,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
}
}
- override void importAll(Scope* sc)
- {
- // do not evaluate condition before semantic pass
- }
-
override const(char)* kind() const
{
return "static if";
@@ -1057,11 +959,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
// change this to give semantics to documentation comments on static foreach declarations
}
- override void importAll(Scope* sc)
- {
- // do not evaluate aggregate before semantic pass
- }
-
override const(char)* kind() const
{
return "static foreach";
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index 98c5e52..35628e2 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -26,11 +26,9 @@ public:
virtual Dsymbols *include(Scope *sc);
virtual Scope *newScope(Scope *sc);
- void importAll(Scope *sc) override;
void addComment(const utf8_t *comment) override;
const char *kind() const override;
bool oneMember(Dsymbol **ps, Identifier *ident) override;
- void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
bool hasPointers() override final;
bool hasStaticCtorOrDtor() override final;
void checkCtorConstInit() override final;
@@ -132,7 +130,6 @@ public:
unsigned anonalignsize; // size of anonymous struct for alignment purposes
AnonDeclaration *syntaxCopy(Dsymbol *s) override;
- void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
const char *kind() const override;
AnonDeclaration *isAnonDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
@@ -171,7 +168,6 @@ public:
StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
Dsymbols *include(Scope *sc) override;
- void importAll(Scope *sc) override;
StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
@@ -190,7 +186,6 @@ public:
bool oneMember(Dsymbol **ps, Identifier *ident) override;
Dsymbols *include(Scope *sc) override;
void addComment(const utf8_t *comment) override;
- void importAll(Scope *sc) override;
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 89a5948..4c0b96a 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -247,6 +247,8 @@ final class CParser(AST) : Parser!AST
break;
case TOK.charLiteral:
+ case TOK.wcharLiteral:
+ case TOK.dcharLiteral:
case TOK.int32Literal:
case TOK.uns32Literal:
case TOK.int64Literal:
@@ -725,6 +727,12 @@ final class CParser(AST) : Parser!AST
nextToken();
break;
+ case TOK.wcharLiteral:
+ e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tuns16);
+ nextToken();
+ break;
+
+ case TOK.dcharLiteral:
case TOK.uns32Literal:
e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
nextToken();
@@ -1899,6 +1907,7 @@ final class CParser(AST) : Parser!AST
}
bool isalias = true;
+ Identifier idt;
if (auto ts = dt.isTypeStruct())
{
if (ts.sym.isAnonymous())
@@ -1908,6 +1917,7 @@ final class CParser(AST) : Parser!AST
ts.sym.ident = id;
isalias = false;
}
+ idt = ts.sym.ident;
}
else if (auto te = dt.isTypeEnum())
{
@@ -1917,6 +1927,7 @@ final class CParser(AST) : Parser!AST
te.sym.ident = id;
isalias = false;
}
+ idt = te.sym.ident;
}
else if (auto tt = dt.isTypeTag())
{
@@ -1930,11 +1941,13 @@ final class CParser(AST) : Parser!AST
Specifier spec;
declareTag(tt, spec);
}
+ idt = tt.id;
}
if (isalias)
{
auto ad = new AST.AliasDeclaration(token.loc, id, dt);
- ad.adFlags |= ad.hidden; // do not print when generating .di files
+ if (id == idt)
+ ad.adFlags |= ad.hidden; // do not print when generating .di files
s = ad;
}
@@ -4272,6 +4285,7 @@ final class CParser(AST) : Parser!AST
case TOK.rightParenthesis:
case TOK.rightBracket:
case TOK.endOfFile:
+ case TOK.endOfLine:
if (!any)
return false;
break;
@@ -4940,6 +4954,8 @@ final class CParser(AST) : Parser!AST
{
case TOK.identifier:
case TOK.charLiteral:
+ case TOK.wcharLiteral:
+ case TOK.dcharLiteral:
case TOK.int32Literal:
case TOK.uns32Literal:
case TOK.int64Literal:
@@ -5794,6 +5810,9 @@ final class CParser(AST) : Parser!AST
buf.writeByte(0);
auto slice = buf.peekChars()[0 .. length];
resetDefineLines(slice); // reset lexer
+ auto save = eSink;
+ auto eLatch = new ErrorSinkLatch();
+ eSink = eLatch;
const(char)* endp = &slice[length - 7];
@@ -5801,40 +5820,40 @@ final class CParser(AST) : Parser!AST
// indexed by Identifier, returns index into symbols[]
// The memory for this is leaked
- void addVar(AST.VarDeclaration v)
+ void addVar(AST.Dsymbol s)
{
- //printf("addVar() %s\n", v.toChars());
- v.isCmacro(true); // mark it as coming from a C #define
+ //printf("addVar() %s\n", s.toChars());
+ if (auto v = s.isVarDeclaration())
+ v.isCmacro(true); // mark it as coming from a C #define
/* If it's already defined, replace the earlier
* definition
*/
- if (size_t* pd = cast(void*)v.ident in defineTab)
+ if (size_t* pd = cast(void*)s.ident in defineTab)
{
//printf("replacing %s\n", v.toChars());
- (*symbols)[*pd] = v;
+ (*symbols)[*pd] = s;
return;
}
- defineTab[cast(void*)v.ident] = symbols.length;
- symbols.push(v);
+ defineTab[cast(void*)s.ident] = symbols.length;
+ symbols.push(s);
}
- Token n;
-
while (p < endp)
{
if (p[0 .. 7] == "#define")
{
p += 7;
- scan(&n);
- //printf("%s\n", n.toChars());
- if (n.value == TOK.identifier)
+ nextToken();
+ //printf("define %s\n", token.toChars());
+ if (token.value == TOK.identifier)
{
- auto id = n.ident;
- scan(&n);
+ auto id = token.ident;
+ const params = *p == '(';
+ nextToken();
AST.Type t;
- switch (n.value)
+ switch (token.value)
{
case TOK.endOfLine: // #define identifier
nextDefineLine();
@@ -5842,14 +5861,16 @@ final class CParser(AST) : Parser!AST
case TOK.int32Literal:
case TOK.charLiteral: t = AST.Type.tint32; goto Linteger;
+ case TOK.wcharLiteral: t = AST.Type.tuns16; goto Linteger;
+ case TOK.dcharLiteral:
case TOK.uns32Literal: t = AST.Type.tuns32; goto Linteger;
case TOK.int64Literal: t = AST.Type.tint64; goto Linteger;
case TOK.uns64Literal: t = AST.Type.tuns64; goto Linteger;
Linteger:
- const intvalue = n.intvalue;
- scan(&n);
- if (n.value == TOK.endOfLine)
+ const intvalue = token.intvalue;
+ nextToken();
+ if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = intvalue;
@@ -5870,9 +5891,9 @@ final class CParser(AST) : Parser!AST
case TOK.imaginary80Literal: t = AST.Type.timaginary80; goto Lfloat;
Lfloat:
- const floatvalue = n.floatvalue;
- scan(&n);
- if (n.value == TOK.endOfLine)
+ const floatvalue = token.floatvalue;
+ nextToken();
+ if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = floatvalue;
@@ -5886,11 +5907,11 @@ final class CParser(AST) : Parser!AST
break;
case TOK.string_:
- const str = n.ustring;
- const len = n.len;
- const postfix = n.postfix;
- scan(&n);
- if (n.value == TOK.endOfLine)
+ const str = token.ustring;
+ const len = token.len;
+ const postfix = token.postfix;
+ nextToken();
+ if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = "string";
@@ -5903,6 +5924,39 @@ final class CParser(AST) : Parser!AST
}
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
+ nextToken();
+ eLatch.sawErrors = false;
+ auto exp = cparseExpression();
+ if (eLatch.sawErrors) // parsing errors
+ break; // abandon this #define
+ if (token.value != TOK.rightParenthesis)
+ break;
+ nextToken();
+ if (token.value != TOK.endOfLine)
+ break;
+ auto ret = new AST.ReturnStatement(exp.loc, exp);
+ auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0);
+ 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;
+ AST.Dsymbols* decldefs = new AST.Dsymbols();
+ decldefs.push(fd);
+ AST.TemplateParameters* tpl = new AST.TemplateParameters();
+ AST.Expression constraint = null;
+ auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
+ addVar(tempdecl);
+ nextDefineLine();
+ continue;
+
default:
break;
}
@@ -5911,8 +5965,8 @@ final class CParser(AST) : Parser!AST
}
else
{
- scan(&n);
- if (n.value != TOK.endOfLine)
+ scan(&token);
+ if (token.value != TOK.endOfLine)
{
skipToNextLine();
}
@@ -5920,6 +5974,7 @@ final class CParser(AST) : Parser!AST
nextDefineLine();
}
+ eSink = save;
defines = buf;
}
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 43efc05..993bab0 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -636,8 +636,11 @@ bool isSafePointerCast(Type srcPointee, Type destPointee)
// It's OK if function pointers differ only in safe/pure/nothrow
if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
+ {
+ import dmd.typesem : covariant;
return srcPointee.covariant(destPointee) == Covariant.yes ||
destPointee.covariant(srcPointee) == Covariant.yes;
+ }
// it's OK to cast to void*
if (destPointee.ty == Tvoid)
return true;
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index bb86b08..cfa374c 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -24,6 +24,7 @@ import dmd.dinterpret;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
+import dmd.dsymbolsem;
import dmd.errors;
import dmd.escape;
import dmd.expression;
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 72b85cf..e066d87 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -594,7 +594,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
fieldState.offset = structsize;
foreach (s; *members)
{
- s.setFieldOffset(this, fieldState, false);
+ s.setFieldOffset(this, &fieldState, false);
}
sizeok = Sizeok.done;
@@ -614,7 +614,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
final bool isFuncHidden(FuncDeclaration fd)
{
//printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
- Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
+ Dsymbol s = this.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors);
if (!s)
{
//printf("not found\n");
@@ -670,6 +670,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
void searchVtbl(ref Dsymbols vtbl)
{
+ import dmd.typesem : covariant;
bool seenInterfaceVirtual;
foreach (s; vtbl)
{
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 0e125fd..bdc91f4 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -1214,88 +1214,6 @@ extern (C++) class VarDeclaration : Declaration
return v;
}
- override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
- {
- //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
-
- if (aliasTuple)
- {
- // If this variable was really a tuple, set the offsets for the tuple fields
- aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
- return;
- }
-
- if (!isField())
- return;
- assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter)));
-
- //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
-
- /* Fields that are tuples appear both as part of TupleDeclarations and
- * as members. That means ignore them if they are already a field.
- */
- if (offset)
- {
- // already a field
- fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
- return;
- }
- for (size_t i = 0; i < ad.fields.length; i++)
- {
- if (ad.fields[i] == this)
- {
- // already a field
- fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
- return;
- }
- }
-
- // Check for forward referenced types which will fail the size() call
- Type t = type.toBasetype();
- if (storage_class & STC.ref_)
- {
- // References are the size of a pointer
- t = Type.tvoidptr;
- }
- Type tv = t.baseElemOf();
- if (tv.ty == Tstruct)
- {
- auto ts = cast(TypeStruct)tv;
- assert(ts.sym != ad); // already checked in ad.determineFields()
- if (!ts.sym.determineSize(loc))
- {
- type = Type.terror;
- errors = true;
- return;
- }
- }
-
- // List in ad.fields. Even if the type is error, it's necessary to avoid
- // pointless error diagnostic "more initializers than fields" on struct literal.
- ad.fields.push(this);
-
- if (t.ty == Terror)
- return;
-
- /* If coming after a bit field in progress,
- * advance past the field
- */
- fieldState.inFlight = false;
-
- const sz = t.size(loc);
- assert(sz != SIZE_INVALID && sz < uint.max);
- uint memsize = cast(uint)sz; // size of member
- uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
- offset = placeField(
- fieldState.offset,
- memsize, memalignsize, alignment,
- ad.structsize, ad.alignsize,
- isunion);
-
- //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
- //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
- }
-
override const(char)* kind() const
{
return "variable";
@@ -1803,211 +1721,6 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
: (1L << (width - 1)) - 1);
return v;
}
-
- override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
- {
- enum log = false;
- static if (log)
- {
- printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
- void print(const ref FieldState fieldState)
- {
- fieldState.print();
- printf(" fieldWidth = %d bits\n", fieldWidth);
- }
- print(fieldState);
- }
-
- Type t = type.toBasetype();
- const bool anon = isAnonymous();
-
- // List in ad.fields. Even if the type is error, it's necessary to avoid
- // pointless error diagnostic "more initializers than fields" on struct literal.
- if (!anon)
- ad.fields.push(this);
-
- if (t.ty == Terror)
- return;
-
- const sz = t.size(loc);
- assert(sz != SIZE_INVALID && sz < uint.max);
- uint memsize = cast(uint)sz; // size of member
- uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
- if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize);
-
- if (fieldWidth == 0 && !anon)
- error(loc, "named bit fields cannot have 0 width");
- if (fieldWidth > memsize * 8)
- error(loc, "bit field width %d is larger than type", fieldWidth);
-
- const style = target.c.bitFieldStyle;
-
- void startNewField()
- {
- if (log) printf("startNewField()\n");
- uint alignsize;
- if (style == TargetC.BitFieldStyle.Gcc_Clang)
- {
- if (fieldWidth > 32)
- alignsize = memalignsize;
- else if (fieldWidth > 16)
- alignsize = 4;
- else if (fieldWidth > 8)
- alignsize = 2;
- else
- alignsize = 1;
- }
- else
- alignsize = memsize; // not memalignsize
-
- uint dummy;
- offset = placeField(
- fieldState.offset,
- memsize, alignsize, alignment,
- ad.structsize,
- (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
- isunion);
-
- fieldState.inFlight = true;
- fieldState.fieldOffset = offset;
- fieldState.bitOffset = 0;
- fieldState.fieldSize = memsize;
- }
-
- if (style == TargetC.BitFieldStyle.Gcc_Clang)
- {
- if (fieldWidth == 0)
- {
- if (!isunion)
- {
- // Use type of zero width field to align to next field
- fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
- ad.structsize = fieldState.offset;
- }
-
- fieldState.inFlight = false;
- return;
- }
-
- if (ad.alignsize == 0)
- ad.alignsize = 1;
- if (!anon &&
- ad.alignsize < memalignsize)
- ad.alignsize = memalignsize;
- }
- else if (style == TargetC.BitFieldStyle.MS)
- {
- if (ad.alignsize == 0)
- ad.alignsize = 1;
- if (fieldWidth == 0)
- {
- if (fieldState.inFlight && !isunion)
- {
- // documentation says align to next int
- //const alsz = cast(uint)Type.tint32.size();
- const alsz = memsize; // but it really does this
- fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
- ad.structsize = fieldState.offset;
- }
-
- fieldState.inFlight = false;
- return;
- }
- }
- else if (style == TargetC.BitFieldStyle.DM)
- {
- if (anon && fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
- return; // this probably should be a bug in DMC
- if (ad.alignsize == 0)
- ad.alignsize = 1;
- if (fieldWidth == 0)
- {
- if (fieldState.inFlight && !isunion)
- {
- const alsz = memsize;
- fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
- ad.structsize = fieldState.offset;
- }
-
- fieldState.inFlight = false;
- return;
- }
- }
-
- if (!fieldState.inFlight)
- {
- //printf("not in flight\n");
- startNewField();
- }
- else if (style == TargetC.BitFieldStyle.Gcc_Clang)
- {
- // If the bit-field spans more units of alignment than its type,
- // start a new field at the next alignment boundary.
- if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
- fieldState.bitOffset + fieldWidth > memalignsize * 8)
- {
- if (log) printf("more units of alignment than its type\n");
- startNewField(); // the bit field is full
- }
- else
- {
- // if alignment boundary is crossed
- uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
- uint end = start + fieldWidth;
- //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
- if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
- {
- if (log) printf("alignment is crossed\n");
- startNewField();
- }
- }
- }
- else if (style == TargetC.BitFieldStyle.DM ||
- style == TargetC.BitFieldStyle.MS)
- {
- if (memsize != fieldState.fieldSize ||
- fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
- {
- //printf("new field\n");
- startNewField();
- }
- }
- else
- assert(0);
-
- offset = fieldState.fieldOffset;
- bitOffset = fieldState.bitOffset;
-
- const pastField = bitOffset + fieldWidth;
- if (style == TargetC.BitFieldStyle.Gcc_Clang)
- {
- auto size = (pastField + 7) / 8;
- fieldState.fieldSize = size;
- //printf(" offset: %d, size: %d\n", offset, size);
- if (isunion)
- {
- const newstructsize = offset + size;
- if (newstructsize > ad.structsize)
- ad.structsize = newstructsize;
- }
- else
- ad.structsize = offset + size;
- }
- else
- fieldState.fieldSize = memsize;
- //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
- //print(fieldState);
-
- if (!isunion)
- {
- fieldState.offset = offset + fieldState.fieldSize;
- fieldState.bitOffset = pastField;
- }
-
- //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize);
- //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
- //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
- }
}
/***********************************************************
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index a65fb44..adbc26b 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -281,7 +281,6 @@ public:
bool systemInferred(bool v);
static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
VarDeclaration *syntaxCopy(Dsymbol *) override;
- void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final;
const char *kind() const override;
AggregateDeclaration *isThis() override final;
bool needThis() override final;
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index 5c01a9f..51b9220 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -222,48 +222,6 @@ extern (C++) final class Import : Dsymbol
return global.errors != errors;
}
- override void importAll(Scope* sc)
- {
- if (mod) return; // Already done
-
- /*
- * https://issues.dlang.org/show_bug.cgi?id=15525
- *
- * Loading the import has failed,
- * most likely because of parsing errors.
- * Therefore we cannot trust the resulting AST.
- */
- if (load(sc))
- {
- // https://issues.dlang.org/show_bug.cgi?id=23873
- // For imports that are not at module or function level,
- // e.g. aggregate level, the import symbol is added to the
- // symbol table and later semantic is performed on it.
- // This leads to semantic analysis on an malformed AST
- // which causes all kinds of segfaults.
- // The fix is to note that the module has errors and avoid
- // semantic analysis on it.
- if(mod)
- mod.errors = true;
- return;
- }
-
- if (!mod) return; // Failed
-
- if (sc.stc & STC.static_)
- isstatic = true;
- mod.importAll(null);
- mod.checkImportDeprecation(loc, sc);
- if (sc.explicitVisibility)
- visibility = sc.visibility;
- if (!isstatic && !aliasId && !names.length)
- sc.scopesym.importScope(mod, visibility);
- // Enable access to pkgs/mod as soon as posible, because compiler
- // can traverse them before the import gets semantic (Issue: 21501)
- if (!aliasId && !names.length)
- addPackageAccess(sc.scopesym);
- }
-
/*******************************
* Mark the imported packages as accessible from the current
* scope. This access check is necessary when using FQN b/c
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index d096e43..6c9e90a 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -401,7 +401,7 @@ extern (C++) final class Module : Package
Identifier searchCacheIdent;
Dsymbol searchCacheSymbol; // cached value of search
- int searchCacheFlags; // cached flags
+ SearchOptFlags searchCacheFlags; // cached flags
bool insearch;
/**
@@ -921,70 +921,6 @@ extern (C++) final class Module : Package
return this;
}
- override void importAll(Scope* prevsc)
- {
- //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
- if (_scope)
- return; // already done
- if (filetype == FileType.ddoc)
- {
- error(loc, "%s `%s` is a Ddoc file, cannot import it", kind, toPrettyChars);
- return;
- }
-
- /* Note that modules get their own scope, from scratch.
- * This is so regardless of where in the syntax a module
- * gets imported, it is unaffected by context.
- * Ignore prevsc.
- */
- Scope* sc = Scope.createGlobal(this, global.errorSink); // create root scope
-
- if (md && md.msg)
- md.msg = semanticString(sc, md.msg, "deprecation message");
-
- // Add import of "object", even for the "object" module.
- // If it isn't there, some compiler rewrites, like
- // classinst == classinst -> .object.opEquals(classinst, classinst)
- // would fail inside object.d.
- if (filetype != FileType.c &&
- (members.length == 0 ||
- (*members)[0].ident != Id.object ||
- (*members)[0].isImport() is null))
- {
- auto im = new Import(Loc.initial, null, Id.object, null, 0);
- members.shift(im);
- }
- if (!symtab)
- {
- // Add all symbols into module's symbol table
- symtab = new DsymbolTable();
- for (size_t i = 0; i < members.length; i++)
- {
- Dsymbol s = (*members)[i];
- s.addMember(sc, sc.scopesym);
- }
- }
- // anything else should be run after addMember, so version/debug symbols are defined
- /* Set scope for the symbols so that if we forward reference
- * a symbol, it can possibly be resolved on the spot.
- * If this works out well, it can be extended to all modules
- * before any semantic() on any of them.
- */
- this.setScope(sc); // remember module scope for semantic
- for (size_t i = 0; i < members.length; i++)
- {
- Dsymbol s = (*members)[i];
- s.setScope(sc);
- }
- for (size_t i = 0; i < members.length; i++)
- {
- Dsymbol s = (*members)[i];
- s.importAll(sc);
- }
- sc = sc.pop();
- sc.pop(); // 2 pops because Scope.createGlobal() created 2
- }
-
/**********************************
* Determine if we need to generate an instance of ModuleInfo
* for this Module.
@@ -1021,14 +957,14 @@ extern (C++) final class Module : Package
}
}
- override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
+ override bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all)
{
if (insearch) // don't follow import cycles
return false;
insearch = true;
scope (exit)
insearch = false;
- if (flags & IgnorePrivateImports)
+ if (flags & SearchOpt.ignorePrivateImports)
visibility = Visibility(Visibility.Kind.public_); // only consider public imports
return super.isPackageAccessible(p, visibility);
}
@@ -1384,7 +1320,53 @@ extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses)
return 0;
}
- ScopeDsymbol._foreach(null, mod.members, &pushAddClassDg);
+ _foreach(null, mod.members, &pushAddClassDg);
+}
+
+
+alias ForeachDg = int delegate(size_t idx, Dsymbol s);
+
+/***************************************
+ * Expands attribute declarations in members in depth first
+ * order. Calls dg(size_t symidx, Dsymbol *sym) for each
+ * member.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Use this function to avoid the O(N + N^2/2) complexity of
+ * calculating dim and calling N times getNth.
+ * Returns:
+ * last value returned by dg()
+ */
+int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
+{
+ assert(dg);
+ if (!members)
+ return 0;
+ size_t n = pn ? *pn : 0; // take over index
+ int result = 0;
+ foreach (size_t i; 0 .. members.length)
+ {
+ import dmd.attrib : AttribDeclaration;
+ import dmd.dtemplate : TemplateMixin;
+
+ Dsymbol s = (*members)[i];
+ if (AttribDeclaration a = s.isAttribDeclaration())
+ result = _foreach(sc, a.include(sc), dg, &n);
+ else if (TemplateMixin tm = s.isTemplateMixin())
+ result = _foreach(sc, tm.members, dg, &n);
+ else if (s.isTemplateInstance())
+ {
+ }
+ else if (s.isUnitTestDeclaration())
+ {
+ }
+ else
+ result = dg(n++, s);
+ if (result)
+ break;
+ }
+ if (pn)
+ *pn = n; // update index
+ return result;
}
/**
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index 5488d5a..03848c0 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -748,7 +748,8 @@ void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false)
auto a = imp.aliases[i];
auto id = a ? a : imp.names[i];
auto loc = Loc.init;
- if (auto symFromId = sc.search(loc, id, null))
+ Dsymbol pscopesym;
+ if (auto symFromId = sc.search(loc, id, pscopesym))
{
emitAnchor(buf, symFromId, sc, forHeader);
}
@@ -3636,11 +3637,12 @@ struct MarkdownLinkReferences
if (id)
{
auto loc = Loc();
- auto symbol = _scope.search(loc, id, null, IgnoreErrors);
+ Dsymbol pscopesym;
+ auto symbol = _scope.search(loc, id, pscopesym, SearchOpt.ignoreErrors);
for (size_t i = 1; symbol && i < ids.length; ++i)
{
id = Identifier.lookup(ids[i].ptr, ids[i].length);
- symbol = id !is null ? symbol.search(loc, id, IgnoreErrors) : null;
+ symbol = id !is null ? symbol.search(loc, id, SearchOpt.ignoreErrors) : null;
}
if (symbol)
link = MarkdownLink(createHref(symbol), null, name, symbol);
@@ -4997,7 +4999,8 @@ void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset)
auto a = imp.aliases[i];
auto id = a ? a : imp.names[i];
auto loc = Loc.init;
- if (auto symFromId = sc.search(loc, id, null))
+ Dsymbol pscopesym;
+ if (auto symFromId = sc.search(loc, id, pscopesym))
{
highlightCode(sc, symFromId, buf, offset);
}
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index d68bcda..cd177a6 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -344,13 +344,13 @@ extern (C++) struct Scope
* Params:
* loc = location to use for error messages
* ident = name to look up
- * pscopesym = if supplied and name is found, set to scope that ident was found in
+ * pscopesym = if supplied and name is found, set to scope that ident was found in, otherwise set to null
* flags = modify search based on flags
*
* Returns:
* symbol if found, null if not
*/
- extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
+ extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, out Dsymbol pscopesym, SearchOptFlags flags = SearchOpt.all)
{
version (LOGSEARCH)
{
@@ -371,7 +371,7 @@ extern (C++) struct Scope
}
// This function is called only for unqualified lookup
- assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
+ assert(!(flags & (SearchOpt.localsOnly | SearchOpt.importsOnly)));
/* If ident is "start at module scope", only look at module scope
*/
@@ -386,15 +386,14 @@ extern (C++) struct Scope
if (Dsymbol s = sc.scopesym.isModule())
{
//printMsg("\tfound", s);
- if (pscopesym)
- *pscopesym = sc.scopesym;
+ pscopesym = sc.scopesym;
return s;
}
}
return null;
}
- Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp)
+ Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, SearchOptFlags flags, Expression* exp)
{
import dmd.mtype;
if (!ad || !ad.aliasthis)
@@ -458,7 +457,7 @@ extern (C++) struct Scope
return s;
}
- Dsymbol searchScopes(int flags)
+ Dsymbol searchScopes(SearchOptFlags flags)
{
for (Scope* sc = &this; sc; sc = sc.enclosing)
{
@@ -468,13 +467,13 @@ extern (C++) struct Scope
//printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags);
if (sc.scopesym.isModule())
- flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
+ flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed
else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration())
continue; // C doesn't have struct scope
if (Dsymbol s = sc.scopesym.search(loc, ident, flags))
{
- if (flags & TagNameSpace)
+ if (flags & SearchOpt.tagNameSpace)
{
// ImportC: if symbol is not a tag, look for it in tag table
if (!s.isScopeDsymbol())
@@ -486,8 +485,7 @@ extern (C++) struct Scope
}
}
//printMsg("\tfound local", s);
- if (pscopesym)
- *pscopesym = sc.scopesym;
+ pscopesym = sc.scopesym;
return s;
}
@@ -499,8 +497,7 @@ extern (C++) struct Scope
if (aliasSym)
{
//printf("found aliassym: %s\n", aliasSym.toChars());
- if (pscopesym)
- *pscopesym = new ExpressionDsymbol(exp);
+ pscopesym = new ExpressionDsymbol(exp);
return aliasSym;
}
}
@@ -513,15 +510,15 @@ extern (C++) struct Scope
}
if (this.flags & SCOPE.ignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
+ flags |= SearchOpt.ignoreVisibility;
// First look in local scopes
- Dsymbol s = searchScopes(flags | SearchLocalsOnly);
+ Dsymbol s = searchScopes(flags | SearchOpt.localsOnly);
version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s);
if (!s)
{
// Second look in imported modules
- s = searchScopes(flags | SearchImportsOnly);
+ s = searchScopes(flags | SearchOpt.importsOnly);
version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s);
}
return s;
@@ -554,8 +551,8 @@ extern (C++) struct Scope
return null;
Scope* sc = &this;
Module.clearCache();
- Dsymbol scopesym = null;
- Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors);
+ Dsymbol scopesym;
+ Dsymbol s = sc.search(Loc.initial, id, scopesym, SearchOpt.ignoreErrors);
if (!s)
return null;
@@ -579,9 +576,9 @@ extern (C++) struct Scope
return s;
}
- Dsymbol scopesym = null;
+ Dsymbol scopesym;
// search for exact name first
- if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors))
+ if (auto s = search(Loc.initial, ident, scopesym, SearchOpt.ignoreErrors))
return s;
return speller!scope_search_fp(ident.toString());
}
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 36e847c..0e0a1f5 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -289,7 +289,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
for (size_t i = 0; i < members.length; i++)
{
Dsymbol s = (*members)[i];
- s.setFieldOffset(this, fieldState, isunion);
+ s.setFieldOffset(this, &fieldState, isunion);
}
if (type.ty == Terror)
{
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 8f5a292..6613c2b 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -203,20 +203,21 @@ enum PASS : ubyte
}
// Search options
-enum : int
+alias SearchOptFlags = uint;
+enum SearchOpt : SearchOptFlags
{
- IgnoreNone = 0x00, // default
- IgnorePrivateImports = 0x01, // don't search private imports
- IgnoreErrors = 0x02, // don't give error messages
- IgnoreAmbiguous = 0x04, // return NULL if ambiguous
- SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
- SearchImportsOnly = 0x10, // only look in imports
- SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
+ all = 0x00, // search for all symbols
+ ignorePrivateImports = 0x01, // don't search private imports
+ ignoreErrors = 0x02, // don't give error messages
+ ignoreAmbiguous = 0x04, // return NULL if ambiguous
+ localsOnly = 0x08, // only look at locals (don't search imports)
+ importsOnly = 0x10, // only look in imports
+ unqualifiedModule = 0x20, // the module scope search is unqualified,
// meaning don't search imports in that scope,
// because qualified module searches search
// their imports
- IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
- TagNameSpace = 0x100, // search ImportC tag symbol table
+ tagNameSpace = 0x40, // search ImportC tag symbol table
+ ignoreVisibility = 0x80, // also find private and package protected symbols
}
/***********************************************************
@@ -712,10 +713,6 @@ extern (C++) class Dsymbol : ASTNode
return toAlias();
}
- void importAll(Scope* sc)
- {
- }
-
bool overloadInsert(Dsymbol s)
{
//printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
@@ -922,10 +919,6 @@ extern (C++) class Dsymbol : ASTNode
return true;
}
- void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
- {
- }
-
/*****************************************
* Is Dsymbol a variable that contains pointers?
*/
@@ -1263,7 +1256,7 @@ public:
(*pary)[p.tag] = true;
}
- bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
+ bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) nothrow
{
if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
@@ -1272,7 +1265,7 @@ public:
{
// only search visible scopes && imported modules should ignore private imports
if (visibility.kind <= visibilities[i] &&
- ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
+ ss.isScopeDsymbol.isPackageAccessible(p, visibility, SearchOpt.ignorePrivateImports))
return true;
}
return false;
@@ -1371,48 +1364,6 @@ public:
return false;
}
- extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
-
- /***************************************
- * Expands attribute declarations in members in depth first
- * order. Calls dg(size_t symidx, Dsymbol *sym) for each
- * member.
- * If dg returns !=0, stops and returns that value else returns 0.
- * Use this function to avoid the O(N + N^2/2) complexity of
- * calculating dim and calling N times getNth.
- * Returns:
- * last value returned by dg()
- */
- extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
- {
- assert(dg);
- if (!members)
- return 0;
- size_t n = pn ? *pn : 0; // take over index
- int result = 0;
- foreach (size_t i; 0 .. members.length)
- {
- Dsymbol s = (*members)[i];
- if (AttribDeclaration a = s.isAttribDeclaration())
- result = _foreach(sc, a.include(sc), dg, &n);
- else if (TemplateMixin tm = s.isTemplateMixin())
- result = _foreach(sc, tm.members, dg, &n);
- else if (s.isTemplateInstance())
- {
- }
- else if (s.isUnitTestDeclaration())
- {
- }
- else
- result = dg(n++, s);
- if (result)
- break;
- }
- if (pn)
- *pn = n; // update index
- return result;
- }
-
override final inout(ScopeDsymbol) isScopeDsymbol() inout
{
return this;
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 15c9970..d029c00 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -147,20 +147,21 @@ enum
/* Flags for symbol search
*/
-enum
+typedef uint SearchOptFlags;
+enum class SearchOpt : SearchOptFlags
{
- IgnoreNone = 0x00, // default
- IgnorePrivateImports = 0x01, // don't search private imports
- IgnoreErrors = 0x02, // don't give error messages
- IgnoreAmbiguous = 0x04, // return NULL if ambiguous
- SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
- SearchImportsOnly = 0x10, // only look in imports
- SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
- // meaning don't search imports in that scope,
- // because qualified module searches search
- // their imports
- IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
- TagNameSpace = 0x100, // search ImportC tag symbol table
+ all = 0x00, // default
+ ignorePrivateImports = 0x01, // don't search private imports
+ ignoreErrors = 0x02, // don't give error messages
+ ignoreAmbiguous = 0x04, // return NULL if ambiguous
+ localsOnly = 0x08, // only look at locals (don't search imports)
+ importsOnly = 0x10, // only look in imports
+ unqualifiedModule = 0x20, // the module scope search is unqualified,
+ // meaning don't search imports in that scope,
+ // because qualified module searches search
+ // their imports
+ tagNameSpace = 0x40, // search ImportC tag symbol table
+ ignoreVisibility = 0x80, // also find private and package protected symbols
};
struct FieldState
@@ -227,7 +228,6 @@ public:
virtual const char *kind() const;
virtual Dsymbol *toAlias(); // resolve real symbol
virtual Dsymbol *toAlias2();
- virtual void importAll(Scope *sc);
virtual bool overloadInsert(Dsymbol *s);
virtual uinteger_t size(const Loc &loc);
virtual bool isforwardRef();
@@ -247,7 +247,6 @@ public:
virtual Visibility visible();
virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
virtual bool oneMember(Dsymbol **ps, Identifier *ident);
- virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
virtual bool hasPointers();
virtual bool hasStaticCtorOrDtor();
virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { }
@@ -336,7 +335,7 @@ private:
public:
ScopeDsymbol *syntaxCopy(Dsymbol *s) override;
virtual void importScope(Dsymbol *s, Visibility visibility);
- virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
+ virtual bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
bool isforwardRef() override final;
static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2);
const char *kind() const override;
@@ -427,6 +426,8 @@ public:
};
void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
-Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc);
void setScope(Dsymbol *d, Scope *sc);
+void importAll(Dsymbol *d, Scope *sc);
+void setFieldOffset(Dsymbol *d, AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 060abfe..df0a9a5 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -246,6 +246,20 @@ bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc)
return true;
}
+/*********************************
+ * Check type to see if it is based on a deprecated symbol.
+ */
+private void checkDeprecated(Type type, const ref Loc loc, Scope* sc)
+{
+ if (Dsymbol s = type.toDsymbol(sc))
+ {
+ s.checkDeprecated(loc, sc);
+ }
+
+ if (auto tn = type.nextOf())
+ tn.checkDeprecated(loc, sc);
+}
+
// Returns true if a contract can appear without a function body.
package bool allowsContractWithoutBody(FuncDeclaration funcdecl)
{
@@ -304,6 +318,128 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem
return false;
}
+/*************************************
+ * Find the `alias this` symbol of e's type.
+ * Params:
+ * sc = context
+ * e = expression forming the `this`
+ * gag = do not print errors, return `null` instead
+ * findOnly = don't do further processing like resolving properties,
+ * i.e. just return plain dotExp() result.
+ * Returns:
+ * Expression that is `e.aliasthis`
+ */
+Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
+{
+ import dmd.typesem : dotExp;
+ for (AggregateDeclaration ad = isAggregate(e.type); ad;)
+ {
+ if (ad.aliasthis)
+ {
+ Loc loc = e.loc;
+ Type tthis = (e.op == EXP.type ? e.type : null);
+ const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag));
+ uint olderrors = gag ? global.startGagging() : 0;
+ e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags);
+ if (!e || findOnly)
+ return gag && global.endGagging(olderrors) ? null : e;
+
+ if (tthis && ad.aliasthis.sym.needThis())
+ {
+ if (auto ve = e.isVarExp())
+ {
+ if (auto fd = ve.var.isFuncDeclaration())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13009
+ // Support better match for the overloaded alias this.
+ bool hasOverloads;
+ if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
+ {
+ if (!hasOverloads)
+ fd = f; // use exact match
+ e = new VarExp(loc, fd, hasOverloads);
+ e.type = f.type;
+ e = new CallExp(loc, e);
+ goto L1;
+ }
+ }
+ }
+ /* non-@property function is not called inside typeof(),
+ * so resolve it ahead.
+ */
+ {
+ int save = sc.intypeof;
+ sc.intypeof = 1; // bypass "need this" error check
+ e = resolveProperties(sc, e);
+ sc.intypeof = save;
+ }
+ L1:
+ e = new TypeExp(loc, new TypeTypeof(loc, e));
+ e = e.expressionSemantic(sc);
+ }
+ e = resolveProperties(sc, e);
+ if (!gag)
+ ad.aliasthis.checkDeprecatedAliasThis(loc, sc);
+ else if (global.endGagging(olderrors))
+ e = null;
+ }
+
+ import dmd.dclass : ClassDeclaration;
+ auto cd = ad.isClassDeclaration();
+ if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
+ {
+ ad = cd.baseClass;
+ continue;
+ }
+ break;
+ }
+ return e;
+}
+
+/**
+ * Check if an `alias this` is deprecated
+ *
+ * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to
+ * check if `expression` uses a deprecated `aliasthis`, but this calls
+ * `toPrettyChars` which lead to the following message:
+ * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated"
+ *
+ * Params:
+ * at = The `AliasThis` object to check
+ * loc = `Loc` of the expression triggering the access to `at`
+ * sc = `Scope` of the expression
+ * (deprecations do not trigger in deprecated scopes)
+ *
+ * Returns:
+ * Whether the alias this was reported as deprecated.
+ */
+private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
+{
+ if (global.params.useDeprecated != DiagnosticReporting.off
+ && at.isDeprecated() && !sc.isDeprecated())
+ {
+ const(char)* message = null;
+ for (Dsymbol p = at; p; p = p.parent)
+ {
+ message = p.depdecl ? p.depdecl.getMessage() : null;
+ if (message)
+ break;
+ }
+ if (message)
+ deprecation(loc, "`alias %s this` is deprecated - %s",
+ at.sym.toChars(), message);
+ else
+ deprecation(loc, "`alias %s this` is deprecated",
+ at.sym.toChars());
+
+ if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
+ ti.printInstantiationTrace(Classification.deprecation);
+
+ return true;
+ }
+ return false;
+}
+
private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
alias visit = Visitor.visit;
@@ -359,7 +495,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
Dsymbol s = ad.search(dsym.loc, dsym.ident);
if (!s)
{
- s = sc.search(dsym.loc, dsym.ident, null);
+ Dsymbol pscopesym;
+ s = sc.search(dsym.loc, dsym.ident, pscopesym);
if (s)
error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars());
else
@@ -449,7 +586,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null");
printf(" stc = x%llx\n", dsym.storage_class);
printf(" storage_class = x%llx\n", dsym.storage_class);
- printf("linkage = %d\n", dsym.linkage);
+ printf("linkage = %d\n", dsym._linkage);
//if (strcmp(toChars(), "mul") == 0) assert(0);
}
//if (semanticRun > PASS.initial)
@@ -1494,7 +1631,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
AliasDeclaration ad = imp.aliasdecls[i];
//printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope);
- Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports);
+ Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], SearchOpt.ignorePrivateImports);
if (sym)
{
import dmd.access : symbolIsVisible;
@@ -4121,7 +4258,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// check if `_d_cmain` is defined
bool cmainTemplateExists()
{
- auto rootSymbol = sc.search(funcdecl.loc, Id.empty, null);
+ Dsymbol pscopesym;
+ auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym);
if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object))
if (moduleSymbol.search(funcdecl.loc, Id.CMain))
return true;
@@ -7206,7 +7344,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
AliasDeclaration findAliasDeclaration(AliasAssign ds, Scope* sc)
{
Dsymbol scopesym;
- Dsymbol as = sc.search(ds.loc, ds.ident, &scopesym);
+ Dsymbol as = sc.search(ds.loc, ds.ident, scopesym);
if (!as)
{
.error(ds.loc, "%s `%s` undefined identifier `%s`", ds.kind, ds.toPrettyChars, ds.ident.toChars());
@@ -7833,11 +7971,11 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope*
* d = dsymbol where ident is searched for
* loc = location to print for error messages
* ident = identifier to search for
- * flags = IgnoreXXXX
+ * flags = search options
* Returns:
* null if not found
*/
-extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone)
+extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all)
{
scope v = new SearchVisitor(loc, ident, flags);
d.accept(v);
@@ -7862,13 +8000,13 @@ Dsymbol search_correct(Dsymbol d, Identifier ident)
cost = 0; // all the same cost
Dsymbol s = d;
Module.clearCache();
- return s.search(Loc.initial, id, IgnoreErrors);
+ return s.search(Loc.initial, id, SearchOpt.ignoreErrors);
}
if (global.gag)
return null; // don't do it for speculative compiles; too time consuming
// search for exact name first
- if (auto s = d.search(Loc.initial, ident, IgnoreErrors))
+ if (auto s = d.search(Loc.initial, ident, SearchOpt.ignoreErrors))
return s;
import dmd.root.speller : speller;
@@ -7881,10 +8019,10 @@ private extern(C++) class SearchVisitor : Visitor
const Loc loc;
Identifier ident;
- int flags;
+ SearchOptFlags flags;
Dsymbol result;
- this(const ref Loc loc, Identifier ident, int flags)
+ this(const ref Loc loc, Identifier ident, SearchOptFlags flags)
{
this.loc = loc;
this.ident = ident;
@@ -7908,7 +8046,7 @@ private extern(C++) class SearchVisitor : Visitor
//if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
// Look in symbols declared in this module
- if (sds.symtab && !(flags & SearchImportsOnly))
+ if (sds.symtab && !(flags & SearchOpt.importsOnly))
{
//printf(" look in locals\n");
auto s1 = sds.symtab.lookup(ident);
@@ -7931,30 +8069,30 @@ private extern(C++) class SearchVisitor : Visitor
for (size_t i = 0; i < sds.importedScopes.length; i++)
{
// If private import, don't search it
- if ((flags & IgnorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_)
+ if ((flags & SearchOpt.ignorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_)
continue;
- int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
+ SearchOptFlags sflags = flags & (SearchOpt.ignoreErrors | SearchOpt.ignoreAmbiguous); // remember these in recursive searches
Dsymbol ss = (*sds.importedScopes)[i];
//printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
if (ss.isModule())
{
- if (flags & SearchLocalsOnly)
+ if (flags & SearchOpt.localsOnly)
continue;
}
else // mixin template
{
- if (flags & SearchImportsOnly)
+ if (flags & SearchOpt.importsOnly)
continue;
- sflags |= SearchLocalsOnly;
+ sflags |= SearchOpt.localsOnly;
}
/* Don't find private members if ss is a module
*/
- Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
+ Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? SearchOpt.ignorePrivateImports : SearchOpt.all));
import dmd.access : symbolIsVisible;
- if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2))
+ if (!s2 || !(flags & SearchOpt.ignoreVisibility) && !symbolIsVisible(sds, s2))
continue;
if (!s)
{
@@ -8025,7 +8163,7 @@ private extern(C++) class SearchVisitor : Visitor
}
}
- if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
+ if (flags & SearchOpt.ignoreAmbiguous) // if return NULL on ambiguity
return setResult(null);
/* If two imports from C import files, pick first one, as C has global name space
@@ -8033,7 +8171,7 @@ private extern(C++) class SearchVisitor : Visitor
if (s.isCsymbol() && s2.isCsymbol())
continue;
- if (!(flags & IgnoreErrors))
+ if (!(flags & SearchOpt.ignoreErrors))
ScopeDsymbol.multiplyDefined(loc, s, s2);
break;
}
@@ -8060,7 +8198,7 @@ private extern(C++) class SearchVisitor : Visitor
override void visit(WithScopeSymbol ws)
{
//printf("WithScopeSymbol.search(%s)\n", ident.toChars());
- if (flags & SearchImportsOnly)
+ if (flags & SearchOpt.importsOnly)
return setResult(null);
// Acts as proxy to the with class declaration
Dsymbol s = null;
@@ -8301,7 +8439,7 @@ private extern(C++) class SearchVisitor : Visitor
if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called
{
- if (!(flags & IgnoreErrors))
+ if (!(flags & SearchOpt.ignoreErrors))
.error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars());
return setResult(null);
}
@@ -8324,7 +8462,7 @@ private extern(C++) class SearchVisitor : Visitor
override void visit(Package pkg)
{
//printf("%s Package.search('%s', flags = x%x)\n", pkg.toChars(), ident.toChars(), flags);
- flags &= ~SearchLocalsOnly; // searching an import is always transitive
+ flags &= ~cast(int)SearchOpt.localsOnly; // searching an import is always transitive
if (!pkg.isModule() && pkg.mod)
{
// Prefer full package name.
@@ -8351,8 +8489,8 @@ private extern(C++) class SearchVisitor : Visitor
/* Qualified module searches always search their imports,
* even if SearchLocalsOnly
*/
- if (!(flags & SearchUnqualifiedModule))
- flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
+ if (!(flags & SearchOpt.unqualifiedModule))
+ flags &= ~(SearchOpt.unqualifiedModule | SearchOpt.localsOnly);
if (m.searchCacheIdent == ident && m.searchCacheFlags == flags)
{
@@ -8401,7 +8539,7 @@ private extern(C++) class SearchVisitor : Visitor
if (!sd.members || !sd.symtab) // opaque or semantic() is not yet called
{
// .stringof is always defined (but may be hidden by some other symbol)
- if(ident != Id.stringof && !(flags & IgnoreErrors) && sd.semanticRun < PASS.semanticdone)
+ if(ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && sd.semanticRun < PASS.semanticdone)
.error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars());
return setResult(null);
}
@@ -8427,7 +8565,7 @@ private extern(C++) class SearchVisitor : Visitor
if (!cd.members || !cd.symtab) // opaque or addMember is not yet done
{
// .stringof is always defined (but may be hidden by some other symbol)
- if (ident != Id.stringof && !(flags & IgnoreErrors) && cd.semanticRun < PASS.semanticdone)
+ if (ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && cd.semanticRun < PASS.semanticdone)
cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars());
//*(char*)0=0;
return setResult(null);
@@ -8437,7 +8575,7 @@ private extern(C++) class SearchVisitor : Visitor
auto s = result;
// don't search imports of base classes
- if (flags & SearchImportsOnly)
+ if (flags & SearchOpt.importsOnly)
return setResult(s);
if (s)
@@ -8462,7 +8600,7 @@ private extern(C++) class SearchVisitor : Visitor
continue;
else if (s == cd) // happens if s is nested in this and derives from this
s = null;
- else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s))
+ else if (!(flags & SearchOpt.ignoreVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s))
s = null;
else
break;
@@ -8621,3 +8759,554 @@ private extern(C++) class SetScopeVisitor : Visitor
visit(cast(AttribDeclaration)uad);
}
}
+
+extern(C++) void importAll(Dsymbol d, Scope* sc)
+{
+ scope iav = new ImportAllVisitor(sc);
+ d.accept(iav);
+}
+
+extern(C++) class ImportAllVisitor : Visitor
+{
+ alias visit = typeof(super).visit;
+ Scope* sc;
+
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ override void visit(Dsymbol d) {}
+
+ override void visit(Import imp)
+ {
+ if (imp.mod) return; // Already done
+
+ /*
+ * https://issues.dlang.org/show_bug.cgi?id=15525
+ *
+ * Loading the import has failed,
+ * most likely because of parsing errors.
+ * Therefore we cannot trust the resulting AST.
+ */
+ if (imp.load(sc))
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=23873
+ // For imports that are not at module or function level,
+ // e.g. aggregate level, the import symbol is added to the
+ // symbol table and later semantic is performed on it.
+ // This leads to semantic analysis on an malformed AST
+ // which causes all kinds of segfaults.
+ // The fix is to note that the module has errors and avoid
+ // semantic analysis on it.
+ if(imp.mod)
+ imp.mod.errors = true;
+ return;
+ }
+
+ if (!imp.mod) return; // Failed
+
+ if (sc.stc & STC.static_)
+ imp.isstatic = true;
+ imp.mod.importAll(null);
+ imp.mod.checkImportDeprecation(imp.loc, sc);
+ if (sc.explicitVisibility)
+ imp.visibility = sc.visibility;
+ if (!imp.isstatic && !imp.aliasId && !imp.names.length)
+ sc.scopesym.importScope(imp.mod, imp.visibility);
+ // Enable access to pkgs/mod as soon as posible, because compiler
+ // can traverse them before the import gets semantic (Issue: 21501)
+ if (!imp.aliasId && !imp.names.length)
+ imp.addPackageAccess(sc.scopesym);
+ }
+
+ override void visit(Module m)
+ {
+ //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", m, m.toChars(), m.parent);
+ if (m._scope)
+ return; // already done
+ if (m.filetype == FileType.ddoc)
+ {
+ error(m.loc, "%s `%s` is a Ddoc file, cannot import it", m.kind, m.toPrettyChars);
+ return;
+ }
+
+ /* Note that modules get their own scope, from scratch.
+ * This is so regardless of where in the syntax a module
+ * gets imported, it is unaffected by context.
+ * Ignore prevsc.
+ */
+ Scope* sc = Scope.createGlobal(m, global.errorSink); // create root scope
+
+ if (m.md && m.md.msg)
+ m.md.msg = semanticString(sc, m.md.msg, "deprecation message");
+
+ // Add import of "object", even for the "object" module.
+ // If it isn't there, some compiler rewrites, like
+ // classinst == classinst -> .object.opEquals(classinst, classinst)
+ // would fail inside object.d.
+ if (m.filetype != FileType.c &&
+ (m.members.length == 0 ||
+ (*m.members)[0].ident != Id.object ||
+ (*m.members)[0].isImport() is null))
+ {
+ auto im = new Import(Loc.initial, null, Id.object, null, 0);
+ m.members.shift(im);
+ }
+ if (!m.symtab)
+ {
+ // Add all symbols into module's symbol table
+ m.symtab = new DsymbolTable();
+ for (size_t i = 0; i < m.members.length; i++)
+ {
+ Dsymbol s = (*m.members)[i];
+ s.addMember(sc, sc.scopesym);
+ }
+ }
+ // anything else should be run after addMember, so version/debug symbols are defined
+ /* Set scope for the symbols so that if we forward reference
+ * a symbol, it can possibly be resolved on the spot.
+ * If this works out well, it can be extended to all modules
+ * before any semantic() on any of them.
+ */
+ m.setScope(sc); // remember module scope for semantic
+ for (size_t i = 0; i < m.members.length; i++)
+ {
+ Dsymbol s = (*m.members)[i];
+ s.setScope(sc);
+ }
+ for (size_t i = 0; i < m.members.length; i++)
+ {
+ Dsymbol s = (*m.members)[i];
+ s.importAll(sc);
+ }
+ sc = sc.pop();
+ sc.pop(); // 2 pops because Scope.createGlobal() created 2
+ }
+
+ override void visit(AttribDeclaration atb)
+ {
+ Dsymbols* d = atb.include(sc);
+ //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
+ if (d)
+ {
+ Scope* sc2 = atb.newScope(sc);
+ d.foreachDsymbol( s => s.importAll(sc2) );
+ if (sc2 != sc)
+ sc2.pop();
+ }
+ }
+
+ // do not evaluate condition before semantic pass
+ override void visit(StaticIfDeclaration _) {}
+ // do not evaluate aggregate before semantic pass
+ override void visit(StaticForeachDeclaration _) {}
+}
+
+extern(C++) void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion)
+{
+ scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion);
+ d.accept(v);
+}
+
+private extern(C++) class SetFieldOffsetVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ AggregateDeclaration ad;
+ FieldState* fieldState;
+ bool isunion;
+
+ this(AggregateDeclaration ad, FieldState* fieldState, bool isunion)
+ {
+ this.ad = ad;
+ this.fieldState = fieldState;
+ this.isunion = isunion;
+ }
+
+ override void visit(Dsymbol d) {}
+
+ override void visit(Nspace ns)
+ {
+ //printf("Nspace::setFieldOffset() %s\n", toChars());
+ if (ns._scope) // if fwd reference
+ dsymbolSemantic(ns, null); // try to resolve it
+ ns.members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
+ }
+
+ override void visit(VarDeclaration vd)
+ {
+ //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), vd.toChars());
+
+ if (vd.aliasTuple)
+ {
+ // If this variable was really a tuple, set the offsets for the tuple fields
+ vd.aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
+ return;
+ }
+
+ if (!vd.isField())
+ return;
+ assert(!(vd.storage_class & (STC.static_ | STC.extern_ | STC.parameter)));
+
+ //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
+
+ /* Fields that are tuples appear both as part of TupleDeclarations and
+ * as members. That means ignore them if they are already a field.
+ */
+ if (vd.offset)
+ {
+ // already a field
+ fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
+ return;
+ }
+ for (size_t i = 0; i < ad.fields.length; i++)
+ {
+ if (ad.fields[i] == vd)
+ {
+ // already a field
+ fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
+ return;
+ }
+ }
+
+ // Check for forward referenced types which will fail the size() call
+ Type t = vd.type.toBasetype();
+ if (vd.storage_class & STC.ref_)
+ {
+ // References are the size of a pointer
+ t = Type.tvoidptr;
+ }
+ Type tv = t.baseElemOf();
+ if (tv.ty == Tstruct)
+ {
+ auto ts = cast(TypeStruct)tv;
+ assert(ts.sym != ad); // already checked in ad.determineFields()
+ if (!ts.sym.determineSize(vd.loc))
+ {
+ vd.type = Type.terror;
+ vd.errors = true;
+ return;
+ }
+ }
+
+ // List in ad.fields. Even if the type is error, it's necessary to avoid
+ // pointless error diagnostic "more initializers than fields" on struct literal.
+ ad.fields.push(vd);
+
+ if (t.ty == Terror)
+ return;
+
+ /* If coming after a bit field in progress,
+ * advance past the field
+ */
+ fieldState.inFlight = false;
+
+ const sz = t.size(vd.loc);
+ assert(sz != SIZE_INVALID && sz < uint.max);
+ uint memsize = cast(uint)sz; // size of member
+ uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
+ vd.offset = placeField(
+ fieldState.offset,
+ memsize, memalignsize, vd.alignment,
+ ad.structsize, ad.alignsize,
+ isunion);
+
+ //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
+ //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
+ }
+
+ override void visit(BitFieldDeclaration bfd)
+ {
+ enum log = false;
+ static if (log)
+ {
+ printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), bfd.toChars());
+ void print(const FieldState* fieldState)
+ {
+ fieldState.print();
+ printf(" fieldWidth = %d bits\n", bfd.fieldWidth);
+ }
+ print(fieldState);
+ }
+
+ Type t = bfd.type.toBasetype();
+ const bool anon = bfd.isAnonymous();
+
+ // List in ad.fields. Even if the type is error, it's necessary to avoid
+ // pointless error diagnostic "more initializers than fields" on struct literal.
+ if (!anon)
+ ad.fields.push(bfd);
+
+ if (t.ty == Terror)
+ return;
+
+ const sz = t.size(bfd.loc);
+ assert(sz != SIZE_INVALID && sz < uint.max);
+ uint memsize = cast(uint)sz; // size of member
+ uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
+ if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize);
+
+ if (bfd.fieldWidth == 0 && !anon)
+ error(bfd.loc, "named bit fields cannot have 0 width");
+ if (bfd.fieldWidth > memsize * 8)
+ error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth);
+
+ const style = target.c.bitFieldStyle;
+
+ void startNewField()
+ {
+ if (log) printf("startNewField()\n");
+ uint alignsize;
+ if (style == TargetC.BitFieldStyle.Gcc_Clang)
+ {
+ if (bfd.fieldWidth > 32)
+ alignsize = memalignsize;
+ else if (bfd.fieldWidth > 16)
+ alignsize = 4;
+ else if (bfd.fieldWidth > 8)
+ alignsize = 2;
+ else
+ alignsize = 1;
+ }
+ else
+ alignsize = memsize; // not memalignsize
+
+ uint dummy;
+ bfd.offset = placeField(
+ fieldState.offset,
+ memsize, alignsize, bfd.alignment,
+ ad.structsize,
+ (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
+ isunion);
+
+ fieldState.inFlight = true;
+ fieldState.fieldOffset = bfd.offset;
+ fieldState.bitOffset = 0;
+ fieldState.fieldSize = memsize;
+ }
+
+ if (style == TargetC.BitFieldStyle.Gcc_Clang)
+ {
+ if (bfd.fieldWidth == 0)
+ {
+ if (!isunion)
+ {
+ // Use type of zero width field to align to next field
+ fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
+ ad.structsize = fieldState.offset;
+ }
+
+ fieldState.inFlight = false;
+ return;
+ }
+
+ if (ad.alignsize == 0)
+ ad.alignsize = 1;
+ if (!anon &&
+ ad.alignsize < memalignsize)
+ ad.alignsize = memalignsize;
+ }
+ else if (style == TargetC.BitFieldStyle.MS)
+ {
+ if (ad.alignsize == 0)
+ ad.alignsize = 1;
+ if (bfd.fieldWidth == 0)
+ {
+ if (fieldState.inFlight && !isunion)
+ {
+ // documentation says align to next int
+ //const alsz = cast(uint)Type.tint32.size();
+ const alsz = memsize; // but it really does this
+ fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+ ad.structsize = fieldState.offset;
+ }
+
+ fieldState.inFlight = false;
+ return;
+ }
+ }
+ else if (style == TargetC.BitFieldStyle.DM)
+ {
+ if (anon && bfd.fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
+ return; // this probably should be a bug in DMC
+ if (ad.alignsize == 0)
+ ad.alignsize = 1;
+ if (bfd.fieldWidth == 0)
+ {
+ if (fieldState.inFlight && !isunion)
+ {
+ const alsz = memsize;
+ fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+ ad.structsize = fieldState.offset;
+ }
+
+ fieldState.inFlight = false;
+ return;
+ }
+ }
+
+ if (!fieldState.inFlight)
+ {
+ //printf("not in flight\n");
+ startNewField();
+ }
+ else if (style == TargetC.BitFieldStyle.Gcc_Clang)
+ {
+ // If the bit-field spans more units of alignment than its type,
+ // start a new field at the next alignment boundary.
+ if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
+ fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8)
+ {
+ if (log) printf("more units of alignment than its type\n");
+ startNewField(); // the bit field is full
+ }
+ else
+ {
+ // if alignment boundary is crossed
+ uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
+ uint end = start + bfd.fieldWidth;
+ //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
+ if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
+ {
+ if (log) printf("alignment is crossed\n");
+ startNewField();
+ }
+ }
+ }
+ else if (style == TargetC.BitFieldStyle.DM ||
+ style == TargetC.BitFieldStyle.MS)
+ {
+ if (memsize != fieldState.fieldSize ||
+ fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8)
+ {
+ //printf("new field\n");
+ startNewField();
+ }
+ }
+ else
+ assert(0);
+
+ bfd.offset = fieldState.fieldOffset;
+ bfd.bitOffset = fieldState.bitOffset;
+
+ const pastField = bfd.bitOffset + bfd.fieldWidth;
+ if (style == TargetC.BitFieldStyle.Gcc_Clang)
+ {
+ auto size = (pastField + 7) / 8;
+ fieldState.fieldSize = size;
+ //printf(" offset: %d, size: %d\n", offset, size);
+ if (isunion)
+ {
+ const newstructsize = bfd.offset + size;
+ if (newstructsize > ad.structsize)
+ ad.structsize = newstructsize;
+ }
+ else
+ ad.structsize = bfd.offset + size;
+ }
+ else
+ fieldState.fieldSize = memsize;
+ //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
+ //print(fieldState);
+
+ if (!isunion)
+ {
+ fieldState.offset = bfd.offset + fieldState.fieldSize;
+ fieldState.bitOffset = pastField;
+ }
+
+ //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize);
+ //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
+ //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
+ }
+
+ override void visit(TemplateMixin tm)
+ {
+ //printf("TemplateMixin.setFieldOffset() %s\n", tm.toChars());
+ if (tm._scope) // if fwd reference
+ dsymbolSemantic(tm, null); // try to resolve it
+
+ tm.members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
+ }
+
+ override void visit(AttribDeclaration atd)
+ {
+ atd.include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
+ }
+
+ override void visit(AnonDeclaration anond)
+ {
+ //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", anond);
+ if (anond.decl)
+ {
+ /* This works by treating an AnonDeclaration as an aggregate 'member',
+ * so in order to place that member we need to compute the member's
+ * size and alignment.
+ */
+ size_t fieldstart = ad.fields.length;
+
+ /* Hackishly hijack ad's structsize and alignsize fields
+ * for use in our fake anon aggregate member.
+ */
+ uint savestructsize = ad.structsize;
+ uint savealignsize = ad.alignsize;
+ ad.structsize = 0;
+ ad.alignsize = 0;
+
+ FieldState fs;
+ anond.decl.foreachDsymbol( (s)
+ {
+ s.setFieldOffset(ad, &fs, anond.isunion);
+ if (anond.isunion)
+ fs.offset = 0;
+ });
+
+ /* https://issues.dlang.org/show_bug.cgi?id=13613
+ * If the fields in this.members had been already
+ * added in ad.fields, just update *poffset for the subsequent
+ * field offset calculation.
+ */
+ if (fieldstart == ad.fields.length)
+ {
+ ad.structsize = savestructsize;
+ ad.alignsize = savealignsize;
+ fieldState.offset = ad.structsize;
+ return;
+ }
+
+ anond.anonstructsize = ad.structsize;
+ anond.anonalignsize = ad.alignsize;
+ ad.structsize = savestructsize;
+ ad.alignsize = savealignsize;
+
+ // 0 sized structs are set to 1 byte
+ if (anond.anonstructsize == 0)
+ {
+ anond.anonstructsize = 1;
+ anond.anonalignsize = 1;
+ }
+
+ assert(anond._scope);
+ auto alignment = anond._scope.alignment();
+
+ /* Given the anon 'member's size and alignment,
+ * go ahead and place it.
+ */
+ anond.anonoffset = placeField(
+ fieldState.offset,
+ anond.anonstructsize, anond.anonalignsize, alignment,
+ ad.structsize, ad.alignsize,
+ isunion);
+
+ // Add to the anon fields the base offset of this anonymous aggregate
+ //printf("anon fields, anonoffset = %d\n", anonoffset);
+ foreach (const i; fieldstart .. ad.fields.length)
+ {
+ VarDeclaration v = ad.fields[i];
+ //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
+ v.offset += anond.anonoffset;
+ }
+ }
+ }
+}
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 326d663..e440b9e 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -6465,7 +6465,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
*/
Identifier id = name;
Dsymbol scopesym;
- Dsymbol s = sc.search(loc, id, &scopesym);
+ Dsymbol s = sc.search(loc, id, scopesym);
if (!s)
{
s = sc.search_correct(id);
@@ -7831,15 +7831,6 @@ extern (C++) final class TemplateMixin : TemplateInstance
return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
}
- override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
- {
- //printf("TemplateMixin.setFieldOffset() %s\n", toChars());
- if (_scope) // if fwd reference
- dsymbolSemantic(this, null); // try to resolve it
-
- members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
- }
-
override const(char)* toChars() const
{
OutBuffer buf;
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 9f85574..ed83a8d 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -3284,7 +3284,7 @@ ASTCodegen.Dsymbol symbolFromType(ASTCodegen.Type t) @safe
*/
ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name)
{
- if (auto mem = sym.search(Loc.initial, name, ASTCodegen.IgnoreErrors))
+ if (auto mem = sym.search(Loc.initial, name, ASTCodegen.SearchOpt.ignoreErrors))
return mem;
// search doesn't work for declarations inside of uninstantiated
diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d
index ce23517..3811f1d 100644
--- a/gcc/d/dmd/errorsink.d
+++ b/gcc/d/dmd/errorsink.d
@@ -61,6 +61,20 @@ class ErrorSinkNull : ErrorSink
}
/*****************************************
+ * Ignores the messages, but sets `sawErrors` for any calls to `error()`
+ */
+class ErrorSinkLatch : ErrorSinkNull
+{
+ nothrow:
+ extern (C++):
+ override:
+
+ bool sawErrors;
+
+ void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; }
+}
+
+/*****************************************
* Simplest implementation, just sends messages to stderr.
* See also: ErrorSinkCompiler.
*/
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index cd93e54..f51a8b0 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -21,7 +21,6 @@ import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
-import dmd.gluelayer;
import dmd.dclass;
import dmd.declaration;
import dmd.dimport;
@@ -2240,7 +2239,7 @@ extern (C++) final class StructLiteralExp : Expression
// while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
union
{
- Symbol* sym; /// back end symbol to initialize with literal
+ void* sym; /// back end symbol to initialize with literal (used as a Symbol*)
/// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
StructLiteralExp inlinecopy;
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 1664bf2..c21b382 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -875,7 +875,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
Loc loc = ue.loc;
// TODO: merge with Scope.search.searchScopes()
- Dsymbol searchScopes(int flags)
+ Dsymbol searchScopes(SearchOptFlags flags)
{
Dsymbol s = null;
for (Scope* scx = sc; scx; scx = scx.enclosing)
@@ -883,7 +883,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
if (!scx.scopesym)
continue;
if (scx.scopesym.isModule())
- flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
+ flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed
s = scx.scopesym.search(loc, ident, flags);
if (s)
{
@@ -910,18 +910,18 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
return s;
}
- int flags = 0;
+ SearchOptFlags flags = SearchOpt.all;
Dsymbol s;
if (sc.flags & SCOPE.ignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
+ flags |= SearchOpt.ignoreVisibility;
// First look in local scopes
- s = searchScopes(flags | SearchLocalsOnly);
+ s = searchScopes(flags | SearchOpt.localsOnly);
if (!s)
{
// Second look in imported modules
- s = searchScopes(flags | SearchImportsOnly);
+ s = searchScopes(flags | SearchOpt.importsOnly);
}
if (!s)
@@ -3743,7 +3743,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Dsymbol scopesym;
- Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
+ Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
if (s)
{
if (s.errors)
@@ -6744,7 +6744,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!sc.insert(s))
{
- auto conflict = sc.search(Loc.initial, s.ident, null);
+ Dsymbol pscopesym;
+ auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
conflict.kind(), conflict.toChars());
@@ -6986,7 +6987,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (!tup && !sc.insert(s))
{
- auto conflict = sc.search(Loc.initial, s.ident, null);
+ Dsymbol pscopesym;
+ auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
conflict.kind(), conflict.toChars());
@@ -7293,7 +7295,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
s.dsymbolSemantic(sc);
if (!sc.insert(s))
{
- auto conflict = sc.search(Loc.initial, s.ident, null);
+ Dsymbol pscopesym;
+ auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
conflict.kind(), conflict.toChars());
@@ -14208,15 +14211,15 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
if (auto ie = eright.isScopeExp()) // also used for template alias's
{
- auto flags = SearchLocalsOnly;
+ SearchOptFlags flags = SearchOpt.localsOnly;
/* Disable access to another module's private imports.
* The check for 'is sds our current module' is because
* the current module should have access to its own imports.
*/
if (ie.sds.isModule() && ie.sds != sc._module)
- flags |= IgnorePrivateImports;
+ flags |= SearchOpt.ignorePrivateImports;
if (sc.flags & SCOPE.ignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
+ flags |= SearchOpt.ignoreVisibility;
Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
/* Check for visibility before resolving aliases because public
* aliases to private symbols are public.
@@ -16038,7 +16041,8 @@ VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration f
*/
bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
{
- auto rootSymbol = sc.search(loc, Id.empty, null);
+ Dsymbol pscopesym;
+ auto rootSymbol = sc.search(loc, Id.empty, pscopesym);
if (auto moduleSymbol = rootSymbol.search(loc, module_))
if (moduleSymbol.search(loc, id))
return true;
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 351faa47..feaa5bb 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -695,6 +695,7 @@ extern (C++) class FuncDeclaration : Declaration
int result = 0;
if (fd.ident == ident)
{
+ import dmd.typesem : covariant;
const cov = type.covariant(fd.type);
if (cov != Covariant.distinct)
{
@@ -721,6 +722,8 @@ extern (C++) class FuncDeclaration : Declaration
final int findVtblIndex(Dsymbols* vtbl, int dim)
{
//printf("findVtblIndex() %s\n", toChars());
+ import dmd.typesem : covariant;
+
FuncDeclaration mismatch = null;
StorageClass mismatchstc = 0;
int mismatchvi = -1;
@@ -947,6 +950,7 @@ extern (C++) class FuncDeclaration : Declaration
*/
if (t.ty == Tfunction)
{
+ import dmd.typesem : covariant;
auto tf = cast(TypeFunction)f.type;
if (tf.covariant(t) == Covariant.yes &&
tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
@@ -1157,6 +1161,7 @@ extern (C++) class FuncDeclaration : Declaration
args.push(e);
}
+ import dmd.typesem : callMatch;
MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
if (m > MATCH.nomatch)
{
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index 8d88207..9257bc4 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -167,7 +167,7 @@ extern (C++) struct Param
bool cov; // generate code coverage data
ubyte covPercent; // 0..100 code coverage percentage required
bool ctfe_cov = false; // generate coverage data for ctfe
- bool ignoreUnsupportedPragmas; // rather than error on them
+ bool ignoreUnsupportedPragmas = true; // rather than error on them
bool useModuleInfo = true; // generate runtime module information
bool useTypeInfo = true; // generate runtime type information
bool useExceptions = true; // support exception handling
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
index 624cd74..2a02f13 100644
--- a/gcc/d/dmd/import.h
+++ b/gcc/d/dmd/import.h
@@ -41,7 +41,6 @@ public:
const char *kind() const override;
Visibility visible() override;
Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees
- void importAll(Scope *sc) override;
Dsymbol *toAlias() override;
bool overloadInsert(Dsymbol *s) override;
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index e484100..5aefb00 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -12,21 +12,15 @@
module dmd.init;
import core.stdc.stdio;
-import core.checkedint;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
-import dmd.dsymbol;
import dmd.expression;
-import dmd.globals;
-import dmd.hdrgen;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
-import dmd.common.outbuffer;
import dmd.rootobject;
-import dmd.tokens;
import dmd.visitor;
enum NeedInterpret : int
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 6d31f95..19d576d 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -606,7 +606,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
import dmd.common.outbuffer;
OutBuffer buf;
- HdrGenStage hgs;
+ HdrGenState hgs;
toCBuffer(ts.sym, buf, hgs);
printf("%s\n", buf.peekChars());
}
@@ -803,9 +803,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
Loop1:
for (size_t index = 0; index < ci.initializerList.length; )
{
- CInitializer cprev;
- size_t indexprev;
- L1:
DesigInit di = ci.initializerList[index];
Designators* dlist = di.designatorList;
if (dlist)
@@ -833,15 +830,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
continue Loop1;
}
}
- if (cprev)
- {
- /* The peeling didn't work, so unpeel it
- */
- ci = cprev;
- index = indexprev;
- di = ci.initializerList[index];
- goto L2;
- }
error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars());
return err();
}
@@ -849,18 +837,55 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
if (fieldi == nfields)
break;
- if (/*index == 0 && ci.initializerList.length == 1 &&*/ di.initializer.isCInitializer())
+
+ auto ix = di.initializer;
+
+ /* If a C initializer is wrapped in a C initializer, with no designators,
+ * peel off the outer one
+ */
+ if (ix.isCInitializer())
+ {
+ CInitializer cix = ix.isCInitializer();
+ if (cix.initializerList.length == 1)
+ {
+ DesigInit dix = cix.initializerList[0];
+ if (!dix.designatorList)
+ {
+ Initializer inix = dix.initializer;
+ if (inix.isCInitializer())
+ ix = inix;
+ }
+ }
+ }
+
+ if (auto cix = ix.isCInitializer())
{
- /* Try peeling off this set of { } and see if it works
+ /* ImportC loses the structure from anonymous structs, but this is retained
+ * by the initializer syntax. if a CInitializer has a Designator, it is probably
+ * a nested anonymous struct
*/
- cprev = ci;
- ci = di.initializer.isCInitializer();
- indexprev = index;
- index = 0;
- goto L1;
+ if (cix.initializerList.length)
+ {
+ DesigInit dix = cix.initializerList[0];
+ Designators* dlistx = dix.designatorList;
+ if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident)
+ {
+ auto id = (*dlistx)[0].ident;
+ foreach (k, f; sd.fields[]) // linear search for now
+ {
+ if (f.ident == id)
+ {
+ fieldi = k;
+ si.addInit(id, dix.initializer);
+ ++fieldi;
+ ++index;
+ continue Loop1;
+ }
+ }
+ }
+ }
}
- L2:
VarDeclaration field;
while (1) // skip field if it overlaps with previously seen fields
{
@@ -871,10 +896,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
if (fieldi == nfields)
break;
}
+
auto tn = field.type.toBasetype();
auto tnsa = tn.isTypeSArray();
auto tns = tn.isTypeStruct();
- auto ix = di.initializer;
+
if (tnsa && ix.isExpInitializer())
{
ExpInitializer ei = ix.isExpInitializer();
@@ -1013,7 +1039,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
}
else
{
- error(ci.loc, "unrecognized C initializer `%s`", toChars(ci));
+ error(ci.loc, "unrecognized C initializer `%s` for type `%s`", toChars(ci), t.toChars());
return err();
}
}
@@ -1548,6 +1574,11 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope*
cast(int) nfields, nfields != 1 ? "s".ptr : "".ptr);
return null;
}
+ if (fieldi >= nfields)
+ {
+ error(argLoc, "trying to initialize past the last field `%s` of `%s`", sd.fields[nfields - 1].toChars(), sd.toChars());
+ return null;
+ }
VarDeclaration vd = sd.fields[fieldi];
if (elems[fieldi])
diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d
index d19d435..c90c360 100644
--- a/gcc/d/dmd/lambdacomp.d
+++ b/gcc/d/dmd/lambdacomp.d
@@ -244,7 +244,7 @@ public:
{
// we must check what the identifier expression is.
Dsymbol scopesym;
- Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
+ Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
if (s)
{
auto v = s.isVarDeclaration();
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index b8faec7..2c6a595 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -2008,23 +2008,17 @@ class Lexer
case 'u':
dchar d1;
size_t idx;
- auto msg = utf_decodeChar(str, idx, d1);
- dchar d2 = 0;
- if (idx < n && !msg)
- msg = utf_decodeChar(str, idx, d2);
- if (msg)
- error(loc, "%.*s", cast(int)msg.length, msg.ptr);
- else if (idx < n)
- error(loc, "max number of chars in 16 bit character literal is 2, had %d",
- cast(int)((n + 1) >> 1));
- else if (d1 > 0x1_0000)
- error(loc, "%d does not fit in 16 bits", d1);
- else if (d2 > 0x1_0000)
- error(loc, "%d does not fit in 16 bits", d2);
- u = d1;
- if (d2)
- u = (d1 << 16) | d2;
- break;
+ while (idx < n)
+ {
+ string msg = utf_decodeChar(str, idx, d1);
+ if (msg)
+ error(loc, "%.*s", cast(int)msg.length, msg.ptr);
+ }
+ if (d1 >= 0x1_0000)
+ error(loc, "x%x does not fit in 16 bits", d1);
+ t.unsvalue = d1;
+ t.value = TOK.wcharLiteral; // C11 6.4.4.4-9
+ return;
case 'U':
dchar d;
@@ -2035,8 +2029,9 @@ class Lexer
else if (idx < n)
error(loc, "max number of chars in 32 bit character literal is 1, had %d",
cast(int)((n + 3) >> 2));
- u = d;
- break;
+ t.unsvalue = d;
+ t.value = TOK.dcharLiteral; // C11 6.4.4.4-9
+ return;
default:
assert(0);
@@ -3270,7 +3265,7 @@ class Lexer
while (1)
{
printf("%s ", (*tk).toChars());
- if (tk.value == TOK.endOfFile)
+ if (tk.value == TOK.endOfFile || tk.value == TOK.endOfLine)
break;
tk = peek(tk);
}
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index cab0b0a..80a6ea2 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -88,7 +88,7 @@ public:
Identifier *searchCacheIdent;
Dsymbol *searchCacheSymbol; // cached value of search
- int searchCacheFlags; // cached flags
+ SearchOptFlags searchCacheFlags; // cached flags
d_bool insearch;
// module from command line we're imported from,
@@ -121,9 +121,8 @@ public:
const char *kind() const override;
bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise.
Module *parse(); // syntactic parse
- void importAll(Scope *sc) override;
int needModuleInfo();
- bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override;
+ bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all) override;
Dsymbol *symtabInsert(Dsymbol *s) override;
static void runDeferredSemantic();
static void runDeferredSemantic2();
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 8860f14..626bf74 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -19,7 +19,6 @@ import core.stdc.string;
import dmd.aggregate;
import dmd.arraytypes;
-import dmd.attrib;
import dmd.astenums;
import dmd.ast_node;
import dmd.gluelayer;
@@ -35,7 +34,6 @@ import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
-import dmd.expressionsem;
import dmd.func;
import dmd.globals;
import dmd.hdrgen;
@@ -522,262 +520,6 @@ extern (C++) abstract class Type : ASTNode
return mcache;
}
- /*******************************
- * Covariant means that 'this' can substitute for 't',
- * i.e. a pure function is a match for an impure type.
- * Params:
- * t = type 'this' is covariant with
- * pstc = if not null, store STCxxxx which would make it covariant
- * cppCovariant = true if extern(C++) function types should follow C++ covariant rules
- * Returns:
- * An enum value of either `Covariant.yes` or a reason it's not covariant.
- */
- final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false)
- {
- version (none)
- {
- printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars());
- printf("deco = %p, %p\n", deco, t.deco);
- // printf("ty = %d\n", next.ty);
- printf("mod = %x, %x\n", mod, t.mod);
- }
- if (pstc)
- *pstc = 0;
- StorageClass stc = 0;
-
- bool notcovariant = false;
-
- if (equals(t))
- return Covariant.yes;
-
- TypeFunction t1 = this.isTypeFunction();
- TypeFunction t2 = t.isTypeFunction();
-
- if (!t1 || !t2)
- goto Ldistinct;
-
- if (t1.parameterList.varargs != t2.parameterList.varargs)
- goto Ldistinct;
-
- if (t1.parameterList.parameters && t2.parameterList.parameters)
- {
- if (t1.parameterList.length != t2.parameterList.length)
- goto Ldistinct;
-
- foreach (i, fparam1; t1.parameterList)
- {
- Parameter fparam2 = t2.parameterList[i];
- Type tp1 = fparam1.type;
- Type tp2 = fparam2.type;
-
- if (!tp1.equals(tp2))
- {
- if (tp1.ty == tp2.ty)
- {
- if (auto tc1 = tp1.isTypeClass())
- {
- if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
- goto Lcov;
- }
- else if (auto ts1 = tp1.isTypeStruct())
- {
- if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
- goto Lcov;
- }
- else if (tp1.ty == Tpointer)
- {
- if (tp2.implicitConvTo(tp1))
- goto Lcov;
- }
- else if (tp1.ty == Tarray)
- {
- if (tp2.implicitConvTo(tp1))
- goto Lcov;
- }
- else if (tp1.ty == Tdelegate)
- {
- if (tp2.implicitConvTo(tp1))
- goto Lcov;
- }
- }
- goto Ldistinct;
- }
- Lcov:
- notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
-
- /* https://issues.dlang.org/show_bug.cgi?id=23135
- * extern(C++) mutable parameters are not covariant with const.
- */
- if (t1.linkage == LINK.cpp && cppCovariant)
- {
- notcovariant |= tp1.isNaked() != tp2.isNaked();
- if (auto tpn1 = tp1.nextOf())
- notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
- }
- }
- }
- else if (t1.parameterList.parameters != t2.parameterList.parameters)
- {
- if (t1.parameterList.length || t2.parameterList.length)
- goto Ldistinct;
- }
-
- // The argument lists match
- if (notcovariant)
- goto Lnotcovariant;
- if (t1.linkage != t2.linkage)
- goto Lnotcovariant;
-
- {
- // Return types
- Type t1n = t1.next;
- Type t2n = t2.next;
-
- if (!t1n || !t2n) // happens with return type inference
- goto Lnotcovariant;
-
- if (t1n.equals(t2n))
- goto Lcovariant;
- if (t1n.ty == Tclass && t2n.ty == Tclass)
- {
- /* If same class type, but t2n is const, then it's
- * covariant. Do this test first because it can work on
- * forward references.
- */
- if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
- goto Lcovariant;
-
- // If t1n is forward referenced:
- ClassDeclaration cd = (cast(TypeClass)t1n).sym;
- if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
- cd.dsymbolSemantic(null);
- if (!cd.isBaseInfoComplete())
- {
- return Covariant.fwdref;
- }
- }
- if (t1n.ty == Tstruct && t2n.ty == Tstruct)
- {
- if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
- goto Lcovariant;
- }
- else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
- {
- if (t1.isref && t2.isref)
- {
- // Treat like pointers to t1n and t2n
- if (t1n.constConv(t2n) < MATCH.constant)
- goto Lnotcovariant;
- }
- goto Lcovariant;
- }
- else if (t1n.ty == Tnull)
- {
- // NULL is covariant with any pointer type, but not with any
- // dynamic arrays, associative arrays or delegates.
- // https://issues.dlang.org/show_bug.cgi?id=8589
- // https://issues.dlang.org/show_bug.cgi?id=19618
- Type t2bn = t2n.toBasetype();
- if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
- goto Lcovariant;
- }
- // bottom type is covariant to any type
- else if (t1n.ty == Tnoreturn)
- goto Lcovariant;
- }
- goto Lnotcovariant;
-
- Lcovariant:
- if (t1.isref != t2.isref)
- goto Lnotcovariant;
-
- if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
- {
- StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
- StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
- if (t1.isreturn)
- {
- stc1 |= STC.return_;
- if (!t1.isScopeQual)
- stc1 |= STC.ref_;
- }
- if (t2.isreturn)
- {
- stc2 |= STC.return_;
- if (!t2.isScopeQual)
- stc2 |= STC.ref_;
- }
- if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
- goto Lnotcovariant;
- }
-
- // We can subtract 'return ref' from 'this', but cannot add it
- else if (t1.isreturn && !t2.isreturn)
- goto Lnotcovariant;
-
- /* https://issues.dlang.org/show_bug.cgi?id=23135
- * extern(C++) mutable member functions are not covariant with const.
- */
- if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
- goto Lnotcovariant;
-
- /* Can convert mutable to const
- */
- if (!MODimplicitConv(t2.mod, t1.mod))
- {
- version (none)
- {
- //stop attribute inference with const
- // If adding 'const' will make it covariant
- if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
- stc |= STC.const_;
- else
- goto Lnotcovariant;
- }
- else
- {
- goto Ldistinct;
- }
- }
-
- /* Can convert pure to impure, nothrow to throw, and nogc to gc
- */
- if (!t1.purity && t2.purity)
- stc |= STC.pure_;
-
- if (!t1.isnothrow && t2.isnothrow)
- stc |= STC.nothrow_;
-
- if (!t1.isnogc && t2.isnogc)
- stc |= STC.nogc;
-
- /* Can convert safe/trusted to system
- */
- if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
- {
- // Should we infer trusted or safe? Go with safe.
- stc |= STC.safe;
- }
-
- if (stc)
- {
- if (pstc)
- *pstc = stc;
- goto Lnotcovariant;
- }
-
- //printf("\tcovaraint: 1\n");
- return Covariant.yes;
-
- Ldistinct:
- //printf("\tcovaraint: 0\n");
- return Covariant.distinct;
-
- Lnotcovariant:
- //printf("\tcovaraint: 2\n");
- return Covariant.no;
- }
-
/********************************
* For pretty-printing a type.
*/
@@ -1061,17 +803,6 @@ extern (C++) abstract class Type : ASTNode
return isscalar();
}
- /*********************************
- * Check type to see if it is based on a deprecated symbol.
- */
- void checkDeprecated(const ref Loc loc, Scope* sc)
- {
- if (Dsymbol s = toDsymbol(sc))
- {
- s.checkDeprecated(loc, sc);
- }
- }
-
final bool isConst() const nothrow pure @nogc @safe
{
return (mod & MODFlags.const_) != 0;
@@ -2825,13 +2556,6 @@ extern (C++) abstract class TypeNext : Type
this.next = next;
}
- override final void checkDeprecated(const ref Loc loc, Scope* sc)
- {
- Type.checkDeprecated(loc, sc);
- if (next) // next can be NULL if TypeFunction and auto return type
- next.checkDeprecated(loc, sc);
- }
-
override final int hasWild() const
{
if (ty == Tfunction)
@@ -4612,27 +4336,7 @@ extern (C++) final class TypeFunction : TypeNext
return t.merge();
}
- // arguments get specially formatted
- private const(char)* getParamError(Expression arg, Parameter par)
- {
- if (global.gag && !global.params.v.showGaggedErrors)
- return null;
- // show qualification when toChars() is the same but types are different
- // https://issues.dlang.org/show_bug.cgi?id=19948
- // when comparing the type with strcmp, we need to drop the qualifier
- bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) &&
- strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0;
- auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars();
- OutBuffer buf;
- // only mention rvalue if it's relevant
- const rv = !arg.isLvalue() && par.isReference();
- buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
- rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
- parameterToChars(par, this, qual));
- return buf.extractChars();
- }
-
- private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args)
+ extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args)
{
if (global.gag && !global.params.v.showGaggedErrors)
return null;
@@ -4642,185 +4346,6 @@ extern (C++) final class TypeFunction : TypeNext
}
/********************************
- * 'args' are being matched to function 'this'
- * Determine match level.
- * Params:
- * tthis = type of `this` pointer, null if not member function
- * argumentList = arguments to function call
- * flag = 1: performing a partial ordering match
- * pMessage = address to store error message, or null
- * sc = context
- * Returns:
- * MATCHxxxx
- */
- extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
- {
- //printf("TypeFunction::callMatch() %s\n", toChars());
- MATCH match = MATCH.exact; // assume exact match
- ubyte wildmatch = 0;
-
- if (tthis)
- {
- Type t = tthis;
- if (t.toBasetype().ty == Tpointer)
- t = t.toBasetype().nextOf(); // change struct* to struct
- if (t.mod != mod)
- {
- if (MODimplicitConv(t.mod, mod))
- match = MATCH.constant;
- else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_))
- {
- match = MATCH.constant;
- }
- else
- return MATCH.nomatch;
- }
- if (isWild())
- {
- if (t.isWild())
- wildmatch |= MODFlags.wild;
- else if (t.isConst())
- wildmatch |= MODFlags.const_;
- else if (t.isImmutable())
- wildmatch |= MODFlags.immutable_;
- else
- wildmatch |= MODFlags.mutable;
- }
- }
-
- const nparams = parameterList.length;
- if (argumentList.length > nparams)
- {
- if (parameterList.varargs == VarArg.none)
- {
- // suppress early exit if an error message is wanted,
- // so we can check any matching args are valid
- if (!pMessage)
- return MATCH.nomatch;
- }
- // too many args; no match
- match = MATCH.convert; // match ... with a "conversion" match level
- }
-
- // https://issues.dlang.org/show_bug.cgi?id=22997
- if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
- {
- OutBuffer buf;
- buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
- if (pMessage)
- *pMessage = buf.extractChars();
- return MATCH.nomatch;
- }
- auto resolvedArgs = resolveNamedArgs(argumentList, pMessage);
- Expression[] args;
- if (!resolvedArgs)
- {
- if (!pMessage || *pMessage)
- return MATCH.nomatch;
-
- // if no message was provided, it was because of overflow which will be diagnosed below
- match = MATCH.nomatch;
- args = argumentList.arguments ? (*argumentList.arguments)[] : null;
- }
- else
- {
- args = (*resolvedArgs)[];
- }
-
- foreach (u, p; parameterList)
- {
- if (u >= args.length)
- break;
-
- Expression arg = args[u];
- if (!arg)
- continue; // default argument
-
- Type tprm = p.type;
- Type targ = arg.type;
-
- if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
- {
- const isRef = p.isReference();
- wildmatch |= targ.deduceWild(tprm, isRef);
- }
- }
- if (wildmatch)
- {
- /* Calculate wild matching modifier
- */
- if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
- wildmatch = MODFlags.const_;
- else if (wildmatch & MODFlags.immutable_)
- wildmatch = MODFlags.immutable_;
- else if (wildmatch & MODFlags.wild)
- wildmatch = MODFlags.wild;
- else
- {
- assert(wildmatch & MODFlags.mutable);
- wildmatch = MODFlags.mutable;
- }
- }
-
- foreach (u, p; parameterList)
- {
- MATCH m;
-
- assert(p);
-
- // One or more arguments remain
- if (u < args.length)
- {
- Expression arg = args[u];
- if (!arg)
- continue; // default argument
- m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage);
- }
- else if (p.defaultArg)
- continue;
-
- /* prefer matching the element type rather than the array
- * type when more arguments are present with T[]...
- */
- if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
- goto L1;
-
- //printf("\tm = %d\n", m);
- if (m == MATCH.nomatch) // if no match
- {
- L1:
- if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
- {
- auto trailingArgs = args[u .. $];
- if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage))
- return vmatch < match ? vmatch : match;
- // Error message was already generated in `matchTypeSafeVarArgs`
- return MATCH.nomatch;
- }
- if (pMessage && u >= args.length)
- *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
- u + 1, parameterToChars(p, this, false));
- // If an error happened previously, `pMessage` was already filled
- else if (pMessage && !*pMessage)
- *pMessage = getParamError(args[u], p);
-
- return MATCH.nomatch;
- }
- if (m < match)
- match = m; // pick worst match
- }
-
- if (pMessage && !parameterList.varargs && args.length > nparams)
- {
- // all parameters had a match, but there are surplus args
- *pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length);
- return MATCH.nomatch;
- }
- //printf("match = %d\n", match);
- return match;
- }
-
- /********************************
* Convert an `argumentList`, which may contain named arguments, into
* a list of arguments in the order of the parameter list.
*
@@ -6935,7 +6460,7 @@ extern (C++) final class Parameter : ASTNode
return isCovariantScope(returnByRef, thisSTC, otherSTC);
}
- extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
+ extern (D) static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
{
// Workaround for failing covariance when finding a common type of delegates,
// some of which have parameters with inferred scope
@@ -7235,328 +6760,6 @@ const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe
}
/**
- * Used by `callMatch` to check if the copy constructor may be called to
- * copy the argument
- *
- * This is done by seeing if a call to the copy constructor can be made:
- * ```
- * typeof(tprm) __copytmp;
- * copytmp.__copyCtor(arg);
- * ```
- */
-private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
- Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
-{
- auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
- tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
- tmp.dsymbolSemantic(sc);
- Expression ve = new VarExp(arg.loc, tmp);
- Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
- e = new CallExp(arg.loc, e, arg);
- //printf("e = %s\n", e.toChars());
- if (.trySemantic(e, sc))
- return true;
-
- if (pMessage)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=22202
- *
- * If a function was deduced by semantic on the CallExp,
- * it means that resolveFuncCall completed succesfully.
- * Therefore, there exists a callable copy constructor,
- * however, it cannot be called because scope constraints
- * such as purity, safety or nogc.
- */
- OutBuffer buf;
- auto callExp = e.isCallExp();
- if (auto f = callExp.f)
- {
- char[] s;
- if (!f.isPure && sc.func.setImpure())
- s ~= "pure ";
- if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
- s ~= "@safe ";
- if (!f.isNogc && sc.func.setGC(arg.loc, null))
- s ~= "nogc ";
- if (s)
- {
- s[$-1] = '\0';
- buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
- }
- else if (f.isGenerated() && f.isDisabled())
- {
- /* https://issues.dlang.org/show_bug.cgi?id=23097
- * Compiler generated copy constructor failed.
- */
- buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
- argStruct.toChars());
- }
- else
- {
- /* Although a copy constructor may exist, no suitable match was found.
- * i.e: `inout` constructor creates `const` object, not mutable.
- * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
- */
- goto Lnocpctor;
- }
- }
- else
- {
- Lnocpctor:
- buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
- argStruct.toChars(), arg.type.toChars(), tprm.toChars());
- }
-
- *pMessage = buf.extractChars();
- }
- return false;
-}
-
-/**
- * Match a single parameter to an argument.
- *
- * This function is called by `TypeFunction.callMatch` while iterating over
- * the list of parameter. Here we check if `arg` is a match for `p`,
- * which is mostly about checking if `arg.type` converts to `p`'s type
- * and some check about value reference.
- *
- * Params:
- * tf = The `TypeFunction`, only used for error reporting
- * p = The parameter of `tf` being matched
- * arg = Argument being passed (bound) to `p`
- * wildmatch = Wild (`inout`) matching level, derived from the full argument list
- * flag = A non-zero value means we're doing a partial ordering check
- * (no value semantic check)
- * sc = Scope we are in
- * pMessage = A buffer to write the error in, or `null`
- *
- * Returns: Whether `trailingArgs` match `p`.
- */
-private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
- Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
-{
- //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
- MATCH m;
- Type targ = arg.type;
- Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
-
- if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
- m = MATCH.convert;
- else if (flag)
- {
- // for partial ordering, value is an irrelevant mockup, just look at the type
- m = targ.implicitConvTo(tprm);
- }
- else
- {
- const isRef = p.isReference();
- StructDeclaration argStruct, prmStruct;
-
- // first look for a copy constructor
- if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
- {
- // if the argument and the parameter are of the same unqualified struct type
- argStruct = (cast(TypeStruct)targ).sym;
- prmStruct = (cast(TypeStruct)tprm).sym;
- }
-
- // check if the copy constructor may be called to copy the argument
- if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
- {
- if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
- return MATCH.nomatch;
- m = MATCH.exact;
- }
- else
- {
- import dmd.dcast : cimplicitConvTo;
- m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
- }
- }
-
- // Non-lvalues do not match ref or out parameters
- if (p.isReference())
- {
- // https://issues.dlang.org/show_bug.cgi?id=13783
- // Don't use toBasetype() to handle enum types.
- Type ta = targ;
- Type tp = tprm;
- //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
-
- if (m && !arg.isLvalue())
- {
- if (p.storageClass & STC.out_)
- {
- if (pMessage) *pMessage = tf.getParamError(arg, p);
- return MATCH.nomatch;
- }
-
- if (arg.op == EXP.string_ && tp.ty == Tsarray)
- {
- if (ta.ty != Tsarray)
- {
- Type tn = tp.nextOf().castMod(ta.nextOf().mod);
- dinteger_t dim = (cast(StringExp)arg).len;
- ta = tn.sarrayOf(dim);
- }
- }
- else if (arg.op == EXP.slice && tp.ty == Tsarray)
- {
- // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
- if (ta.ty != Tsarray)
- {
- Type tn = ta.nextOf();
- dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
- ta = tn.sarrayOf(dim);
- }
- }
- else if ((p.storageClass & STC.in_) && global.params.previewIn)
- {
- // Allow converting a literal to an `in` which is `ref`
- if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
- {
- Type tn = tp.nextOf();
- dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
- ta = tn.sarrayOf(dim);
- }
-
- // Need to make this a rvalue through a temporary
- m = MATCH.convert;
- }
- else if (global.params.rvalueRefParam != FeatureState.enabled ||
- p.storageClass & STC.out_ ||
- !arg.type.isCopyable()) // can't copy to temp for ref parameter
- {
- if (pMessage) *pMessage = tf.getParamError(arg, p);
- return MATCH.nomatch;
- }
- else
- {
- /* in functionParameters() we'll convert this
- * rvalue into a temporary
- */
- m = MATCH.convert;
- }
- }
-
- /* If the match is not already perfect or if the arg
- is not a lvalue then try the `alias this` chain
- see https://issues.dlang.org/show_bug.cgi?id=15674
- and https://issues.dlang.org/show_bug.cgi?id=21905
- */
- if (ta != tp || !arg.isLvalue())
- {
- Type firsttab = ta.toBasetype();
- while (1)
- {
- Type tab = ta.toBasetype();
- Type tat = tab.aliasthisOf();
- if (!tat || !tat.implicitConvTo(tprm))
- break;
- if (tat == tab || tat == firsttab)
- break;
- ta = tat;
- }
- }
-
- /* A ref variable should work like a head-const reference.
- * e.g. disallows:
- * ref T <- an lvalue of const(T) argument
- * ref T[dim] <- an lvalue of const(T[dim]) argument
- */
- if (!ta.constConv(tp))
- {
- if (pMessage) *pMessage = tf.getParamError(arg, p);
- return MATCH.nomatch;
- }
- }
- return m;
-}
-
-/**
- * Match the remaining arguments `trailingArgs` with parameter `p`.
- *
- * Assume we already checked that `p` is the last parameter of `tf`,
- * and we want to know whether the arguments would match `p`.
- *
- * Params:
- * tf = The `TypeFunction`, only used for error reporting
- * p = The last parameter of `tf` which is variadic
- * trailingArgs = The remaining arguments that should match `p`
- * pMessage = A buffer to write the error in, or `null`
- *
- * Returns: Whether `trailingArgs` match `p`.
- */
-private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
- Expression[] trailingArgs, const(char)** pMessage)
-{
- Type tb = p.type.toBasetype();
-
- switch (tb.ty)
- {
- case Tsarray:
- TypeSArray tsa = cast(TypeSArray)tb;
- dinteger_t sz = tsa.dim.toInteger();
- if (sz != trailingArgs.length)
- {
- if (pMessage)
- *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
- sz, trailingArgs.length);
- return MATCH.nomatch;
- }
- goto case Tarray;
- case Tarray:
- {
- MATCH match = MATCH.exact;
- TypeArray ta = cast(TypeArray)tb;
- foreach (arg; trailingArgs)
- {
- MATCH m;
- assert(arg);
-
- /* If lazy array of delegates,
- * convert arg(s) to delegate(s)
- */
- Type tret = p.isLazyArray();
- if (tret)
- {
- if (ta.next.equals(arg.type))
- m = MATCH.exact;
- else if (tret.toBasetype().ty == Tvoid)
- m = MATCH.convert;
- else
- {
- m = arg.implicitConvTo(tret);
- if (m == MATCH.nomatch)
- m = arg.implicitConvTo(ta.next);
- }
- }
- else
- m = arg.implicitConvTo(ta.next);
-
- if (m == MATCH.nomatch)
- {
- if (pMessage) *pMessage = tf.getParamError(arg, p);
- return MATCH.nomatch;
- }
- if (m < match)
- match = m;
- }
- return match;
- }
- case Tclass:
- // We leave it up to the actual constructor call to do the matching.
- return MATCH.exact;
-
- default:
- // We can have things as `foo(int[int] wat...)` but they only match
- // with an associative array proper.
- if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p);
- return MATCH.nomatch;
- }
-}
-
-/**
* Creates an appropriate vector type for `tv` that will hold one boolean
* result for each element of the vector type. The result of vector comparisons
* is a single or doubleword mask of all 1s (comparison true) or all 0s
@@ -7738,3 +6941,36 @@ TypeIdentifier getException()
tid.addIdent(Id.Exception);
return tid;
}
+
+/**************************************
+ * Check and set 'att' if 't' is a recursive 'alias this' type
+ *
+ * The goal is to prevent endless loops when there is a cycle in the alias this chain.
+ * Since there is no multiple `alias this`, the chain either ends in a leaf,
+ * or it loops back on itself as some point.
+ *
+ * Example: S0 -> (S1 -> S2 -> S3 -> S1)
+ *
+ * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
+ * `S1` is a recursive alias this type, but since `att` is initialized to `null`,
+ * this still returns `false`, but `att1` is set to `S1`.
+ * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
+ * we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
+ *
+ * Params:
+ * att = type reference used to detect recursion. Should be initialized to `null`.
+ * t = type of 'alias this' rewrite to attempt
+ *
+ * Returns:
+ * `false` if the rewrite is safe, `true` if it would loop back around
+ */
+bool isRecursiveAliasThis(ref Type att, Type t)
+{
+ //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
+ auto tb = t.toBasetype();
+ if (att && tb.equivalent(att))
+ return true;
+ else if (!att && tb.checkAliasThisRec())
+ att = tb;
+ return false;
+}
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 675e944..ef1ce10 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -225,7 +225,6 @@ public:
// kludge for template.isType()
DYNCAST dyncast() const override final { return DYNCAST_TYPE; }
size_t getUniqueID() const;
- Covariant covariant(Type *, StorageClass * = NULL, bool = false);
const char *toChars() const override;
char *toPrettyChars(bool QualifyTypes = false);
static void _init();
@@ -249,7 +248,6 @@ public:
virtual bool isString();
virtual bool isAssignable();
virtual bool isBoolean();
- virtual void checkDeprecated(const Loc &loc, Scope *sc);
bool isConst() const { return (mod & MODconst) != 0; }
bool isImmutable() const { return (mod & MODimmutable) != 0; }
bool isMutable() const { return (mod & (MODconst | MODimmutable | MODwild)) == 0; }
@@ -364,7 +362,6 @@ class TypeNext : public Type
public:
Type *next;
- void checkDeprecated(const Loc &loc, Scope *sc) override final;
int hasWild() const override final;
Type *nextOf() override final;
Type *makeConst() override final;
@@ -929,3 +926,4 @@ public:
// If the type is a class or struct, returns the symbol for it, else null.
AggregateDeclaration *isAggregate(Type *t);
+Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);
diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d
index 22c6e63..65f7d29 100644
--- a/gcc/d/dmd/nspace.d
+++ b/gcc/d/dmd/nspace.d
@@ -46,22 +46,14 @@
module dmd.nspace;
-import dmd.aggregate;
import dmd.arraytypes;
-import dmd.astenums;
-import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem;
-import dmd.errors;
import dmd.expression;
-import dmd.globals;
import dmd.identifier;
import dmd.location;
import dmd.visitor;
import core.stdc.stdio;
-private enum LOG = false;
-
/// Ditto
extern (C++) final class Nspace : ScopeDsymbol
{
@@ -91,14 +83,6 @@ extern (C++) final class Nspace : ScopeDsymbol
return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
}
- override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
- {
- //printf("Nspace::setFieldOffset() %s\n", toChars());
- if (_scope) // if fwd reference
- dsymbolSemantic(this, null); // try to resolve it
- members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
- }
-
override const(char)* kind() const
{
return "namespace";
diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h
index 701cc93..4a1bd91 100644
--- a/gcc/d/dmd/nspace.h
+++ b/gcc/d/dmd/nspace.h
@@ -22,7 +22,6 @@ class Nspace final : public ScopeDsymbol
Expression *identExp;
Nspace *syntaxCopy(Dsymbol *s) override;
bool hasPointers() override;
- void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
const char *kind() const override;
Nspace *isNspace() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index 2cac5f2..cceb5a7 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -130,5 +130,5 @@ struct Scope
AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value,
// do not set wasRead for it
- Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone);
+ Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
};
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index c255701..7498eaf 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -520,7 +520,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
{
Parameter narg = Parameter.getNth(t.arguments, j);
assert(narg.ident);
- VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration();
+ Dsymbol pscopesym;
+ VarDeclaration v = sc2.search(Loc.initial, narg.ident, pscopesym).isVarDeclaration();
assert(v);
(*exps)[j] = new VarExp(v.loc, v);
}
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index b5906c8..4304544 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -20,19 +20,15 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.errors;
-import dmd.gluelayer;
import dmd.cond;
import dmd.declaration;
import dmd.dsymbol;
import dmd.expression;
import dmd.func;
-import dmd.globals;
-import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
-import dmd.common.outbuffer;
import dmd.rootobject;
import dmd.sapply;
import dmd.staticassert;
@@ -333,6 +329,8 @@ extern (C++) final class ErrorStatement : Statement
extern (D) this()
{
super(Loc.initial, STMT.Error);
+
+ import dmd.globals;
assert(global.gaggedErrors || global.errors);
}
@@ -1773,7 +1771,7 @@ extern (C++) class AsmStatement : Statement
*/
extern (C++) final class InlineAsmStatement : AsmStatement
{
- code* asmcode;
+ void* asmcode;
uint asmalign; // alignment of this statement
uint regs; // mask of registers modified (must match regm_t in back end)
bool refparam; // true if function parameter is referenced
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index ef8423f..1e493f0 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -716,7 +716,7 @@ public:
class InlineAsmStatement final : public AsmStatement
{
public:
- code *asmcode;
+ void *asmcode;
unsigned asmalign; // alignment of this statement
unsigned regs; // mask of registers modified (must match regm_t in back end)
d_bool refparam; // true if function parameter is referenced
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 3873adc..fcc606b 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -2261,7 +2261,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
continue;
assert(scx.sw == sw);
- if (!scx.search(cs.exp.loc, v.ident, null))
+ Dsymbol pscopesym;
+ if (!scx.search(cs.exp.loc, v.ident, pscopesym))
{
error(cs.loc, "`case` variable `%s` declared at %s cannot be declared in `switch` body",
v.toChars(), v.loc.toChars());
@@ -2525,10 +2526,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (fd.fes)
fd = fd.fes.func; // fd is now function enclosing foreach
- TypeFunction tf = cast(TypeFunction)fd.type;
- assert(tf.ty == Tfunction);
+ auto tf = fd.type.isTypeFunction();
- if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult)
+ if (rs.exp && rs.exp.isVarExp() && rs.exp.isVarExp().var == fd.vresult)
{
// return vresult;
if (sc.fes)
@@ -2616,7 +2616,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
rs.exp.checkSharedAccess(sc, returnSharedRef);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (rs.exp.op == EXP.type)
+ if (rs.exp.isTypeExp())
rs.exp = resolveAliasThis(sc, rs.exp);
rs.exp = resolveProperties(sc, rs.exp);
@@ -2632,14 +2632,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// Extract side-effect part
rs.exp = Expression.extractLast(rs.exp, e0);
- if (rs.exp.op == EXP.call)
+ if (rs.exp.isCallExp())
rs.exp = valueNoDtor(rs.exp);
/* Void-return function can have void / noreturn typed expression
* on return statement.
*/
auto texp = rs.exp.type;
- const convToVoid = texp.ty == Tvoid || texp.ty == Tnoreturn;
+ const convToVoid = texp.ty == Tvoid || texp.isTypeNoreturn();
if (tbret && tbret.ty == Tvoid || convToVoid)
{
@@ -2688,7 +2688,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
{
tf.next = rs.exp.type;
}
- else if (tret.ty != Terror && !rs.exp.type.equals(tret))
+ else if (!tret.isTypeError() && !rs.exp.type.equals(tret))
{
int m1 = rs.exp.type.implicitConvTo(tret);
int m2 = tret.implicitConvTo(rs.exp.type);
@@ -2789,7 +2789,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// Found an actual return value before
else if (tf.next.ty != Tvoid && !resType.toBasetype().isTypeNoreturn())
{
- if (tf.next.ty != Terror)
+ if (!tf.next.isTypeError())
{
error(rs.loc, "mismatched function return type inference of `void` and `%s`", tf.next.toChars());
}
@@ -2807,7 +2807,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return
{
- if (tbret.ty != Terror)
+ if (!tbret.isTypeError())
{
if (e0)
error(rs.loc, "expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars());
@@ -2901,7 +2901,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
if (e0)
{
- if (e0.op == EXP.declaration || e0.op == EXP.comma)
+ if (e0.isDeclarationExp() || e0.isCommaExp())
{
rs.exp = Expression.combine(e0, rs.exp);
}
diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d
index 7f22c4c..760c66a 100644
--- a/gcc/d/dmd/staticassert.d
+++ b/gcc/d/dmd/staticassert.d
@@ -14,14 +14,11 @@
module dmd.staticassert;
import dmd.arraytypes;
-import dmd.dscope;
import dmd.dsymbol;
import dmd.expression;
-import dmd.globals;
import dmd.location;
import dmd.id;
import dmd.identifier;
-import dmd.mtype;
import dmd.visitor;
/***********************************************************
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 44f95ec..4be1361 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -311,7 +311,6 @@ public:
const char *kind() const override;
bool oneMember(Dsymbol **ps, Identifier *ident) override;
bool hasPointers() override;
- void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
const char *toChars() const override;
TemplateMixin *isTemplateMixin() override { return this; }
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 0acadbb..aebc0b5 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -1665,12 +1665,12 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
else if (auto ed = sm.isEnumDeclaration())
{
- ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg);
+ _foreach(null, ed.members, &pushIdentsDg);
}
return 0;
}
- ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg);
+ _foreach(sc, sds.members, &pushIdentsDg);
auto cd = sds.isClassDeclaration();
if (cd && e.ident == Id.allMembers)
{
@@ -1684,7 +1684,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
{
auto cb = (*cd.baseclasses)[i].sym;
assert(cb);
- ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg);
+ _foreach(null, cb.members, &pushIdentsDg);
if (cb.baseclasses.length)
pushBaseMembersDg(cb);
}
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 2063a95..b0e45f4 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -228,7 +228,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
Type t = s.getType(); // type symbol, type alias, or type tuple?
uint errorsave = global.errors;
- int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports;
+ SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports;
Dsymbol sm = s.searchX(loc, sc, id, flags);
if (sm)
@@ -380,12 +380,12 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
* loc = location to print the error messages
* sc = the scope where the symbol is located
* id = the id of the symbol
- * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
+ * flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports`
*
* Returns:
* symbol found, NULL if not
*/
-private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, int flags)
+private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags)
{
//printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
Dsymbol s = dsym.toAlias();
@@ -486,6 +486,529 @@ Expression typeToExpression(Type t)
}
}
+/********************************
+ * 'args' are being matched to function type 'tf'
+ * Determine match level.
+ * Params:
+ * tf = function type
+ * tthis = type of `this` pointer, null if not member function
+ * argumentList = arguments to function call
+ * flag = 1: performing a partial ordering match
+ * pMessage = address to store error message, or null
+ * sc = context
+ * Returns:
+ * MATCHxxxx
+ */
+extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
+{
+ //printf("TypeFunction::callMatch() %s\n", tf.toChars());
+ MATCH match = MATCH.exact; // assume exact match
+ ubyte wildmatch = 0;
+
+ if (tthis)
+ {
+ Type t = tthis;
+ if (t.toBasetype().ty == Tpointer)
+ t = t.toBasetype().nextOf(); // change struct* to struct
+ if (t.mod != tf.mod)
+ {
+ if (MODimplicitConv(t.mod, tf.mod))
+ match = MATCH.constant;
+ else if ((tf.mod & MODFlags.wild) && MODimplicitConv(t.mod, (tf.mod & ~MODFlags.wild) | MODFlags.const_))
+ {
+ match = MATCH.constant;
+ }
+ else
+ return MATCH.nomatch;
+ }
+ if (tf.isWild())
+ {
+ if (t.isWild())
+ wildmatch |= MODFlags.wild;
+ else if (t.isConst())
+ wildmatch |= MODFlags.const_;
+ else if (t.isImmutable())
+ wildmatch |= MODFlags.immutable_;
+ else
+ wildmatch |= MODFlags.mutable;
+ }
+ }
+
+ ParameterList* parameterList = &tf.parameterList;
+ const nparams = parameterList.length;
+ if (argumentList.length > nparams)
+ {
+ if (parameterList.varargs == VarArg.none)
+ {
+ // suppress early exit if an error message is wanted,
+ // so we can check any matching args are valid
+ if (!pMessage)
+ return MATCH.nomatch;
+ }
+ // too many args; no match
+ match = MATCH.convert; // match ... with a "conversion" match level
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=22997
+ if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
+ {
+ OutBuffer buf;
+ buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
+ if (pMessage)
+ *pMessage = buf.extractChars();
+ return MATCH.nomatch;
+ }
+ auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
+ Expression[] args;
+ if (!resolvedArgs)
+ {
+ if (!pMessage || *pMessage)
+ return MATCH.nomatch;
+
+ // if no message was provided, it was because of overflow which will be diagnosed below
+ match = MATCH.nomatch;
+ args = argumentList.arguments ? (*argumentList.arguments)[] : null;
+ }
+ else
+ {
+ args = (*resolvedArgs)[];
+ }
+
+ foreach (u, p; *parameterList)
+ {
+ if (u >= args.length)
+ break;
+
+ Expression arg = args[u];
+ if (!arg)
+ continue; // default argument
+
+ Type tprm = p.type;
+ Type targ = arg.type;
+
+ if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
+ {
+ const isRef = p.isReference();
+ wildmatch |= targ.deduceWild(tprm, isRef);
+ }
+ }
+ if (wildmatch)
+ {
+ /* Calculate wild matching modifier
+ */
+ if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
+ wildmatch = MODFlags.const_;
+ else if (wildmatch & MODFlags.immutable_)
+ wildmatch = MODFlags.immutable_;
+ else if (wildmatch & MODFlags.wild)
+ wildmatch = MODFlags.wild;
+ else
+ {
+ assert(wildmatch & MODFlags.mutable);
+ wildmatch = MODFlags.mutable;
+ }
+ }
+
+ foreach (u, p; *parameterList)
+ {
+ MATCH m;
+
+ assert(p);
+
+ // One or more arguments remain
+ if (u < args.length)
+ {
+ Expression arg = args[u];
+ if (!arg)
+ continue; // default argument
+ m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);
+ }
+ else if (p.defaultArg)
+ continue;
+
+ /* prefer matching the element type rather than the array
+ * type when more arguments are present with T[]...
+ */
+ if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
+ goto L1;
+
+ //printf("\tm = %d\n", m);
+ if (m == MATCH.nomatch) // if no match
+ {
+ L1:
+ if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
+ {
+ auto trailingArgs = args[u .. $];
+ if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
+ return vmatch < match ? vmatch : match;
+ // Error message was already generated in `matchTypeSafeVarArgs`
+ return MATCH.nomatch;
+ }
+ if (pMessage && u >= args.length)
+ *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`",
+ u + 1, parameterToChars(p, tf, false));
+ // If an error happened previously, `pMessage` was already filled
+ else if (pMessage && !*pMessage)
+ *pMessage = tf.getParamError(args[u], p);
+
+ return MATCH.nomatch;
+ }
+ if (m < match)
+ match = m; // pick worst match
+ }
+
+ if (pMessage && !parameterList.varargs && args.length > nparams)
+ {
+ // all parameters had a match, but there are surplus args
+ *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length);
+ return MATCH.nomatch;
+ }
+ //printf("match = %d\n", match);
+ return match;
+}
+
+/**
+ * Used by `callMatch` to check if the copy constructor may be called to
+ * copy the argument
+ *
+ * This is done by seeing if a call to the copy constructor can be made:
+ * ```
+ * typeof(tprm) __copytmp;
+ * copytmp.__copyCtor(arg);
+ * ```
+ */
+private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
+ Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
+{
+ auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
+ tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
+ tmp.dsymbolSemantic(sc);
+ Expression ve = new VarExp(arg.loc, tmp);
+ Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
+ e = new CallExp(arg.loc, e, arg);
+ //printf("e = %s\n", e.toChars());
+ if (.trySemantic(e, sc))
+ return true;
+
+ if (pMessage)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=22202
+ *
+ * If a function was deduced by semantic on the CallExp,
+ * it means that resolveFuncCall completed succesfully.
+ * Therefore, there exists a callable copy constructor,
+ * however, it cannot be called because scope constraints
+ * such as purity, safety or nogc.
+ */
+ OutBuffer buf;
+ auto callExp = e.isCallExp();
+ if (auto f = callExp.f)
+ {
+ char[] s;
+ if (!f.isPure && sc.func.setImpure())
+ s ~= "pure ";
+ if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
+ s ~= "@safe ";
+ if (!f.isNogc && sc.func.setGC(arg.loc, null))
+ s ~= "nogc ";
+ if (s)
+ {
+ s[$-1] = '\0';
+ buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
+ }
+ else if (f.isGenerated() && f.isDisabled())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=23097
+ * Compiler generated copy constructor failed.
+ */
+ buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
+ argStruct.toChars());
+ }
+ else
+ {
+ /* Although a copy constructor may exist, no suitable match was found.
+ * i.e: `inout` constructor creates `const` object, not mutable.
+ * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
+ */
+ goto Lnocpctor;
+ }
+ }
+ else
+ {
+ Lnocpctor:
+ buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
+ argStruct.toChars(), arg.type.toChars(), tprm.toChars());
+ }
+
+ *pMessage = buf.extractChars();
+ }
+ return false;
+}
+
+/**
+ * Match a single parameter to an argument.
+ *
+ * This function is called by `TypeFunction.callMatch` while iterating over
+ * the list of parameter. Here we check if `arg` is a match for `p`,
+ * which is mostly about checking if `arg.type` converts to `p`'s type
+ * and some check about value reference.
+ *
+ * Params:
+ * tf = The `TypeFunction`, only used for error reporting
+ * p = The parameter of `tf` being matched
+ * arg = Argument being passed (bound) to `p`
+ * wildmatch = Wild (`inout`) matching level, derived from the full argument list
+ * flag = A non-zero value means we're doing a partial ordering check
+ * (no value semantic check)
+ * sc = Scope we are in
+ * pMessage = A buffer to write the error in, or `null`
+ *
+ * Returns: Whether `trailingArgs` match `p`.
+ */
+private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
+ Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
+{
+ //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
+ MATCH m;
+ Type targ = arg.type;
+ Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
+
+ if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
+ m = MATCH.convert;
+ else if (flag)
+ {
+ // for partial ordering, value is an irrelevant mockup, just look at the type
+ m = targ.implicitConvTo(tprm);
+ }
+ else
+ {
+ const isRef = p.isReference();
+ StructDeclaration argStruct, prmStruct;
+
+ // first look for a copy constructor
+ if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
+ {
+ // if the argument and the parameter are of the same unqualified struct type
+ argStruct = (cast(TypeStruct)targ).sym;
+ prmStruct = (cast(TypeStruct)tprm).sym;
+ }
+
+ // check if the copy constructor may be called to copy the argument
+ if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
+ {
+ if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
+ return MATCH.nomatch;
+ m = MATCH.exact;
+ }
+ else
+ {
+ import dmd.dcast : cimplicitConvTo;
+ m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
+ }
+ }
+
+ // Non-lvalues do not match ref or out parameters
+ if (p.isReference())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13783
+ // Don't use toBasetype() to handle enum types.
+ Type ta = targ;
+ Type tp = tprm;
+ //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
+
+ if (m && !arg.isLvalue())
+ {
+ if (p.storageClass & STC.out_)
+ {
+ if (pMessage) *pMessage = tf.getParamError(arg, p);
+ return MATCH.nomatch;
+ }
+
+ if (arg.op == EXP.string_ && tp.ty == Tsarray)
+ {
+ if (ta.ty != Tsarray)
+ {
+ Type tn = tp.nextOf().castMod(ta.nextOf().mod);
+ dinteger_t dim = (cast(StringExp)arg).len;
+ ta = tn.sarrayOf(dim);
+ }
+ }
+ else if (arg.op == EXP.slice && tp.ty == Tsarray)
+ {
+ // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+ if (ta.ty != Tsarray)
+ {
+ Type tn = ta.nextOf();
+ dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
+ ta = tn.sarrayOf(dim);
+ }
+ }
+ else if ((p.storageClass & STC.in_) && global.params.previewIn)
+ {
+ // Allow converting a literal to an `in` which is `ref`
+ if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
+ {
+ Type tn = tp.nextOf();
+ dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
+ ta = tn.sarrayOf(dim);
+ }
+
+ // Need to make this a rvalue through a temporary
+ m = MATCH.convert;
+ }
+ else if (global.params.rvalueRefParam != FeatureState.enabled ||
+ p.storageClass & STC.out_ ||
+ !arg.type.isCopyable()) // can't copy to temp for ref parameter
+ {
+ if (pMessage) *pMessage = tf.getParamError(arg, p);
+ return MATCH.nomatch;
+ }
+ else
+ {
+ /* in functionParameters() we'll convert this
+ * rvalue into a temporary
+ */
+ m = MATCH.convert;
+ }
+ }
+
+ /* If the match is not already perfect or if the arg
+ is not a lvalue then try the `alias this` chain
+ see https://issues.dlang.org/show_bug.cgi?id=15674
+ and https://issues.dlang.org/show_bug.cgi?id=21905
+ */
+ if (ta != tp || !arg.isLvalue())
+ {
+ Type firsttab = ta.toBasetype();
+ while (1)
+ {
+ Type tab = ta.toBasetype();
+ Type tat = tab.aliasthisOf();
+ if (!tat || !tat.implicitConvTo(tprm))
+ break;
+ if (tat == tab || tat == firsttab)
+ break;
+ ta = tat;
+ }
+ }
+
+ /* A ref variable should work like a head-const reference.
+ * e.g. disallows:
+ * ref T <- an lvalue of const(T) argument
+ * ref T[dim] <- an lvalue of const(T[dim]) argument
+ */
+ if (!ta.constConv(tp))
+ {
+ if (pMessage) *pMessage = tf.getParamError(arg, p);
+ return MATCH.nomatch;
+ }
+ }
+ return m;
+}
+
+// arguments get specially formatted
+private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter par)
+{
+ if (global.gag && !global.params.v.showGaggedErrors)
+ return null;
+ // show qualification when toChars() is the same but types are different
+ // https://issues.dlang.org/show_bug.cgi?id=19948
+ // when comparing the type with strcmp, we need to drop the qualifier
+ bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) &&
+ strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0;
+ auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars();
+ OutBuffer buf;
+ // only mention rvalue if it's relevant
+ const rv = !arg.isLvalue() && par.isReference();
+ buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
+ rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
+ parameterToChars(par, tf, qual));
+ return buf.extractChars();
+}
+
+/**
+ * Match the remaining arguments `trailingArgs` with parameter `p`.
+ *
+ * Assume we already checked that `p` is the last parameter of `tf`,
+ * and we want to know whether the arguments would match `p`.
+ *
+ * Params:
+ * tf = The `TypeFunction`, only used for error reporting
+ * p = The last parameter of `tf` which is variadic
+ * trailingArgs = The remaining arguments that should match `p`
+ * pMessage = A buffer to write the error in, or `null`
+ *
+ * Returns: Whether `trailingArgs` match `p`.
+ */
+private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
+ Expression[] trailingArgs, const(char)** pMessage)
+{
+ Type tb = p.type.toBasetype();
+
+ switch (tb.ty)
+ {
+ case Tsarray:
+ TypeSArray tsa = cast(TypeSArray)tb;
+ dinteger_t sz = tsa.dim.toInteger();
+ if (sz != trailingArgs.length)
+ {
+ if (pMessage)
+ *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
+ sz, trailingArgs.length);
+ return MATCH.nomatch;
+ }
+ goto case Tarray;
+ case Tarray:
+ {
+ MATCH match = MATCH.exact;
+ TypeArray ta = cast(TypeArray)tb;
+ foreach (arg; trailingArgs)
+ {
+ MATCH m;
+ assert(arg);
+
+ /* If lazy array of delegates,
+ * convert arg(s) to delegate(s)
+ */
+ Type tret = p.isLazyArray();
+ if (tret)
+ {
+ if (ta.next.equals(arg.type))
+ m = MATCH.exact;
+ else if (tret.toBasetype().ty == Tvoid)
+ m = MATCH.convert;
+ else
+ {
+ m = arg.implicitConvTo(tret);
+ if (m == MATCH.nomatch)
+ m = arg.implicitConvTo(ta.next);
+ }
+ }
+ else
+ m = arg.implicitConvTo(ta.next);
+
+ if (m == MATCH.nomatch)
+ {
+ if (pMessage) *pMessage = tf.getParamError(arg, p);
+ return MATCH.nomatch;
+ }
+ if (m < match)
+ match = m;
+ }
+ return match;
+ }
+ case Tclass:
+ // We leave it up to the actual constructor call to do the matching.
+ return MATCH.exact;
+
+ default:
+ // We can have things as `foo(int[int] wat...)` but they only match
+ // with an associative array proper.
+ if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p);
+ return MATCH.nomatch;
+ }
+}
+
/******************************************
* Perform semantic analysis on a type.
* Params:
@@ -1878,7 +2401,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
/* look for pre-existing declaration
*/
Dsymbol scopesym;
- auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
+ auto s = sc2.search(mtype.loc, mtype.id, scopesym, SearchOpt.ignoreErrors | SearchOpt.tagNameSpace);
if (!s || s.isModule())
{
// no pre-existing declaration, so declare it
@@ -2753,7 +3276,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
}
Dsymbol scopesym;
- Dsymbol s = sc.search(loc, mt.ident, &scopesym);
+ Dsymbol s = sc.search(loc, mt.ident, scopesym);
/*
* https://issues.dlang.org/show_bug.cgi?id=1170
* https://issues.dlang.org/show_bug.cgi?id=10739
@@ -2776,7 +3299,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
mixinTempl.dsymbolSemantic(sc);
}
sds.members.foreachDsymbol( s => semanticOnMixin(s) );
- s = sc.search(loc, mt.ident, &scopesym);
+ s = sc.search(loc, mt.ident, scopesym);
}
}
@@ -3794,8 +4317,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
return e;
}
- immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
- s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
+ immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
+ s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
L1:
if (!s)
{
@@ -4074,8 +4597,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
return e;
}
- int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
- s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
+ SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
+ s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
L1:
if (!s)
@@ -4723,7 +5246,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
return *pt;
}
- Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports);
+ Dsymbol s = mConfig.searchX(Loc.initial, sc, id, SearchOpt.ignorePrivateImports);
if (!s)
{
error(loc, "`%s` not found in core.stdc.config", id.toChars());
@@ -4748,6 +5271,263 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
return *pt;
}
+/*******************************
+ * Covariant means that 'src' can substitute for 't',
+ * i.e. a pure function is a match for an impure type.
+ * Params:
+ * src = source type
+ * t = type 'src' is covariant with
+ * pstc = if not null, store STCxxxx which would make it covariant
+ * cppCovariant = true if extern(C++) function types should follow C++ covariant rules
+ * Returns:
+ * An enum value of either `Covariant.yes` or a reason it's not covariant.
+ */
+extern (C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
+{
+ version (none)
+ {
+ printf("Type::covariant(t = %s) %s\n", t.toChars(), src.toChars());
+ printf("deco = %p, %p\n", src.deco, t.deco);
+ // printf("ty = %d\n", next.ty);
+ printf("mod = %x, %x\n", src.mod, t.mod);
+ }
+ if (pstc)
+ *pstc = 0;
+ StorageClass stc = 0;
+
+ bool notcovariant = false;
+
+ if (src.equals(t))
+ return Covariant.yes;
+
+ TypeFunction t1 = src.isTypeFunction();
+ TypeFunction t2 = t.isTypeFunction();
+
+ if (!t1 || !t2)
+ goto Ldistinct;
+
+ if (t1.parameterList.varargs != t2.parameterList.varargs)
+ goto Ldistinct;
+
+ if (t1.parameterList.parameters && t2.parameterList.parameters)
+ {
+ if (t1.parameterList.length != t2.parameterList.length)
+ goto Ldistinct;
+
+ foreach (i, fparam1; t1.parameterList)
+ {
+ Parameter fparam2 = t2.parameterList[i];
+ Type tp1 = fparam1.type;
+ Type tp2 = fparam2.type;
+
+ if (!tp1.equals(tp2))
+ {
+ if (tp1.ty == tp2.ty)
+ {
+ if (auto tc1 = tp1.isTypeClass())
+ {
+ if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
+ goto Lcov;
+ }
+ else if (auto ts1 = tp1.isTypeStruct())
+ {
+ if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
+ goto Lcov;
+ }
+ else if (tp1.ty == Tpointer)
+ {
+ if (tp2.implicitConvTo(tp1))
+ goto Lcov;
+ }
+ else if (tp1.ty == Tarray)
+ {
+ if (tp2.implicitConvTo(tp1))
+ goto Lcov;
+ }
+ else if (tp1.ty == Tdelegate)
+ {
+ if (tp2.implicitConvTo(tp1))
+ goto Lcov;
+ }
+ }
+ goto Ldistinct;
+ }
+ Lcov:
+ notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
+
+ /* https://issues.dlang.org/show_bug.cgi?id=23135
+ * extern(C++) mutable parameters are not covariant with const.
+ */
+ if (t1.linkage == LINK.cpp && cppCovariant)
+ {
+ notcovariant |= tp1.isNaked() != tp2.isNaked();
+ if (auto tpn1 = tp1.nextOf())
+ notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
+ }
+ }
+ }
+ else if (t1.parameterList.parameters != t2.parameterList.parameters)
+ {
+ if (t1.parameterList.length || t2.parameterList.length)
+ goto Ldistinct;
+ }
+
+ // The argument lists match
+ if (notcovariant)
+ goto Lnotcovariant;
+ if (t1.linkage != t2.linkage)
+ goto Lnotcovariant;
+
+ {
+ // Return types
+ Type t1n = t1.next;
+ Type t2n = t2.next;
+
+ if (!t1n || !t2n) // happens with return type inference
+ goto Lnotcovariant;
+
+ if (t1n.equals(t2n))
+ goto Lcovariant;
+ if (t1n.ty == Tclass && t2n.ty == Tclass)
+ {
+ /* If same class type, but t2n is const, then it's
+ * covariant. Do this test first because it can work on
+ * forward references.
+ */
+ if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
+ goto Lcovariant;
+
+ // If t1n is forward referenced:
+ ClassDeclaration cd = (cast(TypeClass)t1n).sym;
+ if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
+ cd.dsymbolSemantic(null);
+ if (!cd.isBaseInfoComplete())
+ {
+ return Covariant.fwdref;
+ }
+ }
+ if (t1n.ty == Tstruct && t2n.ty == Tstruct)
+ {
+ if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
+ goto Lcovariant;
+ }
+ else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
+ {
+ if (t1.isref && t2.isref)
+ {
+ // Treat like pointers to t1n and t2n
+ if (t1n.constConv(t2n) < MATCH.constant)
+ goto Lnotcovariant;
+ }
+ goto Lcovariant;
+ }
+ else if (t1n.ty == Tnull)
+ {
+ // NULL is covariant with any pointer type, but not with any
+ // dynamic arrays, associative arrays or delegates.
+ // https://issues.dlang.org/show_bug.cgi?id=8589
+ // https://issues.dlang.org/show_bug.cgi?id=19618
+ Type t2bn = t2n.toBasetype();
+ if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
+ goto Lcovariant;
+ }
+ // bottom type is covariant to any type
+ else if (t1n.ty == Tnoreturn)
+ goto Lcovariant;
+ }
+ goto Lnotcovariant;
+
+Lcovariant:
+ if (t1.isref != t2.isref)
+ goto Lnotcovariant;
+
+ if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
+ {
+ StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
+ StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
+ if (t1.isreturn)
+ {
+ stc1 |= STC.return_;
+ if (!t1.isScopeQual)
+ stc1 |= STC.ref_;
+ }
+ if (t2.isreturn)
+ {
+ stc2 |= STC.return_;
+ if (!t2.isScopeQual)
+ stc2 |= STC.ref_;
+ }
+ if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
+ goto Lnotcovariant;
+ }
+
+ // We can subtract 'return ref' from 'this', but cannot add it
+ else if (t1.isreturn && !t2.isreturn)
+ goto Lnotcovariant;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=23135
+ * extern(C++) mutable member functions are not covariant with const.
+ */
+ if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
+ goto Lnotcovariant;
+
+ /* Can convert mutable to const
+ */
+ if (!MODimplicitConv(t2.mod, t1.mod))
+ {
+ version (none)
+ {
+ //stop attribute inference with const
+ // If adding 'const' will make it covariant
+ if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
+ stc |= STC.const_;
+ else
+ goto Lnotcovariant;
+ }
+ else
+ {
+ goto Ldistinct;
+ }
+ }
+
+ /* Can convert pure to impure, nothrow to throw, and nogc to gc
+ */
+ if (!t1.purity && t2.purity)
+ stc |= STC.pure_;
+
+ if (!t1.isnothrow && t2.isnothrow)
+ stc |= STC.nothrow_;
+
+ if (!t1.isnogc && t2.isnogc)
+ stc |= STC.nogc;
+
+ /* Can convert safe/trusted to system
+ */
+ if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
+ {
+ // Should we infer trusted or safe? Go with safe.
+ stc |= STC.safe;
+ }
+
+ if (stc)
+ {
+ if (pstc)
+ *pstc = stc;
+ goto Lnotcovariant;
+ }
+
+ //printf("\tcovaraint: 1\n");
+ return Covariant.yes;
+
+Ldistinct:
+ //printf("\tcovaraint: 0\n");
+ return Covariant.distinct;
+
+Lnotcovariant:
+ //printf("\tcovaraint: 2\n");
+ return Covariant.no;
+}
+
/******************************* Private *****************************************/
private:
diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi
index e6a8a90..fe1c625 100644
--- a/gcc/d/gdc.texi
+++ b/gcc/d/gdc.texi
@@ -740,8 +740,10 @@ arguments like @code{va_start}.
@opindex fignore-unknown-pragmas
@opindex fno-ignore-unknown-pragmas
-@item -fignore-unknown-pragmas
-Turns off errors for unsupported pragmas.
+@item -fno-ignore-unknown-pragmas
+Do not recognize unsupported pragmas. Any @code{pragma()} encountered that is
+not part of the D language will result in an error. This option is now
+deprecated and will be removed in a future release.
@opindex fmax-errors
@item -fmax-errors=@var{n}
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index f67113141..257a2ab 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "dmd/aggregate.h"
+#include "dmd/dsymbol.h"
#include "dmd/enum.h"
#include "dmd/errors.h"
#include "dmd/expression.h"
@@ -205,7 +206,7 @@ make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL)
/* Create object module in order to complete the semantic. */
if (!object_module->_scope)
- object_module->importAll (NULL);
+ importAll (object_module, NULL);
/* Object class doesn't exist, create a stub one that will cause an error if
used. */