@@ -1,4 +1,4 @@
-65a3da148c0c700a6c928f0e13799b2a7d34fcbe
+ff57fec51558013b25cadb7e83da9f4675915d56
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-beta.1
+v2.106.0-rc.1
@@ -663,7 +663,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
*/
extern (D) final Dsymbol searchCtor()
{
- auto s = search(Loc.initial, Id.ctor);
+ auto s = this.search(Loc.initial, Id.ctor);
if (s)
{
if (!(s.isCtorDeclaration() ||
@@ -167,7 +167,6 @@ private:
public:
static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject);
StructDeclaration *syntaxCopy(Dsymbol *s) override;
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
const char *kind() const override;
void finalizeSize() override final;
bool isPOD();
@@ -285,7 +284,6 @@ public:
virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);
bool isBaseInfoComplete();
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
void finalizeSize() override;
bool hasMonitor();
bool isFuncHidden(FuncDeclaration *fd);
@@ -383,6 +383,7 @@ enum STMT : ubyte
enum InitKind : ubyte
{
void_,
+ default_,
error,
struct_,
array,
@@ -32,7 +32,7 @@ import dmd.declaration;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem : dsymbolSemantic;
+import dmd.dsymbolsem;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
@@ -123,18 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
return sc;
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- Dsymbols* d = include(sc);
- if (d)
- {
- Scope* sc2 = newScope(sc);
- d.foreachDsymbol( s => s.addMember(sc2, sds) );
- if (sc2 != sc)
- sc2.pop();
- }
- }
-
override void setScope(Scope* sc)
{
Dsymbols* d = include(sc);
@@ -295,34 +283,6 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration
return t;
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- Dsymbols* d = include(sc);
- if (d)
- {
- Scope* sc2 = newScope(sc);
-
- d.foreachDsymbol( (s)
- {
- //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars());
- // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol)
- if (auto decl = s.isDeclaration())
- {
- decl.storage_class |= stc & STC.local;
- if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case?
- {
- sdecl.stc |= stc & STC.local;
- }
- }
- s.addMember(sc2, sds);
- });
-
- if (sc2 != sc)
- sc2.pop();
- }
-
- }
-
override inout(StorageClassDeclaration) isStorageClassDeclaration() inout
{
return this;
@@ -640,37 +600,6 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration
return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining);
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- if (pkg_identifiers)
- {
- Dsymbol tmp;
- Package.resolve(pkg_identifiers, &tmp, null);
- visibility.pkg = tmp ? tmp.isPackage() : null;
- pkg_identifiers = null;
- }
- if (visibility.kind == Visibility.Kind.package_ && visibility.pkg && sc._module)
- {
- Module m = sc._module;
-
- // https://issues.dlang.org/show_bug.cgi?id=17441
- // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if
- // each package's .isModule() properites are equal.
- //
- // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null.
- // This breaks package declarations of the package in question if they are declared in
- // the same package.d file, which _do_ have a module associated with them, and hence a non-null
- // isModule()
- if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident))
- {
- Package pkg = m.parent ? m.parent.isPackage() : null;
- if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg))
- .error(loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", kind(), toPrettyChars(false), m.toPrettyChars(true));
- }
- }
- return AttribDeclaration.addMember(sc, sds);
- }
-
override const(char)* kind() const
{
return "visibility attribute";
@@ -1054,23 +983,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
}
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
- /* This is deferred until the condition evaluated later (by the include() call),
- * so that expressions in the condition can refer to declarations
- * in the same scope, such as:
- *
- * template Foo(int i)
- * {
- * const int j = i + 1;
- * static if (j == 3)
- * const int k;
- * }
- */
- this.scopesym = sds;
- }
-
override void setScope(Scope* sc)
{
// do not evaluate condition before semantic pass
@@ -1186,12 +1098,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
return d;
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- // used only for caching the enclosing symbol
- this.scopesym = sds;
- }
-
override void addComment(const(char)* comment)
{
// do nothing
@@ -1266,15 +1172,6 @@ extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
return sc.push(sym);
}
- /***************************************
- * Lazily initializes the scope to forward to.
- */
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- sym.parent = sds;
- return super.addMember(sc, sym);
- }
-
override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
{
return this;
@@ -1312,12 +1209,6 @@ extern (C++) final class MixinDeclaration : AttribDeclaration
return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps));
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
- this.scopesym = sds;
- }
-
override void setScope(Scope* sc)
{
Dsymbol.setScope(sc);
@@ -26,7 +26,6 @@ public:
virtual Dsymbols *include(Scope *sc);
virtual Scope *newScope(Scope *sc);
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope *sc) override;
void importAll(Scope *sc) override;
void addComment(const utf8_t *comment) override;
@@ -49,7 +48,6 @@ public:
StorageClassDeclaration *syntaxCopy(Dsymbol *s) override;
Scope *newScope(Scope *sc) override;
bool oneMember(Dsymbol **ps, Identifier *ident) override final;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
StorageClassDeclaration *isStorageClassDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
@@ -110,7 +108,6 @@ public:
VisibilityDeclaration *syntaxCopy(Dsymbol *s) override;
Scope *newScope(Scope *sc) override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
const char *kind() const override;
const char *toPrettyChars(bool unused) override;
VisibilityDeclaration *isVisibilityDeclaration() override { return this; }
@@ -179,7 +176,6 @@ public:
StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
Dsymbols *include(Scope *sc) override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope *sc) override;
void importAll(Scope *sc) override;
StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
@@ -199,7 +195,6 @@ public:
StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override;
bool oneMember(Dsymbol **ps, Identifier *ident) override;
Dsymbols *include(Scope *sc) override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
void addComment(const utf8_t *comment) override;
void setScope(Scope *sc) override;
void importAll(Scope *sc) override;
@@ -213,7 +208,6 @@ public:
ForwardingScopeDsymbol *sym;
Scope *newScope(Scope *sc) override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
ForwardingAttribDeclaration *isForwardingAttribDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -229,7 +223,6 @@ public:
d_bool compiled;
MixinDeclaration *syntaxCopy(Dsymbol *s) override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope *sc) override;
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
@@ -281,7 +281,7 @@ struct OutBuffer
write(&v, v.sizeof);
}
- /// NOT zero-terminated
+ /// Buffer will NOT be zero-terminated
extern (C++) void writestring(const(char)* s) pure nothrow @system
{
if (!s)
@@ -302,14 +302,14 @@ struct OutBuffer
write(s);
}
- /// NOT zero-terminated, followed by newline
+ /// Buffer will NOT be zero-terminated, followed by newline
void writestringln(const(char)[] s) pure nothrow @safe
{
writestring(s);
writenl();
}
- /** Write string to buffer, ensure it is zero terminated
+ /** Write C string AND null byte
*/
void writeStringz(const(char)* s) pure nothrow @system
{
@@ -2168,6 +2168,7 @@ final class CParser(AST) : Parser!AST
* C11 Initialization
* initializer:
* assignment-expression
+ * { } // C23 6.7.10 addition
* { initializer-list }
* { initializer-list , }
*
@@ -2198,6 +2199,12 @@ final class CParser(AST) : Parser!AST
nextToken();
const loc = token.loc;
+ if (token.value == TOK.rightCurly) // { }
+ {
+ nextToken();
+ return new AST.DefaultInitializer(loc);
+ }
+
/* Collect one or more `designation (opt) initializer`
* into ci.initializerList, but lazily create ci
*/
@@ -28,6 +28,7 @@ import dmd.func;
import dmd.globals;
import dmd.location;
import dmd.mtype;
+import dmd.root.bitarray;
import dmd.root.complex;
import dmd.root.ctfloat;
import dmd.root.port;
@@ -43,14 +44,14 @@ import dmd.visitor;
extern (D) struct UnionExp
{
// yes, default constructor does nothing
- extern (D) this(Expression e)
+ extern (D) this(Expression e) nothrow
{
memcpy(&this, cast(void*)e, e.size);
}
/* Extract pointer to Expression
*/
- extern (D) Expression exp() return
+ extern (D) Expression exp() return nothrow
{
return cast(Expression)&u;
}
@@ -109,7 +110,7 @@ void emplaceExp(T : Expression, Args...)(void* p, Args args)
(cast(T)p).__ctor(args);
}
-void emplaceExp(T : UnionExp)(T* p, Expression e)
+void emplaceExp(T : UnionExp)(T* p, Expression e) nothrow
{
memcpy(p, cast(void*)e, e.size);
}
@@ -134,7 +135,7 @@ void generateUncaughtError(ThrownExceptionExp tee)
* Returns:
* index of the field, or -1 if not found
*/
-int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe
+int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe nothrow
{
foreach (i, field; sd.fields)
{
@@ -145,7 +146,7 @@ int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pur
}
// True if 'e' is CTFEExp::cantexp, or an exception
-bool exceptionOrCantInterpret(const Expression e) @safe
+bool exceptionOrCantInterpret(const Expression e) @safe nothrow
{
return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext);
}
@@ -153,7 +154,7 @@ bool exceptionOrCantInterpret(const Expression e) @safe
/************** Aggregate literals (AA/string/array/struct) ******************/
// Given expr, which evaluates to an array/AA/string literal,
// return true if it needs to be copied
-bool needToCopyLiteral(const Expression expr)
+bool needToCopyLiteral(const Expression expr) nothrow
{
Expression e = cast()expr;
for (;;)
@@ -593,7 +594,7 @@ TypeAArray toBuiltinAAType(Type t)
/************** TypeInfo operations ************************************/
// Return true if type is TypeInfo_Class
-bool isTypeInfo_Class(const Type type)
+bool isTypeInfo_Class(const Type type) nothrow
{
auto tc = cast()type.isTypeClass();
return tc && (Type.dtypeinfo == tc.sym || Type.dtypeinfo.isBaseOf(tc.sym, null));
@@ -741,14 +742,14 @@ Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expres
Expression agg2 = getAggregateFromPointer(e2, &ofs2);
if (agg1 == agg2)
{
- Type pointee = (cast(TypePointer)agg1.type).next;
+ Type pointee = agg1.type.nextOf();
const sz = pointee.size();
emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
}
else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr)
{
- Type pointee = (cast(TypePointer)agg1.type).next;
+ Type pointee = agg1.type.nextOf();
const sz = pointee.size();
emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
}
@@ -794,14 +795,14 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
goto Lcant;
}
dinteger_t ofs2 = e2.toInteger();
- Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next;
+ Type pointee = agg1.type.toBasetype().nextOf();
dinteger_t sz = pointee.size();
sinteger_t indx;
dinteger_t len;
- if (agg1.op == EXP.symbolOffset)
+ if (auto soe = agg1.isSymOffExp())
{
indx = ofs1 / sz;
- len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger();
+ len = soe.var.type.isTypeSArray().dim.toInteger();
}
else
{
@@ -836,9 +837,9 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars());
goto Lcant;
}
- if (eptr.type.toBasetype().ty == Tsarray)
+ if (auto tsa = eptr.type.toBasetype().isTypeSArray())
{
- dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger();
+ dinteger_t dim = tsa.dim.toInteger();
// Create a CTFE pointer &agg1[indx .. indx+dim]
auto se = ctfeEmplaceExp!SliceExp(loc, agg1,
ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t),
@@ -978,7 +979,7 @@ bool isCtfeComparable(Expression e)
}
/// Map EXP comparison ops
-private bool numCmp(N)(EXP op, N n1, N n2)
+private bool numCmp(N)(EXP op, N n1, N n2) nothrow
{
switch (op)
{
@@ -997,25 +998,25 @@ private bool numCmp(N)(EXP op, N n1, N n2)
}
/// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool specificCmp(EXP op, int rawCmp) @safe
+bool specificCmp(EXP op, int rawCmp) @safe nothrow
{
return numCmp!int(op, rawCmp, 0);
}
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe
+bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe nothrow
{
return numCmp!dinteger_t(op, n1, n2);
}
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe
+bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe nothrow
{
return numCmp!sinteger_t(op, n1, n2);
}
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool realCmp(EXP op, real_t r1, real_t r2) @safe
+bool realCmp(EXP op, real_t r1, real_t r2) @safe nothrow
{
// Don't rely on compiler, handle NAN arguments separately
if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
@@ -1105,7 +1106,7 @@ private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinte
/* Given a delegate expression e, return .funcptr.
* If e is NullExp, return NULL.
*/
-private FuncDeclaration funcptrOf(Expression e) @safe
+private FuncDeclaration funcptrOf(Expression e) @safe nothrow
{
assert(e.type.ty == Tdelegate);
if (auto de = e.isDelegateExp())
@@ -1116,7 +1117,7 @@ private FuncDeclaration funcptrOf(Expression e) @safe
return null;
}
-private bool isArray(const Expression e) @safe
+private bool isArray(const Expression e) @safe nothrow
{
return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_;
}
@@ -1270,8 +1271,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
size_t dim = es1.keys.length;
if (es2.keys.length != dim)
return 1;
- bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim);
- memset(used, 0, bool.sizeof * dim);
+ BitArray used;
+ used.length = dim;
foreach (size_t i; 0 .. dim)
{
Expression k1 = (*es1.keys)[i];
@@ -1290,11 +1291,9 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
}
if (!v2 || ctfeRawCmp(loc, v1, v2, identity))
{
- mem.xfree(used);
return 1;
}
}
- mem.xfree(used);
return 0;
}
else if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.null_)
@@ -2000,9 +1999,8 @@ void showCtfeExpr(Expression e, int level = 0)
UnionExp voidInitLiteral(Type t, VarDeclaration var)
{
UnionExp ue;
- if (t.ty == Tsarray)
+ if (auto tsa = t.isTypeSArray())
{
- TypeSArray tsa = cast(TypeSArray)t;
Expression elem = voidInitLiteral(tsa.next, var).copy();
// For aggregate value types (structs, static arrays) we must
// create an a separate copy for each element.
@@ -2019,9 +2017,8 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var)
ArrayLiteralExp ae = ue.exp().isArrayLiteralExp();
ae.ownedByCtfe = OwnedBy.ctfe;
}
- else if (t.ty == Tstruct)
+ else if (auto ts = t.isTypeStruct())
{
- TypeStruct ts = cast(TypeStruct)t;
auto exps = new Expressions(ts.sym.fields.length);
foreach (size_t i; 0 .. ts.sym.fields.length)
{
@@ -1631,6 +1631,13 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
}
else if (tob.ty == Tvector && t1b.ty != Tvector)
{
+ if (t1b.ty == Tsarray)
+ {
+ // Casting static array to vector with same size, e.g. `cast(int4) int[4]`
+ if (t1b.size(e.loc) != tob.size(e.loc))
+ goto Lfail;
+ return new VectorExp(e.loc, e, tob).expressionSemantic(sc);
+ }
//printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars());
TypeVector tv = tob.isTypeVector();
Expression result = new CastExp(e.loc, e, tv.elementType());
@@ -180,7 +180,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
int cppDtorVtblIndex = -1;
/// to prevent recursive attempts
- private bool inuse;
+ bool inuse;
ThreeState isabstract;
@@ -367,7 +367,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
baseok = Baseok.none;
}
- extern (D) private void classError(const(char)* fmt, const(char)* arg)
+ extern (D) final void classError(const(char)* fmt, const(char)* arg)
{
.error(loc, fmt, kind, toPrettyChars, arg);
}
@@ -468,67 +468,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
return baseok >= Baseok.done;
}
- override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
- //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
- if (_scope && baseok < Baseok.semanticdone)
- {
- if (!inuse)
- {
- // must semantic on base class/interfaces
- inuse = true;
- dsymbolSemantic(this, null);
- inuse = false;
- }
- }
-
- if (!members || !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) && semanticRun < PASS.semanticdone)
- classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars());
- //*(char*)0=0;
- return null;
- }
-
- auto s = ScopeDsymbol.search(loc, ident, flags);
-
- // don't search imports of base classes
- if (flags & SearchImportsOnly)
- return s;
-
- if (s)
- return s;
-
- // Search bases classes in depth-first, left to right order
- foreach (b; (*baseclasses)[])
- {
- if (!b.sym)
- continue;
-
- if (!b.sym.symtab)
- {
- classError("%s `%s` base `%s` is forward referenced", b.sym.ident.toChars());
- continue;
- }
-
- import dmd.access : symbolIsVisible;
-
- s = b.sym.search(loc, ident, flags);
- if (!s)
- continue;
- else if (s == this) // happens if s is nested in this and derives from this
- s = null;
- else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s))
- s = null;
- else
- break;
- }
-
- return s;
- }
-
/************************************
* Search base classes in depth-first, left-to-right order for
* a class or interface named 'ident'.
@@ -675,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 = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
+ Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
if (!s)
{
//printf("not found\n");
@@ -421,18 +421,6 @@ extern (C++) abstract class Declaration : Dsymbol
return Modifiable.yes;
}
- override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- Dsymbol s = Dsymbol.search(loc, ident, flags);
- if (!s && type)
- {
- s = type.toDsymbol(_scope);
- if (s)
- s = s.search(loc, ident, flags);
- }
- return s;
- }
-
final bool isStatic() const pure nothrow @nogc @safe
{
return (storage_class & STC.static_) != 0;
@@ -124,7 +124,6 @@ public:
const char *kind() const override;
uinteger_t size(const Loc &loc) override final;
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
bool isStatic() const { return (storage_class & STCstatic) != 0; }
LINK resolvedLinkage() const; // returns the linkage, resolving the target-specific `System` one
@@ -83,25 +83,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
return ed;
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- version (none)
- {
- printf("EnumDeclaration::addMember() %s\n", toChars());
- for (size_t i = 0; i < members.length; i++)
- {
- EnumMember em = (*members)[i].isEnumMember();
- printf(" member %s\n", em.toChars());
- }
- }
- if (!isAnonymous())
- {
- ScopeDsymbol.addMember(sc, sds);
- }
-
- addEnumMembersToSymtab(this, sc, sds);
- }
-
override void setScope(Scope* sc)
{
if (semanticRun > PASS.initial)
@@ -126,19 +107,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
return "enum";
}
- override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars());
- if (_scope)
- {
- // Try one last time to resolve this enum
- dsymbolSemantic(this, _scope);
- }
-
- Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
- return s;
- }
-
// is Dsymbol deprecated?
override bool isDeprecated() const
{
@@ -305,33 +305,6 @@ extern (C++) final class Import : Dsymbol
return this;
}
- /*****************************
- * Add import to sd's symbol table.
- */
- override void addMember(Scope* sc, ScopeDsymbol sd)
- {
- //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc);
- if (names.length == 0)
- return Dsymbol.addMember(sc, sd);
- if (aliasId)
- Dsymbol.addMember(sc, sd);
- /* Instead of adding the import to sd's symbol table,
- * add each of the alias=name pairs
- */
- for (size_t i = 0; i < names.length; i++)
- {
- Identifier name = names[i];
- Identifier _alias = aliases[i];
- if (!_alias)
- _alias = name;
- auto tname = new TypeIdentifier(loc, name);
- auto ad = new AliasDeclaration(loc, _alias, tname);
- ad._import = this;
- ad.addMember(sc, sd);
- aliasdecls.push(ad);
- }
- }
-
override void setScope(Scope* sc)
{
Dsymbol.setScope(sc);
@@ -348,19 +321,6 @@ extern (C++) final class Import : Dsymbol
}
}
- override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
- if (!pkg)
- {
- load(null);
- mod.importAll(null);
- mod.dsymbolSemantic(null);
- }
- // Forward it to the package/module
- return pkg.search(loc, ident, flags);
- }
-
override bool overloadInsert(Dsymbol s)
{
/* Allow multiple imports with the same package base, but disallow
@@ -268,22 +268,6 @@ extern (C++) class Package : ScopeDsymbol
return isAncestorPackageOf(pkg.parent.isPackage());
}
- override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- //printf("%s Package.search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
- flags &= ~SearchLocalsOnly; // searching an import is always transitive
- if (!isModule() && mod)
- {
- // Prefer full package name.
- Dsymbol s = symtab ? symtab.lookup(ident) : null;
- if (s)
- return s;
- //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
- return mod.search(loc, ident, flags);
- }
- return ScopeDsymbol.search(loc, ident, flags);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -414,10 +398,10 @@ extern (C++) final class Module : Package
return rootimports == ThreeState.yes;
}
- private Identifier searchCacheIdent;
- private Dsymbol searchCacheSymbol; // cached value of search
- private int searchCacheFlags; // cached flags
- private bool insearch;
+ Identifier searchCacheIdent;
+ Dsymbol searchCacheSymbol; // cached value of search
+ int searchCacheFlags; // cached flags
+ bool insearch;
/**
* A root module is one that will be compiled all the way to
@@ -1036,47 +1020,6 @@ extern (C++) final class Module : Package
}
}
- override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- /* Since modules can be circularly referenced,
- * need to stop infinite recursive searches.
- * This is done with the cache.
- */
- //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", toChars(), ident.toChars(), flags, insearch);
- if (insearch)
- return null;
-
- /* Qualified module searches always search their imports,
- * even if SearchLocalsOnly
- */
- if (!(flags & SearchUnqualifiedModule))
- flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
-
- if (searchCacheIdent == ident && searchCacheFlags == flags)
- {
- //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
- // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null");
- return searchCacheSymbol;
- }
-
- uint errors = global.errors;
-
- insearch = true;
- Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
- insearch = false;
-
- if (errors == global.errors)
- {
- // https://issues.dlang.org/show_bug.cgi?id=10752
- // Can cache the result only when it does not cause
- // access error so the side-effect should be reproduced in later search.
- searchCacheIdent = ident;
- searchCacheSymbol = s;
- searchCacheFlags = flags;
- }
- return s;
- }
-
override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
{
if (insearch) // don't follow import cycles
@@ -66,13 +66,15 @@ enum SCOPE
fullinst = 0x10000, /// fully instantiate templates
ctfeBlock = 0x20000, /// inside a `if (__ctfe)` block
+ dip1000 = 0x40000, /// dip1000 errors enabled for this scope
+ dip25 = 0x80000, /// dip25 errors enabled for this scope
}
/// Flags that are carried along with a scope push()
private enum PersistentFlags =
SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility |
- SCOPE.Cfile | SCOPE.ctfeBlock;
+ SCOPE.Cfile | SCOPE.ctfeBlock | SCOPE.dip1000 | SCOPE.dip25;
extern (C++) struct Scope
{
@@ -176,6 +178,10 @@ extern (C++) struct Scope
m = m.parent;
m.addMember(null, sc.scopesym);
m.parent = null; // got changed by addMember()
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ sc.flags |= SCOPE.dip1000;
+ if (global.params.useDIP25 == FeatureState.enabled)
+ sc.flags |= SCOPE.dip25;
if (_module.filetype == FileType.c)
sc.flags |= SCOPE.Cfile;
// Create the module scope underneath the global scope
@@ -344,7 +350,7 @@ extern (C++) struct Scope
* Returns:
* symbol if found, null if not
*/
- extern (D) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
+ extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
{
version (LOGSEARCH)
{
@@ -821,4 +827,16 @@ extern (C++) struct Scope
{
return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0;
}
+
+ /// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
+ extern (D) FeatureState useDIP1000()
+ {
+ return (flags & SCOPE.dip1000) ? FeatureState.enabled : FeatureState.disabled;
+ }
+
+ /// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
+ extern (D) FeatureState useDIP25()
+ {
+ return (flags & SCOPE.dip25) ? FeatureState.enabled : FeatureState.disabled;
+ }
}
@@ -263,23 +263,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
return sd;
}
- override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
- if (_scope && !symtab)
- dsymbolSemantic(this, _scope);
-
- if (!members || !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) && semanticRun < PASS.semanticdone)
- .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars());
- return null;
- }
-
- return ScopeDsymbol.search(loc, ident, flags);
- }
-
override const(char)* kind() const
{
return "struct";
@@ -35,7 +35,6 @@ import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
-import dmd.expressionsem;
import dmd.func;
import dmd.globals;
import dmd.id;
@@ -750,67 +749,6 @@ extern (C++) class Dsymbol : ASTNode
return toAlias();
}
- void addMember(Scope* sc, ScopeDsymbol sds)
- {
- //printf("Dsymbol::addMember('%s')\n", toChars());
- //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
- //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
- parent = sds;
- if (isAnonymous()) // no name, so can't add it to symbol table
- return;
-
- if (!sds.symtabInsert(this)) // if name is already defined
- {
- if (isAliasDeclaration() && !_scope)
- setScope(sc);
- Dsymbol s2 = sds.symtabLookup(this,ident);
- /* https://issues.dlang.org/show_bug.cgi?id=17434
- *
- * If we are trying to add an import to the symbol table
- * that has already been introduced, then keep the one with
- * larger visibility. This is fine for imports because if
- * we have multiple imports of the same file, if a single one
- * is public then the symbol is reachable.
- */
- if (auto i1 = isImport())
- {
- if (auto i2 = s2.isImport())
- {
- if (sc.explicitVisibility && sc.visibility > i2.visibility)
- sds.symtab.update(this);
- }
- }
-
- // If using C tag/prototype/forward declaration rules
- if (sc.flags & SCOPE.Cfile && !this.isImport())
- {
- if (handleTagSymbols(*sc, this, s2, sds))
- return;
- if (handleSymbolRedeclarations(*sc, this, s2, sds))
- return;
-
- sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading
- errors = true;
- return;
- }
-
- if (!s2.overloadInsert(this))
- {
- sds.multiplyDefined(Loc.initial, this, s2);
- errors = true;
- }
- }
- if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
- {
- if (ident == Id.__sizeof ||
- !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
- {
- .error(loc, "%s `%s` `.%s` property cannot be redefined", kind, toPrettyChars, ident.toChars());
- errors = true;
- }
- }
- }
-
/*************************************
* Set scope for future semantic analysis so we can
* deal better with forward references.
@@ -831,21 +769,6 @@ extern (C++) class Dsymbol : ASTNode
{
}
- /*********************************************
- * Search for ident as member of s.
- * Params:
- * loc = location to print for error messages
- * ident = identifier to search for
- * flags = IgnoreXXXX
- * Returns:
- * null if not found
- */
- Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
- {
- //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
- return null;
- }
-
extern (D) final Dsymbol search_correct(Identifier ident)
{
/***************************************************
@@ -870,7 +793,7 @@ extern (C++) class Dsymbol : ASTNode
if (global.gag)
return null; // don't do it for speculative compiles; too time consuming
// search for exact name first
- if (auto s = search(Loc.initial, ident, IgnoreErrors))
+ if (auto s = this.search(Loc.initial, ident, IgnoreErrors))
return s;
return speller!symbol_search_fp(ident.toString());
}
@@ -1339,12 +1262,12 @@ extern (C++) class ScopeDsymbol : Dsymbol
Dsymbols* members; // all Dsymbol's in this scope
DsymbolTable symtab; // members[] sorted into table
uint endlinnum; // the linnumber of the statement after the scope (0 if unknown)
-
-private:
/// symbols whose members have been imported, i.e. imported modules and template mixins
Dsymbols* importedScopes;
Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import
+private:
+
import dmd.root.bitarray;
BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
@@ -1373,166 +1296,7 @@ public:
return sds;
}
- /*****************************************
- * This function is #1 on the list of functions that eat cpu time.
- * Be very, very careful about slowing it down.
- */
- override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
- //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
-
- // Look in symbols declared in this module
- if (symtab && !(flags & SearchImportsOnly))
- {
- //printf(" look in locals\n");
- auto s1 = symtab.lookup(ident);
- if (s1)
- {
- //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
- return s1;
- }
- }
- //printf(" not found in locals\n");
-
- // Look in imported scopes
- if (!importedScopes)
- return null;
-
- //printf(" look in imports\n");
- Dsymbol s = null;
- OverloadSet a = null;
- // Look in imported modules
- for (size_t i = 0; i < importedScopes.length; i++)
- {
- // If private import, don't search it
- if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_)
- continue;
- int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
- Dsymbol ss = (*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)
- continue;
- }
- else // mixin template
- {
- if (flags & SearchImportsOnly)
- continue;
-
- sflags |= SearchLocalsOnly;
- }
-
- /* Don't find private members if ss is a module
- */
- Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
- import dmd.access : symbolIsVisible;
- if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
- continue;
- if (!s)
- {
- s = s2;
- if (s && s.isOverloadSet())
- a = mergeOverloadSet(ident, a, s);
- }
- else if (s2 && s != s2)
- {
- if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
- {
- /* After following aliases, we found the same
- * symbol, so it's not an ambiguity. But if one
- * alias is deprecated or less accessible, prefer
- * the other.
- */
- if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
- s = s2;
- }
- else
- {
- /* Two imports of the same module should be regarded as
- * the same.
- */
- Import i1 = s.isImport();
- Import i2 = s2.isImport();
- if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
- {
- /* https://issues.dlang.org/show_bug.cgi?id=8668
- * Public selective import adds AliasDeclaration in module.
- * To make an overload set, resolve aliases in here and
- * get actual overload roots which accessible via s and s2.
- */
- s = s.toAlias();
- s2 = s2.toAlias();
- /* If both s2 and s are overloadable (though we only
- * need to check s once)
- */
-
- auto so2 = s2.isOverloadSet();
- if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
- {
- if (symbolIsVisible(this, s2))
- {
- a = mergeOverloadSet(ident, a, s2);
- }
- if (!symbolIsVisible(this, s))
- s = s2;
- continue;
- }
-
- /* Two different overflow sets can have the same members
- * https://issues.dlang.org/show_bug.cgi?id=16709
- */
- auto so = s.isOverloadSet();
- if (so && so2)
- {
- if (so.a.length == so2.a.length)
- {
- foreach (j; 0 .. so.a.length)
- {
- if (so.a[j] !is so2.a[j])
- goto L1;
- }
- continue; // the same
- L1:
- { } // different
- }
- }
-
- if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
- return null;
-
- /* If two imports from C import files, pick first one, as C has global name space
- */
- if (s.isCsymbol() && s2.isCsymbol())
- continue;
-
- if (!(flags & IgnoreErrors))
- ScopeDsymbol.multiplyDefined(loc, s, s2);
- break;
- }
- }
- }
- }
- if (s)
- {
- /* Build special symbol if we had multiple finds
- */
- if (a)
- {
- if (!s.isOverloadSet())
- a = mergeOverloadSet(ident, a, s);
- s = a;
- }
- //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
- return s;
- }
- //printf(" not found in imports\n");
- return null;
- }
-
- extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
+ extern (D) final OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
{
if (!os)
{
@@ -1844,40 +1608,6 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol
this.withstate = withstate;
}
- override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
- if (flags & SearchImportsOnly)
- return null;
- // Acts as proxy to the with class declaration
- Dsymbol s = null;
- Expression eold = null;
- for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true))
- {
- if (auto se = e.isScopeExp())
- {
- s = se.sds;
- }
- else if (e.isTypeExp())
- {
- s = e.type.toDsymbol(null);
- }
- else
- {
- Type t = e.type.toBasetype();
- s = t.toDsymbol(null);
- }
- if (s)
- {
- s = s.search(loc, ident, flags);
- if (s)
- return s;
- }
- eold = e;
- }
- return null;
- }
-
override inout(WithScopeSymbol) isWithScopeSymbol() inout
{
return this;
@@ -1896,217 +1626,28 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
{
// either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
// Discriminated using DYNCAST and, for expressions, also EXP
- private RootObject arrayContent;
- Scope* sc;
+ RootObject arrayContent;
extern (D) this(Scope* sc, Expression exp) nothrow @safe
{
super(exp.loc, null);
assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
- this.sc = sc;
+ this._scope = sc;
this.arrayContent = exp;
}
extern (D) this(Scope* sc, TypeTuple type) nothrow @safe
{
- this.sc = sc;
+ this._scope = sc;
this.arrayContent = type;
}
extern (D) this(Scope* sc, TupleDeclaration td) nothrow @safe
{
- this.sc = sc;
+ this._scope = sc;
this.arrayContent = td;
}
- /// This override is used to solve `$`
- override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
- {
- //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
- if (ident != Id.dollar)
- return null;
-
- VarDeclaration* pvar;
- Expression ce;
-
- static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
- {
-
- /* $ gives the number of type entries in the type tuple
- */
- auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
- Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t);
- v._init = new ExpInitializer(Loc.initial, e);
- v.storage_class |= STC.temp | STC.static_ | STC.const_;
- v.dsymbolSemantic(sc);
- return v;
- }
-
- const DYNCAST kind = arrayContent.dyncast();
- switch (kind) with (DYNCAST)
- {
- case dsymbol:
- TupleDeclaration td = cast(TupleDeclaration) arrayContent;
- /* $ gives the number of elements in the tuple
- */
- auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
- Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t);
- v._init = new ExpInitializer(Loc.initial, e);
- v.storage_class |= STC.temp | STC.static_ | STC.const_;
- v.dsymbolSemantic(sc);
- return v;
- case type:
- return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
- default:
- break;
- }
- Expression exp = cast(Expression) arrayContent;
- if (auto ie = exp.isIndexExp())
- {
- /* array[index] where index is some function of $
- */
- pvar = &ie.lengthVar;
- ce = ie.e1;
- }
- else if (auto se = exp.isSliceExp())
- {
- /* array[lwr .. upr] where lwr or upr is some function of $
- */
- pvar = &se.lengthVar;
- ce = se.e1;
- }
- else if (auto ae = exp.isArrayExp())
- {
- /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
- * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
- */
- pvar = &ae.lengthVar;
- ce = ae.e1;
- }
- else
- {
- /* Didn't find $, look in enclosing scope(s).
- */
- return null;
- }
- ce = ce.lastComma();
- /* If we are indexing into an array that is really a type
- * tuple, rewrite this as an index into a type tuple and
- * try again.
- */
- if (auto te = ce.isTypeExp())
- {
- if (auto ttp = te.type.isTypeTuple())
- return dollarFromTypeTuple(loc, ttp, sc);
- }
- /* *pvar is lazily initialized, so if we refer to $
- * multiple times, it gets set only once.
- */
- if (!*pvar) // if not already initialized
- {
- /* Create variable v and set it to the value of $
- */
- VarDeclaration v;
- Type t;
- if (auto tupexp = ce.isTupleExp())
- {
- /* It is for an expression tuple, so the
- * length will be a const.
- */
- Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t);
- v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
- v.storage_class |= STC.temp | STC.static_ | STC.const_;
- }
- else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
- {
- // Look for opDollar
- assert(exp.op == EXP.array || exp.op == EXP.slice);
- AggregateDeclaration ad = isAggregate(t);
- assert(ad);
- Dsymbol s = ad.search(loc, Id.opDollar);
- if (!s) // no dollar exists -- search in higher scope
- return null;
- s = s.toAlias();
- Expression e = null;
- // Check for multi-dimensional opDollar(dim) template.
- if (TemplateDeclaration td = s.isTemplateDeclaration())
- {
- dinteger_t dim = 0;
- if (auto ae = exp.isArrayExp())
- {
- dim = ae.currentDimension;
- }
- else if (exp.isSliceExp())
- {
- dim = 0; // slices are currently always one-dimensional
- }
- else
- {
- assert(0);
- }
- auto tiargs = new Objects();
- Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
- edim = edim.expressionSemantic(sc);
- tiargs.push(edim);
- e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
- }
- else
- {
- /* opDollar exists, but it's not a template.
- * This is acceptable ONLY for single-dimension indexing.
- * Note that it's impossible to have both template & function opDollar,
- * because both take no arguments.
- */
- auto ae = exp.isArrayExp();
- if (ae && ae.arguments.length != 1)
- {
- error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars());
- return null;
- }
- Declaration d = s.isDeclaration();
- assert(d);
- e = new DotVarExp(loc, ce, d);
- }
- e = e.expressionSemantic(sc);
- if (!e.type)
- error(exp.loc, "`%s` has no value", e.toChars());
- t = e.type.toBasetype();
- if (t && t.ty == Tfunction)
- e = new CallExp(e.loc, e);
- v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
- v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
- }
- else
- {
- /* For arrays, $ will either be a compile-time constant
- * (in which case its value in set during constant-folding),
- * or a variable (in which case an expression is created in
- * toir.c).
- */
-
- // https://issues.dlang.org/show_bug.cgi?id=16213
- // For static arrays $ is known at compile time,
- // so declare it as a manifest constant.
- auto tsa = ce.type ? ce.type.isTypeSArray() : null;
- if (tsa)
- {
- auto e = new ExpInitializer(loc, tsa.dim);
- v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest);
- }
- else
- {
- auto e = new VoidInitializer(Loc.initial);
- e.type = Type.tsize_t;
- v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
- v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
- }
- }
- *pvar = v;
- }
- (*pvar).dsymbolSemantic(sc);
- return (*pvar);
- }
-
override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
{
return this;
@@ -228,10 +228,8 @@ public:
virtual const char *kind() const;
virtual Dsymbol *toAlias(); // resolve real symbol
virtual Dsymbol *toAlias2();
- virtual void addMember(Scope *sc, ScopeDsymbol *sds);
virtual void setScope(Scope *sc);
virtual void importAll(Scope *sc);
- virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
virtual bool overloadInsert(Dsymbol *s);
virtual uinteger_t size(const Loc &loc);
virtual bool isforwardRef();
@@ -331,16 +329,14 @@ public:
Dsymbols *members; // all Dsymbol's in this scope
DsymbolTable *symtab; // members[] sorted into table
unsigned endlinnum; // the linnumber of the statement after the scope (0 if unknown)
-
-private:
Dsymbols *importedScopes; // imported Dsymbol's
Visibility::Kind *visibilities; // array of `Visibility.Kind`, one for each import
+private:
BitArray accessiblePackages, privateAccessiblePackages;
public:
ScopeDsymbol *syntaxCopy(Dsymbol *s) override;
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
virtual void importScope(Dsymbol *s, Visibility visibility);
virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
bool isforwardRef() override final;
@@ -362,7 +358,6 @@ class WithScopeSymbol final : public ScopeDsymbol
public:
WithStatement *withstate;
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
WithScopeSymbol *isWithScopeSymbol() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
@@ -372,12 +367,8 @@ public:
class ArrayScopeSymbol final : public ScopeDsymbol
{
-private:
- RootObject *arrayContent;
public:
- Scope *sc;
-
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone) override;
+ RootObject *arrayContent;
ArrayScopeSymbol *isArrayScopeSymbol() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
@@ -437,3 +428,6 @@ public:
// Number of symbols in symbol table
size_t length() const;
};
+
+void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
+Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
@@ -23,6 +23,7 @@ import dmd.astenums;
import dmd.attrib;
import dmd.blockexit;
import dmd.clone;
+import dmd.cond;
import dmd.compiler;
import dmd.dcast;
import dmd.dclass;
@@ -1141,7 +1142,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
else if (auto ale = ex.isArrayLiteralExp())
{
// or an array literal assigned to a `scope` variable
- if (global.params.useDIP1000 == FeatureState.enabled
+ if (sc.useDIP1000 == FeatureState.enabled
&& !dsym.type.nextOf().needsDestruction())
ale.onstack = true;
}
@@ -1170,10 +1171,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// https://issues.dlang.org/show_bug.cgi?id=14166
// Don't run CTFE for the temporary variables inside typeof
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret);
+ import dmd.semantic2 : lowerStaticAAs;
+ lowerStaticAAs(dsym, sc);
const init_err = dsym._init.isExpInitializer();
if (init_err && init_err.exp.op == EXP.showCtfeContext)
{
- errorSupplemental(dsym.loc, "compile time context created here");
+ errorSupplemental(dsym.loc, "compile time context created here");
}
}
}
@@ -1979,7 +1982,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (!cd.compiled)
{
cd.decl = compileIt(cd);
- cd.AttribDeclaration.addMember(sc, cd.scopesym);
+ attribAddMember(cd, sc, cd.scopesym);
cd.compiled = true;
if (cd._scope && cd.decl)
@@ -3385,7 +3388,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested()))
{
- import core.bitop;
+ import core.bitop : popcnt;
auto mods = MODtoChars(tf.mod);
.error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, mods);
if (tf.next && tf.next.ty != Tvoid && popcnt(tf.mod) == 1)
@@ -5831,6 +5834,365 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
+/*
+Adds dsym as a member of scope sds.
+
+Params:
+ dsym = dsymbol to inserted
+ sc = scope where the dsymbol is declared
+ sds = ScopeDsymbol where dsym is inserted
+*/
+extern(C++) void addMember(Dsymbol dsym, Scope* sc, ScopeDsymbol sds)
+{
+ auto addMemberVisitor = new AddMemberVisitor(sc, sds);
+ dsym.accept(addMemberVisitor);
+}
+
+private void attribAddMember(AttribDeclaration atb, Scope* sc, ScopeDsymbol sds)
+{
+ Dsymbols* d = atb.include(sc);
+ if (d)
+ {
+ Scope* sc2 = atb.newScope(sc);
+ d.foreachDsymbol( s => s.addMember(sc2, sds) );
+ if (sc2 != sc)
+ sc2.pop();
+ }
+}
+
+private extern(C++) class AddMemberVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ Scope* sc;
+ ScopeDsymbol sds;
+
+ this(Scope* sc, ScopeDsymbol sds)
+ {
+ this.sc = sc;
+ this.sds = sds;
+ }
+
+ override void visit(Dsymbol dsym)
+ {
+ //printf("Dsymbol::addMember('%s')\n", toChars());
+ //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
+ //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
+ dsym.parent = sds;
+ if (dsym.isAnonymous()) // no name, so can't add it to symbol table
+ return;
+
+ if (!sds.symtabInsert(dsym)) // if name is already defined
+ {
+ if (dsym.isAliasDeclaration() && !dsym._scope)
+ dsym.setScope(sc);
+ Dsymbol s2 = sds.symtabLookup(dsym, dsym.ident);
+ /* https://issues.dlang.org/show_bug.cgi?id=17434
+ *
+ * If we are trying to add an import to the symbol table
+ * that has already been introduced, then keep the one with
+ * larger visibility. This is fine for imports because if
+ * we have multiple imports of the same file, if a single one
+ * is public then the symbol is reachable.
+ */
+ if (auto i1 = dsym.isImport())
+ {
+ if (auto i2 = s2.isImport())
+ {
+ if (sc.explicitVisibility && sc.visibility > i2.visibility)
+ sds.symtab.update(dsym);
+ }
+ }
+
+ // If using C tag/prototype/forward declaration rules
+ if (sc.flags & SCOPE.Cfile && !dsym.isImport())
+ {
+ if (handleTagSymbols(*sc, dsym, s2, sds))
+ return;
+ if (handleSymbolRedeclarations(*sc, dsym, s2, sds))
+ return;
+
+ sds.multiplyDefined(Loc.initial, dsym, s2); // ImportC doesn't allow overloading
+ dsym.errors = true;
+ return;
+ }
+
+ if (!s2.overloadInsert(dsym))
+ {
+ sds.multiplyDefined(Loc.initial, dsym, s2);
+ dsym.errors = true;
+ }
+ }
+ if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
+ {
+ if (dsym.ident == Id.__sizeof ||
+ !(sc && sc.flags & SCOPE.Cfile) && (dsym.ident == Id.__xalignof || dsym.ident == Id._mangleof))
+ {
+ .error(dsym.loc, "%s `%s` `.%s` property cannot be redefined", dsym.kind, dsym.toPrettyChars, dsym.ident.toChars());
+ dsym.errors = true;
+ }
+ }
+ }
+
+
+ override void visit(StaticAssert _)
+ {
+ // we didn't add anything
+ }
+
+ /*****************************
+ * Add import to sd's symbol table.
+ */
+ override void visit(Import imp)
+ {
+ //printf("Import.addMember(this=%s, sds=%s, sc=%p)\n", imp.toChars(), sds.toChars(), sc);
+ if (imp.names.length == 0)
+ return visit(cast(Dsymbol)imp);
+ if (imp.aliasId)
+ visit(cast(Dsymbol)imp);
+
+ /* Instead of adding the import to sds's symbol table,
+ * add each of the alias=name pairs
+ */
+ for (size_t i = 0; i < imp.names.length; i++)
+ {
+ Identifier name = imp.names[i];
+ Identifier _alias = imp.aliases[i];
+ if (!_alias)
+ _alias = name;
+ auto tname = new TypeIdentifier(imp.loc, name);
+ auto ad = new AliasDeclaration(imp.loc, _alias, tname);
+ ad._import = imp;
+ addMember(ad, sc, sds);
+ imp.aliasdecls.push(ad);
+ }
+ }
+
+ override void visit(AttribDeclaration atb)
+ {
+ attribAddMember(atb, sc, sds);
+ }
+
+ override void visit(StorageClassDeclaration stcd)
+ {
+ Dsymbols* d = stcd.include(sc);
+ if (d)
+ {
+ Scope* sc2 = stcd.newScope(sc);
+
+ d.foreachDsymbol( (s)
+ {
+ //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars());
+ // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol)
+ if (auto decl = s.isDeclaration())
+ {
+ decl.storage_class |= stcd.stc & STC.local;
+ if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case?
+ {
+ sdecl.stc |= stcd.stc & STC.local;
+ }
+ }
+ s.addMember(sc2, sds);
+ });
+
+ if (sc2 != sc)
+ sc2.pop();
+ }
+ }
+
+ override void visit(VisibilityDeclaration visd)
+ {
+ if (visd.pkg_identifiers)
+ {
+ Dsymbol tmp;
+ Package.resolve(visd.pkg_identifiers, &tmp, null);
+ visd.visibility.pkg = tmp ? tmp.isPackage() : null;
+ visd.pkg_identifiers = null;
+ }
+ if (visd.visibility.kind == Visibility.Kind.package_ && visd.visibility.pkg && sc._module)
+ {
+ Module m = sc._module;
+
+ // https://issues.dlang.org/show_bug.cgi?id=17441
+ // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if
+ // each package's .isModule() properites are equal.
+ //
+ // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null.
+ // This breaks package declarations of the package in question if they are declared in
+ // the same package.d file, which _do_ have a module associated with them, and hence a non-null
+ // isModule()
+ if (!m.isPackage() || !visd.visibility.pkg.ident.equals(m.isPackage().ident))
+ {
+ Package pkg = m.parent ? m.parent.isPackage() : null;
+ if (!pkg || !visd.visibility.pkg.isAncestorPackageOf(pkg))
+ .error(visd.loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", visd.kind(), visd.toPrettyChars(false), m.toPrettyChars(true));
+ }
+ }
+ attribAddMember(visd, sc, sds);
+ }
+
+ override void visit(StaticIfDeclaration sid)
+ {
+ //printf("StaticIfDeclaration::addMember() '%s'\n", sid.toChars());
+ /* This is deferred until the condition evaluated later (by the include() call),
+ * so that expressions in the condition can refer to declarations
+ * in the same scope, such as:
+ *
+ * template Foo(int i)
+ * {
+ * const int j = i + 1;
+ * static if (j == 3)
+ * const int k;
+ * }
+ */
+ sid.scopesym = sds;
+ }
+
+
+ override void visit(StaticForeachDeclaration sfd)
+ {
+ // used only for caching the enclosing symbol
+ sfd.scopesym = sds;
+ }
+
+ /***************************************
+ * Lazily initializes the scope to forward to.
+ */
+ override void visit(ForwardingAttribDeclaration fad)
+ {
+ fad.sym.parent = sds;
+ sds = fad.sym;
+ attribAddMember(fad, sc, fad.sym);
+ }
+
+ override void visit(MixinDeclaration md)
+ {
+ //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, md.memnum);
+ md.scopesym = sds;
+ }
+
+ override void visit(DebugSymbol ds)
+ {
+ //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), ds.toChars());
+ Module m = sds.isModule();
+ // Do not add the member to the symbol table,
+ // just make sure subsequent debug declarations work.
+ if (ds.ident)
+ {
+ if (!m)
+ {
+ .error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars);
+ ds.errors = true;
+ }
+ else
+ {
+ if (findCondition(m.debugidsNot, ds.ident))
+ {
+ .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars);
+ ds.errors = true;
+ }
+ if (!m.debugids)
+ m.debugids = new Identifiers();
+ m.debugids.push(ds.ident);
+ }
+ }
+ else
+ {
+ if (!m)
+ {
+ .error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars);
+ ds.errors = true;
+ }
+ else
+ m.debuglevel = ds.level;
+ }
+ }
+
+ override void visit(VersionSymbol vs)
+ {
+ //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), vs.toChars());
+ Module m = sds.isModule();
+ // Do not add the member to the symbol table,
+ // just make sure subsequent debug declarations work.
+ if (vs.ident)
+ {
+ VersionCondition.checkReserved(vs.loc, vs.ident.toString());
+ if (!m)
+ {
+ .error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars);
+ vs.errors = true;
+ }
+ else
+ {
+ if (findCondition(m.versionidsNot, vs.ident))
+ {
+ .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars);
+ vs.errors = true;
+ }
+ if (!m.versionids)
+ m.versionids = new Identifiers();
+ m.versionids.push(vs.ident);
+ }
+ }
+ else
+ {
+ if (!m)
+ {
+ .error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars);
+ vs.errors = true;
+ }
+ else
+ m.versionlevel = vs.level;
+ }
+ }
+
+ override void visit(Nspace ns)
+ {
+ visit(cast(Dsymbol)ns);
+
+ if (ns.members)
+ {
+ if (!ns.symtab)
+ ns.symtab = new DsymbolTable();
+ // The namespace becomes 'imported' into the enclosing scope
+ for (Scope* sce = sc; 1; sce = sce.enclosing)
+ {
+ ScopeDsymbol sds2 = sce.scopesym;
+ if (sds2)
+ {
+ sds2.importScope(ns, Visibility(Visibility.Kind.public_));
+ break;
+ }
+ }
+ assert(sc);
+ sc = sc.push(ns);
+ sc.linkage = LINK.cpp; // namespaces default to C++ linkage
+ sc.parent = ns;
+ ns.members.foreachDsymbol(s => s.addMember(sc, ns));
+ sc.pop();
+ }
+ }
+
+ override void visit(EnumDeclaration ed)
+ {
+ version (none)
+ {
+ printf("EnumDeclaration::addMember() %s\n", ed.toChars());
+ for (size_t i = 0; i < ed.members.length; i++)
+ {
+ EnumMember em = (*ed.members)[i].isEnumMember();
+ printf(" member %s\n", em.toChars());
+ }
+ }
+ if (!ed.isAnonymous())
+ {
+ visit(cast(Dsymbol)ed);
+ }
+
+ addEnumMembersToSymtab(ed, sc, sds);
+ }
+}
+
/*******************************************
* Add members of EnumDeclaration to the symbol table(s).
* Params:
@@ -5904,7 +6266,7 @@ private bool isDRuntimeHook(Identifier id)
id == Id._d_arraysetlengthTImpl || id == Id._d_arraysetlengthT ||
id == Id._d_arraysetlengthTTrace ||
id == Id._d_arrayappendT || id == Id._d_arrayappendTTrace ||
- id == Id._d_arrayappendcTXImpl;
+ id == Id._d_arrayappendcTX;
}
void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList)
@@ -7431,3 +7793,617 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope*
p, funcdecl.toChars());
}
}
+
+/*********************************************
+ * Search for ident as member of d.
+ * Params:
+ * d = dsymbol where ident is searched for
+ * loc = location to print for error messages
+ * ident = identifier to search for
+ * flags = IgnoreXXXX
+ * Returns:
+ * null if not found
+ */
+extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone)
+{
+ scope v = new SearchVisitor(loc, ident, flags);
+ d.accept(v);
+ return v.result;
+}
+
+private extern(C++) class SearchVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ const Loc loc;
+ Identifier ident;
+ int flags;
+ Dsymbol result;
+
+ this(const ref Loc loc, Identifier ident, int flags)
+ {
+ this.loc = loc;
+ this.ident = ident;
+ this.flags = flags;
+ }
+
+ void setResult(Dsymbol d)
+ {
+ result = d;
+ }
+
+ override void visit(Dsymbol d)
+ {
+ //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", d, d.toChars(), ident.toChars());
+ return setResult(null);
+ }
+
+ override void visit(ScopeDsymbol sds)
+ {
+ //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", sds.toChars(), ident.toChars(), flags);
+ //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
+
+ // Look in symbols declared in this module
+ if (sds.symtab && !(flags & SearchImportsOnly))
+ {
+ //printf(" look in locals\n");
+ auto s1 = sds.symtab.lookup(ident);
+ if (s1)
+ {
+ //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
+ return setResult(s1);
+ }
+ }
+ //printf(" not found in locals\n");
+
+ // Look in imported scopes
+ if (!sds.importedScopes)
+ return setResult(null);
+
+ //printf(" look in imports\n");
+ Dsymbol s = null;
+ OverloadSet a = null;
+ // Look in imported modules
+ 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_)
+ continue;
+ int sflags = flags & (IgnoreErrors | 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)
+ continue;
+ }
+ else // mixin template
+ {
+ if (flags & SearchImportsOnly)
+ continue;
+
+ sflags |= SearchLocalsOnly;
+ }
+
+ /* Don't find private members if ss is a module
+ */
+ Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
+ import dmd.access : symbolIsVisible;
+ if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2))
+ continue;
+ if (!s)
+ {
+ s = s2;
+ if (s && s.isOverloadSet())
+ a = sds.mergeOverloadSet(ident, a, s);
+ }
+ else if (s2 && s != s2)
+ {
+ if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
+ {
+ /* After following aliases, we found the same
+ * symbol, so it's not an ambiguity. But if one
+ * alias is deprecated or less accessible, prefer
+ * the other.
+ */
+ if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
+ s = s2;
+ }
+ else
+ {
+ /* Two imports of the same module should be regarded as
+ * the same.
+ */
+ Import i1 = s.isImport();
+ Import i2 = s2.isImport();
+ if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=8668
+ * Public selective import adds AliasDeclaration in module.
+ * To make an overload set, resolve aliases in here and
+ * get actual overload roots which accessible via s and s2.
+ */
+ s = s.toAlias();
+ s2 = s2.toAlias();
+ /* If both s2 and s are overloadable (though we only
+ * need to check s once)
+ */
+
+ auto so2 = s2.isOverloadSet();
+ if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
+ {
+ if (symbolIsVisible(sds, s2))
+ {
+ a = sds.mergeOverloadSet(ident, a, s2);
+ }
+ if (!symbolIsVisible(sds, s))
+ s = s2;
+ continue;
+ }
+
+ /* Two different overflow sets can have the same members
+ * https://issues.dlang.org/show_bug.cgi?id=16709
+ */
+ auto so = s.isOverloadSet();
+ if (so && so2)
+ {
+ if (so.a.length == so2.a.length)
+ {
+ foreach (j; 0 .. so.a.length)
+ {
+ if (so.a[j] !is so2.a[j])
+ goto L1;
+ }
+ continue; // the same
+ L1:
+ { } // different
+ }
+ }
+
+ if (flags & 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
+ */
+ if (s.isCsymbol() && s2.isCsymbol())
+ continue;
+
+ if (!(flags & IgnoreErrors))
+ ScopeDsymbol.multiplyDefined(loc, s, s2);
+ break;
+ }
+ }
+ }
+ }
+ if (s)
+ {
+ /* Build special symbol if we had multiple finds
+ */
+ if (a)
+ {
+ if (!s.isOverloadSet())
+ a = sds.mergeOverloadSet(ident, a, s);
+ s = a;
+ }
+ //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
+ return setResult(s);
+ }
+ //printf(" not found in imports\n");
+ return setResult(null);
+ }
+
+ override void visit(WithScopeSymbol ws)
+ {
+ //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
+ if (flags & SearchImportsOnly)
+ return setResult(null);
+ // Acts as proxy to the with class declaration
+ Dsymbol s = null;
+ Expression eold = null;
+ for (Expression e = ws.withstate.exp; e && e != eold; e = resolveAliasThis(ws._scope, e, true))
+ {
+ if (auto se = e.isScopeExp())
+ {
+ s = se.sds;
+ }
+ else if (e.isTypeExp())
+ {
+ s = e.type.toDsymbol(null);
+ }
+ else
+ {
+ Type t = e.type.toBasetype();
+ s = t.toDsymbol(null);
+ }
+ if (s)
+ {
+ s = s.search(loc, ident, flags);
+ if (s)
+ return setResult(s);
+ }
+ eold = e;
+ }
+ return setResult(null);
+ }
+
+ override void visit(ArrayScopeSymbol ass)
+ {
+ //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
+ if (ident != Id.dollar)
+ return setResult(null);
+
+ VarDeclaration* pvar;
+ Expression ce;
+
+ static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
+ {
+
+ /* $ gives the number of type entries in the type tuple
+ */
+ auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
+ Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t);
+ v._init = new ExpInitializer(Loc.initial, e);
+ v.storage_class |= STC.temp | STC.static_ | STC.const_;
+ v.dsymbolSemantic(sc);
+ return v;
+ }
+
+ const DYNCAST kind = ass.arrayContent.dyncast();
+ switch (kind) with (DYNCAST)
+ {
+ case dsymbol:
+ TupleDeclaration td = cast(TupleDeclaration) ass.arrayContent;
+ /* $ gives the number of elements in the tuple
+ */
+ auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
+ Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t);
+ v._init = new ExpInitializer(Loc.initial, e);
+ v.storage_class |= STC.temp | STC.static_ | STC.const_;
+ v.dsymbolSemantic(ass._scope);
+ return setResult(v);
+ case type:
+ return setResult(dollarFromTypeTuple(loc, cast(TypeTuple) ass.arrayContent, ass._scope));
+ default:
+ break;
+ }
+ Expression exp = cast(Expression) ass.arrayContent;
+ if (auto ie = exp.isIndexExp())
+ {
+ /* array[index] where index is some function of $
+ */
+ pvar = &ie.lengthVar;
+ ce = ie.e1;
+ }
+ else if (auto se = exp.isSliceExp())
+ {
+ /* array[lwr .. upr] where lwr or upr is some function of $
+ */
+ pvar = &se.lengthVar;
+ ce = se.e1;
+ }
+ else if (auto ae = exp.isArrayExp())
+ {
+ /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
+ * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
+ */
+ pvar = &ae.lengthVar;
+ ce = ae.e1;
+ }
+ else
+ {
+ /* Didn't find $, look in enclosing scope(s).
+ */
+ return setResult(null);
+ }
+ ce = ce.lastComma();
+ /* If we are indexing into an array that is really a type
+ * tuple, rewrite this as an index into a type tuple and
+ * try again.
+ */
+ if (auto te = ce.isTypeExp())
+ {
+ if (auto ttp = te.type.isTypeTuple())
+ return setResult(dollarFromTypeTuple(loc, ttp, ass._scope));
+ }
+ /* *pvar is lazily initialized, so if we refer to $
+ * multiple times, it gets set only once.
+ */
+ if (!*pvar) // if not already initialized
+ {
+ /* Create variable v and set it to the value of $
+ */
+ VarDeclaration v;
+ Type t;
+ if (auto tupexp = ce.isTupleExp())
+ {
+ /* It is for an expression tuple, so the
+ * length will be a const.
+ */
+ Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t);
+ v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
+ v.storage_class |= STC.temp | STC.static_ | STC.const_;
+ }
+ else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
+ {
+ // Look for opDollar
+ assert(exp.op == EXP.array || exp.op == EXP.slice);
+ AggregateDeclaration ad = isAggregate(t);
+ assert(ad);
+ Dsymbol s = ad.search(loc, Id.opDollar);
+ if (!s) // no dollar exists -- search in higher scope
+ return setResult(null);
+ s = s.toAlias();
+ Expression e = null;
+ // Check for multi-dimensional opDollar(dim) template.
+ if (TemplateDeclaration td = s.isTemplateDeclaration())
+ {
+ dinteger_t dim = 0;
+ if (auto ae = exp.isArrayExp())
+ {
+ dim = ae.currentDimension;
+ }
+ else if (exp.isSliceExp())
+ {
+ dim = 0; // slices are currently always one-dimensional
+ }
+ else
+ {
+ assert(0);
+ }
+ auto tiargs = new Objects();
+ Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
+ edim = edim.expressionSemantic(ass._scope);
+ tiargs.push(edim);
+ e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
+ }
+ else
+ {
+ /* opDollar exists, but it's not a template.
+ * This is acceptable ONLY for single-dimension indexing.
+ * Note that it's impossible to have both template & function opDollar,
+ * because both take no arguments.
+ */
+ auto ae = exp.isArrayExp();
+ if (ae && ae.arguments.length != 1)
+ {
+ error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars());
+ return setResult(null);
+ }
+ Declaration d = s.isDeclaration();
+ assert(d);
+ e = new DotVarExp(loc, ce, d);
+ }
+ e = e.expressionSemantic(ass._scope);
+ if (!e.type)
+ error(exp.loc, "`%s` has no value", e.toChars());
+ t = e.type.toBasetype();
+ if (t && t.ty == Tfunction)
+ e = new CallExp(e.loc, e);
+ v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
+ v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
+ }
+ else
+ {
+ /* For arrays, $ will either be a compile-time constant
+ * (in which case its value in set during constant-folding),
+ * or a variable (in which case an expression is created in
+ * toir.c).
+ */
+
+ // https://issues.dlang.org/show_bug.cgi?id=16213
+ // For static arrays $ is known at compile time,
+ // so declare it as a manifest constant.
+ auto tsa = ce.type ? ce.type.isTypeSArray() : null;
+ if (tsa)
+ {
+ auto e = new ExpInitializer(loc, tsa.dim);
+ v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest);
+ }
+ else
+ {
+ auto e = new VoidInitializer(Loc.initial);
+ e.type = Type.tsize_t;
+ v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
+ v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
+ }
+ }
+ *pvar = v;
+ }
+ (*pvar).dsymbolSemantic(ass._scope);
+ return setResult((*pvar));
+
+ }
+
+ override void visit(Import imp)
+ {
+ //printf("%s.Import.search(ident = '%s', flags = x%x)\n", imp.toChars(), ident.toChars(), flags);
+ if (!imp.pkg)
+ {
+ imp.load(null);
+ imp.mod.importAll(null);
+ imp.mod.dsymbolSemantic(null);
+ }
+ // Forward it to the package/module
+ return setResult(imp.pkg.search(loc, ident, flags));
+
+ }
+
+ override void visit(Nspace ns)
+ {
+ //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars());
+ if (ns._scope && !ns.symtab)
+ dsymbolSemantic(ns, ns._scope);
+
+ if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called
+ {
+ if (!(flags & IgnoreErrors))
+ .error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars());
+ return setResult(null);
+ }
+
+ visit(cast(ScopeDsymbol)ns);
+ }
+
+ override void visit(EnumDeclaration em)
+ {
+ //printf("%s.EnumDeclaration::search('%s')\n", em.toChars(), ident.toChars());
+ if (em._scope)
+ {
+ // Try one last time to resolve this enum
+ dsymbolSemantic(em, em._scope);
+ }
+
+ visit(cast(ScopeDsymbol)em);
+ }
+
+ 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
+ if (!pkg.isModule() && pkg.mod)
+ {
+ // Prefer full package name.
+ Dsymbol s = pkg.symtab ? pkg.symtab.lookup(ident) : null;
+ if (s)
+ return setResult(s);
+ //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
+ return setResult(pkg.mod.search(loc, ident, flags));
+ }
+
+ visit(cast(ScopeDsymbol)pkg);
+ }
+
+ override void visit(Module m)
+ {
+ /* Since modules can be circularly referenced,
+ * need to stop infinite recursive searches.
+ * This is done with the cache.
+ */
+ //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", m.toChars(), ident.toChars(), flags, m.insearch);
+ if (m.insearch)
+ return setResult(null);
+
+ /* Qualified module searches always search their imports,
+ * even if SearchLocalsOnly
+ */
+ if (!(flags & SearchUnqualifiedModule))
+ flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
+
+ if (m.searchCacheIdent == ident && m.searchCacheFlags == flags)
+ {
+ //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
+ // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null");
+ return setResult(m.searchCacheSymbol);
+ }
+
+ uint errors = global.errors;
+
+ m.insearch = true;
+ visit(cast(ScopeDsymbol)m);
+ Dsymbol s = result;
+ m.insearch = false;
+
+ if (errors == global.errors)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=10752
+ // Can cache the result only when it does not cause
+ // access error so the side-effect should be reproduced in later search.
+ m.searchCacheIdent = ident;
+ m.searchCacheSymbol = s;
+ m.searchCacheFlags = flags;
+ }
+ return setResult(s);
+ }
+
+ override void visit(Declaration decl)
+ {
+ Dsymbol s = null;
+ if (decl.type)
+ {
+ s = decl.type.toDsymbol(decl._scope);
+ if (s)
+ s = s.search(loc, ident, flags);
+ }
+ return setResult(s);
+ }
+
+ override void visit(StructDeclaration sd)
+ {
+ //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", sd.toChars(), ident.toChars(), flags);
+ if (sd._scope && !sd.symtab)
+ dsymbolSemantic(sd, sd._scope);
+
+ 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)
+ .error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars());
+ return setResult(null);
+ }
+
+ visit(cast(ScopeDsymbol)sd);
+ }
+
+ override void visit(ClassDeclaration cd)
+ {
+ //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", cd.toChars(), ident.toChars(), flags);
+ //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
+ if (cd._scope && cd.baseok < Baseok.semanticdone)
+ {
+ if (!cd.inuse)
+ {
+ // must semantic on base class/interfaces
+ cd.inuse = true;
+ dsymbolSemantic(cd, null);
+ cd.inuse = false;
+ }
+ }
+
+ 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)
+ cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars());
+ //*(char*)0=0;
+ return setResult(null);
+ }
+
+ visit(cast(ScopeDsymbol)cd);
+ auto s = result;
+
+ // don't search imports of base classes
+ if (flags & SearchImportsOnly)
+ return setResult(s);
+
+ if (s)
+ return setResult(s);
+
+ // Search bases classes in depth-first, left to right order
+ foreach (b; (*cd.baseclasses)[])
+ {
+ if (!b.sym)
+ continue;
+
+ if (!b.sym.symtab)
+ {
+ cd.classError("%s `%s` base `%s` is forward referenced", b.sym.ident.toChars());
+ continue;
+ }
+
+ import dmd.access : symbolIsVisible;
+
+ s = b.sym.search(loc, ident, flags);
+ if (!s)
+ 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))
+ s = null;
+ else
+ break;
+ }
+
+ return setResult(s);
+ }
+}
@@ -746,7 +746,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
OutBuffer buf;
HdrGenState hgs;
- buf.writestring(ident.toString());
+ buf.writestring(ident == Id.ctor ? "this" : ident.toString());
buf.writeByte('(');
foreach (i, const tp; *parameters)
{
@@ -763,6 +763,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
{
TypeFunction tf = cast(TypeFunction)fd.type;
buf.writestring(parametersTypeToChars(tf.parameterList));
+ if (tf.mod)
+ {
+ buf.writeByte(' ');
+ buf.MODtoBuffer(tf.mod);
+ }
}
}
@@ -20,6 +20,7 @@ import dmd.astenums;
import dmd.arraytypes;
import dmd.attrib;
import dmd.dsymbol;
+import dmd.dsymbolsem;
import dmd.errors;
import dmd.globals;
import dmd.hdrgen;
@@ -68,43 +68,6 @@ extern (C++) final class DebugSymbol : Dsymbol
}
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
- Module m = sds.isModule();
- // Do not add the member to the symbol table,
- // just make sure subsequent debug declarations work.
- if (ident)
- {
- if (!m)
- {
- .error(loc, "%s `%s` declaration must be at module level", kind, toPrettyChars);
- errors = true;
- }
- else
- {
- if (findCondition(m.debugidsNot, ident))
- {
- .error(loc, "%s `%s` defined after use", kind, toPrettyChars);
- errors = true;
- }
- if (!m.debugids)
- m.debugids = new Identifiers();
- m.debugids.push(ident);
- }
- }
- else
- {
- if (!m)
- {
- .error(loc, "%s `%s` level declaration must be at module level", kind, toPrettyChars);
- errors = true;
- }
- else
- m.debuglevel = level;
- }
- }
-
override const(char)* kind() const nothrow
{
return "debug";
@@ -162,44 +125,6 @@ extern (C++) final class VersionSymbol : Dsymbol
}
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
- Module m = sds.isModule();
- // Do not add the member to the symbol table,
- // just make sure subsequent debug declarations work.
- if (ident)
- {
- VersionCondition.checkReserved(loc, ident.toString());
- if (!m)
- {
- .error(loc, "%s `%s` declaration must be at module level", kind, toPrettyChars);
- errors = true;
- }
- else
- {
- if (findCondition(m.versionidsNot, ident))
- {
- .error(loc, "%s `%s` defined after use", kind, toPrettyChars);
- errors = true;
- }
- if (!m.versionids)
- m.versionids = new Identifiers();
- m.versionids.push(ident);
- }
- }
- else
- {
- if (!m)
- {
- .error(loc, "%s `%s` level declaration must be at module level", kind, toPrettyChars);
- errors = true;
- }
- else
- m.versionlevel = level;
- }
- }
-
override const(char)* kind() const nothrow
{
return "version";
@@ -46,12 +46,10 @@ public:
bool inuse(bool v);
EnumDeclaration *syntaxCopy(Dsymbol *s) override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope *sc) override;
bool oneMember(Dsymbol **ps, Identifier *ident) override;
Type *getType() override;
const char *kind() const override;
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
bool isDeprecated() const override; // is Dsymbol deprecated?
Visibility visible() override;
bool isSpecial() const;
@@ -25,7 +25,7 @@ import dmd.dsymbol;
import dmd.errors;
import dmd.expression;
import dmd.func;
-import dmd.globals;
+import dmd.globals : FeatureState;
import dmd.id;
import dmd.identifier;
import dmd.init;
@@ -169,7 +169,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
if (!(eb.isMutable || eb2.isMutable))
return;
- if (!tf.islive && !(global.params.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe()))
+ if (!tf.islive && !(sc.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe()))
return;
if (!gag)
@@ -377,7 +377,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
sc.setUnsafeDIP1000(gag, arg.loc, msg, v, parId ? parId : fdc, fdc))
{
result = true;
- printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), vPar, 10);
+ printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), sc.useDIP1000), vPar, 10);
}
}
@@ -1094,7 +1094,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
{
if (p == sc.func)
{
- result |= escapingRef(v, global.params.useDIP1000);
+ result |= escapingRef(v, sc.useDIP1000);
continue;
}
}
@@ -1110,7 +1110,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
{
//printf("escaping reference to local ref variable %s\n", v.toChars());
//printf("storage class = x%llx\n", v.storage_class);
- result |= escapingRef(v, global.params.useDIP25);
+ result |= escapingRef(v, sc.useDIP25);
continue;
}
// Don't need to be concerned if v's parent does not return a ref
@@ -1125,12 +1125,12 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
const(char)* msg = "storing reference to outer local variable `%s` into allocated memory causes it to escape";
if (!gag)
{
- previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars());
+ previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars());
}
// If -preview=dip25 is used, the user wants an error
// Otherwise, issue a deprecation
- result |= (global.params.useDIP25 == FeatureState.enabled);
+ result |= (sc.useDIP25 == FeatureState.enabled);
}
}
@@ -1264,7 +1264,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
// https://issues.dlang.org/show_bug.cgi?id=23191
if (!gag)
{
- previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)(e.loc,
+ previewErrorFunc(sc.isDeprecated(), sc.useDIP1000)(e.loc,
"scope parameter `%s` may not be returned", v.toChars()
);
result = true;
@@ -1403,7 +1403,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
{
//printf("escaping reference to local ref variable %s\n", v.toChars());
//printf("storage class = x%llx\n", v.storage_class);
- escapingRef(v, global.params.useDIP25);
+ escapingRef(v, sc.useDIP25);
continue;
}
// Don't need to be concerned if v's parent does not return a ref
@@ -1415,7 +1415,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
{
const(char)* msg = "escaping reference to outer local variable `%s`";
if (!gag)
- previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars());
+ previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars());
result = true;
continue;
}
@@ -2588,7 +2588,7 @@ public
bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg,
RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
{
- return setUnsafePreview(sc, global.params.useDIP1000, gag, loc, msg, arg0, arg1, arg2);
+ return setUnsafePreview(sc, sc.useDIP1000, gag, loc, msg, arg0, arg1, arg2);
}
/***************************************
@@ -4617,7 +4617,9 @@ extern (C++) final class UshrAssignExp : BinAssignExp
*/
extern (C++) class CatAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ Expression lowering; // lowered druntime hook `_d_arrayappend{cTX,T}`
+
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
super(loc, EXP.concatenateAssign, e1, e2);
}
@@ -52,7 +52,7 @@ void expandTuples(Expressions *exps, Identifiers *names = nullptr);
StringExp *toUTF8(StringExp *se, Scope *sc);
Expression *resolveLoc(Expression *exp, const Loc &loc, Scope *sc);
MATCH implicitConvTo(Expression *e, Type *t);
-Expression *toLvalue(Expression *_this, Scope *sc);
+Expression *toLvalue(Expression *_this, Scope *sc, const char* action);
Expression *modifiableLvalue(Expression* exp, Scope *sc);
typedef unsigned char OwnedBy;
@@ -1114,6 +1114,8 @@ public:
class CatAssignExp : public BinAssignExp
{
public:
+ Expression *lowering; // lowered druntime hook `_d_arrayappend{cTX,T}`
+
void accept(Visitor *v) override { v->visit(this); }
};
@@ -2150,7 +2150,7 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
* verified instead. This is to keep errors related to the original code
* and not the lowering.
*/
- if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT)
+ if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT || f.ident == Id._d_newarraymTX)
return false;
if (!f.isNogc())
@@ -3129,7 +3129,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
arg = ev.expressionSemantic(sc);
}
- arg = arg.toLvalue(sc);
+ arg = arg.toLvalue(sc, "create `in` parameter from");
// Look for mutable misaligned pointer, etc., in @safe mode
err |= checkUnsafeAccess(sc, arg, false, true);
@@ -3147,7 +3147,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
arg = ev.expressionSemantic(sc);
}
- arg = arg.toLvalue(sc);
+ arg = arg.toLvalue(sc, "create `ref` parameter from");
// Look for mutable misaligned pointer, etc., in @safe mode
err |= checkUnsafeAccess(sc, arg, false, true);
@@ -3166,7 +3166,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
err |= checkUnsafeAccess(sc, arg, false, true);
err |= checkDefCtor(arg.loc, t); // t must be default constructible
}
- arg = arg.toLvalue(sc);
+ arg = arg.toLvalue(sc, "create `out` parameter from");
}
else if (p.isLazy())
{
@@ -3209,7 +3209,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
const explicitScope = p.isLazy() ||
((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
if ((pStc & (STC.scope_ | STC.lazy_)) &&
- ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) &&
+ ((sc.useDIP1000 == FeatureState.enabled) || explicitScope) &&
!(pStc & STC.return_))
{
/* Argument value cannot escape from the called function.
@@ -5115,23 +5115,23 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
tb = tb.isTypeDArray().next.toBasetype();
}
- if (nargs == 1)
- {
- if (global.params.betterC || !sc.needsCodegen())
+ if (global.params.betterC || !sc.needsCodegen())
goto LskipNewArrayLowering;
- /* Class types may inherit base classes that have errors.
- * This may leak errors from the base class to the derived one
- * and then to the hook. Semantic analysis is performed eagerly
- * to a void this.
- */
- if (auto tc = exp.type.nextOf.isTypeClass())
- {
- tc.sym.dsymbolSemantic(sc);
- if (tc.sym.errors)
- goto LskipNewArrayLowering;
- }
+ /* Class types may inherit base classes that have errors.
+ * This may leak errors from the base class to the derived one
+ * and then to the hook. Semantic analysis is performed eagerly
+ * to a void this.
+ */
+ if (auto tc = exp.type.nextOf.isTypeClass())
+ {
+ tc.sym.dsymbolSemantic(sc);
+ if (tc.sym.errors)
+ goto LskipNewArrayLowering;
+ }
+ if (nargs == 1)
+ {
auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT;
if (!verifyHookExist(exp.loc, *sc, hook, "new array"))
goto LskipNewArrayLowering;
@@ -5163,6 +5163,45 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
arguments.push((*exp.arguments)[0]);
arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool));
+ lowering = new CallExp(exp.loc, lowering, arguments);
+ exp.lowering = lowering.expressionSemantic(sc);
+ }
+ else
+ {
+ auto hook = global.params.tracegc ? Id._d_newarraymTXTrace : Id._d_newarraymTX;
+ if (!verifyHookExist(exp.loc, *sc, hook, "new multi-dimensional array"))
+ goto LskipNewArrayLowering;
+
+ /* Lower the memory allocation and initialization of `new T[][]...[](n1, n2, ...)`
+ * to `_d_newarraymTX!(T[][]...[], T)([n1, n2, ...])`.
+ */
+ Expression lowering = new IdentifierExp(exp.loc, Id.empty);
+ lowering = new DotIdExp(exp.loc, lowering, Id.object);
+
+ auto tbn = exp.type.nextOf();
+ while (tbn.ty == Tarray)
+ tbn = tbn.nextOf();
+ auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
+ MODFlags.immutable_ | MODFlags.shared_);
+
+ auto tiargs = new Objects();
+ tiargs.push(exp.type);
+ tiargs.push(unqualTbn);
+ lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
+
+ auto arguments = new Expressions();
+ if (global.params.tracegc)
+ {
+ auto funcname = (sc.callsc && sc.callsc.func) ?
+ sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
+ arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
+ arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
+ arguments.push(new StringExp(exp.loc, funcname.toDString()));
+ }
+
+ arguments.push(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments));
+ arguments.push(new IntegerExp(exp.loc, tbn.isShared(), Type.tbool));
+
lowering = new CallExp(exp.loc, lowering, arguments);
exp.lowering = lowering.expressionSemantic(sc);
}
@@ -8295,7 +8334,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
{
// `toLvalue` call further below is upon exp.e1, omitting & from the error message
- exp.toLvalue(sc);
+ exp.toLvalue(sc, "take address of");
return setError();
}
}
@@ -8385,7 +8424,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
- exp.e1 = exp.e1.toLvalue(sc);
+ exp.e1 = exp.e1.toLvalue(sc, "take address of");
if (exp.e1.op == EXP.error)
{
result = exp.e1;
@@ -9017,14 +9056,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
- // Look for casting to a vector type
- if (tob.ty == Tvector && t1b.ty != Tvector)
- {
- result = new VectorExp(exp.loc, exp.e1, exp.to);
- result = result.expressionSemantic(sc);
- return;
- }
-
Expression ex = exp.e1.castTo(sc, exp.to);
if (ex.op == EXP.error)
{
@@ -11727,8 +11758,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = res;
- if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
- sc.needsCodegen())
+ if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && sc.needsCodegen())
{
// if aa ordering is triggered, `res` will be a CommaExp
// and `.e2` will be the rewritten original expression.
@@ -11772,7 +11802,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
arguments.push(exp.e1);
arguments.push(exp.e2);
Expression ce = new CallExp(exp.loc, id, arguments);
- *output = ce.expressionSemantic(sc);
+
+ exp.lowering = ce.expressionSemantic(sc);
+ *output = exp;
}
else if (exp.op == EXP.concatenateElemAssign)
{
@@ -11792,15 +11824,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
- if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object))
+ if (!verifyHookExist(exp.loc, *sc, hook, "appending element to arrays", Id.object))
return setError();
- // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
+ // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
Expression id = new IdentifierExp(exp.loc, Id.empty);
id = new DotIdExp(exp.loc, id, Id.object);
- auto tiargs = new Objects();
- tiargs.push(exp.e1.type);
- id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs);
id = new DotIdExp(exp.loc, id, hook);
auto arguments = new Expressions();
@@ -11827,11 +11856,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
/* Before the template hook, this check was performed in e2ir.d
* for expressions like `a ~= a[$-1]`. Here, $ will be modified
- * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
+ * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
* a temporary variable.
*/
value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
- exp.e2 = value2;
// `__appendtmp*` will be destroyed together with the array `exp.e1`.
auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
@@ -11847,13 +11875,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
e0 = Expression.combine(e0, value1);
e0 = Expression.combine(eValue1, e0);
-
e0 = Expression.combine(eValue2, e0);
- *output = e0.expressionSemantic(sc);
+ exp.lowering = e0.expressionSemantic(sc);
+ *output = exp;
}
}
-
}
override void visit(AddExp exp)
@@ -15210,15 +15237,21 @@ Expression addDtorHook(Expression e, Scope* sc)
* Params:
* _this = expression to convert
* sc = scope
+ * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
* Returns: converted expression, or `ErrorExp` on error
*/
-extern(C++) Expression toLvalue(Expression _this, Scope* sc)
+extern(C++) Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
{
- return toLvalueImpl(_this, sc, _this);
+ return toLvalueImpl(_this, sc, action, _this);
}
// e = original un-lowered expression for error messages, in case of recursive calls
-private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
+private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e)
+{
+ if (!action)
+ action = "create lvalue of";
+
+ assert(e);
Expression visit(Expression _this)
{
// BinaryAssignExp does not have an EXP associated
@@ -15230,9 +15263,11 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
_this.loc = e.loc;
if (e.op == EXP.type)
- error(_this.loc, "`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
+ error(_this.loc, "cannot %s type `%s`", action, e.type.toChars());
+ else if (e.op == EXP.template_)
+ error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toChars());
else
- error(_this.loc, "`%s` is not an lvalue and cannot be modified", e.toChars());
+ error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars());
return ErrorExp.get();
}
@@ -15241,7 +15276,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
{
if (!_this.loc.isValid())
_this.loc = e.loc;
- error(e.loc, "cannot modify constant `%s`", e.toChars());
+ error(e.loc, "cannot %s constant `%s`", action, e.toChars());
return ErrorExp.get();
}
@@ -15285,22 +15320,22 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
auto var = _this.var;
if (var.storage_class & STC.manifest)
{
- error(_this.loc, "manifest constant `%s` cannot be modified", var.toChars());
+ error(_this.loc, "cannot %s manifest constant `%s`", action, var.toChars());
return ErrorExp.get();
}
if (var.storage_class & STC.lazy_ && !_this.delegateWasExtracted)
{
- error(_this.loc, "lazy variable `%s` cannot be modified", var.toChars());
+ error(_this.loc, "cannot %s lazy variable `%s`", action, var.toChars());
return ErrorExp.get();
}
if (var.ident == Id.ctfe)
{
- error(_this.loc, "cannot modify compiler-generated variable `__ctfe`");
+ error(_this.loc, "cannot %s compiler-generated variable `__ctfe`", action);
return ErrorExp.get();
}
if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
{
- error(_this.loc, "cannot modify operator `$`");
+ error(_this.loc, "cannot %s operator `$`", action);
return ErrorExp.get();
}
return _this;
@@ -15370,7 +15405,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
Expression visitVectorArray(VectorArrayExp _this)
{
- _this.e1 = _this.e1.toLvalueImpl(sc, e);
+ _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
return _this;
}
@@ -15389,19 +15424,19 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
Expression visitComma(CommaExp _this)
{
- _this.e2 = _this.e2.toLvalue(sc);
+ _this.e2 = _this.e2.toLvalue(sc, action);
return _this;
}
Expression visitDelegatePointer(DelegatePtrExp _this)
{
- _this.e1 = _this.e1.toLvalueImpl(sc, e);
+ _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
return _this;
}
Expression visitDelegateFuncptr(DelegateFuncptrExp _this)
{
- _this.e1 = _this.e1.toLvalueImpl(sc, e);
+ _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
return _this;
}
@@ -15430,8 +15465,8 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
{
// convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
CondExp e = cast(CondExp)(_this.copy());
- e.e1 = _this.e1.toLvalue(sc).addressOf();
- e.e2 = _this.e2.toLvalue(sc).addressOf();
+ e.e1 = _this.e1.toLvalue(sc, action).addressOf();
+ e.e2 = _this.e2.toLvalue(sc, action).addressOf();
e.type = _this.type.pointerTo();
return new PtrExp(_this.loc, e, _this.type);
@@ -15634,12 +15669,13 @@ extern(C++) Expression modifiableLvalue(Expression _this, Scope* sc)
// e = original / un-lowered expression to print in error messages
private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression e)
{
+ assert(e);
Expression visit(Expression exp)
{
//printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
// See if this expression is a modifiable lvalue (i.e. not const)
if (exp.isBinAssignExp())
- return exp.toLvalue(sc);
+ return exp.toLvalue(sc, "modify");
auto type = exp.type;
if (checkModifiable(exp, sc) == Modifiable.yes)
@@ -15672,7 +15708,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
return ErrorExp.get();
}
}
- return exp.toLvalueImpl(sc, e);
+ return exp.toLvalueImpl(sc, "modify", e);
}
Expression visitString(StringExp exp)
@@ -15762,7 +15798,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
}
exp.e1 = exp.e1.modifiableLvalue(sc);
exp.e2 = exp.e2.modifiableLvalue(sc);
- return exp.toLvalue(sc);
+ return exp.toLvalue(sc, "modify");
}
switch(_this.op)
@@ -15803,7 +15839,7 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
}
if (sc.func && !sc.intypeof && !v.isDataseg())
{
- if (global.params.useDIP1000 != FeatureState.enabled &&
+ if (sc.useDIP1000 != FeatureState.enabled &&
!(v.storage_class & STC.temp) &&
sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
{
@@ -3241,13 +3241,6 @@ unittest
assert(mismatches.isMutable);
}
-private const(char)* prependSpace(const(char)* str)
-{
- if (!str || !*str) return "";
-
- return (" " ~ str.toDString() ~ "\0").ptr;
-}
-
/// Flag used by $(LREF resolveFuncCall).
enum FuncResolveFlag : ubyte
{
@@ -3361,14 +3354,11 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
- const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
- const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
-
.error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
s.parent.toPrettyChars(), s.ident.toChars(),
fargsBuf.peekChars(),
- m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
- m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
+ m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
+ m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
return null;
}
@@ -3422,15 +3412,25 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
if (!tf)
tf = fd.originalType.toTypeFunction();
- if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
+ // modifier mismatch
+ if (tthis && (fd.isCtorDeclaration() ?
+ !MODimplicitConv(tf.mod, tthis.mod) :
+ !MODimplicitConv(tthis.mod, tf.mod)))
{
OutBuffer thisBuf, funcBuf;
MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
if (hasOverloads)
{
- .error(loc, "none of the overloads of `%s` are callable using a %sobject",
- fd.ident.toChars(), thisBuf.peekChars());
+ OutBuffer buf;
+ buf.argExpTypesToCBuffer(fargs);
+ if (fd.isCtorDeclaration())
+ .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
+ fd.toChars(), thisBuf.peekChars(), buf.peekChars());
+ else
+ .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
+ fd.toChars(), thisBuf.peekChars(), buf.peekChars());
+
if (!global.gag || global.params.v.showGaggedErrors)
printCandidates(loc, fd, sc.isDeprecated());
return null;
@@ -3447,8 +3447,12 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
return null;
}
- .error(loc, "%smethod `%s` is not callable using a %sobject",
- funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
+ if (fd.isCtorDeclaration())
+ .error(loc, "%s%s `%s` cannot construct a %sobject",
+ funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
+ else
+ .error(loc, "%smethod `%s` is not callable using a %sobject",
+ funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
if (mismatches.isNotShared)
.errorSupplemental(fd.loc, "Consider adding `shared` here");
@@ -3535,11 +3539,17 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
if (!print)
return true;
auto tf = cast(TypeFunction) fd.type;
+ OutBuffer buf;
+ buf.writestring(fd.toPrettyChars());
+ buf.writestring(parametersTypeToChars(tf.parameterList));
+ if (tf.mod)
+ {
+ buf.writeByte(' ');
+ buf.MODtoBuffer(tf.mod);
+ }
.errorSupplemental(fd.loc,
- printed ? " `%s%s`" :
- single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`",
- fd.toPrettyChars(),
- parametersTypeToChars(tf.parameterList));
+ printed ? " `%s`" :
+ single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
}
else if (auto td = s.isTemplateDeclaration())
{
@@ -4621,7 +4631,14 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)
case default_:
if (!sc.func)
return false;
- if (!sc.func.isSafeBypassingInference() && !sc.func.safetyViolation)
+ if (sc.func.isSafeBypassingInference())
+ {
+ if (!gag)
+ {
+ warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ }
+ }
+ else if (!sc.func.safetyViolation)
{
import dmd.func : AttributeViolation;
sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
@@ -1943,7 +1943,7 @@ private void visitTemplateParameters(TemplateParameters* parameters, ref OutBuff
{
if (i)
buf.writestring(", ");
- p.templateParameterToBuffer(buf, &hgs);
+ toCBuffer(p, buf, hgs);
}
}
@@ -2885,10 +2885,10 @@ void floatToBuffer(Type type, const real_t value, ref OutBuffer buf, const bool
}
}
-private void templateParameterToBuffer(TemplateParameter tp, ref OutBuffer buf, HdrGenState* hgs)
+void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs)
{
- scope v = new TemplateParameterPrettyPrintVisitor(&buf, hgs);
- tp.accept(v);
+ scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs);
+ (cast() tp).accept(v);
}
private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor
@@ -3262,12 +3262,6 @@ void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments)
}
}
-void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs)
-{
- scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs);
- (cast() tp).accept(v);
-}
-
void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects)
{
if (!objects || !objects.length)
@@ -3837,7 +3831,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
{
if (i)
buf.writestring(", ");
- p.templateParameterToBuffer(buf, hgs);
+ toCBuffer(p, buf, *hgs);
}
buf.writeByte(')');
}
@@ -3862,6 +3856,11 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState
buf.writestring("void");
}
+ void visitDefault(DefaultInitializer iz)
+ {
+ buf.writestring("{ }");
+ }
+
void visitStruct(StructInitializer si)
{
//printf("StructInitializer::toCBuffer()\n");
@@ -323,6 +323,8 @@ immutable Msgtable[] msgtable =
{ "_d_newitemTTrace" },
{ "_d_newarrayT" },
{ "_d_newarrayTTrace" },
+ { "_d_newarraymTX" },
+ { "_d_newarraymTXTrace" },
{ "_d_assert_fail" },
{ "dup" },
{ "_aaApply" },
@@ -366,7 +368,6 @@ immutable Msgtable[] msgtable =
{ "_d_arraysetlengthTTrace"},
{ "_d_arrayappendT" },
{ "_d_arrayappendTTrace" },
- { "_d_arrayappendcTXImpl" },
{ "_d_arrayappendcTX" },
{ "_d_arrayappendcTXTrace" },
{ "_d_arraycatnTX" },
@@ -43,9 +43,7 @@ public:
Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees
void importAll(Scope *sc) override;
Dsymbol *toAlias() override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope* sc) override;
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
bool overloadInsert(Dsymbol *s) override;
Import *isImport() override { return this; }
@@ -20,6 +20,7 @@ import dmd.dcast;
import dmd.declaration;
import dmd.dscope;
import dmd.dsymbol;
+import dmd.dsymbolsem;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
@@ -68,6 +68,11 @@ extern (C++) class Initializer : ASTNode
return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null;
}
+ final inout(DefaultInitializer) isDefaultInitializer() inout @nogc nothrow pure
+ {
+ return kind == InitKind.default_ ? cast(inout DefaultInitializer)cast(void*)this : null;
+ }
+
final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure
{
return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null;
@@ -111,6 +116,24 @@ extern (C++) final class VoidInitializer : Initializer
}
}
+/***********************************************************
+ * The C23 default initializer `{ }`
+ */
+extern (C++) final class DefaultInitializer : Initializer
+{
+ Type type; // type that this will initialize to
+
+ extern (D) this(const ref Loc loc) @safe
+ {
+ super(loc, InitKind.default_);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
/***********************************************************
*/
extern (C++) final class ErrorInitializer : Initializer
@@ -266,6 +289,11 @@ Initializer syntaxCopy(Initializer inx)
return new VoidInitializer(vi.loc);
}
+ static Initializer visitDefault(DefaultInitializer vi)
+ {
+ return new DefaultInitializer(vi.loc);
+ }
+
static Initializer visitError(ErrorInitializer vi)
{
return vi;
@@ -352,6 +380,7 @@ mixin template VisitInitializer(Result)
final switch (init.kind)
{
case InitKind.void_: mixin(visitCase("Void")); break;
+ case InitKind.default_: mixin(visitCase("Default")); break;
case InitKind.error: mixin(visitCase("Error")); break;
case InitKind.struct_: mixin(visitCase("Struct")); break;
case InitKind.array: mixin(visitCase("Array")); break;
@@ -20,6 +20,7 @@ class Expression;
class Type;
class ErrorInitializer;
class VoidInitializer;
+class DefaultInitializer;
class StructInitializer;
class ArrayInitializer;
class ExpInitializer;
@@ -37,6 +38,7 @@ public:
ErrorInitializer *isErrorInitializer();
VoidInitializer *isVoidInitializer();
+ DefaultInitializer *isDefaultInitializer();
StructInitializer *isStructInitializer();
ArrayInitializer *isArrayInitializer();
ExpInitializer *isExpInitializer();
@@ -53,6 +55,14 @@ public:
void accept(Visitor *v) override { v->visit(this); }
};
+class DefaultInitializer final : public Initializer
+{
+public:
+ Type *type; // type that this will initialize to
+
+ void accept(Visitor *v) override { v->visit(this); }
+};
+
class ErrorInitializer final : public Initializer
{
public:
@@ -24,6 +24,7 @@ import dmd.dinterpret;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
+import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
@@ -106,6 +107,7 @@ Expression toAssocArrayLiteral(ArrayInitializer ai)
*/
extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret)
{
+ //printf("initializerSemantic() tx: %p %s\n", tx, tx.toChars());
Type t = tx;
static Initializer err()
@@ -119,6 +121,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
return i;
}
+ Initializer visitDefault(DefaultInitializer i)
+ {
+ i.type = t;
+ return i;
+ }
+
Initializer visitError(ErrorInitializer i)
{
return i;
@@ -1017,6 +1025,12 @@ Initializer inferType(Initializer init, Scope* sc)
return new ErrorInitializer();
}
+ Initializer visitDefault(DefaultInitializer i)
+ {
+ error(i.loc, "cannot infer type from default initializer");
+ return new ErrorInitializer();
+ }
+
Initializer visitError(ErrorInitializer i)
{
return i;
@@ -1175,6 +1189,11 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
return null;
}
+ Expression visitDefault(DefaultInitializer di)
+ {
+ return di.type ? di.type.defaultInit(Loc.initial, isCfile) : null;
+ }
+
Expression visitError(ErrorInitializer)
{
return ErrorExp.get();
@@ -22,6 +22,7 @@ import dmd.astenums;
import dmd.declaration;
import dmd.denum;
import dmd.dsymbol;
+import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.expression;
import dmd.func;
@@ -43,7 +43,6 @@ public:
bool isAncestorPackageOf(const Package * const pkg) const;
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
void accept(Visitor *v) override { v->visit(this); }
Module *isPackageMod();
@@ -124,7 +123,6 @@ public:
Module *parse(); // syntactic parse
void importAll(Scope *sc) override;
int needModuleInfo();
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override;
Dsymbol *symtabInsert(Dsymbol *s) override;
static void runDeferredSemantic();
@@ -108,12 +108,6 @@ public:
return;
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
}
- else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendcTX)
- {
- if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`"))
- return;
- f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
- }
}
override void visit(ArrayLiteralExp e)
@@ -187,20 +181,14 @@ public:
override void visit(CatAssignExp e)
{
- /* CatAssignExp will exist in `__traits(compiles, ...)` and in the `.e1` branch of a `__ctfe ? :` CondExp.
- * The other branch will be `_d_arrayappendcTX(e1, 1), e1[$-1]=e2` which will generate the warning about
- * GC usage. See visit(CallExp).
- */
if (checkOnly)
{
err = true;
return;
}
- if (f.setGC(e.loc, null))
- {
- err = true;
+ if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`"))
return;
- }
+ f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
}
override void visit(CatExp e)
@@ -85,33 +85,6 @@ extern (C++) final class Nspace : ScopeDsymbol
return ns;
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- ScopeDsymbol.addMember(sc, sds);
-
- if (members)
- {
- if (!symtab)
- symtab = new DsymbolTable();
- // The namespace becomes 'imported' into the enclosing scope
- for (Scope* sce = sc; 1; sce = sce.enclosing)
- {
- ScopeDsymbol sds2 = sce.scopesym;
- if (sds2)
- {
- sds2.importScope(this, Visibility(Visibility.Kind.public_));
- break;
- }
- }
- assert(sc);
- sc = sc.push(this);
- sc.linkage = LINK.cpp; // namespaces default to C++ linkage
- sc.parent = this;
- members.foreachDsymbol(s => s.addMember(sc, this));
- sc.pop();
- }
- }
-
override void setScope(Scope* sc)
{
ScopeDsymbol.setScope(sc);
@@ -126,22 +99,6 @@ extern (C++) final class Nspace : ScopeDsymbol
}
}
- override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
- {
- //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars());
- if (_scope && !symtab)
- dsymbolSemantic(this, _scope);
-
- if (!members || !symtab) // opaque or semantic() is not yet called
- {
- if (!(flags & IgnoreErrors))
- .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars());
- return null;
- }
-
- return ScopeDsymbol.search(loc, ident, flags);
- }
-
override bool hasPointers()
{
//printf("Nspace::hasPointers() %s\n", toChars());
@@ -21,9 +21,7 @@ class Nspace final : public ScopeDsymbol
public:
Expression *identExp;
Nspace *syntaxCopy(Dsymbol *s) override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope *sc) override;
- Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
bool hasPointers() override;
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
const char *kind() const override;
@@ -23,6 +23,7 @@ import dmd.declaration;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
+import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
@@ -928,6 +928,14 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
}
}
+ void visitCatAssign(CatAssignExp e)
+ {
+ if (auto lowering = e.lowering)
+ optimize(lowering, result, keepLvalue);
+ else
+ visitBinAssign(e);
+ }
+
void visitBin(BinExp e)
{
//printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
@@ -1392,9 +1400,9 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
case EXP.leftShiftAssign:
case EXP.rightShiftAssign:
case EXP.unsignedRightShiftAssign:
+ case EXP.concatenateDcharAssign: visitBinAssign(ex.isBinAssignExp()); break;
case EXP.concatenateElemAssign:
- case EXP.concatenateDcharAssign:
- case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break;
+ case EXP.concatenateAssign: visitCatAssign(cast(CatAssignExp) ex); break;
case EXP.minusMinus:
case EXP.plusPlus:
@@ -4878,30 +4878,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.Declaration v;
AST.Dsymbol s;
- // try to parse function type:
- // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
bool attributesAppended;
const StorageClass funcStc = parseTypeCtor();
- Token* tlu = &token;
Token* tk;
- if (token.value != TOK.function_ &&
- token.value != TOK.delegate_ &&
- isBasicType(&tlu) && tlu &&
- tlu.value == TOK.leftParenthesis)
- {
- AST.Type tret = parseBasicType();
- auto parameterList = parseParameterList(null);
-
- parseAttributes();
- if (udas)
- error("user-defined attributes not allowed for `alias` declarations");
-
- attributesAppended = true;
- storage_class = appendStorageClass(storage_class, funcStc);
- AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class);
- v = new AST.AliasDeclaration(loc, ident, tf);
- }
- else if (token.value == TOK.function_ ||
+ // function literal?
+ if (token.value == TOK.function_ ||
token.value == TOK.delegate_ ||
token.value == TOK.leftParenthesis &&
skipAttributes(peekPastParen(&token), &tk) &&
@@ -4911,10 +4892,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis &&
skipAttributes(peekPastParen(peek(&token)), &tk) &&
(tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
- token.value == TOK.auto_ && peekNext() == TOK.ref_ &&
- peekNext2() == TOK.leftParenthesis &&
- skipAttributes(peekPastParen(peek(peek(&token))), &tk) &&
- (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)
+ token.value == TOK.auto_ &&
+ (peekNext() == TOK.leftParenthesis || // for better error
+ peekNext() == TOK.ref_ &&
+ peekNext2() == TOK.leftParenthesis)
)
{
// function (parameters) { statements... }
@@ -4955,21 +4936,46 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
else
{
- parseAttributes();
// type
+ parseAttributes();
if (udas)
error("user-defined attributes not allowed for `alias` declarations");
- auto t = parseType();
+ auto t = parseBasicType();
+ t = parseTypeSuffixes(t);
+ if (token.value == TOK.identifier)
+ {
+ error("unexpected identifier `%s` after `%s`",
+ token.ident.toChars(), t.toChars());
+ nextToken();
+ }
+ else if (token.value == TOK.leftParenthesis)
+ {
+ // function type:
+ // StorageClasses Type ( Parameters ) MemberFunctionAttributes
+ auto parameterList = parseParameterList(null);
+ udas = null;
+ parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
+ if (udas)
+ error("user-defined attributes not allowed for `alias` declarations");
+
+ attributesAppended = true;
+ // Note: method types can have a TypeCtor attribute
+ storage_class = appendStorageClass(storage_class, funcStc);
+ t = new AST.TypeFunction(parameterList, t, link, storage_class);
+ }
// Disallow meaningless storage classes on type aliases
if (storage_class)
{
// Don't raise errors for STC that are part of a function/delegate type, e.g.
// `alias F = ref pure nothrow @nogc @safe int function();`
- auto tp = t.isTypePointer;
- const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
- const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
+ const remStc = t.isTypeFunction ?
+ storage_class & ~(STC.FUNCATTR | STC.TYPECTOR) : {
+ auto tp = t.isTypePointer;
+ const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
+ return isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
+ }();
if (remStc)
{
@@ -7217,6 +7223,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return false;
}
+ // pt = test token. If found, pt is set to the token after BasicType
private bool isBasicType(Token** pt)
{
// This code parallels parseBasicType()
@@ -298,5 +298,6 @@ public:
void visit(AST.StructInitializer i) { visit(cast(AST.Initializer)i); }
void visit(AST.ArrayInitializer i) { visit(cast(AST.Initializer)i); }
void visit(AST.VoidInitializer i) { visit(cast(AST.Initializer)i); }
+ void visit(AST.DefaultInitializer i) { visit(cast(AST.Initializer)i); }
void visit(AST.CInitializer i) { visit(cast(AST.CInitializer)i); }
}
@@ -61,6 +61,9 @@ enum class SCOPE
Cfile = 0x0800, // C semantics apply
free = 0x8000, // is on free list
fullinst = 0x10000, // fully instantiate templates
+ ctfeBlock = 0x20000, // inside a `if (__ctfe)` block
+ dip1000 = 0x40000, // dip1000 errors enabled for this scope
+ dip25 = 0x80000, // dip25 errors enabled for this scope
};
struct Scope
@@ -126,4 +129,6 @@ 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);
};
@@ -918,7 +918,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
if (f.isref)
{
// Function returns a reference
- exp = exp.toLvalue(sc2);
+ exp = exp.toLvalue(sc2, "`ref` return");
checkReturnEscapeRef(sc2, exp, false);
exp = exp.optimize(WANTvalue, /*keepLvalue*/ true);
}
@@ -3801,7 +3801,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde,
{
version (none)
{
- if (global.params.useDIP1000 == FeatureState.enabled)
+ if (sc2.useDIP1000 == FeatureState.enabled)
{
message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`");
}
@@ -3809,7 +3809,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde,
}
else
{
- if (global.params.useDIP1000 == FeatureState.enabled)
+ if (sc2.useDIP1000 == FeatureState.enabled)
++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope'
}
assert(tab.ty == Tstruct || tab.ty == Tclass);
@@ -52,11 +52,6 @@ extern (C++) final class StaticAssert : Dsymbol
return new StaticAssert(loc, exp.syntaxCopy(), msgs ? Expression.arraySyntaxCopy(msgs) : null);
}
- override void addMember(Scope* sc, ScopeDsymbol sds)
- {
- // we didn't add anything
- }
-
override bool oneMember(Dsymbol* ps, Identifier ident)
{
//printf("StaticAssert::oneMember())\n");
@@ -21,7 +21,6 @@ public:
Expressions *msg;
StaticAssert *syntaxCopy(Dsymbol *s) override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
bool oneMember(Dsymbol **ps, Identifier *ident) override;
const char *kind() const override;
StaticAssert *isStaticAssert() override { return this; }
@@ -32,6 +32,7 @@ import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
+import dmd.errorsink;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
@@ -92,43 +93,50 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg)
}
/**
- * get an array of size_t values that indicate possible pointer words in memory
- * if interpreted as the type given as argument
- * Returns: the size of the type in bytes, ulong.max on error
+ * Fill an array of target size_t values that indicate possible pointer words in memory
+ * if interpreted as the type given as argument.
+ * One bit in the array per pointer-sized piece of memory
+ * Params:
+ * loc = location for error messages
+ * t = type to generate pointer bitmap from
+ * data = array forming the bitmap
+ * eSink = error message sink
+ * Returns:
+ * size of the type `t` in bytes, ulong.max on error
*/
-ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
+ulong getTypePointerBitmap(Loc loc, Type t, ref Array!(ulong) data, ErrorSink eSink)
{
- ulong sz;
- if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration())
- sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc);
- else
- sz = t.size(loc);
+ auto tc = t.isTypeClass();
+ const ulong sz = (tc && !tc.sym.isInterfaceDeclaration())
+ ? tc.sym.AggregateDeclaration.size(loc)
+ : t.size(loc);
if (sz == SIZE_INVALID)
return ulong.max;
- const sz_size_t = Type.tsize_t.size(loc);
+ const sz_size_t = Type.tsize_t.size(loc); // size of target's size_t
+ assert(sz_size_t <= ulong.sizeof);
if (sz > sz.max - sz_size_t)
{
- error(loc, "size overflow for type `%s`", t.toChars());
+ eSink.error(loc, "size overflow for type `%s`", t.toChars());
return ulong.max;
}
- ulong bitsPerWord = sz_size_t * 8;
- ulong cntptr = (sz + sz_size_t - 1) / sz_size_t;
- ulong cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
+ const ulong bitsPerElement = sz_size_t * 8; // bits used in each array element
+ const ulong cntptr = (sz + sz_size_t - 1) / sz_size_t; // pointers have same size as sz_size_t
+ const ulong length = (cntptr + bitsPerElement - 1) / bitsPerElement; // a bit per pointer
- data.setDim(cast(size_t)cntdata);
+ data.setDim(cast(size_t)length);
data.zero();
ulong offset;
- bool error;
+ bool error; // sticky error indicator
void visit(Type t)
{
void setpointer(ulong off)
{
ulong ptroff = off / sz_size_t;
- (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t));
+ data[cast(size_t)(ptroff / bitsPerElement)] |= 1L << (ptroff % bitsPerElement);
}
void visitType(Type t)
@@ -247,7 +255,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
visit.VisitType(t);
}
- if (auto tc = t.isTypeClass())
+ if (auto tcx = t.isTypeClass())
{
// a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
void visitTopLevelClass(TypeClass t)
@@ -264,7 +272,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
offset = classoff;
}
- visitTopLevelClass(tc);
+ visitTopLevelClass(tcx);
}
else
visit(t);
@@ -281,28 +289,28 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
*
* Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
*/
-private Expression pointerBitmap(TraitsExp e)
+private Expression pointerBitmap(TraitsExp e, ErrorSink eSink)
{
if (!e.args || e.args.length != 1)
{
- error(e.loc, "a single type expected for trait pointerBitmap");
+ eSink.error(e.loc, "a single type expected for trait pointerBitmap");
return ErrorExp.get();
}
Type t = getType((*e.args)[0]);
if (!t)
{
- error(e.loc, "`%s` is not a type", (*e.args)[0].toChars());
+ eSink.error(e.loc, "`%s` is not a type", (*e.args)[0].toChars());
return ErrorExp.get();
}
Array!(ulong) data;
- ulong sz = getTypePointerBitmap(e.loc, t, &data);
+ const ulong sz = getTypePointerBitmap(e.loc, t, data, eSink);
if (sz == ulong.max)
return ErrorExp.get();
auto exps = new Expressions(data.length + 1);
- (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t);
+ (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t); // [0] is size in bytes of t
foreach (size_t i; 1 .. exps.length)
(*exps)[i] = new IntegerExp(e.loc, data[cast(size_t) (i - 1)], Type.tsize_t);
@@ -472,13 +480,13 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
if (e.ident == Id.isAbstractClass)
{
- return isTypeX(t => t.toBasetype().ty == Tclass &&
- (cast(TypeClass)t.toBasetype()).sym.isAbstract());
+ return isTypeX(t => t.toBasetype().isTypeClass() &&
+ t.toBasetype().isTypeClass().sym.isAbstract());
}
if (e.ident == Id.isFinalClass)
{
- return isTypeX(t => t.toBasetype().ty == Tclass &&
- ((cast(TypeClass)t.toBasetype()).sym.storage_class & STC.final_) != 0);
+ return isTypeX(t => t.toBasetype().isTypeClass() &&
+ (t.toBasetype().isTypeClass().sym.storage_class & STC.final_) != 0);
}
if (e.ident == Id.isTemplate)
{
@@ -508,7 +516,8 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
Type tb = t.baseElemOf();
- if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
+ auto ts = tb.isTypeStruct();
+ if (auto sd = ts ? ts.sym : null)
{
return sd.isPOD() ? True() : False();
}
@@ -529,7 +538,8 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
Type tb = t.baseElemOf();
- if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
+ auto ts = tb.isTypeStruct();
+ if (auto sd = ts ? ts.sym : null)
{
return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False())
: (sd.hasCopyCtor ? True() : False());
@@ -793,10 +803,10 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
{
if (auto p = s.toParent()) // `C`'s parent is `C!2`, believe it or not
{
- if (p.isTemplateInstance()) // `C!2` is a template instance
+ if (auto ti = p.isTemplateInstance()) // `C!2` is a template instance
{
s = p; // `C!2`'s parent is `T1`
- auto td = (cast(TemplateInstance)p).tempdecl;
+ auto td = ti.tempdecl;
if (td)
s = td; // get the declaration context just in case there's two contexts
}
@@ -1297,7 +1307,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
if (fd && fd.parent && fd.parent.isTemplateInstance)
{
fd.functionSemantic3();
- tf = cast(TypeFunction)fd.type;
+ tf = fd.type.isTypeFunction();
}
auto mods = new Expressions();
@@ -1738,9 +1748,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
ex = ex.expressionSemantic(sc2);
ex = resolvePropertiesOnly(sc2, ex);
ex = ex.optimize(WANTvalue);
- if (sc2.func && sc2.func.type.ty == Tfunction)
+ if (sc2.func && sc2.func.type.isTypeFunction())
{
- const tf = cast(TypeFunction)sc2.func.type;
+ const tf = sc2.func.type.isTypeFunction();
err |= tf.isnothrow && canThrow(ex, sc2.func, null);
}
ex = checkGC(sc2, ex);
@@ -1868,7 +1878,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
if (e.ident == Id.getPointerBitmap)
{
- return pointerBitmap(e);
+ return pointerBitmap(e, global.errorSink);
}
if (e.ident == Id.initSymbol)
{
@@ -1099,7 +1099,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
if (isRefOrOut && !isAuto &&
!(global.params.previewIn && (fparam.storageClass & STC.in_)) &&
global.params.rvalueRefParam != FeatureState.enabled)
- e = e.toLvalue(sc);
+ e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from");
fparam.defaultArg = e;
return (e.op != EXP.error);
@@ -20,7 +20,6 @@ public:
DebugSymbol *syntaxCopy(Dsymbol *) override;
const char *toChars() const override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
const char *kind() const override;
DebugSymbol *isDebugSymbol() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -34,7 +33,6 @@ public:
VersionSymbol *syntaxCopy(Dsymbol *) override;
const char *toChars() const override;
- void addMember(Scope *sc, ScopeDsymbol *sds) override;
const char *kind() const override;
VersionSymbol *isVersionSymbol() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -176,6 +176,7 @@ class NewDeclaration;
class Initializer;
class VoidInitializer;
+class DefaultInitializer;
class ErrorInitializer;
class StructInitializer;
class ArrayInitializer;
@@ -591,6 +592,7 @@ public:
virtual void visit(StructInitializer *i) { visit((Initializer *)i); }
virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); }
virtual void visit(VoidInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(DefaultInitializer *i) { visit((Initializer *)i); }
virtual void visit(CInitializer *i) { visit((Initializer *)i); }
};
@@ -789,42 +789,58 @@ public:
void visit (CatAssignExp *e) final override
{
+ if (!global.params.useGC)
+ {
+ error_at (make_location_t (e->loc),
+ "appending to array in %qs requires the GC and cannot be "
+ "used with %<-fno-druntime%>", e->toChars ());
+ this->result_ = error_mark_node;
+ return;
+ }
+
Type *tb1 = e->e1->type->toBasetype ();
Type *tb2 = e->e2->type->toBasetype ();
- Type *etype = tb1->nextOf ()->toBasetype ();
-
- /* Save the address of `e1', so it can be evaluated first.
- As all D run-time library functions for concat assignments update `e1'
- in-place and then return its value, the saved address can also be used as
- the result of this expression as well. */
- tree lhs = build_expr (e->e1);
- tree lexpr = stabilize_expr (&lhs);
- tree ptr = d_save_expr (build_address (lhs));
- tree result = NULL_TREE;
- if (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar
- && (etype->ty == TY::Tchar || etype->ty == TY::Twchar))
+ if (e->op == EXP::concatenateDcharAssign)
{
/* Append a dchar to a char[] or wchar[]:
The assignment is handled by the D run-time library, so only
need to call `_d_arrayappend[cw]d(&e1, e2)' */
+ Type *etype = tb1->nextOf ()->toBasetype ();
+
+ /* Save the address of `e1', so it can be evaluated first.
+ As all D run-time library functions for concat assignments update
+ `e1' in-place and then return its value, the saved address can also
+ be used as the result of this expression as well. */
+ tree lhs = build_expr (e->e1);
+ tree lexpr = stabilize_expr (&lhs);
+ tree ptr = d_save_expr (build_address (lhs));
+ tree result = NULL_TREE;
+
+ gcc_assert (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar
+ && (etype->ty == TY::Tchar || etype->ty == TY::Twchar));
+
libcall_fn libcall = (etype->ty == TY::Tchar)
? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD;
result = build_libcall (libcall, e->type, 2,
ptr, build_expr (e->e2));
+
+ /* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr; */
+ result = compound_expr (compound_expr (lexpr, ptr), result);
+ this->result_ = compound_expr (result, build_deref (ptr));
}
else
{
+ gcc_assert (e->op == EXP::concatenateAssign
+ || e->op == EXP::concatenateElemAssign);
+ gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray);
/* Appending an element or array to another array has already been
handled by the front-end. */
- gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray);
- gcc_unreachable ();
- }
+ gcc_assert (e->lowering);
- /* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr; */
- result = compound_expr (compound_expr (lexpr, ptr), result);
- this->result_ = compound_expr (result, build_deref (ptr));
+ this->result_ = build_expr (e->lowering);
+ }
}
/* Build an assignment expression. The right operand is implicitly
@@ -2359,50 +2375,9 @@ public:
/* Allocating memory for a new D array. */
gcc_assert (e->arguments && e->arguments->length >= 1);
- if (e->arguments->length == 1)
- {
- /* Single dimension array allocations has already been handled by
- the front-end. */
- gcc_assert (e->lowering);
- result = build_expr (e->lowering);
- }
- else
- {
- /* Multidimensional array allocations. */
- tree tarray = make_array_type (Type::tsize_t, e->arguments->length);
- tree var = build_local_temp (tarray);
- vec <constructor_elt, va_gc> *elms = NULL;
-
- /* Get the base element type for the array, generating the
- initializer for the dims parameter along the way. */
- Type *telem = e->newtype->toBasetype ();
- for (size_t i = 0; i < e->arguments->length; i++)
- {
- Expression *arg = (*e->arguments)[i];
- CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg));
-
- gcc_assert (telem->ty == TY::Tarray);
- telem = telem->toBasetype ()->nextOf ();
- gcc_assert (telem);
- }
-
- /* Initialize the temporary. */
- tree init = modify_expr (var, build_constructor (tarray, elms));
- var = compound_expr (init, var);
-
- /* Generate: _d_newarraymTX(ti, dims)
- or: _d_newarraymiTX(ti, dims) */
- libcall_fn libcall = telem->isZeroInit ()
- ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX;
-
- tree tinfo = build_typeinfo (e, e->type);
- tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()),
- size_int (e->arguments->length),
- build_address (var));
-
- result = build_libcall (libcall, e->newtype->toBasetype (), 2,
- tinfo, dims);
- }
+ /* Array allocations have already been handled by the front-end. */
+ gcc_assert (e->lowering != NULL);
+ result = build_expr (e->lowering);
if (e->argprefix)
result = compound_expr (build_expr (e->argprefix), result);
@@ -70,13 +70,6 @@ DEF_D_RUNTIME (DYNAMIC_CAST, "_d_dynamic_cast", RT(OBJECT),
DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT),
P2(OBJECT, CLASSINFO), 0)
-/* Used when calling `new' on a multi-dimensional array.
- The `i' variant is for when the initializer is nonzero. */
-DEF_D_RUNTIME (NEWARRAYMTX, "_d_newarraymTX", RT(ARRAY_VOID),
- P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0)
-DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID),
- P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0)
-
/* Used for allocating an array literal on the GC heap. */
DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR),
P2(CONST_TYPEINFO, SIZE_T), 0)
@@ -58,7 +58,7 @@ void semantic1()
void semantic2a(X...)(X expr)
{
alias X[0] var1;
- asm { "%0" : "=m" (var1); } // { dg-error "double' is a 'double' definition and cannot be modified" }
+ asm { "%0" : "=m" (var1); } // { dg-error "cannot modify type 'double'" }
}
void semantic2()
@@ -1,3 +1,4 @@
+// function type aliases
module issue16020;
alias F1 = const(int)(); const(int) f1(){return 42;}
@@ -36,4 +37,8 @@ alias Specialized = FunTemplate!int;
alias Compared = void(int);
static assert(is(Specialized == Compared));
-void main() {}
+// type suffixes
+alias FT = const(int)*();
+static assert(is(FT* == const(int)* function()));
+alias FT2 = int*[2]() pure;
+static assert(is(FT2* == int*[2] function() pure));
@@ -119,3 +119,12 @@ void f(bool cond, string s) @nogc {
alias Unused2 = typeof(&inner); // (Does not) INFERS GC (anymore)
enum Unused3 = __traits(compiles , &inner);
}
+
+// https://issues.dlang.org/show_bug.cgi?id=24072
+
+version (D_SIMD) void f24072() @nogc
+{
+ alias int4 = __vector(int[4]);
+ int4 b = cast(int4)[1, 2, 3, 4];
+ int4 c = cast(int4)[1, 2];
+}
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/b20011.d(25): Error: `S1(cast(ubyte)0u).member` is not an lvalue and cannot be modified
-fail_compilation/b20011.d(28): Error: `S2(null).member` is not an lvalue and cannot be modified
-fail_compilation/b20011.d(29): Error: `S2(null).member` is not an lvalue and cannot be modified
-fail_compilation/b20011.d(32): Error: `U1(cast(ubyte)0u, ).m2` is not an lvalue and cannot be modified
+fail_compilation/b20011.d(25): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue
+fail_compilation/b20011.d(28): Error: cannot modify expression `S2(null).member` because it is not an lvalue
+fail_compilation/b20011.d(29): Error: cannot modify expression `S2(null).member` because it is not an lvalue
+fail_compilation/b20011.d(32): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue
fail_compilation/b20011.d(37): Error: function `b20011.main.assignableByRef(ref ubyte p)` is not callable using argument types `(ubyte)`
fail_compilation/b20011.d(37): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p`
fail_compilation/b20011.d(38): Error: function `b20011.main.assignableByOut(out ubyte p)` is not callable using argument types `(ubyte)`
new file mode 100644
@@ -0,0 +1,26 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/const_ctor.d(23): Error: `const` copy constructor `const_ctor.S1.this` cannot construct a mutable object
+fail_compilation/const_ctor.d(25): Error: `const` constructor `const_ctor.S2.this` cannot construct a mutable object
+---
+*/
+
+struct S1
+{
+ this(ref const S1 s) const {}
+ int* i;
+}
+struct S2
+{
+ this(int) const {}
+ int* i;
+}
+
+void main()
+{
+ const(S1) s1;
+ S1 m1 = s1;
+
+ S2 s2 = S2(5);
+}
new file mode 100644
@@ -0,0 +1,29 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ctor_attr.d(26): Error: none of the overloads of `this` can construct a mutable object with argument types `(int)`
+fail_compilation/ctor_attr.d(16): Candidates are: `ctor_attr.S.this(int x) const`
+fail_compilation/ctor_attr.d(18): `ctor_attr.S.this(string x)`
+fail_compilation/ctor_attr.d(17): `this()(int x) shared`
+fail_compilation/ctor_attr.d(28): Error: none of the overloads of `foo` are callable using a mutable object with argument types `(int)`
+fail_compilation/ctor_attr.d(20): Candidates are: `ctor_attr.S.foo(int x) immutable`
+fail_compilation/ctor_attr.d(21): `ctor_attr.S.foo(string x)`
+---
+*/
+
+struct S
+{
+ this(int x) const {}
+ this()(int x) shared {}
+ this(string x) {}
+
+ void foo(int x) immutable {}
+ void foo(string x) {}
+}
+
+void f()
+{
+ auto s = S(1);
+ S t;
+ t.foo(1);
+}
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/diag10415.d(36): Error: none of the overloads of `x` are callable using argument types `(int) const`
-fail_compilation/diag10415.d(13): Candidates are: `diag10415.C.x()`
+fail_compilation/diag10415.d(13): Candidates are: `diag10415.C.x() const`
fail_compilation/diag10415.d(18): `diag10415.C.x(int __param_0)`
fail_compilation/diag10415.d(39): Error: d.x is not an lvalue
---
@@ -26,10 +26,10 @@ fail_compilation/diag10862.d-mixin-78(78): Error: assignment cannot be used as a
fail_compilation/diag10862.d-mixin-79(79): Error: assignment cannot be used as a condition, perhaps `==` was meant?
fail_compilation/diag10862.d-mixin-80(80): Error: using the result of a comma expression is not allowed
fail_compilation/diag10862.d-mixin-80(80): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d-mixin-83(83): Error: `a + b` is not an lvalue and cannot be modified
+fail_compilation/diag10862.d-mixin-83(83): Error: cannot modify expression `a + b` because it is not an lvalue
fail_compilation/diag10862.d-mixin-84(84): Error: undefined identifier `c`
fail_compilation/diag10862.d(86): Error: undefined identifier `semanticError`
-fail_compilation/diag10862.d(93): Error: lazy variable `bar` cannot be modified
+fail_compilation/diag10862.d(93): Error: cannot modify lazy variable `bar`
fail_compilation/diag10862.d(95): Error: template instance `diag10862.test3.foo!int` error instantiating
---
*/
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10926.d(11): Error: `cast(const(int)[])c` is not an lvalue and cannot be modified
+fail_compilation/diag10926.d(11): Error: cannot modify expression `cast(const(int)[])c` because it is not an lvalue
---
*/
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag14102.d(14): Error: `-x` is not an lvalue and cannot be modified
-fail_compilation/diag14102.d(15): Error: `-(x -= 1)` is not an lvalue and cannot be modified
-fail_compilation/diag14102.d(16): Error: `-(x -= 1 -= 1)` is not an lvalue and cannot be modified
-fail_compilation/diag14102.d(17): Error: `-(x -= 1 -= 1 -= 1)` is not an lvalue and cannot be modified
+fail_compilation/diag14102.d(14): Error: cannot modify expression `-x` because it is not an lvalue
+fail_compilation/diag14102.d(15): Error: cannot modify expression `-(x -= 1)` because it is not an lvalue
+fail_compilation/diag14102.d(16): Error: cannot modify expression `-(x -= 1 -= 1)` because it is not an lvalue
+fail_compilation/diag14102.d(17): Error: cannot modify expression `-(x -= 1 -= 1 -= 1)` because it is not an lvalue
---
*/
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified
+fail_compilation/diag4596.d(15): Error: cannot modify expression `this` because it is not an lvalue
fail_compilation/diag4596.d(16): Error: conditional expression `1 ? this : this` is not a modifiable lvalue
-fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified
+fail_compilation/diag4596.d(18): Error: cannot modify expression `super` because it is not an lvalue
fail_compilation/diag4596.d(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue
---
*/
@@ -6,7 +6,7 @@ fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int __
fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int __param_0, int __param_1)`
fail_compilation/diag8101b.d(30): Error: function `diag8101b.S.bar(int __param_0)` is not callable using argument types `(double)`
fail_compilation/diag8101b.d(30): cannot pass argument `1.0` of type `double` to parameter `int __param_0`
-fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object
+fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object with argument types `(int)`
fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int __param_0)`
fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int __param_0, int __param_1)`
fail_compilation/diag8101b.d(35): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object
deleted file mode 100644
@@ -1,56 +0,0 @@
-/*
-REQUIRED_ARGS: -de
-TEST_OUTPUT:
----
-fail_compilation/dip1000_deprecation.d(17): Deprecation: `@safe` function `main` calling `inferred`
-fail_compilation/dip1000_deprecation.d(25): which wouldn't be `@safe` because of:
-fail_compilation/dip1000_deprecation.d(25): scope variable `x0` may not be returned
-fail_compilation/dip1000_deprecation.d(19): Deprecation: `@safe` function `main` calling `inferredC`
-fail_compilation/dip1000_deprecation.d(36): which calls `dip1000_deprecation.inferred`
-fail_compilation/dip1000_deprecation.d(25): which wouldn't be `@safe` because of:
-fail_compilation/dip1000_deprecation.d(25): scope variable `x0` may not be returned
----
-*/
-
-void main() @safe
-{
- cast(void)inferred();
- cast(void)inferredB(); // no deprecation, trusted
- cast(void)inferredC(); // nested deprecation
-}
-
-auto inferred()
-{
- scope int* x0;
- return x0;
-}
-
-auto inferredB() @trusted
-{
- scope int* x1;
- return x1;
-}
-
-auto inferredC()
-{
- return inferred(); // no deprecation, inferredC is not explicit `@safe`
-}
-
-@safe:
-
-struct S
-{
- int* ptr;
- int* incorrectReturnRef() scope return @trusted {return ptr;}
-}
-
-S createS() { return S.init; }
-
-int* escape(int i)
-{
- if (i) return S().incorrectReturnRef();
- if (i) return createS().incorrectReturnRef();
-
- S s;
- return s.incorrectReturnRef();
-}
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10299.d(11): Error: `foo!string` is not an lvalue and cannot be modified
+fail_compilation/fail10299.d(11): Error: cannot take address of expression `foo!string` because it is not an lvalue
---
*/
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified
-fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified
+fail_compilation/fail13116.d(14): Error: cannot `ref` return expression `this` because it is not an lvalue
+fail_compilation/fail13116.d(23): Error: cannot `ref` return expression `super` because it is not an lvalue
---
*/
struct S
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13336a.d(28): Error: `choose(true)` is not an lvalue and cannot be modified
+fail_compilation/fail13336a.d(28): Error: cannot modify expression `choose(true)` because it is not an lvalue
---
*/
@@ -6,8 +6,8 @@ double sy;
/*
TEST_OUTPUT:
---
-fail_compilation/fail13336b.d(16): Error: `cast(double)sx` is not an lvalue and cannot be modified
-fail_compilation/fail13336b.d(24): Error: `cast(double)sx` is not an lvalue and cannot be modified
+fail_compilation/fail13336b.d(16): Error: cannot `ref` return expression `cast(double)sx` because it is not an lvalue
+fail_compilation/fail13336b.d(24): Error: cannot `ref` return expression `cast(double)sx` because it is not an lvalue
---
*/
ref f1(bool f)
@@ -1,13 +1,13 @@
/* TEST_OUTPUT:
---
-fail_compilation/fail17491.d(22): Error: `(S17491).init` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(23): Error: `S17491(0)` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(25): Error: `S17491(0).field` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(26): Error: `S17491(0).field` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(31): Error: `S17491(0)` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(32): Error: `S17491(0)` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(34): Error: `S17491(0).field` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(35): Error: `S17491(0).field` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(22): Error: cannot modify expression `(S17491).init` because it is not an lvalue
+fail_compilation/fail17491.d(23): Error: cannot take address of expression `S17491(0)` because it is not an lvalue
+fail_compilation/fail17491.d(25): Error: cannot modify expression `S17491(0).field` because it is not an lvalue
+fail_compilation/fail17491.d(26): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue
+fail_compilation/fail17491.d(31): Error: cannot modify expression `S17491(0)` because it is not an lvalue
+fail_compilation/fail17491.d(32): Error: cannot take address of expression `S17491(0)` because it is not an lvalue
+fail_compilation/fail17491.d(34): Error: cannot modify expression `S17491(0).field` because it is not an lvalue
+fail_compilation/fail17491.d(35): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue
---
*/
// https://issues.dlang.org/show_bug.cgi?id=17491
@@ -1,16 +1,12 @@
/+ TEST_OUTPUT:
---
-fail_compilation/fail21243.d(16): Error: found `(` when expecting `ref` and function literal following `auto`
-fail_compilation/fail21243.d(16): Error: semicolon expected following auto declaration, not `int`
-fail_compilation/fail21243.d(16): Error: semicolon needed to end declaration of `x` instead of `)`
-fail_compilation/fail21243.d(16): Error: declaration expected, not `)`
-fail_compilation/fail21243.d(17): Error: `auto` can only be used as part of `auto ref` for function literal return values
-fail_compilation/fail21243.d(18): Error: basic type expected, not `(`
-fail_compilation/fail21243.d(18): Error: function declaration without return type. (Note that constructors are always named `this`)
-fail_compilation/fail21243.d(18): Deprecation: storage class `auto` has no effect in type aliases
-fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration, not `=>`
-fail_compilation/fail21243.d(18): Error: declaration expected, not `=>`
-fail_compilation/fail21243.d(19): Error: `auto` can only be used as part of `auto ref` for function literal return values
+fail_compilation/fail21243.d(12): Error: found `(` when expecting `ref` and function literal following `auto`
+fail_compilation/fail21243.d(12): Error: semicolon expected following auto declaration, not `int`
+fail_compilation/fail21243.d(12): Error: semicolon needed to end declaration of `x` instead of `)`
+fail_compilation/fail21243.d(12): Error: declaration expected, not `)`
+fail_compilation/fail21243.d(13): Error: `auto` can only be used as part of `auto ref` for function literal return values
+fail_compilation/fail21243.d(14): Error: `auto` can only be used as part of `auto ref` for function literal return values
+fail_compilation/fail21243.d(15): Error: `auto` can only be used as part of `auto ref` for function literal return values
---
+/
auto a = auto (int x) => x;
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail217.d(22): Error: mutable method `fail217.Message.this` is not callable using a `immutable` object
+fail_compilation/fail217.d(22): Error: mutable constructor `fail217.Message.this` cannot construct a `immutable` object
fail_compilation/fail217.d(13): Consider adding `const` or `inout` here
---
*/
new file mode 100644
@@ -0,0 +1,22 @@
+/+
+TEST_OUTPUT:
+---
+fail_compilation/fail24224.d(19): Error: struct / class type expected as argument to __traits(initSymbol) instead of `ES`
+fail_compilation/fail24224.d(20): Error: struct / class type expected as argument to __traits(initSymbol) instead of `EU`
+fail_compilation/fail24224.d(21): Error: struct / class type expected as argument to __traits(initSymbol) instead of `EC`
+---
++/
+struct S {}
+union U {}
+class C {}
+
+enum ES : S { a = S.init }
+enum EU : U { a = U.init }
+enum EC : C { a = C.init }
+
+void test()
+{
+ auto init1 = __traits(initSymbol, ES);
+ auto init2 = __traits(initSymbol, EU);
+ auto init3 = __traits(initSymbol, EC);
+}
@@ -2,12 +2,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail6795.d(19): Error: `[0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(20): Error: `[0:0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(22): Error: `[0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(23): Error: `[0:0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(25): Error: `[0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(26): Error: `[0:0][0]` is not an lvalue and cannot be modified
+fail_compilation/fail6795.d(19): Error: cannot modify expression `[0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(20): Error: cannot modify expression `[0:0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(22): Error: cannot modify expression `[0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(23): Error: cannot modify expression `[0:0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(25): Error: cannot take address of expression `[0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(26): Error: cannot take address of expression `[0:0][0]` because it is not an lvalue
---
*/
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7424d.d(10): Error: template `this.g()()` has no value
+fail_compilation/fail7424d.d(10): Error: template `this.g()() immutable` has no value
---
*/
struct S7424d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7424e.d(10): Error: template `this.g()()` has no value
+fail_compilation/fail7424e.d(10): Error: template `this.g()() immutable` has no value
---
*/
struct S7424e
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7424f.d(10): Error: template `this.g()()` has no value
+fail_compilation/fail7424f.d(10): Error: template `this.g()() shared` has no value
---
*/
struct S7424f
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7424i.d(10): Error: template `this.g()()` has no value
+fail_compilation/fail7424i.d(10): Error: template `this.g()() immutable` has no value
---
*/
struct S7424g
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7603a.d(7): Error: cannot modify constant `true`
+fail_compilation/fail7603a.d(7): Error: cannot create default argument for `ref` / `out` parameter from constant `true`
---
*/
void test(ref bool val = true) { }
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7603b.d(7): Error: cannot modify constant `true`
+fail_compilation/fail7603b.d(7): Error: cannot create default argument for `ref` / `out` parameter from constant `true`
---
*/
void test(out bool val = true) { }
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7603c.d(8): Error: cannot modify constant `3`
+fail_compilation/fail7603c.d(8): Error: cannot create default argument for `ref` / `out` parameter from constant `3`
---
*/
enum x = 3;
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9537.d(26): Error: `foo(tuple(1, 2))` is not an lvalue and cannot be modified
+fail_compilation/fail9537.d(26): Error: cannot take address of expression `foo(tuple(1, 2))` because it is not an lvalue
---
*/
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9773.d(7): Error: `""` is not an lvalue and cannot be modified
+fail_compilation/fail9773.d(7): Error: cannot create default argument for `ref` / `out` parameter from expression `""` because it is not an lvalue
---
*/
void f(ref string a = "")
@@ -3,7 +3,7 @@ TEST_OUTPUT:
---
fail_compilation/fail9891.d(13): Error: expression `i` of type `immutable(int)` is not implicitly convertible to type `ref int` of parameter `n`
fail_compilation/fail9891.d(18): Error: expression `i` of type `immutable(int)` is not implicitly convertible to type `out int` of parameter `n`
-fail_compilation/fail9891.d(23): Error: `prop()` is not an lvalue and cannot be modified
+fail_compilation/fail9891.d(23): Error: cannot create default argument for `ref` / `out` parameter from expression `prop()` because it is not an lvalue
---
*/
@@ -207,21 +207,21 @@ fail_compilation/fail_arrayop2.d(265): Error: array operation `[1] * 6` without
fail_compilation/fail_arrayop2.d(268): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'` without destination memory not allowed
fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(275): Error: `([1] * 6)[0..2]` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(275): Error: cannot take address of expression `([1] * 6)[0..2]` because it is not an lvalue
fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]`
fail_compilation/fail_arrayop2.d(281): Error: the `delete` keyword is obsolete
fail_compilation/fail_arrayop2.d(281): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(290): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(290): Error: cannot modify expression `[1] * 6` because it is not an lvalue
fail_compilation/fail_arrayop2.d(291): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(294): Error: `[1] * 6` is not an lvalue and cannot be modified
-fail_compilation/fail_arrayop2.d(295): Error: `([1] * 6)[]` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(294): Error: cannot modify expression `[1] * 6` because it is not an lvalue
+fail_compilation/fail_arrayop2.d(295): Error: cannot modify expression `([1] * 6)[]` because it is not an lvalue
fail_compilation/fail_arrayop2.d(298): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(299): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(300): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(303): Error: `[1] * 6` is not an lvalue and cannot be modified
-fail_compilation/fail_arrayop2.d(304): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(303): Error: cannot modify expression `[1] * 6` because it is not an lvalue
+fail_compilation/fail_arrayop2.d(304): Error: cannot modify expression `[1] * 6` because it is not an lvalue
fail_compilation/fail_arrayop2.d(307): Error: `[1] * 6` is not of integral type, it is a `int[]`
fail_compilation/fail_arrayop2.d(308): Error: `[1] * 6` is not of integral type, it is a `int[]`
fail_compilation/fail_arrayop2.d(309): Error: `[1] * 6` is not of integral type, it is a `int[]`
@@ -1,10 +1,6 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail_scope.d(28): Deprecation: scope parameter `da` may not be returned
-fail_compilation/fail_scope.d(30): Deprecation: scope parameter `o` may not be returned
-fail_compilation/fail_scope.d(31): Deprecation: scope parameter `dg` may not be returned
-fail_compilation/fail_scope.d(38): Deprecation: scope parameter `p` may not be returned
fail_compilation/fail_scope.d(43): Error: returning `cast(char[])string` escapes a reference to local variable `string`
fail_compilation/fail_scope.d(61): Error: returning `s.bar()` escapes a reference to local variable `s`
fail_compilation/fail_scope.d(72): Error: `fail_scope.foo8` called with argument types `(int)` matches both:
@@ -23,6 +19,10 @@ fail_compilation/fail_scope.d(135): Error: returning `foo16226(i)` escapes a ref
//fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned
*/
+
+
+
+
alias int delegate() dg_t;
int[] checkEscapeScope1(scope int[] da) { return da; }
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10419.d(12): Error: `arr().length` is not an lvalue and cannot be modified
+fail_compilation/ice10419.d(12): Error: cannot modify expression `arr().length` because it is not an lvalue
---
*/
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12841.d(23): Error: `taskPool().amap(Args...)(Args args)` is not an lvalue and cannot be modified
-fail_compilation/ice12841.d(24): Error: `amap(Args...)(Args args)` is not an lvalue and cannot be modified
+fail_compilation/ice12841.d(23): Error: cannot take address of expression `taskPool().amap(Args...)(Args args)` because it is not an lvalue
+fail_compilation/ice12841.d(24): Error: cannot take address of template `amap(Args...)(Args args)`, perhaps instantiate it first
---
*/
@@ -3,7 +3,7 @@ TEST_OUTPUT:
---
fail_compilation/ice13459.d(12): Error: undefined identifier `B`
fail_compilation/ice13459.d(18): Error: none of the overloads of `opSlice` are callable using argument types `(int, int)`
-fail_compilation/ice13459.d(11): Candidate is: `ice13459.A.opSlice()`
+fail_compilation/ice13459.d(11): Candidate is: `ice13459.A.opSlice() const`
---
*/
struct A
@@ -2,7 +2,7 @@
DISABLED: freebsd32 linux32 osx32 win32
TEST_OUTPUT:
---
-fail_compilation/ice20264.d(12): Error: `cast(__vector(float[4]))a` is not an lvalue and cannot be modified
+fail_compilation/ice20264.d(12): Error: cannot modify expression `cast(__vector(float[4]))a` because it is not an lvalue
---
*/
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` is not callable using argument types `!()(int)`
-fail_compilation/ice9284.d(12): Candidate is: `__ctor()(string)`
+fail_compilation/ice9284.d(12): Candidate is: `this()(string)`
fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating
---
*/
new file mode 100644
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/immutable_ctor.d(18): Error: `immutable` copy constructor `immutable_ctor.S1.this` cannot construct a mutable object
+---
+*/
+
+struct S1
+{
+ this(ref const S1 s) immutable {
+ }
+ int i;
+}
+
+void main()
+{
+ const(S1) s1;
+ S1 ms1 = s1;
+}
@@ -1,9 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/issue16020.d(12): Error: user-defined attributes not allowed for `alias` declarations
-fail_compilation/issue16020.d(13): Error: semicolon expected to close `alias` declaration, not `(`
-fail_compilation/issue16020.d(13): Error: declaration expected, not `(`
+fail_compilation/issue16020.d(13): Error: user-defined attributes not allowed for `alias` declarations
+fail_compilation/issue16020.d(14): Error: semicolon expected to close `alias` declaration, not `(`
+fail_compilation/issue16020.d(14): Error: declaration expected, not `(`
+fail_compilation/issue16020.d(15): Deprecation: storage class `final` has no effect in type aliases
---
*/
module issue16020;
@@ -11,3 +12,4 @@ module issue16020;
struct UDA{}
alias Fun = @UDA void();
alias FunTemplate = void(T)(T t);
+alias F2 = final int();
@@ -1,12 +1,12 @@
/* TEST_OUTPUT:
---
-fail_compilation/issue20704.d(17): Error: cannot modify constant `0`
+fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from constant `0`
fail_compilation/issue20704.d(28): Error: template instance `issue20704.f2!int` error instantiating
-fail_compilation/issue20704.d(19): Error: cannot modify constant `0`
+fail_compilation/issue20704.d(19): Error: cannot create default argument for `ref` / `out` parameter from constant `0`
fail_compilation/issue20704.d(30): Error: template instance `issue20704.f4!int` error instantiating
-fail_compilation/issue20704.d(17): Error: `S(0)` is not an lvalue and cannot be modified
+fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from expression `S(0)` because it is not an lvalue
fail_compilation/issue20704.d(36): Error: template instance `issue20704.f2!(S)` error instantiating
-fail_compilation/issue20704.d(17): Error: `null` is not an lvalue and cannot be modified
+fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from expression `null` because it is not an lvalue
fail_compilation/issue20704.d(38): Error: template instance `issue20704.f2!(C)` error instantiating
---
*/
@@ -2,7 +2,7 @@
REQUIRED_ARGS: -m64
TEST_OUTPUT:
---
-fail_compilation/test16381.d(15): Error: `foo()` is not an lvalue and cannot be modified
+fail_compilation/test16381.d(15): Error: cannot take address of expression `foo()` because it is not an lvalue
---
*/
@@ -3,7 +3,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test22048.d(10): Error: unexpected identifier `p` in declarator
+fail_compilation/test22048.d(10): Error: unexpected identifier `p` after `int`
---
*/
@@ -3,8 +3,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test24157.d(23): Error: `p.self()` is not an lvalue and cannot be modified
-fail_compilation/test24157.d(27): Error: `p.unshared()` is not an lvalue and cannot be modified
+fail_compilation/test24157.d(23): Error: cannot take address of expression `p.self()` because it is not an lvalue
+fail_compilation/test24157.d(27): Error: cannot take address of expression `p.unshared()` because it is not an lvalue
---
*/
new file mode 100644
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=24159
+// REQUIRED_ARGS: -betterC
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test24159.d(13): Error: appending to array in `x ~= 3` requires the GC which is not available with -betterC
+---
+*/
+
+extern(C) void main()
+{
+ int[] x = null;
+ x ~= 3;
+}
@@ -5,9 +5,9 @@ TEST_OUTPUT:
---
fail_compilation/testrvaluecpctor.d(16): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo`
fail_compilation/testrvaluecpctor.d(24): Template instance `testrvaluecpctor.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` creates an rvalue constructor for `struct Foo`
-fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `__ctor` are callable using a `immutable` object
+fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `this` can construct a `immutable` object with argument types `(immutable(Foo!int))`
fail_compilation/testrvaluecpctor.d(18): Candidates are: `testrvaluecpctor.Foo!int.Foo.this(ref scope Foo!int rhs)`
-fail_compilation/testrvaluecpctor.d(16): `__ctor(Rhs, this This)(scope Rhs rhs)`
+fail_compilation/testrvaluecpctor.d(16): `this(Rhs, this This)(scope Rhs rhs)`
---
*/
new file mode 100644
@@ -0,0 +1,48 @@
+/**
+TEST_OUTPUT:
+---
+fail_compilation/tolvalue.d(28): Error: cannot take address of template `templateFunc(T)()`, perhaps instantiate it first
+fail_compilation/tolvalue.d(29): Error: cannot take address of type `int`
+fail_compilation/tolvalue.d(30): Error: cannot take address of constant `3`
+fail_compilation/tolvalue.d(31): Error: cannot take address of operator `$`
+fail_compilation/tolvalue.d(32): Error: cannot take address of compiler-generated variable `__ctfe`
+fail_compilation/tolvalue.d(33): Error: cannot take address of manifest constant `f`
+fail_compilation/tolvalue.d(38): Error: cannot create default argument for `ref` / `out` parameter from constant `3`
+fail_compilation/tolvalue.d(39): Error: cannot create default argument for `ref` / `out` parameter from compiler-generated variable `__ctfe`
+fail_compilation/tolvalue.d(40): Error: cannot create default argument for `ref` / `out` parameter from manifest constant `f`
+fail_compilation/tolvalue.d(45): Error: cannot modify constant `3`
+fail_compilation/tolvalue.d(46): Error: cannot modify compiler-generated variable `__ctfe`
+fail_compilation/tolvalue.d(47): Error: cannot modify manifest constant `f`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=24238
+
+void templateFunc(T)() {}
+alias intAlias = int;
+enum E { f }
+
+void addr()
+{
+ int[] a;
+ auto x0 = &templateFunc;
+ auto x1 = &intAlias;
+ auto x2 = &3;
+ auto x3 = a[&$];
+ auto x4 = &__ctfe;
+ auto x6 = &E.f;
+}
+
+void refArg()
+{
+ void f0(ref int = 3) {}
+ void f1(ref bool = __ctfe) {}
+ void f3(ref E = E.f) {}
+}
+
+void inc(int lz)
+{
+ 3++;
+ __ctfe++;
+ E.f++;
+}
new file mode 100644
@@ -0,0 +1,13 @@
+/**
+REQUIRED_ARGS: -m64
+TEST_OUTPUT:
+---
+fail_compilation/vector_cast.d(11): Error: cannot cast expression `a` of type `int[3]` to `__vector(int[4])`
+fail_compilation/vector_cast.d(13): Error: cannot cast expression `a` of type `int[5]` to `__vector(int[4])`
+---
+*/
+
+alias int4 = __vector(int[4]);
+int4 convtest3(int[3] a) { return cast(int4) a; }
+int4 convtest4(int[4] a) { return cast(int4) a; }
+int4 convtest5(int[5] a) { return cast(int4) a; }
@@ -56,7 +56,7 @@ struct Key
{
int v;
bool opEquals(ref const Key o) const { return v == o.v; }
- size_t toHash() const { return v; }
+ size_t toHash() const nothrow { return v; }
}
Destructing[Key] dAa = [Key(1): Destructing(10), Key(2): Destructing(20)];
@@ -142,6 +142,18 @@ void testImmutable()
/////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=24209
+void testLocalStatic() @trusted
+{
+ static int[int] aa0 = [1: 2];
+ __gshared string[string] aa1 = null;
+
+ assert(aa0[1] == 2);
+ assert(aa1.length == 0);
+}
+
+/////////////////////////////////////////////
+
void main()
{
testSimple();
@@ -150,4 +162,5 @@ void main()
testStructInit();
testClassInit();
testImmutable();
+ testLocalStatic();
}
new file mode 100644
@@ -0,0 +1,30 @@
+// https://issues.dlang.org/show_bug.cgi?id=24184
+
+void stage3(alias abc)(ubyte[])
+{
+ bool skipSpaces()
+ {
+ abc();
+ return false;
+ }
+ skipSpaces;
+}
+ubyte[] singleThreadJsonImpl(alias xxx)(ubyte[] table)
+{
+ align(64) ubyte[] vector;
+
+ ubyte[] abc() { return vector; }
+
+ stage3!(abc)(table);
+
+ return table;
+}
+ubyte[] singleThreadJsonText()
+{
+ bool xxx() { return true; }
+
+ return singleThreadJsonImpl!(xxx)([]);
+}
+void deserializeJson() { singleThreadJsonText(); }
+
+void main() { deserializeJson(); }
@@ -1,4 +1,4 @@
-643b1261bba0757d97efa3ff1f63e461271eb000
+ff57fec51558013b25cadb7e83da9f4675915d56
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
@@ -666,10 +666,12 @@ void getAMDcacheinfo()
// to determine number of processors.
void getCpuInfo0B()
{
- int level=0;
int threadsPerCore;
uint a, b, c, d;
- do {
+ // I'm not sure about this. The docs state that there
+ // are 2 hyperthreads per core if HT is factory enabled.
+ for (int level = 0; level < 2; level++)
+ {
version (GNU_OR_LDC) asm pure nothrow @nogc {
"cpuid" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (0x0B), "c" (level);
} else asm pure nothrow @nogc {
@@ -681,19 +683,20 @@ void getCpuInfo0B()
mov c, ECX;
mov d, EDX;
}
- if (b!=0) {
- // I'm not sure about this. The docs state that there
- // are 2 hyperthreads per core if HT is factory enabled.
- if (level==0)
+ if (b != 0)
+ {
+ if (level == 0)
threadsPerCore = b & 0xFFFF;
- else if (level==1) {
+ else if (level == 1)
+ {
cpuFeatures.maxThreads = b & 0xFFFF;
cpuFeatures.maxCores = cpuFeatures.maxThreads / threadsPerCore;
}
-
}
- ++level;
- } while (a!=0 || b!=0);
+ // Got "invalid domain" returned from cpuid
+ if (a == 0 && b == 0)
+ break;
+ }
}
void cpuidX86()
@@ -14,56 +14,55 @@ private extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref return scope
private enum isCopyingNothrow(T) = __traits(compiles, (ref T rhs) nothrow { T lhs = rhs; });
-/// Implementation of `_d_arrayappendcTX` and `_d_arrayappendcTXTrace`
-template _d_arrayappendcTXImpl(Tarr : T[], T)
+/**
+ * Extend an array `px` by `n` elements.
+ * Caller must initialize those elements.
+ * Params:
+ * px = the array that will be extended, taken as a reference
+ * n = how many new elements to extend it with
+ * Returns:
+ * The new value of `px`
+ * Bugs:
+ * This function template was ported from a much older runtime hook that bypassed safety,
+ * purity, and throwabilty checks. To prevent breaking existing code, this function template
+ * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
+ */
+ref Tarr _d_arrayappendcTX(Tarr : T[], T)(return ref scope Tarr px, size_t n) @trusted
{
- private enum errorMessage = "Cannot append to array if compiling without support for runtime type information!";
+ // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718
+ version (DigitalMars) pragma(inline, false);
+ version (D_TypeInfo)
+ {
+ auto ti = typeid(Tarr);
+
+ // _d_arrayappendcTX takes the `px` as a ref byte[], but its length
+ // should still be the original length
+ auto pxx = (cast(byte*)px.ptr)[0 .. px.length];
+ ._d_arrayappendcTX(ti, pxx, n);
+ px = (cast(T*)pxx.ptr)[0 .. pxx.length];
+
+ return px;
+ }
+ else
+ assert(0, "Cannot append to array if compiling without support for runtime type information!");
+}
+version (D_ProfileGC)
+{
/**
- * Extend an array `px` by `n` elements.
- * Caller must initialize those elements.
- * Params:
- * px = the array that will be extended, taken as a reference
- * n = how many new elements to extend it with
- * Returns:
- * The new value of `px`
- * Bugs:
- * This function template was ported from a much older runtime hook that bypassed safety,
- * purity, and throwabilty checks. To prevent breaking existing code, this function template
- * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
+ * TraceGC wrapper around $(REF _d_arrayappendT, core,internal,array,appending).
*/
- ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow
+ ref Tarr _d_arrayappendcTXTrace(Tarr : T[], T)(string file, int line, string funcname, return ref scope Tarr px, size_t n) @trusted
{
- // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718
- version (DigitalMars) pragma(inline, false);
version (D_TypeInfo)
{
- auto ti = typeid(Tarr);
-
- // _d_arrayappendcTX takes the `px` as a ref byte[], but its length
- // should still be the original length
- auto pxx = (cast(byte*)px.ptr)[0 .. px.length];
- ._d_arrayappendcTX(ti, pxx, n);
- px = (cast(T*)pxx.ptr)[0 .. pxx.length];
+ import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
+ mixin(TraceHook!(Tarr.stringof, "_d_arrayappendcTX"));
- return px;
+ return _d_arrayappendcTX(px, n);
}
else
- assert(0, errorMessage);
- }
-
- version (D_ProfileGC)
- {
- import core.internal.array.utils : _d_HookTraceImpl;
-
- /**
- * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl).
- * Bugs:
- * This function template was ported from a much older runtime hook that bypassed safety,
- * purity, and throwabilty checks. To prevent breaking existing code, this function template
- * is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
- */
- alias _d_arrayappendcTXTrace = _d_HookTraceImpl!(Tarr, _d_arrayappendcTX, errorMessage);
+ static assert(0, "Cannot append to array if compiling without support for runtime type information!");
}
}
@@ -78,7 +77,7 @@ ref Tarr _d_arrayappendT(Tarr : T[], T)(return ref scope Tarr x, scope Tarr y) @
enum hasPostblit = __traits(hasPostblit, T);
auto length = x.length;
- _d_arrayappendcTXImpl!Tarr._d_arrayappendcTX(x, y.length);
+ _d_arrayappendcTX(x, y.length);
// Only call `copyEmplace` if `T` has a copy ctor and no postblit.
static if (hasElaborateCopyConstructor!T && !hasPostblit)
@@ -126,7 +125,7 @@ version (D_ProfileGC)
return _d_arrayappendT(x, y);
}
else
- assert(0, "Cannot append to array if compiling without support for runtime type information!");
+ static assert(0, "Cannot append to array if compiling without support for runtime type information!");
}
}
@@ -486,3 +486,111 @@ version (D_ProfileGC)
assert(0, "Cannot create new array if compiling without support for runtime type information!");
}
}
+
+/**
+ * Create a new multi-dimensional array. Also initalize elements if their type has an initializer.
+ * Otherwise, not zero-initialize the array.
+ *
+ * ---
+ * void main()
+ * {
+ * S[][] s = new S[][](2, 3)
+ *
+ * // lowering:
+ * S[] s = _d_newarraymTX!(S[][], S)([2, 3]);
+ * }
+ * ---
+ *
+ * Params:
+ * dims = array length values for each dimension
+ * isShared = whether the array should be shared
+ *
+ * Returns:
+ * newly allocated array
+ */
+Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trusted
+{
+ debug(PRINTF) printf("_d_newarraymTX(dims.length = %d)\n", dims.length);
+
+ if (dims.length == 0)
+ return null;
+
+ alias UnqT = Unqual!(T);
+
+ void[] __allocateInnerArray(size_t[] dims)
+ {
+ import core.internal.array.utils : __arrayStart, __setArrayAllocLength, __arrayAlloc;
+
+ auto dim = dims[0];
+
+ debug(PRINTF) printf("__allocateInnerArray(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length);
+ if (dims.length == 1)
+ {
+ auto r = _d_newarrayT!UnqT(dim, isShared);
+ return *cast(void[]*)(&r);
+ }
+
+ auto allocSize = (void[]).sizeof * dim;
+ auto info = __arrayAlloc!UnqT(allocSize);
+ __setArrayAllocLength!UnqT(info, allocSize, isShared);
+ auto p = __arrayStart(info)[0 .. dim];
+
+ foreach (i; 0..dim)
+ {
+ (cast(void[]*)p.ptr)[i] = __allocateInnerArray(dims[1..$]);
+ }
+ return p;
+ }
+
+ auto result = __allocateInnerArray(dims);
+ debug(PRINTF) printf("result = %llx\n", result.ptr);
+
+ return (cast(U*) result.ptr)[0 .. dims[0]];
+}
+
+unittest
+{
+ int[][] a = _d_newarraymTX!(int[][], int)([2, 3]);
+
+ assert(a.length == 2);
+ for (size_t i = 0; i < a.length; i++)
+ {
+ assert(a[i].length == 3);
+ for (size_t j = 0; j < a[i].length; j++)
+ assert(a[i][j] == 0);
+ }
+}
+
+unittest
+{
+ struct S { int x = 1; }
+
+ S[][] a = _d_newarraymTX!(S[][], S)([2, 3]);
+
+ assert(a.length == 2);
+ for (size_t i = 0; i < a.length; i++)
+ {
+ assert(a[i].length == 3);
+ for (size_t j = 0; j < a[i].length; j++)
+ assert(a[i][j].x == 1);
+ }
+}
+
+version (D_ProfileGC)
+{
+ /**
+ * TraceGC wrapper around $(REF _d_newarraymT, core,internal,array,construction).
+ */
+ Tarr _d_newarraymTXTrace(Tarr : U[], T, U)(string file, int line, string funcname, size_t[] dims, bool isShared=false) @trusted
+ {
+ version (D_TypeInfo)
+ {
+ import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure;
+ mixin(TraceHook!(T.stringof, "_d_newarraymTX"));
+
+ return _d_newarraymTX!(Tarr, T)(dims, isShared);
+ }
+ else
+ assert(0, "Cannot create new multi-dimensional array if compiling without support for runtime type information!");
+ }
+}
@@ -656,7 +656,7 @@ version (DigitalMars)
asm pure nothrow @nogc @trusted
{
naked;
- rep; nop;
+ pause;
ret;
}
}
@@ -665,8 +665,7 @@ version (DigitalMars)
asm pure nothrow @nogc @trusted
{
naked;
- // pause; // TODO: DMD should add this opcode to its inline asm
- rep; nop;
+ pause;
ret;
}
}
@@ -3336,7 +3336,7 @@ Lmark:
busyThreads.atomicOp!"+="(1); // main thread is busy
- evStart.set();
+ evStart.setIfInitialized();
debug(PARALLEL_PRINTF) printf("mark %lld roots\n", cast(ulong)(ptop - pbot));
@@ -3438,7 +3438,7 @@ Lmark:
stopGC = true;
while (atomicLoad(stoppedThreads) < startedThreads && !allThreadsDead)
{
- evStart.set();
+ evStart.setIfInitialized();
evDone.wait(dur!"msecs"(1));
}
@@ -3467,7 +3467,7 @@ Lmark:
{
evStart.wait();
pullFromScanStack();
- evDone.set();
+ evDone.setIfInitialized();
}
stoppedThreads.atomicOp!"+="(1);
}
@@ -50,6 +50,7 @@ struct Impl
immutable uint valsz;
immutable uint valoff;
Flags flags;
+ size_t delegate(scope const void*) nothrow hashFn;
enum Flags : ubyte
{
@@ -76,15 +77,19 @@ private size_t mix(size_t h) @safe pure nothrow @nogc
struct Entry(K, V)
{
- /*const*/ K key; // this really should be const, but legacy issues.
+ // can make this const, because we aren't really going to use it aside from
+ // construction.
+ const K key;
V value;
}
// create a binary-compatible AA structure that can be used directly as an
// associative array.
-AAShell makeAA(K, V)(V[K] src)
+// NOTE: this must only be called during CTFE
+AAShell makeAA(K, V)(V[K] src) @trusted
{
+ assert(__ctfe, "makeAA Must only be called at compile time");
immutable srclen = src.length;
assert(srclen <= uint.max);
alias E = Entry!(K, V);
@@ -96,6 +101,12 @@ AAShell makeAA(K, V)(V[K] src)
while (srclen * GROW_DEN > dim * GROW_NUM)
dim = dim * GROW_FAC;
+ // used during runtime.
+ size_t delegate(scope const void *) nothrow hashFn = (scope const void* val) {
+ auto x = cast(K*)val;
+ return hashOf(*x);
+ };
+
Bucket[] buckets;
// Allocate and fill the buckets
if (__ctfe)
@@ -140,5 +151,19 @@ AAShell makeAA(K, V)(V[K] src)
} ();
// return the new implementation
return AAShell(new Impl(buckets, cast(uint)srclen, 0, typeid(E), firstUsed,
- K.sizeof, V.sizeof, E.value.offsetof, flags));
+ K.sizeof, V.sizeof, E.value.offsetof, flags, hashFn));
+}
+
+unittest
+{
+ static struct Foo
+ {
+ ubyte x;
+ double d;
+ }
+ static int[Foo] utaa = [Foo(1, 2.0) : 5];
+ auto k = Foo(1, 2.0);
+ // verify that getHash doesn't match hashOf for Foo
+ assert(typeid(Foo).getHash(&k) != hashOf(k));
+ assert(utaa[Foo(1, 2.0)] == 5);
}
@@ -797,7 +797,7 @@ else
}
else version (LoongArch64)
{
- // Define bits representing exceptions in the FPSR status word.
+ // Define bits representing exceptions in the Flags field in FCSR{0,2}.
enum
{
FE_INEXACT = 0x010000, ///
@@ -808,13 +808,13 @@ else
FE_ALL_EXCEPT = 0x1f0000, ///
}
- // Define bits representing rounding modes in the FPCR Rmode field.
+ // Define bits representing rounding modes in the RM field in FCSR{0,3}.
enum
{
FE_TONEAREST = 0x000, ///
FE_TOWARDZERO = 0x100, ///
- FE_DOWNWARD = 0x200, ///
- FE_UPWARD = 0x300, ///
+ FE_UPWARD = 0x200, ///
+ FE_DOWNWARD = 0x300, ///
}
}
else
@@ -257,6 +257,12 @@ T va_arg(T)(ref va_list ap)
ap += T.sizeof.alignUp;
return *p;
}
+ else version (LoongArch64)
+ {
+ auto p = cast(T*) ap;
+ ap += T.sizeof.alignUp;
+ return *p;
+ }
else version (MIPS_Any)
{
auto p = cast(T*) ap;
@@ -61,7 +61,7 @@ struct ProcessFile
group.create(&doProcess);
buffer = std.file.read(filename);
- event.set();
+ event.setIfInitialized();
group.joinAll();
event.terminate();
}
@@ -162,9 +162,13 @@ nothrow @nogc:
}
}
+ deprecated ("Use setIfInitialized() instead") void set()
+ {
+ setIfInitialized();
+ }
/// Set the event to "signaled", so that waiting clients are resumed
- void set()
+ void setIfInitialized()
{
version (Windows)
{
@@ -302,7 +306,7 @@ private:
// auto-reset, initial state false
Event ev1 = Event(false, false);
assert(!ev1.wait(1.dur!"msecs"));
- ev1.set();
+ ev1.setIfInitialized();
assert(ev1.wait());
assert(!ev1.wait(1.dur!"msecs"));
@@ -336,7 +340,7 @@ unittest
auto start = MonoTime.currTime;
assert(numRunning == 0);
- event.set();
+ event.setIfInitialized();
group.joinAll();
assert(numRunning == numThreads);
@@ -339,6 +339,8 @@ enum EM_CSKY = 252;
enum EM_NUM = 253;
+enum EM_LOONGARCH = 258;
+
enum EM_ALPHA = 0x9026;
enum EV_NONE = 0;
@@ -13,6 +13,7 @@ extern (C):
version (MIPS32) version = MIPS_Any;
version (MIPS64) version = MIPS_Any;
+version (LoongArch64) version = LoongArch_Any;
version (PPC) version = PPC_Any;
version (PPC64) version = PPC_Any;
version (S390) version = IBMZ_Any;
@@ -156,3 +157,19 @@ else version (IBMZ_Any)
enum HWCAP_S390_TE = 1024;
enum HWCAP_S390_VX = 2048;
}
+else version (LoongArch_Any)
+{
+ enum HWCAP_LOONGARCH_CPUCFG = 0x00000001;
+ enum HWCAP_LOONGARCH_LAM = 0x00000002;
+ enum HWCAP_LOONGARCH_UAL = 0x00000004;
+ enum HWCAP_LOONGARCH_FPU = 0x00000008;
+ enum HWCAP_LOONGARCH_LSX = 0x00000010;
+ enum HWCAP_LOONGARCH_LASX = 0x00000020;
+ enum HWCAP_LOONGARCH_CRC32 = 0x00000040;
+ enum HWCAP_LOONGARCH_COMPLEX = 0x00000080;
+ enum HWCAP_LOONGARCH_CRYPTO = 0x00000100;
+ enum HWCAP_LOONGARCH_LVZ = 0x00000200;
+ enum HWCAP_LOONGARCH_LBT_X86 = 0x00000400;
+ enum HWCAP_LOONGARCH_LBT_ARM = 0x00000800;
+ enum HWCAP_LOONGARCH_LBT_MIPS = 0x00001000;
+}
@@ -432,6 +432,7 @@ else version (MIPS_Any)
MAP_HUGETLB = 0x80000,
}
}
+// http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/bits/mman-map-flags-generic.h
else version (LoongArch64)
{
static if (_DEFAULT_SOURCE) enum
@@ -178,8 +178,12 @@ private
}
else version (LoongArch64)
{
- version = AsmLoongArch64_Posix;
- version = AsmExternal;
+ version (Posix)
+ {
+ version = AsmLoongArch64_Posix;
+ version = AsmExternal;
+ version = AlignFiberStackTo16Byte;
+ }
}
version (Posix)
@@ -1444,24 +1448,28 @@ private:
}
else version (AsmLoongArch64_Posix)
{
+ // Like others, FP registers and return address ($r1) are kept
+ // below the saved stack top (tstack) to hide from GC scanning.
+ // fiber_switchContext expects newp sp to look like this:
+ // 10: $r21 (reserved)
+ // 9: $r22 (frame pointer)
+ // 8: $r23
+ // ...
+ // 0: $r31 <-- newp tstack
+ // -1: $r1 (return address) [&fiber_entryPoint]
+ // -2: $f24
+ // ...
+ // -9: $f31
+
version (StackGrowsDown) {}
- else static assert(0);
+ else
+ static assert(false, "Only full descending stacks supported on LoongArch64");
- // Like others, FP registers and return address (ra) are kept
- // below the saved stack top (tstack) to hide from GC scanning.
- // The newp stack should look like this on LoongArch64:
- // 18: fp <- pstack
- // ...
- // 9: s0 <- newp tstack
- // 8: ra [&fiber_entryPoint]
- // 7: fs7
- // ...
- // 1: fs1
- // 0: fs0
- pstack -= 10 * size_t.sizeof; // skip s0-s8 and fp
- // set $ra
- push( cast(size_t) &fiber_entryPoint );
- pstack += size_t.sizeof;
+ // Only need to set return address ($r1). Everything else is fine
+ // zero initialized.
+ pstack -= size_t.sizeof * 11; // skip past space reserved for $r21-$r31
+ push (cast(size_t) &fiber_entryPoint);
+ pstack += size_t.sizeof; // adjust sp (newp) above lr
}
else version (AsmAArch64_Posix)
{
@@ -129,6 +129,13 @@ void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
ap += tsize.alignUp;
parmn[0..tsize] = p[0..tsize];
}
+ else version (LoongArch64)
+ {
+ const tsize = ti.tsize;
+ auto p = cast(void*) ap;
+ ap += tsize.alignUp;
+ parmn[0..tsize] = p[0..tsize];
+ }
else version (MIPS_Any)
{
const tsize = ti.tsize;
@@ -642,7 +642,8 @@ class TypeInfo
*/
size_t getHash(scope const void* p) @trusted nothrow const
{
- return hashOf(p);
+ // by default, do not assume anything about the type
+ return 0;
}
/// Compares two instances for equality.
@@ -2918,19 +2919,19 @@ alias AssociativeArray(Key, Value) = Value[Key];
* Params:
* aa = The associative array.
*/
-void clear(Value, Key)(Value[Key] aa)
+void clear(Value, Key)(Value[Key] aa) @trusted
{
_aaClear(*cast(AA *) &aa);
}
/** ditto */
-void clear(Value, Key)(Value[Key]* aa)
+void clear(Value, Key)(Value[Key]* aa) @trusted
{
_aaClear(*cast(AA *) aa);
}
///
-@system unittest
+@safe unittest
{
auto aa = ["k1": 2];
aa.clear;
@@ -4666,11 +4667,13 @@ public import core.internal.array.appending : _d_arrayappendT;
version (D_ProfileGC)
{
public import core.internal.array.appending : _d_arrayappendTTrace;
+ public import core.internal.array.appending : _d_arrayappendcTXTrace;
public import core.internal.array.concatenation : _d_arraycatnTXTrace;
public import core.lifetime : _d_newitemTTrace;
public import core.internal.array.construction : _d_newarrayTTrace;
+ public import core.internal.array.construction : _d_newarraymTXTrace;
}
-public import core.internal.array.appending : _d_arrayappendcTXImpl;
+public import core.internal.array.appending : _d_arrayappendcTX;
public import core.internal.array.comparison : __cmp;
public import core.internal.array.equality : __equals;
public import core.internal.array.casting: __ArrayCast;
@@ -4678,6 +4681,7 @@ public import core.internal.array.concatenation : _d_arraycatnTX;
public import core.internal.array.construction : _d_arrayctor;
public import core.internal.array.construction : _d_arraysetctor;
public import core.internal.array.construction : _d_newarrayT;
+public import core.internal.array.construction : _d_newarraymTX;
public import core.internal.array.arrayassign : _d_arrayassign_l;
public import core.internal.array.arrayassign : _d_arrayassign_r;
public import core.internal.array.arrayassign : _d_arraysetassign;
@@ -41,7 +41,7 @@ struct AA
Impl* impl;
alias impl this;
- private @property bool empty() const pure nothrow @nogc
+ private @property bool empty() const pure nothrow @nogc @safe
{
return impl is null || !impl.length;
}
@@ -57,6 +57,7 @@ private:
buckets = allocBuckets(sz);
firstUsed = cast(uint) buckets.length;
valoff = cast(uint) talign(keysz, ti.value.talign);
+ hashFn = &ti.key.getHash;
import rt.lifetime : hasPostblit, unqualify;
@@ -78,6 +79,10 @@ private:
immutable uint valoff;
Flags flags;
+ // function that calculates hash of a key. Set on creation
+ // the parameter is a pointer to the key.
+ size_t delegate(scope const void*) nothrow hashFn;
+
enum Flags : ubyte
{
none = 0x0,
@@ -85,7 +90,7 @@ private:
hasPointers = 0x2,
}
- @property size_t length() const pure nothrow @nogc
+ @property size_t length() const pure nothrow @nogc @safe
{
assert(used >= deleted);
return used - deleted;
@@ -156,7 +161,7 @@ private:
GC.free(obuckets.ptr); // safe to free b/c impossible to reference
}
- void clear() pure nothrow
+ void clear() pure nothrow @trusted
{
import core.stdc.string : memset;
// clear all data, but don't change bucket array length
@@ -457,9 +462,9 @@ private size_t mix(size_t h) @safe pure nothrow @nogc
return h;
}
-private size_t calcHash(scope const void* pkey, scope const TypeInfo keyti) nothrow
+private size_t calcHash(scope const void *pkey, scope const Impl* impl) nothrow
{
- immutable hash = keyti.getHash(pkey);
+ immutable hash = impl.hashFn(pkey);
// highest bit is set to distinguish empty/deleted from filled buckets
return mix(hash) | HASH_FILLED_MARK;
}
@@ -550,7 +555,7 @@ extern (C) void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti,
}
// get hash and bucket for key
- immutable hash = calcHash(pkey, ti.key);
+ immutable hash = calcHash(pkey, aa);
// found a value => return it
if (auto p = aa.findSlotLookup(hash, pkey, ti.key))
@@ -617,7 +622,7 @@ extern (C) inout(void)* _aaInX(inout AA aa, scope const TypeInfo keyti, scope co
if (aa.empty)
return null;
- immutable hash = calcHash(pkey, keyti);
+ immutable hash = calcHash(pkey, aa);
if (auto p = aa.findSlotLookup(hash, pkey, keyti))
return p.entry + aa.valoff;
return null;
@@ -629,7 +634,7 @@ extern (C) bool _aaDelX(AA aa, scope const TypeInfo keyti, scope const void* pke
if (aa.empty)
return false;
- immutable hash = calcHash(pkey, keyti);
+ immutable hash = calcHash(pkey, aa);
if (auto p = aa.findSlotLookup(hash, pkey, keyti))
{
// clear entry
@@ -648,7 +653,7 @@ extern (C) bool _aaDelX(AA aa, scope const TypeInfo keyti, scope const void* pke
}
/// Remove all elements from AA.
-extern (C) void _aaClear(AA aa) pure nothrow
+extern (C) void _aaClear(AA aa) pure nothrow @safe
{
if (!aa.empty)
{
@@ -778,7 +783,7 @@ extern (C) Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void
uint actualLength = 0;
foreach (_; 0 .. length)
{
- immutable hash = calcHash(pkey, ti.key);
+ immutable hash = calcHash(pkey, aa);
auto p = aa.findSlotLookup(hash, pkey, ti.key);
if (p is null)
@@ -1041,98 +1041,6 @@ extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) pure nothrow @
}
}
-
-/*
- * Helper for creating multi-dimensional arrays
- */
-private void[] _d_newarrayOpT(alias op)(const TypeInfo ti, size_t[] dims)
-{
- debug(PRINTF) printf("_d_newarrayOpT(ndims = %d)\n", dims.length);
- if (dims.length == 0)
- return null;
-
- void[] foo(const TypeInfo ti, size_t[] dims)
- {
- auto tinext = unqualify(ti.next);
- auto dim = dims[0];
-
- debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length);
- if (dims.length == 1)
- {
- auto r = op(ti, dim);
- return *cast(void[]*)(&r);
- }
-
- auto allocsize = (void[]).sizeof * dim;
- auto info = __arrayAlloc(allocsize, ti, tinext);
- auto isshared = typeid(ti) is typeid(TypeInfo_Shared);
- __setArrayAllocLength(info, allocsize, isshared, tinext);
- auto p = __arrayStart(info)[0 .. dim];
-
- foreach (i; 0..dim)
- {
- (cast(void[]*)p.ptr)[i] = foo(tinext, dims[1..$]);
- }
- return p;
- }
-
- auto result = foo(ti, dims);
- debug(PRINTF) printf("result = %llx\n", result.ptr);
-
- return result;
-}
-
-
-/**
-Create a new multi-dimensional array
-
-Has two variants:
-- `_d_newarraymTX` which initializes to 0
-- `_d_newarraymiTX` which initializes elements based on `TypeInfo`
-
----
-void main()
-{
- new int[][](10, 20);
- // _d_newarraymTX(typeid(float), [10, 20]);
-
- new float[][][](10, 20, 30);
- // _d_newarraymiTX(typeid(float), [10, 20, 30]);
-}
----
-
-Params:
- ti = `TypeInfo` of the array type
- dims = array length values for each dimension
-
-Returns:
- newly allocated array
-*/
-extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims) @weak
-{
- debug(PRINTF) printf("_d_newarraymT(dims.length = %d)\n", dims.length);
-
- if (dims.length == 0)
- return null;
- else
- {
- return _d_newarrayOpT!(_d_newarrayT)(ti, dims);
- }
-}
-
-/// ditto
-extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) @weak
-{
- debug(PRINTF) printf("_d_newarraymiT(dims.length = %d)\n", dims.length);
-
- if (dims.length == 0)
- return null;
- else
- {
- return _d_newarrayOpT!(_d_newarrayiT)(ti, dims);
- }
-}
-
/**
Non-template version of $(REF _d_newitemT, core,lifetime) that does not perform
initialization. Needed for $(REF allocEntry, rt,aaA).
@@ -1,4 +1,4 @@
-fc06c514a8c4492f60fc89b8c4f857e6932fbcbd
+17bafda797296e04f40f16a9660e5a9685392db4
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
@@ -4809,26 +4809,41 @@ private template ReduceSeedType(E)
/++
Implements the homonym function (also known as `accumulate`, $(D
compress), `inject`, or `foldl`) present in various programming
-languages of functional flavor. The call `fold!(fun)(range, seed)`
-first assigns `seed` to an internal variable `result`,
-also called the accumulator. Then, for each element `x` in $(D
-range), `result = fun(result, x)` gets evaluated. Finally, $(D
-result) is returned. The one-argument version `fold!(fun)(range)`
+languages of functional flavor, iteratively calling one or more predicates.
+
+$(P Each predicate in `fun` must take two arguments:)
+* An accumulator value
+* An element of the range `r`
+$(P Each predicate must return a value which implicitly converts to the
+type of the accumulator.)
+
+$(P For a single predicate,
+the call `fold!(fun)(range, seed)` will:)
+
+* Use `seed` to initialize an internal variable `result` (also called
+ the accumulator).
+* For each element `e` in $(D range), evaluate `result = fun(result, e)`.
+* Return $(D result).
+
+$(P The one-argument version `fold!(fun)(range)`
works similarly, but it uses the first element of the range as the
-seed (the range must be non-empty).
+seed (the range must be non-empty) and iterates over the remaining
+elements.)
+
+Multiple results are produced when using multiple predicates.
Params:
fun = the predicate function(s) to apply to the elements
See_Also:
- $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function))
+ * $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function))
- $(LREF sum) is similar to `fold!((a, b) => a + b)` that offers
- precise summing of floating point numbers.
+ * $(LREF sum) is similar to `fold!((a, b) => a + b)` that offers
+ precise summing of floating point numbers.
- This is functionally equivalent to $(LREF reduce) with the argument order
- reversed, and without the need to use $(REF_ALTTEXT `tuple`,tuple,std,typecons)
- for multiple seeds.
+ * `fold` is functionally equivalent to $(LREF reduce) with the argument order
+ reversed, and without the need to use $(REF_ALTTEXT `tuple`,tuple,std,typecons)
+ for multiple seeds.
+/
template fold(fun...)
if (fun.length >= 1)
@@ -4836,20 +4851,21 @@ if (fun.length >= 1)
/**
Params:
r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to fold
- seed = the initial value of the accumulator
+ seeds = the initial values of each accumulator (optional), one for each predicate
Returns:
- the accumulated `result`
+ Either the accumulated result for a single predicate, or a
+ $(REF_ALTTEXT `Tuple`,Tuple,std,typecons) of results.
*/
- auto fold(R, S...)(R r, S seed)
+ auto fold(R, S...)(R r, S seeds)
{
static if (S.length < 2)
{
- return reduce!fun(seed, r);
+ return reduce!fun(seeds, r);
}
else
{
import std.typecons : tuple;
- return reduce!fun(tuple(seed), r);
+ return reduce!fun(tuple(seeds), r);
}
}
}
@@ -4860,10 +4876,10 @@ if (fun.length >= 1)
immutable arr = [1, 2, 3, 4, 5];
// Sum all elements
- assert(arr.fold!((a, b) => a + b) == 15);
+ assert(arr.fold!((a, e) => a + e) == 15);
// Sum all elements with explicit seed
- assert(arr.fold!((a, b) => a + b)(6) == 21);
+ assert(arr.fold!((a, e) => a + e)(6) == 21);
import std.algorithm.comparison : min, max;
import std.typecons : tuple;
@@ -4875,10 +4891,10 @@ if (fun.length >= 1)
assert(arr.fold!(min, max)(0, 7) == tuple(0, 7));
// Can be used in a UFCS chain
- assert(arr.map!(a => a + 1).fold!((a, b) => a + b) == 20);
+ assert(arr.map!(a => a + 1).fold!((a, e) => a + e) == 20);
// Return the last element of any range
- assert(arr.fold!((a, b) => b) == 5);
+ assert(arr.fold!((a, e) => e) == 5);
}
@safe @nogc pure nothrow unittest
@@ -1546,28 +1546,96 @@ if (isInputRange!Range && !isInfinite!Range &&
}
// find
+/**
+Finds an element `e` of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
+where `pred(e)` is `true`.
+$(P
+$(PANEL
+$(UL
+$(LI `find` behaves similarly to `dropWhile` in other languages.)
+$(LI To _find the *last* matching element in a
+$(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) `haystack`,
+call `find!pred(retro(haystack))`. See $(REF retro, std,range).)
+)))
+
+Complexity:
+ `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
+
+Params:
+
+ pred = The predicate to match an element.
+ haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
+ searched in.
+
+Returns:
+ `haystack` advanced such that the front element satisfies `pred`.
+ If no such element exists, returns an empty `haystack`.
+*/
+InputRange find(alias pred, InputRange)(InputRange haystack)
+if (isInputRange!InputRange)
+{
+ alias R = InputRange;
+ alias predFun = unaryFun!pred;
+ static if (isNarrowString!R)
+ {
+ import std.utf : decode;
+
+ immutable len = haystack.length;
+ size_t i = 0, next = 0;
+ while (next < len)
+ {
+ if (predFun(decode(haystack, next)))
+ return haystack[i .. $];
+ i = next;
+ }
+ return haystack[$ .. $];
+ }
+ else
+ {
+ //standard range
+ for ( ; !haystack.empty; haystack.popFront() )
+ {
+ if (predFun(haystack.front))
+ break;
+ }
+ return haystack;
+ }
+}
+
+///
+@safe unittest
+{
+ auto arr = [ 1, 2, 3, 4, 1 ];
+ assert(find!("a > 2")(arr) == [ 3, 4, 1 ]);
+
+ // with predicate alias
+ bool pred(int e) => e + 1 > 1.5;
+ assert(find!(pred)(arr) == arr);
+}
+
+@safe pure unittest
+{
+ int[] r = [ 1, 2, 3 ];
+ assert(find!(a=>a > 2)(r) == [3]);
+ bool pred(int x) { return x + 1 > 1.5; }
+ assert(find!(pred)(r) == r);
+
+ assert(find!(a=>a > 'v')("hello world") == "world");
+ assert(find!(a=>a%4 == 0)("日本語") == "本語");
+}
+
/**
Finds an individual element in an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
Elements of `haystack` are compared with `needle` by using predicate
`pred` with `pred(haystack.front, needle)`.
-`find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
-
The predicate is passed to $(REF binaryFun, std, functional), and can either accept a
string, or any callable that can be executed via `pred(element, element)`.
-To _find the last occurrence of `needle` in a
-$(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) `haystack`,
-call `find(retro(haystack), needle)`. See $(REF retro, std,range).
-
-If no `needle` is provided, `pred(haystack.front)` will be evaluated on each
-element of the input range.
-
-If `input` is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives),
+If `haystack` is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives),
`needle` can be a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) too.
In this case `startsWith!pred(haystack, needle)` is evaluated on each evaluation.
-Note:
- `find` behaves similar to `dropWhile` in other languages.
+$(NOTE To find the first element $(I not) matching the needle, use predicate `"a != b"`.)
Complexity:
`find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
@@ -1579,21 +1647,16 @@ Complexity:
Params:
pred = The predicate for comparing each element with the needle, defaulting to equality `"a == b"`.
- The negated predicate `"a != b"` can be used to search instead for the first
- element $(I not) matching the needle.
-
haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
searched in.
-
needle = The element searched for.
Returns:
-
`haystack` advanced such that the front element is the one searched for;
that is, until `binaryFun!pred(haystack.front, needle)` is `true`. If no
such position exists, returns an empty `haystack`.
-See_ALso: $(LREF findAdjacent), $(LREF findAmong), $(LREF findSkip), $(LREF findSplit), $(LREF startsWith)
+See_Also: $(LREF findAdjacent), $(LREF findAmong), $(LREF findSkip), $(LREF findSplit), $(LREF startsWith)
*/
InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle)
if (isInputRange!InputRange &&
@@ -1754,8 +1817,8 @@ if (isInputRange!InputRange &&
assert(arr.find(4) == [4, 4, 4, 4, 5, 6, 9]);
assert(arr.find(1) == arr);
assert(arr.find(9) == [9]);
- assert(arr.find!((a, b) => a > b)(4) == [5, 6, 9]);
- assert(arr.find!((a, b) => a < b)(4) == arr);
+ assert(arr.find!((e, n) => e > n)(4) == [5, 6, 9]);
+ assert(arr.find!((e, n) => e < n)(4) == arr);
assert(arr.find(0).empty);
assert(arr.find(10).empty);
assert(arr.find(8).empty);
@@ -1770,7 +1833,7 @@ if (isInputRange!InputRange &&
import std.uni : toLower;
string[] s = ["Hello", "world", "!"];
- assert(s.find!((a, b) => toLower(a) == b)("hello") == s);
+ assert(s.find!((e, n) => toLower(e) == n)("hello") == s);
}
@safe unittest
@@ -1862,60 +1925,6 @@ if (isInputRange!InputRange &&
assert([x].find(x).empty == false);
}
-/// ditto
-InputRange find(alias pred, InputRange)(InputRange haystack)
-if (isInputRange!InputRange)
-{
- alias R = InputRange;
- alias predFun = unaryFun!pred;
- static if (isNarrowString!R)
- {
- import std.utf : decode;
-
- immutable len = haystack.length;
- size_t i = 0, next = 0;
- while (next < len)
- {
- if (predFun(decode(haystack, next)))
- return haystack[i .. $];
- i = next;
- }
- return haystack[$ .. $];
- }
- else
- {
- //standard range
- for ( ; !haystack.empty; haystack.popFront() )
- {
- if (predFun(haystack.front))
- break;
- }
- return haystack;
- }
-}
-
-///
-@safe unittest
-{
- auto arr = [ 1, 2, 3, 4, 1 ];
- assert(find!("a > 2")(arr) == [ 3, 4, 1 ]);
-
- // with predicate alias
- bool pred(int x) { return x + 1 > 1.5; }
- assert(find!(pred)(arr) == arr);
-}
-
-@safe pure unittest
-{
- int[] r = [ 1, 2, 3 ];
- assert(find!(a=>a > 2)(r) == [3]);
- bool pred(int x) { return x + 1 > 1.5; }
- assert(find!(pred)(r) == r);
-
- assert(find!(a=>a > 'v')("hello world") == "world");
- assert(find!(a=>a%4 == 0)("日本語") == "本語");
-}
-
/// ditto
R1 find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle)
if (isForwardRange!R1 && isForwardRange!R2
@@ -2376,9 +2385,9 @@ is considered to be 1.) The strategy used in searching several
subranges at once maximizes cache usage by moving in `haystack` as
few times as possible.
*/
-Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...)
-(Range haystack, Ranges needles)
-if (Ranges.length > 1 && is(typeof(startsWith!pred(haystack, needles))))
+Tuple!(Range, size_t) find(alias pred = "a == b", Range, Needles...)
+(Range haystack, Needles needles)
+if (Needles.length > 1 && is(typeof(startsWith!pred(haystack, needles))))
{
for (;; haystack.popFront())
{
@@ -2536,13 +2545,13 @@ was successful.
For more information about `pred` see $(LREF find).
See_Also:
-$(REF among, std,algorithm,comparison) for checking a value against multiple possibilities.
+$(REF among, std,algorithm,comparison) for checking a value against multiple arguments.
+/
template canFind(alias pred="a == b")
{
/++
- Returns `true` if and only if any value `v` found in the
- input range `range` satisfies the predicate `pred`.
+ Returns `true` if and only if `pred(e)` is true for any value `e` in the
+ input range `range`.
Performs (at most) $(BIGOH haystack.length) evaluations of `pred`.
+/
bool canFind(Range)(Range haystack)
@@ -2565,16 +2574,15 @@ template canFind(alias pred="a == b")
Returns the 1-based index of the first needle found in `haystack`. If no
needle is found, then `0` is returned.
- So, if used directly in the condition of an if statement or loop, the result
+ So, if used directly in the condition of an `if` statement or loop, the result
will be `true` if one of the needles is found and `false` if none are
found, whereas if the result is used elsewhere, it can either be cast to
`bool` for the same effect or used to get which needle was found first
- without having to deal with the tuple that `LREF find` returns for the
+ without having to deal with the tuple that $(LREF find) returns for the
same operation.
+/
- size_t canFind(Range, Ranges...)(Range haystack, scope Ranges needles)
- if (Ranges.length > 1 &&
- allSatisfy!(isForwardRange, Ranges) &&
+ size_t canFind(Range, Needles...)(Range haystack, scope Needles needles)
+ if (Needles.length > 1 &&
is(typeof(find!pred(haystack, needles))))
{
return find!pred(haystack, needles)[1];
@@ -2584,15 +2592,21 @@ template canFind(alias pred="a == b")
///
@safe unittest
{
- assert(canFind([0, 1, 2, 3], 2) == true);
- assert(canFind([0, 1, 2, 3], [1, 2], [2, 3]));
- assert(canFind([0, 1, 2, 3], [1, 2], [2, 3]) == 1);
- assert(canFind([0, 1, 2, 3], [1, 7], [2, 3]));
- assert(canFind([0, 1, 2, 3], [1, 7], [2, 3]) == 2);
+ const arr = [0, 1, 2, 3];
+ assert(canFind(arr, 2));
+ assert(!canFind(arr, 4));
+
+ // find one of several needles
+ assert(arr.canFind(3, 2));
+ assert(arr.canFind(3, 2) == 2); // second needle found
+ assert(arr.canFind([1, 3], 2) == 2);
- assert(canFind([0, 1, 2, 3], 4) == false);
- assert(!canFind([0, 1, 2, 3], [1, 3], [2, 4]));
- assert(canFind([0, 1, 2, 3], [1, 3], [2, 4]) == 0);
+ assert(canFind(arr, [1, 2], [2, 3]));
+ assert(canFind(arr, [1, 2], [2, 3]) == 1);
+ assert(canFind(arr, [1, 7], [2, 3]));
+ assert(canFind(arr, [1, 7], [2, 3]) == 2);
+ assert(!canFind(arr, [1, 3], [2, 4]));
+ assert(canFind(arr, [1, 3], [2, 4]) == 0);
}
/**
@@ -2607,10 +2621,10 @@ template canFind(alias pred="a == b")
"cardboard"
];
assert(!canFind(words, "bees"));
- assert( canFind!((string a, string b) => a.startsWith(b))(words, "bees"));
+ assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
}
-/// Search for mutliple items in an array of items (search for needles in an array of hay stacks)
+/// Search for multiple items in an array of items (search for needles in an array of haystacks)
@safe unittest
{
string s1 = "aaa111aaa";
@@ -2618,7 +2632,7 @@ template canFind(alias pred="a == b")
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
- assert(hay.canFind!(e => (e.canFind("111", "222"))));
+ assert(hay.canFind!(e => e.canFind("111", "222")));
}
@safe unittest
@@ -2736,7 +2750,7 @@ Returns:
`seq` advanced to the first matching element, or until empty if there are no
matching elements.
-See_Also: $(LREF find), $(REF std,algorithm,comparison,among)
+See_Also: $(LREF find), $(REF among, std,algorithm,comparison)
*/
InputRange findAmong(alias pred = "a == b", InputRange, ForwardRange)(
InputRange seq, ForwardRange choices)
@@ -1201,7 +1201,7 @@ private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
auto a2 = minimallyInitializedArray!(S2[][])(2, 2);
assert(a2);
enum b2 = minimallyInitializedArray!(S2[][])(2, 2);
- assert(b2);
+ assert(b2 !is null);
static struct S3
{
//this() @disable;
@@ -1210,7 +1210,7 @@ private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
auto a3 = minimallyInitializedArray!(S3[][])(2, 2);
assert(a3);
enum b3 = minimallyInitializedArray!(S3[][])(2, 2);
- assert(b3);
+ assert(b3 !is null);
}
/++
@@ -54,7 +54,7 @@ $(UL
$(LI `trace`)
$(LI `info`)
$(LI `warning`)
- #(LI `error`)
+ $(LI `error`)
$(LI `critical`)
$(LI `fatal`)
)
@@ -33,6 +33,7 @@ version (SPARC64) version = SPARC_Any;
version (SystemZ) version = IBMZ_Any;
version (RISCV32) version = RISCV_Any;
version (RISCV64) version = RISCV_Any;
+version (LoongArch64) version = LoongArch_Any;
version (D_InlineAsm_X86) version = InlineAsm_X86_Any;
version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any;
@@ -60,6 +61,7 @@ else version (X86_Any) version = IeeeFlagsSupport;
else version (PPC_Any) version = IeeeFlagsSupport;
else version (RISCV_Any) version = IeeeFlagsSupport;
else version (MIPS_Any) version = IeeeFlagsSupport;
+else version (LoongArch_Any) version = IeeeFlagsSupport;
else version (ARM_Any) version = IeeeFlagsSupport;
// Struct FloatingPointControl is only available if hardware FP units are available.
@@ -90,6 +92,7 @@ private:
// The ARM and PowerPC FPSCR is a 32-bit register.
// The SPARC FSR is a 32bit register (64 bits for SPARC 7 & 8, but high bits are uninteresting).
// The RISC-V (32 & 64 bit) fcsr is 32-bit register.
+ // THe LoongArch fcsr (fcsr0) is a 32-bit register.
uint flags;
version (CRuntime_Microsoft)
@@ -216,6 +219,15 @@ private:
return result;
`);
}
+ else version (LoongArch_Any)
+ {
+ uint result = void;
+ asm pure nothrow @nogc
+ {
+ "movfcsr2gr %0,$r2" : "=r" (result);
+ }
+ return result & EXCEPTIONS_MASK;
+ }
else
assert(0, "Not yet supported");
}
@@ -303,6 +315,13 @@ private:
}
`);
}
+ else version (LoongArch_Any)
+ {
+ asm nothrow @nogc
+ {
+ "movgr2fcsr $r2,$r0";
+ }
+ }
else
{
/* SPARC:
@@ -725,6 +744,21 @@ nothrow @nogc:
| inexactException,
}
}
+ else version (LoongArch_Any)
+ {
+ enum : ExceptionMask
+ {
+ inexactException = 0x00,
+ divByZeroException = 0x01,
+ overflowException = 0x02,
+ underflowException = 0x04,
+ invalidException = 0x08,
+ severeExceptions = overflowException | divByZeroException
+ | invalidException,
+ allExceptions = severeExceptions | underflowException
+ | inexactException,
+ }
+ }
else version (MIPS_Any)
{
enum : ExceptionMask
@@ -812,6 +846,8 @@ nothrow @nogc:
return true;
else version (MIPS_Any)
return true;
+ else version (LoongArch_Any)
+ return true;
else version (ARM_Any)
{
// The hasExceptionTraps_impl function is basically pure,
@@ -885,6 +921,10 @@ private:
{
alias ControlState = uint;
}
+ else version (LoongArch_Any)
+ {
+ alias ControlState = uint;
+ }
else version (MIPS_Any)
{
alias ControlState = uint;
@@ -1008,6 +1048,16 @@ private:
return cont;
`);
}
+ else version (LoongArch_Any)
+ {
+ ControlState cont;
+ asm pure nothrow @nogc
+ {
+ "movfcsr2gr %0,$r0" : "=r" (cont);
+ }
+ cont &= (roundingMask | allExceptions);
+ return cont;
+ }
else
assert(0, "Not yet supported");
}
@@ -1120,6 +1170,14 @@ private:
}
`);
}
+ else version (LoongArch_Any)
+ {
+ asm nothrow @nogc
+ {
+ "movgr2fcsr $r0,%0" :
+ : "r" (newState & (roundingMask | allExceptions));
+ }
+ }
else
assert(0, "Not yet supported");
}