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.
This commit is contained in:
parent
cfc6d9ae81
commit
838e706fa5
65 changed files with 3210 additions and 1961 deletions
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1 +1 @@
|
|||
v2.106.0
|
||||
v2.106.1-rc.1
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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); }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -60,6 +60,20 @@ class ErrorSinkNull : ErrorSink
|
|||
void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
|
||||
}
|
||||
|
||||
/*****************************************
|
||||
* 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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
/* Try peeling off this set of { } and see if it works
|
||||
*/
|
||||
cprev = ci;
|
||||
ci = di.initializer.isCInitializer();
|
||||
indexprev = index;
|
||||
index = 0;
|
||||
goto L1;
|
||||
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())
|
||||
{
|
||||
/* 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
|
||||
*/
|
||||
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])
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
@ -4641,185 +4345,6 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
return buf.extractChars();
|
||||
}
|
||||
|
||||
/********************************
|
||||
* '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
|
||||
|
@ -7234,328 +6759,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
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/***********************************************************
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -26,3 +26,7 @@ _Static_assert(F80 == 9.0L, "9");
|
|||
|
||||
#define SSS "hello"
|
||||
_Static_assert(SSS[0] == 'h', "10");
|
||||
|
||||
#define ABC 12
|
||||
#define GHI (size) abbadabba
|
||||
#define DEF (ABC + 5)
|
||||
|
|
|
@ -1,86 +0,0 @@
|
|||
// REQUIRED_ARGS: -o-
|
||||
// PERMUTE_ARGS:
|
||||
|
||||
template TypeTuple(T...) { alias TypeTuple = T; }
|
||||
|
||||
bool startsWith(string s, string m) { return s[0 .. m.length] == m; }
|
||||
|
||||
void main()
|
||||
{
|
||||
enum string castPrefix = "cast(" ~ size_t.stringof ~ ")";
|
||||
|
||||
// TypeSArray
|
||||
static assert((int[10]).stringof == "int[10]", T.stringof);
|
||||
|
||||
int[] arr;
|
||||
|
||||
// IndexExp
|
||||
{
|
||||
// index == IntegerExp
|
||||
static assert((arr[ 4 ]).stringof == "arr[4]");
|
||||
static assert((arr[ 4U ]).stringof == "arr[4]");
|
||||
static assert((arr[ 4L ]).stringof == "arr[4]");
|
||||
static assert((arr[ 4LU]).stringof == "arr[4]");
|
||||
|
||||
// index == UAddExp
|
||||
static assert((arr[+4 ]).stringof == "arr[4]");
|
||||
static assert((arr[+4U ]).stringof == "arr[4]");
|
||||
static assert((arr[+4L ]).stringof == "arr[4]");
|
||||
static assert((arr[+4LU]).stringof == "arr[4]");
|
||||
|
||||
// index == NegExp
|
||||
static assert((arr[-4 ]).stringof == "arr[" ~ castPrefix ~ "-4]");
|
||||
static assert((arr[-4U ]).stringof == "arr[4294967292]");
|
||||
static assert((arr[int.min] ).stringof == "arr[" ~ castPrefix ~ "-2147483648]");
|
||||
static if (is(size_t == ulong))
|
||||
{
|
||||
static assert((arr[-4L ]).stringof == "arr[" ~ castPrefix ~ "-4L]");
|
||||
static assert((arr[-4LU]).stringof == "arr[-4LU]");
|
||||
|
||||
// IntegerLiteral needs suffix if the value is greater than long.max
|
||||
static assert((arr[long.max + 0]).stringof == "arr[9223372036854775807]");
|
||||
static assert((arr[long.max + 1]).stringof == "arr[" ~ castPrefix ~ "(9223372036854775807L + 1L)]");
|
||||
}
|
||||
|
||||
foreach (Int; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong))
|
||||
{
|
||||
enum Int p4 = +4;
|
||||
enum string result1 = (arr[p4]).stringof;
|
||||
static assert(result1 == "arr[4]");
|
||||
|
||||
enum string result2 = (arr[cast(Int)+4]).stringof;
|
||||
static assert(result2 == "arr[4]");
|
||||
}
|
||||
foreach (Int; TypeTuple!(byte, short, int, long))
|
||||
{
|
||||
// keep "cast(Type)" in the string representation
|
||||
|
||||
enum Int m4 = -4;
|
||||
static if (is(typeof({ size_t x = m4; })))
|
||||
{
|
||||
enum string result1 = (arr[m4]).stringof;
|
||||
static assert(result1.startsWith("arr[" ~ castPrefix));
|
||||
}
|
||||
else
|
||||
static assert(!__traits(compiles, arr[m4]));
|
||||
|
||||
enum string result2 = (arr[cast(Int)-4]).stringof;
|
||||
static assert(result2.startsWith("arr[" ~ castPrefix));
|
||||
}
|
||||
}
|
||||
|
||||
// SliceExp
|
||||
{
|
||||
// lwr,upr == IntegerExp
|
||||
static assert((arr[4 .. 8 ]).stringof == "arr[4..8]");
|
||||
static assert((arr[4U .. 8U ]).stringof == "arr[4..8]");
|
||||
static assert((arr[4L .. 8L ]).stringof == "arr[4..8]");
|
||||
static assert((arr[4LU .. 8LU]).stringof == "arr[4..8]");
|
||||
|
||||
// lwr,upr == UAddExp
|
||||
static assert((arr[+4 .. +8 ]).stringof == "arr[4..8]");
|
||||
static assert((arr[+4U .. +8U ]).stringof == "arr[4..8]");
|
||||
static assert((arr[+4L .. +8L ]).stringof == "arr[4..8]");
|
||||
static assert((arr[+4LU .. +8LU]).stringof == "arr[4..8]");
|
||||
}
|
||||
}
|
|
@ -12,3 +12,6 @@ static assert(F64 == 8.0);
|
|||
static assert(F80 == 9.0L);
|
||||
|
||||
static assert(SSS == "hello");
|
||||
|
||||
static assert(ABC == 12);
|
||||
static assert(DEF == 17);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
|
||||
fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
|
||||
fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
|
||||
fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ TEST_OUTPUT:
|
|||
---
|
||||
fail_compilation/pragmas.d(103): Error: one boolean expression expected for `pragma(inline)`, not 2
|
||||
fail_compilation/pragmas.d(108): Error: one boolean expression expected for `pragma(inline)`, not 2
|
||||
fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)`
|
||||
---
|
||||
*/
|
||||
|
||||
|
@ -28,5 +27,5 @@ void test3()
|
|||
|
||||
void test4()
|
||||
{
|
||||
pragma(unrecognized, "string");
|
||||
pragma(unrecognized, "string"); // permitted, just ignored
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -202,26 +202,26 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
|
|||
core/stdc/ctype.d core/stdc/errno.d core/stdc/fenv.d \
|
||||
core/stdc/float_.d core/stdc/inttypes.d core/stdc/limits.d \
|
||||
core/stdc/locale.d core/stdc/math.d core/stdc/signal.d \
|
||||
core/stdc/stdarg.d core/stdc/stddef.d core/stdc/stdint.d \
|
||||
core/stdc/stdio.d core/stdc/stdlib.d core/stdc/string.d \
|
||||
core/stdc/tgmath.d core/stdc/time.d core/stdc/wchar_.d \
|
||||
core/stdc/wctype.d core/sync/barrier.d core/sync/condition.d \
|
||||
core/sync/config.d core/sync/event.d core/sync/exception.d \
|
||||
core/sync/mutex.d core/sync/package.d core/sync/rwmutex.d \
|
||||
core/sync/semaphore.d core/thread/context.d core/thread/fiber.d \
|
||||
core/thread/osthread.d core/thread/package.d core/thread/threadbase.d \
|
||||
core/thread/threadgroup.d core/thread/types.d core/time.d \
|
||||
core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \
|
||||
gcc/attributes.d gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d \
|
||||
gcc/gthread.d gcc/sections/common.d gcc/sections/elf.d \
|
||||
gcc/sections/macho.d gcc/sections/package.d gcc/sections/pecoff.d \
|
||||
gcc/simd.d gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
|
||||
gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \
|
||||
rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \
|
||||
rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \
|
||||
rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \
|
||||
rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \
|
||||
rt/util/utility.d
|
||||
core/stdc/stdarg.d core/stdc/stdatomic.d core/stdc/stddef.d \
|
||||
core/stdc/stdint.d core/stdc/stdio.d core/stdc/stdlib.d \
|
||||
core/stdc/string.d core/stdc/tgmath.d core/stdc/time.d \
|
||||
core/stdc/wchar_.d core/stdc/wctype.d core/sync/barrier.d \
|
||||
core/sync/condition.d core/sync/config.d core/sync/event.d \
|
||||
core/sync/exception.d core/sync/mutex.d core/sync/package.d \
|
||||
core/sync/rwmutex.d core/sync/semaphore.d core/thread/context.d \
|
||||
core/thread/fiber.d core/thread/osthread.d core/thread/package.d \
|
||||
core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \
|
||||
core/time.d core/vararg.d core/volatile.d etc/valgrind/valgrind.d \
|
||||
gcc/attribute.d gcc/attributes.d gcc/backtrace.d gcc/builtins.d \
|
||||
gcc/deh.d gcc/emutls.d gcc/gthread.d gcc/sections/common.d \
|
||||
gcc/sections/elf.d gcc/sections/macho.d gcc/sections/package.d \
|
||||
gcc/sections/pecoff.d gcc/simd.d gcc/unwind/arm.d \
|
||||
gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \
|
||||
gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \
|
||||
rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \
|
||||
rt/deh.d rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d \
|
||||
rt/memory.d rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d \
|
||||
rt/tlsgc.d rt/util/typeinfo.d rt/util/utility.d
|
||||
|
||||
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \
|
||||
core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \
|
||||
|
|
|
@ -225,23 +225,24 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
|
|||
core/stdc/config.lo core/stdc/ctype.lo core/stdc/errno.lo \
|
||||
core/stdc/fenv.lo core/stdc/float_.lo core/stdc/inttypes.lo \
|
||||
core/stdc/limits.lo core/stdc/locale.lo core/stdc/math.lo \
|
||||
core/stdc/signal.lo core/stdc/stdarg.lo core/stdc/stddef.lo \
|
||||
core/stdc/stdint.lo core/stdc/stdio.lo core/stdc/stdlib.lo \
|
||||
core/stdc/string.lo core/stdc/tgmath.lo core/stdc/time.lo \
|
||||
core/stdc/wchar_.lo core/stdc/wctype.lo core/sync/barrier.lo \
|
||||
core/sync/condition.lo core/sync/config.lo core/sync/event.lo \
|
||||
core/sync/exception.lo core/sync/mutex.lo core/sync/package.lo \
|
||||
core/sync/rwmutex.lo core/sync/semaphore.lo \
|
||||
core/thread/context.lo core/thread/fiber.lo \
|
||||
core/thread/osthread.lo core/thread/package.lo \
|
||||
core/thread/threadbase.lo core/thread/threadgroup.lo \
|
||||
core/thread/types.lo core/time.lo core/vararg.lo \
|
||||
core/volatile.lo etc/valgrind/valgrind.lo gcc/attribute.lo \
|
||||
gcc/attributes.lo gcc/backtrace.lo gcc/builtins.lo gcc/deh.lo \
|
||||
gcc/emutls.lo gcc/gthread.lo gcc/sections/common.lo \
|
||||
gcc/sections/elf.lo gcc/sections/macho.lo \
|
||||
gcc/sections/package.lo gcc/sections/pecoff.lo gcc/simd.lo \
|
||||
gcc/unwind/arm.lo gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
|
||||
core/stdc/signal.lo core/stdc/stdarg.lo core/stdc/stdatomic.lo \
|
||||
core/stdc/stddef.lo core/stdc/stdint.lo core/stdc/stdio.lo \
|
||||
core/stdc/stdlib.lo core/stdc/string.lo core/stdc/tgmath.lo \
|
||||
core/stdc/time.lo core/stdc/wchar_.lo core/stdc/wctype.lo \
|
||||
core/sync/barrier.lo core/sync/condition.lo \
|
||||
core/sync/config.lo core/sync/event.lo core/sync/exception.lo \
|
||||
core/sync/mutex.lo core/sync/package.lo core/sync/rwmutex.lo \
|
||||
core/sync/semaphore.lo core/thread/context.lo \
|
||||
core/thread/fiber.lo core/thread/osthread.lo \
|
||||
core/thread/package.lo core/thread/threadbase.lo \
|
||||
core/thread/threadgroup.lo core/thread/types.lo core/time.lo \
|
||||
core/vararg.lo core/volatile.lo etc/valgrind/valgrind.lo \
|
||||
gcc/attribute.lo gcc/attributes.lo gcc/backtrace.lo \
|
||||
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
|
||||
gcc/sections/common.lo gcc/sections/elf.lo \
|
||||
gcc/sections/macho.lo gcc/sections/package.lo \
|
||||
gcc/sections/pecoff.lo gcc/simd.lo gcc/unwind/arm.lo \
|
||||
gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
|
||||
gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \
|
||||
object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \
|
||||
rt/arraycat.lo rt/cast_.lo rt/config.lo rt/critical_.lo \
|
||||
|
@ -879,26 +880,26 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
|
|||
core/stdc/ctype.d core/stdc/errno.d core/stdc/fenv.d \
|
||||
core/stdc/float_.d core/stdc/inttypes.d core/stdc/limits.d \
|
||||
core/stdc/locale.d core/stdc/math.d core/stdc/signal.d \
|
||||
core/stdc/stdarg.d core/stdc/stddef.d core/stdc/stdint.d \
|
||||
core/stdc/stdio.d core/stdc/stdlib.d core/stdc/string.d \
|
||||
core/stdc/tgmath.d core/stdc/time.d core/stdc/wchar_.d \
|
||||
core/stdc/wctype.d core/sync/barrier.d core/sync/condition.d \
|
||||
core/sync/config.d core/sync/event.d core/sync/exception.d \
|
||||
core/sync/mutex.d core/sync/package.d core/sync/rwmutex.d \
|
||||
core/sync/semaphore.d core/thread/context.d core/thread/fiber.d \
|
||||
core/thread/osthread.d core/thread/package.d core/thread/threadbase.d \
|
||||
core/thread/threadgroup.d core/thread/types.d core/time.d \
|
||||
core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \
|
||||
gcc/attributes.d gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d \
|
||||
gcc/gthread.d gcc/sections/common.d gcc/sections/elf.d \
|
||||
gcc/sections/macho.d gcc/sections/package.d gcc/sections/pecoff.d \
|
||||
gcc/simd.d gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
|
||||
gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \
|
||||
rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \
|
||||
rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \
|
||||
rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \
|
||||
rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \
|
||||
rt/util/utility.d
|
||||
core/stdc/stdarg.d core/stdc/stdatomic.d core/stdc/stddef.d \
|
||||
core/stdc/stdint.d core/stdc/stdio.d core/stdc/stdlib.d \
|
||||
core/stdc/string.d core/stdc/tgmath.d core/stdc/time.d \
|
||||
core/stdc/wchar_.d core/stdc/wctype.d core/sync/barrier.d \
|
||||
core/sync/condition.d core/sync/config.d core/sync/event.d \
|
||||
core/sync/exception.d core/sync/mutex.d core/sync/package.d \
|
||||
core/sync/rwmutex.d core/sync/semaphore.d core/thread/context.d \
|
||||
core/thread/fiber.d core/thread/osthread.d core/thread/package.d \
|
||||
core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \
|
||||
core/time.d core/vararg.d core/volatile.d etc/valgrind/valgrind.d \
|
||||
gcc/attribute.d gcc/attributes.d gcc/backtrace.d gcc/builtins.d \
|
||||
gcc/deh.d gcc/emutls.d gcc/gthread.d gcc/sections/common.d \
|
||||
gcc/sections/elf.d gcc/sections/macho.d gcc/sections/package.d \
|
||||
gcc/sections/pecoff.d gcc/simd.d gcc/unwind/arm.d \
|
||||
gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \
|
||||
gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \
|
||||
rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \
|
||||
rt/deh.d rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d \
|
||||
rt/memory.d rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d \
|
||||
rt/tlsgc.d rt/util/typeinfo.d rt/util/utility.d
|
||||
|
||||
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \
|
||||
core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \
|
||||
|
@ -1316,6 +1317,7 @@ core/stdc/locale.lo: core/stdc/$(am__dirstamp)
|
|||
core/stdc/math.lo: core/stdc/$(am__dirstamp)
|
||||
core/stdc/signal.lo: core/stdc/$(am__dirstamp)
|
||||
core/stdc/stdarg.lo: core/stdc/$(am__dirstamp)
|
||||
core/stdc/stdatomic.lo: core/stdc/$(am__dirstamp)
|
||||
core/stdc/stddef.lo: core/stdc/$(am__dirstamp)
|
||||
core/stdc/stdint.lo: core/stdc/$(am__dirstamp)
|
||||
core/stdc/stdio.lo: core/stdc/$(am__dirstamp)
|
||||
|
|
|
@ -33,7 +33,7 @@ version (LDC) version = GNU_OR_LDC;
|
|||
*
|
||||
* Returns: the slice containing the result
|
||||
*/
|
||||
T[] arrayOp(T : T[], Args...)(T[] res, Filter!(isType, Args) args) @trusted @nogc pure nothrow
|
||||
T[] arrayOp(T : T[], Args...)(T[] res, Filter!(isType, Args) args) @trusted
|
||||
{
|
||||
alias scalarizedExp = staticMap!(toElementType, Args);
|
||||
alias check = typeCheck!(true, T, scalarizedExp); // must support all scalar ops
|
||||
|
@ -541,7 +541,7 @@ unittest
|
|||
}
|
||||
|
||||
// test handling of v op= exp
|
||||
unittest
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
uint[32] c;
|
||||
arrayOp!(uint[], uint, "+=")(c[], 2);
|
||||
|
@ -556,7 +556,7 @@ unittest
|
|||
}
|
||||
|
||||
// proper error message for UDT lacking certain ops
|
||||
unittest
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
static assert(!is(typeof(&arrayOp!(int[4][], int[4], "+="))));
|
||||
static assert(!is(typeof(&arrayOp!(int[4][], int[4], "u-", "="))));
|
||||
|
@ -585,7 +585,7 @@ unittest
|
|||
}
|
||||
|
||||
// test mixed type array op
|
||||
unittest
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
uint[32] a = 0xF;
|
||||
float[32] res = 2.0f;
|
||||
|
@ -595,7 +595,7 @@ unittest
|
|||
}
|
||||
|
||||
// test mixed type array op
|
||||
unittest
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
static struct S
|
||||
{
|
||||
|
@ -613,7 +613,7 @@ unittest
|
|||
}
|
||||
|
||||
// test scalar after operation argument
|
||||
unittest
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
float[32] res, a = 2, b = 3;
|
||||
float c = 4;
|
||||
|
@ -622,7 +622,7 @@ unittest
|
|||
assert(v == 2 * 3 + 4);
|
||||
}
|
||||
|
||||
unittest
|
||||
@nogc nothrow pure @safe unittest
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=17964
|
||||
uint bug(){
|
||||
|
@ -635,7 +635,7 @@ unittest
|
|||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=19796
|
||||
unittest
|
||||
nothrow pure @safe unittest
|
||||
{
|
||||
double[] data = [0.5];
|
||||
double[] result;
|
||||
|
@ -645,7 +645,7 @@ unittest
|
|||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21110
|
||||
unittest
|
||||
pure unittest
|
||||
{
|
||||
import core.exception;
|
||||
|
||||
|
@ -668,3 +668,20 @@ unittest
|
|||
void func() { dst[] = a[] + b[]; }
|
||||
assertThrown!AssertError(func(), "Array operations with mismatched lengths must throw an error");
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=24272
|
||||
unittest
|
||||
{
|
||||
static struct B
|
||||
{
|
||||
B opOpAssign(string op)(B other)
|
||||
{
|
||||
static int g;
|
||||
g++;
|
||||
throw new Exception("");
|
||||
}
|
||||
}
|
||||
|
||||
B[] bArr;
|
||||
bArr[] += B();
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ version (DigitalMars)
|
|||
enum SizedReg(int reg, T = size_t) = registerNames[reg][RegIndex!T];
|
||||
}
|
||||
|
||||
enum IsAtomicLockFree(T) = T.sizeof <= size_t.sizeof * 2;
|
||||
|
||||
inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted
|
||||
if (CanCAS!T)
|
||||
{
|
||||
|
@ -649,6 +651,11 @@ version (DigitalMars)
|
|||
}
|
||||
}
|
||||
|
||||
void atomicSignalFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted
|
||||
{
|
||||
// no-op, dmd doesn't reorder instructions
|
||||
}
|
||||
|
||||
void pause() pure nothrow @nogc @trusted
|
||||
{
|
||||
version (D_InlineAsm_X86)
|
||||
|
@ -681,37 +688,57 @@ else version (GNU)
|
|||
import gcc.builtins;
|
||||
import gcc.config;
|
||||
|
||||
// Targets where MemoryOrder.acq_rel is sufficiently cheaper than using
|
||||
// MemoryOrder.seq, used when the MemoryOrder requested is not valid for
|
||||
// a given atomic operation.
|
||||
version (IA64)
|
||||
private enum PreferAcquireRelease = true;
|
||||
else version (PPC)
|
||||
private enum PreferAcquireRelease = true;
|
||||
else version (PPC64)
|
||||
private enum PreferAcquireRelease = true;
|
||||
else
|
||||
private enum PreferAcquireRelease = false;
|
||||
|
||||
enum IsAtomicLockFree(T) = __atomic_is_lock_free(T.sizeof, null);
|
||||
|
||||
inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted
|
||||
if (CanCAS!T)
|
||||
{
|
||||
// MemoryOrder.rel and MemoryOrder.acq_rel are not valid for load.
|
||||
static assert(order != MemoryOrder.rel, "invalid MemoryOrder for atomicLoad()");
|
||||
|
||||
static if (order == MemoryOrder.acq_rel)
|
||||
enum smodel = PreferAcquireRelease ? MemoryOrder.acq : MemoryOrder.seq;
|
||||
else
|
||||
enum smodel = order;
|
||||
|
||||
static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
|
||||
{
|
||||
static if (T.sizeof == ubyte.sizeof)
|
||||
{
|
||||
ubyte value = __atomic_load_1(cast(shared)src, order);
|
||||
ubyte value = __atomic_load_1(cast(shared)src, smodel);
|
||||
return *cast(typeof(return)*)&value;
|
||||
}
|
||||
else static if (T.sizeof == ushort.sizeof)
|
||||
{
|
||||
ushort value = __atomic_load_2(cast(shared)src, order);
|
||||
ushort value = __atomic_load_2(cast(shared)src, smodel);
|
||||
return *cast(typeof(return)*)&value;
|
||||
}
|
||||
else static if (T.sizeof == uint.sizeof)
|
||||
{
|
||||
uint value = __atomic_load_4(cast(shared)src, order);
|
||||
uint value = __atomic_load_4(cast(shared)src, smodel);
|
||||
return *cast(typeof(return)*)&value;
|
||||
}
|
||||
else static if (T.sizeof == ulong.sizeof && GNU_Have_64Bit_Atomics)
|
||||
{
|
||||
ulong value = __atomic_load_8(cast(shared)src, order);
|
||||
ulong value = __atomic_load_8(cast(shared)src, smodel);
|
||||
return *cast(typeof(return)*)&value;
|
||||
}
|
||||
else static if (GNU_Have_LibAtomic)
|
||||
{
|
||||
T value;
|
||||
__atomic_load(T.sizeof, cast(shared)src, &value, order);
|
||||
__atomic_load(T.sizeof, cast(shared)src, &value, smodel);
|
||||
return *cast(typeof(return)*)&value;
|
||||
}
|
||||
else
|
||||
|
@ -728,20 +755,26 @@ else version (GNU)
|
|||
void atomicStore(MemoryOrder order = MemoryOrder.seq, T)(T* dest, T value) pure nothrow @nogc @trusted
|
||||
if (CanCAS!T)
|
||||
{
|
||||
// MemoryOrder.acq and MemoryOrder.acq_rel are not valid for store.
|
||||
static assert(order != MemoryOrder.acq, "Invalid MemoryOrder for atomicStore()");
|
||||
|
||||
static if (order == MemoryOrder.acq_rel)
|
||||
enum smodel = PreferAcquireRelease ? MemoryOrder.rel : MemoryOrder.seq;
|
||||
else
|
||||
enum smodel = order;
|
||||
|
||||
static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
|
||||
{
|
||||
static if (T.sizeof == ubyte.sizeof)
|
||||
__atomic_store_1(cast(shared)dest, *cast(ubyte*)&value, order);
|
||||
__atomic_store_1(cast(shared)dest, *cast(ubyte*)&value, smodel);
|
||||
else static if (T.sizeof == ushort.sizeof)
|
||||
__atomic_store_2(cast(shared)dest, *cast(ushort*)&value, order);
|
||||
__atomic_store_2(cast(shared)dest, *cast(ushort*)&value, smodel);
|
||||
else static if (T.sizeof == uint.sizeof)
|
||||
__atomic_store_4(cast(shared)dest, *cast(uint*)&value, order);
|
||||
__atomic_store_4(cast(shared)dest, *cast(uint*)&value, smodel);
|
||||
else static if (T.sizeof == ulong.sizeof && GNU_Have_64Bit_Atomics)
|
||||
__atomic_store_8(cast(shared)dest, *cast(ulong*)&value, order);
|
||||
__atomic_store_8(cast(shared)dest, *cast(ulong*)&value, smodel);
|
||||
else static if (GNU_Have_LibAtomic)
|
||||
__atomic_store(T.sizeof, cast(shared)dest, cast(void*)&value, order);
|
||||
__atomic_store(T.sizeof, cast(shared)dest, cast(void*)&value, smodel);
|
||||
else
|
||||
static assert(0, "Invalid template type specified.");
|
||||
}
|
||||
|
@ -814,30 +847,36 @@ else version (GNU)
|
|||
{
|
||||
static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
|
||||
{
|
||||
// MemoryOrder.acq is not valid for exchange.
|
||||
static if (order == MemoryOrder.acq)
|
||||
enum smodel = PreferAcquireRelease ? MemoryOrder.acq_rel : MemoryOrder.seq;
|
||||
else
|
||||
enum smodel = order;
|
||||
|
||||
static if (T.sizeof == byte.sizeof)
|
||||
{
|
||||
ubyte res = __atomic_exchange_1(cast(shared)dest, *cast(ubyte*)&value, order);
|
||||
ubyte res = __atomic_exchange_1(cast(shared)dest, *cast(ubyte*)&value, smodel);
|
||||
return *cast(typeof(return)*)&res;
|
||||
}
|
||||
else static if (T.sizeof == short.sizeof)
|
||||
{
|
||||
ushort res = __atomic_exchange_2(cast(shared)dest, *cast(ushort*)&value, order);
|
||||
ushort res = __atomic_exchange_2(cast(shared)dest, *cast(ushort*)&value, smodel);
|
||||
return *cast(typeof(return)*)&res;
|
||||
}
|
||||
else static if (T.sizeof == int.sizeof)
|
||||
{
|
||||
uint res = __atomic_exchange_4(cast(shared)dest, *cast(uint*)&value, order);
|
||||
uint res = __atomic_exchange_4(cast(shared)dest, *cast(uint*)&value, smodel);
|
||||
return *cast(typeof(return)*)&res;
|
||||
}
|
||||
else static if (T.sizeof == long.sizeof && GNU_Have_64Bit_Atomics)
|
||||
{
|
||||
ulong res = __atomic_exchange_8(cast(shared)dest, *cast(ulong*)&value, order);
|
||||
ulong res = __atomic_exchange_8(cast(shared)dest, *cast(ulong*)&value, smodel);
|
||||
return *cast(typeof(return)*)&res;
|
||||
}
|
||||
else static if (GNU_Have_LibAtomic)
|
||||
{
|
||||
T res = void;
|
||||
__atomic_exchange(T.sizeof, cast(shared)dest, cast(void*)&value, &res, order);
|
||||
__atomic_exchange(T.sizeof, cast(shared)dest, cast(void*)&value, &res, smodel);
|
||||
return res;
|
||||
}
|
||||
else
|
||||
|
@ -885,21 +924,42 @@ else version (GNU)
|
|||
|
||||
static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
|
||||
{
|
||||
static if (fail == MemoryOrder.rel || fail == MemoryOrder.acq_rel)
|
||||
{
|
||||
// MemoryOrder.rel and MemoryOrder.acq_rel are not valid failure models.
|
||||
enum smodel = (succ != MemoryOrder.seq && PreferAcquireRelease)
|
||||
? MemoryOrder.acq_rel : MemoryOrder.seq;
|
||||
enum fmodel = (succ != MemoryOrder.seq && PreferAcquireRelease)
|
||||
? MemoryOrder.raw : MemoryOrder.seq;
|
||||
}
|
||||
else static if (fail > succ)
|
||||
{
|
||||
// Failure memory model cannot be stronger than success.
|
||||
enum smodel = (fail != MemoryOrder.seq && PreferAcquireRelease)
|
||||
? MemoryOrder.acq_rel : MemoryOrder.seq;
|
||||
enum fmodel = fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
enum smodel = succ;
|
||||
enum fmodel = fail;
|
||||
}
|
||||
|
||||
static if (T.sizeof == byte.sizeof)
|
||||
res = __atomic_compare_exchange_1(cast(shared)dest, compare, *cast(ubyte*)&value,
|
||||
weak, succ, fail);
|
||||
weak, smodel, fmodel);
|
||||
else static if (T.sizeof == short.sizeof)
|
||||
res = __atomic_compare_exchange_2(cast(shared)dest, compare, *cast(ushort*)&value,
|
||||
weak, succ, fail);
|
||||
weak, smodel, fmodel);
|
||||
else static if (T.sizeof == int.sizeof)
|
||||
res = __atomic_compare_exchange_4(cast(shared)dest, compare, *cast(uint*)&value,
|
||||
weak, succ, fail);
|
||||
weak, smodel, fmodel);
|
||||
else static if (T.sizeof == long.sizeof && GNU_Have_64Bit_Atomics)
|
||||
res = __atomic_compare_exchange_8(cast(shared)dest, compare, *cast(ulong*)&value,
|
||||
weak, succ, fail);
|
||||
weak, smodel, fmodel);
|
||||
else static if (GNU_Have_LibAtomic)
|
||||
res = __atomic_compare_exchange(T.sizeof, cast(shared)dest, compare, cast(void*)&value,
|
||||
succ, fail);
|
||||
smodel, fmodel);
|
||||
else
|
||||
static assert(0, "Invalid template type specified.");
|
||||
}
|
||||
|
@ -945,6 +1005,11 @@ else version (GNU)
|
|||
}
|
||||
}
|
||||
|
||||
void atomicSignalFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted
|
||||
{
|
||||
__atomic_signal_fence(order);
|
||||
}
|
||||
|
||||
void pause() pure nothrow @nogc @trusted
|
||||
{
|
||||
version (X86)
|
||||
|
|
1124
libphobos/libdruntime/core/stdc/stdatomic.d
Normal file
1124
libphobos/libdruntime/core/stdc/stdatomic.d
Normal file
File diff suppressed because it is too large
Load diff
|
@ -2129,6 +2129,13 @@ extern (C) void thread_init() @nogc nothrow
|
|||
static extern(C) void initChildAfterFork()
|
||||
{
|
||||
auto thisThread = Thread.getThis();
|
||||
if (!thisThread)
|
||||
{
|
||||
// It is possible that runtime was not properly initialized in the current process or thread -
|
||||
// it may happen after `fork` call when using a dynamically loaded shared library written in D from a multithreaded non-D program.
|
||||
// In such case getThis will return null.
|
||||
return;
|
||||
}
|
||||
thisThread.m_addr = pthread_self();
|
||||
assert( thisThread.m_addr != thisThread.m_addr.init );
|
||||
thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );
|
||||
|
|
|
@ -526,6 +526,12 @@ unittest
|
|||
|
||||
private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow;
|
||||
|
||||
/** Makes ownee use owner's mutex.
|
||||
* This will initialize owner's mutex if it hasn't been set yet.
|
||||
* Params:
|
||||
* ownee = object to change
|
||||
* owner = source object
|
||||
*/
|
||||
void setSameMutex(shared Object ownee, shared Object owner)
|
||||
{
|
||||
import core.atomic : atomicLoad;
|
||||
|
|
Loading…
Add table
Reference in a new issue