diff --git a/dmd/access.d b/dmd/access.d index 1010c140b68..8d022030173 100644 --- a/dmd/access.d +++ b/dmd/access.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/attribute.html#visibility_attributes, Visibility Attributes) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/access.d, _access.d) diff --git a/dmd/aggregate.d b/dmd/aggregate.d index 5f0934b748e..854067388bf 100644 --- a/dmd/aggregate.d +++ b/dmd/aggregate.d @@ -4,7 +4,7 @@ * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions), * $(LINK2 https://dlang.org/spec/class.html, Class). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d) @@ -65,7 +65,7 @@ enum ClassKind : ubyte * Returns: * 0-terminated string for `c` */ -const(char)* toChars(ClassKind c) @safe +const(char)* ClassKindToChars(ClassKind c) @safe { final switch (c) { @@ -178,16 +178,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol return sc2; } - override final void setScope(Scope* sc) - { - // Might need a scope to resolve forward references. The check for - // semanticRun prevents unnecessary setting of _scope during deferred - // setScope phases for aggregates which already finished semantic(). - // See https://issues.dlang.org/show_bug.cgi?id=16607 - if (semanticRun < PASS.semanticdone) - ScopeDsymbol.setScope(sc); - } - /*************************************** * Returns: * The total number of fields minus the number of hidden fields. @@ -663,7 +653,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() || diff --git a/dmd/aggregate.h b/dmd/aggregate.h index 060e4e6c083..e187bbcb044 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -113,7 +113,6 @@ class AggregateDeclaration : public ScopeDsymbol Sizeok sizeok; // set when structsize contains valid data virtual Scope *newScope(Scope *sc); - void setScope(Scope *sc) override final; virtual void finalizeSize() = 0; uinteger_t size(const Loc &loc) override final; bool fill(const Loc &loc, Expressions &elements, bool ctorinit); @@ -169,7 +168,6 @@ class StructDeclaration : public AggregateDeclaration 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(); @@ -291,7 +289,6 @@ class ClassDeclaration : public AggregateDeclaration 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); diff --git a/dmd/aliasthis.d b/dmd/aliasthis.d index a8933f6d2fe..0e063caa2fc 100644 --- a/dmd/aliasthis.d +++ b/dmd/aliasthis.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/class.html#alias-this, Alias This) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d) @@ -14,16 +14,10 @@ module dmd.aliasthis; import core.stdc.stdio; -import dmd.aggregate; -import dmd.dscope; + import dmd.dsymbol; -import dmd.expression; -import dmd.expressionsem; -import dmd.globals; import dmd.identifier; import dmd.location; -import dmd.mtype; -import dmd.tokens; import dmd.visitor; /*********************************************************** @@ -71,161 +65,3 @@ extern (C++) final class AliasThis : Dsymbol return this.isDeprecated_; } } - -/************************************* - * Find the `alias this` symbol of e's type. - * Params: - * sc = context - * e = expression forming the `this` - * gag = do not print errors, return `null` instead - * findOnly = don't do further processing like resolving properties, - * i.e. just return plain dotExp() result. - * Returns: - * Expression that is `e.aliasthis` - */ -Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false) -{ - import dmd.typesem : dotExp; - for (AggregateDeclaration ad = isAggregate(e.type); ad;) - { - if (ad.aliasthis) - { - Loc loc = e.loc; - Type tthis = (e.op == EXP.type ? e.type : null); - const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag)); - uint olderrors = gag ? global.startGagging() : 0; - e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags); - if (!e || findOnly) - return gag && global.endGagging(olderrors) ? null : e; - - if (tthis && ad.aliasthis.sym.needThis()) - { - if (auto ve = e.isVarExp()) - { - if (auto fd = ve.var.isFuncDeclaration()) - { - // https://issues.dlang.org/show_bug.cgi?id=13009 - // Support better match for the overloaded alias this. - bool hasOverloads; - if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) - { - if (!hasOverloads) - fd = f; // use exact match - e = new VarExp(loc, fd, hasOverloads); - e.type = f.type; - e = new CallExp(loc, e); - goto L1; - } - } - } - /* non-@property function is not called inside typeof(), - * so resolve it ahead. - */ - { - int save = sc.intypeof; - sc.intypeof = 1; // bypass "need this" error check - e = resolveProperties(sc, e); - sc.intypeof = save; - } - L1: - e = new TypeExp(loc, new TypeTypeof(loc, e)); - e = e.expressionSemantic(sc); - } - e = resolveProperties(sc, e); - if (!gag) - ad.aliasthis.checkDeprecatedAliasThis(loc, sc); - else if (global.endGagging(olderrors)) - e = null; - } - - import dmd.dclass : ClassDeclaration; - auto cd = ad.isClassDeclaration(); - if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) - { - ad = cd.baseClass; - continue; - } - break; - } - return e; -} - -/** - * Check if an `alias this` is deprecated - * - * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to - * check if `expression` uses a deprecated `aliasthis`, but this calls - * `toPrettyChars` which lead to the following message: - * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated" - * - * Params: - * at = The `AliasThis` object to check - * loc = `Loc` of the expression triggering the access to `at` - * sc = `Scope` of the expression - * (deprecations do not trigger in deprecated scopes) - * - * Returns: - * Whether the alias this was reported as deprecated. - */ -bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc) -{ - import dmd.errors : deprecation, Classification; - import dmd.dsymbolsem : getMessage; - - if (global.params.useDeprecated != DiagnosticReporting.off - && at.isDeprecated() && !sc.isDeprecated()) - { - const(char)* message = null; - for (Dsymbol p = at; p; p = p.parent) - { - message = p.depdecl ? p.depdecl.getMessage() : null; - if (message) - break; - } - if (message) - deprecation(loc, "`alias %s this` is deprecated - %s", - at.sym.toChars(), message); - else - deprecation(loc, "`alias %s this` is deprecated", - at.sym.toChars()); - - if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) - ti.printInstantiationTrace(Classification.deprecation); - - return true; - } - return false; -} - -/************************************** - * Check and set 'att' if 't' is a recursive 'alias this' type - * - * The goal is to prevent endless loops when there is a cycle in the alias this chain. - * Since there is no multiple `alias this`, the chain either ends in a leaf, - * or it loops back on itself as some point. - * - * Example: S0 -> (S1 -> S2 -> S3 -> S1) - * - * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. - * `S1` is a recursive alias this type, but since `att` is initialized to `null`, - * this still returns `false`, but `att1` is set to `S1`. - * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, - * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. - * - * Params: - * att = type reference used to detect recursion. Should be initialized to `null`. - * t = type of 'alias this' rewrite to attempt - * - * Returns: - * `false` if the rewrite is safe, `true` if it would loop back around - */ -bool isRecursiveAliasThis(ref Type att, Type t) -{ - //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); - auto tb = t.toBasetype(); - if (att && tb.equivalent(att)) - return true; - else if (!att && tb.checkAliasThisRec()) - att = tb; - return false; -} diff --git a/dmd/aliasthis.h b/dmd/aliasthis.h index 092490fd5de..88ba35319b3 100644 --- a/dmd/aliasthis.h +++ b/dmd/aliasthis.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2009-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2009-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/argtypes_aarch64.d b/dmd/argtypes_aarch64.d index 6fbf3ee8bef..6de36557038 100644 --- a/dmd/argtypes_aarch64.d +++ b/dmd/argtypes_aarch64.d @@ -1,7 +1,7 @@ /** * Break down a D type into basic (register) types for the AArch64 ABI. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Martin Kinkelin * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_aarch64.d, _argtypes_aarch64.d) diff --git a/dmd/argtypes_sysv_x64.d b/dmd/argtypes_sysv_x64.d index 1ef32fcdf91..bf00e615da7 100644 --- a/dmd/argtypes_sysv_x64.d +++ b/dmd/argtypes_sysv_x64.d @@ -1,7 +1,7 @@ /** * Break down a D type into basic (register) types for the x86_64 System V ABI. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Martin Kinkelin * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_sysv_x64.d, _argtypes_sysv_x64.d) diff --git a/dmd/argtypes_x86.d b/dmd/argtypes_x86.d index 6dc2c8deeff..ac4b29ae46a 100644 --- a/dmd/argtypes_x86.d +++ b/dmd/argtypes_x86.d @@ -1,7 +1,7 @@ /** * Break down a D type into basic (register) types for the 32-bit x86 ABI. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_x86.d, _argtypes_x86.d) diff --git a/dmd/arrayop.d b/dmd/arrayop.d index 25bbb3f32ad..afe6054f4aa 100644 --- a/dmd/arrayop.d +++ b/dmd/arrayop.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/arrays.html#array-operations, Array Operations) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d, _arrayop.d) @@ -172,7 +172,7 @@ Expression arrayOp(BinAssignExp e, Scope* sc) } if (e.e1.op == EXP.arrayLiteral) { - return e.e1.modifiableLvalue(sc, e.e1); + return e.e1.modifiableLvalue(sc); } return arrayOp(e.isBinExp(), sc); diff --git a/dmd/arraytypes.d b/dmd/arraytypes.d index 6634a6af1fc..feab9a49c7c 100644 --- a/dmd/arraytypes.d +++ b/dmd/arraytypes.d @@ -1,7 +1,7 @@ /** * Provide aliases for arrays of certain declarations or statements. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d) diff --git a/dmd/arraytypes.h b/dmd/arraytypes.h index 05126a53d7e..779642813f5 100644 --- a/dmd/arraytypes.h +++ b/dmd/arraytypes.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2006-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2006-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/ast_node.d b/dmd/ast_node.d index 313c2bd3691..c8c95fa0782 100644 --- a/dmd/ast_node.d +++ b/dmd/ast_node.d @@ -1,7 +1,7 @@ /** * Defines the base class for all nodes which are part of the AST. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d, _ast_node.d) diff --git a/dmd/ast_node.h b/dmd/ast_node.h index 6154c6d1b3a..a24218a86d0 100644 --- a/dmd/ast_node.h +++ b/dmd/ast_node.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/astcodegen.d b/dmd/astcodegen.d index d40f836faae..f17907719a7 100644 --- a/dmd/astcodegen.d +++ b/dmd/astcodegen.d @@ -97,6 +97,6 @@ struct ASTCodegen alias isExpression = dmd.dtemplate.isExpression; alias isTuple = dmd.dtemplate.isTuple; - alias IgnoreErrors = dmd.dsymbol.IgnoreErrors; + alias SearchOpt = dmd.dsymbol.SearchOpt; alias PASS = dmd.dsymbol.PASS; } diff --git a/dmd/astenums.d b/dmd/astenums.d index 77f36f304a5..f19edb9e4b4 100644 --- a/dmd/astenums.d +++ b/dmd/astenums.d @@ -1,7 +1,7 @@ /** * Defines enums common to dmd and dmd as parse library. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d, _astenums.d) * Documentation: https://dlang.org/phobos/dmd_astenums.html @@ -63,7 +63,7 @@ enum STC : ulong // transfer changes to declaration.h foreach_ = 0x4000, /// variable for foreach loop variadic = 0x8000, /// the `variadic` parameter in: T foo(T a, U b, V variadic...) - // = 0x1_0000, + constscoperef = 0x1_0000, /// when `in` means const|scope|ref templateparameter = 0x2_0000, /// template parameter ref_ = 0x4_0000, /// `ref` scope_ = 0x8_0000, /// `scope` @@ -112,7 +112,7 @@ enum STC : ulong // transfer changes to declaration.h volatile_ = 0x40_0000_0000_0000, /// destined for volatile in the back end safeGroup = STC.safe | STC.trusted | STC.system, - IOR = STC.in_ | STC.ref_ | STC.out_, + IOR = STC.constscoperef | STC.in_ | STC.ref_ | STC.out_, TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild), FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live | safeGroup), @@ -383,6 +383,7 @@ enum STMT : ubyte enum InitKind : ubyte { void_, + default_, error, struct_, array, diff --git a/dmd/asttypename.d b/dmd/asttypename.d index d853950e52a..da30c2f0e3d 100644 --- a/dmd/asttypename.d +++ b/dmd/asttypename.d @@ -1,7 +1,7 @@ /** * Development utility for printing AST nodes by their internal name, instead of as D source code. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Stefan Koch * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/asttypename.d, _asttypename.d) diff --git a/dmd/attrib.d b/dmd/attrib.d index 88a94faa6fa..64c7a202fc1 100644 --- a/dmd/attrib.d +++ b/dmd/attrib.d @@ -14,7 +14,7 @@ * - Protection (`private`, `public`) * - Deprecated declarations (`@deprecated`) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d) @@ -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,44 +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); - //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d); - if (d) - { - Scope* sc2 = newScope(sc); - d.foreachDsymbol( s => s.setScope(sc2) ); - if (sc2 != sc) - sc2.pop(); - } - } - - override void importAll(Scope* sc) - { - Dsymbols* d = include(sc); - //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); - if (d) - { - Scope* sc2 = newScope(sc); - d.foreachDsymbol( s => s.importAll(sc2) ); - if (sc2 != sc) - sc2.pop(); - } - } - override void addComment(const(char)* comment) { //printf("AttribDeclaration::addComment %s\n", comment); @@ -175,17 +137,12 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return "attribute"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { Dsymbols* d = include(null); return Dsymbol.oneMembers(d, ps, ident); } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); - } - override final bool hasPointers() { return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; @@ -268,10 +225,10 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining); } - override final bool oneMember(Dsymbol* ps, Identifier ident) + override final bool oneMember(out Dsymbol ps, Identifier ident) { bool t = Dsymbol.oneMembers(decl, ps, ident); - if (t && *ps) + if (t && ps) { /* This is to deal with the following case: * struct Tick { @@ -281,7 +238,7 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration * before the semantic analysis of 'to', so that template overloading based on the * 'this' pointer can be successful. */ - FuncDeclaration fd = (*ps).isFuncDeclaration(); + FuncDeclaration fd = ps.isFuncDeclaration(); if (fd) { /* Use storage_class2 instead of storage_class otherwise when we do .di generation @@ -295,34 +252,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; @@ -378,14 +307,6 @@ extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration return scx; } - override void setScope(Scope* sc) - { - //printf("DeprecatedDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol.setScope(sc); // for forward reference - return AttribDeclaration.setScope(sc); - } - override void accept(Visitor v) { v.visit(this); @@ -473,13 +394,6 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration sc.aligndecl, sc.inlining); } - override void setScope(Scope* sc) - { - if (decl) - Dsymbol.setScope(sc); // for forward reference - return AttribDeclaration.setScope(sc); - } - override const(char)* toChars() const { return toString().ptr; @@ -640,37 +554,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"; @@ -774,88 +657,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl)); } - override void setScope(Scope* sc) - { - if (decl) - Dsymbol.setScope(sc); - return AttribDeclaration.setScope(sc); - } - - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this); - if (decl) - { - /* This works by treating an AnonDeclaration as an aggregate 'member', - * so in order to place that member we need to compute the member's - * size and alignment. - */ - size_t fieldstart = ad.fields.length; - - /* Hackishly hijack ad's structsize and alignsize fields - * for use in our fake anon aggregate member. - */ - uint savestructsize = ad.structsize; - uint savealignsize = ad.alignsize; - ad.structsize = 0; - ad.alignsize = 0; - - FieldState fs; - decl.foreachDsymbol( (s) - { - s.setFieldOffset(ad, fs, this.isunion); - if (this.isunion) - fs.offset = 0; - }); - - /* https://issues.dlang.org/show_bug.cgi?id=13613 - * If the fields in this.members had been already - * added in ad.fields, just update *poffset for the subsequent - * field offset calculation. - */ - if (fieldstart == ad.fields.length) - { - ad.structsize = savestructsize; - ad.alignsize = savealignsize; - fieldState.offset = ad.structsize; - return; - } - - anonstructsize = ad.structsize; - anonalignsize = ad.alignsize; - ad.structsize = savestructsize; - ad.alignsize = savealignsize; - - // 0 sized structs are set to 1 byte - if (anonstructsize == 0) - { - anonstructsize = 1; - anonalignsize = 1; - } - - assert(_scope); - auto alignment = _scope.alignment(); - - /* Given the anon 'member's size and alignment, - * go ahead and place it. - */ - anonoffset = placeField( - fieldState.offset, - anonstructsize, anonalignsize, alignment, - ad.structsize, ad.alignsize, - isunion); - - // Add to the anon fields the base offset of this anonymous aggregate - //printf("anon fields, anonoffset = %d\n", anonoffset); - foreach (const i; fieldstart .. ad.fields.length) - { - VarDeclaration v = ad.fields[i]; - //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); - v.offset += anonoffset; - } - } - } - override const(char)* kind() const { return (isunion ? "anonymous union" : "anonymous struct"); @@ -963,7 +764,7 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl)); } - override final bool oneMember(Dsymbol* ps, Identifier ident) + override final bool oneMember(out Dsymbol ps, Identifier ident) { //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc); if (condition.inc != Include.notComputed) @@ -973,8 +774,8 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration } else { - bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null); - *ps = null; + bool res = (Dsymbol.oneMembers(decl, ps, ident) && ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && ps is null); + ps = null; return res; } } @@ -1005,11 +806,6 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration } } - override void setScope(Scope* sc) - { - include(sc).foreachDsymbol( s => s.setScope(sc) ); - } - override void accept(Visitor v) { v.visit(this); @@ -1075,35 +871,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 - // But do set the scope, in case we need it for forward referencing - Dsymbol.setScope(sc); - } - - override void importAll(Scope* sc) - { - // do not evaluate condition before semantic pass - } - override const(char)* kind() const { return "static if"; @@ -1155,7 +922,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration Dsymbol.arraySyntaxCopy(decl)); } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { // Required to support IFTI on a template that contains a // `static foreach` declaration. `super.oneMember` calls @@ -1166,7 +933,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration { return super.oneMember(ps, ident); } - *ps = null; // a `static foreach` declaration may in general expand to multiple symbols + ps = null; // a `static foreach` declaration may in general expand to multiple symbols return false; } @@ -1207,30 +974,12 @@ 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 // change this to give semantics to documentation comments on static foreach declarations } - override void setScope(Scope* sc) - { - // do not evaluate condition before semantic pass - // But do set the scope, in case we need it for forward referencing - Dsymbol.setScope(sc); - } - - override void importAll(Scope* sc) - { - // do not evaluate aggregate before semantic pass - } - override const(char)* kind() const { return "static foreach"; @@ -1287,15 +1036,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; @@ -1333,17 +1073,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); - } - override const(char)* kind() const { return "mixin"; @@ -1394,14 +1123,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration return sc2; } - override void setScope(Scope* sc) - { - //printf("UserAttributeDeclaration::setScope() %p\n", this); - if (decl) - Dsymbol.setScope(sc); // for forward reference of UDAs - return AttribDeclaration.setScope(sc); - } - extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2) { Expressions* udas; @@ -1596,3 +1317,27 @@ int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg) return 0; } + + +/** + * Returns: true if the given expression is an enum from `core.attribute` named `id` + */ +bool isEnumAttribute(Expression e, Identifier id) +{ + import dmd.attrib : isCoreUda; + import dmd.id : Id; + + // Logic based on dmd.objc.Supported.declaredAsOptionalCount + auto typeExp = e.isTypeExp; + if (!typeExp) + return false; + + auto typeEnum = typeExp.type.isTypeEnum(); + if (!typeEnum) + return false; + + if (isCoreUda(typeEnum.sym, id)) + return true; + + return false; +} diff --git a/dmd/attrib.h b/dmd/attrib.h index f47a1f6f836..344a7e929a7 100644 --- a/dmd/attrib.h +++ b/dmd/attrib.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -26,13 +26,9 @@ class AttribDeclaration : public Dsymbol 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; const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; bool hasPointers() override final; bool hasStaticCtorOrDtor() override final; void checkCtorConstInit() override final; @@ -48,8 +44,7 @@ class StorageClassDeclaration : public AttribDeclaration 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; + bool oneMember(Dsymbol *&ps, Identifier *ident) override final; StorageClassDeclaration *isStorageClassDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -63,7 +58,6 @@ class DeprecatedDeclaration final : public StorageClassDeclaration DeprecatedDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - void setScope(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -86,7 +80,6 @@ class CPPMangleDeclaration final : public AttribDeclaration CPPMangleDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - void setScope(Scope *sc) override; const char *toChars() const override; void accept(Visitor *v) override { v->visit(this); } }; @@ -110,7 +103,6 @@ class VisibilityDeclaration final : public AttribDeclaration 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; } @@ -138,8 +130,6 @@ class AnonDeclaration final : public AttribDeclaration unsigned anonalignsize; // size of anonymous struct for alignment purposes AnonDeclaration *syntaxCopy(Dsymbol *s) override; - void setScope(Scope *sc) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; AnonDeclaration *isAnonDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -163,10 +153,9 @@ class ConditionalDeclaration : public AttribDeclaration Dsymbols *elsedecl; // array of Dsymbol's for else block ConditionalDeclaration *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override final; + bool oneMember(Dsymbol *&ps, Identifier *ident) override final; Dsymbols *include(Scope *sc) override; void addComment(const utf8_t *comment) override final; - void setScope(Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -179,9 +168,6 @@ class StaticIfDeclaration final : public ConditionalDeclaration 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; } const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } @@ -197,12 +183,9 @@ class StaticForeachDeclaration final : public AttribDeclaration Dsymbols *cache; StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override; - bool oneMember(Dsymbol **ps, Identifier *ident) 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; const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } }; @@ -213,7 +196,6 @@ class ForwardingAttribDeclaration final : public AttribDeclaration 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,8 +211,6 @@ class MixinDeclaration final : public AttribDeclaration 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); } }; @@ -246,7 +226,6 @@ class UserAttributeDeclaration final : public AttribDeclaration UserAttributeDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - void setScope(Scope *sc) override; Expressions *getAttributes(); const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } diff --git a/dmd/blockexit.d b/dmd/blockexit.d index 5108ecf7ba7..d77af7e1c5c 100644 --- a/dmd/blockexit.d +++ b/dmd/blockexit.d @@ -1,7 +1,7 @@ /** * Find out in what ways control flow can exit a statement block. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d, _blockexit.d) diff --git a/dmd/builtin.d b/dmd/builtin.d index 67f26a79e2b..48df4c33fda 100644 --- a/dmd/builtin.d +++ b/dmd/builtin.d @@ -3,7 +3,7 @@ * * Currently includes functions from `std.math`, `core.math` and `core.bitop`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d) diff --git a/dmd/canthrow.d b/dmd/canthrow.d index 8aece3bdd71..31155f188dc 100644 --- a/dmd/canthrow.d +++ b/dmd/canthrow.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#nothrow-functions, Nothrow Functions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d, _canthrow.d) @@ -80,7 +80,8 @@ CT canThrow(Expression e, FuncDeclaration func, ErrorSink eSink) if (!f.isDtorDeclaration()) errorSupplementalInferredAttr(f, 10, false, STC.nothrow_); - e.checkOverriddenDtor(null, f, dd => dd.type.toTypeFunction().isnothrow, "not nothrow"); + import dmd.expressionsem : checkOverriddenDtor; + f.checkOverriddenDtor(null, e.loc, dd => dd.type.toTypeFunction().isnothrow, "not nothrow"); } else if (func) { diff --git a/dmd/chkformat.d b/dmd/chkformat.d index 8cfad5916c7..5024f9bb210 100644 --- a/dmd/chkformat.d +++ b/dmd/chkformat.d @@ -1,7 +1,7 @@ /** * Check the arguments to `printf` and `scanf` against the `format` string. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d, _chkformat.d) diff --git a/dmd/cli.d b/dmd/cli.d index 9c79f10d8ab..8c2e96fba99 100644 --- a/dmd/cli.d +++ b/dmd/cli.d @@ -5,7 +5,7 @@ * However, this file will be used to generate the * $(LINK2 https://dlang.org/dmd-linux.html, online documentation) and MAN pages. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cli.d, _cli.d) @@ -342,6 +342,15 @@ dmd -cov -unittest myprog.d With $(I filename), write module dependencies as text to $(I filename) (only imports).`, ), + Option("dllimport=", + "Windows only: select symbols to dllimport (none/defaultLibsOnly/all)", + `Which global variables to dllimport implicitly if not defined in a root module + $(UL + $(LI $(I none): None) + $(LI $(I defaultLibsOnly): Only druntime/Phobos symbols) + $(LI $(I all): All) + )`, + ), Option("extern-std=", "set C++ name mangling compatibility with ", "Standards supported are: @@ -465,7 +474,7 @@ dmd -cov -unittest myprog.d $(P Note that multiple `-i=...` options are allowed, each one adds a pattern.)}" ), Option("ignore", - "ignore unsupported pragmas" + "deprecated flag, unsupported pragmas are always ignored now" ), Option("inline", "do function inlining", @@ -818,6 +827,14 @@ dmd -cov -unittest myprog.d Option("vgc", "list all gc allocations including hidden ones" ), + Option("visibility=", + "default visibility of symbols (default/hidden/public)", + "$(UL + $(LI $(I default): Hidden for Windows targets without -shared, otherwise public) + $(LI $(I hidden): Only export symbols marked with 'export') + $(LI $(I public): Export all symbols) + )", + ), Option("vtls", "list all variables going into thread local storage" ), diff --git a/dmd/clone.d b/dmd/clone.d index ca7f398ae7a..6fbf8e284de 100644 --- a/dmd/clone.d +++ b/dmd/clone.d @@ -2,7 +2,7 @@ * Builds struct member functions if needed and not defined by the user. * Includes `opEquals`, `opAssign`, post blit, copy constructor and destructor. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/clone.d, _clone.d) @@ -1571,7 +1571,7 @@ private Statement generateCopyCtorBody(StructDeclaration sd) * `true` if one needs to be generated * `false` otherwise */ -private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) +bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) { if (global.errors) return false; diff --git a/dmd/common/README.md b/dmd/common/README.md index 853fd4ff502..ad507c75bd4 100644 --- a/dmd/common/README.md +++ b/dmd/common/README.md @@ -5,4 +5,4 @@ | [bitfields.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/bitfields.d) | Pack multiple boolean fields into bit fields | | [file.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/file.d) | Functions and objects dedicated to file I/O and management | | [outbuffer.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data | -| [string.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/string.d) | Common string functions including filename manipulation | +| [string.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/smallbuffer.d) | Common string functions including filename manipulation | diff --git a/dmd/common/bitfields.d b/dmd/common/bitfields.d index b9fcb0995c9..01aa56d1809 100644 --- a/dmd/common/bitfields.d +++ b/dmd/common/bitfields.d @@ -1,7 +1,7 @@ /** * A library bitfields utility * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Dennis Korpel * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d, common/bitfields.d) diff --git a/dmd/common/file.d b/dmd/common/file.d index 924cde64976..f18e801294f 100644 --- a/dmd/common/file.d +++ b/dmd/common/file.d @@ -4,7 +4,7 @@ * Functions and objects dedicated to file I/O and management. TODO: Move here artifacts * from places such as root/ so both the frontend and the backend have access to them. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d, common/_file.d) @@ -17,13 +17,13 @@ module dmd.common.file; import core.stdc.errno : errno; import core.stdc.stdio : fprintf, remove, rename, stderr; import core.stdc.stdlib : exit; -import core.stdc.string : strerror; +import core.stdc.string : strerror, strlen; import core.sys.windows.winbase; import core.sys.windows.winnt; import core.sys.posix.fcntl; import core.sys.posix.unistd; -import dmd.common.string; +import dmd.common.smallbuffer; nothrow: @@ -137,7 +137,8 @@ struct FileMapping(Datum) enum openFlags = CREATE_ALWAYS; } - handle = filename.asDString.extendedPathThen!(p => CreateFileW(p.ptr, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null)); + handle = filename[0 .. strlen(filename)]. + extendedPathThen!(p => CreateFileW(p.ptr, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null)); if (handle == invalidHandle) { static if (is(Datum == const)) @@ -320,7 +321,7 @@ struct FileMapping(Datum) else version(Windows) { import core.sys.windows.winbase; - if (deleteme.asDString.extendedPathThen!(p => DeleteFileW(p.ptr)) == 0) + if (deleteme[0 .. strlen(deleteme)].extendedPathThen!(p => DeleteFileW(p.ptr)) == 0) { fprintf(stderr, "DeleteFileW error %d\n", GetLastError()); return false; @@ -455,8 +456,8 @@ struct FileMapping(Datum) else version(Windows) { import core.sys.windows.winbase; - auto r = oldname.asDString.extendedPathThen!( - p1 => filename.asDString.extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING)) + auto r = oldname[0 .. strlen(oldname)].extendedPathThen!( + p1 => filename[0 .. strlen(filename)].extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING)) ); if (r == 0) { @@ -491,7 +492,7 @@ extern(D) static bool writeFile(const(char)* name, const void[] data) nothrow else version (Windows) { DWORD numwritten; // here because of the gotos - const nameStr = name.asDString; + const nameStr = name[0 .. strlen(name)]; // work around Windows file path length limitation // (see documentation for extendedPathThen). HANDLE h = nameStr.extendedPathThen! diff --git a/dmd/common/int128.d b/dmd/common/int128.d index a45af4254ef..796687b1f77 100644 --- a/dmd/common/int128.d +++ b/dmd/common/int128.d @@ -2,7 +2,7 @@ * * Not optimized for speed. * - * Copyright: Copyright D Language Foundation 2022. + * Copyright: Copyright (C) 2022-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Authors: Walter Bright * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/int128.d, root/_int128.d) diff --git a/dmd/common/outbuffer.d b/dmd/common/outbuffer.d index b8ad7851e4d..cff08ec5d43 100644 --- a/dmd/common/outbuffer.d +++ b/dmd/common/outbuffer.d @@ -1,7 +1,7 @@ /** * An expandable buffer in which you can write text or binary data. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d, root/_outbuffer.d) @@ -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 { diff --git a/dmd/common/outbuffer.h b/dmd/common/outbuffer.h index 4c1dceea3f6..2250497c38f 100644 --- a/dmd/common/outbuffer.h +++ b/dmd/common/outbuffer.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/common/string.d b/dmd/common/smallbuffer.d similarity index 80% rename from dmd/common/string.d rename to dmd/common/smallbuffer.d index 9453a3474da..c6aa7abbc60 100644 --- a/dmd/common/string.d +++ b/dmd/common/smallbuffer.d @@ -1,14 +1,14 @@ /** * Common string functions including filename manipulation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) - * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d, common/_string.d) - * Documentation: https://dlang.org/phobos/dmd_common_string.html - * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/string.d + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/smallbuffer.d, common/_smallbuffer.d) + * Documentation: https://dlang.org/phobos/dmd_common_smallbuffer.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/smallbuffer */ -module dmd.common.string; +module dmd.common.smallbuffer; nothrow: @@ -48,7 +48,7 @@ struct SmallBuffer(Element) } else { - assert(len < sizeof.max / (2 * Element.sizeof)); + assert(len < size_t.max / (2 * Element.sizeof)); _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; @@ -76,7 +76,7 @@ struct SmallBuffer(Element) else { __dtor(); - assert(len < sizeof.max / Element.sizeof); + assert(len < size_t.max / Element.sizeof); _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; @@ -106,34 +106,12 @@ unittest assert(b[] !is buf[]); } -/** -Converts a zero-terminated C string to a D slice. Takes linear time and allocates no memory. - -Params: -stringz = the C string to be converted - -Returns: -a slice comprehending the string. The terminating 0 is not part of the slice. -*/ -auto asDString(C)(C* stringz) pure @nogc nothrow -{ - import core.stdc.string : strlen; - return stringz[0 .. strlen(stringz)]; -} - -/// -unittest -{ - const char* p = "123".ptr; - assert(p.asDString == "123"); -} - /** (Windows only) Converts a narrow string to a wide string using `buffer` as strorage. Returns a slice managed by `buffer` containing the converted string. The terminating zero is not part of the returned slice, but is guaranteed to follow it. */ -version(Windows) wchar[] toWStringz(const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow +version(Windows) wchar[] toWStringz(scope const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow { import core.sys.windows.winnls : MultiByteToWideChar; import dmd.common.file : CodePage; @@ -141,16 +119,17 @@ version(Windows) wchar[] toWStringz(const(char)[] narrow, ref SmallBuffer!wchar if (narrow is null) return null; - const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length); - if (requiredLength < cast(int) buffer.length) + size_t length; + int i; + while (1) { - buffer[requiredLength] = 0; - return buffer[0 .. requiredLength]; + // https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar + length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length); + if (length < buffer.length) + break; + buffer.create(length + 1); + assert(++i == 1); // ensure loop should only execute once or twice } - - buffer.create(requiredLength + 1); - const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, requiredLength); - assert(length == requiredLength); buffer[length] = 0; return buffer[0 .. length]; } diff --git a/dmd/compiler.d b/dmd/compiler.d index 8562e87f0bb..010d323aaa8 100644 --- a/dmd/compiler.d +++ b/dmd/compiler.d @@ -1,7 +1,7 @@ /** * Describes a back-end compiler and implements compiler-specific actions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d, _compiler.d) @@ -15,6 +15,7 @@ import core.stdc.string; import dmd.astenums; import dmd.arraytypes; +import dmd.ctfeexpr; import dmd.dmodule; import dmd.errors; import dmd.expression; diff --git a/dmd/compiler.h b/dmd/compiler.h index c7cbce3bd7f..74351edb449 100644 --- a/dmd/compiler.h +++ b/dmd/compiler.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/cond.d b/dmd/cond.d index a8d099433a2..1b32ff774c8 100644 --- a/dmd/cond.d +++ b/dmd/cond.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/version.html, Conditional Compilation) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cond.d, _cond.d) @@ -29,6 +29,7 @@ import dmd.globals; import dmd.identifier; import dmd.location; import dmd.mtype; +import dmd.optimize; import dmd.typesem; import dmd.common.outbuffer; import dmd.rootobject; diff --git a/dmd/cond.h b/dmd/cond.h index d02ae1321c5..fe497c2da7e 100644 --- a/dmd/cond.h +++ b/dmd/cond.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/console.d b/dmd/console.d index 3b834b6fe4b..a57348c89b5 100644 --- a/dmd/console.d +++ b/dmd/console.d @@ -2,7 +2,7 @@ * Control the various text mode attributes, such as color, when writing text * to the console. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/console.d, _console.d) diff --git a/dmd/constfold.d b/dmd/constfold.d index fc3fd3b2486..7bd9691a429 100644 --- a/dmd/constfold.d +++ b/dmd/constfold.d @@ -5,7 +5,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d) diff --git a/dmd/cparse.d b/dmd/cparse.d index 1d3cf8c1427..82d569450fd 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -3,7 +3,7 @@ * * Specification: C11 * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d, _cparse.d) @@ -250,6 +250,8 @@ final class CParser(AST) : Parser!AST break; case TOK.charLiteral: + case TOK.wcharLiteral: + case TOK.dcharLiteral: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: @@ -331,6 +333,7 @@ final class CParser(AST) : Parser!AST case TOK._Atomic: case TOK.__attribute__: + case TOK.__declspec: Ldeclaration: { @@ -605,15 +608,23 @@ final class CParser(AST) : Parser!AST { Identifier ident; nextToken(); - if (token.value != TOK.identifier) + if (token.value == TOK.identifier) { - error("identifier expected following `goto`"); + ident = token.ident; + nextToken(); + } + else if (token.value == TOK.mul) + { + /* https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + */ + error("`goto *` computed goto extension is not supported"); ident = null; + cparseUnaryExp(); // parse and throw away } else { - ident = token.ident; - nextToken(); + error("identifier expected following `goto`"); + ident = null; } s = new AST.GotoStatement(loc, ident); check(TOK.semicolon, "`goto` statement"); @@ -727,6 +738,12 @@ final class CParser(AST) : Parser!AST nextToken(); break; + case TOK.wcharLiteral: + e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tuns16); + nextToken(); + break; + + case TOK.dcharLiteral: case TOK.uns32Literal: e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32); nextToken(); @@ -1050,6 +1067,14 @@ final class CParser(AST) : Parser!AST break; } + case TOK.andAnd: + /* https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + */ + error("unary `&&` computed goto extension is not supported"); + nextToken(); + e = cparseCastExp(); + break; + case TOK._Alignof: { nextToken(); @@ -1892,7 +1917,16 @@ final class CParser(AST) : Parser!AST if (specifier.alignExps) error("no alignment-specifier for typedef declaration"); // C11 6.7.5-2 + if (specifier.vector_size) + { + auto length = new AST.IntegerExp(token.loc, specifier.vector_size / dt.size(), AST.Type.tuns32); + auto tsa = new AST.TypeSArray(dt, length); + dt = new AST.TypeVector(tsa); + specifier.vector_size = 0; // used it up + } + bool isalias = true; + Identifier idt; if (auto ts = dt.isTypeStruct()) { if (ts.sym.isAnonymous()) @@ -1902,6 +1936,7 @@ final class CParser(AST) : Parser!AST ts.sym.ident = id; isalias = false; } + idt = ts.sym.ident; } else if (auto te = dt.isTypeEnum()) { @@ -1911,24 +1946,25 @@ final class CParser(AST) : Parser!AST te.sym.ident = id; isalias = false; } + idt = te.sym.ident; } else if (auto tt = dt.isTypeTag()) { - if (tt.id || tt.tok == TOK.enum_) - { - if (!tt.id && id) - /* This applies for enums declared as - * typedef enum {A} E; - */ - tt.id = id; - Specifier spec; - declareTag(tt, spec); - } + if (!tt.id && id) + /* This applies for enums declared as + * typedef enum {A} E; + */ + tt.id = id; + Specifier spec; + declareTag(tt, spec); + idt = tt.id; } if (isalias) { + //printf("AliasDeclaration %s %s\n", id.toChars(), dt.toChars()); auto ad = new AST.AliasDeclaration(token.loc, id, dt); - ad.adFlags |= ad.hidden; // do not print when generating .di files + if (id == idt) + ad.adFlags |= ad.hidden; // do not print when generating .di files s = ad; } @@ -2025,6 +2061,9 @@ final class CParser(AST) : Parser!AST } symbols.push(s); } + if (level == LVL.global && !id) + error("expected identifier for declaration"); + first = false; switch (token.value) @@ -2167,6 +2206,7 @@ final class CParser(AST) : Parser!AST * C11 Initialization * initializer: * assignment-expression + * { } // C23 6.7.10 addition * { initializer-list } * { initializer-list , } * @@ -2197,6 +2237,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 */ @@ -2738,7 +2784,7 @@ final class CParser(AST) : Parser!AST private AST.Type cparseDeclarator(DTR declarator, AST.Type tbase, out Identifier pident, ref Specifier specifier) { - //printf("cparseDeclarator(%d, %p)\n", declarator, t); + //printf("cparseDeclarator(%d, %s)\n", declarator, tbase.toChars()); AST.Types constTypes; // all the Types that will need `const` applied to them /* Insert tx -> t into @@ -2757,6 +2803,7 @@ final class CParser(AST) : Parser!AST AST.Type parseDecl(AST.Type t) { + //printf("parseDecl() t: %s\n", t.toChars()); AST.Type ts; while (1) { @@ -2772,9 +2819,18 @@ final class CParser(AST) : Parser!AST break; case TOK.leftParenthesis: // ( declarator ) + //printf("leftParen\n"); /* like: T (*fp)(); * T ((*fp))(); */ + auto tk = &token; + if (!isCDeclarator(tk, declarator)) + { + /* Not ( declarator ), might be parameter-list + */ + ts = t; + break; + } nextToken(); if (token.value == TOK.__stdcall) // T (__stdcall*fp)(); @@ -2788,6 +2844,7 @@ final class CParser(AST) : Parser!AST break; case TOK.mul: // pointer + //printf("star\n"); t = new AST.TypePointer(t); nextToken(); // add post fixes const/volatile/restrict/_Atomic @@ -2799,6 +2856,7 @@ final class CParser(AST) : Parser!AST continue; default: + //printf("default %s\n", token.toChars()); if (declarator == DTR.xdirect) { if (!t || t.isTypeIdentifier()) @@ -2916,7 +2974,7 @@ final class CParser(AST) : Parser!AST if (specifier._pure) stc |= STC.pure_; AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, stc); - // tf = tf.addSTC(storageClass); // TODO + //tf = tf.addSTC(storageClass); // TODO insertTx(ts, tf, t); // ts -> ... -> tf -> t if (ts != tf) @@ -2929,6 +2987,8 @@ final class CParser(AST) : Parser!AST } break; } + if (declarator == DTR.xdirect && !pident) + error("expected identifier for declarator"); return ts; } @@ -4242,6 +4302,7 @@ final class CParser(AST) : Parser!AST case TOK.rightParenthesis: case TOK.rightBracket: case TOK.endOfFile: + case TOK.endOfLine: if (!any) return false; break; @@ -4558,6 +4619,7 @@ final class CParser(AST) : Parser!AST */ private bool isCDeclarator(ref Token* pt, DTR declarator) { + //printf("isCDeclarator()\n"); auto t = pt; while (1) { @@ -4580,6 +4642,8 @@ final class CParser(AST) : Parser!AST else if (t.value == TOK.leftParenthesis) { t = peek(t); + if (t.value == TOK.__stdcall) + t = peek(t); if (!isCDeclarator(t, declarator)) return false; if (t.value != TOK.rightParenthesis) @@ -4907,6 +4971,8 @@ final class CParser(AST) : Parser!AST { case TOK.identifier: case TOK.charLiteral: + case TOK.wcharLiteral: + case TOK.dcharLiteral: case TOK.int32Literal: case TOK.uns32Literal: case TOK.int64Literal: @@ -5771,6 +5837,9 @@ final class CParser(AST) : Parser!AST buf.writeByte(0); auto slice = buf.peekChars()[0 .. length]; resetDefineLines(slice); // reset lexer + auto save = eSink; + auto eLatch = new ErrorSinkLatch(); + eSink = eLatch; const(char)* endp = &slice[length - 7]; @@ -5778,40 +5847,40 @@ final class CParser(AST) : Parser!AST // indexed by Identifier, returns index into symbols[] // The memory for this is leaked - void addVar(AST.VarDeclaration v) + void addVar(AST.Dsymbol s) { - //printf("addVar() %s\n", v.toChars()); - v.isCmacro(true); // mark it as coming from a C #define + //printf("addVar() %s\n", s.toChars()); + if (auto v = s.isVarDeclaration()) + v.isCmacro(true); // mark it as coming from a C #define /* If it's already defined, replace the earlier * definition */ - if (size_t* pd = cast(void*)v.ident in defineTab) + if (size_t* pd = cast(void*)s.ident in defineTab) { //printf("replacing %s\n", v.toChars()); - (*symbols)[*pd] = v; + (*symbols)[*pd] = s; return; } - defineTab[cast(void*)v.ident] = symbols.length; - symbols.push(v); + defineTab[cast(void*)s.ident] = symbols.length; + symbols.push(s); } - Token n; - while (p < endp) { if (p[0 .. 7] == "#define") { p += 7; - scan(&n); - //printf("%s\n", n.toChars()); - if (n.value == TOK.identifier) + nextToken(); + //printf("define %s\n", token.toChars()); + if (token.value == TOK.identifier) { - auto id = n.ident; - scan(&n); + auto id = token.ident; + const params = *p == '('; + nextToken(); AST.Type t; - switch (n.value) + switch (token.value) { case TOK.endOfLine: // #define identifier nextDefineLine(); @@ -5819,14 +5888,16 @@ final class CParser(AST) : Parser!AST case TOK.int32Literal: case TOK.charLiteral: t = AST.Type.tint32; goto Linteger; + case TOK.wcharLiteral: t = AST.Type.tuns16; goto Linteger; + case TOK.dcharLiteral: case TOK.uns32Literal: t = AST.Type.tuns32; goto Linteger; case TOK.int64Literal: t = AST.Type.tint64; goto Linteger; case TOK.uns64Literal: t = AST.Type.tuns64; goto Linteger; Linteger: - const intvalue = n.intvalue; - scan(&n); - if (n.value == TOK.endOfLine) + const intvalue = token.intvalue; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = intvalue; @@ -5847,9 +5918,9 @@ final class CParser(AST) : Parser!AST case TOK.imaginary80Literal: t = AST.Type.timaginary80; goto Lfloat; Lfloat: - const floatvalue = n.floatvalue; - scan(&n); - if (n.value == TOK.endOfLine) + const floatvalue = token.floatvalue; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = floatvalue; @@ -5863,11 +5934,11 @@ final class CParser(AST) : Parser!AST break; case TOK.string_: - const str = n.ustring; - const len = n.len; - const postfix = n.postfix; - scan(&n); - if (n.value == TOK.endOfLine) + const str = token.ustring; + const len = token.len; + const postfix = token.postfix; + nextToken(); + if (token.value == TOK.endOfLine) { /* Declare manifest constant: * enum id = "string"; @@ -5880,6 +5951,39 @@ final class CParser(AST) : Parser!AST } break; + case TOK.leftParenthesis: + /* Look for: + * #define ID ( expression ) + * and rewrite it to a template function: + * auto ID()() { return expression; } + */ + if (params) + break; // no parameters + nextToken(); + eLatch.sawErrors = false; + auto exp = cparseExpression(); + if (eLatch.sawErrors) // parsing errors + break; // abandon this #define + if (token.value != TOK.rightParenthesis) + break; + nextToken(); + if (token.value != TOK.endOfLine) + break; + auto ret = new AST.ReturnStatement(exp.loc, exp); + auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0); + StorageClass stc = STC.auto_; + auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc); + auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0); + fd.fbody = ret; + AST.Dsymbols* decldefs = new AST.Dsymbols(); + decldefs.push(fd); + AST.TemplateParameters* tpl = new AST.TemplateParameters(); + AST.Expression constraint = null; + auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false); + addVar(tempdecl); + nextDefineLine(); + continue; + default: break; } @@ -5888,8 +5992,8 @@ final class CParser(AST) : Parser!AST } else { - scan(&n); - if (n.value != TOK.endOfLine) + scan(&token); + if (token.value != TOK.endOfLine) { skipToNextLine(); } @@ -5897,6 +6001,7 @@ final class CParser(AST) : Parser!AST nextDefineLine(); } + eSink = save; defines = buf; } diff --git a/dmd/cppmangle.d b/dmd/cppmangle.d index 55844ddf606..90b6295ab2f 100644 --- a/dmd/cppmangle.d +++ b/dmd/cppmangle.d @@ -4,7 +4,7 @@ * This is the POSIX side of the implementation. * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d) diff --git a/dmd/cppmanglewin.d b/dmd/cppmanglewin.d index e154650e5c8..de9255b2996 100644 --- a/dmd/cppmanglewin.d +++ b/dmd/cppmanglewin.d @@ -1,7 +1,7 @@ /** * Do mangling for C++ linkage for Digital Mars C++ and Microsoft Visual C++. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmanglewin.d, _cppmanglewin.d) diff --git a/dmd/ctfe.h b/dmd/ctfe.h index bb92778e253..72d895c7150 100644 --- a/dmd/ctfe.h +++ b/dmd/ctfe.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/ctfeexpr.d b/dmd/ctfeexpr.d index ddfb57d22d7..5fe1e7dccb0 100644 --- a/dmd/ctfeexpr.d +++ b/dmd/ctfeexpr.d @@ -1,7 +1,7 @@ /** * CTFE for expressions involving pointers, slices, array concatenation etc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d) @@ -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; @@ -35,75 +36,98 @@ import dmd.root.rmem; import dmd.tokens; import dmd.visitor; - -/*********************************************************** - * A reference to a class, or an interface. We need this when we - * point to a base class (we must record what the type is). +/****************************************************************/ +/* A type meant as a union of all the Expression types, + * to serve essentially as a Variant that will sit on the stack + * during CTFE to reduce memory consumption. */ -extern (C++) final class ClassReferenceExp : Expression +extern (D) struct UnionExp { - StructLiteralExp value; - - extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) @safe + // yes, default constructor does nothing + extern (D) this(Expression e) nothrow { - super(loc, EXP.classReference); - assert(lit && lit.sd && lit.sd.isClassDeclaration()); - this.value = lit; - this.type = type; + memcpy(&this, cast(void*)e, e.size); } - ClassDeclaration originalClass() + /* Extract pointer to Expression + */ + extern (D) Expression exp() return nothrow { - return value.sd.isClassDeclaration(); + return cast(Expression)&u; } - // Return index of the field, or -1 if not found - private int getFieldIndex(Type fieldtype, uint fieldoffset) + /* Convert to an allocated Expression + */ + extern (D) Expression copy() { - ClassDeclaration cd = originalClass(); - uint fieldsSoFar = 0; - for (size_t j = 0; j < value.elements.length; j++) + Expression e = exp(); + //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr); + assert(e.size <= u.sizeof); + switch (e.op) { - while (j - fieldsSoFar >= cd.fields.length) - { - fieldsSoFar += cd.fields.length; - cd = cd.baseClass; - } - VarDeclaration v2 = cd.fields[j - fieldsSoFar]; - if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size()) - { - return cast(int)(value.elements.length - fieldsSoFar - cd.fields.length + (j - fieldsSoFar)); - } + case EXP.cantExpression: return CTFEExp.cantexp; + case EXP.voidExpression: return CTFEExp.voidexp; + case EXP.break_: return CTFEExp.breakexp; + case EXP.continue_: return CTFEExp.continueexp; + case EXP.goto_: return CTFEExp.gotoexp; + default: return e.copy(); } - return -1; } - // Return index of the field, or -1 if not found - // Same as getFieldIndex, but checks for a direct match with the VarDeclaration - int findFieldIndexByName(VarDeclaration v) - { - ClassDeclaration cd = originalClass(); - size_t fieldsSoFar = 0; - for (size_t j = 0; j < value.elements.length; j++) - { - while (j - fieldsSoFar >= cd.fields.length) - { - fieldsSoFar += cd.fields.length; - cd = cd.baseClass; - } - VarDeclaration v2 = cd.fields[j - fieldsSoFar]; - if (v == v2) - { - return cast(int)(value.elements.length - fieldsSoFar - cd.fields.length + (j - fieldsSoFar)); - } - } - return -1; - } +private: + // Ensure that the union is suitably aligned. + align(8) union _AnonStruct_u + { + char[__traits(classInstanceSize, Expression)] exp; + char[__traits(classInstanceSize, IntegerExp)] integerexp; + char[__traits(classInstanceSize, ErrorExp)] errorexp; + char[__traits(classInstanceSize, RealExp)] realexp; + char[__traits(classInstanceSize, ComplexExp)] complexexp; + char[__traits(classInstanceSize, SymOffExp)] symoffexp; + char[__traits(classInstanceSize, StringExp)] stringexp; + char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp; + char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp; + char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp; + char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp; + char[__traits(classInstanceSize, NullExp)] nullexp; + char[__traits(classInstanceSize, DotVarExp)] dotvarexp; + char[__traits(classInstanceSize, AddrExp)] addrexp; + char[__traits(classInstanceSize, IndexExp)] indexexp; + char[__traits(classInstanceSize, SliceExp)] sliceexp; + char[__traits(classInstanceSize, VectorExp)] vectorexp; + } + + _AnonStruct_u u; +} - override void accept(Visitor v) - { - v.visit(this); - } +void emplaceExp(T : Expression, Args...)(void* p, Args args) +{ + static if (__VERSION__ < 2099) + const init = typeid(T).initializer; + else + const init = __traits(initSymbol, T); + p[0 .. __traits(classInstanceSize, T)] = init[]; + (cast(T)p).__ctor(args); +} + +void emplaceExp(T : UnionExp)(T* p, Expression e) nothrow +{ + memcpy(p, cast(void*)e, e.size); +} + +// Generate an error message when this exception is not caught +void generateUncaughtError(ThrownExceptionExp tee) +{ + UnionExp ue = void; + Expression e = resolveSlice((*tee.thrown.value.elements)[0], &ue); + StringExp se = e.toStringExp(); + error(tee.thrown.loc, "uncaught CTFE exception `%s(%s)`", tee.thrown.type.toChars(), se ? se.toChars() : e.toChars()); + /* Also give the line where the throw statement was. We won't have it + * in the case where the ThrowStatement is generated internally + * (eg, in ScopeStatement) + */ + if (tee.loc.isValid() && !tee.loc.equals(tee.thrown.loc)) + .errorSupplemental(tee.loc, "thrown from here"); } /************************* @@ -111,7 +135,7 @@ extern (C++) final class ClassReferenceExp : Expression * 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) { @@ -121,102 +145,8 @@ int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pur return -1; } -/*********************************************************** - * Fake class which holds the thrown exception. - * Used for implementing exception handling. - */ -extern (C++) final class ThrownExceptionExp : Expression -{ - ClassReferenceExp thrown; // the thing being tossed - - extern (D) this(const ref Loc loc, ClassReferenceExp victim) @safe - { - super(loc, EXP.thrownException); - this.thrown = victim; - this.type = victim.type; - } - - override const(char)* toChars() const - { - return "CTFE ThrownException"; - } - - // Generate an error message when this exception is not caught - extern (D) void generateUncaughtError() - { - UnionExp ue = void; - Expression e = resolveSlice((*thrown.value.elements)[0], &ue); - StringExp se = e.toStringExp(); - error(thrown.loc, "uncaught CTFE exception `%s(%s)`", thrown.type.toChars(), se ? se.toChars() : e.toChars()); - /* Also give the line where the throw statement was. We won't have it - * in the case where the ThrowStatement is generated internally - * (eg, in ScopeStatement) - */ - if (loc.isValid() && !loc.equals(thrown.loc)) - .errorSupplemental(loc, "thrown from here"); - } - - override void accept(Visitor v) - { - v.visit(this); - } -} - -/*********************************************************** - * This type is only used by the interpreter. - */ -extern (C++) final class CTFEExp : Expression -{ - extern (D) this(EXP tok) - { - super(Loc.initial, tok); - type = Type.tvoid; - } - - override const(char)* toChars() const - { - switch (op) - { - case EXP.cantExpression: - return ""; - case EXP.voidExpression: - return "cast(void)0"; - case EXP.showCtfeContext: - return ""; - case EXP.break_: - return ""; - case EXP.continue_: - return ""; - case EXP.goto_: - return ""; - default: - assert(0); - } - } - - extern (D) __gshared CTFEExp cantexp; - extern (D) __gshared CTFEExp voidexp; - extern (D) __gshared CTFEExp breakexp; - extern (D) __gshared CTFEExp continueexp; - extern (D) __gshared CTFEExp gotoexp; - /* Used when additional information is needed regarding - * a ctfe error. - */ - extern (D) __gshared CTFEExp showcontext; - - extern (D) static bool isCantExp(const Expression e) @safe - { - return e && e.op == EXP.cantExpression; - } - - extern (D) static bool isGotoExp(const Expression e) @safe - { - return e && e.op == EXP.goto_; - } -} - // 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); } @@ -224,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 (;;) @@ -664,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)); @@ -706,8 +636,11 @@ bool isSafePointerCast(Type srcPointee, Type destPointee) // It's OK if function pointers differ only in safe/pure/nothrow if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction) + { + import dmd.typesem : covariant; return srcPointee.covariant(destPointee) == Covariant.yes || destPointee.covariant(srcPointee) == Covariant.yes; + } // it's OK to cast to void* if (destPointee.ty == Tvoid) return true; @@ -812,14 +745,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); } @@ -865,14 +798,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 { @@ -907,9 +840,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), @@ -1049,7 +982,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) { @@ -1068,25 +1001,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 @@ -1176,7 +1109,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()) @@ -1187,7 +1120,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_; } @@ -1341,8 +1274,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]; @@ -1361,11 +1294,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_) @@ -2071,9 +2002,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. @@ -2090,9 +2020,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) { diff --git a/dmd/ctorflow.d b/dmd/ctorflow.d index 128c698ab87..ba5240e5e10 100644 --- a/dmd/ctorflow.d +++ b/dmd/ctorflow.d @@ -1,7 +1,7 @@ /** * Manage flow analysis for constructors. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d, _ctorflow.d) diff --git a/dmd/dcast.d b/dmd/dcast.d index 8ab71fb8582..628c688979f 100644 --- a/dmd/dcast.d +++ b/dmd/dcast.d @@ -1,7 +1,7 @@ /** * Semantic analysis for cast-expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d) @@ -24,6 +24,7 @@ import dmd.dinterpret; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.errors; import dmd.escape; import dmd.expression; @@ -38,6 +39,7 @@ import dmd.init; import dmd.intrange; import dmd.mtype; import dmd.opover; +import dmd.optimize; import dmd.root.ctfloat; import dmd.common.outbuffer; import dmd.root.rmem; @@ -67,7 +69,6 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t) Expression visit(Expression e) { // printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars()); - if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t)) { // no need for an extra cast when matching is exact @@ -801,8 +802,8 @@ extern(C++) MATCH implicitConvTo(Expression e, Type t) return result; } - else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) - { + else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer)) + { // Tpointer because ImportC eagerly converts Tsarray to Tpointer result = MATCH.exact; // Convert array literal to vector type TypeVector tv = tb.isTypeVector(); @@ -1486,6 +1487,10 @@ MATCH cimplicitConvTo(Expression e, Type t) if (tb.equals(typeb)) return MATCH.exact; + + if (tb.isTypeVector() || typeb.isTypeVector()) + return implicitConvTo(e, t); // permissive checking doesn't apply to vectors + if ((typeb.isintegral() || typeb.isfloating()) && (tb.isintegral() || tb.isfloating())) return MATCH.convert; @@ -2297,9 +2302,10 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) ae.type = tp; } } - else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray)) + else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer)) { // Convert array literal to vector type + // The Tpointer case comes from C eagerly converting Tsarray to Tpointer TypeVector tv = tb.isTypeVector(); TypeSArray tbase = tv.basetype.isTypeSArray(); assert(tbase.ty == Tsarray); diff --git a/dmd/dclass.d b/dmd/dclass.d index 6113320b9dd..1aab1f0a1e6 100644 --- a/dmd/dclass.d +++ b/dmd/dclass.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d) @@ -180,7 +180,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration int cppDtorVtblIndex = -1; /// to prevent recursive attempts - private bool inuse; + bool inuse; ThreeState isabstract; @@ -370,7 +370,7 @@ version (IN_LLVM) {} else 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); } @@ -471,67 +471,6 @@ version (IN_LLVM) {} else 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'. @@ -658,7 +597,7 @@ version (IN_LLVM) {} else fieldState.offset = structsize; foreach (s; *members) { - s.setFieldOffset(this, fieldState, false); + s.setFieldOffset(this, &fieldState, false); } sizeok = Sizeok.done; @@ -678,7 +617,7 @@ version (IN_LLVM) {} else 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, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors); if (!s) { //printf("not found\n"); @@ -734,6 +673,7 @@ version (IN_LLVM) {} else void searchVtbl(ref Dsymbols vtbl) { + import dmd.typesem : covariant; bool seenInterfaceVirtual; foreach (s; vtbl) { diff --git a/dmd/declaration.d b/dmd/declaration.d index aab3d626d85..4e8e81f8005 100644 --- a/dmd/declaration.d +++ b/dmd/declaration.d @@ -2,7 +2,7 @@ * Miscellaneous declarations, including typedef, alias, variable declarations including the * implicit this declaration, type tuples, ClassInfo, ModuleInfo and various TypeInfos. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d, _declaration.d) @@ -246,11 +246,6 @@ extern (C++) abstract class Declaration : Dsymbol enum nounderscore = 4; // don't prepend _ to mangled name enum hidden = 8; // don't print this in .di files -version (IN_LLVM) {} else -{ - Symbol* isym; // import version of csym -} - // overridden symbol with pragma(mangle, "...") const(char)[] mangleOverride; @@ -424,18 +419,6 @@ version (IN_LLVM) {} else 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; @@ -1239,88 +1222,6 @@ version (IN_LLVM) return v; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); - - if (aliasTuple) - { - // If this variable was really a tuple, set the offsets for the tuple fields - aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); - return; - } - - if (!isField()) - return; - assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter))); - - //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); - - /* Fields that are tuples appear both as part of TupleDeclarations and - * as members. That means ignore them if they are already a field. - */ - if (offset) - { - // already a field - fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 - return; - } - for (size_t i = 0; i < ad.fields.length; i++) - { - if (ad.fields[i] == this) - { - // already a field - fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 - return; - } - } - - // Check for forward referenced types which will fail the size() call - Type t = type.toBasetype(); - if (storage_class & STC.ref_) - { - // References are the size of a pointer - t = Type.tvoidptr; - } - Type tv = t.baseElemOf(); - if (tv.ty == Tstruct) - { - auto ts = cast(TypeStruct)tv; - assert(ts.sym != ad); // already checked in ad.determineFields() - if (!ts.sym.determineSize(loc)) - { - type = Type.terror; - errors = true; - return; - } - } - - // List in ad.fields. Even if the type is error, it's necessary to avoid - // pointless error diagnostic "more initializers than fields" on struct literal. - ad.fields.push(this); - - if (t.ty == Terror) - return; - - /* If coming after a bit field in progress, - * advance past the field - */ - fieldState.inFlight = false; - - const sz = t.size(loc); - assert(sz != SIZE_INVALID && sz < uint.max); - uint memsize = cast(uint)sz; // size of member - uint memalignsize = target.fieldalign(t); // size of member for alignment purposes - offset = placeField( - fieldState.offset, - memsize, memalignsize, alignment, - ad.structsize, ad.alignsize, - isunion); - - //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); - } - override const(char)* kind() const { return "variable"; @@ -1828,211 +1729,6 @@ extern (C++) class BitFieldDeclaration : VarDeclaration : (1L << (width - 1)) - 1); return v; } - - override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - enum log = false; - static if (log) - { - printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars()); - void print(const ref FieldState fieldState) - { - fieldState.print(); - printf(" fieldWidth = %d bits\n", fieldWidth); - } - print(fieldState); - } - - Type t = type.toBasetype(); - const bool anon = isAnonymous(); - - // List in ad.fields. Even if the type is error, it's necessary to avoid - // pointless error diagnostic "more initializers than fields" on struct literal. - if (!anon) - ad.fields.push(this); - - if (t.ty == Terror) - return; - - const sz = t.size(loc); - assert(sz != SIZE_INVALID && sz < uint.max); - uint memsize = cast(uint)sz; // size of member - uint memalignsize = target.fieldalign(t); // size of member for alignment purposes - if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize); - - if (fieldWidth == 0 && !anon) - error(loc, "named bit fields cannot have 0 width"); - if (fieldWidth > memsize * 8) - error(loc, "bit field width %d is larger than type", fieldWidth); - - const style = target.c.bitFieldStyle; - - void startNewField() - { - if (log) printf("startNewField()\n"); - uint alignsize; - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - if (fieldWidth > 32) - alignsize = memalignsize; - else if (fieldWidth > 16) - alignsize = 4; - else if (fieldWidth > 8) - alignsize = 2; - else - alignsize = 1; - } - else - alignsize = memsize; // not memalignsize - - uint dummy; - offset = placeField( - fieldState.offset, - memsize, alignsize, alignment, - ad.structsize, - (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize, - isunion); - - fieldState.inFlight = true; - fieldState.fieldOffset = offset; - fieldState.bitOffset = 0; - fieldState.fieldSize = memsize; - } - - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - if (fieldWidth == 0) - { - if (!isunion) - { - // Use type of zero width field to align to next field - fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - - if (ad.alignsize == 0) - ad.alignsize = 1; - if (!anon && - ad.alignsize < memalignsize) - ad.alignsize = memalignsize; - } - else if (style == TargetC.BitFieldStyle.MS) - { - if (ad.alignsize == 0) - ad.alignsize = 1; - if (fieldWidth == 0) - { - if (fieldState.inFlight && !isunion) - { - // documentation says align to next int - //const alsz = cast(uint)Type.tint32.size(); - const alsz = memsize; // but it really does this - fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - } - else if (style == TargetC.BitFieldStyle.DM) - { - if (anon && fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0)) - return; // this probably should be a bug in DMC - if (ad.alignsize == 0) - ad.alignsize = 1; - if (fieldWidth == 0) - { - if (fieldState.inFlight && !isunion) - { - const alsz = memsize; - fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; - } - } - - if (!fieldState.inFlight) - { - //printf("not in flight\n"); - startNewField(); - } - else if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - // If the bit-field spans more units of alignment than its type, - // start a new field at the next alignment boundary. - if (fieldState.bitOffset == fieldState.fieldSize * 8 && - fieldState.bitOffset + fieldWidth > memalignsize * 8) - { - if (log) printf("more units of alignment than its type\n"); - startNewField(); // the bit field is full - } - else - { - // if alignment boundary is crossed - uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset; - uint end = start + fieldWidth; - //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize); - if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8)) - { - if (log) printf("alignment is crossed\n"); - startNewField(); - } - } - } - else if (style == TargetC.BitFieldStyle.DM || - style == TargetC.BitFieldStyle.MS) - { - if (memsize != fieldState.fieldSize || - fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8) - { - //printf("new field\n"); - startNewField(); - } - } - else - assert(0); - - offset = fieldState.fieldOffset; - bitOffset = fieldState.bitOffset; - - const pastField = bitOffset + fieldWidth; - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - auto size = (pastField + 7) / 8; - fieldState.fieldSize = size; - //printf(" offset: %d, size: %d\n", offset, size); - if (isunion) - { - const newstructsize = offset + size; - if (newstructsize > ad.structsize) - ad.structsize = newstructsize; - } - else - ad.structsize = offset + size; - } - else - fieldState.fieldSize = memsize; - //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize); - //print(fieldState); - - if (!isunion) - { - fieldState.offset = offset + fieldState.fieldSize; - fieldState.bitOffset = pastField; - } - - //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize); - //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); - } } /*********************************************************** diff --git a/dmd/declaration.h b/dmd/declaration.h index 85331865728..5cfa428018f 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -54,7 +54,7 @@ struct AttributeViolation; #define STCforeach 0x4000ULL /// variable for foreach loop #define STCvariadic 0x8000ULL /// the `variadic` parameter in: T foo(T a, U b, V variadic...) - // 0x10000ULL + #define STCconstscoperef 0x10000ULL /// when `in` means const|scope|ref #define STCtemplateparameter 0x20000ULL /// template parameter #define STCref 0x40000ULL /// `ref` #define STCscope 0x80000ULL /// `scope` @@ -118,15 +118,11 @@ class Declaration : public Dsymbol LINK _linkage; // may be `LINK::system`; use `resolvedLinkage()` to resolve it short inuse; // used to detect cycles uint8_t adFlags; -#if !IN_LLVM - Symbol* isym; // import version of csym -#endif DString mangleOverride; // overridden symbol with pragma(mangle, "...") 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 @@ -292,7 +288,6 @@ class VarDeclaration : public Declaration bool systemInferred(bool v); static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined); VarDeclaration *syntaxCopy(Dsymbol *) override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final; const char *kind() const override; AggregateDeclaration *isThis() override final; bool needThis() override final; @@ -875,6 +870,7 @@ class StaticCtorDeclaration : public FuncDeclaration class SharedStaticCtorDeclaration final : public StaticCtorDeclaration { public: + bool standalone; SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *) override; SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() override { return this; } diff --git a/dmd/delegatize.d b/dmd/delegatize.d index 490ef56646f..62800d3fdb7 100644 --- a/dmd/delegatize.d +++ b/dmd/delegatize.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#lazy-params, Lazy Parameters) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d, _delegatize.d) diff --git a/dmd/denum.d b/dmd/denum.d index 7ba993781de..c872ba3c5df 100644 --- a/dmd/denum.d +++ b/dmd/denum.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d) @@ -83,33 +83,7 @@ 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) - return; - ScopeDsymbol.setScope(sc); - } - - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { if (isAnonymous()) return Dsymbol.oneMembers(members, ps, ident); @@ -126,19 +100,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 { diff --git a/dmd/dimport.d b/dmd/dimport.d index d74c8603420..b083c03aebe 100644 --- a/dmd/dimport.d +++ b/dmd/dimport.d @@ -1,7 +1,7 @@ /** * A `Dsymbol` representing a renamed import. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d) @@ -222,48 +222,6 @@ extern (C++) final class Import : Dsymbol return global.errors != errors; } - override void importAll(Scope* sc) - { - if (mod) return; // Already done - - /* - * https://issues.dlang.org/show_bug.cgi?id=15525 - * - * Loading the import has failed, - * most likely because of parsing errors. - * Therefore we cannot trust the resulting AST. - */ - if (load(sc)) - { - // https://issues.dlang.org/show_bug.cgi?id=23873 - // For imports that are not at module or function level, - // e.g. aggregate level, the import symbol is added to the - // symbol table and later semantic is performed on it. - // This leads to semantic analysis on an malformed AST - // which causes all kinds of segfaults. - // The fix is to note that the module has errors and avoid - // semantic analysis on it. - if(mod) - mod.errors = true; - return; - } - - if (!mod) return; // Failed - - if (sc.stc & STC.static_) - isstatic = true; - mod.importAll(null); - mod.checkImportDeprecation(loc, sc); - if (sc.explicitVisibility) - visibility = sc.visibility; - if (!isstatic && !aliasId && !names.length) - sc.scopesym.importScope(mod, visibility); - // Enable access to pkgs/mod as soon as posible, because compiler - // can traverse them before the import gets semantic (Issue: 21501) - if (!aliasId && !names.length) - addPackageAccess(sc.scopesym); - } - /******************************* * Mark the imported packages as accessible from the current * scope. This access check is necessary when using FQN b/c @@ -305,62 +263,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); - if (aliasdecls.length) - { - if (!mod) - importAll(sc); - - sc = sc.push(mod); - sc.visibility = visibility; - foreach (ad; aliasdecls) - ad.setScope(sc); - sc = sc.pop(); - } - } - - 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 diff --git a/dmd/dinterpret.d b/dmd/dinterpret.d index 56f17f41839..65d9e87b396 100644 --- a/dmd/dinterpret.d +++ b/dmd/dinterpret.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE)) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d) diff --git a/dmd/dmacro.d b/dmd/dmacro.d index 6e6c4b17e99..c04fbec731d 100644 --- a/dmd/dmacro.d +++ b/dmd/dmacro.d @@ -1,7 +1,7 @@ /** * Text macro processor for Ddoc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d, _dmacro.d) diff --git a/dmd/dmangle.d b/dmd/dmangle.d index c58b5857482..15b77eaac4c 100644 --- a/dmd/dmangle.d +++ b/dmd/dmangle.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d) @@ -152,6 +152,7 @@ import dmd.identifier; import dmd.mtype; import dmd.root.ctfloat; import dmd.common.outbuffer; +import dmd.optimize; import dmd.root.aav; import dmd.root.string; import dmd.root.stringtable; @@ -527,7 +528,7 @@ void mangleParameter(Parameter p, ref OutBuffer buf, ref Backref backref) if (stc & STC.return_) buf.writestring("Nk"); // return - switch (stc & (STC.IOR | STC.lazy_)) + switch (stc & ((STC.IOR | STC.lazy_) & ~STC.constscoperef)) { case 0: break; diff --git a/dmd/dmodule.d b/dmd/dmodule.d index 055ac237a69..86dab92bf61 100644 --- a/dmd/dmodule.d +++ b/dmd/dmodule.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/module.html, Modules) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d, _dmodule.d) @@ -33,6 +33,7 @@ import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.file_manager; +import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; @@ -274,22 +275,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); @@ -421,10 +406,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 + SearchOptFlags searchCacheFlags; // cached flags + bool insearch; /** * A root module is one that will be compiled all the way to @@ -852,7 +837,7 @@ version (IN_LLVM) } else { - const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + const bool doUnittests = global.params.parsingUnittestsRequired(); scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink, &global.compileEnv, doUnittests); p.transitionIn = global.params.v.vin; p.nextToken(); @@ -995,70 +980,6 @@ version (IN_LLVM) return this; } - override void importAll(Scope* prevsc) - { - //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - if (_scope) - return; // already done - if (filetype == FileType.ddoc) - { - error(loc, "%s `%s` is a Ddoc file, cannot import it", kind, toPrettyChars); - return; - } - - /* Note that modules get their own scope, from scratch. - * This is so regardless of where in the syntax a module - * gets imported, it is unaffected by context. - * Ignore prevsc. - */ - Scope* sc = Scope.createGlobal(this, global.errorSink); // create root scope - - if (md && md.msg) - md.msg = semanticString(sc, md.msg, "deprecation message"); - - // Add import of "object", even for the "object" module. - // If it isn't there, some compiler rewrites, like - // classinst == classinst -> .object.opEquals(classinst, classinst) - // would fail inside object.d. - if (filetype != FileType.c && - (members.length == 0 || - (*members)[0].ident != Id.object || - (*members)[0].isImport() is null)) - { - auto im = new Import(Loc.initial, null, Id.object, null, 0); - members.shift(im); - } - if (!symtab) - { - // Add all symbols into module's symbol table - symtab = new DsymbolTable(); - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.addMember(sc, sc.scopesym); - } - } - // anything else should be run after addMember, so version/debug symbols are defined - /* Set scope for the symbols so that if we forward reference - * a symbol, it can possibly be resolved on the spot. - * If this works out well, it can be extended to all modules - * before any semantic() on any of them. - */ - setScope(sc); // remember module scope for semantic - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.setScope(sc); - } - for (size_t i = 0; i < members.length; i++) - { - Dsymbol s = (*members)[i]; - s.importAll(sc); - } - sc = sc.pop(); - sc.pop(); // 2 pops because Scope.createGlobal() created 2 - } - /********************************** * Determine if we need to generate an instance of ModuleInfo * for this Module. @@ -1095,55 +1016,14 @@ version (IN_LLVM) } } - 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) + override bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) { if (insearch) // don't follow import cycles return false; insearch = true; scope (exit) insearch = false; - if (flags & IgnorePrivateImports) + if (flags & SearchOpt.ignorePrivateImports) visibility = Visibility(Visibility.Kind.public_); // only consider public imports return super.isPackageAccessible(p, visibility); } @@ -1523,7 +1403,53 @@ extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses) return 0; } - ScopeDsymbol._foreach(null, mod.members, &pushAddClassDg); + _foreach(null, mod.members, &pushAddClassDg); +} + + +alias ForeachDg = int delegate(size_t idx, Dsymbol s); + +/*************************************** + * Expands attribute declarations in members in depth first + * order. Calls dg(size_t symidx, Dsymbol *sym) for each + * member. + * If dg returns !=0, stops and returns that value else returns 0. + * Use this function to avoid the O(N + N^2/2) complexity of + * calculating dim and calling N times getNth. + * Returns: + * last value returned by dg() + */ +int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null) +{ + assert(dg); + if (!members) + return 0; + size_t n = pn ? *pn : 0; // take over index + int result = 0; + foreach (size_t i; 0 .. members.length) + { + import dmd.attrib : AttribDeclaration; + import dmd.dtemplate : TemplateMixin; + + Dsymbol s = (*members)[i]; + if (AttribDeclaration a = s.isAttribDeclaration()) + result = _foreach(sc, a.include(sc), dg, &n); + else if (TemplateMixin tm = s.isTemplateMixin()) + result = _foreach(sc, tm.members, dg, &n); + else if (s.isTemplateInstance()) + { + } + else if (s.isUnitTestDeclaration()) + { + } + else + result = dg(n++, s); + if (result) + break; + } + if (pn) + *pn = n; // update index + return result; } /** @@ -1716,3 +1642,36 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) return buf; } + +/******************************************* + * Look for member of the form: + * const(MemberInfo)[] getMembers(string); + * Returns NULL if not found + */ +extern(C++) FuncDeclaration findGetMembers(ScopeDsymbol dsym) +{ + import dmd.opover : search_function; + Dsymbol s = search_function(dsym, Id.getmembers); + FuncDeclaration fdx = s ? s.isFuncDeclaration() : null; + version (none) + { + // Finish + __gshared TypeFunction tfgetmembers; + if (!tfgetmembers) + { + Scope sc; + sc.eSink = global.errorSink; + auto parameters = new Parameters(); + Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null); + parameters.push(p); + Type tret = null; + TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d); + tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction(); + } + if (fdx) + fdx = fdx.overloadExactMatch(tfgetmembers); + } + if (fdx && fdx.isVirtual()) + fdx = null; + return fdx; +} diff --git a/dmd/doc.d b/dmd/doc.d index 75b4165c44a..1728d673065 100644 --- a/dmd/doc.d +++ b/dmd/doc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/ddoc.html, Documentation Generator) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/doc.d, _doc.d) @@ -753,7 +753,8 @@ void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false) auto a = imp.aliases[i]; auto id = a ? a : imp.names[i]; auto loc = Loc.init; - if (auto symFromId = sc.search(loc, id, null)) + Dsymbol pscopesym; + if (auto symFromId = sc.search(loc, id, pscopesym)) { emitAnchor(buf, symFromId, sc, forHeader); } @@ -1300,7 +1301,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) Type origType = d.originalType ? d.originalType : d.type; if (origType.ty == Tfunction) { - functionToBufferFull(cast(TypeFunction)origType, *buf, d.ident, &hgs, td); + functionToBufferFull(cast(TypeFunction)origType, *buf, d.ident, hgs, td); } else toCBuffer(origType, *buf, d.ident, hgs); @@ -3641,11 +3642,12 @@ struct MarkdownLinkReferences if (id) { auto loc = Loc(); - auto symbol = _scope.search(loc, id, null, IgnoreErrors); + Dsymbol pscopesym; + auto symbol = _scope.search(loc, id, pscopesym, SearchOpt.ignoreErrors); for (size_t i = 1; symbol && i < ids.length; ++i) { id = Identifier.lookup(ids[i].ptr, ids[i].length); - symbol = id !is null ? symbol.search(loc, id, IgnoreErrors) : null; + symbol = id !is null ? symbol.search(loc, id, SearchOpt.ignoreErrors) : null; } if (symbol) link = MarkdownLink(createHref(symbol), null, name, symbol); @@ -5002,7 +5004,8 @@ void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset) auto a = imp.aliases[i]; auto id = a ? a : imp.names[i]; auto loc = Loc.init; - if (auto symFromId = sc.search(loc, id, null)) + Dsymbol pscopesym; + if (auto symFromId = sc.search(loc, id, pscopesym)) { highlightCode(sc, symFromId, buf, offset); } diff --git a/dmd/doc.h b/dmd/doc.h index ebd3094348d..71a66b90cb8 100644 --- a/dmd/doc.h +++ b/dmd/doc.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/dscope.d b/dmd/dscope.d index b3769593dc1..f7b30776496 100644 --- a/dmd/dscope.d +++ b/dmd/dscope.d @@ -3,7 +3,7 @@ * * Not to be confused with the `scope` storage class. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d) @@ -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 { @@ -181,6 +183,10 @@ version (IN_LLVM) 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 @@ -343,13 +349,13 @@ version (IN_LLVM) * Params: * loc = location to use for error messages * ident = name to look up - * pscopesym = if supplied and name is found, set to scope that ident was found in + * pscopesym = if supplied and name is found, set to scope that ident was found in, otherwise set to null * flags = modify search based on flags * * Returns: * symbol if found, null if not */ - extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) + extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, out Dsymbol pscopesym, SearchOptFlags flags = SearchOpt.all) { version (LOGSEARCH) { @@ -370,7 +376,7 @@ version (IN_LLVM) } // This function is called only for unqualified lookup - assert(!(flags & (SearchLocalsOnly | SearchImportsOnly))); + assert(!(flags & (SearchOpt.localsOnly | SearchOpt.importsOnly))); /* If ident is "start at module scope", only look at module scope */ @@ -385,15 +391,14 @@ version (IN_LLVM) if (Dsymbol s = sc.scopesym.isModule()) { //printMsg("\tfound", s); - if (pscopesym) - *pscopesym = sc.scopesym; + pscopesym = sc.scopesym; return s; } } return null; } - Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp) + Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, SearchOptFlags flags, Expression* exp) { import dmd.mtype; if (!ad || !ad.aliasthis) @@ -457,7 +462,7 @@ version (IN_LLVM) return s; } - Dsymbol searchScopes(int flags) + Dsymbol searchScopes(SearchOptFlags flags) { for (Scope* sc = &this; sc; sc = sc.enclosing) { @@ -467,13 +472,13 @@ version (IN_LLVM) //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags); if (sc.scopesym.isModule()) - flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed + flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration()) continue; // C doesn't have struct scope if (Dsymbol s = sc.scopesym.search(loc, ident, flags)) { - if (flags & TagNameSpace) + if (flags & SearchOpt.tagNameSpace) { // ImportC: if symbol is not a tag, look for it in tag table if (!s.isScopeDsymbol()) @@ -485,8 +490,7 @@ version (IN_LLVM) } } //printMsg("\tfound local", s); - if (pscopesym) - *pscopesym = sc.scopesym; + pscopesym = sc.scopesym; return s; } @@ -498,8 +502,7 @@ version (IN_LLVM) if (aliasSym) { //printf("found aliassym: %s\n", aliasSym.toChars()); - if (pscopesym) - *pscopesym = new ExpressionDsymbol(exp); + pscopesym = new ExpressionDsymbol(exp); return aliasSym; } } @@ -512,15 +515,15 @@ version (IN_LLVM) } if (this.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; // First look in local scopes - Dsymbol s = searchScopes(flags | SearchLocalsOnly); + Dsymbol s = searchScopes(flags | SearchOpt.localsOnly); version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s); if (!s) { // Second look in imported modules - s = searchScopes(flags | SearchImportsOnly); + s = searchScopes(flags | SearchOpt.importsOnly); version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s); } return s; @@ -553,8 +556,8 @@ version (IN_LLVM) return null; Scope* sc = &this; Module.clearCache(); - Dsymbol scopesym = null; - Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors); + Dsymbol scopesym; + Dsymbol s = sc.search(Loc.initial, id, scopesym, SearchOpt.ignoreErrors); if (!s) return null; @@ -578,9 +581,9 @@ version (IN_LLVM) return s; } - Dsymbol scopesym = null; + Dsymbol scopesym; // search for exact name first - if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors)) + if (auto s = search(Loc.initial, ident, scopesym, SearchOpt.ignoreErrors)) return s; return speller!scope_search_fp(ident.toString()); } @@ -826,4 +829,16 @@ version (IN_LLVM) { 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; + } } diff --git a/dmd/dstruct.d b/dmd/dstruct.d index 0223e3d773e..ce75984107e 100644 --- a/dmd/dstruct.d +++ b/dmd/dstruct.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d, _dstruct.d) @@ -272,23 +272,6 @@ version (IN_LLVM) {} else 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"; @@ -315,7 +298,7 @@ version (IN_LLVM) {} else for (size_t i = 0; i < members.length; i++) { Dsymbol s = (*members)[i]; - s.setFieldOffset(this, fieldState, isunion); + s.setFieldOffset(this, &fieldState, isunion); } if (type.ty == Terror) { @@ -460,7 +443,11 @@ version (IN_LLVM) {} else ispod = ThreeState.yes; - if (enclosing || postblit || dtor || hasCopyCtor) + import dmd.clone; + bool hasCpCtorLocal; + needCopyCtor(this, hasCpCtorLocal); + + if (enclosing || search(this, loc, Id.postblit) || search(this, loc, Id.dtor) || hasCpCtorLocal) { ispod = ThreeState.no; return false; diff --git a/dmd/dsymbol.d b/dmd/dsymbol.d index 364399a5fc5..9d3d5d9084b 100644 --- a/dmd/dsymbol.d +++ b/dmd/dsymbol.d @@ -1,7 +1,7 @@ /** * The base class for a D symbol, which can be a module, variable, function, enum, etc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d) @@ -31,11 +31,9 @@ import dmd.dmodule; import dmd.dversion; import dmd.dscope; import dmd.dstruct; -import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; -import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; @@ -45,11 +43,9 @@ import dmd.lexer; import dmd.location; import dmd.mtype; import dmd.nspace; -import dmd.opover; import dmd.root.aav; import dmd.root.rmem; import dmd.rootobject; -import dmd.root.speller; import dmd.root.string; import dmd.statement; import dmd.staticassert; @@ -214,20 +210,21 @@ enum PASS : ubyte } // Search options -enum : int +alias SearchOptFlags = uint; +enum SearchOpt : SearchOptFlags { - IgnoreNone = 0x00, // default - IgnorePrivateImports = 0x01, // don't search private imports - IgnoreErrors = 0x02, // don't give error messages - IgnoreAmbiguous = 0x04, // return NULL if ambiguous - SearchLocalsOnly = 0x08, // only look at locals (don't search imports) - SearchImportsOnly = 0x10, // only look in imports - SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, + all = 0x00, // search for all symbols + ignorePrivateImports = 0x01, // don't search private imports + ignoreErrors = 0x02, // don't give error messages + ignoreAmbiguous = 0x04, // return NULL if ambiguous + localsOnly = 0x08, // only look at locals (don't search imports) + importsOnly = 0x10, // only look in imports + unqualifiedModule = 0x20, // the module scope search is unqualified, // meaning don't search imports in that scope, // because qualified module searches search // their imports - IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols - TagNameSpace = 0x100, // search ImportC tag symbol table + tagNameSpace = 0x40, // search ImportC tag symbol table + ignoreVisibility = 0x80, // also find private and package protected symbols } /*********************************************************** @@ -423,40 +420,6 @@ version (IN_LLVM) return '`' ~ cstr.toDString() ~ "`\0"; } - final bool checkDeprecated(const ref Loc loc, Scope* sc) - { - if (global.params.useDeprecated == DiagnosticReporting.off) - return false; - if (!this.isDeprecated()) - return false; - // Don't complain if we're inside a deprecated symbol's scope - if (sc.isDeprecated()) - return false; - // Don't complain if we're inside a template constraint - // https://issues.dlang.org/show_bug.cgi?id=21831 - if (sc.flags & SCOPE.constraint) - return false; - - const(char)* message = null; - for (Dsymbol p = this; p; p = p.parent) - { - message = p.depdecl ? p.depdecl.getMessage() : null; - if (message) - break; - } - if (message) - deprecation(loc, "%s `%s` is deprecated - %s", kind, toPrettyChars, message); - else - deprecation(loc, "%s `%s` is deprecated", kind, toPrettyChars); - - if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) - ti.printInstantiationTrace(Classification.deprecation); - else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null) - ti.printInstantiationTrace(Classification.deprecation); - - return true; - } - /********************************** * Determine which Module a Dsymbol is in. */ @@ -786,189 +749,6 @@ version (IN_LLVM) 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. - */ - void setScope(Scope* sc) - { - //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc); - if (!sc.nofree) - sc.setNoFree(); // may need it even after semantic() finishes - _scope = sc; - if (sc.depdecl) - depdecl = sc.depdecl; - if (!userAttribDecl) - userAttribDecl = sc.userAttribDecl; - } - - void importAll(Scope* sc) - { - } - - /********************************************* - * 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) - { - /*************************************************** - * Search for symbol with correct spelling. - */ - extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost) - { - /* If not in the lexer's string table, it certainly isn't in the symbol table. - * Doing this first is a lot faster. - */ - if (!seed.length) - return null; - Identifier id = Identifier.lookup(seed); - if (!id) - return null; - cost = 0; // all the same cost - Dsymbol s = this; - Module.clearCache(); - return s.search(Loc.initial, id, IgnoreErrors); - } - - 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)) - return s; - return speller!symbol_search_fp(ident.toString()); - } - - /*************************************** - * Search for identifier id as a member of `this`. - * `id` may be a template instance. - * - * Params: - * loc = location to print the error messages - * sc = the scope where the symbol is located - * id = the id of the symbol - * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports` - * - * Returns: - * symbol found, NULL if not - */ - extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags) - { - //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); - Dsymbol s = toAlias(); - Dsymbol sm; - if (Declaration d = s.isDeclaration()) - { - if (d.inuse) - { - .error(loc, "circular reference to `%s`", d.toPrettyChars()); - return null; - } - } - switch (id.dyncast()) - { - case DYNCAST.identifier: - sm = s.search(loc, cast(Identifier)id, flags); - break; - case DYNCAST.dsymbol: - { - // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol st = cast(Dsymbol)id; - TemplateInstance ti = st.isTemplateInstance(); - sm = s.search(loc, ti.name); - if (!sm) - return null; - sm = sm.toAlias(); - TemplateDeclaration td = sm.isTemplateDeclaration(); - if (!td) - return null; // error but handled later - ti.tempdecl = td; - if (!ti.semanticRun) - ti.dsymbolSemantic(sc); - sm = ti.toAlias(); - break; - } - case DYNCAST.type: - case DYNCAST.expression: - default: - assert(0); - } - return sm; - } - bool overloadInsert(Dsymbol s) { //printf("Dsymbol::overloadInsert('%s')\n", s.toChars()); @@ -1101,27 +881,27 @@ version (IN_LLVM) /************************************** * Determine if this symbol is only one. * Returns: - * false, *ps = NULL: There are 2 or more symbols - * true, *ps = NULL: There are zero symbols - * true, *ps = symbol: The one and only one symbol + * false, ps = null: There are 2 or more symbols + * true, ps = null: There are zero symbols + * true, ps = symbol: The one and only one symbol */ - bool oneMember(Dsymbol* ps, Identifier ident) + bool oneMember(out Dsymbol ps, Identifier ident) { //printf("Dsymbol::oneMember()\n"); - *ps = this; + ps = this; return true; } /***************************************** * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. */ - extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident) + extern (D) static bool oneMembers(Dsymbols* members, out Dsymbol ps, Identifier ident) { //printf("Dsymbol::oneMembers() %d\n", members ? members.length : 0); Dsymbol s = null; if (!members) { - *ps = null; + ps = null; return true; } @@ -1133,21 +913,21 @@ version (IN_LLVM) if (!x) { //printf("\tfalse 1\n"); - assert(*ps is null); + assert(ps is null); return false; } - if (*ps) + if (ps) { assert(ident); - if (!(*ps).ident || !(*ps).ident.equals(ident)) + if (!ps.ident || !ps.ident.equals(ident)) continue; if (!s) - s = *ps; - else if (s.isOverloadable() && (*ps).isOverloadable()) + s = ps; + else if (s.isOverloadable() && ps.isOverloadable()) { // keep head of overload set FuncDeclaration f1 = s.isFuncDeclaration(); - FuncDeclaration f2 = (*ps).isFuncDeclaration(); + FuncDeclaration f2 = ps.isFuncDeclaration(); if (f1 && f2) { assert(!f1.isFuncAliasDeclaration()); @@ -1164,21 +944,17 @@ version (IN_LLVM) } else // more than one symbol { - *ps = null; + ps = null; //printf("\tfalse 2\n"); return false; } } } - *ps = s; // s is the one symbol, null if none + ps = s; // s is the one symbol, null if none //printf("\ttrue\n"); return true; } - void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - } - /***************************************** * Is Dsymbol a variable that contains pointers? */ @@ -1375,12 +1151,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 @@ -1409,166 +1185,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) { @@ -1675,7 +1292,7 @@ public: (*pary)[p.tag] = true; } - bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow + bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) nothrow { if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] || visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag]) @@ -1684,7 +1301,7 @@ public: { // only search visible scopes && imported modules should ignore private imports if (visibility.kind <= visibilities[i] && - ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports)) + ss.isScopeDsymbol.isPackageAccessible(p, visibility, SearchOpt.ignorePrivateImports)) return true; } return false; @@ -1740,38 +1357,6 @@ public: return "ScopeDsymbol"; } - /******************************************* - * Look for member of the form: - * const(MemberInfo)[] getMembers(string); - * Returns NULL if not found - */ - final FuncDeclaration findGetMembers() - { - Dsymbol s = search_function(this, Id.getmembers); - FuncDeclaration fdx = s ? s.isFuncDeclaration() : null; - version (none) - { - // Finish - __gshared TypeFunction tfgetmembers; - if (!tfgetmembers) - { - Scope sc; - sc.eSink = global.errorSink; - auto parameters = new Parameters(); - Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null); - parameters.push(p); - Type tret = null; - tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d); - tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc); - } - if (fdx) - fdx = fdx.overloadExactMatch(tfgetmembers); - } - if (fdx && fdx.isVirtual()) - fdx = null; - return fdx; - } - /******************************** * Insert Dsymbol in table. * Params: @@ -1815,48 +1400,6 @@ public: return false; } - extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s); - - /*************************************** - * Expands attribute declarations in members in depth first - * order. Calls dg(size_t symidx, Dsymbol *sym) for each - * member. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - * Returns: - * last value returned by dg() - */ - extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null) - { - assert(dg); - if (!members) - return 0; - size_t n = pn ? *pn : 0; // take over index - int result = 0; - foreach (size_t i; 0 .. members.length) - { - Dsymbol s = (*members)[i]; - if (AttribDeclaration a = s.isAttribDeclaration()) - result = _foreach(sc, a.include(sc), dg, &n); - else if (TemplateMixin tm = s.isTemplateMixin()) - result = _foreach(sc, tm.members, dg, &n); - else if (s.isTemplateInstance()) - { - } - else if (s.isUnitTestDeclaration()) - { - } - else - result = dg(n++, s); - if (result) - break; - } - if (pn) - *pn = n; // update index - return result; - } - override final inout(ScopeDsymbol) isScopeDsymbol() inout { return this; @@ -1880,40 +1423,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 (e.op == EXP.scope_) - { - s = (cast(ScopeExp)e).sds; - } - else if (e.op == EXP.type) - { - 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; @@ -1932,216 +1441,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 (exp.op == EXP.array) - { - dim = (cast(ArrayExp)exp).currentDimension; - } - else if (exp.op == EXP.slice) - { - 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. - */ - if (exp.op == EXP.array && (cast(ArrayExp)exp).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; diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h index b9bdecd81ef..9c15ea368b3 100644 --- a/dmd/dsymbol.h +++ b/dmd/dsymbol.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -149,20 +149,21 @@ enum /* Flags for symbol search */ -enum +typedef uint SearchOptFlags; +enum class SearchOpt : SearchOptFlags { - IgnoreNone = 0x00, // default - IgnorePrivateImports = 0x01, // don't search private imports - IgnoreErrors = 0x02, // don't give error messages - IgnoreAmbiguous = 0x04, // return NULL if ambiguous - SearchLocalsOnly = 0x08, // only look at locals (don't search imports) - SearchImportsOnly = 0x10, // only look in imports - SearchUnqualifiedModule = 0x20, // the module scope search is unqualified, - // meaning don't search imports in that scope, - // because qualified module searches search - // their imports - IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols - TagNameSpace = 0x100, // search ImportC tag symbol table + all = 0x00, // default + ignorePrivateImports = 0x01, // don't search private imports + ignoreErrors = 0x02, // don't give error messages + ignoreAmbiguous = 0x04, // return NULL if ambiguous + localsOnly = 0x08, // only look at locals (don't search imports) + importsOnly = 0x10, // only look in imports + unqualifiedModule = 0x20, // the module scope search is unqualified, + // meaning don't search imports in that scope, + // because qualified module searches search + // their imports + tagNameSpace = 0x40, // search ImportC tag symbol table + ignoreVisibility = 0x80, // also find private and package protected symbols }; struct FieldState @@ -212,7 +213,6 @@ class Dsymbol : public ASTNode const char *locToChars(); bool equals(const RootObject * const o) const override; bool isAnonymous() const; - bool checkDeprecated(const Loc &loc, Scope *sc); Module *getModule(); bool isCsymbol(); Module *getAccessModule(); @@ -235,10 +235,6 @@ class Dsymbol : public ASTNode 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(); @@ -257,8 +253,7 @@ class Dsymbol : public ASTNode virtual bool needThis(); // need a 'this' pointer? virtual Visibility visible(); virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual bool oneMember(Dsymbol **ps, Identifier *ident); - virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); + virtual bool oneMember(Dsymbol *&ps, Identifier *ident); virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { } @@ -338,22 +333,19 @@ class ScopeDsymbol : public Dsymbol 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); + virtual bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); bool isforwardRef() override final; static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2); const char *kind() const override; - FuncDeclaration *findGetMembers(); virtual Dsymbol *symtabInsert(Dsymbol *s); virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id); bool hasStaticCtorOrDtor() override; @@ -369,7 +361,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); } @@ -379,12 +370,8 @@ class WithScopeSymbol final : public ScopeDsymbol 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); } @@ -444,3 +431,10 @@ class DsymbolTable final : public RootObject // 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, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly); +bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc); +void setScope(Dsymbol *d, Scope *sc); +void importAll(Dsymbol *d, Scope *sc); +void setFieldOffset(Dsymbol *d, AggregateDeclaration *ad, FieldState& fieldState, bool isunion); diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index c5dd7382e44..eedfb42eae3 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -2,7 +2,7 @@ * Does the semantic 1 pass on the AST, which looks at symbol declarations but not initializers * or function bodies. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d, _dsymbolsem.d) @@ -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; @@ -57,6 +58,7 @@ import dmd.nogc; import dmd.nspace; import dmd.objc; import dmd.opover; +import dmd.optimize; import dmd.parse; import dmd.root.array; import dmd.root.filename; @@ -220,6 +222,53 @@ const(char)* getMessage(DeprecatedDeclaration dd) return dd.msgstr; } +bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc) +{ + if (global.params.useDeprecated == DiagnosticReporting.off) + return false; + if (!d.isDeprecated()) + return false; + // Don't complain if we're inside a deprecated symbol's scope + if (sc.isDeprecated()) + return false; + // Don't complain if we're inside a template constraint + // https://issues.dlang.org/show_bug.cgi?id=21831 + if (sc.flags & SCOPE.constraint) + return false; + + const(char)* message = null; + for (Dsymbol p = d; p; p = p.parent) + { + message = p.depdecl ? p.depdecl.getMessage() : null; + if (message) + break; + } + if (message) + deprecation(loc, "%s `%s` is deprecated - %s", d.kind, d.toPrettyChars, message); + else + deprecation(loc, "%s `%s` is deprecated", d.kind, d.toPrettyChars); + + if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) + ti.printInstantiationTrace(Classification.deprecation); + else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null) + ti.printInstantiationTrace(Classification.deprecation); + + return true; +} + +/********************************* + * Check type to see if it is based on a deprecated symbol. + */ +private void checkDeprecated(Type type, const ref Loc loc, Scope* sc) +{ + if (Dsymbol s = type.toDsymbol(sc)) + { + s.checkDeprecated(loc, sc); + } + + if (auto tn = type.nextOf()) + tn.checkDeprecated(loc, sc); +} // Returns true if a contract can appear without a function body. package bool allowsContractWithoutBody(FuncDeclaration funcdecl) @@ -279,6 +328,128 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem return false; } +/************************************* + * Find the `alias this` symbol of e's type. + * Params: + * sc = context + * e = expression forming the `this` + * gag = do not print errors, return `null` instead + * findOnly = don't do further processing like resolving properties, + * i.e. just return plain dotExp() result. + * Returns: + * Expression that is `e.aliasthis` + */ +Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false) +{ + import dmd.typesem : dotExp; + for (AggregateDeclaration ad = isAggregate(e.type); ad;) + { + if (ad.aliasthis) + { + Loc loc = e.loc; + Type tthis = (e.op == EXP.type ? e.type : null); + const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag)); + uint olderrors = gag ? global.startGagging() : 0; + e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags); + if (!e || findOnly) + return gag && global.endGagging(olderrors) ? null : e; + + if (tthis && ad.aliasthis.sym.needThis()) + { + if (auto ve = e.isVarExp()) + { + if (auto fd = ve.var.isFuncDeclaration()) + { + // https://issues.dlang.org/show_bug.cgi?id=13009 + // Support better match for the overloaded alias this. + bool hasOverloads; + if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) + { + if (!hasOverloads) + fd = f; // use exact match + e = new VarExp(loc, fd, hasOverloads); + e.type = f.type; + e = new CallExp(loc, e); + goto L1; + } + } + } + /* non-@property function is not called inside typeof(), + * so resolve it ahead. + */ + { + int save = sc.intypeof; + sc.intypeof = 1; // bypass "need this" error check + e = resolveProperties(sc, e); + sc.intypeof = save; + } + L1: + e = new TypeExp(loc, new TypeTypeof(loc, e)); + e = e.expressionSemantic(sc); + } + e = resolveProperties(sc, e); + if (!gag) + ad.aliasthis.checkDeprecatedAliasThis(loc, sc); + else if (global.endGagging(olderrors)) + e = null; + } + + import dmd.dclass : ClassDeclaration; + auto cd = ad.isClassDeclaration(); + if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) + { + ad = cd.baseClass; + continue; + } + break; + } + return e; +} + +/** + * Check if an `alias this` is deprecated + * + * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to + * check if `expression` uses a deprecated `aliasthis`, but this calls + * `toPrettyChars` which lead to the following message: + * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated" + * + * Params: + * at = The `AliasThis` object to check + * loc = `Loc` of the expression triggering the access to `at` + * sc = `Scope` of the expression + * (deprecations do not trigger in deprecated scopes) + * + * Returns: + * Whether the alias this was reported as deprecated. + */ +private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc) +{ + if (global.params.useDeprecated != DiagnosticReporting.off + && at.isDeprecated() && !sc.isDeprecated()) + { + const(char)* message = null; + for (Dsymbol p = at; p; p = p.parent) + { + message = p.depdecl ? p.depdecl.getMessage() : null; + if (message) + break; + } + if (message) + deprecation(loc, "`alias %s this` is deprecated - %s", + at.sym.toChars(), message); + else + deprecation(loc, "`alias %s this` is deprecated", + at.sym.toChars()); + + if (auto ti = sc.parent ? sc.parent.isInstantiated() : null) + ti.printInstantiationTrace(Classification.deprecation); + + return true; + } + return false; +} + private extern(C++) final class DsymbolSemanticVisitor : Visitor { alias visit = Visitor.visit; @@ -334,7 +505,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor Dsymbol s = ad.search(dsym.loc, dsym.ident); if (!s) { - s = sc.search(dsym.loc, dsym.ident, null); + Dsymbol pscopesym; + s = sc.search(dsym.loc, dsym.ident, pscopesym); if (s) error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars()); else @@ -424,7 +596,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null"); printf(" stc = x%llx\n", dsym.storage_class); printf(" storage_class = x%llx\n", dsym.storage_class); - printf("linkage = %d\n", dsym.linkage); + printf("linkage = %d\n", dsym._linkage); //if (strcmp(toChars(), "mul") == 0) assert(0); } //if (semanticRun > PASS.initial) @@ -785,7 +957,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // At this point we can add `scope` to the STC instead of `in`, // because we are never going to use this variable's STC for user messages - if (dsym.storage_class & STC.in_ && global.params.previewIn) + if (dsym.storage_class & STC.constscoperef) dsym.storage_class |= STC.scope_; if (dsym.storage_class & STC.scope_) @@ -1164,7 +1336,7 @@ version (IN_LLVM) 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; } @@ -1483,7 +1655,7 @@ version (IN_LLVM) { AliasDeclaration ad = imp.aliasdecls[i]; //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope); - Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports); + Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], SearchOpt.ignorePrivateImports); if (sym) { import dmd.access : symbolIsVisible; @@ -2024,7 +2196,7 @@ else // !IN_LLVM const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + const bool doUnittests = global.params.parsingUnittestsRequired(); auto loc = adjustLocForMixin(str, cd.loc, global.params.mixinOut); scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); p.transitionIn = global.params.v.vin; @@ -2051,7 +2223,7 @@ else // !IN_LLVM 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) @@ -2597,6 +2769,10 @@ else // !IN_LLVM em.origValue = e; } em.value = e; + // https://issues.dlang.org/show_bug.cgi?id=24311 + // First enum member is .init value, which gets put into static segment + if (first) + lowerStaticAAs(e, sc); } else if (first) { @@ -2865,7 +3041,7 @@ else // !IN_LLVM if (tempdecl.members) { Dsymbol s; - if (Dsymbol.oneMembers(tempdecl.members, &s, tempdecl.ident) && s) + if (Dsymbol.oneMembers(tempdecl.members, s, tempdecl.ident) && s) { tempdecl.onemember = s; s.parent = tempdecl; @@ -3464,9 +3640,13 @@ version (IN_LLVM) if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) { - OutBuffer buf; - MODtoBuffer(buf, tf.mod); - .error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, buf.peekChars()); + 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) + .errorSupplemental(funcdecl.loc, + "did you mean to use `%s(%s)` as the return type?", mods, tf.next.toChars()); + tf.mod = 0; // remove qualifiers } @@ -3998,7 +4178,7 @@ version (IN_LLVM) auto fd = s.isFuncDeclaration(); functionToBufferFull(cast(TypeFunction)(funcdecl.type), buf, - new Identifier(funcdecl.toPrettyChars()), &hgs, null); + new Identifier(funcdecl.toPrettyChars()), hgs, null); const(char)* funcdeclToChars = buf.peekChars(); if (fd) @@ -4021,7 +4201,7 @@ version (IN_LLVM) else { functionToBufferFull(cast(TypeFunction)(fd.type), buf1, - new Identifier(fd.toPrettyChars()), &hgs, null); + new Identifier(fd.toPrettyChars()), hgs, null); error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", funcdeclToChars, buf1.peekChars()); @@ -4162,7 +4342,8 @@ version (IN_LLVM) // check if `_d_cmain` is defined bool cmainTemplateExists() { - auto rootSymbol = sc.search(funcdecl.loc, Id.empty, null); + Dsymbol pscopesym; + auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym); if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object)) if (moduleSymbol.search(funcdecl.loc, Id.CMain)) return true; @@ -4495,6 +4676,24 @@ version (IN_LLVM) m.needmoduleinfo = 1; //printf("module1 %s needs moduleinfo\n", m.toChars()); } + + foreachUda(scd, sc, (Expression e) { + import dmd.attrib : isEnumAttribute; + if (!isEnumAttribute(e, Id.udaStandalone)) + return 0; + + if (auto sharedCtor = scd.isSharedStaticCtorDeclaration()) + { + auto trust = sharedCtor.type.isTypeFunction().trust; + if (trust != TRUST.system && trust != TRUST.trusted) + error(e.loc, "a module constructor using `@%s` must be `@system` or `@trusted`", Id.udaStandalone.toChars()); + sharedCtor.standalone = true; + } + else + .error(e.loc, "`@%s` can only be used on shared static constructors", Id.udaStandalone.toChars()); + + return 1; + }); } override void visit(StaticDtorDeclaration sdd) @@ -4734,9 +4933,15 @@ version (IN_LLVM) { if (ts.sym != sd) { - auto ti = ts.sym.isInstantiated(); + TemplateInstance ti = ts.sym.isInstantiated(); if (ti && isError(ti)) ts.sym = sd; + /* For C modules, if module A contains `struct S;` and + * module B contains `struct S { members...}` then replace + * the former with the latter + */ + else if (!ts.sym.members && sd.members) + ts.sym = sd; } } @@ -5260,7 +5465,7 @@ version (IN_LLVM) cldec.classKind = ClassKind.cpp; if (cldec.classKind != cldec.baseClass.classKind) .error(cldec.loc, "%s `%s` with %s linkage cannot inherit from class `%s` with %s linkage", cldec.kind, cldec.toPrettyChars, - cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars()); + ClassKindToChars(cldec.classKind), cldec.baseClass.toChars(), ClassKindToChars(cldec.baseClass.classKind)); if (cldec.baseClass.stack) cldec.stack = true; @@ -5908,140 +6113,499 @@ version (IN_LLVM) } } -/******************************************* - * Add members of EnumDeclaration to the symbol table(s). - * Params: - * ed = EnumDeclaration - * sc = context of `ed` - * sds = symbol table that `ed` resides in - */ -void addEnumMembersToSymtab(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds) +/* +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) { - const bool isCEnum = (sc.flags & SCOPE.Cfile) != 0; // it's an ImportC enum - //printf("addEnumMembersToSymtab(ed: %s added: %d Cfile: %d)\n", ed.toChars(), ed.added, isCEnum); - if (ed.added) - return; - ed.added = true; + auto addMemberVisitor = new AddMemberVisitor(sc, sds); + dsym.accept(addMemberVisitor); +} - if (!ed.members) - return; +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(); + } +} - const bool isAnon = ed.isAnonymous(); +private extern(C++) class AddMemberVisitor : Visitor +{ + alias visit = Visitor.visit; - if ((isCEnum || isAnon) && !sds.symtab) - sds.symtab = new DsymbolTable(); + Scope* sc; + ScopeDsymbol sds; - if ((isCEnum || !isAnon) && !ed.symtab) - ed.symtab = new DsymbolTable(); + this(Scope* sc, ScopeDsymbol sds) + { + this.sc = sc; + this.sds = sds; + } - ed.members.foreachDsymbol( (s) + override void visit(Dsymbol dsym) { - if (EnumMember em = s.isEnumMember()) + //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 { - //printf("adding EnumMember %s to %s %d\n", em.toChars(), ed.toChars(), isCEnum); - em.ed = ed; - if (isCEnum) + 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()) { - /* C doesn't add the enum member to the symbol table of the enum tag, it adds - * it to the symbol table that the tag is in. This is in contrast to D, where enum - * members become members of the enum tag. To accommodate this, we add - * the enum members to both symbol tables. - */ - em.addMember(sc, ed); // add em to ed's symbol table - em.addMember(sc, sds); // add em to symbol table that ed is in - em.parent = ed; // restore it after previous addMember() changed it + if (auto i2 = s2.isImport()) + { + if (sc.explicitVisibility && sc.visibility > i2.visibility) + sds.symtab.update(dsym); + } } - else + + // If using C tag/prototype/forward declaration rules + if (sc.flags & SCOPE.Cfile && !dsym.isImport()) { - em.addMember(sc, isAnon ? sds : ed); + 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; + } + } + } -/****************************************************** - * Verifies if the given Identifier is a DRuntime hook. It uses the hooks - * defined in `id.d`. - * - * Params: - * id = Identifier to verify - * Returns: - * true if `id` is a DRuntime hook - * false otherwise - */ -private bool isDRuntimeHook(Identifier id) -{ - return id == Id._d_HookTraceImpl || - id == Id._d_newclassT || id == Id._d_newclassTTrace || - id == Id._d_arraycatnTX || id == Id._d_arraycatnTXTrace || - id == Id._d_newThrowable || id == Id._d_delThrowable || - id == Id._d_arrayassign_l || id == Id._d_arrayassign_r || - id == Id._d_arraysetassign || id == Id._d_arraysetctor || - id == Id._d_arrayctor || - id == Id._d_arraysetlengthTImpl || id == Id._d_arraysetlengthT || - id == Id._d_arraysetlengthTTrace || - id == Id._d_arrayappendT || id == Id._d_arrayappendTTrace || - id == Id._d_arrayappendcTX; -} -void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList) -{ - //printf("[%s] TemplateInstance.dsymbolSemantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst.loc.toChars(), tempinst.toChars(), tempinst, global.gag, sc); - version (none) + override void visit(StaticAssert _) { - for (Dsymbol s = tempinst; s; s = s.parent) - { - printf("\t%s\n", s.toChars()); - } - printf("Scope\n"); - for (Scope* scx = sc; scx; scx = scx.enclosing) + // 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++) { - printf("\t%s parent %s\n", scx._module ? scx._module.toChars() : "null", scx.parent ? scx.parent.toChars() : "null"); + 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); } } - static if (LOG) + override void visit(AttribDeclaration atb) { - printf("\n+TemplateInstance.dsymbolSemantic('%s', this=%p)\n", tempinst.toChars(), tempinst); + attribAddMember(atb, sc, sds); } - if (tempinst.inst) // if semantic() was already run + + override void visit(StorageClassDeclaration stcd) { - static if (LOG) + Dsymbols* d = stcd.include(sc); + if (d) { - printf("-TemplateInstance.dsymbolSemantic('%s', this=%p) already run\n", - tempinst.inst.toChars(), tempinst.inst); + 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(); } - return; } - if (tempinst.semanticRun != PASS.initial) + + override void visit(VisibilityDeclaration visd) { - static if (LOG) + if (visd.pkg_identifiers) { - printf("Recursive template expansion\n"); + Dsymbol tmp; + Package.resolve(visd.pkg_identifiers, &tmp, null); + visd.visibility.pkg = tmp ? tmp.isPackage() : null; + visd.pkg_identifiers = null; } - auto ungag = Ungag(global.gag); - if (!tempinst.gagged) - global.gag = 0; - .error(tempinst.loc, "%s `%s` recursive template expansion", tempinst.kind, tempinst.toPrettyChars); - if (tempinst.gagged) - tempinst.semanticRun = PASS.initial; - else - tempinst.inst = tempinst; - tempinst.errors = true; - return; - } + if (visd.visibility.kind == Visibility.Kind.package_ && visd.visibility.pkg && sc._module) + { + Module m = sc._module; - // Get the enclosing template instance from the scope tinst - tempinst.tinst = sc.tinst; + // 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); + } - // Get the instantiating module from the scope minst - tempinst.minst = sc.minst; - // https://issues.dlang.org/show_bug.cgi?id=10920 - // If the enclosing function is non-root symbol, - // this instance should be speculative. - if (!tempinst.tinst && sc.func && sc.func.inNonRoot()) + override void visit(StaticIfDeclaration sid) { - tempinst.minst = null; + //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: + * ed = EnumDeclaration + * sc = context of `ed` + * sds = symbol table that `ed` resides in + */ +void addEnumMembersToSymtab(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds) +{ + const bool isCEnum = (sc.flags & SCOPE.Cfile) != 0; // it's an ImportC enum + //printf("addEnumMembersToSymtab(ed: %s added: %d Cfile: %d)\n", ed.toChars(), ed.added, isCEnum); + if (ed.added) + return; + ed.added = true; + + if (!ed.members) + return; + + const bool isAnon = ed.isAnonymous(); + + if ((isCEnum || isAnon) && !sds.symtab) + sds.symtab = new DsymbolTable(); + + if ((isCEnum || !isAnon) && !ed.symtab) + ed.symtab = new DsymbolTable(); + + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + { + //printf("adding EnumMember %s to %s %d\n", em.toChars(), ed.toChars(), isCEnum); + em.ed = ed; + if (isCEnum) + { + /* C doesn't add the enum member to the symbol table of the enum tag, it adds + * it to the symbol table that the tag is in. This is in contrast to D, where enum + * members become members of the enum tag. To accommodate this, we add + * the enum members to both symbol tables. + */ + em.addMember(sc, ed); // add em to ed's symbol table + em.addMember(sc, sds); // add em to symbol table that ed is in + em.parent = ed; // restore it after previous addMember() changed it + } + else + { + em.addMember(sc, isAnon ? sds : ed); + } + } + }); +} + +/****************************************************** + * Verifies if the given Identifier is a DRuntime hook. It uses the hooks + * defined in `id.d`. + * + * Params: + * id = Identifier to verify + * Returns: + * true if `id` is a DRuntime hook + * false otherwise + */ +private bool isDRuntimeHook(Identifier id) +{ + return id == Id._d_HookTraceImpl || + id == Id._d_newclassT || id == Id._d_newclassTTrace || + id == Id._d_arraycatnTX || id == Id._d_arraycatnTXTrace || + id == Id._d_newThrowable || id == Id._d_delThrowable || + id == Id._d_arrayassign_l || id == Id._d_arrayassign_r || + id == Id._d_arraysetassign || id == Id._d_arraysetctor || + id == Id._d_arrayctor || + id == Id._d_arraysetlengthTImpl || id == Id._d_arraysetlengthT || + id == Id._d_arraysetlengthTTrace || + id == Id._d_arrayappendT || id == Id._d_arrayappendTTrace || + id == Id._d_arrayappendcTX; +} + +void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList) +{ + //printf("[%s] TemplateInstance.dsymbolSemantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst.loc.toChars(), tempinst.toChars(), tempinst, global.gag, sc); + version (none) + { + for (Dsymbol s = tempinst; s; s = s.parent) + { + printf("\t%s\n", s.toChars()); + } + printf("Scope\n"); + for (Scope* scx = sc; scx; scx = scx.enclosing) + { + printf("\t%s parent %s\n", scx._module ? scx._module.toChars() : "null", scx.parent ? scx.parent.toChars() : "null"); + } + } + + static if (LOG) + { + printf("\n+TemplateInstance.dsymbolSemantic('%s', this=%p)\n", tempinst.toChars(), tempinst); + } + if (tempinst.inst) // if semantic() was already run + { + static if (LOG) + { + printf("-TemplateInstance.dsymbolSemantic('%s', this=%p) already run\n", + tempinst.inst.toChars(), tempinst.inst); + } + return; + } + if (tempinst.semanticRun != PASS.initial) + { + static if (LOG) + { + printf("Recursive template expansion\n"); + } + auto ungag = Ungag(global.gag); + if (!tempinst.gagged) + global.gag = 0; + .error(tempinst.loc, "%s `%s` recursive template expansion", tempinst.kind, tempinst.toPrettyChars); + if (tempinst.gagged) + tempinst.semanticRun = PASS.initial; + else + tempinst.inst = tempinst; + tempinst.errors = true; + return; + } + + // Get the enclosing template instance from the scope tinst + tempinst.tinst = sc.tinst; + + // Get the instantiating module from the scope minst + tempinst.minst = sc.minst; + // https://issues.dlang.org/show_bug.cgi?id=10920 + // If the enclosing function is non-root symbol, + // this instance should be speculative. + if (!tempinst.tinst && sc.func && sc.func.inNonRoot()) + { + tempinst.minst = null; } tempinst.gagged = (global.gag > 0); @@ -6363,7 +6927,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList if (tempinst.members.length) { Dsymbol s; - if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) + if (Dsymbol.oneMembers(tempinst.members, s, tempdecl.ident) && s) { //printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl\n"); @@ -6418,7 +6982,7 @@ version (IN_LLVM) if (tempinst.members.length) { Dsymbol s; - if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) + if (Dsymbol.oneMembers(tempinst.members, s, tempdecl.ident) && s) { if (!tempinst.aliasdecl || tempinst.aliasdecl != s) { @@ -6910,7 +7474,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc) AliasDeclaration findAliasDeclaration(AliasAssign ds, Scope* sc) { Dsymbol scopesym; - Dsymbol as = sc.search(ds.loc, ds.ident, &scopesym); + Dsymbol as = sc.search(ds.loc, ds.ident, scopesym); if (!as) { .error(ds.loc, "%s `%s` undefined identifier `%s`", ds.kind, ds.toPrettyChars, ds.ident.toChars()); @@ -7530,3 +8094,1349 @@ 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 = search options + * Returns: + * null if not found + */ +extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all) +{ + scope v = new SearchVisitor(loc, ident, flags); + d.accept(v); + return v.result; +} + +Dsymbol search_correct(Dsymbol d, Identifier ident) +{ + /*************************************************** + * Search for symbol with correct spelling. + */ + Dsymbol symbol_search_fp(const(char)[] seed, out int cost) + { + /* If not in the lexer's string table, it certainly isn't in the symbol table. + * Doing this first is a lot faster. + */ + if (!seed.length) + return null; + Identifier id = Identifier.lookup(seed); + if (!id) + return null; + cost = 0; // all the same cost + Dsymbol s = d; + Module.clearCache(); + return s.search(Loc.initial, id, SearchOpt.ignoreErrors); + } + + if (global.gag) + return null; // don't do it for speculative compiles; too time consuming + // search for exact name first + if (auto s = d.search(Loc.initial, ident, SearchOpt.ignoreErrors)) + return s; + + import dmd.root.speller : speller; + return speller!symbol_search_fp(ident.toString()); +} + +private extern(C++) class SearchVisitor : Visitor +{ + alias visit = Visitor.visit; + + const Loc loc; + Identifier ident; + SearchOptFlags flags; + Dsymbol result; + + this(const ref Loc loc, Identifier ident, SearchOptFlags 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 & SearchOpt.importsOnly)) + { + //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 & SearchOpt.ignorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_) + continue; + SearchOptFlags sflags = flags & (SearchOpt.ignoreErrors | SearchOpt.ignoreAmbiguous); // remember these in recursive searches + Dsymbol ss = (*sds.importedScopes)[i]; + //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport()); + + if (ss.isModule()) + { + if (flags & SearchOpt.localsOnly) + continue; + } + else // mixin template + { + if (flags & SearchOpt.importsOnly) + continue; + + sflags |= SearchOpt.localsOnly; + } + + /* Don't find private members if ss is a module + */ + Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? SearchOpt.ignorePrivateImports : SearchOpt.all)); + import dmd.access : symbolIsVisible; + if (!s2 || !(flags & SearchOpt.ignoreVisibility) && !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 & SearchOpt.ignoreAmbiguous) // if return NULL on ambiguity + return setResult(null); + + /* If two imports from C import files, pick first one, as C has global name space + */ + if (s.isCsymbol() && s2.isCsymbol()) + continue; + + if (!(flags & SearchOpt.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 & SearchOpt.importsOnly) + 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 & SearchOpt.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 &= ~cast(int)SearchOpt.localsOnly; // 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 & SearchOpt.unqualifiedModule)) + flags &= ~(SearchOpt.unqualifiedModule | SearchOpt.localsOnly); + + 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 & SearchOpt.ignoreErrors) && sd.semanticRun < PASS.semanticdone) + .error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars()); + return setResult(null); + } + + 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 & SearchOpt.ignoreErrors) && cd.semanticRun < PASS.semanticdone) + cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars()); + //*(char*)0=0; + return setResult(null); + } + + visit(cast(ScopeDsymbol)cd); + auto s = result; + + // don't search imports of base classes + if (flags & SearchOpt.importsOnly) + 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 & SearchOpt.ignoreVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s)) + s = null; + else + break; + } + + return setResult(s); + } +} +/************************************* + * Set scope for future semantic analysis so we can + * deal better with forward references. + * + * Params: + * d = dsymbol for which the scope is set + * sc = scope that is used to set the value + */ +extern(C++) void setScope(Dsymbol d, Scope* sc) +{ + scope setScopeVisitor = new SetScopeVisitor(sc); + d.accept(setScopeVisitor); +} + +private extern(C++) class SetScopeVisitor : Visitor +{ + alias visit = typeof(super).visit; + Scope* sc; + + this(Scope* sc) + { + this.sc = sc; + } + + override void visit(Dsymbol d) + { + //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", d, d.toChars(), sc, sc.stc); + if (!sc.nofree) + sc.setNoFree(); // may need it even after semantic() finishes + d._scope = sc; + if (sc.depdecl) + d.depdecl = sc.depdecl; + if (!d.userAttribDecl) + d.userAttribDecl = sc.userAttribDecl; + } + + override void visit(Import i) + { + visit(cast(Dsymbol)i); + if (i.aliasdecls.length) + { + if (!i.mod) + i.importAll(sc); + + sc = sc.push(i.mod); + sc.visibility = i.visibility; + foreach (ad; i.aliasdecls) + ad.setScope(sc); + sc = sc.pop(); + } + } + + override void visit(Nspace ns) + { + visit(cast(Dsymbol)ns); + if (ns.members) + { + assert(sc); + sc = sc.push(ns); + sc.linkage = LINK.cpp; // namespaces default to C++ linkage + sc.parent = ns; + ns.members.foreachDsymbol(s => s.setScope(sc)); + sc.pop(); + } + } + + override void visit(EnumDeclaration ed) + { + if (ed.semanticRun > PASS.initial) + return; + visit(cast(Dsymbol)ed); + } + + override void visit(AggregateDeclaration ad) + { + // Might need a scope to resolve forward references. The check for + // semanticRun prevents unnecessary setting of _scope during deferred + // setScope phases for aggregates which already finished semantic(). + // See https://issues.dlang.org/show_bug.cgi?id=16607 + if (ad.semanticRun < PASS.semanticdone) + visit(cast(Dsymbol)ad); + } + + override void visit(AttribDeclaration atr) + { + Dsymbols* d = atr.include(sc); + //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d); + if (d) + { + Scope* sc2 = atr.newScope(sc); + d.foreachDsymbol( s => s.setScope(sc2) ); + if (sc2 != sc) + sc2.pop(); + } + } + + override void visit(DeprecatedDeclaration dd) + { + //printf("DeprecatedDeclaration::setScope() %p\n", this); + if (dd.decl) + visit(cast(Dsymbol)dd); // for forward reference + visit(cast(AttribDeclaration)dd); + } + + override void visit(CPPMangleDeclaration cppmd) + { + if (cppmd.decl) + visit(cast(Dsymbol)cppmd); // for forward reference + visit(cast(AttribDeclaration)cppmd); + } + + override void visit(AnonDeclaration anond) + { + if (anond.decl) + visit(cast(Dsymbol)anond); // for forward reference + visit(cast(AttribDeclaration)anond); + } + + override void visit(ConditionalDeclaration condd) + { + condd.include(sc).foreachDsymbol( s => s.setScope(sc) ); + } + + override void visit(StaticIfDeclaration sid) + { + // do not evaluate condition before semantic pass + // But do set the scope, in case we need it for forward referencing + visit(cast(Dsymbol)sid); // for forward reference + } + + override void visit(StaticForeachDeclaration sfd) + { + // do not evaluate condition before semantic pass + // But do set the scope, in case we need it for forward referencing + visit(cast(Dsymbol)sfd); // for forward reference + } + + override void visit(MixinDeclaration md) + { + visit(cast(Dsymbol)md); + } + + override void visit(UserAttributeDeclaration uad) + { + //printf("UserAttributeDeclaration::setScope() %p\n", this); + if (uad.decl) + visit(cast(Dsymbol)uad); + visit(cast(AttribDeclaration)uad); + } +} + +extern(C++) void importAll(Dsymbol d, Scope* sc) +{ + scope iav = new ImportAllVisitor(sc); + d.accept(iav); +} + +extern(C++) class ImportAllVisitor : Visitor +{ + alias visit = typeof(super).visit; + Scope* sc; + + this(Scope* sc) + { + this.sc = sc; + } + + override void visit(Dsymbol d) {} + + override void visit(Import imp) + { + if (imp.mod) return; // Already done + + /* + * https://issues.dlang.org/show_bug.cgi?id=15525 + * + * Loading the import has failed, + * most likely because of parsing errors. + * Therefore we cannot trust the resulting AST. + */ + if (imp.load(sc)) + { + // https://issues.dlang.org/show_bug.cgi?id=23873 + // For imports that are not at module or function level, + // e.g. aggregate level, the import symbol is added to the + // symbol table and later semantic is performed on it. + // This leads to semantic analysis on an malformed AST + // which causes all kinds of segfaults. + // The fix is to note that the module has errors and avoid + // semantic analysis on it. + if(imp.mod) + imp.mod.errors = true; + return; + } + + if (!imp.mod) return; // Failed + + if (sc.stc & STC.static_) + imp.isstatic = true; + imp.mod.importAll(null); + imp.mod.checkImportDeprecation(imp.loc, sc); + if (sc.explicitVisibility) + imp.visibility = sc.visibility; + if (!imp.isstatic && !imp.aliasId && !imp.names.length) + sc.scopesym.importScope(imp.mod, imp.visibility); + // Enable access to pkgs/mod as soon as posible, because compiler + // can traverse them before the import gets semantic (Issue: 21501) + if (!imp.aliasId && !imp.names.length) + imp.addPackageAccess(sc.scopesym); + } + + override void visit(Module m) + { + //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", m, m.toChars(), m.parent); + if (m._scope) + return; // already done + if (m.filetype == FileType.ddoc) + { + error(m.loc, "%s `%s` is a Ddoc file, cannot import it", m.kind, m.toPrettyChars); + return; + } + + /* Note that modules get their own scope, from scratch. + * This is so regardless of where in the syntax a module + * gets imported, it is unaffected by context. + * Ignore prevsc. + */ + Scope* sc = Scope.createGlobal(m, global.errorSink); // create root scope + + if (m.md && m.md.msg) + m.md.msg = semanticString(sc, m.md.msg, "deprecation message"); + + // Add import of "object", even for the "object" module. + // If it isn't there, some compiler rewrites, like + // classinst == classinst -> .object.opEquals(classinst, classinst) + // would fail inside object.d. + if (m.filetype != FileType.c && + (m.members.length == 0 || + (*m.members)[0].ident != Id.object || + (*m.members)[0].isImport() is null)) + { + auto im = new Import(Loc.initial, null, Id.object, null, 0); + m.members.shift(im); + } + if (!m.symtab) + { + // Add all symbols into module's symbol table + m.symtab = new DsymbolTable(); + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.addMember(sc, sc.scopesym); + } + } + // anything else should be run after addMember, so version/debug symbols are defined + /* Set scope for the symbols so that if we forward reference + * a symbol, it can possibly be resolved on the spot. + * If this works out well, it can be extended to all modules + * before any semantic() on any of them. + */ + m.setScope(sc); // remember module scope for semantic + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.setScope(sc); + } + for (size_t i = 0; i < m.members.length; i++) + { + Dsymbol s = (*m.members)[i]; + s.importAll(sc); + } + sc = sc.pop(); + sc.pop(); // 2 pops because Scope.createGlobal() created 2 + } + + override void visit(AttribDeclaration atb) + { + Dsymbols* d = atb.include(sc); + //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d); + if (d) + { + Scope* sc2 = atb.newScope(sc); + d.foreachDsymbol( s => s.importAll(sc2) ); + if (sc2 != sc) + sc2.pop(); + } + } + + // do not evaluate condition before semantic pass + override void visit(StaticIfDeclaration _) {} + // do not evaluate aggregate before semantic pass + override void visit(StaticForeachDeclaration _) {} +} + +extern(C++) void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion) +{ + scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion); + d.accept(v); +} + +private extern(C++) class SetFieldOffsetVisitor : Visitor +{ + alias visit = Visitor.visit; + + AggregateDeclaration ad; + FieldState* fieldState; + bool isunion; + + this(AggregateDeclaration ad, FieldState* fieldState, bool isunion) + { + this.ad = ad; + this.fieldState = fieldState; + this.isunion = isunion; + } + + override void visit(Dsymbol d) {} + + override void visit(Nspace ns) + { + //printf("Nspace::setFieldOffset() %s\n", toChars()); + if (ns._scope) // if fwd reference + dsymbolSemantic(ns, null); // try to resolve it + ns.members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); + } + + override void visit(VarDeclaration vd) + { + //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), vd.toChars()); + + if (vd.aliasTuple) + { + // If this variable was really a tuple, set the offsets for the tuple fields + vd.aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); + return; + } + + if (!vd.isField()) + return; + assert(!(vd.storage_class & (STC.static_ | STC.extern_ | STC.parameter))); + + //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); + + /* Fields that are tuples appear both as part of TupleDeclarations and + * as members. That means ignore them if they are already a field. + */ + if (vd.offset) + { + // already a field + fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 + return; + } + for (size_t i = 0; i < ad.fields.length; i++) + { + if (ad.fields[i] == vd) + { + // already a field + fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613 + return; + } + } + + // Check for forward referenced types which will fail the size() call + Type t = vd.type.toBasetype(); + if (vd.storage_class & STC.ref_) + { + // References are the size of a pointer + t = Type.tvoidptr; + } + Type tv = t.baseElemOf(); + if (tv.ty == Tstruct) + { + auto ts = cast(TypeStruct)tv; + assert(ts.sym != ad); // already checked in ad.determineFields() + if (!ts.sym.determineSize(vd.loc)) + { + vd.type = Type.terror; + vd.errors = true; + return; + } + } + + // List in ad.fields. Even if the type is error, it's necessary to avoid + // pointless error diagnostic "more initializers than fields" on struct literal. + ad.fields.push(vd); + + if (t.ty == Terror) + return; + + /* If coming after a bit field in progress, + * advance past the field + */ + fieldState.inFlight = false; + + const sz = t.size(vd.loc); + assert(sz != SIZE_INVALID && sz < uint.max); + uint memsize = cast(uint)sz; // size of member + uint memalignsize = target.fieldalign(t); // size of member for alignment purposes + vd.offset = placeField( + fieldState.offset, + memsize, memalignsize, vd.alignment, + ad.structsize, ad.alignsize, + isunion); + + //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); + } + + override void visit(BitFieldDeclaration bfd) + { + enum log = false; + static if (log) + { + printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), bfd.toChars()); + void print(const FieldState* fieldState) + { + fieldState.print(); + printf(" fieldWidth = %d bits\n", bfd.fieldWidth); + } + print(fieldState); + } + + Type t = bfd.type.toBasetype(); + const bool anon = bfd.isAnonymous(); + + // List in ad.fields. Even if the type is error, it's necessary to avoid + // pointless error diagnostic "more initializers than fields" on struct literal. + if (!anon) + ad.fields.push(bfd); + + if (t.ty == Terror) + return; + + const sz = t.size(bfd.loc); + assert(sz != SIZE_INVALID && sz < uint.max); + uint memsize = cast(uint)sz; // size of member + uint memalignsize = target.fieldalign(t); // size of member for alignment purposes + if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize); + + if (bfd.fieldWidth == 0 && !anon) + error(bfd.loc, "named bit fields cannot have 0 width"); + if (bfd.fieldWidth > memsize * 8) + error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth); + + const style = target.c.bitFieldStyle; + + void startNewField() + { + if (log) printf("startNewField()\n"); + uint alignsize; + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + if (bfd.fieldWidth > 32) + alignsize = memalignsize; + else if (bfd.fieldWidth > 16) + alignsize = 4; + else if (bfd.fieldWidth > 8) + alignsize = 2; + else + alignsize = 1; + } + else + alignsize = memsize; // not memalignsize + + uint dummy; + bfd.offset = placeField( + fieldState.offset, + memsize, alignsize, bfd.alignment, + ad.structsize, + (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize, + isunion); + + fieldState.inFlight = true; + fieldState.fieldOffset = bfd.offset; + fieldState.bitOffset = 0; + fieldState.fieldSize = memsize; + } + + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + if (bfd.fieldWidth == 0) + { + if (!isunion) + { + // Use type of zero width field to align to next field + fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + + if (ad.alignsize == 0) + ad.alignsize = 1; + if (!anon && + ad.alignsize < memalignsize) + ad.alignsize = memalignsize; + } + else if (style == TargetC.BitFieldStyle.MS) + { + if (ad.alignsize == 0) + ad.alignsize = 1; + if (bfd.fieldWidth == 0) + { + if (fieldState.inFlight && !isunion) + { + // documentation says align to next int + //const alsz = cast(uint)Type.tint32.size(); + const alsz = memsize; // but it really does this + fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + } + else if (style == TargetC.BitFieldStyle.DM) + { + if (anon && bfd.fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0)) + return; // this probably should be a bug in DMC + if (ad.alignsize == 0) + ad.alignsize = 1; + if (bfd.fieldWidth == 0) + { + if (fieldState.inFlight && !isunion) + { + const alsz = memsize; + fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); + ad.structsize = fieldState.offset; + } + + fieldState.inFlight = false; + return; + } + } + + if (!fieldState.inFlight) + { + //printf("not in flight\n"); + startNewField(); + } + else if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + // If the bit-field spans more units of alignment than its type, + // start a new field at the next alignment boundary. + if (fieldState.bitOffset == fieldState.fieldSize * 8 && + fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8) + { + if (log) printf("more units of alignment than its type\n"); + startNewField(); // the bit field is full + } + else + { + // if alignment boundary is crossed + uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset; + uint end = start + bfd.fieldWidth; + //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize); + if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8)) + { + if (log) printf("alignment is crossed\n"); + startNewField(); + } + } + } + else if (style == TargetC.BitFieldStyle.DM || + style == TargetC.BitFieldStyle.MS) + { + if (memsize != fieldState.fieldSize || + fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8) + { + //printf("new field\n"); + startNewField(); + } + } + else + assert(0); + + bfd.offset = fieldState.fieldOffset; + bfd.bitOffset = fieldState.bitOffset; + + const pastField = bfd.bitOffset + bfd.fieldWidth; + if (style == TargetC.BitFieldStyle.Gcc_Clang) + { + auto size = (pastField + 7) / 8; + fieldState.fieldSize = size; + //printf(" offset: %d, size: %d\n", offset, size); + if (isunion) + { + const newstructsize = bfd.offset + size; + if (newstructsize > ad.structsize) + ad.structsize = newstructsize; + } + else + ad.structsize = bfd.offset + size; + } + else + fieldState.fieldSize = memsize; + //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize); + //print(fieldState); + + if (!isunion) + { + fieldState.offset = bfd.offset + fieldState.fieldSize; + fieldState.bitOffset = pastField; + } + + //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize); + //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); + } + + override void visit(TemplateMixin tm) + { + //printf("TemplateMixin.setFieldOffset() %s\n", tm.toChars()); + if (tm._scope) // if fwd reference + dsymbolSemantic(tm, null); // try to resolve it + + tm.members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } ); + } + + override void visit(AttribDeclaration atd) + { + atd.include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); + } + + override void visit(AnonDeclaration anond) + { + //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", anond); + if (anond.decl) + { + /* This works by treating an AnonDeclaration as an aggregate 'member', + * so in order to place that member we need to compute the member's + * size and alignment. + */ + size_t fieldstart = ad.fields.length; + + /* Hackishly hijack ad's structsize and alignsize fields + * for use in our fake anon aggregate member. + */ + uint savestructsize = ad.structsize; + uint savealignsize = ad.alignsize; + ad.structsize = 0; + ad.alignsize = 0; + + FieldState fs; + anond.decl.foreachDsymbol( (s) + { + s.setFieldOffset(ad, &fs, anond.isunion); + if (anond.isunion) + fs.offset = 0; + }); + + /* https://issues.dlang.org/show_bug.cgi?id=13613 + * If the fields in this.members had been already + * added in ad.fields, just update *poffset for the subsequent + * field offset calculation. + */ + if (fieldstart == ad.fields.length) + { + ad.structsize = savestructsize; + ad.alignsize = savealignsize; + fieldState.offset = ad.structsize; + return; + } + + anond.anonstructsize = ad.structsize; + anond.anonalignsize = ad.alignsize; + ad.structsize = savestructsize; + ad.alignsize = savealignsize; + + // 0 sized structs are set to 1 byte + if (anond.anonstructsize == 0) + { + anond.anonstructsize = 1; + anond.anonalignsize = 1; + } + + assert(anond._scope); + auto alignment = anond._scope.alignment(); + + /* Given the anon 'member's size and alignment, + * go ahead and place it. + */ + anond.anonoffset = placeField( + fieldState.offset, + anond.anonstructsize, anond.anonalignsize, alignment, + ad.structsize, ad.alignsize, + isunion); + + // Add to the anon fields the base offset of this anonymous aggregate + //printf("anon fields, anonoffset = %d\n", anonoffset); + foreach (const i; fieldstart .. ad.fields.length) + { + VarDeclaration v = ad.fields[i]; + //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); + v.offset += anond.anonoffset; + } + } + } +} diff --git a/dmd/dtemplate.d b/dmd/dtemplate.d index 439d424e95a..682a6ada912 100644 --- a/dmd/dtemplate.d +++ b/dmd/dtemplate.d @@ -28,7 +28,7 @@ * arguments, and uses it if found. * - Otherwise, the rest of semantic is run on the `TemplateInstance`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d) @@ -69,6 +69,7 @@ import dmd.initsem; import dmd.location; import dmd.mtype; import dmd.opover; +import dmd.optimize; import dmd.root.array; import dmd.common.outbuffer; import dmd.rootobject; @@ -619,7 +620,7 @@ version (IN_LLVM) return; Dsymbol s; - if (!Dsymbol.oneMembers(members, &s, ident) || !s) + if (!Dsymbol.oneMembers(members, s, ident) || !s) return; onemember = s; @@ -761,7 +762,7 @@ else OutBuffer buf; HdrGenState hgs; - buf.writestring(ident.toString()); + buf.writestring(ident == Id.ctor ? "this" : ident.toString()); buf.writeByte('('); foreach (i, const tp; *parameters) { @@ -778,6 +779,11 @@ else { TypeFunction tf = cast(TypeFunction)fd.type; buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } } } @@ -6039,9 +6045,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol return "template instance"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { - *ps = null; + ps = null; return true; } @@ -6480,7 +6486,7 @@ version (IN_LLVM) */ Identifier id = name; Dsymbol scopesym; - Dsymbol s = sc.search(loc, id, &scopesym); + Dsymbol s = sc.search(loc, id, scopesym); if (!s) { s = sc.search_correct(id); @@ -7633,7 +7639,7 @@ version (IN_LLVM) if (members.length) { Dsymbol sa; - if (Dsymbol.oneMembers(members, &sa, tempdecl.ident) && sa) + if (Dsymbol.oneMembers(members, sa, tempdecl.ident) && sa) aliasdecl = sa; } done = true; @@ -7854,7 +7860,7 @@ extern (C++) final class TemplateMixin : TemplateInstance return "mixin"; } - override bool oneMember(Dsymbol* ps, Identifier ident) + override bool oneMember(out Dsymbol ps, Identifier ident) { return Dsymbol.oneMember(ps, ident); } @@ -7865,15 +7871,6 @@ extern (C++) final class TemplateMixin : TemplateInstance return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("TemplateMixin.setFieldOffset() %s\n", toChars()); - if (_scope) // if fwd reference - dsymbolSemantic(this, null); // try to resolve it - - members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } ); - } - override const(char)* toChars() const { OutBuffer buf; diff --git a/dmd/dtoh.d b/dmd/dtoh.d index 7c76da99d1b..30991c9171a 100644 --- a/dmd/dtoh.d +++ b/dmd/dtoh.d @@ -2,7 +2,7 @@ * This module contains the implementation of the C++ header generation available through * the command line switch -Hc. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d) @@ -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; @@ -3283,7 +3284,7 @@ ASTCodegen.Dsymbol symbolFromType(ASTCodegen.Type t) @safe */ ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name) { - if (auto mem = sym.search(Loc.initial, name, ASTCodegen.IgnoreErrors)) + if (auto mem = sym.search(Loc.initial, name, ASTCodegen.SearchOpt.ignoreErrors)) return mem; // search doesn't work for declarations inside of uninstantiated diff --git a/dmd/dversion.d b/dmd/dversion.d index aa22532061e..2e3b35264db 100644 --- a/dmd/dversion.d +++ b/dmd/dversion.d @@ -4,7 +4,7 @@ * Specification: $(LINK2 https://dlang.org/spec/version.html#version-specification, Version Specification), * $(LINK2 https://dlang.org/spec/version.html#debug_specification, Debug Specification). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d, _dversion.d) @@ -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"; diff --git a/dmd/entity.d b/dmd/entity.d index c31883f11d9..af74c3bb8d5 100644 --- a/dmd/entity.d +++ b/dmd/entity.d @@ -3,7 +3,7 @@ * * Specification $(LINK2 https://dlang.org/spec/entity.html, Named Character Entities) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/entity.d, _entity.d) diff --git a/dmd/enum.h b/dmd/enum.h index 175456c59ab..b5aeb2663be 100644 --- a/dmd/enum.h +++ b/dmd/enum.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -46,12 +46,9 @@ class EnumDeclaration final : public ScopeDsymbol 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; + 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; diff --git a/dmd/errors.d b/dmd/errors.d index 4208c60758b..fe23c6eb415 100644 --- a/dmd/errors.d +++ b/dmd/errors.d @@ -1,7 +1,7 @@ /** * Functions for raising errors. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d) @@ -661,30 +661,34 @@ private void verrorPrint(const(char)* format, va_list ap, ref ErrorInfo info) { import dmd.root.filename : FileName; const fileName = FileName(loc.filename.toDString); - if (auto file = global.fileManager.lookup(fileName)) + if (auto text = global.fileManager.lookup(fileName)) { - const(char)[][] lines = global.fileManager.getLines(fileName); - if (loc.linnum - 1 < lines.length) + auto range = global.fileManager.splitLines(cast(const(char[])) text); + size_t linnum; + foreach (line; range) { - auto line = lines[loc.linnum - 1]; + ++linnum; + if (linnum != loc.linnum) + continue; if (loc.charnum < line.length) { fprintf(stderr, "%.*s\n", cast(int)line.length, line.ptr); // The number of column bytes and the number of display columns // occupied by a character are not the same for non-ASCII charaters. // https://issues.dlang.org/show_bug.cgi?id=21849 - size_t c = 0; - while (c < loc.charnum - 1) + size_t col = 0; + while (col < loc.charnum - 1) { import dmd.root.utf : utf_decodeChar; dchar u; - const msg = utf_decodeChar(line, c, u); + const msg = utf_decodeChar(line, col, u); assert(msg is null, msg); fputc(' ', stderr); } fputc('^', stderr); fputc('\n', stderr); } + break; } } } diff --git a/dmd/errors.h b/dmd/errors.h index 759ad277fda..308e81e30ba 100644 --- a/dmd/errors.h +++ b/dmd/errors.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/errorsink.d b/dmd/errorsink.d index ce2351738d6..afea689546b 100644 --- a/dmd/errorsink.d +++ b/dmd/errorsink.d @@ -1,7 +1,7 @@ /** * Provides an abstraction for what to do with error messages. * - * Copyright: Copyright (C) 2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2023-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errorsink.d, _errorsink.d) @@ -60,6 +60,20 @@ class ErrorSinkNull : ErrorSink void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { } } +/***************************************** + * Ignores the messages, but sets `sawErrors` for any calls to `error()` + */ +class ErrorSinkLatch : ErrorSinkNull +{ + nothrow: + extern (C++): + override: + + bool sawErrors; + + void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; } +} + /***************************************** * Simplest implementation, just sends messages to stderr. * See also: ErrorSinkCompiler. diff --git a/dmd/escape.d b/dmd/escape.d index 3f85ea08320..433907a17be 100644 --- a/dmd/escape.d +++ b/dmd/escape.d @@ -1,7 +1,7 @@ /** * Most of the logic to implement scoped pointers and scoped references is here. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/escape.d, _escape.d) @@ -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; @@ -1296,7 +1296,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { if (log) { - printf("byref `%s` %s\n", v.toChars(), toChars(buildScopeRef(v.storage_class))); + printf("byref `%s` %s\n", v.toChars(), ScopeRefToChars(buildScopeRef(v.storage_class))); } // 'featureState' tells us whether to emit an error or a deprecation, @@ -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; } @@ -2343,7 +2343,7 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) VarDeclaration[10] tmp = void; size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.length : 0); - import dmd.common.string : SmallBuffer; + import dmd.common.smallbuffer : SmallBuffer; auto sb = SmallBuffer!VarDeclaration(dim, tmp[]); VarDeclaration[] array = sb[]; @@ -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); } /*************************************** diff --git a/dmd/expression.d b/dmd/expression.d index 033094707a6..e1b41c2088b 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d) @@ -18,25 +18,18 @@ import core.stdc.stdio; import core.stdc.string; import dmd.aggregate; -import dmd.aliasthis; -import dmd.arrayop; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.gluelayer; -import dmd.ctfeexpr; -import dmd.ctorflow; import dmd.dclass; import dmd.declaration; import dmd.dimport; import dmd.dmodule; -import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; import dmd.errors; import dmd.errorsink; -import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; @@ -45,39 +38,20 @@ import dmd.identifier; import dmd.init; import dmd.location; import dmd.mtype; -import dmd.opover; -import dmd.optimize; import dmd.root.complex; import dmd.root.ctfloat; -import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.optional; import dmd.root.rmem; import dmd.rootobject; import dmd.root.string; import dmd.root.utf; -import dmd.safe; import dmd.target; import dmd.tokens; import dmd.visitor; enum LOGSEMANTIC = false; -void emplaceExp(T : Expression, Args...)(void* p, Args args) -{ - static if (__VERSION__ < 2099) - const init = typeid(T).initializer; - else - const init = __traits(initSymbol, T); - p[0 .. __traits(classInstanceSize, T)] = init[]; - (cast(T)p).__ctor(args); -} - -void emplaceExp(T : UnionExp)(T* p, Expression e) -{ - memcpy(p, cast(void*)e, e.size); -} - /// Return value for `checkModifiable` enum Modifiable { @@ -118,45 +92,6 @@ inout(Expression) lastComma(inout Expression e) } -/*********************************** - * Determine if a `this` is needed to access `d`. - * Params: - * sc = context - * d = declaration to check - * Returns: - * true means a `this` is needed - */ -bool isNeedThisScope(Scope* sc, Declaration d) -{ - if (sc.intypeof == 1) - return false; - - AggregateDeclaration ad = d.isThis(); - if (!ad) - return false; - //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars()); - - for (Dsymbol s = sc.parent; s; s = s.toParentLocal()) - { - //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2()); - if (AggregateDeclaration ad2 = s.isAggregateDeclaration()) - { - if (ad2 == ad) - return false; - else if (ad2.isNested()) - continue; - else - return true; - } - if (FuncDeclaration f = s.isFuncDeclaration()) - { - if (f.isMemberLocal()) - break; - } - } - return true; -} - /**************************************** * Expand tuples in-place. * @@ -315,70 +250,6 @@ TemplateDeclaration getFuncTemplateDecl(Dsymbol s) @safe return null; } -/****************************************************************/ -/* A type meant as a union of all the Expression types, - * to serve essentially as a Variant that will sit on the stack - * during CTFE to reduce memory consumption. - */ -extern (D) struct UnionExp -{ - // yes, default constructor does nothing - extern (D) this(Expression e) - { - memcpy(&this, cast(void*)e, e.size); - } - - /* Extract pointer to Expression - */ - extern (D) Expression exp() return - { - return cast(Expression)&u; - } - - /* Convert to an allocated Expression - */ - extern (D) Expression copy() - { - Expression e = exp(); - //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr); - assert(e.size <= u.sizeof); - switch (e.op) - { - case EXP.cantExpression: return CTFEExp.cantexp; - case EXP.voidExpression: return CTFEExp.voidexp; - case EXP.break_: return CTFEExp.breakexp; - case EXP.continue_: return CTFEExp.continueexp; - case EXP.goto_: return CTFEExp.gotoexp; - default: return e.copy(); - } - } - -private: - // Ensure that the union is suitably aligned. - align(8) union _AnonStruct_u - { - char[__traits(classInstanceSize, Expression)] exp; - char[__traits(classInstanceSize, IntegerExp)] integerexp; - char[__traits(classInstanceSize, ErrorExp)] errorexp; - char[__traits(classInstanceSize, RealExp)] realexp; - char[__traits(classInstanceSize, ComplexExp)] complexexp; - char[__traits(classInstanceSize, SymOffExp)] symoffexp; - char[__traits(classInstanceSize, StringExp)] stringexp; - char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp; - char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp; - char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp; - char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp; - char[__traits(classInstanceSize, NullExp)] nullexp; - char[__traits(classInstanceSize, DotVarExp)] dotvarexp; - char[__traits(classInstanceSize, AddrExp)] addrexp; - char[__traits(classInstanceSize, IndexExp)] indexexp; - char[__traits(classInstanceSize, SliceExp)] sliceexp; - char[__traits(classInstanceSize, VectorExp)] vectorexp; - } - - _AnonStruct_u u; -} - /************************ TypeDotIdExp ************************************/ /* Things like: * int.size @@ -550,10 +421,7 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode override const(char)* toChars() const { - OutBuffer buf; - HdrGenState hgs; - toCBuffer(this, buf, hgs); - return buf.extractChars(); + return .toChars(this); } /********************************** @@ -679,71 +547,6 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode return false; } - /******************************* - * Give error if we're not an lvalue. - * If we can, convert expression to be an lvalue. - */ - Expression toLvalue(Scope* sc, Expression e) - { - if (!e) - e = this; - else if (!loc.isValid()) - loc = e.loc; - - if (e.op == EXP.type) - error(loc, "`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind()); - else - error(loc, "`%s` is not an lvalue and cannot be modified", e.toChars()); - - return ErrorExp.get(); - } - - Expression modifiableLvalue(Scope* sc, Expression e) - { - //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars()); - // See if this expression is a modifiable lvalue (i.e. not const) - if (checkModifiable(this, sc) == Modifiable.yes) - { - assert(type); - if (!type.isMutable()) - { - if (auto dve = this.isDotVarExp()) - { - if (isNeedThisScope(sc, dve.var)) - for (Dsymbol s = sc.func; s; s = s.toParentLocal()) - { - FuncDeclaration ff = s.isFuncDeclaration(); - if (!ff) - break; - if (!ff.type.isMutable) - { - error(loc, "cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod)); - return ErrorExp.get(); - } - } - } - error(loc, "cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars()); - return ErrorExp.get(); - } - else if (!type.isAssignable()) - { - error(loc, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members", - toChars(), type.toChars()); - return ErrorExp.get(); - } - } - return toLvalue(sc, e); - } - - /**************************************** - * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc. - */ - Expression resolveLoc(const ref Loc loc, Scope* sc) - { - this.loc = loc; - return this; - } - /**************************************** * Check that the expression has a valid type. * If not, generates an error "... has no type". @@ -836,417 +639,6 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode return checkValue(); } - extern (D) final bool checkDeprecated(Scope* sc, Dsymbol s) - { - return s.checkDeprecated(loc, sc); - } - - extern (D) final bool checkDisabled(Scope* sc, Dsymbol s) - { - if (auto d = s.isDeclaration()) - { - return d.checkDisabled(loc, sc); - } - - return false; - } - - /********************************************* - * Calling function f. - * Check the purity, i.e. if we're in a pure function - * we can only call other pure functions. - * Returns true if error occurs. - */ - extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f) - { - if (!sc.func) - return false; - if (sc.func == f) - return false; - if (sc.intypeof == 1) - return false; - if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) - return false; - - // If the call has a pure parent, then the called func must be pure. - if (!f.isPure() && checkImpure(sc, loc, null, f)) - { - error(loc, "`pure` %s `%s` cannot call impure %s `%s`", - sc.func.kind(), sc.func.toPrettyChars(), f.kind(), - f.toPrettyChars()); - - if (!f.isDtorDeclaration()) - errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_); - - checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure"); - return true; - } - return false; - } - - /** - * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one - * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but - * the generated dtor is not). - * In that case the method will identify and print all members causing the attribute - * missmatch. - * - * Params: - * sc = scope - * f = potential `DtorDeclaration` - * check = current check (e.g. whether it's pure) - * checkName = the kind of check (e.g. `"pure"`) - */ - extern (D) final void checkOverriddenDtor(Scope* sc, FuncDeclaration f, - scope bool function(DtorDeclaration) check, const string checkName - ) { - auto dd = f.isDtorDeclaration(); - if (!dd || !dd.isGenerated()) - return; - - // DtorDeclaration without parents should fail at an earlier stage - auto ad = cast(AggregateDeclaration) f.toParent2(); - assert(ad); - - if (ad.userDtors.length) - { - if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well) - return; - - // Sanity check - assert(!check(ad.fieldDtor)); - } - - dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:", - dd.isGenerated() ? "generated " : "".ptr, - ad.toChars, - cast(int) checkName.length, checkName.ptr); - - // Search for the offending fields - foreach (field; ad.fields) - { - // Only structs may define automatically called destructors - auto ts = field.type.isTypeStruct(); - if (!ts) - { - // But they might be part of a static array - auto ta = field.type.isTypeSArray(); - if (!ta) - continue; - - ts = ta.baseElemOf().isTypeStruct(); - if (!ts) - continue; - } - - auto fieldSym = ts.toDsymbol(sc); - assert(fieldSym); // Resolving ts must succeed because missing defs. should error before - - auto fieldSd = fieldSym.isStructDeclaration(); - assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR - - if (fieldSd.dtor && !check(fieldSd.dtor)) - { - field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars()); - - if (fieldSd.dtor.isGenerated()) - checkOverriddenDtor(sc, fieldSd.dtor, check, checkName); - else - fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here", - cast(int) checkName.length, checkName.ptr, fieldSd.toChars()); - } - } - } - - /******************************************* - * Accessing variable v. - * Check for purity and safety violations. - * Returns true if error occurs. - */ - extern (D) final bool checkPurity(Scope* sc, VarDeclaration v) - { - //printf("v = %s %s\n", v.type.toChars(), v.toChars()); - /* Look for purity and safety violations when accessing variable v - * from current function. - */ - if (!sc.func) - return false; - if (sc.intypeof == 1) - return false; // allow violations inside typeof(expression) - if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) - return false; // allow violations inside compile-time evaluated expressions and debug conditionals - if (v.ident == Id.ctfe) - return false; // magic variable never violates pure and safe - if (v.isImmutable()) - return false; // always safe and pure to access immutables... - if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf())) - return false; // or const global/parameter values which have no mutable indirections - if (v.storage_class & STC.manifest) - return false; // ...or manifest constants - - // accessing empty structs is pure - // https://issues.dlang.org/show_bug.cgi?id=18694 - // https://issues.dlang.org/show_bug.cgi?id=21464 - // https://issues.dlang.org/show_bug.cgi?id=23589 - if (v.type.ty == Tstruct) - { - StructDeclaration sd = (cast(TypeStruct)v.type).sym; - if (sd.members) // not opaque - { - if (sd.semanticRun >= PASS.semanticdone) - sd.determineSize(v.loc); - if (sd.hasNoFields) - return false; - } - } - - bool err = false; - if (v.isDataseg()) - { - // https://issues.dlang.org/show_bug.cgi?id=7533 - // Accessing implicit generated __gate is pure. - if (v.ident == Id.gate) - return false; - - if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v)) - { - error(loc, "`pure` %s `%s` cannot access mutable static data `%s`", - sc.func.kind(), sc.func.toPrettyChars(), v.toChars()); - err = true; - } - } - else - { - /* Given: - * void f() { - * int fx; - * pure void g() { - * int gx; - * /+pure+/ void h() { - * int hx; - * /+pure+/ void i() { } - * } - * } - * } - * i() can modify hx and gx but not fx - */ - - Dsymbol vparent = v.toParent2(); - for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent)) - { - if (s == vparent) - break; - - if (AggregateDeclaration ad = s.isAggregateDeclaration()) - { - if (ad.isNested()) - continue; - break; - } - FuncDeclaration ff = s.isFuncDeclaration(); - if (!ff) - break; - if (ff.isNested() || ff.isThis()) - { - if (ff.type.isImmutable() || - ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod)) - { - OutBuffer ffbuf; - OutBuffer vbuf; - MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod); - MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod); - error(loc, "%s%s `%s` cannot access %sdata `%s`", - ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars()); - err = true; - break; - } - continue; - } - break; - } - } - - /* Do not allow safe functions to access __gshared data - */ - if (v.storage_class & STC.gshared) - { - if (sc.setUnsafe(false, this.loc, - "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v)) - { - err = true; - } - } - - return err; - } - - /* - Check if sc.func is impure or can be made impure. - Returns true on error, i.e. if sc.func is pure and cannot be made impure. - */ - private static bool checkImpure(Scope* sc, Loc loc, const(char)* fmt, RootObject arg0) - { - return sc.func && (isRootTraitsCompilesScope(sc) - ? sc.func.isPureBypassingInference() >= PURE.weak - : sc.func.setImpure(loc, fmt, arg0)); - } - - /********************************************* - * Calling function f. - * Check the safety, i.e. if we're in a @safe function - * we can only call @safe or @trusted functions. - * Returns true if error occurs. - */ - extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f) - { - if (sc.func == f) - return false; - if (sc.intypeof == 1) - return false; - if (sc.flags & SCOPE.debug_) - return false; - if ((sc.flags & SCOPE.ctfe) && sc.func) - return false; - - if (!sc.func) - { - if (sc.varDecl && !f.safetyInprocess && !f.isSafe() && !f.isTrusted()) - { - if (sc.varDecl.storage_class & STC.safe) - { - error(loc, "`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`", - sc.varDecl.toChars(), f.toChars()); - return true; - } - else - { - sc.varDecl.storage_class |= STC.system; - sc.varDecl.systemInferred = true; - } - } - return false; - } - - if (!f.isSafe() && !f.isTrusted()) - { - if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f)) - { - if (!loc.isValid()) // e.g. implicitly generated dtor - loc = sc.func.loc; - - const prettyChars = f.toPrettyChars(); - error(loc, "`@safe` %s `%s` cannot call `@system` %s `%s`", - sc.func.kind(), sc.func.toPrettyChars(), f.kind(), - prettyChars); - if (!f.isDtorDeclaration) - errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe); - .errorSupplemental(f.loc, "`%s` is declared here", prettyChars); - - checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system"); - - return true; - } - } - else if (f.isSafe() && f.safetyViolation) - { - // for dip1000 by default transition, print deprecations for calling functions that will become `@system` - if (sc.func.isSafeBypassingInference()) - { - .deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars()); - errorSupplementalInferredAttr(f, 10, true, STC.safe); - } - else if (!sc.func.safetyViolation) - { - import dmd.func : AttributeViolation; - sc.func.safetyViolation = new AttributeViolation(this.loc, null, f, null, null); - } - } - return false; - } - - /********************************************* - * Calling function f. - * Check the @nogc-ness, i.e. if we're in a @nogc function - * we can only call other @nogc functions. - * Returns true if error occurs. - */ - extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f) - { - if (!sc.func) - return false; - if (sc.func == f) - return false; - if (sc.intypeof == 1) - return false; - if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) - return false; - /* The original expressions (`new S(...)` or `new S[...]``) will be - * 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) - return false; - - if (!f.isNogc()) - { - if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f)) - { - if (loc.linnum == 0) // e.g. implicitly generated dtor - loc = sc.func.loc; - - // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)), - // so don't print anything to avoid double error messages. - if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT - || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX - || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT)) - { - error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`", - sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); - - if (!f.isDtorDeclaration) - f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc); - } - - checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc"); - - return true; - } - } - return false; - } - - /******************************************** - * Check that the postblit is callable if t is an array of structs. - * Returns true if error happens. - */ - extern (D) final bool checkPostblit(Scope* sc, Type t) - { - if (auto ts = t.baseElemOf().isTypeStruct()) - { - if (global.params.useTypeInfo && Type.dtypeinfo) - { - // https://issues.dlang.org/show_bug.cgi?id=11395 - // Require TypeInfo generation for array concatenation - semanticTypeInfo(sc, t); - } - - StructDeclaration sd = ts.sym; - if (sd.postblit) - { - if (sd.postblit.checkDisabled(loc, sc)) - return true; - - //checkDeprecated(sc, sd.postblit); // necessary? - checkPurity(sc, sd.postblit); - checkSafety(sc, sd.postblit); - checkNogc(sc, sd.postblit); - //checkAccess(sd, loc, sc, sd.postblit); // necessary? - return false; - } - } - return false; - } - /******************************* * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) @@ -1309,11 +701,6 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode return this; } - final Expression optimize(int result, bool keepLvalue = false) - { - return Expression_optimize(this, result, keepLvalue); - } - final int isConst() { //printf("Expression::isConst(): %s\n", e.toChars()); @@ -1601,16 +988,6 @@ extern (C++) final class IntegerExp : Expression return typeof(return)(r); } - override Expression toLvalue(Scope* sc, Expression e) - { - if (!e) - e = this; - else if (!loc.isValid()) - loc = e.loc; - error(e.loc, "cannot modify constant `%s`", e.toChars()); - return ErrorExp.get(); - } - override void accept(Visitor v) { v.visit(this); @@ -1736,7 +1113,7 @@ extern (C++) final class IntegerExp : Expression */ extern (C++) final class ErrorExp : Expression { - private extern (D) this() + extern (D) this() { super(Loc.initial, EXP.error); type = Type.terror; @@ -1759,11 +1136,6 @@ extern (C++) final class ErrorExp : Expression return errorexp; } - override Expression toLvalue(Scope* sc, Expression e) - { - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -2001,11 +1373,6 @@ extern (C++) class IdentifierExp : Expression return true; } - override final Expression toLvalue(Scope* sc, Expression e) - { - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -2050,11 +1417,6 @@ extern (C++) final class DsymbolExp : Expression return true; } - override Expression toLvalue(Scope* sc, Expression e) - { - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -2101,16 +1463,6 @@ extern (C++) class ThisExp : Expression return type.toBasetype().ty != Tclass; } - override final Expression toLvalue(Scope* sc, Expression e) - { - if (type.toBasetype().ty == Tclass) - { - // Class `this` is an rvalue; struct `this` is an lvalue. - return Expression.toLvalue(sc, e); - } - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -2478,18 +1830,6 @@ extern (C++) final class StringExp : Expression return (type && type.toBasetype().ty == Tsarray); } - override Expression toLvalue(Scope* sc, Expression e) - { - //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL); - return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e); - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - error(loc, "cannot modify string literal `%s`", toChars()); - return ErrorExp.get(); - } - /******************************** * Convert string contents to a 0 terminated string, * allocated by mem.xmalloc(). @@ -2919,7 +2259,7 @@ version (IN_LLVM) } else { - Symbol* sym; /// back end symbol to initialize with literal + void* sym; /// back end symbol to initialize with literal (used as a Symbol*) } /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. @@ -3074,14 +2414,6 @@ else return -1; } - override Expression toLvalue(Scope* sc, Expression e) - { - if (sc.flags & SCOPE.Cfile) - return this; // C struct literals are lvalues - else - return Expression.toLvalue(sc, e); - } - override void accept(Visitor v) { v.visit(this); @@ -3227,15 +2559,6 @@ extern (C++) final class TemplateExp : Expression return fd !is null; } - override Expression toLvalue(Scope* sc, Expression e) - { - if (!fd) - return Expression.toLvalue(sc, e); - - assert(sc); - return symbolToExp(fd, loc, sc, true); - } - override bool checkType() { error(loc, "%s `%s` has no type", td.kind(), toChars()); @@ -3442,43 +2765,6 @@ extern (C++) final class VarExp : SymbolExp return true; } - override Expression toLvalue(Scope* sc, Expression e) - { - if (var.storage_class & STC.manifest) - { - error(loc, "manifest constant `%s` cannot be modified", var.toChars()); - return ErrorExp.get(); - } - if (var.storage_class & STC.lazy_ && !delegateWasExtracted) - { - error(loc, "lazy variable `%s` cannot be modified", var.toChars()); - return ErrorExp.get(); - } - if (var.ident == Id.ctfe) - { - error(loc, "cannot modify compiler-generated variable `__ctfe`"); - return ErrorExp.get(); - } - if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574 - { - error(loc, "cannot modify operator `$`"); - return ErrorExp.get(); - } - return this; - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - //printf("VarExp::modifiableLvalue('%s')\n", var.toChars()); - if (var.storage_class & STC.manifest) - { - error(loc, "cannot modify manifest constant `%s`", toChars()); - return ErrorExp.get(); - } - // See if this expression is a modifiable lvalue (i.e. not const) - return Expression.modifiableLvalue(sc, e); - } - override void accept(Visitor v) { v.visit(this); @@ -3505,11 +2791,6 @@ extern (C++) final class OverExp : Expression return true; } - override Expression toLvalue(Scope* sc, Expression e) - { - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -3555,52 +2836,6 @@ extern (C++) final class FuncExp : Expression return false; } - extern (D) void genIdent(Scope* sc) - { - if (fd.ident == Id.empty) - { - const(char)[] s; - if (fd.fes) - s = "__foreachbody"; - else if (fd.tok == TOK.reserved) - s = "__lambda"; - else if (fd.tok == TOK.delegate_) - s = "__dgliteral"; - else - s = "__funcliteral"; - - DsymbolTable symtab; - if (FuncDeclaration func = sc.parent.isFuncDeclaration()) - { - if (func.localsymtab is null) - { - // Inside template constraint, symtab is not set yet. - // Initialize it lazily. - func.localsymtab = new DsymbolTable(); - } - symtab = func.localsymtab; - } - else - { - ScopeDsymbol sds = sc.parent.isScopeDsymbol(); - if (!sds.symtab) - { - // Inside template constraint, symtab may not be set yet. - // Initialize it lazily. - assert(sds.isTemplateInstance()); - sds.symtab = new DsymbolTable(); - } - symtab = sds.symtab; - } - assert(symtab); - Identifier id = Identifier.generateId(s, symtab.length() + 1); - fd.ident = id; - if (td) - td.ident = id; - symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd); - } - } - override FuncExp syntaxCopy() { if (td) @@ -3848,12 +3083,6 @@ extern (C++) abstract class UnaExp : Expression } - override final Expression resolveLoc(const ref Loc loc, Scope* sc) - { - e1 = e1.resolveLoc(loc, sc); - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -3969,18 +3198,6 @@ extern (C++) class BinAssignExp : BinExp return true; } - override final Expression toLvalue(Scope* sc, Expression ex) - { - // Lvalue-ness will be handled in glue layer. - return this; - } - - override final Expression modifiableLvalue(Scope* sc, Expression e) - { - // should check e1.checkModifiable() ? - return toLvalue(sc, this); - } - override void accept(Visitor v) { v.visit(this); @@ -4167,78 +3384,26 @@ extern (C++) final class DotTemplateExp : UnaExp */ extern (C++) final class DotVarExp : UnaExp { - Declaration var; - bool hasOverloads; - - extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true) @safe - { - if (var.isVarDeclaration()) - hasOverloads = false; - - super(loc, EXP.dotVariable, e); - //printf("DotVarExp()\n"); - this.var = var; - this.hasOverloads = hasOverloads; - } - - override bool isLvalue() - { - if (e1.op != EXP.structLiteral) - return true; - auto vd = var.isVarDeclaration(); - return !(vd && vd.isField()); - } - - override Expression toLvalue(Scope* sc, Expression e) - { - //printf("DotVarExp::toLvalue(%s)\n", toChars()); - if (sc && sc.flags & SCOPE.Cfile) - { - /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator - * is an lvalue if the first expression is an lvalue. - */ - if (!e1.isLvalue()) - return Expression.toLvalue(sc, e); - } - if (!isLvalue()) - return Expression.toLvalue(sc, e); - if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor)) - { - if (VarDeclaration vd = var.isVarDeclaration()) - { - auto ad = vd.isMember2(); - if (ad && ad.fields.length == sc.ctorflow.fieldinit.length) - { - foreach (i, f; ad.fields) - { - if (f == vd) - { - if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor)) - { - /* If the address of vd is taken, assume it is thereby initialized - * https://issues.dlang.org/show_bug.cgi?id=15869 - */ - modifyFieldVar(loc, sc, vd, e1); - } - break; - } - } - } - } - } - return this; - } + Declaration var; + bool hasOverloads; - override Expression modifiableLvalue(Scope* sc, Expression e) + extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true) @safe { - version (none) - { - printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); - printf("e1.type = %s\n", e1.type.toChars()); - printf("var.type = %s\n", var.type.toChars()); - } + if (var.isVarDeclaration()) + hasOverloads = false; + + super(loc, EXP.dotVariable, e); + //printf("DotVarExp()\n"); + this.var = var; + this.hasOverloads = hasOverloads; + } - return Expression.modifiableLvalue(sc, e); + override bool isLvalue() + { + if (e1.op != EXP.structLiteral) + return true; + auto vd = var.isVarDeclaration(); + return !(vd && vd.isField()); } override void accept(Visitor v) @@ -4272,49 +3437,6 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs)); } - extern (D) bool findTempDecl(Scope* sc) - { - static if (LOGSEMANTIC) - { - printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars()); - } - if (ti.tempdecl) - return true; - - Expression e = new DotIdExp(loc, e1, ti.name); - e = e.expressionSemantic(sc); - if (e.op == EXP.dot) - e = (cast(DotExp)e).e2; - - Dsymbol s = null; - switch (e.op) - { - case EXP.overloadSet: - s = (cast(OverExp)e).vars; - break; - - case EXP.dotTemplateDeclaration: - s = (cast(DotTemplateExp)e).td; - break; - - case EXP.scope_: - s = (cast(ScopeExp)e).sds; - break; - - case EXP.dotVariable: - s = (cast(DotVarExp)e).var; - break; - - case EXP.variable: - s = (cast(VarExp)e).var; - break; - - default: - return false; - } - return ti.updateTempDecl(sc, s); - } - override bool checkType() { // Same logic as ScopeExp.checkType() @@ -4519,13 +3641,6 @@ extern (C++) final class CallExp : UnaExp return false; } - override Expression toLvalue(Scope* sc, Expression e) - { - if (isLvalue()) - return this; - return Expression.toLvalue(sc, e); - } - override void accept(Visitor v) { v.visit(this); @@ -4633,30 +3748,6 @@ extern (C++) final class PtrExp : UnaExp return true; } - override Expression toLvalue(Scope* sc, Expression e) - { - return this; - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars()); - Declaration var; - if (auto se = e1.isSymOffExp()) - var = se.var; - else if (auto ve = e1.isVarExp()) - var = ve.var; - if (var && var.type.isFunction_Delegate_PtrToFunction()) - { - if (var.type.isTypeFunction()) - error(loc, "function `%s` is not an lvalue and cannot be modified", var.toChars()); - else - error(loc, "function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars()); - return ErrorExp.get(); - } - return Expression.modifiableLvalue(sc, e); - } - override void accept(Visitor v) { v.visit(this); @@ -4788,19 +3879,6 @@ extern (C++) final class CastExp : UnaExp e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf()); } - override Expression toLvalue(Scope* sc, Expression e) - { - if (sc && sc.flags & SCOPE.Cfile) - { - /* C11 6.5.4-5: A cast does not yield an lvalue. - */ - return Expression.toLvalue(sc, e); - } - if (isLvalue()) - return this; - return Expression.toLvalue(sc, e); - } - override void accept(Visitor v) { v.visit(this); @@ -4855,12 +3933,6 @@ extern (C++) final class VectorArrayExp : UnaExp return e1.isLvalue(); } - override Expression toLvalue(Scope* sc, Expression e) - { - e1 = e1.toLvalue(sc, e); - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -4918,18 +3990,6 @@ extern (C++) final class SliceExp : UnaExp return (type && type.toBasetype().ty == Tsarray); } - override Expression toLvalue(Scope* sc, Expression e) - { - //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL); - return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e); - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - error(loc, "slice expression `%s` is not a modifiable lvalue", toChars()); - return this; - } - override Optional!bool toBool() { return e1.toBool(); @@ -4997,13 +4057,6 @@ extern (C++) final class ArrayExp : UnaExp return true; } - override Expression toLvalue(Scope* sc, Expression e) - { - if (type && type.toBasetype().ty == Tvoid) - error(loc, "`void`s have no value"); - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -5051,18 +4104,6 @@ extern (C++) final class CommaExp : BinExp return e2.isLvalue(); } - override Expression toLvalue(Scope* sc, Expression e) - { - e2 = e2.toLvalue(sc, null); - return this; - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - e2 = e2.modifiableLvalue(sc, e); - return this; - } - override Optional!bool toBool() { return e2.toBool(); @@ -5138,21 +4179,6 @@ extern (C++) final class DelegatePtrExp : UnaExp return e1.isLvalue(); } - override Expression toLvalue(Scope* sc, Expression e) - { - e1 = e1.toLvalue(sc, e); - return this; - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - if (sc.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this)) - { - return ErrorExp.get(); - } - return Expression.modifiableLvalue(sc, e); - } - override void accept(Visitor v) { v.visit(this); @@ -5176,21 +4202,6 @@ extern (C++) final class DelegateFuncptrExp : UnaExp return e1.isLvalue(); } - override Expression toLvalue(Scope* sc, Expression e) - { - e1 = e1.toLvalue(sc, e); - return this; - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - if (sc.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this)) - { - return ErrorExp.get(); - } - return Expression.modifiableLvalue(sc, e); - } - override void accept(Visitor v) { v.visit(this); @@ -5238,23 +4249,6 @@ extern (C++) final class IndexExp : BinExp return true; } - override Expression toLvalue(Scope* sc, Expression e) - { - if (isLvalue()) - return this; - return Expression.toLvalue(sc, e); - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); - Expression ex = markSettingAAElem(); - if (ex.op == EXP.error) - return ex; - - return Expression.modifiableLvalue(sc, e); - } - extern (D) Expression markSettingAAElem() { if (e1.type.toBasetype().ty == Taarray) @@ -5357,20 +4351,6 @@ extern (C++) class AssignExp : BinExp return true; } - override final Expression toLvalue(Scope* sc, Expression ex) - { - if (e1.op == EXP.slice || e1.op == EXP.arrayLength) - { - return Expression.toLvalue(sc, ex); - } - - /* In front-end level, AssignExp should make an lvalue of e1. - * Taking the address of e1 will be handled in low level layer, - * so this function does nothing. - */ - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -5768,13 +4748,6 @@ extern (C++) final class CatExp : BinExp super(loc, EXP.concatenate, e1, e2); } - override Expression resolveLoc(const ref Loc loc, Scope* sc) - { - e1 = e1.resolveLoc(loc, sc); - e2 = e2.resolveLoc(loc, sc); - return this; - } - override void accept(Visitor v) { v.visit(this); @@ -6109,28 +5082,6 @@ extern (C++) final class CondExp : BinExp return e1.isLvalue() && e2.isLvalue(); } - override Expression toLvalue(Scope* sc, Expression ex) - { - // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) - CondExp e = cast(CondExp)copy(); - e.e1 = e1.toLvalue(sc, null).addressOf(); - e.e2 = e2.toLvalue(sc, null).addressOf(); - e.type = type.pointerTo(); - return new PtrExp(loc, e, type); - } - - override Expression modifiableLvalue(Scope* sc, Expression e) - { - if (!e1.isLvalue() && !e2.isLvalue()) - { - error(loc, "conditional expression `%s` is not a modifiable lvalue", toChars()); - return ErrorExp.get(); - } - e1 = e1.modifiableLvalue(sc, e1); - e2 = e2.modifiableLvalue(sc, e2); - return toLvalue(sc, this); - } - override void accept(Visitor v) { v.visit(this); @@ -6180,19 +5131,6 @@ extern (C++) final class FileInitExp : DefaultInitExp super(loc, tok); } - override Expression resolveLoc(const ref Loc loc, Scope* sc) - { - //printf("FileInitExp::resolve() %s\n", toChars()); - const(char)* s; - if (op == EXP.fileFullPath) - s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars()); - else - s = loc.isValid() ? loc.filename : sc._module.ident.toChars(); - - Expression e = new StringExp(loc, s.toDString()); - return e.expressionSemantic(sc); - } - override void accept(Visitor v) { v.visit(this); @@ -6209,12 +5147,6 @@ extern (C++) final class LineInitExp : DefaultInitExp super(loc, EXP.line); } - override Expression resolveLoc(const ref Loc loc, Scope* sc) - { - Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); - return e.expressionSemantic(sc); - } - override void accept(Visitor v) { v.visit(this); @@ -6231,13 +5163,6 @@ extern (C++) final class ModuleInitExp : DefaultInitExp super(loc, EXP.moduleString); } - override Expression resolveLoc(const ref Loc loc, Scope* sc) - { - const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); - Expression e = new StringExp(loc, s); - return e.expressionSemantic(sc); - } - override void accept(Visitor v) { v.visit(this); @@ -6254,19 +5179,6 @@ extern (C++) final class FuncInitExp : DefaultInitExp super(loc, EXP.functionString); } - override Expression resolveLoc(const ref Loc loc, Scope* sc) - { - const(char)* s; - if (sc.callsc && sc.callsc.func) - s = sc.callsc.func.Dsymbol.toPrettyChars(); - else if (sc.func) - s = sc.func.Dsymbol.toPrettyChars(); - else - s = ""; - Expression e = new StringExp(loc, s.toDString()); - return e.expressionSemantic(sc); - } - override void accept(Visitor v) { v.visit(this); @@ -6283,29 +5195,153 @@ extern (C++) final class PrettyFuncInitExp : DefaultInitExp super(loc, EXP.prettyFunction); } - override Expression resolveLoc(const ref Loc loc, Scope* sc) + override void accept(Visitor v) + { + v.visit(this); + } +} + +/*********************************************************** + * A reference to a class, or an interface. We need this when we + * point to a base class (we must record what the type is). + */ +extern (C++) final class ClassReferenceExp : Expression +{ + StructLiteralExp value; + + extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) @safe + { + super(loc, EXP.classReference); + assert(lit && lit.sd && lit.sd.isClassDeclaration()); + this.value = lit; + this.type = type; + } + + ClassDeclaration originalClass() { - FuncDeclaration fd = (sc.callsc && sc.callsc.func) - ? sc.callsc.func - : sc.func; + return value.sd.isClassDeclaration(); + } - const(char)* s; - if (fd) + // Return index of the field, or -1 if not found + int getFieldIndex(Type fieldtype, uint fieldoffset) + { + ClassDeclaration cd = originalClass(); + uint fieldsSoFar = 0; + for (size_t j = 0; j < value.elements.length; j++) { - const funcStr = fd.Dsymbol.toPrettyChars(); - OutBuffer buf; - functionToBufferWithIdent(fd.type.isTypeFunction(), buf, funcStr, fd.isStatic); - s = buf.extractChars(); + while (j - fieldsSoFar >= cd.fields.length) + { + fieldsSoFar += cd.fields.length; + cd = cd.baseClass; + } + VarDeclaration v2 = cd.fields[j - fieldsSoFar]; + if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size()) + { + return cast(int)(value.elements.length - fieldsSoFar - cd.fields.length + (j - fieldsSoFar)); + } } - else + return -1; + } + + // Return index of the field, or -1 if not found + // Same as getFieldIndex, but checks for a direct match with the VarDeclaration + int findFieldIndexByName(VarDeclaration v) + { + ClassDeclaration cd = originalClass(); + size_t fieldsSoFar = 0; + for (size_t j = 0; j < value.elements.length; j++) { - s = ""; + while (j - fieldsSoFar >= cd.fields.length) + { + fieldsSoFar += cd.fields.length; + cd = cd.baseClass; + } + VarDeclaration v2 = cd.fields[j - fieldsSoFar]; + if (v == v2) + { + return cast(int)(value.elements.length - fieldsSoFar - cd.fields.length + (j - fieldsSoFar)); + } } + return -1; + } - Expression e = new StringExp(loc, s.toDString()); - e = e.expressionSemantic(sc); - e.type = Type.tstring; - return e; + override void accept(Visitor v) + { + v.visit(this); + } +} + +/*********************************************************** + * This type is only used by the interpreter. + */ +extern (C++) final class CTFEExp : Expression +{ + extern (D) this(EXP tok) + { + super(Loc.initial, tok); + type = Type.tvoid; + } + + override const(char)* toChars() const + { + switch (op) + { + case EXP.cantExpression: + return ""; + case EXP.voidExpression: + return "cast(void)0"; + case EXP.showCtfeContext: + return ""; + case EXP.break_: + return ""; + case EXP.continue_: + return ""; + case EXP.goto_: + return ""; + default: + assert(0); + } + } + + extern (D) __gshared CTFEExp cantexp; + extern (D) __gshared CTFEExp voidexp; + extern (D) __gshared CTFEExp breakexp; + extern (D) __gshared CTFEExp continueexp; + extern (D) __gshared CTFEExp gotoexp; + /* Used when additional information is needed regarding + * a ctfe error. + */ + extern (D) __gshared CTFEExp showcontext; + + extern (D) static bool isCantExp(const Expression e) @safe + { + return e && e.op == EXP.cantExpression; + } + + extern (D) static bool isGotoExp(const Expression e) @safe + { + return e && e.op == EXP.goto_; + } +} + +/*********************************************************** + * Fake class which holds the thrown exception. + * Used for implementing exception handling. + */ +extern (C++) final class ThrownExceptionExp : Expression +{ + ClassReferenceExp thrown; // the thing being tossed + + extern (D) this(const ref Loc loc, ClassReferenceExp victim) @safe + { + super(loc, EXP.thrownException); + this.thrown = victim; + this.type = victim.type; + } + + override const(char)* toChars() const + { + return "CTFE ThrownException"; } override void accept(Visitor v) @@ -6365,154 +5401,6 @@ extern (C++) final class GenericExp : Expression } } -/*************************************** - * Parameters: - * sc: scope - * flag: 1: do not issue error message for invalid modification - 2: the exp is a DotVarExp and a subfield of the leftmost - variable is modified - * Returns: - * Whether the type is modifiable - */ -extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none) -{ - switch(exp.op) - { - case EXP.variable: - auto varExp = cast(VarExp)exp; - - //printf("VarExp::checkModifiable %s", varExp.toChars()); - assert(varExp.type); - return varExp.var.checkModify(varExp.loc, sc, null, flag); - - case EXP.dotVariable: - auto dotVarExp = cast(DotVarExp)exp; - - //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars()); - if (dotVarExp.e1.op == EXP.this_) - return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag); - - /* https://issues.dlang.org/show_bug.cgi?id=12764 - * If inside a constructor and an expression of type `this.field.var` - * is encountered, where `field` is a struct declaration with - * default construction disabled, we must make sure that - * assigning to `var` does not imply that `field` was initialized - */ - if (sc.func && sc.func.isCtorDeclaration()) - { - // if inside a constructor scope and e1 of this DotVarExp - // is another DotVarExp, then check if the leftmost expression is a `this` identifier - if (auto dve = dotVarExp.e1.isDotVarExp()) - { - // Iterate the chain of DotVarExp to find `this` - // Keep track whether access to fields was limited to union members - // s.t. one can initialize an entire struct inside nested unions - // (but not its members) - bool onlyUnion = true; - while (true) - { - auto v = dve.var.isVarDeclaration(); - assert(v); - - // Accessing union member? - auto t = v.type.isTypeStruct(); - if (!t || !t.sym.isUnionDeclaration()) - onlyUnion = false; - - // Another DotVarExp left? - if (!dve.e1 || dve.e1.op != EXP.dotVariable) - break; - - dve = cast(DotVarExp) dve.e1; - } - - if (dve.e1.op == EXP.this_) - { - scope v = dve.var.isVarDeclaration(); - /* if v is a struct member field with no initializer, no default construction - * and v wasn't intialized before - */ - if (v && v.isField() && !v._init && !v.ctorinit) - { - if (auto ts = v.type.isTypeStruct()) - { - if (ts.sym.noDefaultCtor) - { - /* checkModify will consider that this is an initialization - * of v while it is actually an assignment of a field of v - */ - scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag); - if (modifyLevel == Modifiable.initialization) - { - // https://issues.dlang.org/show_bug.cgi?id=22118 - // v is a union type field that was assigned - // a variable, therefore it counts as initialization - if (v.ctorinit) - return Modifiable.initialization; - - return Modifiable.yes; - } - return modifyLevel; - } - } - } - } - } - } - - //printf("\te1 = %s\n", e1.toChars()); - return dotVarExp.e1.checkModifiable(sc, flag); - - case EXP.star: - auto ptrExp = cast(PtrExp)exp; - if (auto se = ptrExp.e1.isSymOffExp()) - { - return se.var.checkModify(ptrExp.loc, sc, null, flag); - } - else if (auto ae = ptrExp.e1.isAddrExp()) - { - return ae.e1.checkModifiable(sc, flag); - } - return Modifiable.yes; - - case EXP.slice: - auto sliceExp = cast(SliceExp)exp; - - //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars()); - auto e1 = sliceExp.e1; - if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice) - { - return e1.checkModifiable(sc, flag); - } - return Modifiable.yes; - - case EXP.comma: - return (cast(CommaExp)exp).e2.checkModifiable(sc, flag); - - case EXP.index: - auto indexExp = cast(IndexExp)exp; - auto e1 = indexExp.e1; - if (e1.type.ty == Tsarray || - e1.type.ty == Taarray || - (e1.op == EXP.index && e1.type.ty != Tarray) || - e1.op == EXP.slice) - { - return e1.checkModifiable(sc, flag); - } - return Modifiable.yes; - - case EXP.question: - auto condExp = cast(CondExp)exp; - if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no - && condExp.e2.checkModifiable(sc, flag) != Modifiable.no) - return Modifiable.yes; - return Modifiable.no; - - default: - return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable - } -} - /** * Verify if the given identifier is _d_array{,set}ctor. * diff --git a/dmd/expression.h b/dmd/expression.h index ffabf0d08ba..93ee693ff66 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -61,7 +61,10 @@ Expression *defaultInit(Type *mt, const Loc &loc, const bool isCfile = false); Expression *ctfeInterpret(Expression *e); 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, const char* action); +Expression *modifiableLvalue(Expression* exp, Scope *sc); typedef unsigned char OwnedBy; enum @@ -115,9 +118,6 @@ class Expression : public ASTNode virtual complex_t toComplex(); virtual StringExp *toStringExp(); virtual bool isLvalue(); - virtual Expression *toLvalue(Scope *sc, Expression *e); - virtual Expression *modifiableLvalue(Scope *sc, Expression *e); - virtual Expression *resolveLoc(const Loc &loc, Scope *sc); virtual bool checkType(); virtual bool checkValue(); Expression *addressOf(); @@ -260,7 +260,6 @@ class IntegerExp final : public Expression real_t toImaginary() override; complex_t toComplex() override; Optional toBool() override; - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } dinteger_t getInteger() { return value; } template @@ -270,7 +269,6 @@ class IntegerExp final : public Expression class ErrorExp final : public Expression { public: - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } static ErrorExp *errorexp; // handy shared value @@ -318,7 +316,6 @@ class IdentifierExp : public Expression static IdentifierExp *create(const Loc &loc, Identifier *ident); bool isLvalue() override final; - Expression *toLvalue(Scope *sc, Expression *e) override final; void accept(Visitor *v) override { v->visit(this); } }; @@ -336,7 +333,6 @@ class DsymbolExp final : public Expression DsymbolExp *syntaxCopy() override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -347,8 +343,7 @@ class ThisExp : public Expression ThisExp *syntaxCopy() override; Optional toBool() override; - bool isLvalue() override final; - Expression *toLvalue(Scope *sc, Expression *e) override final; + bool isLvalue() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -386,8 +381,6 @@ class StringExp final : public Expression StringExp *toStringExp() override; Optional toBool() override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } #if IN_LLVM // The D version returns a slice. @@ -476,7 +469,7 @@ class StructLiteralExp final : public Expression // to the memory used to build the literal for resolving such references. llvm::Value *inProgressMemory; #else - Symbol *sym; // back end symbol to initialize with literal + Symbol *sym; // back end symbol to initialize with literal (used as a Symbol*) #endif // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. @@ -505,7 +498,6 @@ class StructLiteralExp final : public Expression static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL); bool equals(const RootObject * const o) const override; StructLiteralExp *syntaxCopy() override; - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -537,7 +529,6 @@ class TemplateExp final : public Expression FuncDeclaration *fd; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; bool checkType() override; bool checkValue() override; void accept(Visitor *v) override { v->visit(this); } @@ -611,8 +602,6 @@ class VarExp final : public SymbolExp static VarExp *create(const Loc &loc, Declaration *var, bool hasOverloads = true); bool equals(const RootObject * const o) const override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -625,7 +614,6 @@ class OverExp final : public Expression OverloadSet *vars; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -714,7 +702,6 @@ class UnaExp : public Expression Expression *e1; UnaExp *syntaxCopy() override; - Expression *resolveLoc(const Loc &loc, Scope *sc) override final; void accept(Visitor *v) override { v->visit(this); } }; @@ -737,8 +724,6 @@ class BinAssignExp : public BinExp { public: bool isLvalue() override final; - Expression *toLvalue(Scope *sc, Expression *ex) override final; - Expression *modifiableLvalue(Scope *sc, Expression *e) override final; void accept(Visitor *v) override { v->visit(this); } }; @@ -803,8 +788,6 @@ class DotVarExp final : public UnaExp d_bool hasOverloads; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -857,7 +840,6 @@ class CallExp final : public UnaExp CallExp *syntaxCopy() override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -872,8 +854,6 @@ class PtrExp final : public UnaExp { public: bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -918,7 +898,6 @@ class CastExp final : public UnaExp CastExp *syntaxCopy() override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -939,7 +918,6 @@ class VectorArrayExp final : public UnaExp { public: bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -962,8 +940,6 @@ class SliceExp final : public UnaExp public: SliceExp *syntaxCopy() override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; Optional toBool() override; void accept(Visitor *v) override { v->visit(this); } @@ -989,8 +965,6 @@ class DelegatePtrExp final : public UnaExp { public: bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -998,8 +972,6 @@ class DelegateFuncptrExp final : public UnaExp { public: bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -1014,7 +986,6 @@ class ArrayExp final : public UnaExp ArrayExp *syntaxCopy() override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -1033,8 +1004,6 @@ class CommaExp final : public BinExp d_bool isGenerated; d_bool allowCommaExp; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; Optional toBool() override; void accept(Visitor *v) override { v->visit(this); } @@ -1068,8 +1037,6 @@ class IndexExp final : public BinExp IndexExp *syntaxCopy() override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -1103,7 +1070,6 @@ class AssignExp : public BinExp MemorySet memset; bool isLvalue() override final; - Expression *toLvalue(Scope *sc, Expression *ex) override final; void accept(Visitor *v) override { v->visit(this); } }; @@ -1350,8 +1316,6 @@ class CondExp final : public BinExp CondExp *syntaxCopy() override; bool isLvalue() override; - Expression *toLvalue(Scope *sc, Expression *e) override; - Expression *modifiableLvalue(Scope *sc, Expression *e) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -1378,35 +1342,30 @@ class DefaultInitExp : public Expression class FileInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; class LineInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; class ModuleInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; class FuncInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; class PrettyFuncInitExp final : public DefaultInitExp { public: - Expression *resolveLoc(const Loc &loc, Scope *sc) override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 2c6d588b802..5d42177131a 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -3,7 +3,7 @@ * * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d) @@ -87,6 +87,46 @@ import dmd.visitor; enum LOGSEMANTIC = false; +/*********************************** + * Determine if a `this` is needed to access `d`. + * Params: + * sc = context + * d = declaration to check + * Returns: + * true means a `this` is needed + */ +private bool isNeedThisScope(Scope* sc, Declaration d) +{ + if (sc.intypeof == 1) + return false; + + AggregateDeclaration ad = d.isThis(); + if (!ad) + return false; + //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars()); + + for (Dsymbol s = sc.parent; s; s = s.toParentLocal()) + { + //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2()); + if (AggregateDeclaration ad2 = s.isAggregateDeclaration()) + { + if (ad2 == ad) + return false; + else if (ad2.isNested()) + continue; + else + return true; + } + if (FuncDeclaration f = s.isFuncDeclaration()) + { + if (f.isMemberLocal()) + break; + } + } + return true; +} + + /******************************************************** * Perform semantic analysis and CTFE on expressions to produce * a string. @@ -196,6 +236,51 @@ FuncDeclaration hasThis(Scope* sc) } +extern (D) bool findTempDecl(DotTemplateInstanceExp exp, Scope* sc) +{ + auto ti = exp.ti; + auto e1 = exp.e1; + static if (LOGSEMANTIC) + { + printf("DotTemplateInstanceExp::findTempDecl('%s')\n", exp.toChars()); + } + if (ti.tempdecl) + return true; + + Expression e = new DotIdExp(exp.loc, e1, ti.name); + e = e.expressionSemantic(sc); + if (e.op == EXP.dot) + e = (cast(DotExp)e).e2; + + Dsymbol s = null; + switch (e.op) + { + case EXP.overloadSet: + s = (cast(OverExp)e).vars; + break; + + case EXP.dotTemplateDeclaration: + s = (cast(DotTemplateExp)e).td; + break; + + case EXP.scope_: + s = (cast(ScopeExp)e).sds; + break; + + case EXP.dotVariable: + s = (cast(DotVarExp)e).var; + break; + + case EXP.variable: + s = (cast(VarExp)e).var; + break; + + default: + return false; + } + return ti.updateTempDecl(sc, s); +} + /*********************************************************** * Resolve `exp` as a compile-time known string. * Params: @@ -790,7 +875,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) Loc loc = ue.loc; // TODO: merge with Scope.search.searchScopes() - Dsymbol searchScopes(int flags) + Dsymbol searchScopes(SearchOptFlags flags) { Dsymbol s = null; for (Scope* scx = sc; scx; scx = scx.enclosing) @@ -798,7 +883,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) if (!scx.scopesym) continue; if (scx.scopesym.isModule()) - flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed + flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed s = scx.scopesym.search(loc, ident, flags); if (s) { @@ -825,18 +910,18 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) return s; } - int flags = 0; + SearchOptFlags flags = SearchOpt.all; Dsymbol s; if (sc.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; // First look in local scopes - s = searchScopes(flags | SearchLocalsOnly); + s = searchScopes(flags | SearchOpt.localsOnly); if (!s) { // Second look in imported modules - s = searchScopes(flags | SearchImportsOnly); + s = searchScopes(flags | SearchOpt.importsOnly); } if (!s) @@ -1731,6 +1816,403 @@ private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) return false; } +/********************************************* + * Calling function f. + * Check the purity, i.e. if we're in a pure function + * we can only call other pure functions. + * Returns true if error occurs. + */ +private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc) +{ + if (!sc.func) + return false; + if (sc.func == f) + return false; + if (sc.intypeof == 1) + return false; + if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) + return false; + + // If the call has a pure parent, then the called func must be pure. + if (!f.isPure() && checkImpure(sc, loc, null, f)) + { + error(loc, "`pure` %s `%s` cannot call impure %s `%s`", + sc.func.kind(), sc.func.toPrettyChars(), f.kind(), + f.toPrettyChars()); + + if (!f.isDtorDeclaration()) + errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_); + + f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure"); + return true; + } + return false; +} + +/** + * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one + * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but + * the generated dtor is not). + * In that case the method will identify and print all members causing the attribute + * missmatch. + * + * Params: + * f = potential `DtorDeclaration` + * sc = scope + * loc = location + * check = current check (e.g. whether it's pure) + * checkName = the kind of check (e.g. `"pure"`) + */ +void checkOverriddenDtor(FuncDeclaration f, Scope* sc, const ref Loc loc, + scope bool function(DtorDeclaration) check, const string checkName) +{ + auto dd = f.isDtorDeclaration(); + if (!dd || !dd.isGenerated()) + return; + + // DtorDeclaration without parents should fail at an earlier stage + auto ad = cast(AggregateDeclaration) f.toParent2(); + assert(ad); + + if (ad.userDtors.length) + { + if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well) + return; + + // Sanity check + assert(!check(ad.fieldDtor)); + } + + dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:", + dd.isGenerated() ? "generated " : "".ptr, + ad.toChars, + cast(int) checkName.length, checkName.ptr); + + // Search for the offending fields + foreach (field; ad.fields) + { + // Only structs may define automatically called destructors + auto ts = field.type.isTypeStruct(); + if (!ts) + { + // But they might be part of a static array + auto ta = field.type.isTypeSArray(); + if (!ta) + continue; + + ts = ta.baseElemOf().isTypeStruct(); + if (!ts) + continue; + } + + auto fieldSym = ts.toDsymbol(sc); + assert(fieldSym); // Resolving ts must succeed because missing defs. should error before + + auto fieldSd = fieldSym.isStructDeclaration(); + assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR + + if (fieldSd.dtor && !check(fieldSd.dtor)) + { + field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars()); + + if (fieldSd.dtor.isGenerated()) + fieldSd.dtor.checkOverriddenDtor(sc, loc, check, checkName); + else + fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here", + cast(int) checkName.length, checkName.ptr, fieldSd.toChars()); + } + } +} + +/******************************************* + * Accessing variable v. + * Check for purity and safety violations. + * Returns true if error occurs. + */ +private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc) +{ + //printf("v = %s %s\n", v.type.toChars(), v.toChars()); + /* Look for purity and safety violations when accessing variable v + * from current function. + */ + if (!sc.func) + return false; + if (sc.intypeof == 1) + return false; // allow violations inside typeof(expression) + if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) + return false; // allow violations inside compile-time evaluated expressions and debug conditionals + if (v.ident == Id.ctfe) + return false; // magic variable never violates pure and safe + if (v.isImmutable()) + return false; // always safe and pure to access immutables... + if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf())) + return false; // or const global/parameter values which have no mutable indirections + if (v.storage_class & STC.manifest) + return false; // ...or manifest constants + + // accessing empty structs is pure + // https://issues.dlang.org/show_bug.cgi?id=18694 + // https://issues.dlang.org/show_bug.cgi?id=21464 + // https://issues.dlang.org/show_bug.cgi?id=23589 + if (v.type.ty == Tstruct) + { + StructDeclaration sd = (cast(TypeStruct)v.type).sym; + if (sd.members) // not opaque + { + if (sd.semanticRun >= PASS.semanticdone) + sd.determineSize(v.loc); + if (sd.hasNoFields) + return false; + } + } + + bool err = false; + if (v.isDataseg()) + { + // https://issues.dlang.org/show_bug.cgi?id=7533 + // Accessing implicit generated __gate is pure. + if (v.ident == Id.gate) + return false; + + if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v)) + { + error(loc, "`pure` %s `%s` cannot access mutable static data `%s`", + sc.func.kind(), sc.func.toPrettyChars(), v.toChars()); + err = true; + } + } + else + { + /* Given: + * void f() { + * int fx; + * pure void g() { + * int gx; + * /+pure+/ void h() { + * int hx; + * /+pure+/ void i() { } + * } + * } + * } + * i() can modify hx and gx but not fx + */ + + Dsymbol vparent = v.toParent2(); + for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent)) + { + if (s == vparent) + break; + + if (AggregateDeclaration ad = s.isAggregateDeclaration()) + { + if (ad.isNested()) + continue; + break; + } + FuncDeclaration ff = s.isFuncDeclaration(); + if (!ff) + break; + if (ff.isNested() || ff.isThis()) + { + if (ff.type.isImmutable() || + ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod)) + { + OutBuffer ffbuf; + OutBuffer vbuf; + MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod); + MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod); + error(loc, "%s%s `%s` cannot access %sdata `%s`", + ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars()); + err = true; + break; + } + continue; + } + break; + } + } + + /* Do not allow safe functions to access __gshared data + */ + if (v.storage_class & STC.gshared) + { + if (sc.setUnsafe(false, loc, + "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v)) + { + err = true; + } + } + + return err; +} + +/* +Check if sc.func is impure or can be made impure. +Returns true on error, i.e. if sc.func is pure and cannot be made impure. +*/ +private bool checkImpure(Scope* sc, Loc loc, const(char)* fmt, RootObject arg0) +{ + return sc.func && (isRootTraitsCompilesScope(sc) + ? sc.func.isPureBypassingInference() >= PURE.weak + : sc.func.setImpure(loc, fmt, arg0)); +} + +/********************************************* + * Calling function f. + * Check the safety, i.e. if we're in a @safe function + * we can only call @safe or @trusted functions. + * Returns true if error occurs. + */ +private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc) +{ + if (sc.func == f) + return false; + if (sc.intypeof == 1) + return false; + if (sc.flags & SCOPE.debug_) + return false; + if ((sc.flags & SCOPE.ctfe) && sc.func) + return false; + + if (!sc.func) + { + if (sc.varDecl && !f.safetyInprocess && !f.isSafe() && !f.isTrusted()) + { + if (sc.varDecl.storage_class & STC.safe) + { + error(loc, "`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`", + sc.varDecl.toChars(), f.toChars()); + return true; + } + else + { + sc.varDecl.storage_class |= STC.system; + sc.varDecl.systemInferred = true; + } + } + return false; + } + + if (!f.isSafe() && !f.isTrusted()) + { + if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f)) + { + if (!loc.isValid()) // e.g. implicitly generated dtor + loc = sc.func.loc; + + const prettyChars = f.toPrettyChars(); + error(loc, "`@safe` %s `%s` cannot call `@system` %s `%s`", + sc.func.kind(), sc.func.toPrettyChars(), f.kind(), + prettyChars); + if (!f.isDtorDeclaration) + errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe); + .errorSupplemental(f.loc, "`%s` is declared here", prettyChars); + + f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system"); + + return true; + } + } + else if (f.isSafe() && f.safetyViolation) + { + // for dip1000 by default transition, print deprecations for calling functions that will become `@system` + if (sc.func.isSafeBypassingInference()) + { + .deprecation(loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars()); + errorSupplementalInferredAttr(f, 10, true, STC.safe); + } + else if (!sc.func.safetyViolation) + { + import dmd.func : AttributeViolation; + sc.func.safetyViolation = new AttributeViolation(loc, null, f, null, null); + } + } + return false; +} + +/********************************************* + * Calling function f. + * Check the @nogc-ness, i.e. if we're in a @nogc function + * we can only call other @nogc functions. + * Returns true if error occurs. + */ +private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc) +{ + if (!sc.func) + return false; + if (sc.func == f) + return false; + if (sc.intypeof == 1) + return false; + if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) + return false; + /* The original expressions (`new S(...)` or `new S[...]``) will be + * 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 || f.ident == Id._d_newarraymTX) + return false; + + if (!f.isNogc()) + { + if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f)) + { + if (loc.linnum == 0) // e.g. implicitly generated dtor + loc = sc.func.loc; + + // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)), + // so don't print anything to avoid double error messages. + if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT + || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX + || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT)) + { + error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`", + sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); + + if (!f.isDtorDeclaration) + f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc); + } + + f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().isnogc, "non-@nogc"); + + return true; + } + } + return false; +} + +/******************************************** + * Check that the postblit is callable if t is an array of structs. + * Returns true if error happens. + */ +private bool checkPostblit(Type t, ref Loc loc, Scope* sc) +{ + if (auto ts = t.baseElemOf().isTypeStruct()) + { + if (global.params.useTypeInfo && Type.dtypeinfo) + { + // https://issues.dlang.org/show_bug.cgi?id=11395 + // Require TypeInfo generation for array concatenation + semanticTypeInfo(sc, t); + } + + StructDeclaration sd = ts.sym; + if (sd.postblit) + { + if (sd.postblit.checkDisabled(loc, sc)) + return true; + + //checkDeprecated(sc, sd.postblit); // necessary? + sd.postblit.checkPurity(loc, sc); + sd.postblit.checkSafety(loc, sc); + sd.postblit.checkNogc(loc, sc); + //checkAccess(sd, loc, sc, sd.postblit); // necessary? + return false; + } + } + return false; +} + /*************************************** * Pull out any properties. */ @@ -1942,7 +2424,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = { if (auto v = ve.var.isVarDeclaration()) { - if (ve.checkPurity(sc, v)) + if (v.checkPurity(ve.loc, sc)) return ErrorExp.get(); } } @@ -2647,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 = arg.toLvalue(sc, "create `in` parameter from"); // Look for mutable misaligned pointer, etc., in @safe mode err |= checkUnsafeAccess(sc, arg, false, true); @@ -2665,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 = arg.toLvalue(sc, "create `ref` parameter from"); // Look for mutable misaligned pointer, etc., in @safe mode err |= checkUnsafeAccess(sc, arg, false, true); @@ -2684,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 = arg.toLvalue(sc, "create `out` parameter from"); } else if (p.isLazy()) { @@ -2727,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. @@ -3266,7 +3748,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Dsymbol scopesym; - Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); + Dsymbol s = sc.search(exp.loc, exp.ident, scopesym); if (s) { if (s.errors) @@ -3910,7 +4392,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0); if (!e) { - error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars()); + error(cle.loc, "cannot convert initializer `%s` to expression", toChars(init)); return setError(); } result = e; @@ -4639,23 +5121,32 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tb = tb.isTypeDArray().next.toBasetype(); } - if (nargs == 1) + if (!global.params.useGC && sc.needsCodegen()) { - if (global.params.betterC || !sc.needsCodegen()) + version(IN_GCC) + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars()); + else + error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars()); + return setError(); + } + + if (!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; @@ -4690,19 +5181,58 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor lowering = new CallExp(exp.loc, lowering, arguments); exp.lowering = lowering.expressionSemantic(sc); } - } - else if (tb.isscalar()) - { - if (!nargs) - { - } - else if (nargs == 1) + else { - if (exp.names && (*exp.names)[0]) - { - error(exp.loc, "no named argument `%s` allowed for scalar", (*exp.names)[0].toChars()); - return setError(); - } + 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); + } + } + else if (tb.isscalar()) + { + if (!nargs) + { + } + else if (nargs == 1) + { + if (exp.names && (*exp.names)[0]) + { + error(exp.loc, "no named argument `%s` allowed for scalar", (*exp.names)[0].toChars()); + return setError(); + } Expression e = (*exp.arguments)[0]; e = e.implicitCastTo(sc, tb); (*exp.arguments)[0] = e; @@ -4858,6 +5388,52 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; } + private void genIdent(FuncExp exp, Scope* sc) + { + if (exp.fd.ident == Id.empty) + { + const(char)[] s; + if (exp.fd.fes) + s = "__foreachbody"; + else if (exp.fd.tok == TOK.reserved) + s = "__lambda"; + else if (exp.fd.tok == TOK.delegate_) + s = "__dgliteral"; + else + s = "__funcliteral"; + + DsymbolTable symtab; + if (FuncDeclaration func = sc.parent.isFuncDeclaration()) + { + if (func.localsymtab is null) + { + // Inside template constraint, symtab is not set yet. + // Initialize it lazily. + func.localsymtab = new DsymbolTable(); + } + symtab = func.localsymtab; + } + else + { + ScopeDsymbol sds = sc.parent.isScopeDsymbol(); + if (!sds.symtab) + { + // Inside template constraint, symtab may not be set yet. + // Initialize it lazily. + assert(sds.isTemplateInstance()); + sds.symtab = new DsymbolTable(); + } + symtab = sds.symtab; + } + assert(symtab); + Identifier id = Identifier.generateId(s, symtab.length() + 1); + exp.fd.ident = id; + if (exp.td) + exp.td.ident = id; + symtab.insert(exp.td ? cast(Dsymbol)exp.td : cast(Dsymbol)exp.fd); + } + } + override void visit(FuncExp exp) { static if (LOGSEMANTIC) @@ -4888,7 +5464,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor //if (fd.treq) // fd.treq = fd.treq.dsymbolSemantic(loc, sc); - exp.genIdent(sc); + genIdent(exp, sc); // Set target of return type inference if (exp.fd.treq && !exp.fd.type.nextOf()) @@ -5001,7 +5577,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return checkarg; } - exp.genIdent(sc); + genIdent(exp, sc); assert(exp.td.parameters && exp.td.parameters.length); exp.td.dsymbolSemantic(sc); @@ -5263,7 +5839,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ve.type = t.typeSemantic(exp.loc, sc); } VarDeclaration v = ve.var.isVarDeclaration(); - if (v && ve.checkPurity(sc, v)) + if (v && v.checkPurity(ve.loc, sc)) return setError(); } @@ -5891,9 +6467,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Purity and safety check should run after testing arguments matching if (exp.f) { - exp.checkPurity(sc, exp.f); - exp.checkSafety(sc, exp.f); - exp.checkNogc(sc, exp.f); + exp.f.checkPurity(exp.loc, sc); + exp.f.checkSafety(exp.loc, sc); + exp.f.checkNogc(exp.loc, sc); if (exp.f.checkNestedReference(sc, exp.loc)) return setError(); } @@ -6183,7 +6759,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -6251,11 +6828,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (sc.func.fes) { - deprecation(e.loc, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + deprecation(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + deprecationSupplemental(s2.loc, "declared here"); + } else { error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); + errorSupplemental(s2.loc, "declared here"); return setError(); } } @@ -6425,7 +7005,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ if (!tup && !sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -6732,7 +7313,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor s.dsymbolSemantic(sc); if (!sc.insert(s)) { - auto conflict = sc.search(Loc.initial, s.ident, null); + Dsymbol pscopesym; + auto conflict = sc.search(Loc.initial, s.ident, pscopesym); error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); errorSupplemental(conflict.loc, "`%s` `%s` is defined here", conflict.kind(), conflict.toChars()); @@ -6801,7 +7383,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.e1 = exp.e1.expressionSemantic(sc); - exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); + exp.e1 = exp.e1.modifiableLvalue(sc); exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); exp.type = exp.e1.type; @@ -6879,7 +7461,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor uint errors = global.errors; const len = buf.length; const str = buf.extractChars()[0 .. len]; - const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + const bool doUnittests = global.params.parsingUnittestsRequired(); auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut); scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); p.transitionIn = global.params.v.vin; @@ -7028,6 +7610,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("AssertExp::semantic('%s')\n", exp.toChars()); } + if (auto e = exp.e1.isStringExp()) + { + // deprecated in 2.107 + deprecation(e.loc, "assert condition cannot be a string literal"); + deprecationSupplemental(e.loc, "If intentional, use `%s !is null` instead to preserve behaviour", + e.toChars()); + } const generateMsg = !exp.msg && sc.needsCodegen() && // let ctfe interpreter handle the error message @@ -7773,7 +8362,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, null); + exp.toLvalue(sc, "take address of"); return setError(); } } @@ -7863,7 +8452,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - exp.e1 = exp.e1.toLvalue(sc, null); + exp.e1 = exp.e1.toLvalue(sc, "take address of"); if (exp.e1.op == EXP.error) { result = exp.e1; @@ -7940,7 +8529,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!checkAddressVar(sc, exp.e1, v)) return setError(); - ve.checkPurity(sc, v); + v.checkPurity(ve.loc, sc); } FuncDeclaration f = ve.var.isFuncDeclaration(); if (f) @@ -8022,7 +8611,7 @@ version (IN_LLVM) */ if (VarDeclaration v = expToVariable(exp.e1)) { - exp.e1.checkPurity(sc, v); + v.checkPurity(exp.e1.loc, sc); } } else if (wasCond) @@ -8291,7 +8880,7 @@ version (IN_LLVM) return; } exp.e1 = resolveProperties(sc, exp.e1); - exp.e1 = exp.e1.modifiableLvalue(sc, null); + exp.e1 = exp.e1.modifiableLvalue(sc); if (exp.e1.op == EXP.error) { result = exp.e1; @@ -8322,9 +8911,9 @@ version (IN_LLVM) if (cd.dtor) { err |= !cd.dtor.functionSemantic(); - err |= exp.checkPurity(sc, cd.dtor); - err |= exp.checkSafety(sc, cd.dtor); - err |= exp.checkNogc(sc, cd.dtor); + err |= cd.dtor.checkPurity(exp.loc, sc); + err |= cd.dtor.checkSafety(exp.loc, sc); + err |= cd.dtor.checkNogc(exp.loc, sc); } if (err) return setError(); @@ -9499,7 +10088,7 @@ version (IN_LLVM) return; } - exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); + exp.e1 = exp.e1.modifiableLvalue(sc); exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); e = exp; @@ -10261,7 +10850,7 @@ version (IN_LLVM) Expression ex; ex = new IndexExp(exp.loc, ea, ek); ex = ex.expressionSemantic(sc); - ex = ex.modifiableLvalue(sc, ex); // allocate new slot + ex = ex.modifiableLvalue(sc); // allocate new slot ex = ex.optimize(WANTvalue); ey = new ConstructExp(exp.loc, ex, ey); @@ -10352,7 +10941,7 @@ version (IN_LLVM) { if (exp.op != EXP.blit && (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue())) { - if (e1x.checkPostblit(sc, t1)) + if (t1.checkPostblit(e1x.loc, sc)) return setError(); } @@ -10454,7 +11043,7 @@ version (IN_LLVM) { // e1 is not an lvalue, but we let code generator handle it - auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1); + auto ale1x = ale.e1.modifiableLvalueImpl(sc, exp.e1); if (ale1x.op == EXP.error) return setResult(ale1x); ale.e1 = ale1x; @@ -10540,7 +11129,7 @@ version (IN_LLVM) se = cast(SliceExp)se.e1; if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray) { - se.e1 = se.e1.modifiableLvalue(sc, exp.e1); + se.e1 = se.e1.modifiableLvalueImpl(sc, exp.e1); if (se.e1.op == EXP.error) return setResult(se.e1); } @@ -10564,7 +11153,7 @@ version (IN_LLVM) // Try to do a decent error message with the expression // before it gets constant folded if (exp.op == EXP.assign) - e1x = e1x.modifiableLvalue(sc, e1old); + e1x = e1x.modifiableLvalueImpl(sc, e1old); e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true); @@ -10595,7 +11184,7 @@ version (IN_LLVM) // '= null' is the only allowable block assignment (Bug 7493) exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is e2x = e2x.implicitCastTo(sc, t1.nextOf()); - if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf())) + if (exp.op != EXP.blit && e2x.isLvalue() && t1.nextOf.checkPostblit(exp.e1.loc, sc)) return setError(); } else if (exp.e1.op == EXP.slice && @@ -10633,7 +11222,7 @@ version (IN_LLVM) e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue())) { - if (exp.e1.checkPostblit(sc, t1.nextOf())) + if (t1.nextOf().checkPostblit(exp.e1.loc, sc)) return setError(); } @@ -11012,7 +11601,7 @@ version (IN_LLVM) } else { - exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); + exp.e1 = exp.e1.modifiableLvalue(sc); } if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating())) @@ -11071,7 +11660,7 @@ version (IN_LLVM) } } - exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); + exp.e1 = exp.e1.modifiableLvalue(sc); if (exp.e1.op == EXP.error) { result = exp.e1; @@ -11103,7 +11692,7 @@ version (IN_LLVM) { // EXP.concatenateAssign assert(exp.op == EXP.concatenateAssign); - if (exp.e1.checkPostblit(sc, tb1next)) + if (tb1next.checkPostblit(exp.e1.loc, sc)) return setError(); exp.e2 = exp.e2.castTo(sc, exp.e1.type); @@ -11121,7 +11710,7 @@ version (IN_LLVM) if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next)) goto Laliasthis; // Append element - if (exp.e2.checkPostblit(sc, tb2)) + if (tb2.checkPostblit(exp.e2.loc, sc)) return setError(); if (checkNewEscape(sc, exp.e2, false)) @@ -11750,7 +12339,7 @@ version (IN_LLVM) } else { - if (exp.e2.checkPostblit(sc, tb2)) + if (tb2.checkPostblit(exp.e2.loc, sc)) return setError(); // Postblit call will be done in runtime helper function } @@ -11785,7 +12374,7 @@ version (IN_LLVM) } else { - if (exp.e1.checkPostblit(sc, tb1)) + if (tb1.checkPostblit(exp.e1.loc, sc)) return setError(); } @@ -11840,7 +12429,7 @@ version (IN_LLVM) } if (Type tbn = tb.nextOf()) { - if (exp.checkPostblit(sc, tbn)) + if (tbn.checkPostblit(exp.loc, sc)) return setError(); } Type t1 = exp.e1.type.toBasetype(); @@ -13586,6 +14175,14 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) return exp; } +private bool checkDisabled(Dsymbol s, ref Loc loc, Scope* sc) +{ + if (auto d = s.isDeclaration()) + return d.checkDisabled(loc, sc); + + return false; +} + /****************************** * Resolve properties, i.e. `e1.ident`, without seeing UFCS. * Params: @@ -13649,15 +14246,15 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) if (auto ie = eright.isScopeExp()) // also used for template alias's { - auto flags = SearchLocalsOnly; + SearchOptFlags flags = SearchOpt.localsOnly; /* Disable access to another module's private imports. * The check for 'is sds our current module' is because * the current module should have access to its own imports. */ if (ie.sds.isModule() && ie.sds != sc._module) - flags |= IgnorePrivateImports; + flags |= SearchOpt.ignorePrivateImports; if (sc.flags & SCOPE.ignoresymbolvisibility) - flags |= IgnoreSymbolVisibility; + flags |= SearchOpt.ignoreVisibility; Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags); /* Check for visibility before resolving aliases because public * aliases to private symbols are public. @@ -13679,8 +14276,8 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) // if 's' is a tuple variable, the tuple is returned. s = s.toAlias(); - exp.checkDeprecated(sc, s); - exp.checkDisabled(sc, s); + s.checkDeprecated(exp.loc, sc); + s.checkDisabled(exp.loc, sc); if (auto em = s.isEnumMember()) { @@ -14470,6 +15067,107 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) return check(e, returnRef); } +/**************************************** + * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc. + */ +Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) +{ + exp.loc = loc; + + Expression visit(Expression exp) + { + if (auto unaExp = exp.isUnaExp()) + { + unaExp.e1 = unaExp.e1.resolveLoc(loc, sc); + return unaExp; + } + return exp; + } + + Expression visitCat(CatExp exp) + { + exp.e1 = exp.e1.resolveLoc(loc, sc); + exp.e2 = exp.e2.resolveLoc(loc, sc); + return exp; + } + + Expression visitFileInit(FileInitExp exp) + { + //printf("FileInitExp::resolve() %s\n", exp.toChars()); + const(char)* s; + if (exp.op == EXP.fileFullPath) + s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars()); + else + s = loc.isValid() ? loc.filename : sc._module.ident.toChars(); + + Expression e = new StringExp(loc, s.toDString()); + return e.expressionSemantic(sc); + } + + Expression visitLineInit(LineInitExp _) + { + Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); + return e.expressionSemantic(sc); + } + + Expression visitModuleInit(ModuleInitExp _) + { + const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); + Expression e = new StringExp(loc, s); + return e.expressionSemantic(sc); + } + + Expression visitFuncInit(FuncInitExp _) + { + const(char)* s; + if (sc.callsc && sc.callsc.func) + s = sc.callsc.func.Dsymbol.toPrettyChars(); + else if (sc.func) + s = sc.func.Dsymbol.toPrettyChars(); + else + s = ""; + Expression e = new StringExp(loc, s.toDString()); + return e.expressionSemantic(sc); + } + + Expression visitPrettyFunc(PrettyFuncInitExp _) + { + FuncDeclaration fd = (sc.callsc && sc.callsc.func) + ? sc.callsc.func + : sc.func; + + const(char)* s; + if (fd) + { + const funcStr = fd.Dsymbol.toPrettyChars(); + OutBuffer buf; + functionToBufferWithIdent(fd.type.isTypeFunction(), buf, funcStr, fd.isStatic); + s = buf.extractChars(); + } + else + { + s = ""; + } + + Expression e = new StringExp(loc, s.toDString()); + e = e.expressionSemantic(sc); + e.type = Type.tstring; + return e; + } + + switch(exp.op) + { + default: return visit(exp); + case EXP.concatenate: return visitCat(exp.isCatExp()); + case EXP.file: + case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp()); + case EXP.line: return visitLineInit(exp.isLineInitExp); + case EXP.moduleString: return visitModuleInit(exp.isModuleInitExp()); + case EXP.functionString: return visitFuncInit(exp.isFuncInitExp()); + case EXP.prettyFunction: return visitPrettyFunc(exp.isPrettyFuncInitExp()); + } +} + /************************************************ * Destructors are attached to VarDeclarations. * Hence, if expression returns a temp that needs a destructor, @@ -14571,6 +15269,593 @@ Expression addDtorHook(Expression e, Scope* sc) } } +/******************************* + * Try to convert an expression to be an lvalue. + * + * Give error if we're not an lvalue. + * 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, const(char)* action) +{ + 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, const(char)* action, Expression e) +{ + if (!action) + action = "create lvalue of"; + + assert(e); + Expression visit(Expression _this) + { + // BinaryAssignExp does not have an EXP associated + // so it's treated on the default path. + // Lvalue-ness will be handled in glue :layer. + if (_this.isBinAssignExp()) + return _this; + if (!_this.loc.isValid()) + _this.loc = e.loc; + + if (e.op == EXP.type) + 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, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars()); + + return ErrorExp.get(); + } + + Expression visitInteger(IntegerExp _this) + { + if (!_this.loc.isValid()) + _this.loc = e.loc; + error(e.loc, "cannot %s constant `%s`", action, e.toChars()); + return ErrorExp.get(); + } + + Expression visitThis(ThisExp _this) + { + if (_this.type.toBasetype().ty == Tclass) + { + // Class `this` is an rvalue; struct `this` is an lvalue. + return visit(_this); + } + + return _this; + } + + Expression visitString(StringExp _this) + { + //printf("StringExp::toLvalue(%s) type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL); + return (_this.type && _this.type.toBasetype().ty == Tsarray) ? _this : visit(_this); + } + + Expression visitStructLiteral(StructLiteralExp _this) + { + if (sc.flags & SCOPE.Cfile) + return _this; // C struct literals are lvalues + else + return visit(_this); + } + + Expression visitTemplate(TemplateExp _this) + { + if (!_this.fd) + return visit(_this); + + assert(sc); + return symbolToExp(_this.fd, _this.loc, sc, true); + + } + + Expression visitVar(VarExp _this) + { + auto var = _this.var; + if (var.storage_class & STC.manifest) + { + 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, "cannot %s lazy variable `%s`", action, var.toChars()); + return ErrorExp.get(); + } + if (var.ident == Id.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 %s operator `$`", action); + return ErrorExp.get(); + } + return _this; + } + + Expression visitDotVar(DotVarExp _this) + { + auto e1 = _this.e1; + auto var = _this.var; + //printf("DotVarExp::toLvalue(%s)\n", toChars()); + if (sc && sc.flags & SCOPE.Cfile) + { + /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator + * is an lvalue if the first expression is an lvalue. + */ + if (!e1.isLvalue()) + return visit(_this); + } + if (!_this.isLvalue()) + return visit(_this); + if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor)) + { + if (VarDeclaration vd = var.isVarDeclaration()) + { + auto ad = vd.isMember2(); + if (ad && ad.fields.length == sc.ctorflow.fieldinit.length) + { + foreach (i, f; ad.fields) + { + if (f == vd) + { + if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor)) + { + /* If the address of vd is taken, assume it is thereby initialized + * https://issues.dlang.org/show_bug.cgi?id=15869 + */ + modifyFieldVar(_this.loc, sc, vd, e1); + } + break; + } + } + } + } + } + return _this; + } + + Expression visitCall(CallExp _this) + { + if (_this.isLvalue()) + return _this; + return visit(_this); + } + + Expression visitCast(CastExp _this) + { + if (sc && sc.flags & SCOPE.Cfile) + { + /* C11 6.5.4-5: A cast does not yield an lvalue. + */ + return visit(_this); + } + if (_this.isLvalue()) + return _this; + return visit(_this); + } + + Expression visitVectorArray(VectorArrayExp _this) + { + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); + return _this; + } + + Expression visitSlice(SliceExp _this) + { + //printf("SliceExp::toLvalue(%s) _this.type = %s\n", _this.toChars(), _this.type ? _this.type.toChars() : NULL); + return (_this.type && _this.type.toBasetype().ty == Tsarray) ? _this : visit(_this); + } + + Expression visitArray(ArrayExp _this) + { + if (_this.type && _this.type.toBasetype().ty == Tvoid) + error(_this.loc, "`void`s have no value"); + return _this; + } + + Expression visitComma(CommaExp _this) + { + _this.e2 = _this.e2.toLvalue(sc, action); + return _this; + } + + Expression visitDelegatePointer(DelegatePtrExp _this) + { + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); + return _this; + } + + Expression visitDelegateFuncptr(DelegateFuncptrExp _this) + { + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); + return _this; + } + + Expression visitIndex(IndexExp _this) + { + if (_this.isLvalue()) + return _this; + return visit(_this); + } + + Expression visitAssign(AssignExp _this) + { + if (_this.e1.op == EXP.slice || _this.e1.op == EXP.arrayLength) + { + return visit(_this); + } + + /* In front-end level, AssignExp should make an lvalue of e1. + * Taking the address of e1 will be handled in low level layer, + * so this function does nothing. + */ + return _this; + } + + Expression visitCond(CondExp _this) + { + // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) + CondExp e = cast(CondExp)(_this.copy()); + 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); + + } + + switch(_this.op) + { + default: return visit(_this); + + case EXP.int64: return visitInteger(_this.isIntegerExp()); + case EXP.error: return _this; + case EXP.identifier: return _this; + case EXP.dSymbol: return _this; + case EXP.this_: return visitThis(_this.isThisExp()); + case EXP.super_: return visitThis(_this.isSuperExp()); + case EXP.string_: return visitString(_this.isStringExp()); + case EXP.structLiteral: return visitStructLiteral(_this.isStructLiteralExp()); + case EXP.template_: return visitTemplate(_this.isTemplateExp()); + case EXP.variable: return visitVar(_this.isVarExp()); + case EXP.overloadSet: return _this; + case EXP.dotVariable: return visitDotVar(_this.isDotVarExp()); + case EXP.call: return visitCall(_this.isCallExp()); + case EXP.star: return _this; + case EXP.cast_: return visitCast(_this.isCastExp()); + case EXP.vectorArray: return visitVectorArray(_this.isVectorArrayExp()); + case EXP.slice: return visitSlice(_this.isSliceExp()); + case EXP.array: return visitArray(_this.isArrayExp()); + case EXP.comma: return visitComma(_this.isCommaExp()); + case EXP.delegatePointer: return visitDelegatePointer(_this.isDelegatePtrExp()); + case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp()); + case EXP.index: return visitIndex(_this.isIndexExp()); + case EXP.construct: return visitAssign(_this.isConstructExp()); + case EXP.loweredAssignExp: return visitAssign(_this.isLoweredAssignExp()); + case EXP.blit: return visitAssign(_this.isBlitExp()); + case EXP.assign: return visitAssign(_this.isAssignExp()); + case EXP.question: return visitCond(_this.isCondExp()); + } +} + +/*************************************** + * Parameters: + * sc: scope + * flag: 1: do not issue error message for invalid modification + 2: the exp is a DotVarExp and a subfield of the leftmost + variable is modified + * Returns: + * Whether the type is modifiable + */ +Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none) +{ + switch(exp.op) + { + case EXP.variable: + auto varExp = cast(VarExp)exp; + + //printf("VarExp::checkModifiable %s", varExp.toChars()); + assert(varExp.type); + return varExp.var.checkModify(varExp.loc, sc, null, flag); + + case EXP.dotVariable: + auto dotVarExp = cast(DotVarExp)exp; + + //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars()); + if (dotVarExp.e1.op == EXP.this_) + return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag); + + /* https://issues.dlang.org/show_bug.cgi?id=12764 + * If inside a constructor and an expression of type `this.field.var` + * is encountered, where `field` is a struct declaration with + * default construction disabled, we must make sure that + * assigning to `var` does not imply that `field` was initialized + */ + if (sc.func && sc.func.isCtorDeclaration()) + { + // if inside a constructor scope and e1 of this DotVarExp + // is another DotVarExp, then check if the leftmost expression is a `this` identifier + if (auto dve = dotVarExp.e1.isDotVarExp()) + { + // Iterate the chain of DotVarExp to find `this` + // Keep track whether access to fields was limited to union members + // s.t. one can initialize an entire struct inside nested unions + // (but not its members) + bool onlyUnion = true; + while (true) + { + auto v = dve.var.isVarDeclaration(); + assert(v); + + // Accessing union member? + auto t = v.type.isTypeStruct(); + if (!t || !t.sym.isUnionDeclaration()) + onlyUnion = false; + + // Another DotVarExp left? + if (!dve.e1 || dve.e1.op != EXP.dotVariable) + break; + + dve = cast(DotVarExp) dve.e1; + } + + if (dve.e1.op == EXP.this_) + { + scope v = dve.var.isVarDeclaration(); + /* if v is a struct member field with no initializer, no default construction + * and v wasn't intialized before + */ + if (v && v.isField() && !v._init && !v.ctorinit) + { + if (auto ts = v.type.isTypeStruct()) + { + if (ts.sym.noDefaultCtor) + { + /* checkModify will consider that this is an initialization + * of v while it is actually an assignment of a field of v + */ + scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag); + if (modifyLevel == Modifiable.initialization) + { + // https://issues.dlang.org/show_bug.cgi?id=22118 + // v is a union type field that was assigned + // a variable, therefore it counts as initialization + if (v.ctorinit) + return Modifiable.initialization; + + return Modifiable.yes; + } + return modifyLevel; + } + } + } + } + } + } + + //printf("\te1 = %s\n", e1.toChars()); + return dotVarExp.e1.checkModifiable(sc, flag); + + case EXP.star: + auto ptrExp = cast(PtrExp)exp; + if (auto se = ptrExp.e1.isSymOffExp()) + { + return se.var.checkModify(ptrExp.loc, sc, null, flag); + } + else if (auto ae = ptrExp.e1.isAddrExp()) + { + return ae.e1.checkModifiable(sc, flag); + } + return Modifiable.yes; + + case EXP.slice: + auto sliceExp = cast(SliceExp)exp; + + //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars()); + auto e1 = sliceExp.e1; + if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice) + { + return e1.checkModifiable(sc, flag); + } + return Modifiable.yes; + + case EXP.comma: + return (cast(CommaExp)exp).e2.checkModifiable(sc, flag); + + case EXP.index: + auto indexExp = cast(IndexExp)exp; + auto e1 = indexExp.e1; + if (e1.type.ty == Tsarray || + e1.type.ty == Taarray || + (e1.op == EXP.index && e1.type.ty != Tarray) || + e1.op == EXP.slice) + { + return e1.checkModifiable(sc, flag); + } + return Modifiable.yes; + + case EXP.question: + auto condExp = cast(CondExp)exp; + if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no + && condExp.e2.checkModifiable(sc, flag) != Modifiable.no) + return Modifiable.yes; + return Modifiable.no; + + default: + return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable + } +} + +/** + * Similar to `toLvalue`, but also enforce it is mutable or raise an error. + * Params: + * _this = Expression to convert + * sc = scope + * Returns: `_this` converted to an lvalue, or an `ErrorExp` + */ +extern(C++) Expression modifiableLvalue(Expression _this, Scope* sc) +{ + return modifiableLvalueImpl(_this, sc, _this); +} + +// 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, "modify"); + + auto type = exp.type; + if (checkModifiable(exp, sc) == Modifiable.yes) + { + assert(type); + if (!type.isMutable()) + { + if (auto dve = exp.isDotVarExp()) + { + if (isNeedThisScope(sc, dve.var)) + for (Dsymbol s = sc.func; s; s = s.toParentLocal()) + { + FuncDeclaration ff = s.isFuncDeclaration(); + if (!ff) + break; + if (!ff.type.isMutable) + { + error(exp.loc, "cannot modify `%s` in `%s` function", exp.toChars(), MODtoChars(type.mod)); + return ErrorExp.get(); + } + } + } + error(exp.loc, "cannot modify `%s` expression `%s`", MODtoChars(type.mod), exp.toChars()); + return ErrorExp.get(); + } + else if (!type.isAssignable()) + { + error(exp.loc, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members", + exp.toChars(), type.toChars()); + return ErrorExp.get(); + } + } + return exp.toLvalueImpl(sc, "modify", e); + } + + Expression visitString(StringExp exp) + { + error(exp.loc, "cannot modify string literal `%s`", exp.toChars()); + return ErrorExp.get(); + } + + Expression visitVar(VarExp exp) + { + //printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars()); + if (exp.var.storage_class & STC.manifest) + { + error(exp.loc, "cannot modify manifest constant `%s`", exp.toChars()); + return ErrorExp.get(); + } + // See if this expression is a modifiable lvalue (i.e. not const) + return visit(exp); + } + + Expression visitPtr(PtrExp exp) + { + //printf("PtrExp::modifiableLvalue() %s, type %s\n", exp.toChars(), exp.type.toChars()); + Declaration var; + auto e1 = exp.e1; + if (auto se = e1.isSymOffExp()) + var = se.var; + else if (auto ve = e1.isVarExp()) + var = ve.var; + if (var && var.type.isFunction_Delegate_PtrToFunction()) + { + if (var.type.isTypeFunction()) + error(exp.loc, "function `%s` is not an lvalue and cannot be modified", var.toChars()); + else + error(exp.loc, "function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars()); + return ErrorExp.get(); + } + return visit(exp); + } + + Expression visitSlice(SliceExp exp) + { + error(exp.loc, "slice expression `%s` is not a modifiable lvalue", exp.toChars()); + return exp; + } + + Expression visitComma(CommaExp exp) + { + exp.e2 = exp.e2.modifiableLvalueImpl(sc, e); + return exp; + } + + Expression visitDelegatePtr(DelegatePtrExp exp) + { + if (sc.setUnsafe(false, exp.loc, "cannot modify delegate pointer in `@safe` code `%s`", exp)) + { + return ErrorExp.get(); + } + return visit(exp); + } + + Expression visitDelegateFuncptr(DelegateFuncptrExp exp) + { + if (sc.setUnsafe(false, exp.loc, "cannot modify delegate function pointer in `@safe` code `%s`", exp)) + { + return ErrorExp.get(); + } + return visit(exp); + } + + Expression visitIndex(IndexExp exp) + { + //printf("IndexExp::modifiableLvalue(%s)\n", exp.toChars()); + Expression ex = exp.markSettingAAElem(); + if (ex.op == EXP.error) + return ex; + + return visit(exp); + } + + Expression visitCond(CondExp exp) + { + if (!exp.e1.isLvalue() && !exp.e2.isLvalue()) + { + error(exp.loc, "conditional expression `%s` is not a modifiable lvalue", exp.toChars()); + return ErrorExp.get(); + } + exp.e1 = exp.e1.modifiableLvalue(sc); + exp.e2 = exp.e2.modifiableLvalue(sc); + return exp.toLvalue(sc, "modify"); + } + + switch(_this.op) + { + default: return visit(_this); + case EXP.string_: return visitString(_this.isStringExp()); + case EXP.variable: return visitVar(_this.isVarExp()); + case EXP.star: return visitPtr(_this.isPtrExp()); + case EXP.slice: return visitSlice(_this.isSliceExp()); + case EXP.comma: return visitComma(_this.isCommaExp()); + case EXP.delegatePointer: return visitDelegatePtr(_this.isDelegatePtrExp()); + case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp()); + case EXP.index: return visitIndex(_this.isIndexExp()); + case EXP.question: return visitCond(_this.isCondExp()); + } +} + + /**************************************************** * Determine if `exp`, which gets its address taken, can do so safely. * Params: @@ -14593,7 +15878,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)) { @@ -14680,15 +15965,12 @@ bool checkAddressable(Expression e, Scope* sc) */ private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f) { - with(exp) - { - bool error = checkDisabled(sc, f); - error |= checkDeprecated(sc, f); - error |= checkPurity(sc, f); - error |= checkSafety(sc, f); - error |= checkNogc(sc, f); - return error; - } + bool error = f.checkDisabled(exp.loc, sc); + error |= f.checkDeprecated(exp.loc, sc); + error |= f.checkPurity(exp.loc, sc); + error |= f.checkSafety(exp.loc, sc); + error |= f.checkNogc(exp.loc, sc); + return error; } /******************************* @@ -14801,7 +16083,8 @@ VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration f */ bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object) { - auto rootSymbol = sc.search(loc, Id.empty, null); + Dsymbol pscopesym; + auto rootSymbol = sc.search(loc, Id.empty, pscopesym); if (auto moduleSymbol = rootSymbol.search(loc, module_)) if (moduleSymbol.search(loc, id)) return true; diff --git a/dmd/file_manager.d b/dmd/file_manager.d index a0e5d0519c8..eaef8d545e6 100644 --- a/dmd/file_manager.d +++ b/dmd/file_manager.d @@ -1,7 +1,7 @@ /** * Read a file from disk and store it in memory. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d, _file_manager.d) * Documentation: https://dlang.org/phobos/dmd_file_manager.html @@ -10,6 +10,7 @@ module dmd.file_manager; +import core.stdc.stdio; import dmd.root.stringtable : StringTable; import dmd.root.file : File, Buffer; import dmd.root.filename : FileName, isDirSeparator; @@ -281,63 +282,103 @@ nothrow: return fb; } - /** - * Looks up the given filename from the internal file buffer table, and returns the lines within the file. - * If the file does not already exist within the table, it will be read from the filesystem. - * If it has been read before, - * - * Returns: the loaded source file if it was found in memory, - * otherwise `null` + /********************************** + * Take `text` and turn it into an InputRange that emits + * slices into `text` for each line. + * Params: + * text = array of characters + * Returns: + * InputRange accessing `text` as a sequence of lines + * Reference: + * `std.string.splitLines()` */ - const(char)[][] getLines(FileName file) + auto splitLines(const char[] text) { - const(char)[][] lines; - if (const buffer = lookup(file)) + struct Range { - const slice = buffer; - size_t start, end; - for (auto i = 0; i < slice.length; i++) + @safe: + @nogc: + nothrow: + pure: + private: + + const char[] text; + size_t index; // index of start of line + size_t eolIndex; // index of end of line before newline characters + size_t nextIndex; // index past end of line + + public this(const char[] text) + { + this.text = text; + } + + public bool empty() { return index == text.length; } + + public void popFront() { advance(); index = nextIndex; } + + public const(char)[] front() { advance(); return text[index .. eolIndex]; } + + private void advance() { - const c = slice[i]; - if (c == '\n' || c == '\r') + if (index != nextIndex) // if already advanced + return; + + for (size_t i = index; i < text.length; ++i) { - if (i != 0) - { - end = i; - // Appending lines one at a time will certainly be slow - lines ~= cast(const(char)[])slice[start .. end]; - } - // Check for Windows-style CRLF newlines - if (c == '\r') + switch (text[i]) { - if (slice.length > i + 1 && slice[i + 1] == '\n') - { - // This is a CRLF sequence, skip over two characters - start = i + 2; - i++; - } - else - { - // Just a CR sequence - start = i + 1; - } - } - else - { - // The next line should start after the LF sequence - start = i + 1; + case '\v', '\f', '\n': + eolIndex = i; + nextIndex = i + 1; + return; + + case '\r': + if (i + 1 < text.length && text[i + 1] == '\n') // decode "\r\n" + { + eolIndex = i; + nextIndex = i + 2; + return; + } + eolIndex = i; + nextIndex = i + 1; + return; + + /* Manually decode: + * NEL is C2 85 + */ + case 0xC2: + if (i + 1 < text.length && text[i + 1] == 0x85) + { + eolIndex = i; + nextIndex = i + 2; + return; + } + break; + + /* Manually decode: + * lineSep is E2 80 A8 + * paraSep is E2 80 A9 + */ + case 0xE2: + if (i + 2 < text.length && + text[i + 1] == 0x80 && + (text[i + 2] == 0xA8 || text[i + 2] == 0xA9) + ) + { + eolIndex = i; + nextIndex = i + 3; + return; + } + break; + + default: + break; } } } - - if (slice[$ - 1] != '\r' && slice[$ - 1] != '\n') - { - end = slice.length; - lines ~= cast(const(char)[])slice[start .. end]; - } } - return lines; + return Range(text); } /** diff --git a/dmd/foreachvar.d b/dmd/foreachvar.d index dc4b20bf957..53b3c041d1e 100644 --- a/dmd/foreachvar.d +++ b/dmd/foreachvar.d @@ -1,7 +1,7 @@ /** * Utility to visit every variable in an expression. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d, _foreachvar.d) diff --git a/dmd/frontend.h b/dmd/frontend.h index d4090e7d36e..7392c7ee940 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -47,13 +47,11 @@ class CPPNamespaceDeclaration; class UserAttributeDeclaration; class Module; class TemplateInstance; -class ScopeDsymbol; class AggregateDeclaration; class LabelDsymbol; class ClassDeclaration; class Type; class Package; -struct FieldState; template struct Array; class UnitTestDeclaration; @@ -90,6 +88,7 @@ class DebugSymbol; class StructDeclaration; class UnionDeclaration; class InterfaceDeclaration; +class ScopeDsymbol; class ForwardingScopeDsymbol; class WithScopeSymbol; class ArrayScopeSymbol; @@ -117,6 +116,62 @@ class StaticIfCondition; class ForeachStatement; class ForeachRangeStatement; struct OutBuffer; +class TypeInfoClassDeclaration; +class Initializer; +struct IntRange; +struct ModuleDeclaration; +template +struct FileMapping; +struct Escape; +class ErrorSink; +class LabelStatement; +class SwitchStatement; +class Statement; +class TryFinallyStatement; +class ScopeGuardStatement; +struct DocComment; +class WithStatement; +struct AA; +class CaseStatement; +class Catch; +struct Designator; +class GotoCaseStatement; +class GotoStatement; +class Parameter; +class ReturnStatement; +class ScopeStatement; +class TemplateParameter; +class TemplateTypeParameter; +class TemplateValueParameter; +class TemplateAliasParameter; +class TemplateThisParameter; +class TemplateTupleParameter; +struct TemplatePrevious; +class TypeQualified; +struct TYPE; +class TypeBasic; +class TypeFunction; +class TypeError; +class TypeVector; +class TypeSArray; +class TypeDArray; +class TypeAArray; +class TypePointer; +class TypeReference; +class TypeDelegate; +class TypeIdentifier; +class TypeInstance; +class TypeTypeof; +class TypeReturn; +class TypeStruct; +class TypeEnum; +class TypeClass; +class TypeSlice; +class TypeNull; +class TypeMixin; +class TypeTraits; +class TypeNoreturn; +class TypeTag; class StringExp; class IntegerExp; class ErrorExp; @@ -231,63 +286,6 @@ class ThrownExceptionExp; class UnaExp; class BinExp; class BinAssignExp; -class TypeInfoClassDeclaration; -class Initializer; -struct IntRange; -struct ModuleDeclaration; -template -struct FileMapping; -struct Escape; -class ErrorSink; -class LabelStatement; -class SwitchStatement; -class Statement; -class TryFinallyStatement; -class ScopeGuardStatement; -struct DocComment; -class WithStatement; -struct AA; -class Tuple; -class Parameter; -class TemplateParameter; -struct TemplatePrevious; -struct TYPE; -class TypeBasic; -class TypeFunction; -class TypeError; -class TypeVector; -class TypeSArray; -class TypeDArray; -class TypeAArray; -class TypePointer; -class TypeReference; -class TypeDelegate; -class TypeIdentifier; -class TypeInstance; -class TypeTypeof; -class TypeReturn; -class TypeStruct; -class TypeEnum; -class TypeClass; -class TypeSlice; -class TypeNull; -class TypeMixin; -class TypeTraits; -class TypeNoreturn; -class TypeTag; -class TemplateTypeParameter; -class TemplateValueParameter; -class TemplateAliasParameter; -class TemplateThisParameter; -class TemplateTupleParameter; -class TypeQualified; -class CaseStatement; -class Catch; -struct Designator; -class GotoCaseStatement; -class GotoStatement; -class ReturnStatement; -class ScopeStatement; struct ContractInfo; struct ObjcSelector; class PeelStatement; @@ -305,11 +303,11 @@ class TryCatchStatement; class DebugStatement; class ErrorInitializer; class VoidInitializer; +class DefaultInitializer; class StructInitializer; class ArrayInitializer; class ExpInitializer; class CInitializer; -class FileManager; class ErrorStatement; class ExpStatement; class ConditionalStatement; @@ -330,7 +328,8 @@ class InlineAsmStatement; class GccAsmStatement; class ImportStatement; struct Token; -struct code; +struct Param; +class FileManager; class Object; class TypeInfo_Class; class TypeInfo; @@ -478,7 +477,6 @@ class Dsymbol : public ASTNode const char* locToChars(); bool equals(const RootObject* const o) const override; bool isAnonymous() const; - bool checkDeprecated(const Loc& loc, Scope* sc); Module* getModule(); bool isCsymbol(); Module* getAccessModule(); @@ -498,10 +496,6 @@ class Dsymbol : public ASTNode virtual const char* kind() const; virtual Dsymbol* toAlias(); 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, int32_t flags = 0); virtual bool overloadInsert(Dsymbol* s); virtual uinteger_t size(const Loc& loc); virtual bool isforwardRef(); @@ -520,8 +514,7 @@ class Dsymbol : public ASTNode virtual bool needThis(); virtual Visibility visible(); virtual Dsymbol* syntaxCopy(Dsymbol* s); - virtual bool oneMember(Dsymbol** ps, Identifier* ident); - virtual void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion); + virtual bool oneMember(Dsymbol*& ps, Identifier* ident); virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); virtual void addObjcSymbols(Array* classes, Array* categories); @@ -619,20 +612,18 @@ class ScopeDsymbol : public Dsymbol Array* members; DsymbolTable* symtab; uint32_t endlinnum; -private: Array* importedScopes; Visibility::Kind* visibilities; +private: BitArray accessiblePackages; BitArray privateAccessiblePackages; public: ScopeDsymbol* syntaxCopy(Dsymbol* s) override; - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 8) override; virtual void importScope(Dsymbol* s, Visibility visibility); - virtual bool isPackageAccessible(Package* p, Visibility visibility, int32_t flags = 0); + virtual bool isPackageAccessible(Package* p, Visibility visibility, uint32_t flags = 0u); bool isforwardRef() final override; static void multiplyDefined(const Loc& loc, Dsymbol* s1, Dsymbol* s2); const char* kind() const override; - FuncDeclaration* findGetMembers(); virtual Dsymbol* symtabInsert(Dsymbol* s); virtual Dsymbol* symtabLookup(Dsymbol* s, Identifier* id); bool hasStaticCtorOrDtor() override; @@ -789,322 +780,15 @@ struct FileName final } }; -enum class EXP : uint8_t +enum class MATCH { - reserved = 0u, - negate = 1u, - cast_ = 2u, - null_ = 3u, - assert_ = 4u, - array = 5u, - call = 6u, - address = 7u, - type = 8u, - throw_ = 9u, - new_ = 10u, - delete_ = 11u, - star = 12u, - symbolOffset = 13u, - variable = 14u, - dotVariable = 15u, - dotIdentifier = 16u, - dotTemplateInstance = 17u, - dotType = 18u, - slice = 19u, - arrayLength = 20u, - dollar = 21u, - template_ = 22u, - dotTemplateDeclaration = 23u, - declaration = 24u, - dSymbol = 25u, - typeid_ = 26u, - uadd = 27u, - remove = 28u, - newAnonymousClass = 29u, - arrayLiteral = 30u, - assocArrayLiteral = 31u, - structLiteral = 32u, - classReference = 33u, - thrownException = 34u, - delegatePointer = 35u, - delegateFunctionPointer = 36u, - lessThan = 37u, - greaterThan = 38u, - lessOrEqual = 39u, - greaterOrEqual = 40u, - equal = 41u, - notEqual = 42u, - identity = 43u, - notIdentity = 44u, - index = 45u, - is_ = 46u, - leftShift = 47u, - rightShift = 48u, - leftShiftAssign = 49u, - rightShiftAssign = 50u, - unsignedRightShift = 51u, - unsignedRightShiftAssign = 52u, - concatenate = 53u, - concatenateAssign = 54u, - concatenateElemAssign = 55u, - concatenateDcharAssign = 56u, - add = 57u, - min = 58u, - addAssign = 59u, - minAssign = 60u, - mul = 61u, - div = 62u, - mod = 63u, - mulAssign = 64u, - divAssign = 65u, - modAssign = 66u, - and_ = 67u, - or_ = 68u, - xor_ = 69u, - andAssign = 70u, - orAssign = 71u, - xorAssign = 72u, - assign = 73u, - not_ = 74u, - tilde = 75u, - plusPlus = 76u, - minusMinus = 77u, - construct = 78u, - blit = 79u, - dot = 80u, - comma = 81u, - question = 82u, - andAnd = 83u, - orOr = 84u, - prePlusPlus = 85u, - preMinusMinus = 86u, - identifier = 87u, - string_ = 88u, - this_ = 89u, - super_ = 90u, - halt = 91u, - tuple = 92u, - error = 93u, - void_ = 94u, - int64 = 95u, - float64 = 96u, - complex80 = 97u, - import_ = 98u, - delegate_ = 99u, - function_ = 100u, - mixin_ = 101u, - in_ = 102u, - break_ = 103u, - continue_ = 104u, - goto_ = 105u, - scope_ = 106u, - traits = 107u, - overloadSet = 108u, - line = 109u, - file = 110u, - fileFullPath = 111u, - moduleString = 112u, - functionString = 113u, - prettyFunction = 114u, - pow = 115u, - powAssign = 116u, - vector = 117u, - voidExpression = 118u, - cantExpression = 119u, - showCtfeContext = 120u, - objcClassReference = 121u, - vectorArray = 122u, - compoundLiteral = 123u, - _Generic_ = 124u, - interval = 125u, - loweredAssignExp = 126u, + nomatch = 0, + convert = 1, + constant = 2, + exact = 3, }; -typedef uint64_t dinteger_t; - -struct complex_t final -{ - _d_real re; - _d_real im; - complex_t() = delete; - complex_t(_d_real re); - complex_t(_d_real re, _d_real im); - int32_t opEquals(complex_t y) const; -}; - -template -struct Optional final -{ - T value; - bool present; - Optional(T value); - static Optional create(T val); - bool isPresent() const; - bool isEmpty() const; - T get(); - bool hasValue(T exp) const; - Optional() - { - } -}; - -class Expression : public ASTNode -{ -public: - Type* type; - Loc loc; - const EXP op; - size_t size() const; - static void _init(); - static void deinitialize(); - virtual Expression* syntaxCopy(); - DYNCAST dyncast() const final override; - const char* toChars() const override; - virtual dinteger_t toInteger(); - virtual uinteger_t toUInteger(); - virtual _d_real toReal(); - virtual _d_real toImaginary(); - virtual complex_t toComplex(); - virtual StringExp* toStringExp(); - virtual bool isLvalue(); - virtual Expression* toLvalue(Scope* sc, Expression* e); - virtual Expression* modifiableLvalue(Scope* sc, Expression* e); - virtual Expression* resolveLoc(const Loc& loc, Scope* sc); - virtual bool checkType(); - virtual bool checkValue(); - Expression* addressOf(); - Expression* deref(); - Expression* optimize(int32_t result, bool keepLvalue = false); - int32_t isConst(); - virtual bool isIdentical(const Expression* const e) const; - virtual Optional toBool(); - virtual bool hasCode(); - IntegerExp* isIntegerExp(); - ErrorExp* isErrorExp(); - VoidInitExp* isVoidInitExp(); - RealExp* isRealExp(); - ComplexExp* isComplexExp(); - IdentifierExp* isIdentifierExp(); - DollarExp* isDollarExp(); - DsymbolExp* isDsymbolExp(); - ThisExp* isThisExp(); - SuperExp* isSuperExp(); - NullExp* isNullExp(); - StringExp* isStringExp(); - TupleExp* isTupleExp(); - ArrayLiteralExp* isArrayLiteralExp(); - AssocArrayLiteralExp* isAssocArrayLiteralExp(); - StructLiteralExp* isStructLiteralExp(); - CompoundLiteralExp* isCompoundLiteralExp(); - TypeExp* isTypeExp(); - ScopeExp* isScopeExp(); - TemplateExp* isTemplateExp(); - NewExp* isNewExp(); - NewAnonClassExp* isNewAnonClassExp(); - SymOffExp* isSymOffExp(); - VarExp* isVarExp(); - OverExp* isOverExp(); - FuncExp* isFuncExp(); - DeclarationExp* isDeclarationExp(); - TypeidExp* isTypeidExp(); - TraitsExp* isTraitsExp(); - HaltExp* isHaltExp(); - IsExp* isExp(); - MixinExp* isMixinExp(); - ImportExp* isImportExp(); - AssertExp* isAssertExp(); - ThrowExp* isThrowExp(); - DotIdExp* isDotIdExp(); - DotTemplateExp* isDotTemplateExp(); - DotVarExp* isDotVarExp(); - DotTemplateInstanceExp* isDotTemplateInstanceExp(); - DelegateExp* isDelegateExp(); - DotTypeExp* isDotTypeExp(); - CallExp* isCallExp(); - AddrExp* isAddrExp(); - PtrExp* isPtrExp(); - NegExp* isNegExp(); - UAddExp* isUAddExp(); - ComExp* isComExp(); - NotExp* isNotExp(); - DeleteExp* isDeleteExp(); - CastExp* isCastExp(); - VectorExp* isVectorExp(); - VectorArrayExp* isVectorArrayExp(); - SliceExp* isSliceExp(); - ArrayLengthExp* isArrayLengthExp(); - ArrayExp* isArrayExp(); - DotExp* isDotExp(); - CommaExp* isCommaExp(); - IntervalExp* isIntervalExp(); - DelegatePtrExp* isDelegatePtrExp(); - DelegateFuncptrExp* isDelegateFuncptrExp(); - IndexExp* isIndexExp(); - PostExp* isPostExp(); - PreExp* isPreExp(); - AssignExp* isAssignExp(); - LoweredAssignExp* isLoweredAssignExp(); - ConstructExp* isConstructExp(); - BlitExp* isBlitExp(); - AddAssignExp* isAddAssignExp(); - MinAssignExp* isMinAssignExp(); - MulAssignExp* isMulAssignExp(); - DivAssignExp* isDivAssignExp(); - ModAssignExp* isModAssignExp(); - AndAssignExp* isAndAssignExp(); - OrAssignExp* isOrAssignExp(); - XorAssignExp* isXorAssignExp(); - PowAssignExp* isPowAssignExp(); - ShlAssignExp* isShlAssignExp(); - ShrAssignExp* isShrAssignExp(); - UshrAssignExp* isUshrAssignExp(); - CatAssignExp* isCatAssignExp(); - CatElemAssignExp* isCatElemAssignExp(); - CatDcharAssignExp* isCatDcharAssignExp(); - AddExp* isAddExp(); - MinExp* isMinExp(); - CatExp* isCatExp(); - MulExp* isMulExp(); - DivExp* isDivExp(); - ModExp* isModExp(); - PowExp* isPowExp(); - ShlExp* isShlExp(); - ShrExp* isShrExp(); - UshrExp* isUshrExp(); - AndExp* isAndExp(); - OrExp* isOrExp(); - XorExp* isXorExp(); - LogicalExp* isLogicalExp(); - InExp* isInExp(); - RemoveExp* isRemoveExp(); - EqualExp* isEqualExp(); - IdentityExp* isIdentityExp(); - CondExp* isCondExp(); - GenericExp* isGenericExp(); - DefaultInitExp* isDefaultInitExp(); - FileInitExp* isFileInitExp(); - LineInitExp* isLineInitExp(); - ModuleInitExp* isModuleInitExp(); - FuncInitExp* isFuncInitExp(); - PrettyFuncInitExp* isPrettyFuncInitExp(); - ObjcClassReferenceExp* isObjcClassReferenceExp(); - ClassReferenceExp* isClassReferenceExp(); - ThrownExceptionExp* isThrownExceptionExp(); - UnaExp* isUnaExp(); - BinExp* isBinExp(); - BinAssignExp* isBinAssignExp(); - void accept(Visitor* v) override; -}; - -enum class MATCH -{ - nomatch = 0, - convert = 1, - constant = 2, - exact = 3, -}; - -enum class ThreeState : uint8_t +enum class ThreeState : uint8_t { none = 0u, no = 1u, @@ -1271,868 +955,341 @@ struct AssocArray final } }; -enum class TY : uint8_t -{ - Tarray = 0u, - Tsarray = 1u, - Taarray = 2u, - Tpointer = 3u, - Treference = 4u, - Tfunction = 5u, - Tident = 6u, - Tclass = 7u, - Tstruct = 8u, - Tenum = 9u, - Tdelegate = 10u, - Tnone = 11u, - Tvoid = 12u, - Tint8 = 13u, - Tuns8 = 14u, - Tint16 = 15u, - Tuns16 = 16u, - Tint32 = 17u, - Tuns32 = 18u, - Tint64 = 19u, - Tuns64 = 20u, - Tfloat32 = 21u, - Tfloat64 = 22u, - Tfloat80 = 23u, - Timaginary32 = 24u, - Timaginary64 = 25u, - Timaginary80 = 26u, - Tcomplex32 = 27u, - Tcomplex64 = 28u, - Tcomplex80 = 29u, - Tbool = 30u, - Tchar = 31u, - Twchar = 32u, - Tdchar = 33u, - Terror = 34u, - Tinstance = 35u, - Ttypeof = 36u, - Ttuple = 37u, - Tslice = 38u, - Treturn = 39u, - Tnull = 40u, - Tvector = 41u, - Tint128 = 42u, - Tuns128 = 43u, - Ttraits = 44u, - Tmixin = 45u, - Tnoreturn = 46u, - Ttag = 47u, -}; - -enum class Covariant -{ - distinct = 0, - yes = 1, - no = 2, - fwdref = 3, -}; - -class Type : public ASTNode +template +class ParseTimeVisitor { public: - TY ty; - uint8_t mod; - char* deco; - struct Mcache final - { - Type* cto; - Type* ito; - Type* sto; - Type* scto; - Type* wto; - Type* wcto; - Type* swto; - Type* swcto; - Mcache() : - cto(), - ito(), - sto(), - scto(), - wto(), - wcto(), - swto(), - swcto() - { - } - Mcache(Type* cto, Type* ito = nullptr, Type* sto = nullptr, Type* scto = nullptr, Type* wto = nullptr, Type* wcto = nullptr, Type* swto = nullptr, Type* swcto = nullptr) : - cto(cto), - ito(ito), - sto(sto), - scto(scto), - wto(wto), - wcto(wcto), - swto(swto), - swcto(swcto) - {} - }; + virtual void visit(typename AST::Dsymbol ); + virtual void visit(typename AST::Parameter ); + virtual void visit(typename AST::Statement ); + virtual void visit(typename AST::Type ); + virtual void visit(typename AST::Expression ); + virtual void visit(typename AST::TemplateParameter ); + virtual void visit(typename AST::Condition ); + virtual void visit(typename AST::Initializer ); + virtual void visit(typename AST::AliasThis s); + virtual void visit(typename AST::Declaration s); + virtual void visit(typename AST::ScopeDsymbol s); + virtual void visit(typename AST::Import s); + virtual void visit(typename AST::AttribDeclaration s); + virtual void visit(typename AST::StaticAssert s); + virtual void visit(typename AST::DebugSymbol s); + virtual void visit(typename AST::VersionSymbol s); + virtual void visit(typename AST::AliasAssign s); + virtual void visit(typename AST::Package s); + virtual void visit(typename AST::EnumDeclaration s); + virtual void visit(typename AST::AggregateDeclaration s); + virtual void visit(typename AST::TemplateDeclaration s); + virtual void visit(typename AST::TemplateInstance s); + virtual void visit(typename AST::Nspace s); + virtual void visit(typename AST::VarDeclaration s); + virtual void visit(typename AST::FuncDeclaration s); + virtual void visit(typename AST::AliasDeclaration s); + virtual void visit(typename AST::TupleDeclaration s); + virtual void visit(typename AST::FuncLiteralDeclaration s); + virtual void visit(typename AST::PostBlitDeclaration s); + virtual void visit(typename AST::CtorDeclaration s); + virtual void visit(typename AST::DtorDeclaration s); + virtual void visit(typename AST::InvariantDeclaration s); + virtual void visit(typename AST::UnitTestDeclaration s); + virtual void visit(typename AST::NewDeclaration s); + virtual void visit(typename AST::StaticCtorDeclaration s); + virtual void visit(typename AST::StaticDtorDeclaration s); + virtual void visit(typename AST::SharedStaticCtorDeclaration s); + virtual void visit(typename AST::SharedStaticDtorDeclaration s); + virtual void visit(typename AST::MixinDeclaration s); + virtual void visit(typename AST::UserAttributeDeclaration s); + virtual void visit(typename AST::LinkDeclaration s); + virtual void visit(typename AST::AnonDeclaration s); + virtual void visit(typename AST::AlignDeclaration s); + virtual void visit(typename AST::CPPMangleDeclaration s); + virtual void visit(typename AST::CPPNamespaceDeclaration s); + virtual void visit(typename AST::VisibilityDeclaration s); + virtual void visit(typename AST::PragmaDeclaration s); + virtual void visit(typename AST::StorageClassDeclaration s); + virtual void visit(typename AST::ConditionalDeclaration s); + virtual void visit(typename AST::StaticForeachDeclaration s); + virtual void visit(typename AST::DeprecatedDeclaration s); + virtual void visit(typename AST::StaticIfDeclaration s); + virtual void visit(typename AST::EnumMember s); + virtual void visit(typename AST::Module s); + virtual void visit(typename AST::StructDeclaration s); + virtual void visit(typename AST::UnionDeclaration s); + virtual void visit(typename AST::ClassDeclaration s); + virtual void visit(typename AST::InterfaceDeclaration s); + virtual void visit(typename AST::TemplateMixin s); + virtual void visit(typename AST::BitFieldDeclaration s); + virtual void visit(typename AST::ImportStatement s); + virtual void visit(typename AST::ScopeStatement s); + virtual void visit(typename AST::ReturnStatement s); + virtual void visit(typename AST::LabelStatement s); + virtual void visit(typename AST::StaticAssertStatement s); + virtual void visit(typename AST::MixinStatement s); + virtual void visit(typename AST::WhileStatement s); + virtual void visit(typename AST::ForStatement s); + virtual void visit(typename AST::DoStatement s); + virtual void visit(typename AST::ForeachRangeStatement s); + virtual void visit(typename AST::ForeachStatement s); + virtual void visit(typename AST::IfStatement s); + virtual void visit(typename AST::ScopeGuardStatement s); + virtual void visit(typename AST::ConditionalStatement s); + virtual void visit(typename AST::StaticForeachStatement s); + virtual void visit(typename AST::PragmaStatement s); + virtual void visit(typename AST::SwitchStatement s); + virtual void visit(typename AST::CaseRangeStatement s); + virtual void visit(typename AST::CaseStatement s); + virtual void visit(typename AST::DefaultStatement s); + virtual void visit(typename AST::BreakStatement s); + virtual void visit(typename AST::ContinueStatement s); + virtual void visit(typename AST::GotoDefaultStatement s); + virtual void visit(typename AST::GotoCaseStatement s); + virtual void visit(typename AST::GotoStatement s); + virtual void visit(typename AST::SynchronizedStatement s); + virtual void visit(typename AST::WithStatement s); + virtual void visit(typename AST::TryCatchStatement s); + virtual void visit(typename AST::TryFinallyStatement s); + virtual void visit(typename AST::ThrowStatement s); + virtual void visit(typename AST::AsmStatement s); + virtual void visit(typename AST::ExpStatement s); + virtual void visit(typename AST::CompoundStatement s); + virtual void visit(typename AST::CompoundDeclarationStatement s); + virtual void visit(typename AST::CompoundAsmStatement s); + virtual void visit(typename AST::InlineAsmStatement s); + virtual void visit(typename AST::GccAsmStatement s); + virtual void visit(typename AST::TypeBasic t); + virtual void visit(typename AST::TypeError t); + virtual void visit(typename AST::TypeNull t); + virtual void visit(typename AST::TypeNoreturn t); + virtual void visit(typename AST::TypeVector t); + virtual void visit(typename AST::TypeEnum t); + virtual void visit(typename AST::TypeTuple t); + virtual void visit(typename AST::TypeClass t); + virtual void visit(typename AST::TypeStruct t); + virtual void visit(typename AST::TypeNext t); + virtual void visit(typename AST::TypeQualified t); + virtual void visit(typename AST::TypeTraits t); + virtual void visit(typename AST::TypeMixin t); + virtual void visit(typename AST::TypeTag t); + virtual void visit(typename AST::TypeReference t); + virtual void visit(typename AST::TypeSlice t); + virtual void visit(typename AST::TypeDelegate t); + virtual void visit(typename AST::TypePointer t); + virtual void visit(typename AST::TypeFunction t); + virtual void visit(typename AST::TypeArray t); + virtual void visit(typename AST::TypeDArray t); + virtual void visit(typename AST::TypeAArray t); + virtual void visit(typename AST::TypeSArray t); + virtual void visit(typename AST::TypeIdentifier t); + virtual void visit(typename AST::TypeReturn t); + virtual void visit(typename AST::TypeTypeof t); + virtual void visit(typename AST::TypeInstance t); + virtual void visit(typename AST::DeclarationExp e); + virtual void visit(typename AST::IntegerExp e); + virtual void visit(typename AST::NewAnonClassExp e); + virtual void visit(typename AST::IsExp e); + virtual void visit(typename AST::RealExp e); + virtual void visit(typename AST::NullExp e); + virtual void visit(typename AST::TypeidExp e); + virtual void visit(typename AST::TraitsExp e); + virtual void visit(typename AST::StringExp e); + virtual void visit(typename AST::NewExp e); + virtual void visit(typename AST::AssocArrayLiteralExp e); + virtual void visit(typename AST::ArrayLiteralExp e); + virtual void visit(typename AST::MixinExp e); + virtual void visit(typename AST::FuncExp e); + virtual void visit(typename AST::IntervalExp e); + virtual void visit(typename AST::TypeExp e); + virtual void visit(typename AST::ScopeExp e); + virtual void visit(typename AST::IdentifierExp e); + virtual void visit(typename AST::UnaExp e); + virtual void visit(typename AST::DefaultInitExp e); + virtual void visit(typename AST::BinExp e); + virtual void visit(typename AST::DsymbolExp e); + virtual void visit(typename AST::TemplateExp e); + virtual void visit(typename AST::SymbolExp e); + virtual void visit(typename AST::TupleExp e); + virtual void visit(typename AST::ThisExp e); + virtual void visit(typename AST::GenericExp e); + virtual void visit(typename AST::VarExp e); + virtual void visit(typename AST::DollarExp e); + virtual void visit(typename AST::SuperExp e); + virtual void visit(typename AST::AddrExp e); + virtual void visit(typename AST::PreExp e); + virtual void visit(typename AST::PtrExp e); + virtual void visit(typename AST::NegExp e); + virtual void visit(typename AST::UAddExp e); + virtual void visit(typename AST::NotExp e); + virtual void visit(typename AST::ComExp e); + virtual void visit(typename AST::DeleteExp e); + virtual void visit(typename AST::CastExp e); + virtual void visit(typename AST::CallExp e); + virtual void visit(typename AST::DotIdExp e); + virtual void visit(typename AST::AssertExp e); + virtual void visit(typename AST::ThrowExp e); + virtual void visit(typename AST::ImportExp e); + virtual void visit(typename AST::DotTemplateInstanceExp e); + virtual void visit(typename AST::ArrayExp e); + virtual void visit(typename AST::FuncInitExp e); + virtual void visit(typename AST::PrettyFuncInitExp e); + virtual void visit(typename AST::FileInitExp e); + virtual void visit(typename AST::LineInitExp e); + virtual void visit(typename AST::ModuleInitExp e); + virtual void visit(typename AST::CommaExp e); + virtual void visit(typename AST::PostExp e); + virtual void visit(typename AST::PowExp e); + virtual void visit(typename AST::MulExp e); + virtual void visit(typename AST::DivExp e); + virtual void visit(typename AST::ModExp e); + virtual void visit(typename AST::AddExp e); + virtual void visit(typename AST::MinExp e); + virtual void visit(typename AST::CatExp e); + virtual void visit(typename AST::ShlExp e); + virtual void visit(typename AST::ShrExp e); + virtual void visit(typename AST::UshrExp e); + virtual void visit(typename AST::EqualExp e); + virtual void visit(typename AST::InExp e); + virtual void visit(typename AST::IdentityExp e); + virtual void visit(typename AST::CmpExp e); + virtual void visit(typename AST::AndExp e); + virtual void visit(typename AST::XorExp e); + virtual void visit(typename AST::OrExp e); + virtual void visit(typename AST::LogicalExp e); + virtual void visit(typename AST::CondExp e); + virtual void visit(typename AST::AssignExp e); + virtual void visit(typename AST::BinAssignExp e); + virtual void visit(typename AST::AddAssignExp e); + virtual void visit(typename AST::MinAssignExp e); + virtual void visit(typename AST::MulAssignExp e); + virtual void visit(typename AST::DivAssignExp e); + virtual void visit(typename AST::ModAssignExp e); + virtual void visit(typename AST::PowAssignExp e); + virtual void visit(typename AST::AndAssignExp e); + virtual void visit(typename AST::OrAssignExp e); + virtual void visit(typename AST::XorAssignExp e); + virtual void visit(typename AST::ShlAssignExp e); + virtual void visit(typename AST::ShrAssignExp e); + virtual void visit(typename AST::UshrAssignExp e); + virtual void visit(typename AST::CatAssignExp e); + virtual void visit(typename AST::CatElemAssignExp e); + virtual void visit(typename AST::CatDcharAssignExp e); + virtual void visit(typename AST::TemplateAliasParameter tp); + virtual void visit(typename AST::TemplateTypeParameter tp); + virtual void visit(typename AST::TemplateTupleParameter tp); + virtual void visit(typename AST::TemplateValueParameter tp); + virtual void visit(typename AST::TemplateThisParameter tp); + virtual void visit(typename AST::StaticIfCondition c); + virtual void visit(typename AST::DVCondition c); + virtual void visit(typename AST::DebugCondition c); + virtual void visit(typename AST::VersionCondition c); + virtual void visit(typename AST::ExpInitializer i); + virtual void visit(typename AST::StructInitializer i); + virtual void visit(typename AST::ArrayInitializer i); + virtual void visit(typename AST::VoidInitializer i); + virtual void visit(typename AST::DefaultInitializer i); + virtual void visit(typename AST::CInitializer i); +}; -private: - Mcache* mcache; -public: - Type* pto; - Type* rto; - Type* arrayof; - TypeInfoDeclaration* vtinfo; - TYPE* ctype; - static Type* tvoid; - static Type* tint8; - static Type* tuns8; - static Type* tint16; - static Type* tuns16; - static Type* tint32; - static Type* tuns32; - static Type* tint64; - static Type* tuns64; - static Type* tint128; - static Type* tuns128; - static Type* tfloat32; - static Type* tfloat64; - static Type* tfloat80; - static Type* timaginary32; - static Type* timaginary64; - static Type* timaginary80; - static Type* tcomplex32; - static Type* tcomplex64; - static Type* tcomplex80; - static Type* tbool; - static Type* tchar; - static Type* twchar; - static Type* tdchar; - static Type* tshiftcnt; - static Type* tvoidptr; - static Type* tstring; - static Type* twstring; - static Type* tdstring; - static Type* terror; - static Type* tnull; - static Type* tnoreturn; - static Type* tsize_t; - static Type* tptrdiff_t; - static Type* thash_t; - static ClassDeclaration* dtypeinfo; - static ClassDeclaration* typeinfoclass; - static ClassDeclaration* typeinfointerface; - static ClassDeclaration* typeinfostruct; - static ClassDeclaration* typeinfopointer; - static ClassDeclaration* typeinfoarray; - static ClassDeclaration* typeinfostaticarray; - static ClassDeclaration* typeinfoassociativearray; - static ClassDeclaration* typeinfovector; - static ClassDeclaration* typeinfoenum; - static ClassDeclaration* typeinfofunction; - static ClassDeclaration* typeinfodelegate; - static ClassDeclaration* typeinfotypelist; - static ClassDeclaration* typeinfoconst; - static ClassDeclaration* typeinfoinvariant; - static ClassDeclaration* typeinfoshared; - static ClassDeclaration* typeinfowild; - static TemplateDeclaration* rtinfo; - static Type* basic[48LLU]; - virtual const char* kind() const; - Type* copy() const; - virtual Type* syntaxCopy(); - bool equals(const RootObject* const o) const override; - bool equivalent(Type* t); - DYNCAST dyncast() const final override; - size_t getUniqueID() const; - Covariant covariant(Type* t, uint64_t* pstc = nullptr, bool cppCovariant = false); - const char* toChars() const final override; - char* toPrettyChars(bool QualifyTypes = false); - static void _init(); - static void deinitialize(); - uinteger_t size(); - virtual uinteger_t size(const Loc& loc); - virtual uint32_t alignsize(); - Type* trySemantic(const Loc& loc, Scope* sc); - Type* merge2(); - void modToBuffer(OutBuffer& buf) const; - char* modToChars() const; - virtual bool isintegral(); - virtual bool isfloating(); - virtual bool isreal(); - virtual bool isimaginary(); - virtual bool iscomplex(); - virtual bool isscalar(); - virtual bool isunsigned(); - virtual bool isscope(); - virtual bool isString(); - virtual bool isAssignable(); - virtual bool isBoolean(); - virtual void checkDeprecated(const Loc& loc, Scope* sc); - bool isConst() const; - bool isImmutable() const; - bool isMutable() const; - bool isShared() const; - bool isSharedConst() const; - bool isWild() const; - bool isWildConst() const; - bool isSharedWild() const; - bool isNaked() const; - Type* nullAttributes() const; - Type* constOf(); - Type* immutableOf(); - Type* mutableOf(); - Type* sharedOf(); - Type* sharedConstOf(); - Type* unSharedOf(); - Type* wildOf(); - Type* wildConstOf(); - Type* sharedWildOf(); - Type* sharedWildConstOf(); - Type* castMod(uint8_t mod); - Type* addMod(uint8_t mod); - virtual Type* addStorageClass(StorageClass stc); - Type* pointerTo(); - Type* referenceTo(); - Type* arrayOf(); - Type* sarrayOf(dinteger_t dim); - bool hasDeprecatedAliasThis(); - Type* aliasthisOf(); - virtual Type* makeConst(); - virtual Type* makeImmutable(); - virtual Type* makeShared(); - virtual Type* makeSharedConst(); - virtual Type* makeWild(); - virtual Type* makeWildConst(); - virtual Type* makeSharedWild(); - virtual Type* makeSharedWildConst(); - virtual Type* makeMutable(); - virtual Dsymbol* toDsymbol(Scope* sc); - Type* toBasetype(); - virtual bool isBaseOf(Type* t, int32_t* poffset); - virtual MATCH implicitConvTo(Type* to); - virtual MATCH constConv(Type* to); - virtual uint8_t deduceWild(Type* t, bool isRef); - virtual Type* substWildTo(uint32_t mod); - Type* unqualify(uint32_t m); - virtual Type* toHeadMutable(); - virtual ClassDeclaration* isClassHandle(); - virtual structalign_t alignment(); - virtual Expression* defaultInitLiteral(const Loc& loc); - virtual bool isZeroInit(const Loc& loc); - Identifier* getTypeInfoIdent(); - virtual int32_t hasWild() const; - virtual bool hasPointers(); - virtual bool hasVoidInitPointers(); - virtual bool hasSystemFields(); - virtual bool hasInvariant(); - virtual Type* nextOf(); - Type* baseElemOf(); - uint32_t numberOfElems(const Loc& loc); - virtual bool needsDestruction(); - virtual bool needsCopyOrPostblit(); - virtual bool needsNested(); - virtual TypeBasic* isTypeBasic(); - TypeFunction* isPtrToFunction(); - TypeFunction* isFunction_Delegate_PtrToFunction(); - TypeError* isTypeError(); - TypeVector* isTypeVector(); - TypeSArray* isTypeSArray(); - TypeDArray* isTypeDArray(); - TypeAArray* isTypeAArray(); - TypePointer* isTypePointer(); - TypeReference* isTypeReference(); - TypeFunction* isTypeFunction(); - TypeDelegate* isTypeDelegate(); - TypeIdentifier* isTypeIdentifier(); - TypeInstance* isTypeInstance(); - TypeTypeof* isTypeTypeof(); - TypeReturn* isTypeReturn(); - TypeStruct* isTypeStruct(); - TypeEnum* isTypeEnum(); - TypeClass* isTypeClass(); - TypeTuple* isTypeTuple(); - TypeSlice* isTypeSlice(); - TypeNull* isTypeNull(); - TypeMixin* isTypeMixin(); - TypeTraits* isTypeTraits(); - TypeNoreturn* isTypeNoreturn(); - TypeTag* isTypeTag(); - void accept(Visitor* v) override; - TypeFunction* toTypeFunction(); +struct MangleOverride final +{ + Dsymbol* agg; + Identifier* id; + MangleOverride() : + agg(), + id() + { + } + MangleOverride(Dsymbol* agg, Identifier* id = nullptr) : + agg(agg), + id(id) + {} }; -enum class OwnedBy : uint8_t +typedef Array AliasDeclarations; + +typedef Array BaseClasses; + +typedef Array CaseStatements; + +typedef Array Catches; + +typedef Array ClassDeclarations; + +struct DesigInit final { - code = 0u, - ctfe = 1u, - cache = 2u, + Array* designatorList; + Initializer* initializer; + DesigInit() : + designatorList(), + initializer() + { + } + DesigInit(Array* designatorList, Initializer* initializer = nullptr) : + designatorList(designatorList), + initializer(initializer) + {} }; -enum class TOK : uint8_t +typedef Array DesigInits; + +struct Designator final { - reserved = 0u, - leftParenthesis = 1u, - rightParenthesis = 2u, - leftBracket = 3u, - rightBracket = 4u, - leftCurly = 5u, - rightCurly = 6u, - colon = 7u, - semicolon = 8u, - dotDotDot = 9u, - endOfFile = 10u, - cast_ = 11u, - null_ = 12u, - assert_ = 13u, - true_ = 14u, - false_ = 15u, - throw_ = 16u, - new_ = 17u, - delete_ = 18u, - variable = 19u, - slice = 20u, - version_ = 21u, - module_ = 22u, - dollar = 23u, - template_ = 24u, - typeof_ = 25u, - pragma_ = 26u, - typeid_ = 27u, - comment = 28u, - lessThan = 29u, - greaterThan = 30u, - lessOrEqual = 31u, - greaterOrEqual = 32u, - equal = 33u, - notEqual = 34u, - identity = 35u, - notIdentity = 36u, - is_ = 37u, - leftShift = 38u, - rightShift = 39u, - leftShiftAssign = 40u, - rightShiftAssign = 41u, - unsignedRightShift = 42u, - unsignedRightShiftAssign = 43u, - concatenateAssign = 44u, - add = 45u, - min = 46u, - addAssign = 47u, - minAssign = 48u, - mul = 49u, - div = 50u, - mod = 51u, - mulAssign = 52u, - divAssign = 53u, - modAssign = 54u, - and_ = 55u, - or_ = 56u, - xor_ = 57u, - andAssign = 58u, - orAssign = 59u, - xorAssign = 60u, - assign = 61u, - not_ = 62u, - tilde = 63u, - plusPlus = 64u, - minusMinus = 65u, - dot = 66u, - comma = 67u, - question = 68u, - andAnd = 69u, - orOr = 70u, - int32Literal = 71u, - uns32Literal = 72u, - int64Literal = 73u, - uns64Literal = 74u, - int128Literal = 75u, - uns128Literal = 76u, - float32Literal = 77u, - float64Literal = 78u, - float80Literal = 79u, - imaginary32Literal = 80u, - imaginary64Literal = 81u, - imaginary80Literal = 82u, - charLiteral = 83u, - wcharLiteral = 84u, - dcharLiteral = 85u, - identifier = 86u, - string_ = 87u, - hexadecimalString = 88u, - this_ = 89u, - super_ = 90u, - error = 91u, - void_ = 92u, - int8 = 93u, - uns8 = 94u, - int16 = 95u, - uns16 = 96u, - int32 = 97u, - uns32 = 98u, - int64 = 99u, - uns64 = 100u, - int128 = 101u, - uns128 = 102u, - float32 = 103u, - float64 = 104u, - float80 = 105u, - imaginary32 = 106u, - imaginary64 = 107u, - imaginary80 = 108u, - complex32 = 109u, - complex64 = 110u, - complex80 = 111u, - char_ = 112u, - wchar_ = 113u, - dchar_ = 114u, - bool_ = 115u, - struct_ = 116u, - class_ = 117u, - interface_ = 118u, - union_ = 119u, - enum_ = 120u, - import_ = 121u, - alias_ = 122u, - override_ = 123u, - delegate_ = 124u, - function_ = 125u, - mixin_ = 126u, - align_ = 127u, - extern_ = 128u, - private_ = 129u, - protected_ = 130u, - public_ = 131u, - export_ = 132u, - static_ = 133u, - final_ = 134u, - const_ = 135u, - abstract_ = 136u, - debug_ = 137u, - deprecated_ = 138u, - in_ = 139u, - out_ = 140u, - inout_ = 141u, - lazy_ = 142u, - auto_ = 143u, - package_ = 144u, - immutable_ = 145u, - if_ = 146u, - else_ = 147u, - while_ = 148u, - for_ = 149u, - do_ = 150u, - switch_ = 151u, - case_ = 152u, - default_ = 153u, - break_ = 154u, - continue_ = 155u, - with_ = 156u, - synchronized_ = 157u, - return_ = 158u, - goto_ = 159u, - try_ = 160u, - catch_ = 161u, - finally_ = 162u, - asm_ = 163u, - foreach_ = 164u, - foreach_reverse_ = 165u, - scope_ = 166u, - onScopeExit = 167u, - onScopeFailure = 168u, - onScopeSuccess = 169u, - invariant_ = 170u, - unittest_ = 171u, - argumentTypes = 172u, - ref_ = 173u, - macro_ = 174u, - parameters = 175u, - traits = 176u, - pure_ = 177u, - nothrow_ = 178u, - gshared = 179u, - line = 180u, - file = 181u, - fileFullPath = 182u, - moduleString = 183u, - functionString = 184u, - prettyFunction = 185u, - shared_ = 186u, - at = 187u, - pow = 188u, - powAssign = 189u, - goesTo = 190u, - vector = 191u, - pound = 192u, - arrow = 193u, - colonColon = 194u, - wchar_tLiteral = 195u, - endOfLine = 196u, - whitespace = 197u, - inline_ = 198u, - register_ = 199u, - restrict_ = 200u, - signed_ = 201u, - sizeof_ = 202u, - typedef_ = 203u, - unsigned_ = 204u, - volatile_ = 205u, - _Alignas_ = 206u, - _Alignof_ = 207u, - _Atomic_ = 208u, - _Bool_ = 209u, - _Complex_ = 210u, - _Generic_ = 211u, - _Imaginary_ = 212u, - _Noreturn_ = 213u, - _Static_assert_ = 214u, - _Thread_local_ = 215u, - _assert_ = 216u, - _import_ = 217u, - __cdecl_ = 218u, - __declspec_ = 219u, - __stdcall_ = 220u, - __thread_ = 221u, - __pragma_ = 222u, - __int128_ = 223u, - __attribute___ = 224u, + Expression* exp; + Identifier* ident; + Designator() : + exp(), + ident() + { + } }; -enum class MemorySet +typedef Array Designators; + +typedef Array Dsymbols; + +typedef Array DtorDeclarations; + +struct Ensure final { - none = 0, - blockAssign = 1, - referenceInit = 2, + Identifier* id; + Statement* ensure; + Ensure syntaxCopy(); + static Array* arraySyntaxCopy(Array* a); + Ensure() : + id(), + ensure() + { + } + Ensure(Identifier* id, Statement* ensure = nullptr) : + id(id), + ensure(ensure) + {} }; -template -class ParseTimeVisitor -{ -public: - virtual void visit(typename AST::Dsymbol ); - virtual void visit(typename AST::Parameter ); - virtual void visit(typename AST::Statement ); - virtual void visit(typename AST::Type ); - virtual void visit(typename AST::Expression ); - virtual void visit(typename AST::TemplateParameter ); - virtual void visit(typename AST::Condition ); - virtual void visit(typename AST::Initializer ); - virtual void visit(typename AST::AliasThis s); - virtual void visit(typename AST::Declaration s); - virtual void visit(typename AST::ScopeDsymbol s); - virtual void visit(typename AST::Import s); - virtual void visit(typename AST::AttribDeclaration s); - virtual void visit(typename AST::StaticAssert s); - virtual void visit(typename AST::DebugSymbol s); - virtual void visit(typename AST::VersionSymbol s); - virtual void visit(typename AST::AliasAssign s); - virtual void visit(typename AST::Package s); - virtual void visit(typename AST::EnumDeclaration s); - virtual void visit(typename AST::AggregateDeclaration s); - virtual void visit(typename AST::TemplateDeclaration s); - virtual void visit(typename AST::TemplateInstance s); - virtual void visit(typename AST::Nspace s); - virtual void visit(typename AST::VarDeclaration s); - virtual void visit(typename AST::FuncDeclaration s); - virtual void visit(typename AST::AliasDeclaration s); - virtual void visit(typename AST::TupleDeclaration s); - virtual void visit(typename AST::FuncLiteralDeclaration s); - virtual void visit(typename AST::PostBlitDeclaration s); - virtual void visit(typename AST::CtorDeclaration s); - virtual void visit(typename AST::DtorDeclaration s); - virtual void visit(typename AST::InvariantDeclaration s); - virtual void visit(typename AST::UnitTestDeclaration s); - virtual void visit(typename AST::NewDeclaration s); - virtual void visit(typename AST::StaticCtorDeclaration s); - virtual void visit(typename AST::StaticDtorDeclaration s); - virtual void visit(typename AST::SharedStaticCtorDeclaration s); - virtual void visit(typename AST::SharedStaticDtorDeclaration s); - virtual void visit(typename AST::MixinDeclaration s); - virtual void visit(typename AST::UserAttributeDeclaration s); - virtual void visit(typename AST::LinkDeclaration s); - virtual void visit(typename AST::AnonDeclaration s); - virtual void visit(typename AST::AlignDeclaration s); - virtual void visit(typename AST::CPPMangleDeclaration s); - virtual void visit(typename AST::CPPNamespaceDeclaration s); - virtual void visit(typename AST::VisibilityDeclaration s); - virtual void visit(typename AST::PragmaDeclaration s); - virtual void visit(typename AST::StorageClassDeclaration s); - virtual void visit(typename AST::ConditionalDeclaration s); - virtual void visit(typename AST::StaticForeachDeclaration s); - virtual void visit(typename AST::DeprecatedDeclaration s); - virtual void visit(typename AST::StaticIfDeclaration s); - virtual void visit(typename AST::EnumMember s); - virtual void visit(typename AST::Module s); - virtual void visit(typename AST::StructDeclaration s); - virtual void visit(typename AST::UnionDeclaration s); - virtual void visit(typename AST::ClassDeclaration s); - virtual void visit(typename AST::InterfaceDeclaration s); - virtual void visit(typename AST::TemplateMixin s); - virtual void visit(typename AST::BitFieldDeclaration s); - virtual void visit(typename AST::ImportStatement s); - virtual void visit(typename AST::ScopeStatement s); - virtual void visit(typename AST::ReturnStatement s); - virtual void visit(typename AST::LabelStatement s); - virtual void visit(typename AST::StaticAssertStatement s); - virtual void visit(typename AST::MixinStatement s); - virtual void visit(typename AST::WhileStatement s); - virtual void visit(typename AST::ForStatement s); - virtual void visit(typename AST::DoStatement s); - virtual void visit(typename AST::ForeachRangeStatement s); - virtual void visit(typename AST::ForeachStatement s); - virtual void visit(typename AST::IfStatement s); - virtual void visit(typename AST::ScopeGuardStatement s); - virtual void visit(typename AST::ConditionalStatement s); - virtual void visit(typename AST::StaticForeachStatement s); - virtual void visit(typename AST::PragmaStatement s); - virtual void visit(typename AST::SwitchStatement s); - virtual void visit(typename AST::CaseRangeStatement s); - virtual void visit(typename AST::CaseStatement s); - virtual void visit(typename AST::DefaultStatement s); - virtual void visit(typename AST::BreakStatement s); - virtual void visit(typename AST::ContinueStatement s); - virtual void visit(typename AST::GotoDefaultStatement s); - virtual void visit(typename AST::GotoCaseStatement s); - virtual void visit(typename AST::GotoStatement s); - virtual void visit(typename AST::SynchronizedStatement s); - virtual void visit(typename AST::WithStatement s); - virtual void visit(typename AST::TryCatchStatement s); - virtual void visit(typename AST::TryFinallyStatement s); - virtual void visit(typename AST::ThrowStatement s); - virtual void visit(typename AST::AsmStatement s); - virtual void visit(typename AST::ExpStatement s); - virtual void visit(typename AST::CompoundStatement s); - virtual void visit(typename AST::CompoundDeclarationStatement s); - virtual void visit(typename AST::CompoundAsmStatement s); - virtual void visit(typename AST::InlineAsmStatement s); - virtual void visit(typename AST::GccAsmStatement s); - virtual void visit(typename AST::TypeBasic t); - virtual void visit(typename AST::TypeError t); - virtual void visit(typename AST::TypeNull t); - virtual void visit(typename AST::TypeNoreturn t); - virtual void visit(typename AST::TypeVector t); - virtual void visit(typename AST::TypeEnum t); - virtual void visit(typename AST::TypeTuple t); - virtual void visit(typename AST::TypeClass t); - virtual void visit(typename AST::TypeStruct t); - virtual void visit(typename AST::TypeNext t); - virtual void visit(typename AST::TypeQualified t); - virtual void visit(typename AST::TypeTraits t); - virtual void visit(typename AST::TypeMixin t); - virtual void visit(typename AST::TypeTag t); - virtual void visit(typename AST::TypeReference t); - virtual void visit(typename AST::TypeSlice t); - virtual void visit(typename AST::TypeDelegate t); - virtual void visit(typename AST::TypePointer t); - virtual void visit(typename AST::TypeFunction t); - virtual void visit(typename AST::TypeArray t); - virtual void visit(typename AST::TypeDArray t); - virtual void visit(typename AST::TypeAArray t); - virtual void visit(typename AST::TypeSArray t); - virtual void visit(typename AST::TypeIdentifier t); - virtual void visit(typename AST::TypeReturn t); - virtual void visit(typename AST::TypeTypeof t); - virtual void visit(typename AST::TypeInstance t); - virtual void visit(typename AST::DeclarationExp e); - virtual void visit(typename AST::IntegerExp e); - virtual void visit(typename AST::NewAnonClassExp e); - virtual void visit(typename AST::IsExp e); - virtual void visit(typename AST::RealExp e); - virtual void visit(typename AST::NullExp e); - virtual void visit(typename AST::TypeidExp e); - virtual void visit(typename AST::TraitsExp e); - virtual void visit(typename AST::StringExp e); - virtual void visit(typename AST::NewExp e); - virtual void visit(typename AST::AssocArrayLiteralExp e); - virtual void visit(typename AST::ArrayLiteralExp e); - virtual void visit(typename AST::MixinExp e); - virtual void visit(typename AST::FuncExp e); - virtual void visit(typename AST::IntervalExp e); - virtual void visit(typename AST::TypeExp e); - virtual void visit(typename AST::ScopeExp e); - virtual void visit(typename AST::IdentifierExp e); - virtual void visit(typename AST::UnaExp e); - virtual void visit(typename AST::DefaultInitExp e); - virtual void visit(typename AST::BinExp e); - virtual void visit(typename AST::DsymbolExp e); - virtual void visit(typename AST::TemplateExp e); - virtual void visit(typename AST::SymbolExp e); - virtual void visit(typename AST::TupleExp e); - virtual void visit(typename AST::ThisExp e); - virtual void visit(typename AST::GenericExp e); - virtual void visit(typename AST::VarExp e); - virtual void visit(typename AST::DollarExp e); - virtual void visit(typename AST::SuperExp e); - virtual void visit(typename AST::AddrExp e); - virtual void visit(typename AST::PreExp e); - virtual void visit(typename AST::PtrExp e); - virtual void visit(typename AST::NegExp e); - virtual void visit(typename AST::UAddExp e); - virtual void visit(typename AST::NotExp e); - virtual void visit(typename AST::ComExp e); - virtual void visit(typename AST::DeleteExp e); - virtual void visit(typename AST::CastExp e); - virtual void visit(typename AST::CallExp e); - virtual void visit(typename AST::DotIdExp e); - virtual void visit(typename AST::AssertExp e); - virtual void visit(typename AST::ThrowExp e); - virtual void visit(typename AST::ImportExp e); - virtual void visit(typename AST::DotTemplateInstanceExp e); - virtual void visit(typename AST::ArrayExp e); - virtual void visit(typename AST::FuncInitExp e); - virtual void visit(typename AST::PrettyFuncInitExp e); - virtual void visit(typename AST::FileInitExp e); - virtual void visit(typename AST::LineInitExp e); - virtual void visit(typename AST::ModuleInitExp e); - virtual void visit(typename AST::CommaExp e); - virtual void visit(typename AST::PostExp e); - virtual void visit(typename AST::PowExp e); - virtual void visit(typename AST::MulExp e); - virtual void visit(typename AST::DivExp e); - virtual void visit(typename AST::ModExp e); - virtual void visit(typename AST::AddExp e); - virtual void visit(typename AST::MinExp e); - virtual void visit(typename AST::CatExp e); - virtual void visit(typename AST::ShlExp e); - virtual void visit(typename AST::ShrExp e); - virtual void visit(typename AST::UshrExp e); - virtual void visit(typename AST::EqualExp e); - virtual void visit(typename AST::InExp e); - virtual void visit(typename AST::IdentityExp e); - virtual void visit(typename AST::CmpExp e); - virtual void visit(typename AST::AndExp e); - virtual void visit(typename AST::XorExp e); - virtual void visit(typename AST::OrExp e); - virtual void visit(typename AST::LogicalExp e); - virtual void visit(typename AST::CondExp e); - virtual void visit(typename AST::AssignExp e); - virtual void visit(typename AST::BinAssignExp e); - virtual void visit(typename AST::AddAssignExp e); - virtual void visit(typename AST::MinAssignExp e); - virtual void visit(typename AST::MulAssignExp e); - virtual void visit(typename AST::DivAssignExp e); - virtual void visit(typename AST::ModAssignExp e); - virtual void visit(typename AST::PowAssignExp e); - virtual void visit(typename AST::AndAssignExp e); - virtual void visit(typename AST::OrAssignExp e); - virtual void visit(typename AST::XorAssignExp e); - virtual void visit(typename AST::ShlAssignExp e); - virtual void visit(typename AST::ShrAssignExp e); - virtual void visit(typename AST::UshrAssignExp e); - virtual void visit(typename AST::CatAssignExp e); - virtual void visit(typename AST::CatElemAssignExp e); - virtual void visit(typename AST::CatDcharAssignExp e); - virtual void visit(typename AST::TemplateAliasParameter tp); - virtual void visit(typename AST::TemplateTypeParameter tp); - virtual void visit(typename AST::TemplateTupleParameter tp); - virtual void visit(typename AST::TemplateValueParameter tp); - virtual void visit(typename AST::TemplateThisParameter tp); - virtual void visit(typename AST::StaticIfCondition c); - virtual void visit(typename AST::DVCondition c); - virtual void visit(typename AST::DebugCondition c); - virtual void visit(typename AST::VersionCondition c); - virtual void visit(typename AST::ExpInitializer i); - virtual void visit(typename AST::StructInitializer i); - virtual void visit(typename AST::ArrayInitializer i); - virtual void visit(typename AST::VoidInitializer i); - virtual void visit(typename AST::CInitializer i); -}; +typedef Array Ensures; -struct MangleOverride final -{ - Dsymbol* agg; - Identifier* id; - MangleOverride() : - agg(), - id() - { - } - MangleOverride(Dsymbol* agg, Identifier* id = nullptr) : - agg(agg), - id(id) - {} -}; +typedef Array Expressions; -typedef Array AliasDeclarations; +typedef Array FuncDeclarations; -typedef Array BaseClasses; +typedef Array GotoCaseStatements; -typedef Array CaseStatements; +typedef Array GotoStatements; -typedef Array Catches; +typedef Array Identifiers; -typedef Array ClassDeclarations; +typedef Array Initializers; -struct DesigInit final -{ - Array* designatorList; - Initializer* initializer; - DesigInit() : - designatorList(), - initializer() - { - } - DesigInit(Array* designatorList, Initializer* initializer = nullptr) : - designatorList(designatorList), - initializer(initializer) - {} -}; +typedef Array Modules; -typedef Array DesigInits; +typedef Array Objects; -struct Designator final -{ - Expression* exp; - Identifier* ident; - Designator() : - exp(), - ident() - { - } -}; +typedef Array Parameters; -typedef Array Designators; +typedef Array ReturnStatements; -typedef Array Dsymbols; +typedef Array ScopeStatements; -typedef Array DtorDeclarations; - -struct Ensure final -{ - Identifier* id; - Statement* ensure; - Ensure syntaxCopy(); - static Array* arraySyntaxCopy(Array* a); - Ensure() : - id(), - ensure() - { - } - Ensure(Identifier* id, Statement* ensure = nullptr) : - id(id), - ensure(ensure) - {} -}; - -typedef Array Ensures; - -typedef Array Expressions; - -typedef Array FuncDeclarations; - -typedef Array GotoCaseStatements; - -typedef Array GotoStatements; - -typedef Array Identifiers; - -typedef Array Initializers; - -typedef Array Modules; - -typedef Array Objects; - -typedef Array Parameters; - -typedef Array ReturnStatements; - -typedef Array ScopeStatements; - -typedef Array SharedStaticDtorDeclarations; +typedef Array SharedStaticDtorDeclarations; typedef Array Statements; @@ -2216,21 +1373,150 @@ struct FieldState final {} }; -enum +enum class SearchOpt : uint32_t { - IgnoreNone = 0, - IgnorePrivateImports = 1, - IgnoreErrors = 2, - IgnoreAmbiguous = 4, - SearchLocalsOnly = 8, - SearchImportsOnly = 16, - SearchUnqualifiedModule = 32, - IgnoreSymbolVisibility = 128, - TagNameSpace = 256, + all = 0u, + ignorePrivateImports = 1u, + ignoreErrors = 2u, + ignoreAmbiguous = 4u, + localsOnly = 8u, + importsOnly = 16u, + unqualifiedModule = 32u, + tagNameSpace = 64u, + ignoreVisibility = 128u, }; +typedef uint32_t SearchOptFlags; + enum : int32_t { IDX_NOTFOUND = 305419896 }; +class TemplateParameter : public ASTNode +{ +public: + Loc loc; + Identifier* ident; + bool dependent; + virtual TemplateTypeParameter* isTemplateTypeParameter(); + virtual TemplateValueParameter* isTemplateValueParameter(); + virtual TemplateAliasParameter* isTemplateAliasParameter(); + virtual TemplateThisParameter* isTemplateThisParameter(); + virtual TemplateTupleParameter* isTemplateTupleParameter(); + virtual TemplateParameter* syntaxCopy() = 0; + virtual bool declareParameter(Scope* sc) = 0; + virtual void print(RootObject* oarg, RootObject* oded) = 0; + virtual RootObject* specialization() = 0; + virtual RootObject* defaultArg(const Loc& instLoc, Scope* sc) = 0; + virtual bool hasDefaultArg() = 0; + const char* toChars() const override; + DYNCAST dyncast() const override; + virtual RootObject* dummyArg() = 0; + void accept(Visitor* v) override; +}; + +class TemplateAliasParameter final : public TemplateParameter +{ +public: + Type* specType; + RootObject* specAlias; + RootObject* defaultAlias; + TemplateAliasParameter* isTemplateAliasParameter() override; + TemplateAliasParameter* syntaxCopy() override; + bool declareParameter(Scope* sc) override; + void print(RootObject* oarg, RootObject* oded) override; + RootObject* specialization() override; + RootObject* defaultArg(const Loc& instLoc, Scope* sc) override; + bool hasDefaultArg() override; + RootObject* dummyArg() override; + void accept(Visitor* v) override; +}; + +class TemplateDeclaration final : public ScopeDsymbol +{ +public: + Array* parameters; + Array* origParameters; + Expression* constraint; + void* instances; + TemplateDeclaration* overnext; + TemplateDeclaration* overroot; + FuncDeclaration* funcroot; + Dsymbol* onemember; + bool literal; + bool ismixin; + bool isstatic; + bool isTrivialAliasSeq; + bool isTrivialAlias; + bool deprecated_; + Visibility visibility; + TemplatePrevious* previous; +private: + Expression* lastConstraint; + Array lastConstraintNegs; + Array* lastConstraintTiargs; +public: + TemplateDeclaration* syntaxCopy(Dsymbol* __param_0_) override; + bool overloadInsert(Dsymbol* s) override; + bool hasStaticCtorOrDtor() override; + const char* kind() const override; + const char* toChars() const override; + const char* toCharsNoConstraints() const; + const char* toCharsMaybeConstraints(bool includeConstraints) const; + Visibility visible() override; + const char* getConstraintEvalError(const char*& tip); + Scope* scopeForTemplateParameters(TemplateInstance* ti, Scope* sc); + TemplateDeclaration* isTemplateDeclaration() override; + bool isDeprecated() const override; + bool isOverloadable() const override; + void accept(Visitor* v) override; +}; + +class TemplateInstance : public ScopeDsymbol +{ +public: + Identifier* name; + Array* tiargs; + Array tdtypes; + Array importedModules; + Dsymbol* tempdecl; + Dsymbol* enclosing; + Dsymbol* aliasdecl; + TemplateInstance* inst; + ScopeDsymbol* argsym; + size_t hash; + Array* fargs; + Array* deferred; + Module* memberOf; + TemplateInstance* tinst; + TemplateInstance* tnext; + Module* minst; +private: + uint16_t _nest; +public: + uint8_t inuse; +private: + enum class Flag : uint32_t + { + semantictiargsdone = 32768u, + havetempdecl = 16384u, + gagged = 8192u, + available = 8191u, + }; + +public: + TemplateInstance* syntaxCopy(Dsymbol* s) override; + Dsymbol* toAlias() final override; + const char* kind() const override; + bool oneMember(Dsymbol*& ps, Identifier* ident) override; + const char* toChars() const override; + const char* toPrettyCharsHelper() final override; + Identifier* getIdent() final override; + bool equalsx(TemplateInstance* ti); + bool isDiscardable(); + bool needsCodegen(); + TemplateInstance* isTemplateInstance() final override; + void accept(Visitor* v) override; +}; + struct TemplateInstanceBox final { TemplateInstance* ti; @@ -2240,6 +1526,19 @@ struct TemplateInstanceBox final } }; +class TemplateMixin final : public TemplateInstance +{ +public: + TypeQualified* tqual; + TemplateInstance* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + bool oneMember(Dsymbol*& ps, Identifier* ident) override; + bool hasPointers() override; + const char* toChars() const override; + TemplateMixin* isTemplateMixin() override; + void accept(Visitor* v) override; +}; + struct TemplatePrevious final { TemplatePrevious* prev; @@ -2276,6193 +1575,6864 @@ struct TemplateStats final {} }; -struct ArgumentList final +class TemplateTypeParameter : public TemplateParameter { - Array* arguments; - Array* names; - ArgumentList() : - arguments(), - names() - { - } - ArgumentList(Array* arguments, Array* names = nullptr) : - arguments(arguments), - names(names) - {} +public: + Type* specType; + Type* defaultType; + TemplateTypeParameter* isTemplateTypeParameter() final override; + TemplateTypeParameter* syntaxCopy() override; + bool declareParameter(Scope* sc) final override; + void print(RootObject* oarg, RootObject* oded) final override; + RootObject* specialization() final override; + RootObject* defaultArg(const Loc& instLoc, Scope* sc) final override; + bool hasDefaultArg() final override; + RootObject* dummyArg() final override; + void accept(Visitor* v) override; }; -enum : bool { LOGSEMANTIC = false }; +class TemplateThisParameter final : public TemplateTypeParameter +{ +public: + TemplateThisParameter* isTemplateThisParameter() override; + TemplateThisParameter* syntaxCopy() override; + void accept(Visitor* v) override; +}; -enum class Modifiable +class TemplateTupleParameter final : public TemplateParameter { - no = 0, - yes = 1, - initialization = 2, +public: + TemplateTupleParameter* isTemplateTupleParameter() override; + TemplateTupleParameter* syntaxCopy() override; + bool declareParameter(Scope* sc) override; + void print(RootObject* oarg, RootObject* oded) override; + RootObject* specialization() override; + RootObject* defaultArg(const Loc& instLoc, Scope* sc) override; + bool hasDefaultArg() override; + RootObject* dummyArg() override; + void accept(Visitor* v) override; }; -enum class ModifyFlags +class TemplateValueParameter final : public TemplateParameter { - none = 0, - noError = 1, - fieldAssign = 2, +public: + Type* valType; + Expression* specValue; + Expression* defaultValue; + TemplateValueParameter* isTemplateValueParameter() override; + TemplateValueParameter* syntaxCopy() override; + bool declareParameter(Scope* sc) override; + void print(RootObject* oarg, RootObject* oded) override; + RootObject* specialization() override; + RootObject* defaultArg(const Loc& instLoc, Scope* sc) override; + bool hasDefaultArg() override; + RootObject* dummyArg() override; + void accept(Visitor* v) override; }; -struct UnionExp final +class Tuple final : public RootObject { - #pragma pack(push, 8) -private: - union _AnonStruct_u - { - char exp[29LLU]; - char integerexp[40LLU]; - char errorexp[29LLU]; - char realexp[48LLU]; - char complexexp[64LLU]; - char symoffexp[64LLU]; - char stringexp[51LLU]; - char arrayliteralexp[48LLU]; - char assocarrayliteralexp[56LLU]; - char structliteralexp[76LLU]; - char compoundliteralexp[40LLU]; - char nullexp[29LLU]; - char dotvarexp[49LLU]; - char addrexp[40LLU]; - char indexexp[74LLU]; - char sliceexp[65LLU]; - char vectorexp[53LLU]; - }; - #pragma pack(pop) - - // Ignoring var u alignment 8 - _AnonStruct_u u; public: - UnionExp() : - u() - { - } -}; - -enum : int32_t { WANTexpand = 1 }; - -enum : int32_t { WANTvalue = 0 }; - -enum : int32_t { stageApply = 8 }; - -enum : int32_t { stageInlineScan = 16 }; - -enum : int32_t { stageOptimize = 4 }; - -enum : int32_t { stageScrub = 1 }; - -enum : int32_t { stageSearchPointers = 2 }; - -enum : int32_t { stageToCBuffer = 32 }; - -struct AttributeViolation final -{ - Loc loc; - const char* fmtStr; - RootObject* arg0; - RootObject* arg1; - RootObject* arg2; - AttributeViolation() : - loc(Loc(0u, 0u, 0u)), - fmtStr(nullptr), - arg0(nullptr), - arg1(nullptr), - arg2(nullptr) - { - } - AttributeViolation(Loc loc, const char* fmtStr = nullptr, RootObject* arg0 = nullptr, RootObject* arg1 = nullptr, RootObject* arg2 = nullptr) : - loc(loc), - fmtStr(fmtStr), - arg0(arg0), - arg1(arg1), - arg2(arg2) - {} -}; - -enum class ILS : uint8_t -{ - uninitialized = 0u, - no = 1u, - yes = 2u, -}; - -enum class PINLINE : uint8_t -{ - default_ = 0u, - never = 1u, - always = 2u, -}; - -struct ObjcFuncDeclaration final -{ - ObjcSelector* selector; - VarDeclaration* selectorParameter; - bool isOptional; - ObjcFuncDeclaration() : - selector(), - selectorParameter(), - isOptional() - { - } - ObjcFuncDeclaration(ObjcSelector* selector, VarDeclaration* selectorParameter = nullptr, bool isOptional = false) : - selector(selector), - selectorParameter(selectorParameter), - isOptional(isOptional) - {} + Array objects; + DYNCAST dyncast() const override; + const char* toChars() const override; }; -enum class PURE : uint8_t +enum class TY : uint8_t { - impure = 0u, - fwdref = 1u, - weak = 2u, - const_ = 3u, + Tarray = 0u, + Tsarray = 1u, + Taarray = 2u, + Tpointer = 3u, + Treference = 4u, + Tfunction = 5u, + Tident = 6u, + Tclass = 7u, + Tstruct = 8u, + Tenum = 9u, + Tdelegate = 10u, + Tnone = 11u, + Tvoid = 12u, + Tint8 = 13u, + Tuns8 = 14u, + Tint16 = 15u, + Tuns16 = 16u, + Tint32 = 17u, + Tuns32 = 18u, + Tint64 = 19u, + Tuns64 = 20u, + Tfloat32 = 21u, + Tfloat64 = 22u, + Tfloat80 = 23u, + Timaginary32 = 24u, + Timaginary64 = 25u, + Timaginary80 = 26u, + Tcomplex32 = 27u, + Tcomplex64 = 28u, + Tcomplex80 = 29u, + Tbool = 30u, + Tchar = 31u, + Twchar = 32u, + Tdchar = 33u, + Terror = 34u, + Tinstance = 35u, + Ttypeof = 36u, + Ttuple = 37u, + Tslice = 38u, + Treturn = 39u, + Tnull = 40u, + Tvector = 41u, + Tint128 = 42u, + Tuns128 = 43u, + Ttraits = 44u, + Tmixin = 45u, + Tnoreturn = 46u, + Ttag = 47u, }; -enum class VarArg : uint8_t -{ - none = 0u, - variadic = 1u, - typesafe = 2u, - KRvariadic = 3u, -}; +typedef uint64_t dinteger_t; -struct ParameterList final +class Type : public ASTNode { - Array* parameters; - StorageClass stc; - VarArg varargs; - bool hasIdentifierList; - ParameterList(Array* parameters, VarArg varargs = (VarArg)0u, StorageClass stc = 0); - size_t length(); - Parameter* opIndex(size_t i); - ParameterList() : - parameters(), - stc(), - varargs((VarArg)0u), - hasIdentifierList() +public: + TY ty; + uint8_t mod; + char* deco; + struct Mcache final { - } -}; + Type* cto; + Type* ito; + Type* sto; + Type* scto; + Type* wto; + Type* wcto; + Type* swto; + Type* swcto; + Mcache() : + cto(), + ito(), + sto(), + scto(), + wto(), + wcto(), + swto(), + swcto() + { + } + Mcache(Type* cto, Type* ito = nullptr, Type* sto = nullptr, Type* scto = nullptr, Type* wto = nullptr, Type* wcto = nullptr, Type* swto = nullptr, Type* swcto = nullptr) : + cto(cto), + ito(ito), + sto(sto), + scto(scto), + wto(wto), + wcto(wcto), + swto(swto), + swcto(swcto) + {} + }; -class FuncDeclaration : public Declaration -{ -public: - Statement* fbody; - Array foverrides; private: - ContractInfo* contracts; + Mcache* mcache; public: - const char* mangleString; - VarDeclaration* vresult; - LabelDsymbol* returnLabel; - void* isTypeIsolatedCache; - DsymbolTable* localsymtab; - VarDeclaration* vthis; - VarDeclaration* v_arguments; - VarDeclaration* v_argptr; - Array* parameters; - DsymbolTable* labtab; - Dsymbol* overnext; - FuncDeclaration* overnext0; - Loc endloc; - int32_t vtblIndex; - ILS inlineStatusStmt; - ILS inlineStatusExp; - PINLINE inlining; - int32_t inlineNest; - ForeachStatement* fes; - BaseClass* interfaceVirtual; - Type* tintro; - StorageClass storage_class2; - int32_t hasReturnExp; - VarDeclaration* nrvo_var; - Symbol* shidden; - Array* returns; - Array* gotos; - Array* alignSectionVars; - Symbol* salignSection; - BUILTIN builtin; - int32_t tookAddressOf; - bool requiresClosure; - Array closureVars; - Array outerVars; - Array siblingCallers; - Array* inlinedNestedCallees; - AttributeViolation* safetyViolation; - AttributeViolation* nogcViolation; - AttributeViolation* pureViolation; - AttributeViolation* nothrowViolation; - bool purityInprocess() const; - bool purityInprocess(bool v); - bool safetyInprocess() const; - bool safetyInprocess(bool v); - bool nothrowInprocess() const; - bool nothrowInprocess(bool v); - bool nogcInprocess() const; - bool nogcInprocess(bool v); - bool returnInprocess() const; - bool returnInprocess(bool v); - bool inlineScanned() const; - bool inlineScanned(bool v); - bool inferScope() const; - bool inferScope(bool v); - bool hasCatches() const; - bool hasCatches(bool v); - bool skipCodegen() const; - bool skipCodegen(bool v); - bool printf() const; - bool printf(bool v); - bool scanf() const; - bool scanf(bool v); - bool noreturn() const; - bool noreturn(bool v); - bool isNRVO() const; - bool isNRVO(bool v); + Type* pto; + Type* rto; + Type* arrayof; + TypeInfoDeclaration* vtinfo; + TYPE* ctype; + static Type* tvoid; + static Type* tint8; + static Type* tuns8; + static Type* tint16; + static Type* tuns16; + static Type* tint32; + static Type* tuns32; + static Type* tint64; + static Type* tuns64; + static Type* tint128; + static Type* tuns128; + static Type* tfloat32; + static Type* tfloat64; + static Type* tfloat80; + static Type* timaginary32; + static Type* timaginary64; + static Type* timaginary80; + static Type* tcomplex32; + static Type* tcomplex64; + static Type* tcomplex80; + static Type* tbool; + static Type* tchar; + static Type* twchar; + static Type* tdchar; + static Type* tshiftcnt; + static Type* tvoidptr; + static Type* tstring; + static Type* twstring; + static Type* tdstring; + static Type* terror; + static Type* tnull; + static Type* tnoreturn; + static Type* tsize_t; + static Type* tptrdiff_t; + static Type* thash_t; + static ClassDeclaration* dtypeinfo; + static ClassDeclaration* typeinfoclass; + static ClassDeclaration* typeinfointerface; + static ClassDeclaration* typeinfostruct; + static ClassDeclaration* typeinfopointer; + static ClassDeclaration* typeinfoarray; + static ClassDeclaration* typeinfostaticarray; + static ClassDeclaration* typeinfoassociativearray; + static ClassDeclaration* typeinfovector; + static ClassDeclaration* typeinfoenum; + static ClassDeclaration* typeinfofunction; + static ClassDeclaration* typeinfodelegate; + static ClassDeclaration* typeinfotypelist; + static ClassDeclaration* typeinfoconst; + static ClassDeclaration* typeinfoinvariant; + static ClassDeclaration* typeinfoshared; + static ClassDeclaration* typeinfowild; + static TemplateDeclaration* rtinfo; + static Type* basic[48LLU]; + virtual const char* kind() const; + Type* copy() const; + virtual Type* syntaxCopy(); + bool equals(const RootObject* const o) const override; + bool equivalent(Type* t); + DYNCAST dyncast() const final override; + size_t getUniqueID() const; + const char* toChars() const final override; + char* toPrettyChars(bool QualifyTypes = false); + static void _init(); + static void deinitialize(); + uinteger_t size(); + virtual uinteger_t size(const Loc& loc); + virtual uint32_t alignsize(); + Type* trySemantic(const Loc& loc, Scope* sc); + Type* merge2(); + void modToBuffer(OutBuffer& buf) const; + char* modToChars() const; + virtual bool isintegral(); + virtual bool isfloating(); + virtual bool isreal(); + virtual bool isimaginary(); + virtual bool iscomplex(); + virtual bool isscalar(); + virtual bool isunsigned(); + virtual bool isscope(); + virtual bool isString(); + virtual bool isAssignable(); + virtual bool isBoolean(); + bool isConst() const; + bool isImmutable() const; + bool isMutable() const; + bool isShared() const; + bool isSharedConst() const; + bool isWild() const; + bool isWildConst() const; + bool isSharedWild() const; bool isNaked() const; - bool isNaked(bool v); - bool isGenerated() const; - bool isGenerated(bool v); - bool isIntroducing() const; - bool isIntroducing(bool v); - bool hasSemantic3Errors() const; - bool hasSemantic3Errors(bool v); - bool hasNoEH() const; - bool hasNoEH(bool v); - bool inferRetType() const; - bool inferRetType(bool v); - bool hasDualContext() const; - bool hasDualContext(bool v); - bool hasAlwaysInlines() const; - bool hasAlwaysInlines(bool v); - bool isCrtCtor() const; - bool isCrtCtor(bool v); - bool isCrtDtor() const; - bool isCrtDtor(bool v); - bool hasEscapingSiblings() const; - bool hasEscapingSiblings(bool v); - bool computedEscapingSiblings() const; - bool computedEscapingSiblings(bool v); - bool dllImport() const; - bool dllImport(bool v); - bool dllExport() const; - bool dllExport(bool v); -private: - uint32_t bitFields; + Type* nullAttributes() const; + Type* constOf(); + Type* immutableOf(); + Type* mutableOf(); + Type* sharedOf(); + Type* sharedConstOf(); + Type* unSharedOf(); + Type* wildOf(); + Type* wildConstOf(); + Type* sharedWildOf(); + Type* sharedWildConstOf(); + Type* castMod(uint8_t mod); + Type* addMod(uint8_t mod); + virtual Type* addStorageClass(StorageClass stc); + Type* pointerTo(); + Type* referenceTo(); + Type* arrayOf(); + Type* sarrayOf(dinteger_t dim); + bool hasDeprecatedAliasThis(); + Type* aliasthisOf(); + virtual Type* makeConst(); + virtual Type* makeImmutable(); + virtual Type* makeShared(); + virtual Type* makeSharedConst(); + virtual Type* makeWild(); + virtual Type* makeWildConst(); + virtual Type* makeSharedWild(); + virtual Type* makeSharedWildConst(); + virtual Type* makeMutable(); + virtual Dsymbol* toDsymbol(Scope* sc); + Type* toBasetype(); + virtual bool isBaseOf(Type* t, int32_t* poffset); + virtual MATCH implicitConvTo(Type* to); + virtual MATCH constConv(Type* to); + virtual uint8_t deduceWild(Type* t, bool isRef); + virtual Type* substWildTo(uint32_t mod); + Type* unqualify(uint32_t m); + virtual Type* toHeadMutable(); + virtual ClassDeclaration* isClassHandle(); + virtual structalign_t alignment(); + virtual Expression* defaultInitLiteral(const Loc& loc); + virtual bool isZeroInit(const Loc& loc); + Identifier* getTypeInfoIdent(); + virtual int32_t hasWild() const; + virtual bool hasPointers(); + virtual bool hasVoidInitPointers(); + virtual bool hasSystemFields(); + virtual bool hasInvariant(); + virtual Type* nextOf(); + Type* baseElemOf(); + uint32_t numberOfElems(const Loc& loc); + virtual bool needsDestruction(); + virtual bool needsCopyOrPostblit(); + virtual bool needsNested(); + virtual TypeBasic* isTypeBasic(); + TypeFunction* isPtrToFunction(); + TypeFunction* isFunction_Delegate_PtrToFunction(); + TypeError* isTypeError(); + TypeVector* isTypeVector(); + TypeSArray* isTypeSArray(); + TypeDArray* isTypeDArray(); + TypeAArray* isTypeAArray(); + TypePointer* isTypePointer(); + TypeReference* isTypeReference(); + TypeFunction* isTypeFunction(); + TypeDelegate* isTypeDelegate(); + TypeIdentifier* isTypeIdentifier(); + TypeInstance* isTypeInstance(); + TypeTypeof* isTypeTypeof(); + TypeReturn* isTypeReturn(); + TypeStruct* isTypeStruct(); + TypeEnum* isTypeEnum(); + TypeClass* isTypeClass(); + TypeTuple* isTypeTuple(); + TypeSlice* isTypeSlice(); + TypeNull* isTypeNull(); + TypeMixin* isTypeMixin(); + TypeTraits* isTypeTraits(); + TypeNoreturn* isTypeNoreturn(); + TypeTag* isTypeTag(); + void accept(Visitor* v) override; + TypeFunction* toTypeFunction(); +}; + +class TypeDeduced final : public Type +{ public: - ObjcFuncDeclaration objc; - static FuncDeclaration* create(const Loc& loc, const Loc& endloc, Identifier* id, StorageClass storage_class, Type* type, bool noreturn = false); - Array* frequires(); - Array* fensures(); - Statement* frequire(); - Statement* fensure(); - FuncDeclaration* fdrequire(); - FuncDeclaration* fdensure(); - Array* fdrequireParams(); - Array* fdensureParams(); - Array* frequires(Array* param); - Array* fensures(Array* param); - Statement* frequire(Statement* param); - Statement* fensure(Statement* param); - FuncDeclaration* fdrequire(FuncDeclaration* param); - FuncDeclaration* fdensure(FuncDeclaration* param); - Array* fdrequireParams(Array* param); - Array* fdensureParams(Array* param); - FuncDeclaration* syntaxCopy(Dsymbol* s) override; - bool functionSemantic(); - bool functionSemantic3(); - bool equals(const RootObject* const o) const final override; - int32_t findVtblIndex(Array* vtbl, int32_t dim); - bool overloadInsert(Dsymbol* s) override; - bool inUnittest(); - MATCH leastAsSpecialized(FuncDeclaration* g, Array* names); - LabelDsymbol* searchLabel(Identifier* ident, const Loc& loc = Loc::initial); - enum : int32_t { LevelError = -2 }; - - const char* toPrettyChars(bool QualifyTypes = false) override; - const char* toFullSignature(); - bool isMain() const; - bool isCMain() const; - bool isWinMain() const; - bool isDllMain() const; - bool isRtInit() const; - bool isExport() const final override; - bool isImportedSymbol() const final override; - bool isCodeseg() const final override; - bool isOverloadable() const final override; - bool isAbstract() final override; - bool canInferAttributes(Scope* sc); - void initInferAttributes(); - PURE isPure(); - bool isSafe(); - bool isTrusted(); - bool isNogc(); - virtual bool isNested() const; - AggregateDeclaration* isThis() override; - bool needThis() final override; - bool isVirtualMethod(); - virtual bool isVirtual() const; - bool isFinalFunc() const; - virtual bool addPreInvariant(); - virtual bool addPostInvariant(); - const char* kind() const override; - bool isUnique() const; - bool needsClosure(); - bool checkClosure(); - bool hasNestedFrameRefs(); - static bool needsFensure(FuncDeclaration* fd); - void buildEnsureRequire(); - ParameterList getParameterList(); - static FuncDeclaration* genCfunc(Array* fparams, Type* treturn, const char* name, StorageClass stc = 0); - static FuncDeclaration* genCfunc(Array* fparams, Type* treturn, Identifier* id, StorageClass stc = 0); - FuncDeclaration* isFuncDeclaration() final override; - virtual FuncDeclaration* toAliasFunc(); - void accept(Visitor* v) override; -}; - -class CtorDeclaration final : public FuncDeclaration -{ -public: - bool isCpCtor; - CtorDeclaration* syntaxCopy(Dsymbol* s) override; - const char* kind() const override; - const char* toChars() const override; - bool isVirtual() const override; - bool addPreInvariant() override; - bool addPostInvariant() override; - CtorDeclaration* isCtorDeclaration() override; - void accept(Visitor* v) override; -}; - -class DtorDeclaration final : public FuncDeclaration -{ -public: - DtorDeclaration* syntaxCopy(Dsymbol* s) override; - const char* kind() const override; - const char* toChars() const override; - bool isVirtual() const override; - bool addPreInvariant() override; - bool addPostInvariant() override; - bool overloadInsert(Dsymbol* s) override; - DtorDeclaration* isDtorDeclaration() override; - void accept(Visitor* v) override; -}; - -class FuncAliasDeclaration final : public FuncDeclaration -{ -public: - FuncDeclaration* funcalias; - bool hasOverloads; - FuncAliasDeclaration* isFuncAliasDeclaration() override; - const char* kind() const override; - FuncDeclaration* toAliasFunc() override; - void accept(Visitor* v) override; -}; - -class FuncLiteralDeclaration final : public FuncDeclaration -{ -public: - TOK tok; - Type* treq; - bool deferToObj; - FuncLiteralDeclaration* syntaxCopy(Dsymbol* s) override; - bool isNested() const override; - AggregateDeclaration* isThis() override; - bool isVirtual() const override; - bool addPreInvariant() override; - bool addPostInvariant() override; - FuncLiteralDeclaration* isFuncLiteralDeclaration() override; - const char* kind() const override; - const char* toPrettyChars(bool QualifyTypes = false) override; - void accept(Visitor* v) override; -}; - -enum class FuncResolveFlag : uint8_t -{ - standard = 0u, - quiet = 1u, - overloadOnly = 2u, - ufcs = 4u, + Type* tded; + Array argexps; + Array tparams; + void update(Expression* e, Type* tparam); + void update(Type* tt, Expression* e, Type* tparam); + MATCH matchAll(Type* tt); }; -class InvariantDeclaration final : public FuncDeclaration -{ -public: - InvariantDeclaration* syntaxCopy(Dsymbol* s) override; - bool isVirtual() const override; - bool addPreInvariant() override; - bool addPostInvariant() override; - InvariantDeclaration* isInvariantDeclaration() override; - void accept(Visitor* v) override; -}; +extern Dsymbol* isDsymbol(RootObject* o); -class NewDeclaration final : public FuncDeclaration -{ -public: - NewDeclaration* syntaxCopy(Dsymbol* s) override; - const char* kind() const override; - bool isVirtual() const override; - bool addPreInvariant() override; - bool addPostInvariant() override; - NewDeclaration* isNewDeclaration() override; - void accept(Visitor* v) override; -}; +extern bool isError(const RootObject* const o); -class SemanticTimePermissiveVisitor : public Visitor -{ -public: - using Visitor::visit; - void visit(Dsymbol* __param_0_) override; - void visit(Parameter* __param_0_) override; - void visit(Statement* __param_0_) override; - void visit(Type* __param_0_) override; - void visit(Expression* __param_0_) override; - void visit(TemplateParameter* __param_0_) override; - void visit(Condition* __param_0_) override; - void visit(Initializer* __param_0_) override; -}; +extern Expression* isExpression(RootObject* o); -class StatementRewriteWalker : public SemanticTimePermissiveVisitor -{ -public: - using SemanticTimePermissiveVisitor::visit; - Statement** ps; - void visitStmt(Statement*& s); - void replaceCurrent(Statement* s); - void visit(PeelStatement* s) override; - void visit(CompoundStatement* s) override; - void visit(CompoundDeclarationStatement* s) override; - void visit(UnrolledLoopStatement* s) override; - void visit(ScopeStatement* s) override; - void visit(WhileStatement* s) override; - void visit(DoStatement* s) override; - void visit(ForStatement* s) override; - void visit(ForeachStatement* s) override; - void visit(ForeachRangeStatement* s) override; - void visit(IfStatement* s) override; - void visit(SwitchStatement* s) override; - void visit(CaseStatement* s) override; - void visit(CaseRangeStatement* s) override; - void visit(DefaultStatement* s) override; - void visit(SynchronizedStatement* s) override; - void visit(WithStatement* s) override; - void visit(TryCatchStatement* s) override; - void visit(TryFinallyStatement* s) override; - void visit(DebugStatement* s) override; - void visit(LabelStatement* s) override; -}; +extern Parameter* isParameter(RootObject* o); -class NrvoWalker final : public StatementRewriteWalker -{ -public: - using StatementRewriteWalker::visit; - FuncDeclaration* fd; - Scope* sc; - void visit(ReturnStatement* s) override; - void visit(TryFinallyStatement* s) override; -}; +extern TemplateParameter* isTemplateParameter(RootObject* o); -class PostBlitDeclaration final : public FuncDeclaration -{ -public: - PostBlitDeclaration* syntaxCopy(Dsymbol* s) override; - bool isVirtual() const override; - bool addPreInvariant() override; - bool addPostInvariant() override; - bool overloadInsert(Dsymbol* s) override; - PostBlitDeclaration* isPostBlitDeclaration() override; - void accept(Visitor* v) override; -}; +extern Tuple* isTuple(RootObject* o); -class StaticCtorDeclaration : public FuncDeclaration -{ -public: - StaticCtorDeclaration* syntaxCopy(Dsymbol* s) override; - AggregateDeclaration* isThis() final override; - bool isVirtual() const final override; - bool addPreInvariant() final override; - bool addPostInvariant() final override; - bool hasStaticCtorOrDtor() final override; - StaticCtorDeclaration* isStaticCtorDeclaration() final override; - void accept(Visitor* v) override; -}; +extern Type* isType(RootObject* o); -class SharedStaticCtorDeclaration final : public StaticCtorDeclaration -{ -public: - SharedStaticCtorDeclaration* syntaxCopy(Dsymbol* s) override; - SharedStaticCtorDeclaration* isSharedStaticCtorDeclaration() override; - void accept(Visitor* v) override; -}; +extern void printTemplateStats(); -class StaticDtorDeclaration : public FuncDeclaration +class DebugSymbol final : public Dsymbol { public: - VarDeclaration* vgate; - StaticDtorDeclaration* syntaxCopy(Dsymbol* s) override; - AggregateDeclaration* isThis() final override; - bool isVirtual() const final override; - bool hasStaticCtorOrDtor() final override; - bool addPreInvariant() final override; - bool addPostInvariant() final override; - StaticDtorDeclaration* isStaticDtorDeclaration() final override; + uint32_t level; + DebugSymbol* syntaxCopy(Dsymbol* s) override; + const char* toChars() const override; + const char* kind() const override; + DebugSymbol* isDebugSymbol() override; void accept(Visitor* v) override; }; -class SharedStaticDtorDeclaration final : public StaticDtorDeclaration +class VersionSymbol final : public Dsymbol { public: - SharedStaticDtorDeclaration* syntaxCopy(Dsymbol* s) override; - SharedStaticDtorDeclaration* isSharedStaticDtorDeclaration() override; + uint32_t level; + VersionSymbol* syntaxCopy(Dsymbol* s) override; + const char* toChars() const override; + const char* kind() const override; + VersionSymbol* isVersionSymbol() override; void accept(Visitor* v) override; }; -class UnitTestDeclaration final : public FuncDeclaration +enum class EXP : uint8_t { -public: - char* codedoc; - Array deferredNested; - UnitTestDeclaration* syntaxCopy(Dsymbol* s) override; - AggregateDeclaration* isThis() override; - bool isVirtual() const override; - bool addPreInvariant() override; - bool addPostInvariant() override; - UnitTestDeclaration* isUnitTestDeclaration() override; - void accept(Visitor* v) override; -}; - -struct HdrGenState final -{ - bool hdrgen; - bool ddoc; - bool fullDump; - bool importcHdr; - bool fullQual; - int32_t tpltMember; - int32_t autoMember; - int32_t forStmtInit; - int32_t insideFuncBody; - int32_t insideAggregate; - bool declstring; - EnumDeclaration* inEnumDecl; - HdrGenState() : - hdrgen(), - ddoc(), - fullDump(), - importcHdr(), - fullQual(), - tpltMember(), - autoMember(), - forStmtInit(), - insideFuncBody(), - insideAggregate(), - declstring(), - inEnumDecl() - { - } - HdrGenState(bool hdrgen, bool ddoc = false, bool fullDump = false, bool importcHdr = false, bool fullQual = false, int32_t tpltMember = 0, int32_t autoMember = 0, int32_t forStmtInit = 0, int32_t insideFuncBody = 0, int32_t insideAggregate = 0, bool declstring = false, EnumDeclaration* inEnumDecl = nullptr) : - hdrgen(hdrgen), - ddoc(ddoc), - fullDump(fullDump), - importcHdr(importcHdr), - fullQual(fullQual), - tpltMember(tpltMember), - autoMember(autoMember), - forStmtInit(forStmtInit), - insideFuncBody(insideFuncBody), - insideAggregate(insideAggregate), - declstring(declstring), - inEnumDecl(inEnumDecl) - {} -}; - -enum : int32_t { TEST_EMIT_ALL = 0 }; - -extern void genhdrfile(Module* m, OutBuffer& buf); - -extern void moduleToBuffer(OutBuffer& buf, Module* m); - -extern const char* parametersTypeToChars(ParameterList pl); - -extern const char* toChars(const Statement* const s); - -enum class InitKind : uint8_t -{ - void_ = 0u, - error = 1u, - struct_ = 2u, - array = 3u, - exp = 4u, - C_ = 5u, + reserved = 0u, + negate = 1u, + cast_ = 2u, + null_ = 3u, + assert_ = 4u, + array = 5u, + call = 6u, + address = 7u, + type = 8u, + throw_ = 9u, + new_ = 10u, + delete_ = 11u, + star = 12u, + symbolOffset = 13u, + variable = 14u, + dotVariable = 15u, + dotIdentifier = 16u, + dotTemplateInstance = 17u, + dotType = 18u, + slice = 19u, + arrayLength = 20u, + dollar = 21u, + template_ = 22u, + dotTemplateDeclaration = 23u, + declaration = 24u, + dSymbol = 25u, + typeid_ = 26u, + uadd = 27u, + remove = 28u, + newAnonymousClass = 29u, + arrayLiteral = 30u, + assocArrayLiteral = 31u, + structLiteral = 32u, + classReference = 33u, + thrownException = 34u, + delegatePointer = 35u, + delegateFunctionPointer = 36u, + lessThan = 37u, + greaterThan = 38u, + lessOrEqual = 39u, + greaterOrEqual = 40u, + equal = 41u, + notEqual = 42u, + identity = 43u, + notIdentity = 44u, + index = 45u, + is_ = 46u, + leftShift = 47u, + rightShift = 48u, + leftShiftAssign = 49u, + rightShiftAssign = 50u, + unsignedRightShift = 51u, + unsignedRightShiftAssign = 52u, + concatenate = 53u, + concatenateAssign = 54u, + concatenateElemAssign = 55u, + concatenateDcharAssign = 56u, + add = 57u, + min = 58u, + addAssign = 59u, + minAssign = 60u, + mul = 61u, + div = 62u, + mod = 63u, + mulAssign = 64u, + divAssign = 65u, + modAssign = 66u, + and_ = 67u, + or_ = 68u, + xor_ = 69u, + andAssign = 70u, + orAssign = 71u, + xorAssign = 72u, + assign = 73u, + not_ = 74u, + tilde = 75u, + plusPlus = 76u, + minusMinus = 77u, + construct = 78u, + blit = 79u, + dot = 80u, + comma = 81u, + question = 82u, + andAnd = 83u, + orOr = 84u, + prePlusPlus = 85u, + preMinusMinus = 86u, + identifier = 87u, + string_ = 88u, + this_ = 89u, + super_ = 90u, + halt = 91u, + tuple = 92u, + error = 93u, + void_ = 94u, + int64 = 95u, + float64 = 96u, + complex80 = 97u, + import_ = 98u, + delegate_ = 99u, + function_ = 100u, + mixin_ = 101u, + in_ = 102u, + break_ = 103u, + continue_ = 104u, + goto_ = 105u, + scope_ = 106u, + traits = 107u, + overloadSet = 108u, + line = 109u, + file = 110u, + fileFullPath = 111u, + moduleString = 112u, + functionString = 113u, + prettyFunction = 114u, + pow = 115u, + powAssign = 116u, + vector = 117u, + voidExpression = 118u, + cantExpression = 119u, + showCtfeContext = 120u, + objcClassReference = 121u, + vectorArray = 122u, + compoundLiteral = 123u, + _Generic_ = 124u, + interval = 125u, + loweredAssignExp = 126u, }; -class Initializer : public ASTNode +struct complex_t final { -public: - Loc loc; - InitKind kind; - DYNCAST dyncast() const override; - ErrorInitializer* isErrorInitializer(); - VoidInitializer* isVoidInitializer(); - StructInitializer* isStructInitializer(); - ArrayInitializer* isArrayInitializer(); - ExpInitializer* isExpInitializer(); - CInitializer* isCInitializer(); - void accept(Visitor* v) override; + _d_real re; + _d_real im; + complex_t() = delete; + complex_t(_d_real re); + complex_t(_d_real re, _d_real im); + int32_t opEquals(complex_t y) const; }; -class ArrayInitializer final : public Initializer +template +struct Optional final { -public: - Array index; - Array value; - uint32_t dim; - Type* type; - bool sem; - bool isCarray; - bool isAssociativeArray() const; - void accept(Visitor* v) override; + T value; + bool present; + Optional(T value); + static Optional create(T val); + bool isPresent() const; + bool isEmpty() const; + T get(); + bool hasValue(T exp) const; + Optional() + { + } }; -class CInitializer final : public Initializer +class Expression : public ASTNode { public: - Array initializerList; Type* type; - bool sem; - void accept(Visitor* v) override; -}; - -class ErrorInitializer final : public Initializer -{ -public: - void accept(Visitor* v) override; -}; - -class ExpInitializer final : public Initializer -{ -public: - bool expandTuples; - Expression* exp; - void accept(Visitor* v) override; -}; - -enum class NeedInterpret -{ - INITnointerpret = 0, - INITinterpret = 1, + Loc loc; + const EXP op; + size_t size() const; + static void _init(); + static void deinitialize(); + virtual Expression* syntaxCopy(); + DYNCAST dyncast() const final override; + const char* toChars() const override; + virtual dinteger_t toInteger(); + virtual uinteger_t toUInteger(); + virtual _d_real toReal(); + virtual _d_real toImaginary(); + virtual complex_t toComplex(); + virtual StringExp* toStringExp(); + virtual bool isLvalue(); + virtual bool checkType(); + virtual bool checkValue(); + Expression* addressOf(); + Expression* deref(); + int32_t isConst(); + virtual bool isIdentical(const Expression* const e) const; + virtual Optional toBool(); + virtual bool hasCode(); + IntegerExp* isIntegerExp(); + ErrorExp* isErrorExp(); + VoidInitExp* isVoidInitExp(); + RealExp* isRealExp(); + ComplexExp* isComplexExp(); + IdentifierExp* isIdentifierExp(); + DollarExp* isDollarExp(); + DsymbolExp* isDsymbolExp(); + ThisExp* isThisExp(); + SuperExp* isSuperExp(); + NullExp* isNullExp(); + StringExp* isStringExp(); + TupleExp* isTupleExp(); + ArrayLiteralExp* isArrayLiteralExp(); + AssocArrayLiteralExp* isAssocArrayLiteralExp(); + StructLiteralExp* isStructLiteralExp(); + CompoundLiteralExp* isCompoundLiteralExp(); + TypeExp* isTypeExp(); + ScopeExp* isScopeExp(); + TemplateExp* isTemplateExp(); + NewExp* isNewExp(); + NewAnonClassExp* isNewAnonClassExp(); + SymOffExp* isSymOffExp(); + VarExp* isVarExp(); + OverExp* isOverExp(); + FuncExp* isFuncExp(); + DeclarationExp* isDeclarationExp(); + TypeidExp* isTypeidExp(); + TraitsExp* isTraitsExp(); + HaltExp* isHaltExp(); + IsExp* isExp(); + MixinExp* isMixinExp(); + ImportExp* isImportExp(); + AssertExp* isAssertExp(); + ThrowExp* isThrowExp(); + DotIdExp* isDotIdExp(); + DotTemplateExp* isDotTemplateExp(); + DotVarExp* isDotVarExp(); + DotTemplateInstanceExp* isDotTemplateInstanceExp(); + DelegateExp* isDelegateExp(); + DotTypeExp* isDotTypeExp(); + CallExp* isCallExp(); + AddrExp* isAddrExp(); + PtrExp* isPtrExp(); + NegExp* isNegExp(); + UAddExp* isUAddExp(); + ComExp* isComExp(); + NotExp* isNotExp(); + DeleteExp* isDeleteExp(); + CastExp* isCastExp(); + VectorExp* isVectorExp(); + VectorArrayExp* isVectorArrayExp(); + SliceExp* isSliceExp(); + ArrayLengthExp* isArrayLengthExp(); + ArrayExp* isArrayExp(); + DotExp* isDotExp(); + CommaExp* isCommaExp(); + IntervalExp* isIntervalExp(); + DelegatePtrExp* isDelegatePtrExp(); + DelegateFuncptrExp* isDelegateFuncptrExp(); + IndexExp* isIndexExp(); + PostExp* isPostExp(); + PreExp* isPreExp(); + AssignExp* isAssignExp(); + LoweredAssignExp* isLoweredAssignExp(); + ConstructExp* isConstructExp(); + BlitExp* isBlitExp(); + AddAssignExp* isAddAssignExp(); + MinAssignExp* isMinAssignExp(); + MulAssignExp* isMulAssignExp(); + DivAssignExp* isDivAssignExp(); + ModAssignExp* isModAssignExp(); + AndAssignExp* isAndAssignExp(); + OrAssignExp* isOrAssignExp(); + XorAssignExp* isXorAssignExp(); + PowAssignExp* isPowAssignExp(); + ShlAssignExp* isShlAssignExp(); + ShrAssignExp* isShrAssignExp(); + UshrAssignExp* isUshrAssignExp(); + CatAssignExp* isCatAssignExp(); + CatElemAssignExp* isCatElemAssignExp(); + CatDcharAssignExp* isCatDcharAssignExp(); + AddExp* isAddExp(); + MinExp* isMinExp(); + CatExp* isCatExp(); + MulExp* isMulExp(); + DivExp* isDivExp(); + ModExp* isModExp(); + PowExp* isPowExp(); + ShlExp* isShlExp(); + ShrExp* isShrExp(); + UshrExp* isUshrExp(); + AndExp* isAndExp(); + OrExp* isOrExp(); + XorExp* isXorExp(); + LogicalExp* isLogicalExp(); + InExp* isInExp(); + RemoveExp* isRemoveExp(); + EqualExp* isEqualExp(); + IdentityExp* isIdentityExp(); + CondExp* isCondExp(); + GenericExp* isGenericExp(); + DefaultInitExp* isDefaultInitExp(); + FileInitExp* isFileInitExp(); + LineInitExp* isLineInitExp(); + ModuleInitExp* isModuleInitExp(); + FuncInitExp* isFuncInitExp(); + PrettyFuncInitExp* isPrettyFuncInitExp(); + ObjcClassReferenceExp* isObjcClassReferenceExp(); + ClassReferenceExp* isClassReferenceExp(); + ThrownExceptionExp* isThrownExceptionExp(); + UnaExp* isUnaExp(); + BinExp* isBinExp(); + BinAssignExp* isBinAssignExp(); + void accept(Visitor* v) override; }; -class StructInitializer final : public Initializer +class BinExp : public Expression { public: - Array field; - Array value; + Expression* e1; + Expression* e2; + Type* att1; + Type* att2; + BinExp* syntaxCopy() override; + void setNoderefOperands(); void accept(Visitor* v) override; }; -class VoidInitializer final : public Initializer +class BinAssignExp : public BinExp { public: - Type* type; + bool isLvalue() final override; void accept(Visitor* v) override; }; -extern Initializer* initializerSemantic(Initializer* init, Scope* sc, Type*& tx, NeedInterpret needInterpret); - -extern Expression* initializerToExpression(Initializer* init, Type* itype = nullptr, const bool isCfile = false); +class AddAssignExp final : public BinAssignExp +{ +public: + void accept(Visitor* v) override; +}; -enum class DotExpFlag +class AddExp final : public BinExp { - none = 0, - gag = 1, - noDeref = 2, - noAliasThis = 4, +public: + void accept(Visitor* v) override; }; -enum : int32_t { LOGDEFAULTINIT = 0 }; +class UnaExp : public Expression +{ +public: + Expression* e1; + UnaExp* syntaxCopy() override; + void setNoderefOperand(); + void accept(Visitor* v) override; +}; -enum : int32_t { LOGDOTEXP = 0 }; +class AddrExp final : public UnaExp +{ +public: + void accept(Visitor* v) override; +}; -enum class DiagnosticReporting : uint8_t +class AndAssignExp final : public BinAssignExp { - error = 0u, - inform = 1u, - off = 2u, +public: + void accept(Visitor* v) override; }; -enum class CppStdRevision : uint32_t +class AndExp final : public BinExp { - cpp98 = 199711u, - cpp11 = 201103u, - cpp14 = 201402u, - cpp17 = 201703u, - cpp20 = 202002u, +public: + void accept(Visitor* v) override; }; -struct Help final +struct ArgumentList final { - bool manual; - bool usage; - bool mcpu; - bool transition; - bool check; - bool checkAction; - bool revert; - bool preview; - bool externStd; - bool hc; - Help() : - manual(), - usage(), - mcpu(), - transition(), - check(), - checkAction(), - revert(), - preview(), - externStd(), - hc() + Array* arguments; + Array* names; + ArgumentList() : + arguments(), + names() { } - Help(bool manual, bool usage = false, bool mcpu = false, bool transition = false, bool check = false, bool checkAction = false, bool revert = false, bool preview = false, bool externStd = false, bool hc = false) : - manual(manual), - usage(usage), - mcpu(mcpu), - transition(transition), - check(check), - checkAction(checkAction), - revert(revert), - preview(preview), - externStd(externStd), - hc(hc) + ArgumentList(Array* arguments, Array* names = nullptr) : + arguments(arguments), + names(names) {} }; -struct Verbose final +class ArrayExp final : public UnaExp { - bool verbose; - bool showColumns; - bool tls; - bool templates; - bool templatesListInstances; - bool gc; - bool field; - bool complex; - bool vin; - bool showGaggedErrors; - bool printErrorContext; - bool logo; - bool color; - bool cov; - MessageStyle messageStyle; - uint32_t errorLimit; - uint32_t errorSupplementLimit; - uint32_t errorSupplementCount(); - Verbose() : - verbose(), - showColumns(), - tls(), - templates(), - templatesListInstances(), - gc(), - field(), - complex(true), - vin(), - showGaggedErrors(), - printErrorContext(), - logo(), - color(), - cov(), - messageStyle((MessageStyle)0u), - errorLimit(20u), - errorSupplementLimit(6u) - { - } - Verbose(bool verbose, bool showColumns = false, bool tls = false, bool templates = false, bool templatesListInstances = false, bool gc = false, bool field = false, bool complex = true, bool vin = false, bool showGaggedErrors = false, bool printErrorContext = false, bool logo = false, bool color = false, bool cov = false, MessageStyle messageStyle = (MessageStyle)0u, uint32_t errorLimit = 20u, uint32_t errorSupplementLimit = 6u) : - verbose(verbose), - showColumns(showColumns), - tls(tls), - templates(templates), - templatesListInstances(templatesListInstances), - gc(gc), - field(field), - complex(complex), - vin(vin), - showGaggedErrors(showGaggedErrors), - printErrorContext(printErrorContext), - logo(logo), - color(color), - cov(cov), - messageStyle(messageStyle), - errorLimit(errorLimit), - errorSupplementLimit(errorSupplementLimit) - {} +public: + Array* arguments; + size_t currentDimension; + VarDeclaration* lengthVar; + ArrayExp* syntaxCopy() override; + bool isLvalue() override; + void accept(Visitor* v) override; }; -enum class FeatureState : uint8_t +class ArrayLengthExp final : public UnaExp { - default_ = 0u, - disabled = 1u, - enabled = 2u, +public: + void accept(Visitor* v) override; }; -enum class CHECKENABLE : uint8_t +enum class OwnedBy : uint8_t { - _default = 0u, - off = 1u, - on = 2u, - safeonly = 3u, + code = 0u, + ctfe = 1u, + cache = 2u, }; -enum class CHECKACTION : uint8_t +class ArrayLiteralExp final : public Expression { - D = 0u, - C = 1u, - halt = 2u, - context = 3u, +public: + OwnedBy ownedByCtfe; + bool onstack; + Expression* basis; + Array* elements; + static ArrayLiteralExp* create(const Loc& loc, Array* elements); + ArrayLiteralExp* syntaxCopy() override; + bool equals(const RootObject* const o) const override; + Expression* getElement(size_t i); + Optional toBool() override; + StringExp* toStringExp() override; + void accept(Visitor* v) override; }; -struct Output final +class AssertExp final : public UnaExp { - bool doOutput; - bool fullOutput; - _d_dynamicArray< const char > dir; - _d_dynamicArray< const char > name; - Array files; - OutBuffer* buffer; - int32_t bufferLines; - Output() : - doOutput(), - fullOutput(), - dir(), - name(), - files(), - buffer(), - bufferLines() - { - } - Output(bool doOutput, bool fullOutput = false, _d_dynamicArray< const char > dir = {}, _d_dynamicArray< const char > name = {}, Array files = Array(), OutBuffer* buffer = nullptr, int32_t bufferLines = 0) : - doOutput(doOutput), - fullOutput(fullOutput), - dir(dir), - name(name), - files(files), - buffer(buffer), - bufferLines(bufferLines) - {} +public: + Expression* msg; + AssertExp* syntaxCopy() override; + void accept(Visitor* v) override; }; -enum class JsonFieldFlags : uint32_t +enum class MemorySet { - none = 0u, - compilerInfo = 1u, - buildInfo = 2u, - modules = 4u, - semantics = 8u, + none = 0, + blockAssign = 1, + referenceInit = 2, }; -struct Param final +class AssignExp : public BinExp { - bool obj; - bool multiobj; - bool trace; - bool tracegc; - bool vcg_ast; - DiagnosticReporting useDeprecated; - bool useUnitTests; - bool useInline; - bool release; - bool preservePaths; - DiagnosticReporting warnings; - bool cov; - uint8_t covPercent; - bool ctfe_cov; - bool ignoreUnsupportedPragmas; - bool useModuleInfo; - bool useTypeInfo; - bool useExceptions; - bool useGC; - bool betterC; - bool addMain; - bool allInst; - bool bitfields; - CppStdRevision cplusplus; - Help help; - Verbose v; - FeatureState useDIP25; - FeatureState useDIP1000; - bool ehnogc; - bool useDIP1021; - FeatureState fieldwise; - bool fixAliasThis; - FeatureState rvalueRefParam; - FeatureState noSharedAccess; - bool previewIn; - bool inclusiveInContracts; - bool shortenedMethods; - bool fixImmutableConv; - bool fix16997; - FeatureState dtorFields; - FeatureState systemVariables; - CHECKENABLE useInvariants; - CHECKENABLE useIn; - CHECKENABLE useOut; - CHECKENABLE useArrayBounds; - CHECKENABLE useAssert; - CHECKENABLE useSwitchError; - CHECKENABLE boundscheck; - CHECKACTION checkAction; - _d_dynamicArray< const char > argv0; - Array modFileAliasStrings; - Array* imppath; - Array* fileImppath; - _d_dynamicArray< const char > objdir; - _d_dynamicArray< const char > objname; - _d_dynamicArray< const char > libname; - Output ddoc; - Output dihdr; - Output cxxhdr; - Output json; - JsonFieldFlags jsonFieldFlags; - Output makeDeps; - Output mixinOut; - Output moduleDeps; - uint32_t debuglevel; - uint32_t versionlevel; - bool run; - Array runargs; - Array cppswitches; - const char* cpp; - Array objfiles; - Array linkswitches; - Array linkswitchIsForCC; - Array libfiles; - Array dllfiles; - _d_dynamicArray< const char > deffile; - _d_dynamicArray< const char > resfile; - _d_dynamicArray< const char > exefile; - _d_dynamicArray< const char > mapfile; - Param() : - obj(true), - multiobj(), - trace(), - tracegc(), - vcg_ast(), - useDeprecated((DiagnosticReporting)1u), - useUnitTests(), - useInline(false), - release(), - preservePaths(), - warnings((DiagnosticReporting)2u), - cov(), - covPercent(), - ctfe_cov(false), - ignoreUnsupportedPragmas(), - useModuleInfo(true), - useTypeInfo(true), - useExceptions(true), - useGC(true), - betterC(), - addMain(), - allInst(), - bitfields(), - cplusplus((CppStdRevision)201103u), - help(), - v(), - useDIP25((FeatureState)2u), - ehnogc(), - useDIP1021(), - fixAliasThis(), - previewIn(), - inclusiveInContracts(), - shortenedMethods(true), - fixImmutableConv(), - fix16997(true), - useInvariants((CHECKENABLE)0u), - useIn((CHECKENABLE)0u), - useOut((CHECKENABLE)0u), - useArrayBounds((CHECKENABLE)0u), - useAssert((CHECKENABLE)0u), - useSwitchError((CHECKENABLE)0u), - boundscheck((CHECKENABLE)0u), - checkAction((CHECKACTION)0u), - argv0(), - modFileAliasStrings(), - imppath(), - fileImppath(), - objdir(), - objname(), - libname(), - ddoc(), - dihdr(), - cxxhdr(), - json(), - makeDeps(), - mixinOut(), - moduleDeps(), - debuglevel(), - versionlevel(), - run(), - runargs(), - cppswitches(), - cpp(), - objfiles(), - linkswitches(), - linkswitchIsForCC(), - libfiles(), - dllfiles(), - deffile(), - resfile(), - exefile(), - mapfile() - { - } - Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool vcg_ast = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = false, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool useGC = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, Help help = Help(), Verbose v = Verbose(), FeatureState useDIP25 = (FeatureState)2u, FeatureState useDIP1000 = (FeatureState)0u, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)0u, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)0u, FeatureState noSharedAccess = (FeatureState)0u, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)0u, FeatureState systemVariables = (FeatureState)0u, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, _d_dynamicArray< const char > argv0 = {}, Array modFileAliasStrings = Array(), Array* imppath = nullptr, Array* fileImppath = nullptr, _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, uint32_t versionlevel = 0u, bool run = false, Array runargs = Array(), Array cppswitches = Array(), const char* cpp = nullptr, Array objfiles = Array(), Array linkswitches = Array(), Array linkswitchIsForCC = Array(), Array libfiles = Array(), Array dllfiles = Array(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}) : - obj(obj), - multiobj(multiobj), - trace(trace), - tracegc(tracegc), - vcg_ast(vcg_ast), - useDeprecated(useDeprecated), - useUnitTests(useUnitTests), - useInline(useInline), - release(release), - preservePaths(preservePaths), - warnings(warnings), - cov(cov), - covPercent(covPercent), - ctfe_cov(ctfe_cov), - ignoreUnsupportedPragmas(ignoreUnsupportedPragmas), - useModuleInfo(useModuleInfo), - useTypeInfo(useTypeInfo), - useExceptions(useExceptions), - useGC(useGC), - betterC(betterC), - addMain(addMain), - allInst(allInst), - bitfields(bitfields), - cplusplus(cplusplus), - help(help), - v(v), - useDIP25(useDIP25), - useDIP1000(useDIP1000), - ehnogc(ehnogc), - useDIP1021(useDIP1021), - fieldwise(fieldwise), - fixAliasThis(fixAliasThis), - rvalueRefParam(rvalueRefParam), - noSharedAccess(noSharedAccess), - previewIn(previewIn), - inclusiveInContracts(inclusiveInContracts), - shortenedMethods(shortenedMethods), - fixImmutableConv(fixImmutableConv), - fix16997(fix16997), - dtorFields(dtorFields), - systemVariables(systemVariables), - useInvariants(useInvariants), - useIn(useIn), - useOut(useOut), - useArrayBounds(useArrayBounds), - useAssert(useAssert), - useSwitchError(useSwitchError), - boundscheck(boundscheck), - checkAction(checkAction), - argv0(argv0), - modFileAliasStrings(modFileAliasStrings), - imppath(imppath), - fileImppath(fileImppath), - objdir(objdir), - objname(objname), - libname(libname), - ddoc(ddoc), - dihdr(dihdr), - cxxhdr(cxxhdr), - json(json), - jsonFieldFlags(jsonFieldFlags), - makeDeps(makeDeps), - mixinOut(mixinOut), - moduleDeps(moduleDeps), - debuglevel(debuglevel), - versionlevel(versionlevel), - run(run), - runargs(runargs), - cppswitches(cppswitches), - cpp(cpp), - objfiles(objfiles), - linkswitches(linkswitches), - linkswitchIsForCC(linkswitchIsForCC), - libfiles(libfiles), - dllfiles(dllfiles), - deffile(deffile), - resfile(resfile), - exefile(exefile), - mapfile(mapfile) - {} +public: + MemorySet memset; + AssignExp(const Loc& loc, EXP tok, Expression* e1, Expression* e2); + bool isLvalue() final override; + void accept(Visitor* v) override; }; -struct CompileEnv final +class AssocArrayLiteralExp final : public Expression { - uint32_t versionNumber; - _d_dynamicArray< const char > date; - _d_dynamicArray< const char > time; - _d_dynamicArray< const char > vendor; - _d_dynamicArray< const char > timestamp; - bool previewIn; - bool ddocOutput; - bool masm; - CompileEnv() : - versionNumber(), - date(), - time(), - vendor(), - timestamp(), - previewIn(), - ddocOutput(), - masm() - { - } - CompileEnv(uint32_t versionNumber, _d_dynamicArray< const char > date = {}, _d_dynamicArray< const char > time = {}, _d_dynamicArray< const char > vendor = {}, _d_dynamicArray< const char > timestamp = {}, bool previewIn = false, bool ddocOutput = false, bool masm = false) : - versionNumber(versionNumber), - date(date), - time(time), - vendor(vendor), - timestamp(timestamp), - previewIn(previewIn), - ddocOutput(ddocOutput), - masm(masm) - {} +public: + OwnedBy ownedByCtfe; + Array* keys; + Array* values; + Expression* lowering; + bool equals(const RootObject* const o) const override; + AssocArrayLiteralExp* syntaxCopy() override; + Optional toBool() override; + void accept(Visitor* v) override; }; -struct Global final +class BlitExp final : public AssignExp { - _d_dynamicArray< const char > inifilename; - _d_dynamicArray< const char > copyright; - _d_dynamicArray< const char > written; - Array* path; - Array* filePath; - char datetime[26LLU]; - CompileEnv compileEnv; - Param params; - uint32_t errors; - uint32_t warnings; - uint32_t gag; - uint32_t gaggedErrors; - uint32_t gaggedWarnings; - void* console; - Array* versionids; - Array* debugids; - bool hasMainFunction; - uint32_t varSequenceNumber; - FileManager* fileManager; - enum : int32_t { recursionLimit = 500 }; - - ErrorSink* errorSink; - ErrorSink* errorSinkNull; - FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ); - uint32_t startGagging(); - bool endGagging(uint32_t oldGagged); - void increaseErrorCount(); - void _init(); - uint32_t versionNumber(); - const char* const versionChars(); - Global() : - inifilename(), - copyright(73, "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved"), - written(24, "written by Walter Bright"), - path(), - filePath(), - compileEnv(), - params(), - errors(), - warnings(), - gag(), - gaggedErrors(), - gaggedWarnings(), - console(), - versionids(), - debugids(), - hasMainFunction(), - varSequenceNumber(1u), - fileManager(), - errorSink(), - errorSinkNull(), - preprocess() - { - } - Global(_d_dynamicArray< const char > inifilename, _d_dynamicArray< const char > copyright = { 73, "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved" }, _d_dynamicArray< const char > written = { 24, "written by Walter Bright" }, Array* path = nullptr, Array* filePath = nullptr, CompileEnv compileEnv = CompileEnv(), Param params = Param(), uint32_t errors = 0u, uint32_t warnings = 0u, uint32_t gag = 0u, uint32_t gaggedErrors = 0u, uint32_t gaggedWarnings = 0u, void* console = nullptr, Array* versionids = nullptr, Array* debugids = nullptr, bool hasMainFunction = false, uint32_t varSequenceNumber = 1u, FileManager* fileManager = nullptr, ErrorSink* errorSink = nullptr, ErrorSink* errorSinkNull = nullptr, FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ) = nullptr) : - inifilename(inifilename), - copyright(copyright), - written(written), - path(path), - filePath(filePath), - compileEnv(compileEnv), - params(params), - errors(errors), - warnings(warnings), - gag(gag), - gaggedErrors(gaggedErrors), - gaggedWarnings(gaggedWarnings), - console(console), - versionids(versionids), - debugids(debugids), - hasMainFunction(hasMainFunction), - varSequenceNumber(varSequenceNumber), - fileManager(fileManager), - errorSink(errorSink), - errorSinkNull(errorSinkNull), - preprocess(preprocess) - {} +public: + void accept(Visitor* v) override; }; -extern Global global; - -class Parameter final : public ASTNode +class CTFEExp final : public Expression { public: - Loc loc; - StorageClass storageClass; - Type* type; - Identifier* ident; - Expression* defaultArg; - UserAttributeDeclaration* userAttribDecl; - static Parameter* create(const Loc& loc, StorageClass storageClass, Type* type, Identifier* ident, Expression* defaultArg, UserAttributeDeclaration* userAttribDecl); - Parameter* syntaxCopy(); - Type* isLazyArray(); - bool isLazy() const; - bool isReference() const; - DYNCAST dyncast() const override; - void accept(Visitor* v) override; - static size_t dim(Array* parameters); - static Parameter* getNth(Array* parameters, size_t nth); const char* toChars() const override; - bool isCovariant(bool returnByRef, const Parameter* const p, bool previewIn = global.params.previewIn) const; }; -enum class RET +class CallExp final : public UnaExp { - regs = 1, - stack = 2, +public: + Array* arguments; + Array* names; + FuncDeclaration* f; + bool directcall; + bool inDebugStatement; + bool ignoreAttributes; + bool isUfcsRewrite; + VarDeclaration* vthis2; + static CallExp* create(const Loc& loc, Expression* e, Array* exps); + static CallExp* create(const Loc& loc, Expression* e); + static CallExp* create(const Loc& loc, Expression* e, Expression* earg1); + static CallExp* create(const Loc& loc, FuncDeclaration* fd, Expression* earg1); + CallExp* syntaxCopy() override; + bool isLvalue() override; + void accept(Visitor* v) override; }; -enum : uint64_t { SIZE_INVALID = 18446744073709551615LLU }; +class CastExp final : public UnaExp +{ +public: + Type* to; + uint8_t mod; + CastExp* syntaxCopy() override; + bool isLvalue() override; + void accept(Visitor* v) override; +}; -enum class ScopeRef +class CatAssignExp : public BinAssignExp { - None = 0, - Scope = 1, - ReturnScope = 2, - Ref = 3, - ReturnRef = 4, - RefScope = 5, - ReturnRef_Scope = 6, - Ref_ReturnScope = 7, - Return = 8, +public: + Expression* lowering; + void accept(Visitor* v) override; }; -enum class TRUSTformat +class CatDcharAssignExp final : public CatAssignExp { - TRUSTformatDefault = 0, - TRUSTformatSystem = 1, +public: + void accept(Visitor* v) override; }; -class TypeNext : public Type +class CatElemAssignExp final : public CatAssignExp { public: - Type* next; - void checkDeprecated(const Loc& loc, Scope* sc) final override; - int32_t hasWild() const final override; - Type* nextOf() final override; - Type* makeConst() final override; - Type* makeImmutable() final override; - Type* makeShared() final override; - Type* makeSharedConst() final override; - Type* makeWild() final override; - Type* makeWildConst() final override; - Type* makeSharedWild() final override; - Type* makeSharedWildConst() final override; - Type* makeMutable() final override; - MATCH constConv(Type* to) override; - uint8_t deduceWild(Type* t, bool isRef) final override; - void transitive(); void accept(Visitor* v) override; }; -class TypeArray : public TypeNext +class CatExp final : public BinExp { public: + Expression* lowering; void accept(Visitor* v) override; }; -class TypeAArray final : public TypeArray +class ClassReferenceExp final : public Expression { public: - Type* index; - Loc loc; - static TypeAArray* create(Type* t, Type* index); - const char* kind() const override; - TypeAArray* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; - bool isZeroInit(const Loc& loc) override; - bool isBoolean() override; - bool hasPointers() override; - MATCH implicitConvTo(Type* to) override; - MATCH constConv(Type* to) override; + StructLiteralExp* value; + ClassDeclaration* originalClass(); + int32_t getFieldIndex(Type* fieldtype, uint32_t fieldoffset); + int32_t findFieldIndexByName(VarDeclaration* v); void accept(Visitor* v) override; }; -class TypeBasic final : public Type +class CmpExp final : public BinExp { public: - const char* dstring; - uint32_t flags; - const char* kind() const override; - TypeBasic* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; - uint32_t alignsize() override; - bool isintegral() override; - bool isfloating() override; - bool isreal() override; - bool isimaginary() override; - bool iscomplex() override; - bool isscalar() override; - bool isunsigned() override; - MATCH implicitConvTo(Type* to) override; - bool isZeroInit(const Loc& loc) override; - TypeBasic* isTypeBasic() override; void accept(Visitor* v) override; }; -enum class AliasThisRec +class ComExp final : public UnaExp { - no = 0, - yes = 1, - fwdref = 2, - typeMask = 3, - tracing = 4, - tracingDT = 8, +public: + void accept(Visitor* v) override; }; -class TypeClass final : public Type +class CommaExp final : public BinExp { public: - ClassDeclaration* sym; - AliasThisRec att; - CPPMANGLE cppmangle; - const char* kind() const override; - uinteger_t size(const Loc& loc) override; - TypeClass* syntaxCopy() override; - Dsymbol* toDsymbol(Scope* sc) override; - ClassDeclaration* isClassHandle() override; - bool isBaseOf(Type* t, int32_t* poffset) override; - MATCH implicitConvTo(Type* to) override; - MATCH constConv(Type* to) override; - uint8_t deduceWild(Type* t, bool isRef) override; - Type* toHeadMutable() override; - bool isZeroInit(const Loc& loc) override; - bool isscope() override; - bool isBoolean() override; - bool hasPointers() override; + const bool isGenerated; + bool allowCommaExp; + bool isLvalue() override; + Optional toBool() override; void accept(Visitor* v) override; + static void allow(Expression* exp); }; -class TypeDArray final : public TypeArray +class ComplexExp final : public Expression { public: - const char* kind() const override; - TypeDArray* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; - uint32_t alignsize() override; - bool isString() override; - bool isZeroInit(const Loc& loc) override; - bool isBoolean() override; - MATCH implicitConvTo(Type* to) override; - bool hasPointers() override; + complex_t value; + static ComplexExp* create(const Loc& loc, complex_t value, Type* type); + bool equals(const RootObject* const o) const override; + bool isIdentical(const Expression* const e) const override; + dinteger_t toInteger() override; + uinteger_t toUInteger() override; + _d_real toReal() override; + _d_real toImaginary() override; + complex_t toComplex() override; + Optional toBool() override; void accept(Visitor* v) override; }; -class TypeDelegate final : public TypeNext +class CompoundLiteralExp final : public Expression { public: - static TypeDelegate* create(TypeFunction* t); - const char* kind() const override; - TypeDelegate* syntaxCopy() override; - Type* addStorageClass(StorageClass stc) override; - uinteger_t size(const Loc& loc) override; - uint32_t alignsize() override; - MATCH implicitConvTo(Type* to) override; - bool isZeroInit(const Loc& loc) override; - bool isBoolean() override; - bool hasPointers() override; + Initializer* initializer; void accept(Visitor* v) override; }; -class TypeEnum final : public Type +class CondExp final : public BinExp { public: - EnumDeclaration* sym; - const char* kind() const override; - TypeEnum* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; - Type* memType(const Loc& loc = Loc::initial); - uint32_t alignsize() override; - Dsymbol* toDsymbol(Scope* sc) override; - bool isintegral() override; - bool isfloating() override; - bool isreal() override; - bool isimaginary() override; - bool iscomplex() override; - bool isscalar() override; - bool isunsigned() override; - bool isBoolean() override; - bool isString() override; - bool isAssignable() override; - bool needsDestruction() override; - bool needsCopyOrPostblit() override; - bool needsNested() override; - MATCH implicitConvTo(Type* to) override; - MATCH constConv(Type* to) override; - bool isZeroInit(const Loc& loc) override; - bool hasPointers() override; - bool hasVoidInitPointers() override; - bool hasSystemFields() override; - bool hasInvariant() override; - Type* nextOf() override; + Expression* econd; + CondExp* syntaxCopy() override; + bool isLvalue() override; void accept(Visitor* v) override; }; -class TypeError final : public Type +class ConstructExp final : public AssignExp { public: - const char* kind() const override; - TypeError* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; - Expression* defaultInitLiteral(const Loc& loc) override; void accept(Visitor* v) override; }; -enum class TRUST : uint8_t +class DeclarationExp final : public Expression { - default_ = 0u, - system = 1u, - trusted = 2u, - safe = 3u, +public: + Dsymbol* declaration; + DeclarationExp* syntaxCopy() override; + bool hasCode() override; + void accept(Visitor* v) override; }; -class TypeFunction final : public TypeNext +class DefaultInitExp : public Expression { public: - ParameterList parameterList; -private: - struct BitFields final - { - bool isnothrow; - bool isnogc; - bool isproperty; - bool isref; - bool isreturn; - bool isScopeQual; - bool isreturninferred; - bool isscopeinferred; - bool islive; - bool incomplete; - bool isInOutParam; - bool isInOutQual; - bool isctor; - bool isreturnscope; - BitFields() : - isnothrow(), - isnogc(), - isproperty(), - isref(), - isreturn(), - isScopeQual(), - isreturninferred(), - isscopeinferred(), - islive(), - incomplete(), - isInOutParam(), - isInOutQual(), - isctor(), - isreturnscope() - { - } - BitFields(bool isnothrow, bool isnogc = false, bool isproperty = false, bool isref = false, bool isreturn = false, bool isScopeQual = false, bool isreturninferred = false, bool isscopeinferred = false, bool islive = false, bool incomplete = false, bool isInOutParam = false, bool isInOutQual = false, bool isctor = false, bool isreturnscope = false) : - isnothrow(isnothrow), - isnogc(isnogc), - isproperty(isproperty), - isref(isref), - isreturn(isreturn), - isScopeQual(isScopeQual), - isreturninferred(isreturninferred), - isscopeinferred(isscopeinferred), - islive(islive), - incomplete(incomplete), - isInOutParam(isInOutParam), - isInOutQual(isInOutQual), - isctor(isctor), - isreturnscope(isreturnscope) - {} - }; + void accept(Visitor* v) override; +}; +class DelegateExp final : public UnaExp +{ public: - bool isnothrow() const; - bool isnothrow(bool v); - bool isnogc() const; - bool isnogc(bool v); - bool isproperty() const; - bool isproperty(bool v); - bool isref() const; - bool isref(bool v); - bool isreturn() const; - bool isreturn(bool v); - bool isScopeQual() const; - bool isScopeQual(bool v); - bool isreturninferred() const; - bool isreturninferred(bool v); - bool isscopeinferred() const; - bool isscopeinferred(bool v); - bool islive() const; - bool islive(bool v); - bool incomplete() const; - bool incomplete(bool v); - bool isInOutParam() const; - bool isInOutParam(bool v); - bool isInOutQual() const; - bool isInOutQual(bool v); - bool isctor() const; - bool isctor(bool v); - bool isreturnscope() const; - bool isreturnscope(bool v); -private: - uint16_t bitFields; -public: - LINK linkage; - TRUST trust; - PURE purity; - int8_t inuse; - Array* fargs; - static TypeFunction* create(Array* parameters, Type* treturn, uint8_t varargs, LINK linkage, StorageClass stc = 0); - const char* kind() const override; - TypeFunction* syntaxCopy() override; - void purityLevel(); - bool hasLazyParameters(); - bool isDstyleVariadic() const; - StorageClass parameterStorageClass(Type* tthis, Parameter* p, Array* outerVars = nullptr, bool indirect = false); - Type* addStorageClass(StorageClass stc) override; - Type* substWildTo(uint32_t __param_0_) override; - MATCH constConv(Type* to) override; - bool iswild() const; + FuncDeclaration* func; + bool hasOverloads; + VarDeclaration* vthis2; void accept(Visitor* v) override; }; -class TypeQualified : public Type +class DelegateFuncptrExp final : public UnaExp { public: - Loc loc; - Array idents; - TypeQualified* syntaxCopy() override = 0; - uinteger_t size(const Loc& loc) override; + bool isLvalue() override; void accept(Visitor* v) override; }; -class TypeIdentifier final : public TypeQualified +class DelegatePtrExp final : public UnaExp { public: - Identifier* ident; - Dsymbol* originalSymbol; - static TypeIdentifier* create(const Loc& loc, Identifier* ident); - const char* kind() const override; - TypeIdentifier* syntaxCopy() override; - Dsymbol* toDsymbol(Scope* sc) override; + bool isLvalue() override; void accept(Visitor* v) override; }; -class TypeInstance final : public TypeQualified +class DeleteExp final : public UnaExp { public: - TemplateInstance* tempinst; - const char* kind() const override; - TypeInstance* syntaxCopy() override; - Dsymbol* toDsymbol(Scope* sc) override; + bool isRAII; void accept(Visitor* v) override; }; -class TypeMixin final : public Type +class DivAssignExp final : public BinAssignExp { public: - Loc loc; - Array* exps; - RootObject* obj; - const char* kind() const override; - TypeMixin* syntaxCopy() override; - Dsymbol* toDsymbol(Scope* sc) override; void accept(Visitor* v) override; }; -class TypeNoreturn final : public Type +class DivExp final : public BinExp { public: - const char* kind() const override; - TypeNoreturn* syntaxCopy() override; - MATCH implicitConvTo(Type* to) override; - MATCH constConv(Type* to) override; - bool isBoolean() override; - uinteger_t size(const Loc& loc) override; - uint32_t alignsize() override; void accept(Visitor* v) override; }; -class TypeNull final : public Type +class IdentifierExp : public Expression { public: - const char* kind() const override; - TypeNull* syntaxCopy() override; - MATCH implicitConvTo(Type* to) override; - bool hasPointers() override; - bool isBoolean() override; - uinteger_t size(const Loc& loc) override; + Identifier* ident; + bool parens; + static IdentifierExp* create(const Loc& loc, Identifier* ident); + bool isLvalue() final override; void accept(Visitor* v) override; }; -class TypePointer final : public TypeNext +class DollarExp final : public IdentifierExp { public: - static TypePointer* create(Type* t); - const char* kind() const override; - TypePointer* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; - MATCH implicitConvTo(Type* to) override; - MATCH constConv(Type* to) override; - bool isscalar() override; - bool isZeroInit(const Loc& loc) override; - bool hasPointers() override; void accept(Visitor* v) override; }; -class TypeReference final : public TypeNext +class DotExp final : public BinExp { public: - const char* kind() const override; - TypeReference* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; - bool isZeroInit(const Loc& loc) override; void accept(Visitor* v) override; }; -class TypeReturn final : public TypeQualified +class DotIdExp final : public UnaExp { public: - const char* kind() const override; - TypeReturn* syntaxCopy() override; - Dsymbol* toDsymbol(Scope* sc) override; + Identifier* ident; + bool noderef; + bool wantsym; + bool arrow; + static DotIdExp* create(const Loc& loc, Expression* e, Identifier* ident); void accept(Visitor* v) override; }; -class TypeSArray final : public TypeArray +class DotTemplateExp final : public UnaExp { public: - Expression* dim; - const char* kind() const override; - TypeSArray* syntaxCopy() override; - bool isIncomplete(); - uinteger_t size(const Loc& loc) override; - uint32_t alignsize() override; - bool isString() override; - bool isZeroInit(const Loc& loc) override; - structalign_t alignment() override; - MATCH constConv(Type* to) override; - MATCH implicitConvTo(Type* to) override; - Expression* defaultInitLiteral(const Loc& loc) override; - bool hasPointers() override; - bool hasSystemFields() override; - bool hasVoidInitPointers() override; - bool hasInvariant() override; - bool needsDestruction() override; - bool needsCopyOrPostblit() override; - bool needsNested() override; + TemplateDeclaration* td; + bool checkType() override; + bool checkValue() override; void accept(Visitor* v) override; }; -class TypeSlice final : public TypeNext +class DotTemplateInstanceExp final : public UnaExp { public: - Expression* lwr; - Expression* upr; - const char* kind() const override; - TypeSlice* syntaxCopy() override; + TemplateInstance* ti; + DotTemplateInstanceExp* syntaxCopy() override; + bool checkType() override; + bool checkValue() override; void accept(Visitor* v) override; }; -class TypeStruct final : public Type +class DotTypeExp final : public UnaExp { public: - StructDeclaration* sym; - AliasThisRec att; - bool inuse; - static TypeStruct* create(StructDeclaration* sym); - const char* kind() const override; - uinteger_t size(const Loc& loc) override; - uint32_t alignsize() override; - TypeStruct* syntaxCopy() override; - Dsymbol* toDsymbol(Scope* sc) override; - structalign_t alignment() override; - Expression* defaultInitLiteral(const Loc& loc) override; - bool isZeroInit(const Loc& loc) override; - bool isAssignable() override; - bool isBoolean() override; - bool needsDestruction() override; - bool needsCopyOrPostblit() override; - bool needsNested() override; - bool hasPointers() override; - bool hasVoidInitPointers() override; - bool hasSystemFields() override; - bool hasInvariant() override; - MATCH implicitConvTo(Type* to) override; - MATCH constConv(Type* to) override; - uint8_t deduceWild(Type* t, bool isRef) override; - Type* toHeadMutable() override; + Dsymbol* sym; void accept(Visitor* v) override; }; -class TypeTag final : public Type +class DotVarExp final : public UnaExp { public: - Loc loc; - TOK tok; - structalign_t packalign; - Identifier* id; - Type* base; - Array* members; - Type* resolved; - uint8_t mod; - const char* kind() const override; - TypeTag* syntaxCopy() override; + Declaration* var; + bool hasOverloads; + bool isLvalue() override; void accept(Visitor* v) override; }; -class TypeTraits final : public Type +class DsymbolExp final : public Expression { public: - Loc loc; - TraitsExp* exp; - RootObject* obj; - const char* kind() const override; - TypeTraits* syntaxCopy() override; - Dsymbol* toDsymbol(Scope* sc) override; + Dsymbol* s; + bool hasOverloads; + bool isLvalue() override; void accept(Visitor* v) override; - uinteger_t size(const Loc& loc) override; }; -class TypeTuple final : public Type +class EqualExp final : public BinExp { public: - static TypeTuple* empty; - Array* arguments; - static TypeTuple* create(Array* arguments); - static TypeTuple* create(); - static TypeTuple* create(Type* t1); - static TypeTuple* create(Type* t1, Type* t2); - const char* kind() const override; - TypeTuple* syntaxCopy() override; - bool equals(const RootObject* const o) const override; - MATCH implicitConvTo(Type* to) override; void accept(Visitor* v) override; }; -class TypeTypeof final : public TypeQualified +class ErrorExp final : public Expression { public: - Expression* exp; - int32_t inuse; - const char* kind() const override; - TypeTypeof* syntaxCopy() override; - Dsymbol* toDsymbol(Scope* sc) override; - uinteger_t size(const Loc& loc) override; + static ErrorExp* get(); void accept(Visitor* v) override; + static ErrorExp* errorexp; }; -class TypeVector final : public Type +class FileInitExp final : public DefaultInitExp { public: - Type* basetype; - static TypeVector* create(Type* basetype); - const char* kind() const override; - TypeVector* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; - uint32_t alignsize() override; - bool isintegral() override; - bool isfloating() override; - bool isscalar() override; - bool isunsigned() override; - bool isBoolean() override; - MATCH implicitConvTo(Type* to) override; - Expression* defaultInitLiteral(const Loc& loc) override; - TypeBasic* elementType(); - bool isZeroInit(const Loc& loc) override; void accept(Visitor* v) override; }; -extern AggregateDeclaration* isAggregate(Type* t); +enum class TOK : uint8_t +{ + reserved = 0u, + leftParenthesis = 1u, + rightParenthesis = 2u, + leftBracket = 3u, + rightBracket = 4u, + leftCurly = 5u, + rightCurly = 6u, + colon = 7u, + semicolon = 8u, + dotDotDot = 9u, + endOfFile = 10u, + cast_ = 11u, + null_ = 12u, + assert_ = 13u, + true_ = 14u, + false_ = 15u, + throw_ = 16u, + new_ = 17u, + delete_ = 18u, + variable = 19u, + slice = 20u, + version_ = 21u, + module_ = 22u, + dollar = 23u, + template_ = 24u, + typeof_ = 25u, + pragma_ = 26u, + typeid_ = 27u, + comment = 28u, + lessThan = 29u, + greaterThan = 30u, + lessOrEqual = 31u, + greaterOrEqual = 32u, + equal = 33u, + notEqual = 34u, + identity = 35u, + notIdentity = 36u, + is_ = 37u, + leftShift = 38u, + rightShift = 39u, + leftShiftAssign = 40u, + rightShiftAssign = 41u, + unsignedRightShift = 42u, + unsignedRightShiftAssign = 43u, + concatenateAssign = 44u, + add = 45u, + min = 46u, + addAssign = 47u, + minAssign = 48u, + mul = 49u, + div = 50u, + mod = 51u, + mulAssign = 52u, + divAssign = 53u, + modAssign = 54u, + and_ = 55u, + or_ = 56u, + xor_ = 57u, + andAssign = 58u, + orAssign = 59u, + xorAssign = 60u, + assign = 61u, + not_ = 62u, + tilde = 63u, + plusPlus = 64u, + minusMinus = 65u, + dot = 66u, + comma = 67u, + question = 68u, + andAnd = 69u, + orOr = 70u, + int32Literal = 71u, + uns32Literal = 72u, + int64Literal = 73u, + uns64Literal = 74u, + int128Literal = 75u, + uns128Literal = 76u, + float32Literal = 77u, + float64Literal = 78u, + float80Literal = 79u, + imaginary32Literal = 80u, + imaginary64Literal = 81u, + imaginary80Literal = 82u, + charLiteral = 83u, + wcharLiteral = 84u, + dcharLiteral = 85u, + identifier = 86u, + string_ = 87u, + hexadecimalString = 88u, + this_ = 89u, + super_ = 90u, + error = 91u, + void_ = 92u, + int8 = 93u, + uns8 = 94u, + int16 = 95u, + uns16 = 96u, + int32 = 97u, + uns32 = 98u, + int64 = 99u, + uns64 = 100u, + int128 = 101u, + uns128 = 102u, + float32 = 103u, + float64 = 104u, + float80 = 105u, + imaginary32 = 106u, + imaginary64 = 107u, + imaginary80 = 108u, + complex32 = 109u, + complex64 = 110u, + complex80 = 111u, + char_ = 112u, + wchar_ = 113u, + dchar_ = 114u, + bool_ = 115u, + struct_ = 116u, + class_ = 117u, + interface_ = 118u, + union_ = 119u, + enum_ = 120u, + import_ = 121u, + alias_ = 122u, + override_ = 123u, + delegate_ = 124u, + function_ = 125u, + mixin_ = 126u, + align_ = 127u, + extern_ = 128u, + private_ = 129u, + protected_ = 130u, + public_ = 131u, + export_ = 132u, + static_ = 133u, + final_ = 134u, + const_ = 135u, + abstract_ = 136u, + debug_ = 137u, + deprecated_ = 138u, + in_ = 139u, + out_ = 140u, + inout_ = 141u, + lazy_ = 142u, + auto_ = 143u, + package_ = 144u, + immutable_ = 145u, + if_ = 146u, + else_ = 147u, + while_ = 148u, + for_ = 149u, + do_ = 150u, + switch_ = 151u, + case_ = 152u, + default_ = 153u, + break_ = 154u, + continue_ = 155u, + with_ = 156u, + synchronized_ = 157u, + return_ = 158u, + goto_ = 159u, + try_ = 160u, + catch_ = 161u, + finally_ = 162u, + asm_ = 163u, + foreach_ = 164u, + foreach_reverse_ = 165u, + scope_ = 166u, + onScopeExit = 167u, + onScopeFailure = 168u, + onScopeSuccess = 169u, + invariant_ = 170u, + unittest_ = 171u, + argumentTypes = 172u, + ref_ = 173u, + macro_ = 174u, + parameters = 175u, + traits = 176u, + pure_ = 177u, + nothrow_ = 178u, + gshared = 179u, + line = 180u, + file = 181u, + fileFullPath = 182u, + moduleString = 183u, + functionString = 184u, + prettyFunction = 185u, + shared_ = 186u, + at = 187u, + pow = 188u, + powAssign = 189u, + goesTo = 190u, + vector = 191u, + pound = 192u, + arrow = 193u, + colonColon = 194u, + wchar_tLiteral = 195u, + endOfLine = 196u, + whitespace = 197u, + inline_ = 198u, + register_ = 199u, + restrict_ = 200u, + signed_ = 201u, + sizeof_ = 202u, + typedef_ = 203u, + unsigned_ = 204u, + volatile_ = 205u, + _Alignas_ = 206u, + _Alignof_ = 207u, + _Atomic_ = 208u, + _Bool_ = 209u, + _Complex_ = 210u, + _Generic_ = 211u, + _Imaginary_ = 212u, + _Noreturn_ = 213u, + _Static_assert_ = 214u, + _Thread_local_ = 215u, + _assert_ = 216u, + _import_ = 217u, + __cdecl_ = 218u, + __declspec_ = 219u, + __stdcall_ = 220u, + __thread_ = 221u, + __pragma_ = 222u, + __int128_ = 223u, + __attribute___ = 224u, +}; -class Nspace final : public ScopeDsymbol +class FuncExp final : public Expression { 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, int32_t flags = 8) override; - bool hasPointers() override; - void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion) override; - const char* kind() const override; - Nspace* isNspace() override; + FuncLiteralDeclaration* fd; + TemplateDeclaration* td; + TOK tok; + bool equals(const RootObject* const o) const override; + FuncExp* syntaxCopy() override; + const char* toChars() const override; + bool checkType() override; + bool checkValue() override; void accept(Visitor* v) override; }; -enum class STMT : uint8_t -{ - Error = 0u, - Peel = 1u, - Exp = 2u, - DtorExp = 3u, - Mixin = 4u, - Compound = 5u, - CompoundDeclaration = 6u, - CompoundAsm = 7u, - UnrolledLoop = 8u, - Scope = 9u, - Forwarding = 10u, - While = 11u, - Do = 12u, - For = 13u, - Foreach = 14u, - ForeachRange = 15u, - If = 16u, - Conditional = 17u, - StaticForeach = 18u, - Pragma = 19u, - StaticAssert = 20u, - Switch = 21u, - Case = 22u, - CaseRange = 23u, - Default = 24u, - GotoDefault = 25u, - GotoCase = 26u, - SwitchError = 27u, - Return = 28u, - Break = 29u, - Continue = 30u, - Synchronized = 31u, - With = 32u, - TryCatch = 33u, - TryFinally = 34u, - ScopeGuard = 35u, - Throw = 36u, - Debug = 37u, - Goto = 38u, - Label = 39u, - Asm = 40u, - InlineAsm = 41u, - GccAsm = 42u, - Import = 43u, -}; - -class Statement : public ASTNode +class FuncInitExp final : public DefaultInitExp { public: - const Loc loc; - const STMT stmt; - DYNCAST dyncast() const final override; - virtual Statement* syntaxCopy(); - static Array* arraySyntaxCopy(Array* a); - virtual Statement* getRelatedLabeled(); - virtual bool hasBreak() const; - virtual bool hasContinue() const; - virtual Statement* last(); void accept(Visitor* v) override; - virtual ReturnStatement* endsWithReturnStatement(); - ErrorStatement* isErrorStatement(); - PeelStatement* isPeelStatement(); - ScopeStatement* isScopeStatement(); - ExpStatement* isExpStatement(); - CompoundStatement* isCompoundStatement(); - ReturnStatement* isReturnStatement(); - IfStatement* isIfStatement(); - ConditionalStatement* isConditionalStatement(); - StaticForeachStatement* isStaticForeachStatement(); - CaseStatement* isCaseStatement(); - DefaultStatement* isDefaultStatement(); - LabelStatement* isLabelStatement(); - GotoStatement* isGotoStatement(); - GotoDefaultStatement* isGotoDefaultStatement(); - GotoCaseStatement* isGotoCaseStatement(); - BreakStatement* isBreakStatement(); - DtorExpStatement* isDtorExpStatement(); - MixinStatement* isMixinStatement(); - ForwardingStatement* isForwardingStatement(); - DoStatement* isDoStatement(); - WhileStatement* isWhileStatement(); - ForStatement* isForStatement(); - ForeachStatement* isForeachStatement(); - SwitchStatement* isSwitchStatement(); - ContinueStatement* isContinueStatement(); - WithStatement* isWithStatement(); - TryCatchStatement* isTryCatchStatement(); - ThrowStatement* isThrowStatement(); - DebugStatement* isDebugStatement(); - TryFinallyStatement* isTryFinallyStatement(); - ScopeGuardStatement* isScopeGuardStatement(); - SwitchErrorStatement* isSwitchErrorStatement(); - UnrolledLoopStatement* isUnrolledLoopStatement(); - ForeachRangeStatement* isForeachRangeStatement(); - CompoundDeclarationStatement* isCompoundDeclarationStatement(); - CompoundAsmStatement* isCompoundAsmStatement(); - PragmaStatement* isPragmaStatement(); - StaticAssertStatement* isStaticAssertStatement(); - CaseRangeStatement* isCaseRangeStatement(); - SynchronizedStatement* isSynchronizedStatement(); - AsmStatement* isAsmStatement(); - InlineAsmStatement* isInlineAsmStatement(); - GccAsmStatement* isGccAsmStatement(); - ImportStatement* isImportStatement(); }; -class AsmStatement : public Statement +class GenericExp final : public Expression { public: - Token* tokens; - bool caseSensitive; - AsmStatement* syntaxCopy() override; + Expression* cntlExp; + Array* types; + Array* exps; + GenericExp* syntaxCopy() override; void accept(Visitor* v) override; }; -class BreakStatement final : public Statement +class HaltExp final : public Expression { public: - Identifier* ident; - BreakStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class CaseRangeStatement final : public Statement +class IdentityExp final : public BinExp { public: - Expression* first; - Expression* last; - Statement* statement; - CaseRangeStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class CaseStatement final : public Statement +class ImportExp final : public UnaExp { public: - Expression* exp; - Statement* statement; - int32_t index; - VarDeclaration* lastVar; - void* extra; - CaseStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class Catch final : public RootObject +class InExp final : public BinExp { public: - const Loc loc; - Type* type; - Identifier* ident; - Statement* handler; - VarDeclaration* var; - bool errors; - bool internalCatch; - Catch* syntaxCopy(); + void accept(Visitor* v) override; }; -class CompoundStatement : public Statement +class IndexExp final : public BinExp { public: - Array* statements; - static CompoundStatement* create(const Loc& loc, Statement* s1, Statement* s2); - CompoundStatement* syntaxCopy() override; - ReturnStatement* endsWithReturnStatement() final override; - Statement* last() final override; + VarDeclaration* lengthVar; + bool modifiable; + bool indexIsInBounds; + IndexExp* syntaxCopy() override; + bool isLvalue() override; void accept(Visitor* v) override; }; -class CompoundAsmStatement final : public CompoundStatement +class IntegerExp final : public Expression { + dinteger_t value; public: - StorageClass stc; - CompoundAsmStatement* syntaxCopy() override; + static IntegerExp* create(const Loc& loc, dinteger_t value, Type* type); + bool equals(const RootObject* const o) const override; + dinteger_t toInteger() override; + _d_real toReal() override; + _d_real toImaginary() override; + complex_t toComplex() override; + Optional toBool() override; void accept(Visitor* v) override; + dinteger_t getInteger(); + IntegerExp* syntaxCopy() override; + static IntegerExp* createBool(bool b); }; -class CompoundDeclarationStatement final : public CompoundStatement +class IntervalExp final : public Expression { public: - CompoundDeclarationStatement* syntaxCopy() override; + Expression* lwr; + Expression* upr; + Expression* syntaxCopy() override; void accept(Visitor* v) override; }; -class ConditionalStatement final : public Statement +class IsExp final : public Expression { public: - Condition* condition; - Statement* ifbody; - Statement* elsebody; - ConditionalStatement* syntaxCopy() override; + Type* targ; + Identifier* id; + Type* tspec; + Array* parameters; + TOK tok; + TOK tok2; + IsExp* syntaxCopy() override; void accept(Visitor* v) override; }; -class ContinueStatement final : public Statement +enum : bool { LOGSEMANTIC = false }; + +class LineInitExp final : public DefaultInitExp { public: - Identifier* ident; - ContinueStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class DebugStatement final : public Statement +class LogicalExp final : public BinExp { public: - Statement* statement; - DebugStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class DefaultStatement final : public Statement +class LoweredAssignExp final : public AssignExp { public: - Statement* statement; - VarDeclaration* lastVar; - DefaultStatement* syntaxCopy() override; + Expression* lowering; + const char* toChars() const override; void accept(Visitor* v) override; }; -class DoStatement final : public Statement +class MinAssignExp final : public BinAssignExp { public: - Statement* _body; - Expression* condition; - Loc endloc; - DoStatement* syntaxCopy() override; - bool hasBreak() const override; - bool hasContinue() const override; void accept(Visitor* v) override; }; -class ExpStatement : public Statement +class MinExp final : public BinExp { public: - Expression* exp; - static ExpStatement* create(const Loc& loc, Expression* exp); - ExpStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class DtorExpStatement final : public ExpStatement +class MixinExp final : public Expression { public: - VarDeclaration* var; - DtorExpStatement* syntaxCopy() override; + Array* exps; + MixinExp* syntaxCopy() override; + bool equals(const RootObject* const o) const override; void accept(Visitor* v) override; }; -class ErrorStatement final : public Statement +class ModAssignExp final : public BinAssignExp { public: - ErrorStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class ForStatement final : public Statement +class ModExp final : public BinExp { public: - Statement* _init; - Expression* condition; - Expression* increment; - Statement* _body; - Loc endloc; - Statement* relatedLabeled; - ForStatement* syntaxCopy() override; - Statement* getRelatedLabeled() override; - bool hasBreak() const override; - bool hasContinue() const override; void accept(Visitor* v) override; }; -class ForeachRangeStatement final : public Statement +enum class Modifiable { -public: - TOK op; - Parameter* prm; - Expression* lwr; - Expression* upr; - Statement* _body; - Loc endloc; - VarDeclaration* key; - ForeachRangeStatement* syntaxCopy() override; - bool hasBreak() const override; - bool hasContinue() const override; - void accept(Visitor* v) override; -}; - -class ForeachStatement final : public Statement -{ -public: - TOK op; - Array* parameters; - Expression* aggr; - Statement* _body; - Loc endloc; - VarDeclaration* key; - VarDeclaration* value; - FuncDeclaration* func; - Array* cases; - Array* gotos; - ForeachStatement* syntaxCopy() override; - bool hasBreak() const override; - bool hasContinue() const override; - void accept(Visitor* v) override; + no = 0, + yes = 1, + initialization = 2, }; -class ForwardingStatement final : public Statement +enum class ModifyFlags { -public: - ForwardingScopeDsymbol* sym; - Statement* statement; - ForwardingStatement* syntaxCopy() override; - void accept(Visitor* v) override; + none = 0, + noError = 1, + fieldAssign = 2, }; -class GccAsmStatement final : public AsmStatement +class ModuleInitExp final : public DefaultInitExp { public: - StorageClass stc; - Expression* insn; - Array* args; - uint32_t outputargs; - Array* names; - Array* constraints; - Array* clobbers; - Array* labels; - Array* gotos; - GccAsmStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class GotoCaseStatement final : public Statement +class MulAssignExp final : public BinAssignExp { public: - Expression* exp; - CaseStatement* cs; - GotoCaseStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class GotoDefaultStatement final : public Statement +class MulExp final : public BinExp { public: - SwitchStatement* sw; - GotoDefaultStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class GotoStatement final : public Statement +class NegExp final : public UnaExp { public: - Identifier* ident; - LabelDsymbol* label; - Statement* tryBody; - TryFinallyStatement* tf; - ScopeGuardStatement* os; - VarDeclaration* lastVar; - bool inCtfeBlock; - GotoStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class IfStatement final : public Statement +class NewAnonClassExp final : public Expression { public: - Parameter* prm; - Expression* condition; - Statement* ifbody; - Statement* elsebody; - VarDeclaration* match; - Loc endloc; - IfStatement* syntaxCopy() override; + Expression* thisexp; + ClassDeclaration* cd; + Array* arguments; + NewAnonClassExp* syntaxCopy() override; void accept(Visitor* v) override; - bool isIfCtfeBlock(); }; -class ImportStatement final : public Statement +class NewExp final : public Expression { public: - Array* imports; - ImportStatement* syntaxCopy() override; + Expression* thisexp; + Type* newtype; + Array* arguments; + Array* names; + Expression* argprefix; + CtorDeclaration* member; + bool onstack; + bool thrownew; + Expression* lowering; + static NewExp* create(const Loc& loc, Expression* thisexp, Type* newtype, Array* arguments); + NewExp* syntaxCopy() override; void accept(Visitor* v) override; }; -class InlineAsmStatement final : public AsmStatement +class NotExp final : public UnaExp { public: - code* asmcode; - uint32_t asmalign; - uint32_t regs; - bool refparam; - bool naked; - InlineAsmStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class LabelDsymbol final : public Dsymbol +class NullExp final : public Expression { public: - LabelStatement* statement; - bool deleted; - bool iasm; - bool duplicated; - static LabelDsymbol* create(Identifier* ident); - LabelDsymbol* isLabel() override; + bool equals(const RootObject* const o) const override; + Optional toBool() override; + StringExp* toStringExp() override; void accept(Visitor* v) override; }; -class LabelStatement final : public Statement +class ObjcClassReferenceExp final : public Expression { public: - Identifier* ident; - Statement* statement; - Statement* tryBody; - TryFinallyStatement* tf; - ScopeGuardStatement* os; - VarDeclaration* lastVar; - Statement* gotoTarget; - void* extra; - bool breaks; - bool inCtfeBlock; - LabelStatement* syntaxCopy() override; + ClassDeclaration* classDeclaration; void accept(Visitor* v) override; }; -class MixinStatement final : public Statement +class OrAssignExp final : public BinAssignExp { public: - Array* exps; - MixinStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class PeelStatement final : public Statement +class OrExp final : public BinExp { public: - Statement* s; void accept(Visitor* v) override; }; -class PragmaStatement final : public Statement +class OverExp final : public Expression { public: - const Identifier* const ident; - Array* args; - Statement* _body; - PragmaStatement* syntaxCopy() override; + OverloadSet* vars; + bool isLvalue() override; void accept(Visitor* v) override; }; -class ReturnStatement final : public Statement +class PostExp final : public BinExp { public: - Expression* exp; - size_t caseDim; - ReturnStatement* syntaxCopy() override; - ReturnStatement* endsWithReturnStatement() override; void accept(Visitor* v) override; }; -class ScopeGuardStatement final : public Statement +class PowAssignExp final : public BinAssignExp { public: - TOK tok; - Statement* statement; - ScopeGuardStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class ScopeStatement final : public Statement +class PowExp final : public BinExp { public: - Statement* statement; - Loc endloc; - ScopeStatement* syntaxCopy() override; - ReturnStatement* endsWithReturnStatement() override; - bool hasBreak() const override; - bool hasContinue() const override; void accept(Visitor* v) override; }; -class StaticAssertStatement final : public Statement +class PreExp final : public UnaExp { public: - StaticAssert* sa; - StaticAssertStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class StaticForeachStatement final : public Statement +class PrettyFuncInitExp final : public DefaultInitExp { public: - StaticForeach* sfe; - StaticForeachStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class SwitchErrorStatement final : public Statement +class PtrExp final : public UnaExp { public: - Expression* exp; + bool isLvalue() override; void accept(Visitor* v) override; }; -class SwitchStatement final : public Statement +class RealExp final : public Expression { public: - Parameter* param; - Expression* condition; - Statement* _body; - bool isFinal; - Loc endloc; - bool hasDefault; - bool hasVars; - DefaultStatement* sdefault; - Statement* tryBody; - TryFinallyStatement* tf; - Array gotoCases; - Array* cases; - VarDeclaration* lastVar; - SwitchStatement* syntaxCopy() override; - bool hasBreak() const override; + _d_real value; + static RealExp* create(const Loc& loc, _d_real value, Type* type); + bool equals(const RootObject* const o) const override; + bool isIdentical(const Expression* const e) const override; + dinteger_t toInteger() override; + uinteger_t toUInteger() override; + _d_real toReal() override; + _d_real toImaginary() override; + complex_t toComplex() override; + Optional toBool() override; void accept(Visitor* v) override; }; -class SynchronizedStatement final : public Statement +class RemoveExp final : public BinExp { public: - Expression* exp; - Statement* _body; - SynchronizedStatement* syntaxCopy() override; - bool hasBreak() const override; - bool hasContinue() const override; void accept(Visitor* v) override; }; -class ThrowStatement final : public Statement +class ScopeExp final : public Expression { public: - Expression* exp; - bool internalThrow; - ThrowStatement* syntaxCopy() override; + ScopeDsymbol* sds; + ScopeExp* syntaxCopy() override; + bool checkType() override; + bool checkValue() override; void accept(Visitor* v) override; }; -class TryCatchStatement final : public Statement +class ShlAssignExp final : public BinAssignExp { public: - Statement* _body; - Array* catches; - Statement* tryBody; - TryCatchStatement* syntaxCopy() override; - bool hasBreak() const override; void accept(Visitor* v) override; }; -class TryFinallyStatement final : public Statement +class ShlExp final : public BinExp { public: - Statement* _body; - Statement* finalbody; - Statement* tryBody; - bool bodyFallsThru; - static TryFinallyStatement* create(const Loc& loc, Statement* _body, Statement* finalbody); - TryFinallyStatement* syntaxCopy() override; - bool hasBreak() const override; - bool hasContinue() const override; void accept(Visitor* v) override; }; -class UnrolledLoopStatement final : public Statement +class ShrAssignExp final : public BinAssignExp { public: - Array* statements; - UnrolledLoopStatement* syntaxCopy() override; - bool hasBreak() const override; - bool hasContinue() const override; void accept(Visitor* v) override; }; -class WhileStatement final : public Statement +class ShrExp final : public BinExp { public: - Parameter* param; - Expression* condition; - Statement* _body; - Loc endloc; - WhileStatement* syntaxCopy() override; - bool hasBreak() const override; - bool hasContinue() const override; void accept(Visitor* v) override; }; -class WithStatement final : public Statement +class SliceExp final : public UnaExp { public: - Expression* exp; - Statement* _body; - VarDeclaration* wthis; - Loc endloc; - WithStatement* syntaxCopy() override; + Expression* upr; + Expression* lwr; + VarDeclaration* lengthVar; +private: + struct BitFields final + { + bool upperIsInBounds; + bool lowerIsLessThanUpper; + bool arrayop; + BitFields() : + upperIsInBounds(), + lowerIsLessThanUpper(), + arrayop() + { + } + BitFields(bool upperIsInBounds, bool lowerIsLessThanUpper = false, bool arrayop = false) : + upperIsInBounds(upperIsInBounds), + lowerIsLessThanUpper(lowerIsLessThanUpper), + arrayop(arrayop) + {} + }; + +public: + bool upperIsInBounds() const; + bool upperIsInBounds(bool v); + bool lowerIsLessThanUpper() const; + bool lowerIsLessThanUpper(bool v); + bool arrayop() const; + bool arrayop(bool v); +private: + uint8_t bitFields; +public: + SliceExp* syntaxCopy() override; + bool isLvalue() override; + Optional toBool() override; void accept(Visitor* v) override; }; -class StaticAssert final : public Dsymbol +class StringExp final : public Expression { public: - Expression* exp; - Array* msgs; - 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; + char postfix; + OwnedBy ownedByCtfe; + union + { + char* string; + char16_t* wstring; + char32_t* dstring; + }; + size_t len; + uint8_t sz; + bool committed; + bool hexString; + enum : char { NoPostfix = 0u }; + + static StringExp* create(const Loc& loc, const char* s); + static StringExp* create(const Loc& loc, const void* string, size_t len); + bool equals(const RootObject* const o) const override; + size_t numberOfCodeUnits(int32_t tynto = 0) const; + void writeTo(void* dest, bool zero, int32_t tyto = 0) const; + char32_t getCodeUnit(size_t i) const; + StringExp* toStringExp() override; + int32_t compare(const StringExp* const se2) const; + Optional toBool() override; + bool isLvalue() override; void accept(Visitor* v) override; }; -extern Expression* defaultInit(Type* mt, const Loc& loc, const bool isCfile = false); +class StructLiteralExp final : public Expression +{ +public: + StructDeclaration* sd; + Array* elements; + Type* stype; + union + { + void* sym; + StructLiteralExp* inlinecopy; + }; + StructLiteralExp* origin; + uint8_t stageflags; + bool useStaticInit; + bool isOriginal; + OwnedBy ownedByCtfe; + static StructLiteralExp* create(const Loc& loc, StructDeclaration* sd, void* elements, Type* stype = nullptr); + bool equals(const RootObject* const o) const override; + StructLiteralExp* syntaxCopy() override; + void accept(Visitor* v) override; +}; -extern Type* merge(Type* type); +class ThisExp : public Expression +{ +public: + VarDeclaration* var; + ThisExp(const Loc& loc, const EXP tok); + ThisExp* syntaxCopy() override; + Optional toBool() override; + bool isLvalue() final override; + void accept(Visitor* v) override; +}; -extern Type* typeSemantic(Type* type, const Loc& loc, Scope* sc); +class SuperExp final : public ThisExp +{ +public: + void accept(Visitor* v) override; +}; -enum class MODFlags +class SymbolExp : public Expression { - none = 0, - const_ = 1, - immutable_ = 4, - shared_ = 2, - wild = 8, - wildconst = 9, - mutable_ = 16, +public: + Declaration* var; + Dsymbol* originalScope; + bool hasOverloads; + void accept(Visitor* v) override; }; -enum class STC : uint64_t +class SymOffExp final : public SymbolExp { - undefined_ = 0LLU, - static_ = 1LLU, - extern_ = 2LLU, - const_ = 4LLU, - final_ = 8LLU, - abstract_ = 16LLU, - parameter = 32LLU, - field = 64LLU, - override_ = 128LLU, - auto_ = 256LLU, - synchronized_ = 512LLU, - deprecated_ = 1024LLU, - in_ = 2048LLU, - out_ = 4096LLU, - lazy_ = 8192LLU, - foreach_ = 16384LLU, - variadic = 32768LLU, - templateparameter = 131072LLU, - ref_ = 262144LLU, - scope_ = 524288LLU, - scopeinferred = 2097152LLU, - return_ = 4194304LLU, - returnScope = 8388608LLU, - returninferred = 16777216LLU, - immutable_ = 33554432LLU, - manifest = 134217728LLU, - nodtor = 268435456LLU, - nothrow_ = 536870912LLU, - pure_ = 1073741824LLU, - tls = 2147483648LLU, - alias_ = 4294967296LLU, - shared_ = 8589934592LLU, - gshared = 17179869184LLU, - wild = 34359738368LLU, - property = 68719476736LLU, - safe = 137438953472LLU, - trusted = 274877906944LLU, - system = 549755813888LLU, - ctfe = 1099511627776LLU, - disable = 2199023255552LLU, - result = 4398046511104LLU, - nodefaultctor = 8796093022208LLU, - temp = 17592186044416LLU, - rvalue = 35184372088832LLU, - nogc = 70368744177664LLU, - autoref = 140737488355328LLU, - inference = 281474976710656LLU, - exptemp = 562949953421312LLU, - future = 1125899906842624LLU, - local = 2251799813685248LLU, - live = 4503599627370496LLU, - register_ = 9007199254740992LLU, - volatile_ = 18014398509481984LLU, - safeGroup = 962072674304LLU, - IOR = 268288LLU, - TYPECTOR = 42983227396LLU, - FUNCATTR = 4575000774574080LLU, - visibleStorageClasses = 7954966262857631LLU, - flowThruAggregate = 962072674304LLU, - flowThruFunction = 18446742978991225440LLU, +public: + dinteger_t offset; + Optional toBool() override; + void accept(Visitor* v) override; }; -struct ASTCodegen final +class TemplateExp final : public Expression { - using AggregateDeclaration = ::AggregateDeclaration; - using ClassKind = ::ClassKind; - using MangleOverride = ::MangleOverride; - using AliasThis = ::AliasThis; - using AliasDeclarations = ::AliasDeclarations; - using BaseClasses = ::BaseClasses; - using CaseStatements = ::CaseStatements; - using Catches = ::Catches; - using ClassDeclarations = ::ClassDeclarations; - using DesigInits = ::DesigInits; - using Designators = ::Designators; - using Dsymbols = ::Dsymbols; - using DtorDeclarations = ::DtorDeclarations; - using Ensures = ::Ensures; - using Expressions = ::Expressions; - using FuncDeclarations = ::FuncDeclarations; - using GotoCaseStatements = ::GotoCaseStatements; - using GotoStatements = ::GotoStatements; - using Identifiers = ::Identifiers; - using Initializers = ::Initializers; - using Modules = ::Modules; - using Objects = ::Objects; - using Parameters = ::Parameters; - using ReturnStatements = ::ReturnStatements; - using ScopeStatements = ::ScopeStatements; - using SharedStaticDtorDeclarations = ::SharedStaticDtorDeclarations; - using Statements = ::Statements; - using StaticDtorDeclarations = ::StaticDtorDeclarations; - using Strings = ::Strings; - using TemplateInstances = ::TemplateInstances; - using TemplateParameters = ::TemplateParameters; - using Types = ::Types; - using VarDeclarations = ::VarDeclarations; - using AlignDeclaration = ::AlignDeclaration; - using AnonDeclaration = ::AnonDeclaration; - using AttribDeclaration = ::AttribDeclaration; - using CPPMangleDeclaration = ::CPPMangleDeclaration; - using CPPNamespaceDeclaration = ::CPPNamespaceDeclaration; - using ConditionalDeclaration = ::ConditionalDeclaration; - using DeprecatedDeclaration = ::DeprecatedDeclaration; - using ForwardingAttribDeclaration = ::ForwardingAttribDeclaration; - using LinkDeclaration = ::LinkDeclaration; - using MixinDeclaration = ::MixinDeclaration; - using PragmaDeclaration = ::PragmaDeclaration; - using StaticForeachDeclaration = ::StaticForeachDeclaration; - using StaticIfDeclaration = ::StaticIfDeclaration; - using StorageClassDeclaration = ::StorageClassDeclaration; - using UserAttributeDeclaration = ::UserAttributeDeclaration; - using VisibilityDeclaration = ::VisibilityDeclaration; - using Condition = ::Condition; - using DVCondition = ::DVCondition; - using DebugCondition = ::DebugCondition; - using Include = ::Include; - using StaticForeach = ::StaticForeach; - using StaticIfCondition = ::StaticIfCondition; - using VersionCondition = ::VersionCondition; - using BaseClass = ::BaseClass; - using ClassDeclaration = ::ClassDeclaration; - using ClassFlags = ::ClassFlags; - using InterfaceDeclaration = ::InterfaceDeclaration; - using AliasDeclaration = ::AliasDeclaration; - using BitFieldDeclaration = ::BitFieldDeclaration; - using Declaration = ::Declaration; - using MatchAccumulator = ::MatchAccumulator; - using OverDeclaration = ::OverDeclaration; - using SymbolDeclaration = ::SymbolDeclaration; - using ThisDeclaration = ::ThisDeclaration; - using TupleDeclaration = ::TupleDeclaration; - using TypeInfoArrayDeclaration = ::TypeInfoArrayDeclaration; - using TypeInfoAssociativeArrayDeclaration = ::TypeInfoAssociativeArrayDeclaration; - using TypeInfoClassDeclaration = ::TypeInfoClassDeclaration; - using TypeInfoConstDeclaration = ::TypeInfoConstDeclaration; - using TypeInfoDeclaration = ::TypeInfoDeclaration; - using TypeInfoDelegateDeclaration = ::TypeInfoDelegateDeclaration; - using TypeInfoEnumDeclaration = ::TypeInfoEnumDeclaration; - using TypeInfoFunctionDeclaration = ::TypeInfoFunctionDeclaration; - using TypeInfoInterfaceDeclaration = ::TypeInfoInterfaceDeclaration; - using TypeInfoInvariantDeclaration = ::TypeInfoInvariantDeclaration; - using TypeInfoPointerDeclaration = ::TypeInfoPointerDeclaration; - using TypeInfoSharedDeclaration = ::TypeInfoSharedDeclaration; - using TypeInfoStaticArrayDeclaration = ::TypeInfoStaticArrayDeclaration; - using TypeInfoStructDeclaration = ::TypeInfoStructDeclaration; - using TypeInfoTupleDeclaration = ::TypeInfoTupleDeclaration; - using TypeInfoVectorDeclaration = ::TypeInfoVectorDeclaration; - using TypeInfoWildDeclaration = ::TypeInfoWildDeclaration; - using VarDeclaration = ::VarDeclaration; - using EnumDeclaration = ::EnumDeclaration; - using EnumMember = ::EnumMember; - using Import = ::Import; - using Module = ::Module; - using ModuleDeclaration = ::ModuleDeclaration; - using Package = ::Package; - using StructDeclaration = ::StructDeclaration; - using StructFlags = ::StructFlags; - using UnionDeclaration = ::UnionDeclaration; - using AliasAssign = ::AliasAssign; - using ArrayScopeSymbol = ::ArrayScopeSymbol; - using Dsymbol = ::Dsymbol; - using DsymbolTable = ::DsymbolTable; - using ExpressionDsymbol = ::ExpressionDsymbol; - using FieldState = ::FieldState; - using ForwardingScopeDsymbol = ::ForwardingScopeDsymbol; - using OverloadSet = ::OverloadSet; - using PASS = ::PASS; - using ScopeDsymbol = ::ScopeDsymbol; - using Ungag = ::Ungag; - using Visibility = ::Visibility; - using WithScopeSymbol = ::WithScopeSymbol; - using TemplateAliasParameter = ::TemplateAliasParameter; - using TemplateDeclaration = ::TemplateDeclaration; - using TemplateInstance = ::TemplateInstance; - using TemplateInstanceBox = ::TemplateInstanceBox; - using TemplateMixin = ::TemplateMixin; - using TemplateParameter = ::TemplateParameter; - using TemplatePrevious = ::TemplatePrevious; - using TemplateStats = ::TemplateStats; - using TemplateThisParameter = ::TemplateThisParameter; - using TemplateTupleParameter = ::TemplateTupleParameter; - using TemplateTypeParameter = ::TemplateTypeParameter; - using TemplateValueParameter = ::TemplateValueParameter; - using Tuple = ::Tuple; - using TypeDeduced = ::TypeDeduced; - using DebugSymbol = ::DebugSymbol; - using VersionSymbol = ::VersionSymbol; - using AddAssignExp = ::AddAssignExp; - using AddExp = ::AddExp; - using AddrExp = ::AddrExp; - using AndAssignExp = ::AndAssignExp; - using AndExp = ::AndExp; - using ArgumentList = ::ArgumentList; - using ArrayExp = ::ArrayExp; - using ArrayLengthExp = ::ArrayLengthExp; - using ArrayLiteralExp = ::ArrayLiteralExp; - using AssertExp = ::AssertExp; - using AssignExp = ::AssignExp; - using AssocArrayLiteralExp = ::AssocArrayLiteralExp; - using BinAssignExp = ::BinAssignExp; - using BinExp = ::BinExp; - using BlitExp = ::BlitExp; - using CallExp = ::CallExp; - using CastExp = ::CastExp; - using CatAssignExp = ::CatAssignExp; - using CatDcharAssignExp = ::CatDcharAssignExp; - using CatElemAssignExp = ::CatElemAssignExp; - using CatExp = ::CatExp; - using CmpExp = ::CmpExp; - using ComExp = ::ComExp; - using CommaExp = ::CommaExp; - using ComplexExp = ::ComplexExp; - using CompoundLiteralExp = ::CompoundLiteralExp; - using CondExp = ::CondExp; - using ConstructExp = ::ConstructExp; - using DeclarationExp = ::DeclarationExp; - using DefaultInitExp = ::DefaultInitExp; - using DelegateExp = ::DelegateExp; - using DelegateFuncptrExp = ::DelegateFuncptrExp; - using DelegatePtrExp = ::DelegatePtrExp; - using DeleteExp = ::DeleteExp; - using DivAssignExp = ::DivAssignExp; - using DivExp = ::DivExp; - using DollarExp = ::DollarExp; - using DotExp = ::DotExp; - using DotIdExp = ::DotIdExp; - using DotTemplateExp = ::DotTemplateExp; - using DotTemplateInstanceExp = ::DotTemplateInstanceExp; - using DotTypeExp = ::DotTypeExp; - using DotVarExp = ::DotVarExp; - using DsymbolExp = ::DsymbolExp; - using EqualExp = ::EqualExp; - using ErrorExp = ::ErrorExp; - using Expression = ::Expression; - using FileInitExp = ::FileInitExp; - using FuncExp = ::FuncExp; - using FuncInitExp = ::FuncInitExp; - using GenericExp = ::GenericExp; - using HaltExp = ::HaltExp; - using IdentifierExp = ::IdentifierExp; - using IdentityExp = ::IdentityExp; - using ImportExp = ::ImportExp; - using InExp = ::InExp; - using IndexExp = ::IndexExp; - using IntegerExp = ::IntegerExp; - using IntervalExp = ::IntervalExp; - using IsExp = ::IsExp; - using LineInitExp = ::LineInitExp; - using LogicalExp = ::LogicalExp; - using LoweredAssignExp = ::LoweredAssignExp; - using MemorySet = ::MemorySet; - using MinAssignExp = ::MinAssignExp; - using MinExp = ::MinExp; - using MixinExp = ::MixinExp; - using ModAssignExp = ::ModAssignExp; - using ModExp = ::ModExp; - using Modifiable = ::Modifiable; - using ModifyFlags = ::ModifyFlags; - using ModuleInitExp = ::ModuleInitExp; - using MulAssignExp = ::MulAssignExp; - using MulExp = ::MulExp; - using NegExp = ::NegExp; - using NewAnonClassExp = ::NewAnonClassExp; - using NewExp = ::NewExp; - using NotExp = ::NotExp; - using NullExp = ::NullExp; - using ObjcClassReferenceExp = ::ObjcClassReferenceExp; - using OrAssignExp = ::OrAssignExp; - using OrExp = ::OrExp; - using OverExp = ::OverExp; - using OwnedBy = ::OwnedBy; - using PostExp = ::PostExp; - using PowAssignExp = ::PowAssignExp; - using PowExp = ::PowExp; - using PreExp = ::PreExp; - using PrettyFuncInitExp = ::PrettyFuncInitExp; - using PtrExp = ::PtrExp; - using RealExp = ::RealExp; - using RemoveExp = ::RemoveExp; - using ScopeExp = ::ScopeExp; - using ShlAssignExp = ::ShlAssignExp; - using ShlExp = ::ShlExp; - using ShrAssignExp = ::ShrAssignExp; - using ShrExp = ::ShrExp; - using SliceExp = ::SliceExp; - using StringExp = ::StringExp; - using StructLiteralExp = ::StructLiteralExp; - using SuperExp = ::SuperExp; - using SymOffExp = ::SymOffExp; - using SymbolExp = ::SymbolExp; - using TemplateExp = ::TemplateExp; - using ThisExp = ::ThisExp; - using ThrowExp = ::ThrowExp; - using TraitsExp = ::TraitsExp; - using TupleExp = ::TupleExp; - using TypeExp = ::TypeExp; - using TypeidExp = ::TypeidExp; - using UAddExp = ::UAddExp; - using UnaExp = ::UnaExp; - using UnionExp = ::UnionExp; - using UshrAssignExp = ::UshrAssignExp; - using UshrExp = ::UshrExp; - using VarExp = ::VarExp; - using VectorArrayExp = ::VectorArrayExp; - using VectorExp = ::VectorExp; - using VoidInitExp = ::VoidInitExp; - using XorAssignExp = ::XorAssignExp; - using XorExp = ::XorExp; - using emplaceExp = ::emplaceExp; - using AttributeViolation = ::AttributeViolation; - using BUILTIN = ::BUILTIN; - using CtorDeclaration = ::CtorDeclaration; - using DtorDeclaration = ::DtorDeclaration; - using Ensure = ::Ensure; - using FuncAliasDeclaration = ::FuncAliasDeclaration; - using FuncDeclaration = ::FuncDeclaration; - using FuncLiteralDeclaration = ::FuncLiteralDeclaration; - using FuncResolveFlag = ::FuncResolveFlag; - using ILS = ::ILS; - using InvariantDeclaration = ::InvariantDeclaration; - using NewDeclaration = ::NewDeclaration; - using NrvoWalker = ::NrvoWalker; - using PostBlitDeclaration = ::PostBlitDeclaration; - using SharedStaticCtorDeclaration = ::SharedStaticCtorDeclaration; - using SharedStaticDtorDeclaration = ::SharedStaticDtorDeclaration; - using StaticCtorDeclaration = ::StaticCtorDeclaration; - using StaticDtorDeclaration = ::StaticDtorDeclaration; - using UnitTestDeclaration = ::UnitTestDeclaration; - using HdrGenState = ::HdrGenState; - using ArrayInitializer = ::ArrayInitializer; - using CInitializer = ::CInitializer; - using DesigInit = ::DesigInit; - using Designator = ::Designator; - using ErrorInitializer = ::ErrorInitializer; - using ExpInitializer = ::ExpInitializer; - using Initializer = ::Initializer; - using NeedInterpret = ::NeedInterpret; - using StructInitializer = ::StructInitializer; - using VisitInitializer = ::VisitInitializer; - using VoidInitializer = ::VoidInitializer; - using Covariant = ::Covariant; - using DotExpFlag = ::DotExpFlag; - using Parameter = ::Parameter; - using ParameterList = ::ParameterList; - using RET = ::RET; - using ScopeRef = ::ScopeRef; - using TRUSTformat = ::TRUSTformat; - using Type = ::Type; - using TypeAArray = ::TypeAArray; - using TypeArray = ::TypeArray; - using TypeBasic = ::TypeBasic; - using TypeClass = ::TypeClass; - using TypeDArray = ::TypeDArray; - using TypeDelegate = ::TypeDelegate; - using TypeEnum = ::TypeEnum; - using TypeError = ::TypeError; - using TypeFunction = ::TypeFunction; - using TypeIdentifier = ::TypeIdentifier; - using TypeInstance = ::TypeInstance; - using TypeMixin = ::TypeMixin; - using TypeNext = ::TypeNext; - using TypeNoreturn = ::TypeNoreturn; - using TypeNull = ::TypeNull; - using TypePointer = ::TypePointer; - using TypeQualified = ::TypeQualified; - using TypeReference = ::TypeReference; - using TypeReturn = ::TypeReturn; - using TypeSArray = ::TypeSArray; - using TypeSlice = ::TypeSlice; - using TypeStruct = ::TypeStruct; - using TypeTag = ::TypeTag; - using TypeTraits = ::TypeTraits; - using TypeTuple = ::TypeTuple; - using TypeTypeof = ::TypeTypeof; - using TypeVector = ::TypeVector; - using VisitType = ::VisitType; - using Nspace = ::Nspace; - using AsmStatement = ::AsmStatement; - using BreakStatement = ::BreakStatement; - using CaseRangeStatement = ::CaseRangeStatement; - using CaseStatement = ::CaseStatement; - using Catch = ::Catch; - using CompoundAsmStatement = ::CompoundAsmStatement; - using CompoundDeclarationStatement = ::CompoundDeclarationStatement; - using CompoundStatement = ::CompoundStatement; - using ConditionalStatement = ::ConditionalStatement; - using ContinueStatement = ::ContinueStatement; - using DebugStatement = ::DebugStatement; - using DefaultStatement = ::DefaultStatement; - using DoStatement = ::DoStatement; - using DtorExpStatement = ::DtorExpStatement; - using ErrorStatement = ::ErrorStatement; - using ExpStatement = ::ExpStatement; - using ForStatement = ::ForStatement; - using ForeachRangeStatement = ::ForeachRangeStatement; - using ForeachStatement = ::ForeachStatement; - using ForwardingStatement = ::ForwardingStatement; - using GccAsmStatement = ::GccAsmStatement; - using GotoCaseStatement = ::GotoCaseStatement; - using GotoDefaultStatement = ::GotoDefaultStatement; - using GotoStatement = ::GotoStatement; - using IfStatement = ::IfStatement; - using ImportStatement = ::ImportStatement; - using InlineAsmStatement = ::InlineAsmStatement; - using LabelDsymbol = ::LabelDsymbol; - using LabelStatement = ::LabelStatement; - using MixinStatement = ::MixinStatement; - using PeelStatement = ::PeelStatement; - using PragmaStatement = ::PragmaStatement; - using ReturnStatement = ::ReturnStatement; - using ScopeGuardStatement = ::ScopeGuardStatement; - using ScopeStatement = ::ScopeStatement; - using Statement = ::Statement; - using StaticAssertStatement = ::StaticAssertStatement; - using StaticForeachStatement = ::StaticForeachStatement; - using SwitchErrorStatement = ::SwitchErrorStatement; - using SwitchStatement = ::SwitchStatement; - using SynchronizedStatement = ::SynchronizedStatement; - using ThrowStatement = ::ThrowStatement; - using TryCatchStatement = ::TryCatchStatement; - using TryFinallyStatement = ::TryFinallyStatement; - using UnrolledLoopStatement = ::UnrolledLoopStatement; - using VisitStatement = ::VisitStatement; - using WhileStatement = ::WhileStatement; - using WithStatement = ::WithStatement; - using StaticAssert = ::StaticAssert; - using CTFEExp = ::CTFEExp; - using ClassReferenceExp = ::ClassReferenceExp; - using ThrownExceptionExp = ::ThrownExceptionExp; - typedef UserAttributeDeclaration* UserAttributeDeclaration; - typedef Ensure Ensure; - typedef ErrorExp* ErrorExp; - typedef MODFlags MODFlags; - typedef Type* Type; - typedef Parameter* Parameter; - typedef ParameterList ParameterList; - typedef VarArg VarArg; - typedef STC STC; - typedef Dsymbol* Dsymbol; - typedef Array Dsymbols; - typedef Visibility Visibility; - typedef PASS PASS; - ASTCodegen() +public: + TemplateDeclaration* td; + FuncDeclaration* fd; + bool isLvalue() override; + bool checkType() override; + bool checkValue() override; + void accept(Visitor* v) override; +}; + +class ThrowExp final : public UnaExp +{ +public: + ThrowExp* syntaxCopy() override; + void accept(Visitor* v) override; +}; + +class ThrownExceptionExp final : public Expression +{ +public: + ClassReferenceExp* thrown; + const char* toChars() const override; + void accept(Visitor* v) override; +}; + +class TraitsExp final : public Expression +{ +public: + Identifier* ident; + Array* args; + TraitsExp* syntaxCopy() override; + void accept(Visitor* v) override; +}; + +class TupleExp final : public Expression +{ +public: + Expression* e0; + Array* exps; + static TupleExp* create(const Loc& loc, Array* exps); + TupleExp* syntaxCopy() override; + bool equals(const RootObject* const o) const override; + void accept(Visitor* v) override; +}; + +class TypeExp final : public Expression +{ +public: + bool parens; + TypeExp* syntaxCopy() override; + bool checkType() override; + bool checkValue() override; + void accept(Visitor* v) override; +}; + +class TypeidExp final : public Expression +{ +public: + RootObject* obj; + TypeidExp* syntaxCopy() override; + void accept(Visitor* v) override; +}; + +class UAddExp final : public UnaExp +{ +public: + void accept(Visitor* v) override; +}; + +class UshrAssignExp final : public BinAssignExp +{ +public: + void accept(Visitor* v) override; +}; + +class UshrExp final : public BinExp +{ +public: + void accept(Visitor* v) override; +}; + +class VarExp final : public SymbolExp +{ +public: + bool delegateWasExtracted; + static VarExp* create(const Loc& loc, Declaration* var, bool hasOverloads = true); + bool equals(const RootObject* const o) const override; + bool isLvalue() override; + void accept(Visitor* v) override; +}; + +class VectorArrayExp final : public UnaExp +{ +public: + bool isLvalue() override; + void accept(Visitor* v) override; +}; + +class VectorExp final : public UnaExp +{ +public: + TypeVector* to; + uint32_t dim; + OwnedBy ownedByCtfe; + static VectorExp* create(const Loc& loc, Expression* e, Type* t); + VectorExp* syntaxCopy() override; + void accept(Visitor* v) override; +}; + +class VoidInitExp final : public Expression +{ +public: + VarDeclaration* var; + void accept(Visitor* v) override; +}; + +enum : int32_t { WANTexpand = 1 }; + +enum : int32_t { WANTvalue = 0 }; + +class XorAssignExp final : public BinAssignExp +{ +public: + void accept(Visitor* v) override; +}; + +class XorExp final : public BinExp +{ +public: + void accept(Visitor* v) override; +}; + +extern void expandTuples(Array* exps, Array* names = nullptr); + +enum : int32_t { stageApply = 8 }; + +enum : int32_t { stageInlineScan = 16 }; + +enum : int32_t { stageOptimize = 4 }; + +enum : int32_t { stageScrub = 1 }; + +enum : int32_t { stageSearchPointers = 2 }; + +enum : int32_t { stageToCBuffer = 32 }; + +struct AttributeViolation final +{ + Loc loc; + const char* fmtStr; + RootObject* arg0; + RootObject* arg1; + RootObject* arg2; + AttributeViolation() : + loc(Loc(0u, 0u, 0u)), + fmtStr(nullptr), + arg0(nullptr), + arg1(nullptr), + arg2(nullptr) + { + } + AttributeViolation(Loc loc, const char* fmtStr = nullptr, RootObject* arg0 = nullptr, RootObject* arg1 = nullptr, RootObject* arg2 = nullptr) : + loc(loc), + fmtStr(fmtStr), + arg0(arg0), + arg1(arg1), + arg2(arg2) + {} +}; + +enum class ILS : uint8_t +{ + uninitialized = 0u, + no = 1u, + yes = 2u, +}; + +enum class PINLINE : uint8_t +{ + default_ = 0u, + never = 1u, + always = 2u, +}; + +struct ObjcFuncDeclaration final +{ + ObjcSelector* selector; + VarDeclaration* selectorParameter; + bool isOptional; + ObjcFuncDeclaration() : + selector(), + selectorParameter(), + isOptional() + { + } + ObjcFuncDeclaration(ObjcSelector* selector, VarDeclaration* selectorParameter = nullptr, bool isOptional = false) : + selector(selector), + selectorParameter(selectorParameter), + isOptional(isOptional) + {} +}; + +enum class PURE : uint8_t +{ + impure = 0u, + fwdref = 1u, + weak = 2u, + const_ = 3u, +}; + +enum class VarArg : uint8_t +{ + none = 0u, + variadic = 1u, + typesafe = 2u, + KRvariadic = 3u, +}; + +struct ParameterList final +{ + Array* parameters; + StorageClass stc; + VarArg varargs; + bool hasIdentifierList; + ParameterList(Array* parameters, VarArg varargs = (VarArg)0u, StorageClass stc = 0); + size_t length(); + Parameter* opIndex(size_t i); + ParameterList() : + parameters(), + stc(), + varargs((VarArg)0u), + hasIdentifierList() + { + } +}; + +class FuncDeclaration : public Declaration +{ +public: + Statement* fbody; + Array foverrides; +private: + ContractInfo* contracts; +public: + const char* mangleString; + VarDeclaration* vresult; + LabelDsymbol* returnLabel; + void* isTypeIsolatedCache; + DsymbolTable* localsymtab; + VarDeclaration* vthis; + VarDeclaration* v_arguments; + VarDeclaration* v_argptr; + Array* parameters; + DsymbolTable* labtab; + Dsymbol* overnext; + FuncDeclaration* overnext0; + Loc endloc; + int32_t vtblIndex; + ILS inlineStatusStmt; + ILS inlineStatusExp; + PINLINE inlining; + int32_t inlineNest; + ForeachStatement* fes; + BaseClass* interfaceVirtual; + Type* tintro; + StorageClass storage_class2; + int32_t hasReturnExp; + VarDeclaration* nrvo_var; + Symbol* shidden; + Array* returns; + Array* gotos; + Array* alignSectionVars; + Symbol* salignSection; + BUILTIN builtin; + int32_t tookAddressOf; + bool requiresClosure; + Array closureVars; + Array outerVars; + Array siblingCallers; + Array* inlinedNestedCallees; + AttributeViolation* safetyViolation; + AttributeViolation* nogcViolation; + AttributeViolation* pureViolation; + AttributeViolation* nothrowViolation; + bool purityInprocess() const; + bool purityInprocess(bool v); + bool safetyInprocess() const; + bool safetyInprocess(bool v); + bool nothrowInprocess() const; + bool nothrowInprocess(bool v); + bool nogcInprocess() const; + bool nogcInprocess(bool v); + bool returnInprocess() const; + bool returnInprocess(bool v); + bool inlineScanned() const; + bool inlineScanned(bool v); + bool inferScope() const; + bool inferScope(bool v); + bool hasCatches() const; + bool hasCatches(bool v); + bool skipCodegen() const; + bool skipCodegen(bool v); + bool printf() const; + bool printf(bool v); + bool scanf() const; + bool scanf(bool v); + bool noreturn() const; + bool noreturn(bool v); + bool isNRVO() const; + bool isNRVO(bool v); + bool isNaked() const; + bool isNaked(bool v); + bool isGenerated() const; + bool isGenerated(bool v); + bool isIntroducing() const; + bool isIntroducing(bool v); + bool hasSemantic3Errors() const; + bool hasSemantic3Errors(bool v); + bool hasNoEH() const; + bool hasNoEH(bool v); + bool inferRetType() const; + bool inferRetType(bool v); + bool hasDualContext() const; + bool hasDualContext(bool v); + bool hasAlwaysInlines() const; + bool hasAlwaysInlines(bool v); + bool isCrtCtor() const; + bool isCrtCtor(bool v); + bool isCrtDtor() const; + bool isCrtDtor(bool v); + bool hasEscapingSiblings() const; + bool hasEscapingSiblings(bool v); + bool computedEscapingSiblings() const; + bool computedEscapingSiblings(bool v); + bool dllImport() const; + bool dllImport(bool v); + bool dllExport() const; + bool dllExport(bool v); +private: + uint32_t bitFields; +public: + ObjcFuncDeclaration objc; + static FuncDeclaration* create(const Loc& loc, const Loc& endloc, Identifier* id, StorageClass storage_class, Type* type, bool noreturn = false); + Array* frequires(); + Array* fensures(); + Statement* frequire(); + Statement* fensure(); + FuncDeclaration* fdrequire(); + FuncDeclaration* fdensure(); + Array* fdrequireParams(); + Array* fdensureParams(); + Array* frequires(Array* param); + Array* fensures(Array* param); + Statement* frequire(Statement* param); + Statement* fensure(Statement* param); + FuncDeclaration* fdrequire(FuncDeclaration* param); + FuncDeclaration* fdensure(FuncDeclaration* param); + Array* fdrequireParams(Array* param); + Array* fdensureParams(Array* param); + FuncDeclaration* syntaxCopy(Dsymbol* s) override; + bool functionSemantic(); + bool functionSemantic3(); + bool equals(const RootObject* const o) const final override; + int32_t findVtblIndex(Array* vtbl, int32_t dim); + bool overloadInsert(Dsymbol* s) override; + bool inUnittest(); + MATCH leastAsSpecialized(FuncDeclaration* g, Array* names); + LabelDsymbol* searchLabel(Identifier* ident, const Loc& loc = Loc::initial); + enum : int32_t { LevelError = -2 }; + + const char* toPrettyChars(bool QualifyTypes = false) override; + const char* toFullSignature(); + bool isMain() const; + bool isCMain() const; + bool isWinMain() const; + bool isDllMain() const; + bool isRtInit() const; + bool isExport() const final override; + bool isImportedSymbol() const final override; + bool isCodeseg() const final override; + bool isOverloadable() const final override; + bool isAbstract() final override; + bool canInferAttributes(Scope* sc); + void initInferAttributes(); + PURE isPure(); + bool isSafe(); + bool isTrusted(); + bool isNogc(); + virtual bool isNested() const; + AggregateDeclaration* isThis() override; + bool needThis() final override; + bool isVirtualMethod(); + virtual bool isVirtual() const; + bool isFinalFunc() const; + virtual bool addPreInvariant(); + virtual bool addPostInvariant(); + const char* kind() const override; + bool isUnique() const; + bool needsClosure(); + bool checkClosure(); + bool hasNestedFrameRefs(); + static bool needsFensure(FuncDeclaration* fd); + void buildEnsureRequire(); + ParameterList getParameterList(); + static FuncDeclaration* genCfunc(Array* fparams, Type* treturn, const char* name, StorageClass stc = 0); + static FuncDeclaration* genCfunc(Array* fparams, Type* treturn, Identifier* id, StorageClass stc = 0); + FuncDeclaration* isFuncDeclaration() final override; + virtual FuncDeclaration* toAliasFunc(); + void accept(Visitor* v) override; +}; + +class CtorDeclaration final : public FuncDeclaration +{ +public: + bool isCpCtor; + CtorDeclaration* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + const char* toChars() const override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + CtorDeclaration* isCtorDeclaration() override; + void accept(Visitor* v) override; +}; + +class DtorDeclaration final : public FuncDeclaration +{ +public: + DtorDeclaration* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + const char* toChars() const override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + bool overloadInsert(Dsymbol* s) override; + DtorDeclaration* isDtorDeclaration() override; + void accept(Visitor* v) override; +}; + +class FuncAliasDeclaration final : public FuncDeclaration +{ +public: + FuncDeclaration* funcalias; + bool hasOverloads; + FuncAliasDeclaration* isFuncAliasDeclaration() override; + const char* kind() const override; + FuncDeclaration* toAliasFunc() override; + void accept(Visitor* v) override; +}; + +class FuncLiteralDeclaration final : public FuncDeclaration +{ +public: + TOK tok; + Type* treq; + bool deferToObj; + FuncLiteralDeclaration* syntaxCopy(Dsymbol* s) override; + bool isNested() const override; + AggregateDeclaration* isThis() override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + FuncLiteralDeclaration* isFuncLiteralDeclaration() override; + const char* kind() const override; + const char* toPrettyChars(bool QualifyTypes = false) override; + void accept(Visitor* v) override; +}; + +enum class FuncResolveFlag : uint8_t +{ + standard = 0u, + quiet = 1u, + overloadOnly = 2u, + ufcs = 4u, +}; + +class InvariantDeclaration final : public FuncDeclaration +{ +public: + InvariantDeclaration* syntaxCopy(Dsymbol* s) override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + InvariantDeclaration* isInvariantDeclaration() override; + void accept(Visitor* v) override; +}; + +class NewDeclaration final : public FuncDeclaration +{ +public: + NewDeclaration* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + NewDeclaration* isNewDeclaration() override; + void accept(Visitor* v) override; +}; + +class SemanticTimePermissiveVisitor : public Visitor +{ +public: + using Visitor::visit; + void visit(Dsymbol* __param_0_) override; + void visit(Parameter* __param_0_) override; + void visit(Statement* __param_0_) override; + void visit(Type* __param_0_) override; + void visit(Expression* __param_0_) override; + void visit(TemplateParameter* __param_0_) override; + void visit(Condition* __param_0_) override; + void visit(Initializer* __param_0_) override; +}; + +class StatementRewriteWalker : public SemanticTimePermissiveVisitor +{ +public: + using SemanticTimePermissiveVisitor::visit; + Statement** ps; + void visitStmt(Statement*& s); + void replaceCurrent(Statement* s); + void visit(PeelStatement* s) override; + void visit(CompoundStatement* s) override; + void visit(CompoundDeclarationStatement* s) override; + void visit(UnrolledLoopStatement* s) override; + void visit(ScopeStatement* s) override; + void visit(WhileStatement* s) override; + void visit(DoStatement* s) override; + void visit(ForStatement* s) override; + void visit(ForeachStatement* s) override; + void visit(ForeachRangeStatement* s) override; + void visit(IfStatement* s) override; + void visit(SwitchStatement* s) override; + void visit(CaseStatement* s) override; + void visit(CaseRangeStatement* s) override; + void visit(DefaultStatement* s) override; + void visit(SynchronizedStatement* s) override; + void visit(WithStatement* s) override; + void visit(TryCatchStatement* s) override; + void visit(TryFinallyStatement* s) override; + void visit(DebugStatement* s) override; + void visit(LabelStatement* s) override; +}; + +class NrvoWalker final : public StatementRewriteWalker +{ +public: + using StatementRewriteWalker::visit; + FuncDeclaration* fd; + Scope* sc; + void visit(ReturnStatement* s) override; + void visit(TryFinallyStatement* s) override; +}; + +class PostBlitDeclaration final : public FuncDeclaration +{ +public: + PostBlitDeclaration* syntaxCopy(Dsymbol* s) override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + bool overloadInsert(Dsymbol* s) override; + PostBlitDeclaration* isPostBlitDeclaration() override; + void accept(Visitor* v) override; +}; + +class StaticCtorDeclaration : public FuncDeclaration +{ +public: + StaticCtorDeclaration* syntaxCopy(Dsymbol* s) override; + AggregateDeclaration* isThis() final override; + bool isVirtual() const final override; + bool addPreInvariant() final override; + bool addPostInvariant() final override; + bool hasStaticCtorOrDtor() final override; + StaticCtorDeclaration* isStaticCtorDeclaration() final override; + void accept(Visitor* v) override; +}; + +class SharedStaticCtorDeclaration final : public StaticCtorDeclaration +{ +public: + bool standalone; + SharedStaticCtorDeclaration* syntaxCopy(Dsymbol* s) override; + SharedStaticCtorDeclaration* isSharedStaticCtorDeclaration() override; + void accept(Visitor* v) override; +}; + +class StaticDtorDeclaration : public FuncDeclaration +{ +public: + VarDeclaration* vgate; + StaticDtorDeclaration* syntaxCopy(Dsymbol* s) override; + AggregateDeclaration* isThis() final override; + bool isVirtual() const final override; + bool hasStaticCtorOrDtor() final override; + bool addPreInvariant() final override; + bool addPostInvariant() final override; + StaticDtorDeclaration* isStaticDtorDeclaration() final override; + void accept(Visitor* v) override; +}; + +class SharedStaticDtorDeclaration final : public StaticDtorDeclaration +{ +public: + SharedStaticDtorDeclaration* syntaxCopy(Dsymbol* s) override; + SharedStaticDtorDeclaration* isSharedStaticDtorDeclaration() override; + void accept(Visitor* v) override; +}; + +class UnitTestDeclaration final : public FuncDeclaration +{ +public: + char* codedoc; + Array deferredNested; + UnitTestDeclaration* syntaxCopy(Dsymbol* s) override; + AggregateDeclaration* isThis() override; + bool isVirtual() const override; + bool addPreInvariant() override; + bool addPostInvariant() override; + UnitTestDeclaration* isUnitTestDeclaration() override; + void accept(Visitor* v) override; +}; + +struct HdrGenState final +{ + bool hdrgen; + bool ddoc; + bool fullDump; + bool importcHdr; + bool doFuncBodies; + bool vcg_ast; + bool fullQual; + int32_t tpltMember; + int32_t autoMember; + int32_t forStmtInit; + int32_t insideFuncBody; + int32_t insideAggregate; + bool declstring; + EnumDeclaration* inEnumDecl; + HdrGenState() : + hdrgen(), + ddoc(), + fullDump(), + importcHdr(), + doFuncBodies(), + vcg_ast(), + fullQual(), + tpltMember(), + autoMember(), + forStmtInit(), + insideFuncBody(), + insideAggregate(), + declstring(), + inEnumDecl() + { + } + HdrGenState(bool hdrgen, bool ddoc = false, bool fullDump = false, bool importcHdr = false, bool doFuncBodies = false, bool vcg_ast = false, bool fullQual = false, int32_t tpltMember = 0, int32_t autoMember = 0, int32_t forStmtInit = 0, int32_t insideFuncBody = 0, int32_t insideAggregate = 0, bool declstring = false, EnumDeclaration* inEnumDecl = nullptr) : + hdrgen(hdrgen), + ddoc(ddoc), + fullDump(fullDump), + importcHdr(importcHdr), + doFuncBodies(doFuncBodies), + vcg_ast(vcg_ast), + fullQual(fullQual), + tpltMember(tpltMember), + autoMember(autoMember), + forStmtInit(forStmtInit), + insideFuncBody(insideFuncBody), + insideAggregate(insideAggregate), + declstring(declstring), + inEnumDecl(inEnumDecl) + {} +}; + +enum : int32_t { TEST_EMIT_ALL = 0 }; + +extern void genhdrfile(Module* m, bool doFuncBodies, OutBuffer& buf); + +extern void moduleToBuffer(OutBuffer& buf, bool vcg_ast, Module* m); + +extern const char* parametersTypeToChars(ParameterList pl); + +extern const char* toChars(const Statement* const s); + +enum class InitKind : uint8_t +{ + void_ = 0u, + default_ = 1u, + error = 2u, + struct_ = 3u, + array = 4u, + exp = 5u, + C_ = 6u, +}; + +class Initializer : public ASTNode +{ +public: + Loc loc; + InitKind kind; + DYNCAST dyncast() const override; + ErrorInitializer* isErrorInitializer(); + VoidInitializer* isVoidInitializer(); + DefaultInitializer* isDefaultInitializer(); + StructInitializer* isStructInitializer(); + ArrayInitializer* isArrayInitializer(); + ExpInitializer* isExpInitializer(); + CInitializer* isCInitializer(); + void accept(Visitor* v) override; +}; + +class ArrayInitializer final : public Initializer +{ +public: + Array index; + Array value; + uint32_t dim; + Type* type; + bool sem; + bool isCarray; + bool isAssociativeArray() const; + void accept(Visitor* v) override; +}; + +class CInitializer final : public Initializer +{ +public: + Array initializerList; + Type* type; + bool sem; + void accept(Visitor* v) override; +}; + +class DefaultInitializer final : public Initializer +{ +public: + Type* type; + void accept(Visitor* v) override; +}; + +class ErrorInitializer final : public Initializer +{ +public: + void accept(Visitor* v) override; +}; + +class ExpInitializer final : public Initializer +{ +public: + bool expandTuples; + Expression* exp; + void accept(Visitor* v) override; +}; + +enum class NeedInterpret +{ + INITnointerpret = 0, + INITinterpret = 1, +}; + +class StructInitializer final : public Initializer +{ +public: + Array field; + Array value; + void accept(Visitor* v) override; +}; + +class VoidInitializer final : public Initializer +{ +public: + Type* type; + void accept(Visitor* v) override; +}; + +extern Initializer* initializerSemantic(Initializer* init, Scope* sc, Type*& tx, NeedInterpret needInterpret); + +extern Expression* initializerToExpression(Initializer* init, Type* itype = nullptr, const bool isCfile = false); + +enum class Covariant +{ + distinct = 0, + yes = 1, + no = 2, + fwdref = 3, +}; + +enum class DotExpFlag +{ + none = 0, + gag = 1, + noDeref = 2, + noAliasThis = 4, +}; + +enum : int32_t { LOGDEFAULTINIT = 0 }; + +enum : int32_t { LOGDOTEXP = 0 }; + +class Parameter final : public ASTNode +{ +public: + Loc loc; + StorageClass storageClass; + Type* type; + Identifier* ident; + Expression* defaultArg; + UserAttributeDeclaration* userAttribDecl; + static Parameter* create(const Loc& loc, StorageClass storageClass, Type* type, Identifier* ident, Expression* defaultArg, UserAttributeDeclaration* userAttribDecl); + Parameter* syntaxCopy(); + Type* isLazyArray(); + bool isLazy() const; + bool isReference() const; + DYNCAST dyncast() const override; + void accept(Visitor* v) override; + static size_t dim(Array* parameters); + static Parameter* getNth(Array* parameters, size_t nth); + const char* toChars() const override; + bool isCovariant(bool returnByRef, const Parameter* const p) const; +}; + +enum class RET +{ + regs = 1, + stack = 2, +}; + +enum : uint64_t { SIZE_INVALID = 18446744073709551615LLU }; + +enum class ScopeRef +{ + None = 0, + Scope = 1, + ReturnScope = 2, + Ref = 3, + ReturnRef = 4, + RefScope = 5, + ReturnRef_Scope = 6, + Ref_ReturnScope = 7, + Return = 8, +}; + +enum class TRUSTformat +{ + TRUSTformatDefault = 0, + TRUSTformatSystem = 1, +}; + +class TypeNext : public Type +{ +public: + Type* next; + int32_t hasWild() const final override; + Type* nextOf() final override; + Type* makeConst() final override; + Type* makeImmutable() final override; + Type* makeShared() final override; + Type* makeSharedConst() final override; + Type* makeWild() final override; + Type* makeWildConst() final override; + Type* makeSharedWild() final override; + Type* makeSharedWildConst() final override; + Type* makeMutable() final override; + MATCH constConv(Type* to) override; + uint8_t deduceWild(Type* t, bool isRef) final override; + void transitive(); + void accept(Visitor* v) override; +}; + +class TypeArray : public TypeNext +{ +public: + void accept(Visitor* v) override; +}; + +class TypeAArray final : public TypeArray +{ +public: + Type* index; + Loc loc; + static TypeAArray* create(Type* t, Type* index); + const char* kind() const override; + TypeAArray* syntaxCopy() override; + uinteger_t size(const Loc& loc) override; + bool isZeroInit(const Loc& loc) override; + bool isBoolean() override; + bool hasPointers() override; + MATCH implicitConvTo(Type* to) override; + MATCH constConv(Type* to) override; + void accept(Visitor* v) override; +}; + +class TypeBasic final : public Type +{ +public: + const char* dstring; + uint32_t flags; + const char* kind() const override; + TypeBasic* syntaxCopy() override; + uinteger_t size(const Loc& loc) override; + uint32_t alignsize() override; + bool isintegral() override; + bool isfloating() override; + bool isreal() override; + bool isimaginary() override; + bool iscomplex() override; + bool isscalar() override; + bool isunsigned() override; + MATCH implicitConvTo(Type* to) override; + bool isZeroInit(const Loc& loc) override; + TypeBasic* isTypeBasic() override; + void accept(Visitor* v) override; +}; + +enum class AliasThisRec +{ + no = 0, + yes = 1, + fwdref = 2, + typeMask = 3, + tracing = 4, + tracingDT = 8, +}; + +class TypeClass final : public Type +{ +public: + ClassDeclaration* sym; + AliasThisRec att; + CPPMANGLE cppmangle; + const char* kind() const override; + uinteger_t size(const Loc& loc) override; + TypeClass* syntaxCopy() override; + Dsymbol* toDsymbol(Scope* sc) override; + ClassDeclaration* isClassHandle() override; + bool isBaseOf(Type* t, int32_t* poffset) override; + MATCH implicitConvTo(Type* to) override; + MATCH constConv(Type* to) override; + uint8_t deduceWild(Type* t, bool isRef) override; + Type* toHeadMutable() override; + bool isZeroInit(const Loc& loc) override; + bool isscope() override; + bool isBoolean() override; + bool hasPointers() override; + void accept(Visitor* v) override; +}; + +class TypeDArray final : public TypeArray +{ +public: + const char* kind() const override; + TypeDArray* syntaxCopy() override; + uinteger_t size(const Loc& loc) override; + uint32_t alignsize() override; + bool isString() override; + bool isZeroInit(const Loc& loc) override; + bool isBoolean() override; + MATCH implicitConvTo(Type* to) override; + bool hasPointers() override; + void accept(Visitor* v) override; +}; + +class TypeDelegate final : public TypeNext +{ +public: + static TypeDelegate* create(TypeFunction* t); + const char* kind() const override; + TypeDelegate* syntaxCopy() override; + Type* addStorageClass(StorageClass stc) override; + uinteger_t size(const Loc& loc) override; + uint32_t alignsize() override; + MATCH implicitConvTo(Type* to) override; + bool isZeroInit(const Loc& loc) override; + bool isBoolean() override; + bool hasPointers() override; + void accept(Visitor* v) override; +}; + +class TypeEnum final : public Type +{ +public: + EnumDeclaration* sym; + const char* kind() const override; + TypeEnum* syntaxCopy() override; + uinteger_t size(const Loc& loc) override; + Type* memType(const Loc& loc = Loc::initial); + uint32_t alignsize() override; + Dsymbol* toDsymbol(Scope* sc) override; + bool isintegral() override; + bool isfloating() override; + bool isreal() override; + bool isimaginary() override; + bool iscomplex() override; + bool isscalar() override; + bool isunsigned() override; + bool isBoolean() override; + bool isString() override; + bool isAssignable() override; + bool needsDestruction() override; + bool needsCopyOrPostblit() override; + bool needsNested() override; + MATCH implicitConvTo(Type* to) override; + MATCH constConv(Type* to) override; + bool isZeroInit(const Loc& loc) override; + bool hasPointers() override; + bool hasVoidInitPointers() override; + bool hasSystemFields() override; + bool hasInvariant() override; + Type* nextOf() override; + void accept(Visitor* v) override; +}; + +class TypeError final : public Type +{ +public: + const char* kind() const override; + TypeError* syntaxCopy() override; + uinteger_t size(const Loc& loc) override; + Expression* defaultInitLiteral(const Loc& loc) override; + void accept(Visitor* v) override; +}; + +enum class TRUST : uint8_t +{ + default_ = 0u, + system = 1u, + trusted = 2u, + safe = 3u, +}; + +class TypeFunction final : public TypeNext +{ +public: + ParameterList parameterList; +private: + struct BitFields final { - } + bool isnothrow; + bool isnogc; + bool isproperty; + bool isref; + bool isreturn; + bool isScopeQual; + bool isreturninferred; + bool isscopeinferred; + bool islive; + bool incomplete; + bool isInOutParam; + bool isInOutQual; + bool isctor; + bool isreturnscope; + BitFields() : + isnothrow(), + isnogc(), + isproperty(), + isref(), + isreturn(), + isScopeQual(), + isreturninferred(), + isscopeinferred(), + islive(), + incomplete(), + isInOutParam(), + isInOutQual(), + isctor(), + isreturnscope() + { + } + BitFields(bool isnothrow, bool isnogc = false, bool isproperty = false, bool isref = false, bool isreturn = false, bool isScopeQual = false, bool isreturninferred = false, bool isscopeinferred = false, bool islive = false, bool incomplete = false, bool isInOutParam = false, bool isInOutQual = false, bool isctor = false, bool isreturnscope = false) : + isnothrow(isnothrow), + isnogc(isnogc), + isproperty(isproperty), + isref(isref), + isreturn(isreturn), + isScopeQual(isScopeQual), + isreturninferred(isreturninferred), + isscopeinferred(isscopeinferred), + islive(islive), + incomplete(incomplete), + isInOutParam(isInOutParam), + isInOutQual(isInOutQual), + isctor(isctor), + isreturnscope(isreturnscope) + {} + }; + +public: + bool isnothrow() const; + bool isnothrow(bool v); + bool isnogc() const; + bool isnogc(bool v); + bool isproperty() const; + bool isproperty(bool v); + bool isref() const; + bool isref(bool v); + bool isreturn() const; + bool isreturn(bool v); + bool isScopeQual() const; + bool isScopeQual(bool v); + bool isreturninferred() const; + bool isreturninferred(bool v); + bool isscopeinferred() const; + bool isscopeinferred(bool v); + bool islive() const; + bool islive(bool v); + bool incomplete() const; + bool incomplete(bool v); + bool isInOutParam() const; + bool isInOutParam(bool v); + bool isInOutQual() const; + bool isInOutQual(bool v); + bool isctor() const; + bool isctor(bool v); + bool isreturnscope() const; + bool isreturnscope(bool v); +private: + uint16_t bitFields; +public: + LINK linkage; + TRUST trust; + PURE purity; + int8_t inuse; + Array* fargs; + static TypeFunction* create(Array* parameters, Type* treturn, uint8_t varargs, LINK linkage, StorageClass stc = 0); + const char* kind() const override; + TypeFunction* syntaxCopy() override; + void purityLevel(); + bool hasLazyParameters(); + bool isDstyleVariadic() const; + StorageClass parameterStorageClass(Type* tthis, Parameter* p, Array* outerVars = nullptr, bool indirect = false); + Type* addStorageClass(StorageClass stc) override; + Type* substWildTo(uint32_t __param_0_) override; + MATCH constConv(Type* to) override; + bool iswild() const; + void accept(Visitor* v) override; +}; + +class TypeQualified : public Type +{ +public: + Loc loc; + Array idents; + TypeQualified* syntaxCopy() override = 0; + uinteger_t size(const Loc& loc) override; + void accept(Visitor* v) override; +}; + +class TypeIdentifier final : public TypeQualified +{ +public: + Identifier* ident; + Dsymbol* originalSymbol; + static TypeIdentifier* create(const Loc& loc, Identifier* ident); + const char* kind() const override; + TypeIdentifier* syntaxCopy() override; + Dsymbol* toDsymbol(Scope* sc) override; + void accept(Visitor* v) override; +}; + +class TypeInstance final : public TypeQualified +{ +public: + TemplateInstance* tempinst; + const char* kind() const override; + TypeInstance* syntaxCopy() override; + Dsymbol* toDsymbol(Scope* sc) override; + void accept(Visitor* v) override; +}; + +class TypeMixin final : public Type +{ +public: + Loc loc; + Array* exps; + RootObject* obj; + const char* kind() const override; + TypeMixin* syntaxCopy() override; + Dsymbol* toDsymbol(Scope* sc) override; + void accept(Visitor* v) override; +}; + +class TypeNoreturn final : public Type +{ +public: + const char* kind() const override; + TypeNoreturn* syntaxCopy() override; + MATCH implicitConvTo(Type* to) override; + MATCH constConv(Type* to) override; + bool isBoolean() override; + uinteger_t size(const Loc& loc) override; + uint32_t alignsize() override; + void accept(Visitor* v) override; +}; + +class TypeNull final : public Type +{ +public: + const char* kind() const override; + TypeNull* syntaxCopy() override; + MATCH implicitConvTo(Type* to) override; + bool hasPointers() override; + bool isBoolean() override; + uinteger_t size(const Loc& loc) override; + void accept(Visitor* v) override; }; -class Visitor : public ParseTimeVisitor +class TypePointer final : public TypeNext { public: - using ParseTimeVisitor::visit; - virtual void visit(ErrorStatement* s); - virtual void visit(PeelStatement* s); - virtual void visit(UnrolledLoopStatement* s); - virtual void visit(SwitchErrorStatement* s); - virtual void visit(DebugStatement* s); - virtual void visit(DtorExpStatement* s); - virtual void visit(ForwardingStatement* s); - virtual void visit(OverloadSet* s); - virtual void visit(LabelDsymbol* s); - virtual void visit(WithScopeSymbol* s); - virtual void visit(ArrayScopeSymbol* s); - virtual void visit(OverDeclaration* s); - virtual void visit(SymbolDeclaration* s); - virtual void visit(ForwardingAttribDeclaration* s); - virtual void visit(ThisDeclaration* s); - virtual void visit(TypeInfoDeclaration* s); - virtual void visit(TypeInfoStructDeclaration* s); - virtual void visit(TypeInfoClassDeclaration* s); - virtual void visit(TypeInfoInterfaceDeclaration* s); - virtual void visit(TypeInfoPointerDeclaration* s); - virtual void visit(TypeInfoArrayDeclaration* s); - virtual void visit(TypeInfoStaticArrayDeclaration* s); - virtual void visit(TypeInfoAssociativeArrayDeclaration* s); - virtual void visit(TypeInfoEnumDeclaration* s); - virtual void visit(TypeInfoFunctionDeclaration* s); - virtual void visit(TypeInfoDelegateDeclaration* s); - virtual void visit(TypeInfoTupleDeclaration* s); - virtual void visit(TypeInfoConstDeclaration* s); - virtual void visit(TypeInfoInvariantDeclaration* s); - virtual void visit(TypeInfoSharedDeclaration* s); - virtual void visit(TypeInfoWildDeclaration* s); - virtual void visit(TypeInfoVectorDeclaration* s); - virtual void visit(FuncAliasDeclaration* s); - virtual void visit(ErrorInitializer* i); - virtual void visit(ErrorExp* e); - virtual void visit(ComplexExp* e); - virtual void visit(StructLiteralExp* e); - virtual void visit(CompoundLiteralExp* e); - virtual void visit(ObjcClassReferenceExp* e); - virtual void visit(SymOffExp* e); - virtual void visit(OverExp* e); - virtual void visit(HaltExp* e); - virtual void visit(DotTemplateExp* e); - virtual void visit(DotVarExp* e); - virtual void visit(DelegateExp* e); - virtual void visit(DotTypeExp* e); - virtual void visit(VectorExp* e); - virtual void visit(VectorArrayExp* e); - virtual void visit(SliceExp* e); - virtual void visit(ArrayLengthExp* e); - virtual void visit(DelegatePtrExp* e); - virtual void visit(DelegateFuncptrExp* e); - virtual void visit(DotExp* e); - virtual void visit(IndexExp* e); - virtual void visit(ConstructExp* e); - virtual void visit(BlitExp* e); - virtual void visit(RemoveExp* e); - virtual void visit(ClassReferenceExp* e); - virtual void visit(VoidInitExp* e); - virtual void visit(ThrownExceptionExp* e); - virtual void visit(LoweredAssignExp* e); + static TypePointer* create(Type* t); + const char* kind() const override; + TypePointer* syntaxCopy() override; + uinteger_t size(const Loc& loc) override; + MATCH implicitConvTo(Type* to) override; + MATCH constConv(Type* to) override; + bool isscalar() override; + bool isZeroInit(const Loc& loc) override; + bool hasPointers() override; + void accept(Visitor* v) override; }; -class StoppableVisitor : public Visitor +class TypeReference final : public TypeNext { public: - using Visitor::visit; - bool stop; + const char* kind() const override; + TypeReference* syntaxCopy() override; + uinteger_t size(const Loc& loc) override; + bool isZeroInit(const Loc& loc) override; + void accept(Visitor* v) override; }; -struct TargetC final +class TypeReturn final : public TypeQualified { - enum class Runtime : uint8_t - { - Unspecified = 0u, - Bionic = 1u, - DigitalMars = 2u, - Glibc = 3u, - Microsoft = 4u, - Musl = 5u, - Newlib = 6u, - UClibc = 7u, - WASI = 8u, - }; - - enum class BitFieldStyle : uint8_t - { - Unspecified = 0u, - DM = 1u, - MS = 2u, - Gcc_Clang = 3u, - }; - - bool crtDestructorsSupported; - uint8_t boolsize; - uint8_t shortsize; - uint8_t intsize; - uint8_t longsize; - uint8_t long_longsize; - uint8_t long_doublesize; - uint8_t wchar_tsize; - Runtime runtime; - BitFieldStyle bitFieldStyle; - TargetC() : - crtDestructorsSupported(true), - boolsize(), - shortsize(), - intsize(), - longsize(), - long_longsize(), - long_doublesize(), - wchar_tsize() - { - } - TargetC(bool crtDestructorsSupported, uint8_t boolsize = 0u, uint8_t shortsize = 0u, uint8_t intsize = 0u, uint8_t longsize = 0u, uint8_t long_longsize = 0u, uint8_t long_doublesize = 0u, uint8_t wchar_tsize = 0u, Runtime runtime = (Runtime)0u, BitFieldStyle bitFieldStyle = (BitFieldStyle)0u) : - crtDestructorsSupported(crtDestructorsSupported), - boolsize(boolsize), - shortsize(shortsize), - intsize(intsize), - longsize(longsize), - long_longsize(long_longsize), - long_doublesize(long_doublesize), - wchar_tsize(wchar_tsize), - runtime(runtime), - bitFieldStyle(bitFieldStyle) - {} +public: + const char* kind() const override; + TypeReturn* syntaxCopy() override; + Dsymbol* toDsymbol(Scope* sc) override; + void accept(Visitor* v) override; }; -struct TargetCPP final +class TypeSArray final : public TypeArray { - enum class Runtime : uint8_t - { - Unspecified = 0u, - Clang = 1u, - DigitalMars = 2u, - Gcc = 3u, - Microsoft = 4u, - Sun = 5u, - }; +public: + Expression* dim; + const char* kind() const override; + TypeSArray* syntaxCopy() override; + bool isIncomplete(); + uinteger_t size(const Loc& loc) override; + uint32_t alignsize() override; + bool isString() override; + bool isZeroInit(const Loc& loc) override; + structalign_t alignment() override; + MATCH constConv(Type* to) override; + MATCH implicitConvTo(Type* to) override; + Expression* defaultInitLiteral(const Loc& loc) override; + bool hasPointers() override; + bool hasSystemFields() override; + bool hasVoidInitPointers() override; + bool hasInvariant() override; + bool needsDestruction() override; + bool needsCopyOrPostblit() override; + bool needsNested() override; + void accept(Visitor* v) override; +}; - bool reverseOverloads; - bool exceptions; - bool twoDtorInVtable; - bool splitVBasetable; - bool wrapDtorInExternD; - Runtime runtime; - const char* toMangle(Dsymbol* s); - const char* typeInfoMangle(ClassDeclaration* cd); - const char* thunkMangle(FuncDeclaration* fd, int32_t offset); - const char* typeMangle(Type* t); - Type* parameterType(Type* t); - bool fundamentalType(const Type* const t, bool& isFundamental); - uint32_t derivedClassOffset(ClassDeclaration* baseClass); - TargetCPP() : - reverseOverloads(), - exceptions(), - twoDtorInVtable(), - splitVBasetable(), - wrapDtorInExternD() - { - } - TargetCPP(bool reverseOverloads, bool exceptions = false, bool twoDtorInVtable = false, bool splitVBasetable = false, bool wrapDtorInExternD = false, Runtime runtime = (Runtime)0u) : - reverseOverloads(reverseOverloads), - exceptions(exceptions), - twoDtorInVtable(twoDtorInVtable), - splitVBasetable(splitVBasetable), - wrapDtorInExternD(wrapDtorInExternD), - runtime(runtime) - {} +class TypeSlice final : public TypeNext +{ +public: + Expression* lwr; + Expression* upr; + const char* kind() const override; + TypeSlice* syntaxCopy() override; + void accept(Visitor* v) override; }; -struct TargetObjC final +class TypeStruct final : public Type { - bool supported; - TargetObjC() : - supported() - { - } - TargetObjC(bool supported) : - supported(supported) - {} +public: + StructDeclaration* sym; + AliasThisRec att; + bool inuse; + static TypeStruct* create(StructDeclaration* sym); + const char* kind() const override; + uinteger_t size(const Loc& loc) override; + uint32_t alignsize() override; + TypeStruct* syntaxCopy() override; + Dsymbol* toDsymbol(Scope* sc) override; + structalign_t alignment() override; + Expression* defaultInitLiteral(const Loc& loc) override; + bool isZeroInit(const Loc& loc) override; + bool isAssignable() override; + bool isBoolean() override; + bool needsDestruction() override; + bool needsCopyOrPostblit() override; + bool needsNested() override; + bool hasPointers() override; + bool hasVoidInitPointers() override; + bool hasSystemFields() override; + bool hasInvariant() override; + MATCH implicitConvTo(Type* to) override; + MATCH constConv(Type* to) override; + uint8_t deduceWild(Type* t, bool isRef) override; + Type* toHeadMutable() override; + void accept(Visitor* v) override; }; -enum class CPU : uint8_t +class TypeTag final : public Type { - x87 = 0u, - mmx = 1u, - sse = 2u, - sse2 = 3u, - sse3 = 4u, - ssse3 = 5u, - sse4_1 = 6u, - sse4_2 = 7u, - avx = 8u, - avx2 = 9u, - avx512 = 10u, - baseline = 11u, - native = 12u, +public: + Loc loc; + TOK tok; + structalign_t packalign; + Identifier* id; + Type* base; + Array* members; + Type* resolved; + uint8_t mod; + const char* kind() const override; + TypeTag* syntaxCopy() override; + void accept(Visitor* v) override; }; -enum class ErrorKind +class TypeTraits final : public Type { - warning = 0, - deprecation = 1, - error = 2, - tip = 3, - message = 4, +public: + Loc loc; + TraitsExp* exp; + RootObject* obj; + const char* kind() const override; + TypeTraits* syntaxCopy() override; + Dsymbol* toDsymbol(Scope* sc) override; + void accept(Visitor* v) override; + uinteger_t size(const Loc& loc) override; }; -typedef _d_real longdouble; - -typedef uint64_t uint64_t; - -class AggregateDeclaration : public ScopeDsymbol +class TypeTuple final : public Type { public: - Type* type; - StorageClass storage_class; - uint32_t structsize; - uint32_t alignsize; - Array fields; - Dsymbol* deferred; - ClassKind classKind; - CPPMANGLE cppmangle; - MangleOverride* pMangleOverride; - Dsymbol* enclosing; - VarDeclaration* vthis; - VarDeclaration* vthis2; - Array invs; - FuncDeclaration* inv; - Dsymbol* ctor; - CtorDeclaration* defaultCtor; - AliasThis* aliasthis; - Array userDtors; - DtorDeclaration* aggrDtor; - DtorDeclaration* dtor; - DtorDeclaration* tidtor; - DtorDeclaration* fieldDtor; - Expression* getRTInfo; - Visibility visibility; - bool noDefaultCtor; - bool disableNew; - Sizeok sizeok; - virtual Scope* newScope(Scope* sc); - void setScope(Scope* sc) final override; - virtual void finalizeSize() = 0; - uinteger_t size(const Loc& loc) final override; - bool fill(const Loc& loc, Array& elements, bool ctorinit); - Type* getType() final override; - bool isDeprecated() const final override; - bool isNested() const; - bool isExport() const final override; - Visibility visible() final override; - Type* handleType(); - bool hasInvariant(); - void* sinit; - AggregateDeclaration* isAggregateDeclaration() final override; + static TypeTuple* empty; + Array* arguments; + static TypeTuple* create(Array* arguments); + static TypeTuple* create(); + static TypeTuple* create(Type* t1); + static TypeTuple* create(Type* t1, Type* t2); + const char* kind() const override; + TypeTuple* syntaxCopy() override; + bool equals(const RootObject* const o) const override; + MATCH implicitConvTo(Type* to) override; void accept(Visitor* v) override; }; -class AliasThis final : public Dsymbol +class TypeTypeof final : public TypeQualified { public: - Identifier* ident; - Dsymbol* sym; - bool isDeprecated_; - AliasThis* syntaxCopy(Dsymbol* s) override; + Expression* exp; + int32_t inuse; const char* kind() const override; - AliasThis* isAliasThis(); + TypeTypeof* syntaxCopy() override; + Dsymbol* toDsymbol(Scope* sc) override; + uinteger_t size(const Loc& loc) override; void accept(Visitor* v) override; - bool isDeprecated() const override; }; -extern TypeTuple* toArgTypes_x86(Type* t); - -extern TypeTuple* toArgTypes_sysv_x64(Type* t); - -extern TypeTuple* toArgTypes_aarch64(Type* t); - -extern bool isHFVA(Type* t, int32_t maxNumElements = 4, Type** rewriteType = nullptr); - -struct structalign_t final +class TypeVector final : public Type { -private: - uint16_t value; - bool pack; public: - bool isDefault() const; - void setDefault(); - bool isUnknown() const; - void setUnknown(); - void set(uint32_t value); - uint32_t get() const; - bool isPack() const; - void setPack(bool pack); - structalign_t() : - value(0u), - pack() - { - } - structalign_t(uint16_t value, bool pack = false) : - value(value), - pack(pack) - {} + Type* basetype; + static TypeVector* create(Type* basetype); + const char* kind() const override; + TypeVector* syntaxCopy() override; + uinteger_t size(const Loc& loc) override; + uint32_t alignsize() override; + bool isintegral() override; + bool isfloating() override; + bool isscalar() override; + bool isunsigned() override; + bool isBoolean() override; + MATCH implicitConvTo(Type* to) override; + Expression* defaultInitLiteral(const Loc& loc) override; + TypeBasic* elementType(); + bool isZeroInit(const Loc& loc) override; + void accept(Visitor* v) override; }; -class AttribDeclaration : public Dsymbol +extern AggregateDeclaration* isAggregate(Type* t); + +class Nspace final : public ScopeDsymbol { public: - Array* decl; - virtual Array* 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 char* comment) override; + Expression* identExp; + Nspace* syntaxCopy(Dsymbol* s) override; + bool hasPointers() override; const char* kind() const override; - bool oneMember(Dsymbol** ps, Identifier* ident) override; - void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion) override; - bool hasPointers() final override; - bool hasStaticCtorOrDtor() final override; - void checkCtorConstInit() final override; - void addObjcSymbols(Array* classes, Array* categories) final override; - AttribDeclaration* isAttribDeclaration() override; + Nspace* isNspace() override; void accept(Visitor* v) override; }; -class StorageClassDeclaration : public AttribDeclaration +enum class STMT : uint8_t +{ + Error = 0u, + Peel = 1u, + Exp = 2u, + DtorExp = 3u, + Mixin = 4u, + Compound = 5u, + CompoundDeclaration = 6u, + CompoundAsm = 7u, + UnrolledLoop = 8u, + Scope = 9u, + Forwarding = 10u, + While = 11u, + Do = 12u, + For = 13u, + Foreach = 14u, + ForeachRange = 15u, + If = 16u, + Conditional = 17u, + StaticForeach = 18u, + Pragma = 19u, + StaticAssert = 20u, + Switch = 21u, + Case = 22u, + CaseRange = 23u, + Default = 24u, + GotoDefault = 25u, + GotoCase = 26u, + SwitchError = 27u, + Return = 28u, + Break = 29u, + Continue = 30u, + Synchronized = 31u, + With = 32u, + TryCatch = 33u, + TryFinally = 34u, + ScopeGuard = 35u, + Throw = 36u, + Debug = 37u, + Goto = 38u, + Label = 39u, + Asm = 40u, + InlineAsm = 41u, + GccAsm = 42u, + Import = 43u, +}; + +class Statement : public ASTNode { public: - StorageClass stc; - StorageClassDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - bool oneMember(Dsymbol** ps, Identifier* ident) final override; - void addMember(Scope* sc, ScopeDsymbol* sds) override; - StorageClassDeclaration* isStorageClassDeclaration() override; + const Loc loc; + const STMT stmt; + DYNCAST dyncast() const final override; + virtual Statement* syntaxCopy(); + static Array* arraySyntaxCopy(Array* a); + virtual Statement* getRelatedLabeled(); + virtual bool hasBreak() const; + virtual bool hasContinue() const; + virtual Statement* last(); void accept(Visitor* v) override; + virtual ReturnStatement* endsWithReturnStatement(); + ErrorStatement* isErrorStatement(); + PeelStatement* isPeelStatement(); + ScopeStatement* isScopeStatement(); + ExpStatement* isExpStatement(); + CompoundStatement* isCompoundStatement(); + ReturnStatement* isReturnStatement(); + IfStatement* isIfStatement(); + ConditionalStatement* isConditionalStatement(); + StaticForeachStatement* isStaticForeachStatement(); + CaseStatement* isCaseStatement(); + DefaultStatement* isDefaultStatement(); + LabelStatement* isLabelStatement(); + GotoStatement* isGotoStatement(); + GotoDefaultStatement* isGotoDefaultStatement(); + GotoCaseStatement* isGotoCaseStatement(); + BreakStatement* isBreakStatement(); + DtorExpStatement* isDtorExpStatement(); + MixinStatement* isMixinStatement(); + ForwardingStatement* isForwardingStatement(); + DoStatement* isDoStatement(); + WhileStatement* isWhileStatement(); + ForStatement* isForStatement(); + ForeachStatement* isForeachStatement(); + SwitchStatement* isSwitchStatement(); + ContinueStatement* isContinueStatement(); + WithStatement* isWithStatement(); + TryCatchStatement* isTryCatchStatement(); + ThrowStatement* isThrowStatement(); + DebugStatement* isDebugStatement(); + TryFinallyStatement* isTryFinallyStatement(); + ScopeGuardStatement* isScopeGuardStatement(); + SwitchErrorStatement* isSwitchErrorStatement(); + UnrolledLoopStatement* isUnrolledLoopStatement(); + ForeachRangeStatement* isForeachRangeStatement(); + CompoundDeclarationStatement* isCompoundDeclarationStatement(); + CompoundAsmStatement* isCompoundAsmStatement(); + PragmaStatement* isPragmaStatement(); + StaticAssertStatement* isStaticAssertStatement(); + CaseRangeStatement* isCaseRangeStatement(); + SynchronizedStatement* isSynchronizedStatement(); + AsmStatement* isAsmStatement(); + InlineAsmStatement* isInlineAsmStatement(); + GccAsmStatement* isGccAsmStatement(); + ImportStatement* isImportStatement(); }; -class DeprecatedDeclaration final : public StorageClassDeclaration +class AsmStatement : public Statement { public: - Expression* msg; - const char* msgstr; - DeprecatedDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - void setScope(Scope* sc) override; + Token* tokens; + bool caseSensitive; + AsmStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class LinkDeclaration final : public AttribDeclaration +class BreakStatement final : public Statement { public: - LINK linkage; - static LinkDeclaration* create(const Loc& loc, LINK p, Array* decl); - LinkDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - const char* toChars() const override; + Identifier* ident; + BreakStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class CPPMangleDeclaration final : public AttribDeclaration +class CaseRangeStatement final : public Statement { public: - CPPMANGLE cppmangle; - CPPMangleDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - void setScope(Scope* sc) override; - const char* toChars() const override; + Expression* first; + Expression* last; + Statement* statement; + CaseRangeStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class CPPNamespaceDeclaration final : public AttribDeclaration +class CaseStatement final : public Statement { public: Expression* exp; - CPPNamespaceDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - const char* toChars() const override; + Statement* statement; + int32_t index; + VarDeclaration* lastVar; + void* extra; + CaseStatement* syntaxCopy() override; void accept(Visitor* v) override; - CPPNamespaceDeclaration* isCPPNamespaceDeclaration() override; }; -class VisibilityDeclaration final : public AttribDeclaration +class Catch final : public RootObject { public: - Visibility visibility; - _d_dynamicArray< Identifier* > pkg_identifiers; - 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 __param_0_) override; - VisibilityDeclaration* isVisibilityDeclaration() override; - void accept(Visitor* v) override; + const Loc loc; + Type* type; + Identifier* ident; + Statement* handler; + VarDeclaration* var; + bool errors; + bool internalCatch; + Catch* syntaxCopy(); }; -class AlignDeclaration final : public AttribDeclaration +class CompoundStatement : public Statement { public: - Array* exps; - structalign_t salign; - AlignDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; + Array* statements; + static CompoundStatement* create(const Loc& loc, Statement* s1, Statement* s2); + CompoundStatement* syntaxCopy() override; + ReturnStatement* endsWithReturnStatement() final override; + Statement* last() final override; void accept(Visitor* v) override; }; -class AnonDeclaration final : public AttribDeclaration +class CompoundAsmStatement final : public CompoundStatement { public: - bool isunion; - int32_t sem; - uint32_t anonoffset; - uint32_t anonstructsize; - uint32_t anonalignsize; - AnonDeclaration* syntaxCopy(Dsymbol* s) override; - void setScope(Scope* sc) override; - void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion) override; - const char* kind() const override; - AnonDeclaration* isAnonDeclaration() override; + StorageClass stc; + CompoundAsmStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class PragmaDeclaration final : public AttribDeclaration +class CompoundDeclarationStatement final : public CompoundStatement { public: - Array* args; - PragmaDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - const char* kind() const override; + CompoundDeclarationStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class ConditionalDeclaration : public AttribDeclaration +class ConditionalStatement final : public Statement { public: Condition* condition; - Array* elsedecl; - ConditionalDeclaration* syntaxCopy(Dsymbol* s) override; - bool oneMember(Dsymbol** ps, Identifier* ident) final override; - Array* include(Scope* sc) override; - void addComment(const char* comment) final override; - void setScope(Scope* sc) override; - void accept(Visitor* v) override; -}; - -class StaticIfDeclaration final : public ConditionalDeclaration -{ -public: - ScopeDsymbol* scopesym; -private: - bool addisdone; - bool onStack; -public: - StaticIfDeclaration* syntaxCopy(Dsymbol* s) override; - Array* include(Scope* sc) override; - void addMember(Scope* sc, ScopeDsymbol* sds) override; - void setScope(Scope* sc) override; - void importAll(Scope* sc) override; - const char* kind() const override; - StaticIfDeclaration* isStaticIfDeclaration() override; + Statement* ifbody; + Statement* elsebody; + ConditionalStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class StaticForeachDeclaration final : public AttribDeclaration +class ContinueStatement final : public Statement { public: - StaticForeach* sfe; - ScopeDsymbol* scopesym; - bool onStack; - bool cached; - Array* cache; - StaticForeachDeclaration* syntaxCopy(Dsymbol* s) override; - bool oneMember(Dsymbol** ps, Identifier* ident) override; - Array* include(Scope* sc) override; - void addMember(Scope* sc, ScopeDsymbol* sds) override; - void addComment(const char* comment) override; - void setScope(Scope* sc) override; - void importAll(Scope* sc) override; - const char* kind() const override; + Identifier* ident; + ContinueStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class ForwardingAttribDeclaration final : public AttribDeclaration +class DebugStatement final : public Statement { public: - ForwardingScopeDsymbol* sym; - ForwardingAttribDeclaration(Array* decl); - Scope* newScope(Scope* sc) override; - void addMember(Scope* sc, ScopeDsymbol* sds) override; - ForwardingAttribDeclaration* isForwardingAttribDeclaration() override; + Statement* statement; + DebugStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class MixinDeclaration final : public AttribDeclaration +class DefaultStatement final : public Statement { public: - Array* exps; - ScopeDsymbol* scopesym; - bool compiled; - MixinDeclaration* syntaxCopy(Dsymbol* s) override; - void addMember(Scope* sc, ScopeDsymbol* sds) override; - void setScope(Scope* sc) override; - const char* kind() const override; - MixinDeclaration* isMixinDeclaration() override; + Statement* statement; + VarDeclaration* lastVar; + DefaultStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class UserAttributeDeclaration final : public AttribDeclaration +class DoStatement final : public Statement { public: - Array* atts; - UserAttributeDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - void setScope(Scope* sc) override; - Array* getAttributes(); - const char* kind() const override; + Statement* _body; + Expression* condition; + Loc endloc; + DoStatement* syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; - static bool isGNUABITag(Expression* e); - static void checkGNUABITag(Dsymbol* sym, LINK linkage); -}; - -extern BUILTIN isBuiltin(FuncDeclaration* fd); - -extern Expression* eval_builtin(const Loc& loc, FuncDeclaration* fd, Array* arguments); - -extern bool includeImports; - -extern Array includeModulePatterns; - -extern Array compiledImports; - -struct Compiler final -{ - static Expression* paintAsType(UnionExp* pue, Expression* e, Type* type); - static void onParseModule(Module* m); - static bool onImport(Module* m); - Compiler() - { - } }; -class Condition : public ASTNode +class ExpStatement : public Statement { public: - Loc loc; - Include inc; - DYNCAST dyncast() const final override; - virtual Condition* syntaxCopy() = 0; - virtual int32_t include(Scope* sc) = 0; - virtual DebugCondition* isDebugCondition(); - virtual VersionCondition* isVersionCondition(); - virtual StaticIfCondition* isStaticIfCondition(); + Expression* exp; + static ExpStatement* create(const Loc& loc, Expression* exp); + ExpStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class StaticForeach final : public RootObject -{ -public: - Loc loc; - ForeachStatement* aggrfe; - ForeachRangeStatement* rangefe; - bool needExpansion; -}; - -class DVCondition : public Condition +class DtorExpStatement final : public ExpStatement { public: - uint32_t level; - Identifier* ident; - Module* mod; - DVCondition* syntaxCopy() final override; + VarDeclaration* var; + DtorExpStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class DebugCondition final : public DVCondition +class ErrorStatement final : public Statement { public: - static void addGlobalIdent(const char* ident); - int32_t include(Scope* sc) override; - DebugCondition* isDebugCondition() override; + ErrorStatement* syntaxCopy() override; void accept(Visitor* v) override; - const char* toChars() const override; }; -class VersionCondition final : public DVCondition +class ForStatement final : public Statement { public: - static void addGlobalIdent(const char* ident); - static void addPredefinedGlobalIdent(const char* ident); - int32_t include(Scope* sc) override; - VersionCondition* isVersionCondition() override; + Statement* _init; + Expression* condition; + Expression* increment; + Statement* _body; + Loc endloc; + Statement* relatedLabeled; + ForStatement* syntaxCopy() override; + Statement* getRelatedLabeled() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; - const char* toChars() const override; }; -class StaticIfCondition final : public Condition +class ForeachRangeStatement final : public Statement { public: - Expression* exp; - StaticIfCondition* syntaxCopy() override; - int32_t include(Scope* sc) override; + TOK op; + Parameter* prm; + Expression* lwr; + Expression* upr; + Statement* _body; + Loc endloc; + VarDeclaration* key; + ForeachRangeStatement* syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; - StaticIfCondition* isStaticIfCondition() override; - const char* toChars() const override; }; -extern const char* toCppMangleItanium(Dsymbol* s); - -extern const char* cppTypeInfoMangleItanium(Dsymbol* s); - -extern const char* cppThunkMangleItanium(FuncDeclaration* fd, int32_t offset); - -extern const char* toCppMangleMSVC(Dsymbol* s); - -extern const char* cppTypeInfoMangleMSVC(Dsymbol* s); - -extern const char* toCppMangleDMC(Dsymbol* s); - -extern const char* cppTypeInfoMangleDMC(Dsymbol* s); - -extern FileName preprocess(FileName csrcfile, const Loc& loc, bool& ifile, OutBuffer* defines); - -class ClassReferenceExp final : public Expression +class ForeachStatement final : public Statement { public: - StructLiteralExp* value; - ClassDeclaration* originalClass(); - int32_t findFieldIndexByName(VarDeclaration* v); + TOK op; + Array* parameters; + Expression* aggr; + Statement* _body; + Loc endloc; + VarDeclaration* key; + VarDeclaration* value; + FuncDeclaration* func; + Array* cases; + Array* gotos; + ForeachStatement* syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; }; -class ThrownExceptionExp final : public Expression +class ForwardingStatement final : public Statement { public: - ClassReferenceExp* thrown; - const char* toChars() const override; + ForwardingScopeDsymbol* sym; + Statement* statement; + ForwardingStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class CTFEExp final : public Expression +class GccAsmStatement final : public AsmStatement { public: - const char* toChars() const override; + StorageClass stc; + Expression* insn; + Array* args; + uint32_t outputargs; + Array* names; + Array* constraints; + Array* clobbers; + Array* labels; + Array* gotos; + GccAsmStatement* syntaxCopy() override; + void accept(Visitor* v) override; }; -extern MATCH implicitConvTo(Expression* e, Type* t); - -struct BaseClass final +class GotoCaseStatement final : public Statement { - Type* type; - ClassDeclaration* sym; - uint32_t offset; - Array vtbl; - _d_dynamicArray< BaseClass > baseInterfaces; - bool fillVtbl(ClassDeclaration* cd, Array* vtbl, int32_t newinstance); - BaseClass() : - type(), - sym(), - offset(), - vtbl(), - baseInterfaces() - { - } +public: + Expression* exp; + CaseStatement* cs; + GotoCaseStatement* syntaxCopy() override; + void accept(Visitor* v) override; }; -class ClassDeclaration : public AggregateDeclaration +class GotoDefaultStatement final : public Statement { public: - static ClassDeclaration* object; - static ClassDeclaration* throwable; - static ClassDeclaration* exception; - static ClassDeclaration* errorException; - static ClassDeclaration* cpp_type_info_ptr; - ClassDeclaration* baseClass; - FuncDeclaration* staticCtor; - FuncDeclaration* staticDtor; - Array vtbl; - Array vtblFinal; - Array* baseclasses; - _d_dynamicArray< BaseClass* > interfaces; - Array* vtblInterfaces; - TypeInfoClassDeclaration* vclassinfo; - bool com; - bool stack; - int32_t cppDtorVtblIndex; -private: - bool inuse; -public: - ThreeState isabstract; - Baseok baseok; - ObjcClassDeclaration objc; - Symbol* cpp_type_info_ptr_sym; - static ClassDeclaration* create(const Loc& loc, Identifier* id, Array* baseclasses, Array* members, bool inObject); - const char* toPrettyChars(bool qualifyTypes = false) override; - ClassDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - enum : int32_t { OFFSET_RUNTIME = 1985229328 }; - - enum : int32_t { OFFSET_FWDREF = 1985229329 }; - - virtual bool isBaseOf(ClassDeclaration* cd, int32_t* poffset); - bool isBaseInfoComplete() const; - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 8) final override; - void finalizeSize() final override; - bool hasMonitor(); - bool isFuncHidden(FuncDeclaration* fd); - bool isCOMclass() const; - virtual bool isCOMinterface() const; - bool isCPPclass() const; - virtual bool isCPPinterface() const; - bool isAbstract(); - virtual int32_t vtblOffset() const; - const char* kind() const override; - void addObjcSymbols(Array* classes, Array* categories) final override; - Dsymbol* vtblsym; - Dsymbol* vtblSymbol(); - ClassDeclaration* isClassDeclaration() final override; + SwitchStatement* sw; + GotoDefaultStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class InterfaceDeclaration final : public ClassDeclaration +class GotoStatement final : public Statement { public: - InterfaceDeclaration* syntaxCopy(Dsymbol* s) override; - Scope* newScope(Scope* sc) override; - bool isBaseOf(ClassDeclaration* cd, int32_t* poffset) override; - const char* kind() const override; - int32_t vtblOffset() const override; - bool isCPPinterface() const override; - bool isCOMinterface() const override; - InterfaceDeclaration* isInterfaceDeclaration() override; + Identifier* ident; + LabelDsymbol* label; + Statement* tryBody; + TryFinallyStatement* tf; + ScopeGuardStatement* os; + VarDeclaration* lastVar; + bool inCtfeBlock; + GotoStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -extern void ObjectNotFound(Identifier* id); - -class Declaration : public Dsymbol +class IfStatement final : public Statement { public: - Type* type; - Type* originalType; - StorageClass storage_class; - Visibility visibility; - LINK _linkage; - int16_t inuse; - uint8_t adFlags; - enum : int32_t { wasRead = 1 }; - - enum : int32_t { ignoreRead = 2 }; - - enum : int32_t { nounderscore = 4 }; - - enum : int32_t { hidden = 8 }; - - Symbol* isym; - _d_dynamicArray< const char > mangleOverride; - const char* kind() const override; - uinteger_t size(const Loc& loc) final override; - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 8) final override; - bool isStatic() const; - LINK resolvedLinkage() const; - virtual bool isDelete(); - virtual bool isDataseg(); - virtual bool isThreadlocal(); - virtual bool isCodeseg() const; - bool isFinal() const; - virtual bool isAbstract(); - bool isConst() const; - bool isImmutable() const; - bool isWild() const; - bool isAuto() const; - bool isScope() const; - bool isReturn() const; - bool isSynchronized() const; - bool isParameter() const; - bool isDeprecated() const final override; - bool isDisabled() const; - bool isOverride() const; - bool isResult() const; - bool isField() const; - bool isIn() const; - bool isOut() const; - bool isRef() const; - bool isReference() const; - bool isFuture() const; - Visibility visible() final override; - Declaration* isDeclaration() final override; + Parameter* prm; + Expression* condition; + Statement* ifbody; + Statement* elsebody; + VarDeclaration* match; + Loc endloc; + IfStatement* syntaxCopy() override; void accept(Visitor* v) override; + bool isIfCtfeBlock(); }; -class TupleDeclaration final : public Declaration +class ImportStatement final : public Statement { public: - Array* objects; - TypeTuple* tupletype; - bool isexp; - bool building; - TupleDeclaration* syntaxCopy(Dsymbol* s) override; - const char* kind() const override; - Type* getType() override; - Dsymbol* toAlias2() override; - bool needThis() override; - TupleDeclaration* isTupleDeclaration() override; + Array* imports; + ImportStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class AliasDeclaration final : public Declaration -{ -public: - Dsymbol* aliassym; - Dsymbol* overnext; - Dsymbol* _import_; - static AliasDeclaration* create(const Loc& loc, Identifier* id, Type* type); - AliasDeclaration* syntaxCopy(Dsymbol* s) override; - bool overloadInsert(Dsymbol* s) override; - const char* kind() const override; - Type* getType() override; - Dsymbol* toAlias() override; - Dsymbol* toAlias2() override; - bool isOverloadable() const override; - AliasDeclaration* isAliasDeclaration() override; +class InlineAsmStatement final : public AsmStatement +{ +public: + void* asmcode; + uint32_t asmalign; + uint32_t regs; + bool refparam; + bool naked; + InlineAsmStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class OverDeclaration final : public Declaration +class LabelDsymbol final : public Dsymbol { public: - Dsymbol* overnext; - Dsymbol* aliassym; - const char* kind() const override; - bool equals(const RootObject* const o) const override; - bool overloadInsert(Dsymbol* s) override; - bool isOverloadable() const override; - Dsymbol* isUnique(); - OverDeclaration* isOverDeclaration() override; + LabelStatement* statement; + bool deleted; + bool iasm; + bool duplicated; + static LabelDsymbol* create(Identifier* ident); + LabelDsymbol* isLabel() override; void accept(Visitor* v) override; }; -class VarDeclaration : public Declaration +class LabelStatement final : public Statement { public: - Initializer* _init; - Array nestedrefs; - TupleDeclaration* aliasTuple; + Identifier* ident; + Statement* statement; + Statement* tryBody; + TryFinallyStatement* tf; + ScopeGuardStatement* os; VarDeclaration* lastVar; - Expression* edtor; - IntRange* range; - Array* maybes; - uint32_t endlinnum; - uint32_t offset; - uint32_t sequenceNumber; - structalign_t alignment; - enum : uint32_t { AdrOnStackNone = 4294967295u }; + Statement* gotoTarget; + void* extra; + bool breaks; + bool inCtfeBlock; + LabelStatement* syntaxCopy() override; + void accept(Visitor* v) override; +}; - uint32_t ctfeAdrOnStack; - bool isargptr() const; - bool isargptr(bool v); - bool ctorinit() const; - bool ctorinit(bool v); - bool iscatchvar() const; - bool iscatchvar(bool v); - bool isowner() const; - bool isowner(bool v); - bool setInCtorOnly() const; - bool setInCtorOnly(bool v); - bool onstack() const; - bool onstack(bool v); - bool overlapped() const; - bool overlapped(bool v); - bool overlapUnsafe() const; - bool overlapUnsafe(bool v); - bool maybeScope() const; - bool maybeScope(bool v); - bool doNotInferReturn() const; - bool doNotInferReturn(bool v); - bool isArgDtorVar() const; - bool isArgDtorVar(bool v); - bool isCmacro() const; - bool isCmacro(bool v); - bool dllImport() const; - bool dllImport(bool v); - bool dllExport() const; - bool dllExport(bool v); - bool inClosure() const; - bool inClosure(bool v); - bool inAlignSection() const; - bool inAlignSection(bool v); - bool systemInferred() const; - bool systemInferred(bool v); -private: - uint32_t bitFields; +class MixinStatement final : public Statement +{ public: - int8_t canassign; - uint8_t isdataseg; - static VarDeclaration* create(const Loc& loc, Type* type, Identifier* ident, Initializer* _init, StorageClass storage_class = static_cast(STC::undefined_)); - VarDeclaration* syntaxCopy(Dsymbol* s) override; - void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion) override; - const char* kind() const override; - AggregateDeclaration* isThis() final override; - bool needThis() final override; - bool isExport() const final override; - bool isImportedSymbol() const final override; - bool isCtorinit() const; - bool isDataseg() final override; - bool isThreadlocal() final override; - bool isCTFE(); - bool isOverlappedWith(VarDeclaration* v); - bool hasPointers() final override; - bool canTakeAddressOf(); - bool needsScopeDtor(); - void checkCtorConstInit() final override; - Dsymbol* toAlias() final override; - VarDeclaration* isVarDeclaration() final override; + Array* exps; + MixinStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class BitFieldDeclaration : public VarDeclaration +class PeelStatement final : public Statement { public: - Expression* width; - uint32_t fieldWidth; - uint32_t bitOffset; - BitFieldDeclaration* syntaxCopy(Dsymbol* s) override; - BitFieldDeclaration* isBitFieldDeclaration() final override; + Statement* s; void accept(Visitor* v) override; - uint64_t getMinMax(Identifier* id); - void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion) final override; }; -class SymbolDeclaration final : public Declaration +class PragmaStatement final : public Statement { public: - AggregateDeclaration* dsym; - SymbolDeclaration* isSymbolDeclaration() override; + const Identifier* const ident; + Array* args; + Statement* _body; + PragmaStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class TypeInfoDeclaration : public VarDeclaration +class ReturnStatement final : public Statement { public: - Type* tinfo; - static TypeInfoDeclaration* create(Type* tinfo); - TypeInfoDeclaration* syntaxCopy(Dsymbol* s) final override; - const char* toChars() const final override; - TypeInfoDeclaration* isTypeInfoDeclaration() final override; + Expression* exp; + size_t caseDim; + ReturnStatement* syntaxCopy() override; + ReturnStatement* endsWithReturnStatement() override; void accept(Visitor* v) override; }; -class TypeInfoStructDeclaration final : public TypeInfoDeclaration +class ScopeGuardStatement final : public Statement { public: - static TypeInfoStructDeclaration* create(Type* tinfo); + TOK tok; + Statement* statement; + ScopeGuardStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class TypeInfoClassDeclaration final : public TypeInfoDeclaration +class ScopeStatement final : public Statement { public: - static TypeInfoClassDeclaration* create(Type* tinfo); + Statement* statement; + Loc endloc; + ScopeStatement* syntaxCopy() override; + ReturnStatement* endsWithReturnStatement() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; }; -class TypeInfoInterfaceDeclaration final : public TypeInfoDeclaration +class StaticAssertStatement final : public Statement { public: - static TypeInfoInterfaceDeclaration* create(Type* tinfo); + StaticAssert* sa; + StaticAssertStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class TypeInfoPointerDeclaration final : public TypeInfoDeclaration +class StaticForeachStatement final : public Statement { public: - static TypeInfoPointerDeclaration* create(Type* tinfo); + StaticForeach* sfe; + StaticForeachStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class TypeInfoArrayDeclaration final : public TypeInfoDeclaration +class SwitchErrorStatement final : public Statement { public: - static TypeInfoArrayDeclaration* create(Type* tinfo); + Expression* exp; void accept(Visitor* v) override; }; -class TypeInfoStaticArrayDeclaration final : public TypeInfoDeclaration +class SwitchStatement final : public Statement { public: - static TypeInfoStaticArrayDeclaration* create(Type* tinfo); + Parameter* param; + Expression* condition; + Statement* _body; + bool isFinal; + Loc endloc; + bool hasDefault; + bool hasVars; + DefaultStatement* sdefault; + Statement* tryBody; + TryFinallyStatement* tf; + Array gotoCases; + Array* cases; + VarDeclaration* lastVar; + SwitchStatement* syntaxCopy() override; + bool hasBreak() const override; void accept(Visitor* v) override; }; -class TypeInfoAssociativeArrayDeclaration final : public TypeInfoDeclaration +class SynchronizedStatement final : public Statement { public: - static TypeInfoAssociativeArrayDeclaration* create(Type* tinfo); + Expression* exp; + Statement* _body; + SynchronizedStatement* syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; }; -class TypeInfoEnumDeclaration final : public TypeInfoDeclaration +class ThrowStatement final : public Statement { public: - static TypeInfoEnumDeclaration* create(Type* tinfo); + Expression* exp; + bool internalThrow; + ThrowStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class TypeInfoFunctionDeclaration final : public TypeInfoDeclaration +class TryCatchStatement final : public Statement { public: - static TypeInfoFunctionDeclaration* create(Type* tinfo); + Statement* _body; + Array* catches; + Statement* tryBody; + TryCatchStatement* syntaxCopy() override; + bool hasBreak() const override; void accept(Visitor* v) override; }; -class TypeInfoDelegateDeclaration final : public TypeInfoDeclaration +class TryFinallyStatement final : public Statement { public: - static TypeInfoDelegateDeclaration* create(Type* tinfo); + Statement* _body; + Statement* finalbody; + Statement* tryBody; + bool bodyFallsThru; + static TryFinallyStatement* create(const Loc& loc, Statement* _body, Statement* finalbody); + TryFinallyStatement* syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; }; -class TypeInfoTupleDeclaration final : public TypeInfoDeclaration +class UnrolledLoopStatement final : public Statement { public: - static TypeInfoTupleDeclaration* create(Type* tinfo); + Array* statements; + UnrolledLoopStatement* syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; }; -class TypeInfoConstDeclaration final : public TypeInfoDeclaration +class WhileStatement final : public Statement { public: - static TypeInfoConstDeclaration* create(Type* tinfo); + Parameter* param; + Expression* condition; + Statement* _body; + Loc endloc; + WhileStatement* syntaxCopy() override; + bool hasBreak() const override; + bool hasContinue() const override; void accept(Visitor* v) override; }; -class TypeInfoInvariantDeclaration final : public TypeInfoDeclaration +class WithStatement final : public Statement { public: - static TypeInfoInvariantDeclaration* create(Type* tinfo); + Expression* exp; + Statement* _body; + VarDeclaration* wthis; + Loc endloc; + WithStatement* syntaxCopy() override; void accept(Visitor* v) override; }; -class TypeInfoSharedDeclaration final : public TypeInfoDeclaration +class StaticAssert final : public Dsymbol { public: - static TypeInfoSharedDeclaration* create(Type* tinfo); + Expression* exp; + Array* msgs; + StaticAssert* syntaxCopy(Dsymbol* s) override; + bool oneMember(Dsymbol*& ps, Identifier* ident) override; + const char* kind() const override; + StaticAssert* isStaticAssert() override; void accept(Visitor* v) override; }; -class TypeInfoWildDeclaration final : public TypeInfoDeclaration +extern Expression* defaultInit(Type* mt, const Loc& loc, const bool isCfile = false); + +extern Type* merge(Type* type); + +extern Type* typeSemantic(Type* type, const Loc& loc, Scope* sc); + +struct UnionExp final { + #pragma pack(push, 8) +private: + union _AnonStruct_u + { + char exp[29LLU]; + char integerexp[40LLU]; + char errorexp[29LLU]; + char realexp[48LLU]; + char complexexp[64LLU]; + char symoffexp[64LLU]; + char stringexp[51LLU]; + char arrayliteralexp[48LLU]; + char assocarrayliteralexp[56LLU]; + char structliteralexp[76LLU]; + char compoundliteralexp[40LLU]; + char nullexp[29LLU]; + char dotvarexp[49LLU]; + char addrexp[40LLU]; + char indexexp[74LLU]; + char sliceexp[65LLU]; + char vectorexp[53LLU]; + }; + #pragma pack(pop) + + // Ignoring var u alignment 8 + _AnonStruct_u u; public: - static TypeInfoWildDeclaration* create(Type* tinfo); - void accept(Visitor* v) override; + UnionExp() : + u() + { + } }; -class TypeInfoVectorDeclaration final : public TypeInfoDeclaration +enum class MODFlags { -public: - static TypeInfoVectorDeclaration* create(Type* tinfo); - void accept(Visitor* v) override; + none = 0, + const_ = 1, + immutable_ = 4, + shared_ = 2, + wild = 8, + wildconst = 9, + mutable_ = 16, }; -class ThisDeclaration final : public VarDeclaration +enum class STC : uint64_t { -public: - ThisDeclaration* syntaxCopy(Dsymbol* s) override; - ThisDeclaration* isThisDeclaration() override; - void accept(Visitor* v) override; + undefined_ = 0LLU, + static_ = 1LLU, + extern_ = 2LLU, + const_ = 4LLU, + final_ = 8LLU, + abstract_ = 16LLU, + parameter = 32LLU, + field = 64LLU, + override_ = 128LLU, + auto_ = 256LLU, + synchronized_ = 512LLU, + deprecated_ = 1024LLU, + in_ = 2048LLU, + out_ = 4096LLU, + lazy_ = 8192LLU, + foreach_ = 16384LLU, + variadic = 32768LLU, + constscoperef = 65536LLU, + templateparameter = 131072LLU, + ref_ = 262144LLU, + scope_ = 524288LLU, + scopeinferred = 2097152LLU, + return_ = 4194304LLU, + returnScope = 8388608LLU, + returninferred = 16777216LLU, + immutable_ = 33554432LLU, + manifest = 134217728LLU, + nodtor = 268435456LLU, + nothrow_ = 536870912LLU, + pure_ = 1073741824LLU, + tls = 2147483648LLU, + alias_ = 4294967296LLU, + shared_ = 8589934592LLU, + gshared = 17179869184LLU, + wild = 34359738368LLU, + property = 68719476736LLU, + safe = 137438953472LLU, + trusted = 274877906944LLU, + system = 549755813888LLU, + ctfe = 1099511627776LLU, + disable = 2199023255552LLU, + result = 4398046511104LLU, + nodefaultctor = 8796093022208LLU, + temp = 17592186044416LLU, + rvalue = 35184372088832LLU, + nogc = 70368744177664LLU, + autoref = 140737488355328LLU, + inference = 281474976710656LLU, + exptemp = 562949953421312LLU, + future = 1125899906842624LLU, + local = 2251799813685248LLU, + live = 4503599627370496LLU, + register_ = 9007199254740992LLU, + volatile_ = 18014398509481984LLU, + safeGroup = 962072674304LLU, + IOR = 333824LLU, + TYPECTOR = 42983227396LLU, + FUNCATTR = 4575000774574080LLU, + visibleStorageClasses = 7954966262857631LLU, + flowThruAggregate = 962072674304LLU, + flowThruFunction = 18446742978991225440LLU, }; -class EnumDeclaration final : public ScopeDsymbol +struct ASTCodegen final { -public: - Type* type; - Type* memtype; - Visibility visibility; - Expression* maxval; - Expression* minval; - Expression* defaultval; - bool isdeprecated() const; - bool isdeprecated(bool v); - bool added() const; - bool added(bool v); - bool inuse() const; - bool inuse(bool v); -private: - uint8_t bitFields; -public: - 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, int32_t flags = 8) override; - bool isDeprecated() const override; - Visibility visible() override; - bool isSpecial() const; - Expression* getDefaultValue(const Loc& loc); - Type* getMemtype(const Loc& loc); - EnumDeclaration* isEnumDeclaration() override; - Symbol* sinit; - void accept(Visitor* v) override; + using AggregateDeclaration = ::AggregateDeclaration; + using ClassKind = ::ClassKind; + using MangleOverride = ::MangleOverride; + using AliasThis = ::AliasThis; + using AliasDeclarations = ::AliasDeclarations; + using BaseClasses = ::BaseClasses; + using CaseStatements = ::CaseStatements; + using Catches = ::Catches; + using ClassDeclarations = ::ClassDeclarations; + using DesigInits = ::DesigInits; + using Designators = ::Designators; + using Dsymbols = ::Dsymbols; + using DtorDeclarations = ::DtorDeclarations; + using Ensures = ::Ensures; + using Expressions = ::Expressions; + using FuncDeclarations = ::FuncDeclarations; + using GotoCaseStatements = ::GotoCaseStatements; + using GotoStatements = ::GotoStatements; + using Identifiers = ::Identifiers; + using Initializers = ::Initializers; + using Modules = ::Modules; + using Objects = ::Objects; + using Parameters = ::Parameters; + using ReturnStatements = ::ReturnStatements; + using ScopeStatements = ::ScopeStatements; + using SharedStaticDtorDeclarations = ::SharedStaticDtorDeclarations; + using Statements = ::Statements; + using StaticDtorDeclarations = ::StaticDtorDeclarations; + using Strings = ::Strings; + using TemplateInstances = ::TemplateInstances; + using TemplateParameters = ::TemplateParameters; + using Types = ::Types; + using VarDeclarations = ::VarDeclarations; + using AlignDeclaration = ::AlignDeclaration; + using AnonDeclaration = ::AnonDeclaration; + using AttribDeclaration = ::AttribDeclaration; + using CPPMangleDeclaration = ::CPPMangleDeclaration; + using CPPNamespaceDeclaration = ::CPPNamespaceDeclaration; + using ConditionalDeclaration = ::ConditionalDeclaration; + using DeprecatedDeclaration = ::DeprecatedDeclaration; + using ForwardingAttribDeclaration = ::ForwardingAttribDeclaration; + using LinkDeclaration = ::LinkDeclaration; + using MixinDeclaration = ::MixinDeclaration; + using PragmaDeclaration = ::PragmaDeclaration; + using StaticForeachDeclaration = ::StaticForeachDeclaration; + using StaticIfDeclaration = ::StaticIfDeclaration; + using StorageClassDeclaration = ::StorageClassDeclaration; + using UserAttributeDeclaration = ::UserAttributeDeclaration; + using VisibilityDeclaration = ::VisibilityDeclaration; + using Condition = ::Condition; + using DVCondition = ::DVCondition; + using DebugCondition = ::DebugCondition; + using Include = ::Include; + using StaticForeach = ::StaticForeach; + using StaticIfCondition = ::StaticIfCondition; + using VersionCondition = ::VersionCondition; + using BaseClass = ::BaseClass; + using ClassDeclaration = ::ClassDeclaration; + using ClassFlags = ::ClassFlags; + using InterfaceDeclaration = ::InterfaceDeclaration; + using AliasDeclaration = ::AliasDeclaration; + using BitFieldDeclaration = ::BitFieldDeclaration; + using Declaration = ::Declaration; + using MatchAccumulator = ::MatchAccumulator; + using OverDeclaration = ::OverDeclaration; + using SymbolDeclaration = ::SymbolDeclaration; + using ThisDeclaration = ::ThisDeclaration; + using TupleDeclaration = ::TupleDeclaration; + using TypeInfoArrayDeclaration = ::TypeInfoArrayDeclaration; + using TypeInfoAssociativeArrayDeclaration = ::TypeInfoAssociativeArrayDeclaration; + using TypeInfoClassDeclaration = ::TypeInfoClassDeclaration; + using TypeInfoConstDeclaration = ::TypeInfoConstDeclaration; + using TypeInfoDeclaration = ::TypeInfoDeclaration; + using TypeInfoDelegateDeclaration = ::TypeInfoDelegateDeclaration; + using TypeInfoEnumDeclaration = ::TypeInfoEnumDeclaration; + using TypeInfoFunctionDeclaration = ::TypeInfoFunctionDeclaration; + using TypeInfoInterfaceDeclaration = ::TypeInfoInterfaceDeclaration; + using TypeInfoInvariantDeclaration = ::TypeInfoInvariantDeclaration; + using TypeInfoPointerDeclaration = ::TypeInfoPointerDeclaration; + using TypeInfoSharedDeclaration = ::TypeInfoSharedDeclaration; + using TypeInfoStaticArrayDeclaration = ::TypeInfoStaticArrayDeclaration; + using TypeInfoStructDeclaration = ::TypeInfoStructDeclaration; + using TypeInfoTupleDeclaration = ::TypeInfoTupleDeclaration; + using TypeInfoVectorDeclaration = ::TypeInfoVectorDeclaration; + using TypeInfoWildDeclaration = ::TypeInfoWildDeclaration; + using VarDeclaration = ::VarDeclaration; + using EnumDeclaration = ::EnumDeclaration; + using EnumMember = ::EnumMember; + using Import = ::Import; + using ForeachDg = ::ForeachDg; + using Module = ::Module; + using ModuleDeclaration = ::ModuleDeclaration; + using Package = ::Package; + using StructDeclaration = ::StructDeclaration; + using StructFlags = ::StructFlags; + using UnionDeclaration = ::UnionDeclaration; + using AliasAssign = ::AliasAssign; + using ArrayScopeSymbol = ::ArrayScopeSymbol; + using Dsymbol = ::Dsymbol; + using DsymbolTable = ::DsymbolTable; + using ExpressionDsymbol = ::ExpressionDsymbol; + using FieldState = ::FieldState; + using ForwardingScopeDsymbol = ::ForwardingScopeDsymbol; + using OverloadSet = ::OverloadSet; + using PASS = ::PASS; + using ScopeDsymbol = ::ScopeDsymbol; + using SearchOpt = ::SearchOpt; + using SearchOptFlags = ::SearchOptFlags; + using Ungag = ::Ungag; + using Visibility = ::Visibility; + using WithScopeSymbol = ::WithScopeSymbol; + using TemplateAliasParameter = ::TemplateAliasParameter; + using TemplateDeclaration = ::TemplateDeclaration; + using TemplateInstance = ::TemplateInstance; + using TemplateInstanceBox = ::TemplateInstanceBox; + using TemplateMixin = ::TemplateMixin; + using TemplateParameter = ::TemplateParameter; + using TemplatePrevious = ::TemplatePrevious; + using TemplateStats = ::TemplateStats; + using TemplateThisParameter = ::TemplateThisParameter; + using TemplateTupleParameter = ::TemplateTupleParameter; + using TemplateTypeParameter = ::TemplateTypeParameter; + using TemplateValueParameter = ::TemplateValueParameter; + using Tuple = ::Tuple; + using TypeDeduced = ::TypeDeduced; + using DebugSymbol = ::DebugSymbol; + using VersionSymbol = ::VersionSymbol; + using AddAssignExp = ::AddAssignExp; + using AddExp = ::AddExp; + using AddrExp = ::AddrExp; + using AndAssignExp = ::AndAssignExp; + using AndExp = ::AndExp; + using ArgumentList = ::ArgumentList; + using ArrayExp = ::ArrayExp; + using ArrayLengthExp = ::ArrayLengthExp; + using ArrayLiteralExp = ::ArrayLiteralExp; + using AssertExp = ::AssertExp; + using AssignExp = ::AssignExp; + using AssocArrayLiteralExp = ::AssocArrayLiteralExp; + using BinAssignExp = ::BinAssignExp; + using BinExp = ::BinExp; + using BlitExp = ::BlitExp; + using CTFEExp = ::CTFEExp; + using CallExp = ::CallExp; + using CastExp = ::CastExp; + using CatAssignExp = ::CatAssignExp; + using CatDcharAssignExp = ::CatDcharAssignExp; + using CatElemAssignExp = ::CatElemAssignExp; + using CatExp = ::CatExp; + using ClassReferenceExp = ::ClassReferenceExp; + using CmpExp = ::CmpExp; + using ComExp = ::ComExp; + using CommaExp = ::CommaExp; + using ComplexExp = ::ComplexExp; + using CompoundLiteralExp = ::CompoundLiteralExp; + using CondExp = ::CondExp; + using ConstructExp = ::ConstructExp; + using DeclarationExp = ::DeclarationExp; + using DefaultInitExp = ::DefaultInitExp; + using DelegateExp = ::DelegateExp; + using DelegateFuncptrExp = ::DelegateFuncptrExp; + using DelegatePtrExp = ::DelegatePtrExp; + using DeleteExp = ::DeleteExp; + using DivAssignExp = ::DivAssignExp; + using DivExp = ::DivExp; + using DollarExp = ::DollarExp; + using DotExp = ::DotExp; + using DotIdExp = ::DotIdExp; + using DotTemplateExp = ::DotTemplateExp; + using DotTemplateInstanceExp = ::DotTemplateInstanceExp; + using DotTypeExp = ::DotTypeExp; + using DotVarExp = ::DotVarExp; + using DsymbolExp = ::DsymbolExp; + using EqualExp = ::EqualExp; + using ErrorExp = ::ErrorExp; + using Expression = ::Expression; + using FileInitExp = ::FileInitExp; + using FuncExp = ::FuncExp; + using FuncInitExp = ::FuncInitExp; + using GenericExp = ::GenericExp; + using HaltExp = ::HaltExp; + using IdentifierExp = ::IdentifierExp; + using IdentityExp = ::IdentityExp; + using ImportExp = ::ImportExp; + using InExp = ::InExp; + using IndexExp = ::IndexExp; + using IntegerExp = ::IntegerExp; + using IntervalExp = ::IntervalExp; + using IsExp = ::IsExp; + using LineInitExp = ::LineInitExp; + using LogicalExp = ::LogicalExp; + using LoweredAssignExp = ::LoweredAssignExp; + using MemorySet = ::MemorySet; + using MinAssignExp = ::MinAssignExp; + using MinExp = ::MinExp; + using MixinExp = ::MixinExp; + using ModAssignExp = ::ModAssignExp; + using ModExp = ::ModExp; + using Modifiable = ::Modifiable; + using ModifyFlags = ::ModifyFlags; + using ModuleInitExp = ::ModuleInitExp; + using MulAssignExp = ::MulAssignExp; + using MulExp = ::MulExp; + using NegExp = ::NegExp; + using NewAnonClassExp = ::NewAnonClassExp; + using NewExp = ::NewExp; + using NotExp = ::NotExp; + using NullExp = ::NullExp; + using ObjcClassReferenceExp = ::ObjcClassReferenceExp; + using OrAssignExp = ::OrAssignExp; + using OrExp = ::OrExp; + using OverExp = ::OverExp; + using OwnedBy = ::OwnedBy; + using PostExp = ::PostExp; + using PowAssignExp = ::PowAssignExp; + using PowExp = ::PowExp; + using PreExp = ::PreExp; + using PrettyFuncInitExp = ::PrettyFuncInitExp; + using PtrExp = ::PtrExp; + using RealExp = ::RealExp; + using RemoveExp = ::RemoveExp; + using ScopeExp = ::ScopeExp; + using ShlAssignExp = ::ShlAssignExp; + using ShlExp = ::ShlExp; + using ShrAssignExp = ::ShrAssignExp; + using ShrExp = ::ShrExp; + using SliceExp = ::SliceExp; + using StringExp = ::StringExp; + using StructLiteralExp = ::StructLiteralExp; + using SuperExp = ::SuperExp; + using SymOffExp = ::SymOffExp; + using SymbolExp = ::SymbolExp; + using TemplateExp = ::TemplateExp; + using ThisExp = ::ThisExp; + using ThrowExp = ::ThrowExp; + using ThrownExceptionExp = ::ThrownExceptionExp; + using TraitsExp = ::TraitsExp; + using TupleExp = ::TupleExp; + using TypeExp = ::TypeExp; + using TypeidExp = ::TypeidExp; + using UAddExp = ::UAddExp; + using UnaExp = ::UnaExp; + using UshrAssignExp = ::UshrAssignExp; + using UshrExp = ::UshrExp; + using VarExp = ::VarExp; + using VectorArrayExp = ::VectorArrayExp; + using VectorExp = ::VectorExp; + using VoidInitExp = ::VoidInitExp; + using XorAssignExp = ::XorAssignExp; + using XorExp = ::XorExp; + using AttributeViolation = ::AttributeViolation; + using BUILTIN = ::BUILTIN; + using CtorDeclaration = ::CtorDeclaration; + using DtorDeclaration = ::DtorDeclaration; + using Ensure = ::Ensure; + using FuncAliasDeclaration = ::FuncAliasDeclaration; + using FuncDeclaration = ::FuncDeclaration; + using FuncLiteralDeclaration = ::FuncLiteralDeclaration; + using FuncResolveFlag = ::FuncResolveFlag; + using ILS = ::ILS; + using InvariantDeclaration = ::InvariantDeclaration; + using NewDeclaration = ::NewDeclaration; + using NrvoWalker = ::NrvoWalker; + using PostBlitDeclaration = ::PostBlitDeclaration; + using SharedStaticCtorDeclaration = ::SharedStaticCtorDeclaration; + using SharedStaticDtorDeclaration = ::SharedStaticDtorDeclaration; + using StaticCtorDeclaration = ::StaticCtorDeclaration; + using StaticDtorDeclaration = ::StaticDtorDeclaration; + using UnitTestDeclaration = ::UnitTestDeclaration; + using HdrGenState = ::HdrGenState; + using ArrayInitializer = ::ArrayInitializer; + using CInitializer = ::CInitializer; + using DefaultInitializer = ::DefaultInitializer; + using DesigInit = ::DesigInit; + using Designator = ::Designator; + using ErrorInitializer = ::ErrorInitializer; + using ExpInitializer = ::ExpInitializer; + using Initializer = ::Initializer; + using NeedInterpret = ::NeedInterpret; + using StructInitializer = ::StructInitializer; + using VisitInitializer = ::VisitInitializer; + using VoidInitializer = ::VoidInitializer; + using Covariant = ::Covariant; + using DotExpFlag = ::DotExpFlag; + using Parameter = ::Parameter; + using ParameterList = ::ParameterList; + using RET = ::RET; + using ScopeRef = ::ScopeRef; + using TRUSTformat = ::TRUSTformat; + using Type = ::Type; + using TypeAArray = ::TypeAArray; + using TypeArray = ::TypeArray; + using TypeBasic = ::TypeBasic; + using TypeClass = ::TypeClass; + using TypeDArray = ::TypeDArray; + using TypeDelegate = ::TypeDelegate; + using TypeEnum = ::TypeEnum; + using TypeError = ::TypeError; + using TypeFunction = ::TypeFunction; + using TypeIdentifier = ::TypeIdentifier; + using TypeInstance = ::TypeInstance; + using TypeMixin = ::TypeMixin; + using TypeNext = ::TypeNext; + using TypeNoreturn = ::TypeNoreturn; + using TypeNull = ::TypeNull; + using TypePointer = ::TypePointer; + using TypeQualified = ::TypeQualified; + using TypeReference = ::TypeReference; + using TypeReturn = ::TypeReturn; + using TypeSArray = ::TypeSArray; + using TypeSlice = ::TypeSlice; + using TypeStruct = ::TypeStruct; + using TypeTag = ::TypeTag; + using TypeTraits = ::TypeTraits; + using TypeTuple = ::TypeTuple; + using TypeTypeof = ::TypeTypeof; + using TypeVector = ::TypeVector; + using VisitType = ::VisitType; + using Nspace = ::Nspace; + using AsmStatement = ::AsmStatement; + using BreakStatement = ::BreakStatement; + using CaseRangeStatement = ::CaseRangeStatement; + using CaseStatement = ::CaseStatement; + using Catch = ::Catch; + using CompoundAsmStatement = ::CompoundAsmStatement; + using CompoundDeclarationStatement = ::CompoundDeclarationStatement; + using CompoundStatement = ::CompoundStatement; + using ConditionalStatement = ::ConditionalStatement; + using ContinueStatement = ::ContinueStatement; + using DebugStatement = ::DebugStatement; + using DefaultStatement = ::DefaultStatement; + using DoStatement = ::DoStatement; + using DtorExpStatement = ::DtorExpStatement; + using ErrorStatement = ::ErrorStatement; + using ExpStatement = ::ExpStatement; + using ForStatement = ::ForStatement; + using ForeachRangeStatement = ::ForeachRangeStatement; + using ForeachStatement = ::ForeachStatement; + using ForwardingStatement = ::ForwardingStatement; + using GccAsmStatement = ::GccAsmStatement; + using GotoCaseStatement = ::GotoCaseStatement; + using GotoDefaultStatement = ::GotoDefaultStatement; + using GotoStatement = ::GotoStatement; + using IfStatement = ::IfStatement; + using ImportStatement = ::ImportStatement; + using InlineAsmStatement = ::InlineAsmStatement; + using LabelDsymbol = ::LabelDsymbol; + using LabelStatement = ::LabelStatement; + using MixinStatement = ::MixinStatement; + using PeelStatement = ::PeelStatement; + using PragmaStatement = ::PragmaStatement; + using ReturnStatement = ::ReturnStatement; + using ScopeGuardStatement = ::ScopeGuardStatement; + using ScopeStatement = ::ScopeStatement; + using Statement = ::Statement; + using StaticAssertStatement = ::StaticAssertStatement; + using StaticForeachStatement = ::StaticForeachStatement; + using SwitchErrorStatement = ::SwitchErrorStatement; + using SwitchStatement = ::SwitchStatement; + using SynchronizedStatement = ::SynchronizedStatement; + using ThrowStatement = ::ThrowStatement; + using TryCatchStatement = ::TryCatchStatement; + using TryFinallyStatement = ::TryFinallyStatement; + using UnrolledLoopStatement = ::UnrolledLoopStatement; + using VisitStatement = ::VisitStatement; + using WhileStatement = ::WhileStatement; + using WithStatement = ::WithStatement; + using StaticAssert = ::StaticAssert; + using UnionExp = ::UnionExp; + using emplaceExp = ::emplaceExp; + typedef UserAttributeDeclaration* UserAttributeDeclaration; + typedef Ensure Ensure; + typedef ErrorExp* ErrorExp; + typedef MODFlags MODFlags; + typedef Type* Type; + typedef Parameter* Parameter; + typedef ParameterList ParameterList; + typedef VarArg VarArg; + typedef STC STC; + typedef Dsymbol* Dsymbol; + typedef Array Dsymbols; + typedef Visibility Visibility; + typedef SearchOpt SearchOpt; + typedef PASS PASS; + ASTCodegen() + { + } }; -class EnumMember final : public VarDeclaration +class Visitor : public ParseTimeVisitor { public: - Expression*& value(); - Expression* origValue; - Type* origType; - EnumDeclaration* ed; - EnumMember* syntaxCopy(Dsymbol* s) override; - const char* kind() const override; - EnumMember* isEnumMember() override; - void accept(Visitor* v) override; + using ParseTimeVisitor::visit; + virtual void visit(ErrorStatement* s); + virtual void visit(PeelStatement* s); + virtual void visit(UnrolledLoopStatement* s); + virtual void visit(SwitchErrorStatement* s); + virtual void visit(DebugStatement* s); + virtual void visit(DtorExpStatement* s); + virtual void visit(ForwardingStatement* s); + virtual void visit(OverloadSet* s); + virtual void visit(LabelDsymbol* s); + virtual void visit(WithScopeSymbol* s); + virtual void visit(ArrayScopeSymbol* s); + virtual void visit(OverDeclaration* s); + virtual void visit(SymbolDeclaration* s); + virtual void visit(ForwardingAttribDeclaration* s); + virtual void visit(ThisDeclaration* s); + virtual void visit(TypeInfoDeclaration* s); + virtual void visit(TypeInfoStructDeclaration* s); + virtual void visit(TypeInfoClassDeclaration* s); + virtual void visit(TypeInfoInterfaceDeclaration* s); + virtual void visit(TypeInfoPointerDeclaration* s); + virtual void visit(TypeInfoArrayDeclaration* s); + virtual void visit(TypeInfoStaticArrayDeclaration* s); + virtual void visit(TypeInfoAssociativeArrayDeclaration* s); + virtual void visit(TypeInfoEnumDeclaration* s); + virtual void visit(TypeInfoFunctionDeclaration* s); + virtual void visit(TypeInfoDelegateDeclaration* s); + virtual void visit(TypeInfoTupleDeclaration* s); + virtual void visit(TypeInfoConstDeclaration* s); + virtual void visit(TypeInfoInvariantDeclaration* s); + virtual void visit(TypeInfoSharedDeclaration* s); + virtual void visit(TypeInfoWildDeclaration* s); + virtual void visit(TypeInfoVectorDeclaration* s); + virtual void visit(FuncAliasDeclaration* s); + virtual void visit(ErrorInitializer* i); + virtual void visit(ErrorExp* e); + virtual void visit(ComplexExp* e); + virtual void visit(StructLiteralExp* e); + virtual void visit(CompoundLiteralExp* e); + virtual void visit(ObjcClassReferenceExp* e); + virtual void visit(SymOffExp* e); + virtual void visit(OverExp* e); + virtual void visit(HaltExp* e); + virtual void visit(DotTemplateExp* e); + virtual void visit(DotVarExp* e); + virtual void visit(DelegateExp* e); + virtual void visit(DotTypeExp* e); + virtual void visit(VectorExp* e); + virtual void visit(VectorArrayExp* e); + virtual void visit(SliceExp* e); + virtual void visit(ArrayLengthExp* e); + virtual void visit(DelegatePtrExp* e); + virtual void visit(DelegateFuncptrExp* e); + virtual void visit(DotExp* e); + virtual void visit(IndexExp* e); + virtual void visit(ConstructExp* e); + virtual void visit(BlitExp* e); + virtual void visit(RemoveExp* e); + virtual void visit(ClassReferenceExp* e); + virtual void visit(VoidInitExp* e); + virtual void visit(ThrownExceptionExp* e); + virtual void visit(LoweredAssignExp* e); }; -class Import final : public Dsymbol +enum class JsonFieldFlags : uint32_t { -public: - _d_dynamicArray< Identifier* > packages; - Identifier* id; - Identifier* aliasId; - int32_t isstatic; - Visibility visibility; - Array names; - Array aliases; - Module* mod; - Package* pkg; - Array aliasdecls; - const char* kind() const override; - Visibility visible() override; - Import* syntaxCopy(Dsymbol* s) override; - void importAll(Scope* sc) override; - Dsymbol* toAlias() override; - void addMember(Scope* sc, ScopeDsymbol* sd) override; - void setScope(Scope* sc) override; - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 8) override; - bool overloadInsert(Dsymbol* s) override; - Import* isImport() override; - void accept(Visitor* v) override; + none = 0u, + compilerInfo = 1u, + buildInfo = 2u, + modules = 4u, + semantics = 8u, }; -extern Expression* ctfeInterpret(Expression* e); - -extern void printCtfePerformanceStats(); - -extern const char* mangleExact(FuncDeclaration* fd); - -extern void mangleToBuffer(Type* t, OutBuffer& buf); - -extern void mangleToBuffer(Expression* e, OutBuffer& buf); - -extern void mangleToBuffer(Dsymbol* s, OutBuffer& buf); - -extern void mangleToBuffer(TemplateInstance* ti, OutBuffer& buf); - -class Package : public ScopeDsymbol +class StoppableVisitor : public Visitor { public: - PKG isPkgMod; - uint32_t tag; - Module* mod; - const char* kind() const override; - bool equals(const RootObject* const o) const override; - Package* isPackage() final override; - bool isAncestorPackageOf(const Package* const pkg) const; - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 8) override; - void accept(Visitor* v) override; - Module* isPackageMod(); - void resolvePKGunknown(); + using Visitor::visit; + bool stop; }; -class Module final : public Package +struct TargetC final { -public: - static Module* rootModule; - static DsymbolTable* modules; - static Array amodules; - static Array deferred; - static Array deferred2; - static Array deferred3; - static void _init(); - static void deinitialize(); - static AggregateDeclaration* moduleinfo; - _d_dynamicArray< const char > arg; - ModuleDeclaration* md; - const FileName srcfile; - const FileName objfile; - const FileName hdrfile; - FileName docfile; - _d_dynamicArray< const uint8_t > src; - uint32_t errors; - uint32_t numlines; - FileType filetype; - bool hasAlwaysInlines; - bool isPackageFile; - Package* pkg; - Array contentImportedFiles; - int32_t needmoduleinfo; -private: - ThreeState selfimports; - ThreeState rootimports; -public: - void* tagSymTab; -private: - OutBuffer defines; -public: - bool selfImports(); - bool rootImports(); -private: - Identifier* searchCacheIdent; - Dsymbol* searchCacheSymbol; - int32_t searchCacheFlags; - bool insearch; -public: - Module* importedFrom; - Array* decldefs; - Array aimports; - uint32_t debuglevel; - Array* debugids; - Array* debugidsNot; - uint32_t versionlevel; - Array* versionids; - Array* versionidsNot; - MacroTable macrotable; - Escape* _escapetable; - size_t nameoffset; - size_t namelen; - static Module* create(const char* filename, Identifier* ident, int32_t doDocComment, int32_t doHdrGen); - static const char* find(const char* filename); - static Module* load(const Loc& loc, Array* packages, Identifier* ident); - const char* kind() const override; - bool read(const Loc& loc); - Module* parse(); - void importAll(Scope* prevsc) override; - int32_t needModuleInfo(); - void checkImportDeprecation(const Loc& loc, Scope* sc); - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 8) override; - bool isPackageAccessible(Package* p, Visibility visibility, int32_t flags = 0) override; - Dsymbol* symtabInsert(Dsymbol* s) override; - static void runDeferredSemantic(); - static void runDeferredSemantic2(); - static void runDeferredSemantic3(); - int32_t imports(Module* m); - bool isRoot(); - bool isCoreModule(Identifier* ident); - int32_t doppelganger; - Symbol* cov; - _d_dynamicArray< uint32_t > covb; - Symbol* sictor; - Symbol* sctor; - Symbol* sdtor; - Symbol* ssharedctor; - Symbol* sshareddtor; - Symbol* stest; - Symbol* sfilename; - void* ctfe_cov; - Module* isModule() override; - void accept(Visitor* v) override; - void fullyQualifiedName(OutBuffer& buf); -}; + enum class Runtime : uint8_t + { + Unspecified = 0u, + Bionic = 1u, + DigitalMars = 2u, + Glibc = 3u, + Microsoft = 4u, + Musl = 5u, + Newlib = 6u, + UClibc = 7u, + WASI = 8u, + }; -struct ModuleDeclaration final -{ - Loc loc; - Identifier* id; - _d_dynamicArray< Identifier* > packages; - bool isdeprecated; - Expression* msg; - const char* toChars() const; - ModuleDeclaration() : - loc(), - id(), - packages(), - isdeprecated(), - msg() + enum class BitFieldStyle : uint8_t + { + Unspecified = 0u, + DM = 1u, + MS = 2u, + Gcc_Clang = 3u, + }; + + bool crtDestructorsSupported; + uint8_t boolsize; + uint8_t shortsize; + uint8_t intsize; + uint8_t longsize; + uint8_t long_longsize; + uint8_t long_doublesize; + uint8_t wchar_tsize; + Runtime runtime; + BitFieldStyle bitFieldStyle; + TargetC() : + crtDestructorsSupported(true), + boolsize(), + shortsize(), + intsize(), + longsize(), + long_longsize(), + long_doublesize(), + wchar_tsize() { } + TargetC(bool crtDestructorsSupported, uint8_t boolsize = 0u, uint8_t shortsize = 0u, uint8_t intsize = 0u, uint8_t longsize = 0u, uint8_t long_longsize = 0u, uint8_t long_doublesize = 0u, uint8_t wchar_tsize = 0u, Runtime runtime = (Runtime)0u, BitFieldStyle bitFieldStyle = (BitFieldStyle)0u) : + crtDestructorsSupported(crtDestructorsSupported), + boolsize(boolsize), + shortsize(shortsize), + intsize(intsize), + longsize(longsize), + long_longsize(long_longsize), + long_doublesize(long_doublesize), + wchar_tsize(wchar_tsize), + runtime(runtime), + bitFieldStyle(bitFieldStyle) + {} }; -extern void getLocalClasses(Module* mod, Array& aclasses); - -extern void gendocfile(Module* m, const char* const ddoctext_ptr, size_t ddoctext_length, const char* const datetime, ErrorSink* eSink, OutBuffer& outbuf); - -struct Scope final +struct TargetCPP final { - Scope* enclosing; - Module* _module; - ScopeDsymbol* scopesym; - FuncDeclaration* func; - VarDeclaration* varDecl; - Dsymbol* parent; - LabelStatement* slabel; - SwitchStatement* sw; - Statement* tryBody; - TryFinallyStatement* tf; - ScopeGuardStatement* os; - Statement* sbreak; - Statement* scontinue; - ForeachStatement* fes; - Scope* callsc; - Dsymbol* inunion; - bool nofree; - bool inLoop; - int32_t intypeof; - VarDeclaration* lastVar; - ErrorSink* eSink; - Module* minst; - TemplateInstance* tinst; - CtorFlow ctorflow; - AlignDeclaration* aligndecl; - CPPNamespaceDeclaration* namespace_; - LINK linkage; - CPPMANGLE cppmangle; - PragmaDeclaration* inlining; - Visibility visibility; - int32_t explicitVisibility; - StorageClass stc; - DeprecatedDeclaration* depdecl; - uint32_t flags; - UserAttributeDeclaration* userAttribDecl; - DocComment* lastdc; - void* anchorCounts; - Identifier* prevAnchor; - AliasDeclaration* aliasAsg; - Dsymbol* search(const Loc& loc, Identifier* ident, Dsymbol** pscopesym, int32_t flags = 0); - Scope() : - enclosing(), - _module(), - scopesym(), - func(), - varDecl(), - parent(), - slabel(), - sw(), - tryBody(), - tf(), - os(), - sbreak(), - scontinue(), - fes(), - callsc(), - inunion(), - nofree(), - inLoop(), - intypeof(), - lastVar(), - eSink(), - minst(), - tinst(), - ctorflow(), - aligndecl(), - namespace_(), - linkage((LINK)1u), - cppmangle((CPPMANGLE)0u), - inlining(), - visibility(Visibility((Visibility::Kind)5u, nullptr)), - explicitVisibility(), - stc(), - depdecl(), - flags(), - userAttribDecl(), - lastdc(), - prevAnchor(), - aliasAsg() + enum class Runtime : uint8_t + { + Unspecified = 0u, + Clang = 1u, + DigitalMars = 2u, + Gcc = 3u, + Microsoft = 4u, + Sun = 5u, + }; + + bool reverseOverloads; + bool exceptions; + bool twoDtorInVtable; + bool splitVBasetable; + bool wrapDtorInExternD; + Runtime runtime; + const char* toMangle(Dsymbol* s); + const char* typeInfoMangle(ClassDeclaration* cd); + const char* thunkMangle(FuncDeclaration* fd, int32_t offset); + const char* typeMangle(Type* t); + Type* parameterType(Type* t); + bool fundamentalType(const Type* const t, bool& isFundamental); + uint32_t derivedClassOffset(ClassDeclaration* baseClass); + TargetCPP() : + reverseOverloads(), + exceptions(), + twoDtorInVtable(), + splitVBasetable(), + wrapDtorInExternD() { } - Scope(Scope* enclosing, Module* _module = nullptr, ScopeDsymbol* scopesym = nullptr, FuncDeclaration* func = nullptr, VarDeclaration* varDecl = nullptr, Dsymbol* parent = nullptr, LabelStatement* slabel = nullptr, SwitchStatement* sw = nullptr, Statement* tryBody = nullptr, TryFinallyStatement* tf = nullptr, ScopeGuardStatement* os = nullptr, Statement* sbreak = nullptr, Statement* scontinue = nullptr, ForeachStatement* fes = nullptr, Scope* callsc = nullptr, Dsymbol* inunion = nullptr, bool nofree = false, bool inLoop = false, int32_t intypeof = 0, VarDeclaration* lastVar = nullptr, ErrorSink* eSink = nullptr, Module* minst = nullptr, TemplateInstance* tinst = nullptr, CtorFlow ctorflow = CtorFlow(), AlignDeclaration* aligndecl = nullptr, CPPNamespaceDeclaration* namespace_ = nullptr, LINK linkage = (LINK)1u, CPPMANGLE cppmangle = (CPPMANGLE)0u, PragmaDeclaration* inlining = nullptr, Visibility visibility = Visibility((Visibility::Kind)5u, nullptr), int32_t explicitVisibility = 0, uint64_t stc = 0LLU, DeprecatedDeclaration* depdecl = nullptr, uint32_t flags = 0u, UserAttributeDeclaration* userAttribDecl = nullptr, DocComment* lastdc = nullptr, void* anchorCounts = nullptr, Identifier* prevAnchor = nullptr, AliasDeclaration* aliasAsg = nullptr) : - enclosing(enclosing), - _module(_module), - scopesym(scopesym), - func(func), - varDecl(varDecl), - parent(parent), - slabel(slabel), - sw(sw), - tryBody(tryBody), - tf(tf), - os(os), - sbreak(sbreak), - scontinue(scontinue), - fes(fes), - callsc(callsc), - inunion(inunion), - nofree(nofree), - inLoop(inLoop), - intypeof(intypeof), - lastVar(lastVar), - eSink(eSink), - minst(minst), - tinst(tinst), - ctorflow(ctorflow), - aligndecl(aligndecl), - namespace_(namespace_), - linkage(linkage), - cppmangle(cppmangle), - inlining(inlining), - visibility(visibility), - explicitVisibility(explicitVisibility), - stc(stc), - depdecl(depdecl), - flags(flags), - userAttribDecl(userAttribDecl), - lastdc(lastdc), - anchorCounts(anchorCounts), - prevAnchor(prevAnchor), - aliasAsg(aliasAsg) + TargetCPP(bool reverseOverloads, bool exceptions = false, bool twoDtorInVtable = false, bool splitVBasetable = false, bool wrapDtorInExternD = false, Runtime runtime = (Runtime)0u) : + reverseOverloads(reverseOverloads), + exceptions(exceptions), + twoDtorInVtable(twoDtorInVtable), + splitVBasetable(splitVBasetable), + wrapDtorInExternD(wrapDtorInExternD), + runtime(runtime) {} }; -extern FuncDeclaration* search_toString(StructDeclaration* sd); - -class StructDeclaration : public AggregateDeclaration -{ -public: - Array postblits; - FuncDeclaration* postblit; - FuncDeclaration* xeq; - FuncDeclaration* xcmp; - FuncDeclaration* xhash; - static FuncDeclaration* xerreq; - static FuncDeclaration* xerrcmp; - TypeTuple* argTypes; - structalign_t alignment; - ThreeState ispod; - bool zeroInit() const; - bool zeroInit(bool v); - bool hasIdentityAssign() const; - bool hasIdentityAssign(bool v); - bool hasBlitAssign() const; - bool hasBlitAssign(bool v); - bool hasIdentityEquals() const; - bool hasIdentityEquals(bool v); - bool hasNoFields() const; - bool hasNoFields(bool v); - bool hasCopyCtor() const; - bool hasCopyCtor(bool v); - bool hasPointerField() const; - bool hasPointerField(bool v); - bool hasVoidInitPointers() const; - bool hasVoidInitPointers(bool v); - bool hasSystemFields() const; - bool hasSystemFields(bool v); - bool hasFieldWithInvariant() const; - bool hasFieldWithInvariant(bool v); - bool computedTypeProperties() const; - bool computedTypeProperties(bool v); - bool requestTypeInfo() const; - bool requestTypeInfo(bool v); -private: - uint16_t bitFields; -public: - static StructDeclaration* create(const Loc& loc, Identifier* id, bool inObject); - StructDeclaration* syntaxCopy(Dsymbol* s) override; - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 8) final override; - const char* kind() const override; - void finalizeSize() final override; - bool isPOD(); - bool hasCopyConstruction(); - StructDeclaration* isStructDeclaration() final override; - void accept(Visitor* v) override; - uint32_t numArgTypes() const; - Type* argType(uint32_t index); - bool hasRegularCtor(bool checkDisabled = false); -}; - -class UnionDeclaration final : public StructDeclaration +struct TargetObjC final { -public: - UnionDeclaration* syntaxCopy(Dsymbol* s) override; - const char* kind() const override; - UnionDeclaration* isUnionDeclaration() override; - void accept(Visitor* v) override; + bool supported; + TargetObjC() : + supported() + { + } + TargetObjC(bool supported) : + supported(supported) + {} }; -class WithScopeSymbol final : public ScopeDsymbol +enum class CPU : uint8_t { -public: - WithStatement* withstate; - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 8) override; - WithScopeSymbol* isWithScopeSymbol() override; - void accept(Visitor* v) override; + x87 = 0u, + mmx = 1u, + sse = 2u, + sse2 = 3u, + sse3 = 4u, + ssse3 = 5u, + sse4_1 = 6u, + sse4_2 = 7u, + avx = 8u, + avx2 = 9u, + avx512 = 10u, + baseline = 11u, + native = 12u, }; -class ArrayScopeSymbol final : public ScopeDsymbol +enum class ErrorKind { - RootObject* arrayContent; -public: - Scope* sc; - Dsymbol* search(const Loc& loc, Identifier* ident, int32_t flags = 0) override; - ArrayScopeSymbol* isArrayScopeSymbol() override; - void accept(Visitor* v) override; + warning = 0, + deprecation = 1, + error = 2, + tip = 3, + message = 4, }; -class OverloadSet final : public Dsymbol +enum class DiagnosticReporting : uint8_t { -public: - Array a; - void push(Dsymbol* s); - OverloadSet* isOverloadSet() override; - const char* kind() const override; - void accept(Visitor* v) override; + error = 0u, + inform = 1u, + off = 2u, }; -class ForwardingScopeDsymbol final : public ScopeDsymbol +enum class CppStdRevision : uint32_t { -public: - Dsymbol* symtabInsert(Dsymbol* s) override; - Dsymbol* symtabLookup(Dsymbol* s, Identifier* id) override; - void importScope(Dsymbol* s, Visibility visibility) override; - const char* kind() const override; - ForwardingScopeDsymbol* isForwardingScopeDsymbol() override; + cpp98 = 199711u, + cpp11 = 201103u, + cpp14 = 201402u, + cpp17 = 201703u, + cpp20 = 202002u, }; -class ExpressionDsymbol final : public Dsymbol +enum class FeatureState : uint8_t { -public: - Expression* exp; - ExpressionDsymbol(Expression* exp); - ExpressionDsymbol* isExpressionDsymbol() override; + default_ = 0u, + disabled = 1u, + enabled = 2u, }; -class AliasAssign final : public Dsymbol +enum class CHECKENABLE : uint8_t { -public: - Identifier* ident; - Type* type; - Dsymbol* aliassym; - AliasAssign* syntaxCopy(Dsymbol* s) override; - AliasAssign* isAliasAssign() override; - const char* kind() const override; - void accept(Visitor* v) override; + _default = 0u, + off = 1u, + on = 2u, + safeonly = 3u, }; -class DsymbolTable final : public RootObject +enum class CHECKACTION : uint8_t { -public: - AssocArray tab; - Dsymbol* lookup(const Identifier* const ident); - void update(Dsymbol* s); - Dsymbol* insert(Dsymbol* s); - Dsymbol* insert(const Identifier* const ident, Dsymbol* s); - size_t length() const; - DsymbolTable(); + D = 0u, + C = 1u, + halt = 2u, + context = 3u, }; -extern void dsymbolSemantic(Dsymbol* dsym, Scope* sc); - -extern Expression* isExpression(RootObject* o); - -extern Dsymbol* isDsymbol(RootObject* o); - -extern Type* isType(RootObject* o); - -extern Tuple* isTuple(RootObject* o); - -extern Parameter* isParameter(RootObject* o); - -extern TemplateParameter* isTemplateParameter(RootObject* o); - -extern bool isError(const RootObject* const o); - -class Tuple final : public RootObject +struct CompileEnv final { -public: - Array objects; - DYNCAST dyncast() const override; - const char* toChars() const override; + uint32_t versionNumber; + _d_dynamicArray< const char > date; + _d_dynamicArray< const char > time; + _d_dynamicArray< const char > vendor; + _d_dynamicArray< const char > timestamp; + bool previewIn; + bool ddocOutput; + bool masm; + CompileEnv() : + versionNumber(), + date(), + time(), + vendor(), + timestamp(), + previewIn(), + ddocOutput(), + masm() + { + } + CompileEnv(uint32_t versionNumber, _d_dynamicArray< const char > date = {}, _d_dynamicArray< const char > time = {}, _d_dynamicArray< const char > vendor = {}, _d_dynamicArray< const char > timestamp = {}, bool previewIn = false, bool ddocOutput = false, bool masm = false) : + versionNumber(versionNumber), + date(date), + time(time), + vendor(vendor), + timestamp(timestamp), + previewIn(previewIn), + ddocOutput(ddocOutput), + masm(masm) + {} }; -class TemplateDeclaration final : public ScopeDsymbol +typedef _d_real longdouble; + +typedef uint64_t uint64_t; + +class AggregateDeclaration : public ScopeDsymbol { public: - Array* parameters; - Array* origParameters; - Expression* constraint; - void* instances; - TemplateDeclaration* overnext; - TemplateDeclaration* overroot; - FuncDeclaration* funcroot; - Dsymbol* onemember; - bool literal; - bool ismixin; - bool isstatic; - bool isTrivialAliasSeq; - bool isTrivialAlias; - bool deprecated_; + Type* type; + StorageClass storage_class; + uint32_t structsize; + uint32_t alignsize; + Array fields; + Dsymbol* deferred; + ClassKind classKind; + CPPMANGLE cppmangle; + MangleOverride* pMangleOverride; + Dsymbol* enclosing; + VarDeclaration* vthis; + VarDeclaration* vthis2; + Array invs; + FuncDeclaration* inv; + Dsymbol* ctor; + CtorDeclaration* defaultCtor; + AliasThis* aliasthis; + Array userDtors; + DtorDeclaration* aggrDtor; + DtorDeclaration* dtor; + DtorDeclaration* tidtor; + DtorDeclaration* fieldDtor; + Expression* getRTInfo; Visibility visibility; - TemplatePrevious* previous; -private: - Expression* lastConstraint; - Array lastConstraintNegs; - Array* lastConstraintTiargs; -public: - TemplateDeclaration* syntaxCopy(Dsymbol* __param_0_) override; - bool overloadInsert(Dsymbol* s) override; - bool hasStaticCtorOrDtor() override; - const char* kind() const override; - const char* toChars() const override; - const char* toCharsNoConstraints() const; - const char* toCharsMaybeConstraints(bool includeConstraints) const; - Visibility visible() override; - const char* getConstraintEvalError(const char*& tip); - Scope* scopeForTemplateParameters(TemplateInstance* ti, Scope* sc); - TemplateDeclaration* isTemplateDeclaration() override; - bool isDeprecated() const override; - bool isOverloadable() const override; + bool noDefaultCtor; + bool disableNew; + Sizeok sizeok; + virtual Scope* newScope(Scope* sc); + virtual void finalizeSize() = 0; + uinteger_t size(const Loc& loc) final override; + bool fill(const Loc& loc, Array& elements, bool ctorinit); + Type* getType() final override; + bool isDeprecated() const final override; + bool isNested() const; + bool isExport() const final override; + Visibility visible() final override; + Type* handleType(); + bool hasInvariant(); + void* sinit; + AggregateDeclaration* isAggregateDeclaration() final override; void accept(Visitor* v) override; }; -class TypeDeduced final : public Type -{ -public: - Type* tded; - Array argexps; - Array tparams; - void update(Expression* e, Type* tparam); - void update(Type* tt, Expression* e, Type* tparam); - MATCH matchAll(Type* tt); -}; - -class TemplateParameter : public ASTNode +class AliasThis final : public Dsymbol { public: - Loc loc; Identifier* ident; - bool dependent; - virtual TemplateTypeParameter* isTemplateTypeParameter(); - virtual TemplateValueParameter* isTemplateValueParameter(); - virtual TemplateAliasParameter* isTemplateAliasParameter(); - virtual TemplateThisParameter* isTemplateThisParameter(); - virtual TemplateTupleParameter* isTemplateTupleParameter(); - virtual TemplateParameter* syntaxCopy() = 0; - virtual bool declareParameter(Scope* sc) = 0; - virtual void print(RootObject* oarg, RootObject* oded) = 0; - virtual RootObject* specialization() = 0; - virtual RootObject* defaultArg(const Loc& instLoc, Scope* sc) = 0; - virtual bool hasDefaultArg() = 0; - const char* toChars() const override; - DYNCAST dyncast() const override; - virtual RootObject* dummyArg() = 0; + Dsymbol* sym; + bool isDeprecated_; + AliasThis* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + AliasThis* isAliasThis(); void accept(Visitor* v) override; + bool isDeprecated() const override; }; -class TemplateTypeParameter : public TemplateParameter +extern TypeTuple* toArgTypes_x86(Type* t); + +extern TypeTuple* toArgTypes_sysv_x64(Type* t); + +extern TypeTuple* toArgTypes_aarch64(Type* t); + +extern bool isHFVA(Type* t, int32_t maxNumElements = 4, Type** rewriteType = nullptr); + +struct structalign_t final { +private: + uint16_t value; + bool pack; public: - Type* specType; - Type* defaultType; - TemplateTypeParameter* isTemplateTypeParameter() final override; - TemplateTypeParameter* syntaxCopy() override; - bool declareParameter(Scope* sc) final override; - void print(RootObject* oarg, RootObject* oded) final override; - RootObject* specialization() final override; - RootObject* defaultArg(const Loc& instLoc, Scope* sc) final override; - bool hasDefaultArg() final override; - RootObject* dummyArg() final override; - void accept(Visitor* v) override; + bool isDefault() const; + void setDefault(); + bool isUnknown() const; + void setUnknown(); + void set(uint32_t value); + uint32_t get() const; + bool isPack() const; + void setPack(bool pack); + structalign_t() : + value(0u), + pack() + { + } + structalign_t(uint16_t value, bool pack = false) : + value(value), + pack(pack) + {} }; -class TemplateThisParameter final : public TemplateTypeParameter +class AttribDeclaration : public Dsymbol { public: - TemplateThisParameter* isTemplateThisParameter() override; - TemplateThisParameter* syntaxCopy() override; + Array* decl; + virtual Array* include(Scope* sc); + virtual Scope* newScope(Scope* sc); + void addComment(const char* comment) override; + const char* kind() const override; + bool oneMember(Dsymbol*& ps, Identifier* ident) override; + bool hasPointers() final override; + bool hasStaticCtorOrDtor() final override; + void checkCtorConstInit() final override; + void addObjcSymbols(Array* classes, Array* categories) final override; + AttribDeclaration* isAttribDeclaration() override; void accept(Visitor* v) override; }; -class TemplateValueParameter final : public TemplateParameter +class StorageClassDeclaration : public AttribDeclaration { public: - Type* valType; - Expression* specValue; - Expression* defaultValue; - TemplateValueParameter* isTemplateValueParameter() override; - TemplateValueParameter* syntaxCopy() override; - bool declareParameter(Scope* sc) override; - void print(RootObject* oarg, RootObject* oded) override; - RootObject* specialization() override; - RootObject* defaultArg(const Loc& instLoc, Scope* sc) override; - bool hasDefaultArg() override; - RootObject* dummyArg() override; + StorageClass stc; + StorageClassDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; + bool oneMember(Dsymbol*& ps, Identifier* ident) final override; + StorageClassDeclaration* isStorageClassDeclaration() override; void accept(Visitor* v) override; }; -class TemplateAliasParameter final : public TemplateParameter +class DeprecatedDeclaration final : public StorageClassDeclaration { public: - Type* specType; - RootObject* specAlias; - RootObject* defaultAlias; - TemplateAliasParameter* isTemplateAliasParameter() override; - TemplateAliasParameter* syntaxCopy() override; - bool declareParameter(Scope* sc) override; - void print(RootObject* oarg, RootObject* oded) override; - RootObject* specialization() override; - RootObject* defaultArg(const Loc& instLoc, Scope* sc) override; - bool hasDefaultArg() override; - RootObject* dummyArg() override; + Expression* msg; + const char* msgstr; + DeprecatedDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; void accept(Visitor* v) override; }; -class TemplateTupleParameter final : public TemplateParameter +class LinkDeclaration final : public AttribDeclaration { public: - TemplateTupleParameter* isTemplateTupleParameter() override; - TemplateTupleParameter* syntaxCopy() override; - bool declareParameter(Scope* sc) override; - void print(RootObject* oarg, RootObject* oded) override; - RootObject* specialization() override; - RootObject* defaultArg(const Loc& instLoc, Scope* sc) override; - bool hasDefaultArg() override; - RootObject* dummyArg() override; + LINK linkage; + static LinkDeclaration* create(const Loc& loc, LINK p, Array* decl); + LinkDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; + const char* toChars() const override; void accept(Visitor* v) override; }; -class TemplateInstance : public ScopeDsymbol +class CPPMangleDeclaration final : public AttribDeclaration { public: - Identifier* name; - Array* tiargs; - Array tdtypes; - Array importedModules; - Dsymbol* tempdecl; - Dsymbol* enclosing; - Dsymbol* aliasdecl; - TemplateInstance* inst; - ScopeDsymbol* argsym; - size_t hash; - Array* fargs; - Array* deferred; - Module* memberOf; - TemplateInstance* tinst; - TemplateInstance* tnext; - Module* minst; -private: - uint16_t _nest; -public: - uint8_t inuse; -private: - enum class Flag : uint32_t - { - semantictiargsdone = 32768u, - havetempdecl = 16384u, - gagged = 8192u, - available = 8191u, - }; + CPPMANGLE cppmangle; + CPPMangleDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; + const char* toChars() const override; + void accept(Visitor* v) override; +}; +class CPPNamespaceDeclaration final : public AttribDeclaration +{ public: - TemplateInstance* syntaxCopy(Dsymbol* s) override; - Dsymbol* toAlias() final override; - const char* kind() const override; - bool oneMember(Dsymbol** ps, Identifier* ident) override; + Expression* exp; + CPPNamespaceDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; const char* toChars() const override; - const char* toPrettyCharsHelper() final override; - Identifier* getIdent() final override; - bool equalsx(TemplateInstance* ti); - bool isDiscardable(); - bool needsCodegen(); - TemplateInstance* isTemplateInstance() final override; void accept(Visitor* v) override; + CPPNamespaceDeclaration* isCPPNamespaceDeclaration() override; }; -class TemplateMixin final : public TemplateInstance +class VisibilityDeclaration final : public AttribDeclaration { public: - TypeQualified* tqual; - TemplateInstance* syntaxCopy(Dsymbol* s) override; + Visibility visibility; + _d_dynamicArray< Identifier* > pkg_identifiers; + VisibilityDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; const char* kind() const override; - bool oneMember(Dsymbol** ps, Identifier* ident) override; - bool hasPointers() override; - void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion) override; - const char* toChars() const override; - TemplateMixin* isTemplateMixin() override; + const char* toPrettyChars(bool __param_0_) override; + VisibilityDeclaration* isVisibilityDeclaration() override; void accept(Visitor* v) override; }; -extern void printTemplateStats(); - -extern void genCppHdrFiles(Array& ms); - -class DebugSymbol final : public Dsymbol +class AlignDeclaration final : public AttribDeclaration { public: - uint32_t level; - DebugSymbol* syntaxCopy(Dsymbol* s) override; - const char* toChars() const override; - void addMember(Scope* sc, ScopeDsymbol* sds) override; - const char* kind() const override; - DebugSymbol* isDebugSymbol() override; + Array* exps; + structalign_t salign; + AlignDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; void accept(Visitor* v) override; }; -class VersionSymbol final : public Dsymbol +class AnonDeclaration final : public AttribDeclaration { public: - uint32_t level; - VersionSymbol* syntaxCopy(Dsymbol* s) override; - const char* toChars() const override; - void addMember(Scope* sc, ScopeDsymbol* sds) override; + bool isunion; + int32_t sem; + uint32_t anonoffset; + uint32_t anonstructsize; + uint32_t anonalignsize; + AnonDeclaration* syntaxCopy(Dsymbol* s) override; const char* kind() const override; - VersionSymbol* isVersionSymbol() override; + AnonDeclaration* isAnonDeclaration() override; void accept(Visitor* v) override; }; -extern void expandTuples(Array* exps, Array* names = nullptr); - -class IntegerExp final : public Expression +class PragmaDeclaration final : public AttribDeclaration { - dinteger_t value; public: - static IntegerExp* create(const Loc& loc, dinteger_t value, Type* type); - bool equals(const RootObject* const o) const override; - dinteger_t toInteger() override; - _d_real toReal() override; - _d_real toImaginary() override; - complex_t toComplex() override; - Optional toBool() override; - Expression* toLvalue(Scope* sc, Expression* e) override; + Array* args; + PragmaDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; + const char* kind() const override; void accept(Visitor* v) override; - dinteger_t getInteger(); - IntegerExp* syntaxCopy() override; - static IntegerExp* createBool(bool b); }; -class ErrorExp final : public Expression +class ConditionalDeclaration : public AttribDeclaration { public: - static ErrorExp* get(); - Expression* toLvalue(Scope* sc, Expression* e) override; + Condition* condition; + Array* elsedecl; + ConditionalDeclaration* syntaxCopy(Dsymbol* s) override; + bool oneMember(Dsymbol*& ps, Identifier* ident) final override; + Array* include(Scope* sc) override; + void addComment(const char* comment) final override; void accept(Visitor* v) override; - static ErrorExp* errorexp; }; -class VoidInitExp final : public Expression +class StaticIfDeclaration final : public ConditionalDeclaration { public: - VarDeclaration* var; + ScopeDsymbol* scopesym; +private: + bool addisdone; + bool onStack; +public: + StaticIfDeclaration* syntaxCopy(Dsymbol* s) override; + Array* include(Scope* sc) override; + const char* kind() const override; + StaticIfDeclaration* isStaticIfDeclaration() override; void accept(Visitor* v) override; }; -class RealExp final : public Expression +class StaticForeachDeclaration final : public AttribDeclaration { public: - _d_real value; - static RealExp* create(const Loc& loc, _d_real value, Type* type); - bool equals(const RootObject* const o) const override; - bool isIdentical(const Expression* const e) const override; - dinteger_t toInteger() override; - uinteger_t toUInteger() override; - _d_real toReal() override; - _d_real toImaginary() override; - complex_t toComplex() override; - Optional toBool() override; + StaticForeach* sfe; + ScopeDsymbol* scopesym; + bool onStack; + bool cached; + Array* cache; + StaticForeachDeclaration* syntaxCopy(Dsymbol* s) override; + bool oneMember(Dsymbol*& ps, Identifier* ident) override; + Array* include(Scope* sc) override; + void addComment(const char* comment) override; + const char* kind() const override; void accept(Visitor* v) override; }; -class ComplexExp final : public Expression +class ForwardingAttribDeclaration final : public AttribDeclaration { public: - complex_t value; - static ComplexExp* create(const Loc& loc, complex_t value, Type* type); - bool equals(const RootObject* const o) const override; - bool isIdentical(const Expression* const e) const override; - dinteger_t toInteger() override; - uinteger_t toUInteger() override; - _d_real toReal() override; - _d_real toImaginary() override; - complex_t toComplex() override; - Optional toBool() override; + ForwardingScopeDsymbol* sym; + ForwardingAttribDeclaration(Array* decl); + Scope* newScope(Scope* sc) override; + ForwardingAttribDeclaration* isForwardingAttribDeclaration() override; void accept(Visitor* v) override; }; -class IdentifierExp : public Expression +class MixinDeclaration final : public AttribDeclaration { public: - Identifier* ident; - bool parens; - static IdentifierExp* create(const Loc& loc, Identifier* ident); - bool isLvalue() final override; - Expression* toLvalue(Scope* sc, Expression* e) final override; + Array* exps; + ScopeDsymbol* scopesym; + bool compiled; + MixinDeclaration* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + MixinDeclaration* isMixinDeclaration() override; void accept(Visitor* v) override; }; -class DollarExp final : public IdentifierExp +class UserAttributeDeclaration final : public AttribDeclaration { public: + Array* atts; + UserAttributeDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; + Array* getAttributes(); + const char* kind() const override; void accept(Visitor* v) override; + static bool isGNUABITag(Expression* e); + static void checkGNUABITag(Dsymbol* sym, LINK linkage); }; -class DsymbolExp final : public Expression +extern BUILTIN isBuiltin(FuncDeclaration* fd); + +extern Expression* eval_builtin(const Loc& loc, FuncDeclaration* fd, Array* arguments); + +extern bool includeImports; + +extern Array includeModulePatterns; + +extern Array compiledImports; + +struct Compiler final { -public: - Dsymbol* s; - bool hasOverloads; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - void accept(Visitor* v) override; + static Expression* paintAsType(UnionExp* pue, Expression* e, Type* type); + static void onParseModule(Module* m); + static bool onImport(Module* m); + Compiler() + { + } }; -class ThisExp : public Expression +class Condition : public ASTNode { public: - VarDeclaration* var; - ThisExp(const Loc& loc, const EXP tok); - ThisExp* syntaxCopy() override; - Optional toBool() override; - bool isLvalue() final override; - Expression* toLvalue(Scope* sc, Expression* e) final override; + Loc loc; + Include inc; + DYNCAST dyncast() const final override; + virtual Condition* syntaxCopy() = 0; + virtual int32_t include(Scope* sc) = 0; + virtual DebugCondition* isDebugCondition(); + virtual VersionCondition* isVersionCondition(); + virtual StaticIfCondition* isStaticIfCondition(); void accept(Visitor* v) override; }; -class SuperExp final : public ThisExp +class StaticForeach final : public RootObject { public: - void accept(Visitor* v) override; + Loc loc; + ForeachStatement* aggrfe; + ForeachRangeStatement* rangefe; + bool needExpansion; }; -class NullExp final : public Expression +class DVCondition : public Condition { public: - bool equals(const RootObject* const o) const override; - Optional toBool() override; - StringExp* toStringExp() override; + uint32_t level; + Identifier* ident; + Module* mod; + DVCondition* syntaxCopy() final override; void accept(Visitor* v) override; }; -class StringExp final : public Expression +class DebugCondition final : public DVCondition { public: - char postfix; - OwnedBy ownedByCtfe; - union - { - char* string; - char16_t* wstring; - char32_t* dstring; - }; - size_t len; - uint8_t sz; - bool committed; - bool hexString; - enum : char { NoPostfix = 0u }; - - static StringExp* create(const Loc& loc, const char* s); - static StringExp* create(const Loc& loc, const void* string, size_t len); - bool equals(const RootObject* const o) const override; - size_t numberOfCodeUnits(int32_t tynto = 0) const; - void writeTo(void* dest, bool zero, int32_t tyto = 0) const; - char32_t getCodeUnit(size_t i) const; - StringExp* toStringExp() override; - int32_t compare(const StringExp* const se2) const; - Optional toBool() override; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; + static void addGlobalIdent(const char* ident); + int32_t include(Scope* sc) override; + DebugCondition* isDebugCondition() override; void accept(Visitor* v) override; + const char* toChars() const override; }; -class TupleExp final : public Expression +class VersionCondition final : public DVCondition { public: - Expression* e0; - Array* exps; - static TupleExp* create(const Loc& loc, Array* exps); - TupleExp* syntaxCopy() override; - bool equals(const RootObject* const o) const override; + static void addGlobalIdent(const char* ident); + static void addPredefinedGlobalIdent(const char* ident); + int32_t include(Scope* sc) override; + VersionCondition* isVersionCondition() override; void accept(Visitor* v) override; + const char* toChars() const override; }; -class ArrayLiteralExp final : public Expression +class StaticIfCondition final : public Condition { public: - OwnedBy ownedByCtfe; - bool onstack; - Expression* basis; - Array* elements; - static ArrayLiteralExp* create(const Loc& loc, Array* elements); - ArrayLiteralExp* syntaxCopy() override; - bool equals(const RootObject* const o) const override; - Expression* getElement(size_t i); - Optional toBool() override; - StringExp* toStringExp() override; + Expression* exp; + StaticIfCondition* syntaxCopy() override; + int32_t include(Scope* sc) override; void accept(Visitor* v) override; + StaticIfCondition* isStaticIfCondition() override; + const char* toChars() const override; }; -class AssocArrayLiteralExp final : public Expression +extern const char* toCppMangleItanium(Dsymbol* s); + +extern const char* cppTypeInfoMangleItanium(Dsymbol* s); + +extern const char* cppThunkMangleItanium(FuncDeclaration* fd, int32_t offset); + +extern const char* toCppMangleMSVC(Dsymbol* s); + +extern const char* cppTypeInfoMangleMSVC(Dsymbol* s); + +extern const char* toCppMangleDMC(Dsymbol* s); + +extern const char* cppTypeInfoMangleDMC(Dsymbol* s); + +extern FileName preprocess(FileName csrcfile, const Loc& loc, bool& ifile, OutBuffer* defines); + +extern MATCH implicitConvTo(Expression* e, Type* t); + +struct BaseClass final { -public: - OwnedBy ownedByCtfe; - Array* keys; - Array* values; - Expression* lowering; - bool equals(const RootObject* const o) const override; - AssocArrayLiteralExp* syntaxCopy() override; - Optional toBool() override; - void accept(Visitor* v) override; + Type* type; + ClassDeclaration* sym; + uint32_t offset; + Array vtbl; + _d_dynamicArray< BaseClass > baseInterfaces; + bool fillVtbl(ClassDeclaration* cd, Array* vtbl, int32_t newinstance); + BaseClass() : + type(), + sym(), + offset(), + vtbl(), + baseInterfaces() + { + } }; -class StructLiteralExp final : public Expression +class ClassDeclaration : public AggregateDeclaration { public: - StructDeclaration* sd; - Array* elements; - Type* stype; - union - { - Symbol* sym; - StructLiteralExp* inlinecopy; - }; - StructLiteralExp* origin; - uint8_t stageflags; - bool useStaticInit; - bool isOriginal; - OwnedBy ownedByCtfe; - static StructLiteralExp* create(const Loc& loc, StructDeclaration* sd, void* elements, Type* stype = nullptr); - bool equals(const RootObject* const o) const override; - StructLiteralExp* syntaxCopy() override; - Expression* toLvalue(Scope* sc, Expression* e) override; + static ClassDeclaration* object; + static ClassDeclaration* throwable; + static ClassDeclaration* exception; + static ClassDeclaration* errorException; + static ClassDeclaration* cpp_type_info_ptr; + ClassDeclaration* baseClass; + FuncDeclaration* staticCtor; + FuncDeclaration* staticDtor; + Array vtbl; + Array vtblFinal; + Array* baseclasses; + _d_dynamicArray< BaseClass* > interfaces; + Array* vtblInterfaces; + TypeInfoClassDeclaration* vclassinfo; + bool com; + bool stack; + int32_t cppDtorVtblIndex; + bool inuse; + ThreeState isabstract; + Baseok baseok; + ObjcClassDeclaration objc; + Symbol* cpp_type_info_ptr_sym; + static ClassDeclaration* create(const Loc& loc, Identifier* id, Array* baseclasses, Array* members, bool inObject); + const char* toPrettyChars(bool qualifyTypes = false) override; + ClassDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; + enum : int32_t { OFFSET_RUNTIME = 1985229328 }; + + enum : int32_t { OFFSET_FWDREF = 1985229329 }; + + virtual bool isBaseOf(ClassDeclaration* cd, int32_t* poffset); + bool isBaseInfoComplete() const; + void finalizeSize() final override; + bool hasMonitor(); + bool isFuncHidden(FuncDeclaration* fd); + bool isCOMclass() const; + virtual bool isCOMinterface() const; + bool isCPPclass() const; + virtual bool isCPPinterface() const; + bool isAbstract(); + virtual int32_t vtblOffset() const; + const char* kind() const override; + void addObjcSymbols(Array* classes, Array* categories) final override; + Dsymbol* vtblsym; + Dsymbol* vtblSymbol(); + ClassDeclaration* isClassDeclaration() final override; void accept(Visitor* v) override; }; -class CompoundLiteralExp final : public Expression +class InterfaceDeclaration final : public ClassDeclaration { public: - Initializer* initializer; + InterfaceDeclaration* syntaxCopy(Dsymbol* s) override; + Scope* newScope(Scope* sc) override; + bool isBaseOf(ClassDeclaration* cd, int32_t* poffset) override; + const char* kind() const override; + int32_t vtblOffset() const override; + bool isCPPinterface() const override; + bool isCOMinterface() const override; + InterfaceDeclaration* isInterfaceDeclaration() override; void accept(Visitor* v) override; }; -class TypeExp final : public Expression -{ -public: - bool parens; - TypeExp* syntaxCopy() override; - bool checkType() override; - bool checkValue() override; - void accept(Visitor* v) override; -}; +extern void ObjectNotFound(Identifier* id); -class ScopeExp final : public Expression +class Declaration : public Dsymbol { public: - ScopeDsymbol* sds; - ScopeExp* syntaxCopy() override; - bool checkType() override; - bool checkValue() override; - void accept(Visitor* v) override; -}; + Type* type; + Type* originalType; + StorageClass storage_class; + Visibility visibility; + LINK _linkage; + int16_t inuse; + uint8_t adFlags; + enum : int32_t { wasRead = 1 }; -class TemplateExp final : public Expression -{ -public: - TemplateDeclaration* td; - FuncDeclaration* fd; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - bool checkType() override; - bool checkValue() override; - void accept(Visitor* v) override; -}; + enum : int32_t { ignoreRead = 2 }; -class NewExp final : public Expression -{ -public: - Expression* thisexp; - Type* newtype; - Array* arguments; - Array* names; - Expression* argprefix; - CtorDeclaration* member; - bool onstack; - bool thrownew; - Expression* lowering; - static NewExp* create(const Loc& loc, Expression* thisexp, Type* newtype, Array* arguments); - NewExp* syntaxCopy() override; - void accept(Visitor* v) override; -}; + enum : int32_t { nounderscore = 4 }; -class NewAnonClassExp final : public Expression -{ -public: - Expression* thisexp; - ClassDeclaration* cd; - Array* arguments; - NewAnonClassExp* syntaxCopy() override; + enum : int32_t { hidden = 8 }; + + _d_dynamicArray< const char > mangleOverride; + const char* kind() const override; + uinteger_t size(const Loc& loc) final override; + bool isStatic() const; + LINK resolvedLinkage() const; + virtual bool isDelete(); + virtual bool isDataseg(); + virtual bool isThreadlocal(); + virtual bool isCodeseg() const; + bool isFinal() const; + virtual bool isAbstract(); + bool isConst() const; + bool isImmutable() const; + bool isWild() const; + bool isAuto() const; + bool isScope() const; + bool isReturn() const; + bool isSynchronized() const; + bool isParameter() const; + bool isDeprecated() const final override; + bool isDisabled() const; + bool isOverride() const; + bool isResult() const; + bool isField() const; + bool isIn() const; + bool isOut() const; + bool isRef() const; + bool isReference() const; + bool isFuture() const; + Visibility visible() final override; + Declaration* isDeclaration() final override; void accept(Visitor* v) override; }; -class SymbolExp : public Expression +class TupleDeclaration final : public Declaration { public: - Declaration* var; - Dsymbol* originalScope; - bool hasOverloads; + Array* objects; + TypeTuple* tupletype; + bool isexp; + bool building; + TupleDeclaration* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + Type* getType() override; + Dsymbol* toAlias2() override; + bool needThis() override; + TupleDeclaration* isTupleDeclaration() override; void accept(Visitor* v) override; }; -class SymOffExp final : public SymbolExp +class AliasDeclaration final : public Declaration { public: - dinteger_t offset; - Optional toBool() override; + Dsymbol* aliassym; + Dsymbol* overnext; + Dsymbol* _import_; + static AliasDeclaration* create(const Loc& loc, Identifier* id, Type* type); + AliasDeclaration* syntaxCopy(Dsymbol* s) override; + bool overloadInsert(Dsymbol* s) override; + const char* kind() const override; + Type* getType() override; + Dsymbol* toAlias() override; + Dsymbol* toAlias2() override; + bool isOverloadable() const override; + AliasDeclaration* isAliasDeclaration() override; void accept(Visitor* v) override; }; -class VarExp final : public SymbolExp +class OverDeclaration final : public Declaration { public: - bool delegateWasExtracted; - static VarExp* create(const Loc& loc, Declaration* var, bool hasOverloads = true); + Dsymbol* overnext; + Dsymbol* aliassym; + const char* kind() const override; bool equals(const RootObject* const o) const override; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; + bool overloadInsert(Dsymbol* s) override; + bool isOverloadable() const override; + Dsymbol* isUnique(); + OverDeclaration* isOverDeclaration() override; void accept(Visitor* v) override; }; -class OverExp final : public Expression +class VarDeclaration : public Declaration { public: - OverloadSet* vars; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - void accept(Visitor* v) override; -}; + Initializer* _init; + Array nestedrefs; + TupleDeclaration* aliasTuple; + VarDeclaration* lastVar; + Expression* edtor; + IntRange* range; + Array* maybes; + uint32_t endlinnum; + uint32_t offset; + uint32_t sequenceNumber; + structalign_t alignment; + enum : uint32_t { AdrOnStackNone = 4294967295u }; -class FuncExp final : public Expression -{ + uint32_t ctfeAdrOnStack; + bool isargptr() const; + bool isargptr(bool v); + bool ctorinit() const; + bool ctorinit(bool v); + bool iscatchvar() const; + bool iscatchvar(bool v); + bool isowner() const; + bool isowner(bool v); + bool setInCtorOnly() const; + bool setInCtorOnly(bool v); + bool onstack() const; + bool onstack(bool v); + bool overlapped() const; + bool overlapped(bool v); + bool overlapUnsafe() const; + bool overlapUnsafe(bool v); + bool maybeScope() const; + bool maybeScope(bool v); + bool doNotInferReturn() const; + bool doNotInferReturn(bool v); + bool isArgDtorVar() const; + bool isArgDtorVar(bool v); + bool isCmacro() const; + bool isCmacro(bool v); + bool dllImport() const; + bool dllImport(bool v); + bool dllExport() const; + bool dllExport(bool v); + bool inClosure() const; + bool inClosure(bool v); + bool inAlignSection() const; + bool inAlignSection(bool v); + bool systemInferred() const; + bool systemInferred(bool v); +private: + uint32_t bitFields; public: - FuncLiteralDeclaration* fd; - TemplateDeclaration* td; - TOK tok; - bool equals(const RootObject* const o) const override; - FuncExp* syntaxCopy() override; - const char* toChars() const override; - bool checkType() override; - bool checkValue() override; + int8_t canassign; + uint8_t isdataseg; + static VarDeclaration* create(const Loc& loc, Type* type, Identifier* ident, Initializer* _init, StorageClass storage_class = static_cast(STC::undefined_)); + VarDeclaration* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + AggregateDeclaration* isThis() final override; + bool needThis() final override; + bool isExport() const final override; + bool isImportedSymbol() const final override; + bool isCtorinit() const; + bool isDataseg() final override; + bool isThreadlocal() final override; + bool isCTFE(); + bool isOverlappedWith(VarDeclaration* v); + bool hasPointers() final override; + bool canTakeAddressOf(); + bool needsScopeDtor(); + void checkCtorConstInit() final override; + Dsymbol* toAlias() final override; + VarDeclaration* isVarDeclaration() final override; void accept(Visitor* v) override; }; -class DeclarationExp final : public Expression +class BitFieldDeclaration : public VarDeclaration { public: - Dsymbol* declaration; - DeclarationExp* syntaxCopy() override; - bool hasCode() override; + Expression* width; + uint32_t fieldWidth; + uint32_t bitOffset; + BitFieldDeclaration* syntaxCopy(Dsymbol* s) override; + BitFieldDeclaration* isBitFieldDeclaration() final override; void accept(Visitor* v) override; + uint64_t getMinMax(Identifier* id); }; -class TypeidExp final : public Expression +class SymbolDeclaration final : public Declaration { public: - RootObject* obj; - TypeidExp* syntaxCopy() override; + AggregateDeclaration* dsym; + SymbolDeclaration* isSymbolDeclaration() override; void accept(Visitor* v) override; }; -class TraitsExp final : public Expression +class TypeInfoDeclaration : public VarDeclaration { public: - Identifier* ident; - Array* args; - TraitsExp* syntaxCopy() override; + Type* tinfo; + static TypeInfoDeclaration* create(Type* tinfo); + TypeInfoDeclaration* syntaxCopy(Dsymbol* s) final override; + const char* toChars() const final override; + TypeInfoDeclaration* isTypeInfoDeclaration() final override; void accept(Visitor* v) override; }; -class HaltExp final : public Expression +class TypeInfoStructDeclaration final : public TypeInfoDeclaration { public: + static TypeInfoStructDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class IsExp final : public Expression +class TypeInfoClassDeclaration final : public TypeInfoDeclaration { public: - Type* targ; - Identifier* id; - Type* tspec; - Array* parameters; - TOK tok; - TOK tok2; - IsExp* syntaxCopy() override; + static TypeInfoClassDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class UnaExp : public Expression +class TypeInfoInterfaceDeclaration final : public TypeInfoDeclaration { public: - Expression* e1; - UnaExp* syntaxCopy() override; - void setNoderefOperand(); - Expression* resolveLoc(const Loc& loc, Scope* sc) final override; + static TypeInfoInterfaceDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class BinExp : public Expression +class TypeInfoPointerDeclaration final : public TypeInfoDeclaration { public: - Expression* e1; - Expression* e2; - Type* att1; - Type* att2; - BinExp* syntaxCopy() override; - void setNoderefOperands(); + static TypeInfoPointerDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class BinAssignExp : public BinExp +class TypeInfoArrayDeclaration final : public TypeInfoDeclaration { public: - bool isLvalue() final override; - Expression* toLvalue(Scope* sc, Expression* ex) final override; - Expression* modifiableLvalue(Scope* sc, Expression* e) final override; + static TypeInfoArrayDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class MixinExp final : public Expression +class TypeInfoStaticArrayDeclaration final : public TypeInfoDeclaration { public: - Array* exps; - MixinExp* syntaxCopy() override; - bool equals(const RootObject* const o) const override; + static TypeInfoStaticArrayDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class ImportExp final : public UnaExp +class TypeInfoAssociativeArrayDeclaration final : public TypeInfoDeclaration { public: + static TypeInfoAssociativeArrayDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class AssertExp final : public UnaExp +class TypeInfoEnumDeclaration final : public TypeInfoDeclaration { public: - Expression* msg; - AssertExp* syntaxCopy() override; + static TypeInfoEnumDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class ThrowExp final : public UnaExp +class TypeInfoFunctionDeclaration final : public TypeInfoDeclaration { public: - ThrowExp* syntaxCopy() override; + static TypeInfoFunctionDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class DotIdExp final : public UnaExp +class TypeInfoDelegateDeclaration final : public TypeInfoDeclaration { public: - Identifier* ident; - bool noderef; - bool wantsym; - bool arrow; - static DotIdExp* create(const Loc& loc, Expression* e, Identifier* ident); + static TypeInfoDelegateDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class DotTemplateExp final : public UnaExp +class TypeInfoTupleDeclaration final : public TypeInfoDeclaration { public: - TemplateDeclaration* td; - bool checkType() override; - bool checkValue() override; + static TypeInfoTupleDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class DotVarExp final : public UnaExp +class TypeInfoConstDeclaration final : public TypeInfoDeclaration { public: - Declaration* var; - bool hasOverloads; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; + static TypeInfoConstDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class DotTemplateInstanceExp final : public UnaExp +class TypeInfoInvariantDeclaration final : public TypeInfoDeclaration { public: - TemplateInstance* ti; - DotTemplateInstanceExp* syntaxCopy() override; - bool checkType() override; - bool checkValue() override; + static TypeInfoInvariantDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class DelegateExp final : public UnaExp +class TypeInfoSharedDeclaration final : public TypeInfoDeclaration { public: - FuncDeclaration* func; - bool hasOverloads; - VarDeclaration* vthis2; + static TypeInfoSharedDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class DotTypeExp final : public UnaExp +class TypeInfoWildDeclaration final : public TypeInfoDeclaration { public: - Dsymbol* sym; + static TypeInfoWildDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class CallExp final : public UnaExp +class TypeInfoVectorDeclaration final : public TypeInfoDeclaration { public: - Array* arguments; - Array* names; - FuncDeclaration* f; - bool directcall; - bool inDebugStatement; - bool ignoreAttributes; - bool isUfcsRewrite; - VarDeclaration* vthis2; - static CallExp* create(const Loc& loc, Expression* e, Array* exps); - static CallExp* create(const Loc& loc, Expression* e); - static CallExp* create(const Loc& loc, Expression* e, Expression* earg1); - static CallExp* create(const Loc& loc, FuncDeclaration* fd, Expression* earg1); - CallExp* syntaxCopy() override; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; + static TypeInfoVectorDeclaration* create(Type* tinfo); void accept(Visitor* v) override; }; -class AddrExp final : public UnaExp +class ThisDeclaration final : public VarDeclaration { public: + ThisDeclaration* syntaxCopy(Dsymbol* s) override; + ThisDeclaration* isThisDeclaration() override; void accept(Visitor* v) override; }; -class PtrExp final : public UnaExp +class EnumDeclaration final : public ScopeDsymbol { public: - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; + Type* type; + Type* memtype; + Visibility visibility; + Expression* maxval; + Expression* minval; + Expression* defaultval; + bool isdeprecated() const; + bool isdeprecated(bool v); + bool added() const; + bool added(bool v); + bool inuse() const; + bool inuse(bool v); +private: + uint8_t bitFields; +public: + EnumDeclaration* syntaxCopy(Dsymbol* s) override; + bool oneMember(Dsymbol*& ps, Identifier* ident) override; + Type* getType() override; + const char* kind() const override; + bool isDeprecated() const override; + Visibility visible() override; + bool isSpecial() const; + Expression* getDefaultValue(const Loc& loc); + Type* getMemtype(const Loc& loc); + EnumDeclaration* isEnumDeclaration() override; + Symbol* sinit; void accept(Visitor* v) override; }; -class NegExp final : public UnaExp +class EnumMember final : public VarDeclaration { public: + Expression*& value(); + Expression* origValue; + Type* origType; + EnumDeclaration* ed; + EnumMember* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + EnumMember* isEnumMember() override; void accept(Visitor* v) override; }; -class UAddExp final : public UnaExp +class Import final : public Dsymbol { public: + _d_dynamicArray< Identifier* > packages; + Identifier* id; + Identifier* aliasId; + int32_t isstatic; + Visibility visibility; + Array names; + Array aliases; + Module* mod; + Package* pkg; + Array aliasdecls; + const char* kind() const override; + Visibility visible() override; + Import* syntaxCopy(Dsymbol* s) override; + Dsymbol* toAlias() override; + bool overloadInsert(Dsymbol* s) override; + Import* isImport() override; void accept(Visitor* v) override; }; -class ComExp final : public UnaExp +extern Expression* ctfeInterpret(Expression* e); + +extern void printCtfePerformanceStats(); + +extern const char* mangleExact(FuncDeclaration* fd); + +extern void mangleToBuffer(Type* t, OutBuffer& buf); + +extern void mangleToBuffer(Expression* e, OutBuffer& buf); + +extern void mangleToBuffer(Dsymbol* s, OutBuffer& buf); + +extern void mangleToBuffer(TemplateInstance* ti, OutBuffer& buf); + +class Package : public ScopeDsymbol { public: + PKG isPkgMod; + uint32_t tag; + Module* mod; + const char* kind() const override; + bool equals(const RootObject* const o) const override; + Package* isPackage() final override; + bool isAncestorPackageOf(const Package* const pkg) const; void accept(Visitor* v) override; + Module* isPackageMod(); + void resolvePKGunknown(); }; -class NotExp final : public UnaExp +class Module final : public Package { public: + static Module* rootModule; + static DsymbolTable* modules; + static Array amodules; + static Array deferred; + static Array deferred2; + static Array deferred3; + static void _init(); + static void deinitialize(); + static AggregateDeclaration* moduleinfo; + _d_dynamicArray< const char > arg; + ModuleDeclaration* md; + const FileName srcfile; + const FileName objfile; + const FileName hdrfile; + FileName docfile; + _d_dynamicArray< const uint8_t > src; + uint32_t errors; + uint32_t numlines; + FileType filetype; + bool hasAlwaysInlines; + bool isPackageFile; + Package* pkg; + Array contentImportedFiles; + int32_t needmoduleinfo; +private: + ThreeState selfimports; + ThreeState rootimports; +public: + void* tagSymTab; +private: + OutBuffer defines; +public: + bool selfImports(); + bool rootImports(); + Identifier* searchCacheIdent; + Dsymbol* searchCacheSymbol; + uint32_t searchCacheFlags; + bool insearch; + Module* importedFrom; + Array* decldefs; + Array aimports; + uint32_t debuglevel; + Array* debugids; + Array* debugidsNot; + uint32_t versionlevel; + Array* versionids; + Array* versionidsNot; + MacroTable macrotable; + Escape* _escapetable; + size_t nameoffset; + size_t namelen; + static Module* create(const char* filename, Identifier* ident, int32_t doDocComment, int32_t doHdrGen); + static const char* find(const char* filename); + static Module* load(const Loc& loc, Array* packages, Identifier* ident); + const char* kind() const override; + bool read(const Loc& loc); + Module* parse(); + int32_t needModuleInfo(); + void checkImportDeprecation(const Loc& loc, Scope* sc); + bool isPackageAccessible(Package* p, Visibility visibility, uint32_t flags = 0u) override; + Dsymbol* symtabInsert(Dsymbol* s) override; + static void runDeferredSemantic(); + static void runDeferredSemantic2(); + static void runDeferredSemantic3(); + int32_t imports(Module* m); + bool isRoot(); + bool isCoreModule(Identifier* ident); + int32_t doppelganger; + Symbol* cov; + _d_dynamicArray< uint32_t > covb; + Symbol* sictor; + Symbol* sctor; + Symbol* sdtor; + Symbol* ssharedctor; + Symbol* sshareddtor; + Symbol* stest; + Symbol* sfilename; + void* ctfe_cov; + Module* isModule() override; void accept(Visitor* v) override; + void fullyQualifiedName(OutBuffer& buf); }; -class DeleteExp final : public UnaExp +struct ModuleDeclaration final { -public: - bool isRAII; - void accept(Visitor* v) override; + Loc loc; + Identifier* id; + _d_dynamicArray< Identifier* > packages; + bool isdeprecated; + Expression* msg; + const char* toChars() const; + ModuleDeclaration() : + loc(), + id(), + packages(), + isdeprecated(), + msg() + { + } }; -class CastExp final : public UnaExp -{ -public: - Type* to; - uint8_t mod; - CastExp* syntaxCopy() override; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - void accept(Visitor* v) override; -}; +extern void getLocalClasses(Module* mod, Array& aclasses); -class VectorExp final : public UnaExp -{ -public: - TypeVector* to; - uint32_t dim; - OwnedBy ownedByCtfe; - static VectorExp* create(const Loc& loc, Expression* e, Type* t); - VectorExp* syntaxCopy() override; - void accept(Visitor* v) override; -}; +extern FuncDeclaration* findGetMembers(ScopeDsymbol* dsym); -class VectorArrayExp final : public UnaExp -{ -public: - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - void accept(Visitor* v) override; -}; +extern void gendocfile(Module* m, const char* const ddoctext_ptr, size_t ddoctext_length, const char* const datetime, ErrorSink* eSink, OutBuffer& outbuf); -class SliceExp final : public UnaExp +struct Scope final { -public: - Expression* upr; - Expression* lwr; - VarDeclaration* lengthVar; - bool upperIsInBounds() const; - bool upperIsInBounds(bool v); - bool lowerIsLessThanUpper() const; - bool lowerIsLessThanUpper(bool v); - bool arrayop() const; - bool arrayop(bool v); -private: - uint8_t bitFields; -public: - SliceExp* syntaxCopy() override; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; - Optional toBool() override; - void accept(Visitor* v) override; + Scope* enclosing; + Module* _module; + ScopeDsymbol* scopesym; + FuncDeclaration* func; + VarDeclaration* varDecl; + Dsymbol* parent; + LabelStatement* slabel; + SwitchStatement* sw; + Statement* tryBody; + TryFinallyStatement* tf; + ScopeGuardStatement* os; + Statement* sbreak; + Statement* scontinue; + ForeachStatement* fes; + Scope* callsc; + Dsymbol* inunion; + bool nofree; + bool inLoop; + int32_t intypeof; + VarDeclaration* lastVar; + ErrorSink* eSink; + Module* minst; + TemplateInstance* tinst; + CtorFlow ctorflow; + AlignDeclaration* aligndecl; + CPPNamespaceDeclaration* namespace_; + LINK linkage; + CPPMANGLE cppmangle; + PragmaDeclaration* inlining; + Visibility visibility; + int32_t explicitVisibility; + StorageClass stc; + DeprecatedDeclaration* depdecl; + uint32_t flags; + UserAttributeDeclaration* userAttribDecl; + DocComment* lastdc; + void* anchorCounts; + Identifier* prevAnchor; + AliasDeclaration* aliasAsg; + Dsymbol* search(const Loc& loc, Identifier* ident, Dsymbol*& pscopesym, uint32_t flags = 0u); + Scope() : + enclosing(), + _module(), + scopesym(), + func(), + varDecl(), + parent(), + slabel(), + sw(), + tryBody(), + tf(), + os(), + sbreak(), + scontinue(), + fes(), + callsc(), + inunion(), + nofree(), + inLoop(), + intypeof(), + lastVar(), + eSink(), + minst(), + tinst(), + ctorflow(), + aligndecl(), + namespace_(), + linkage((LINK)1u), + cppmangle((CPPMANGLE)0u), + inlining(), + visibility(Visibility((Visibility::Kind)5u, nullptr)), + explicitVisibility(), + stc(), + depdecl(), + flags(), + userAttribDecl(), + lastdc(), + prevAnchor(), + aliasAsg() + { + } + Scope(Scope* enclosing, Module* _module = nullptr, ScopeDsymbol* scopesym = nullptr, FuncDeclaration* func = nullptr, VarDeclaration* varDecl = nullptr, Dsymbol* parent = nullptr, LabelStatement* slabel = nullptr, SwitchStatement* sw = nullptr, Statement* tryBody = nullptr, TryFinallyStatement* tf = nullptr, ScopeGuardStatement* os = nullptr, Statement* sbreak = nullptr, Statement* scontinue = nullptr, ForeachStatement* fes = nullptr, Scope* callsc = nullptr, Dsymbol* inunion = nullptr, bool nofree = false, bool inLoop = false, int32_t intypeof = 0, VarDeclaration* lastVar = nullptr, ErrorSink* eSink = nullptr, Module* minst = nullptr, TemplateInstance* tinst = nullptr, CtorFlow ctorflow = CtorFlow(), AlignDeclaration* aligndecl = nullptr, CPPNamespaceDeclaration* namespace_ = nullptr, LINK linkage = (LINK)1u, CPPMANGLE cppmangle = (CPPMANGLE)0u, PragmaDeclaration* inlining = nullptr, Visibility visibility = Visibility((Visibility::Kind)5u, nullptr), int32_t explicitVisibility = 0, uint64_t stc = 0LLU, DeprecatedDeclaration* depdecl = nullptr, uint32_t flags = 0u, UserAttributeDeclaration* userAttribDecl = nullptr, DocComment* lastdc = nullptr, void* anchorCounts = nullptr, Identifier* prevAnchor = nullptr, AliasDeclaration* aliasAsg = nullptr) : + enclosing(enclosing), + _module(_module), + scopesym(scopesym), + func(func), + varDecl(varDecl), + parent(parent), + slabel(slabel), + sw(sw), + tryBody(tryBody), + tf(tf), + os(os), + sbreak(sbreak), + scontinue(scontinue), + fes(fes), + callsc(callsc), + inunion(inunion), + nofree(nofree), + inLoop(inLoop), + intypeof(intypeof), + lastVar(lastVar), + eSink(eSink), + minst(minst), + tinst(tinst), + ctorflow(ctorflow), + aligndecl(aligndecl), + namespace_(namespace_), + linkage(linkage), + cppmangle(cppmangle), + inlining(inlining), + visibility(visibility), + explicitVisibility(explicitVisibility), + stc(stc), + depdecl(depdecl), + flags(flags), + userAttribDecl(userAttribDecl), + lastdc(lastdc), + anchorCounts(anchorCounts), + prevAnchor(prevAnchor), + aliasAsg(aliasAsg) + {} }; -class ArrayLengthExp final : public UnaExp -{ -public: - void accept(Visitor* v) override; -}; +extern FuncDeclaration* search_toString(StructDeclaration* sd); -class ArrayExp final : public UnaExp +class StructDeclaration : public AggregateDeclaration { public: - Array* arguments; - size_t currentDimension; - VarDeclaration* lengthVar; - ArrayExp* syntaxCopy() override; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - void accept(Visitor* v) override; -}; - -class DotExp final : public BinExp -{ + Array postblits; + FuncDeclaration* postblit; + FuncDeclaration* xeq; + FuncDeclaration* xcmp; + FuncDeclaration* xhash; + static FuncDeclaration* xerreq; + static FuncDeclaration* xerrcmp; + TypeTuple* argTypes; + structalign_t alignment; + ThreeState ispod; + bool zeroInit() const; + bool zeroInit(bool v); + bool hasIdentityAssign() const; + bool hasIdentityAssign(bool v); + bool hasBlitAssign() const; + bool hasBlitAssign(bool v); + bool hasIdentityEquals() const; + bool hasIdentityEquals(bool v); + bool hasNoFields() const; + bool hasNoFields(bool v); + bool hasCopyCtor() const; + bool hasCopyCtor(bool v); + bool hasPointerField() const; + bool hasPointerField(bool v); + bool hasVoidInitPointers() const; + bool hasVoidInitPointers(bool v); + bool hasSystemFields() const; + bool hasSystemFields(bool v); + bool hasFieldWithInvariant() const; + bool hasFieldWithInvariant(bool v); + bool computedTypeProperties() const; + bool computedTypeProperties(bool v); + bool requestTypeInfo() const; + bool requestTypeInfo(bool v); +private: + uint16_t bitFields; public: + static StructDeclaration* create(const Loc& loc, Identifier* id, bool inObject); + StructDeclaration* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + void finalizeSize() final override; + bool isPOD(); + bool hasCopyConstruction(); + StructDeclaration* isStructDeclaration() final override; void accept(Visitor* v) override; + uint32_t numArgTypes() const; + Type* argType(uint32_t index); + bool hasRegularCtor(bool checkDisabled = false); }; -class CommaExp final : public BinExp +class UnionDeclaration final : public StructDeclaration { public: - const bool isGenerated; - bool allowCommaExp; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; - Optional toBool() override; + UnionDeclaration* syntaxCopy(Dsymbol* s) override; + const char* kind() const override; + UnionDeclaration* isUnionDeclaration() override; void accept(Visitor* v) override; - static void allow(Expression* exp); }; -class IntervalExp final : public Expression +class WithScopeSymbol final : public ScopeDsymbol { public: - Expression* lwr; - Expression* upr; - Expression* syntaxCopy() override; + WithStatement* withstate; + WithScopeSymbol* isWithScopeSymbol() override; void accept(Visitor* v) override; }; -class DelegatePtrExp final : public UnaExp +class ArrayScopeSymbol final : public ScopeDsymbol { public: - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; + RootObject* arrayContent; + ArrayScopeSymbol* isArrayScopeSymbol() override; void accept(Visitor* v) override; }; -class DelegateFuncptrExp final : public UnaExp +class OverloadSet final : public Dsymbol { public: - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; + Array a; + void push(Dsymbol* s); + OverloadSet* isOverloadSet() override; + const char* kind() const override; void accept(Visitor* v) override; }; -class IndexExp final : public BinExp +class ForwardingScopeDsymbol final : public ScopeDsymbol { public: - VarDeclaration* lengthVar; - bool modifiable; - bool indexIsInBounds; - IndexExp* syntaxCopy() override; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* e) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; - void accept(Visitor* v) override; + Dsymbol* symtabInsert(Dsymbol* s) override; + Dsymbol* symtabLookup(Dsymbol* s, Identifier* id) override; + void importScope(Dsymbol* s, Visibility visibility) override; + const char* kind() const override; + ForwardingScopeDsymbol* isForwardingScopeDsymbol() override; }; -class PostExp final : public BinExp +class ExpressionDsymbol final : public Dsymbol { public: - void accept(Visitor* v) override; + Expression* exp; + ExpressionDsymbol(Expression* exp); + ExpressionDsymbol* isExpressionDsymbol() override; }; -class PreExp final : public UnaExp +class AliasAssign final : public Dsymbol { public: + Identifier* ident; + Type* type; + Dsymbol* aliassym; + AliasAssign* syntaxCopy(Dsymbol* s) override; + AliasAssign* isAliasAssign() override; + const char* kind() const override; void accept(Visitor* v) override; }; -class AssignExp : public BinExp +class DsymbolTable final : public RootObject { public: - MemorySet memset; - AssignExp(const Loc& loc, EXP tok, Expression* e1, Expression* e2); - bool isLvalue() final override; - Expression* toLvalue(Scope* sc, Expression* ex) final override; - void accept(Visitor* v) override; + AssocArray tab; + Dsymbol* lookup(const Identifier* const ident); + void update(Dsymbol* s); + Dsymbol* insert(Dsymbol* s); + Dsymbol* insert(const Identifier* const ident, Dsymbol* s); + size_t length() const; + DsymbolTable(); }; -class LoweredAssignExp final : public AssignExp -{ -public: - Expression* lowering; - const char* toChars() const override; - void accept(Visitor* v) override; -}; +extern void dsymbolSemantic(Dsymbol* dsym, Scope* sc); -class ConstructExp final : public AssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern void addMember(Dsymbol* dsym, Scope* sc, ScopeDsymbol* sds); -class BlitExp final : public AssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern Dsymbol* search(Dsymbol* d, const Loc& loc, Identifier* ident, uint32_t flags = 0u); -class AddAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern void setScope(Dsymbol* d, Scope* sc); -class MinAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern void importAll(Dsymbol* d, Scope* sc); -class MulAssignExp final : public BinAssignExp +class ImportAllVisitor : public Visitor { public: - void accept(Visitor* v) override; + using Visitor::visit; + Scope* sc; + ImportAllVisitor(Scope* sc); + void visit(Dsymbol* d) override; + void visit(Import* imp) override; + void visit(Module* m) override; + void visit(AttribDeclaration* atb) override; + void visit(StaticIfDeclaration* _) override; + void visit(StaticForeachDeclaration* _) override; }; -class DivAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern void setFieldOffset(Dsymbol* d, AggregateDeclaration* ad, FieldState* fieldState, bool isunion); -class ModAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern void genCppHdrFiles(Array& ms); -class AndAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern Expression* resolveProperties(Scope* sc, Expression* e); -class OrAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern Expression* expressionSemantic(Expression* e, Scope* sc); -class XorAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern Expression* toLvalue(Expression* _this, Scope* sc, const char* action); -class PowAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern Expression* modifiableLvalue(Expression* _this, Scope* sc); -class ShlAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern const char* toChars(const Expression* const e); -class ShrAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern const char* toChars(const Initializer* const i); -class UshrAssignExp final : public BinAssignExp -{ -public: - void accept(Visitor* v) override; -}; +extern const char* toChars(const Type* const t); -class CatAssignExp : public BinAssignExp +extern void json_generate(Array& modules, OutBuffer& buf); + +extern JsonFieldFlags tryParseJsonField(const char* fieldName); + +class NOGCVisitor final : public StoppableVisitor { public: - Expression* lowering; - void accept(Visitor* v) override; + using StoppableVisitor::visit; + FuncDeclaration* f; + bool checkOnly; + bool err; + void doCond(Expression* exp); + void visit(Expression* e) override; + void visit(DeclarationExp* e) override; + void visit(CallExp* e) override; + void visit(ArrayLiteralExp* e) override; + void visit(AssocArrayLiteralExp* e) override; + void visit(NewExp* e) override; + void visit(DeleteExp* e) override; + void visit(IndexExp* e) override; + void visit(AssignExp* e) override; + void visit(CatAssignExp* e) override; + void visit(CatExp* e) override; }; -class CatElemAssignExp final : public CatAssignExp +class Objc { public: - void accept(Visitor* v) override; + static void _init(); + static void deinitialize(); + virtual void setObjc(ClassDeclaration* cd) = 0; + virtual void setObjc(InterfaceDeclaration* ) = 0; + virtual const char* toPrettyChars(ClassDeclaration* classDeclaration, bool qualifyTypes) const = 0; + virtual void setSelector(FuncDeclaration* , Scope* sc) = 0; + virtual void validateSelector(FuncDeclaration* fd) = 0; + virtual void checkLinkage(FuncDeclaration* fd) = 0; + virtual bool isVirtual(const FuncDeclaration* const fd) const = 0; + virtual void setAsOptional(FuncDeclaration* functionDeclaration, Scope* sc) const = 0; + virtual void validateOptional(FuncDeclaration* functionDeclaration) const = 0; + virtual ClassDeclaration* getParent(FuncDeclaration* fd, ClassDeclaration* cd) const = 0; + virtual void addToClassMethodList(FuncDeclaration* fd, ClassDeclaration* cd) const = 0; + virtual AggregateDeclaration* isThis(FuncDeclaration* funcDeclaration) const = 0; + virtual VarDeclaration* createSelectorParameter(FuncDeclaration* fd, Scope* sc) const = 0; + virtual void setMetaclass(InterfaceDeclaration* interfaceDeclaration, Scope* sc) const = 0; + virtual void setMetaclass(ClassDeclaration* classDeclaration, Scope* sc) const = 0; + virtual ClassDeclaration* getRuntimeMetaclass(ClassDeclaration* classDeclaration) const = 0; + virtual void addSymbols(AttribDeclaration* attribDeclaration, Array* classes, Array* categories) const = 0; + virtual void addSymbols(ClassDeclaration* classDeclaration, Array* classes, Array* categories) const = 0; + virtual void checkOffsetof(Expression* expression, AggregateDeclaration* aggregateDeclaration) const = 0; + virtual void checkTupleof(Expression* expression, TypeClass* type) const = 0; }; -class CatDcharAssignExp final : public CatAssignExp +template +class PermissiveVisitor : public ParseTimeVisitor { public: - void accept(Visitor* v) override; + typedef ParseTimeVisitor visit; + virtual void visit(typename AST::Dsymbol ) override; + virtual void visit(typename AST::Parameter ) override; + virtual void visit(typename AST::Statement ) override; + virtual void visit(typename AST::Type ) override; + virtual void visit(typename AST::Expression ) override; + virtual void visit(typename AST::TemplateParameter ) override; + virtual void visit(typename AST::Condition ) override; + virtual void visit(typename AST::Initializer ) override; }; -class AddExp final : public BinExp +extern void semantic2(Dsymbol* dsym, Scope* sc); + +extern void semantic3(Dsymbol* dsym, Scope* sc); + +extern void semanticTypeInfoMembers(StructDeclaration* sd); + +extern Statement* statementSemantic(Statement* s, Scope* sc); + +struct Target final { -public: - void accept(Visitor* v) override; -}; + enum class OS : uint8_t + { + none = 0u, + linux = 1u, + Windows = 2u, + OSX = 4u, + OpenBSD = 8u, + FreeBSD = 16u, + Solaris = 32u, + DragonFlyBSD = 64u, + all = 127u, + Posix = 125u, + }; + + OS os; + uint8_t osMajor; + uint8_t ptrsize; + uint8_t realsize; + uint8_t realpad; + uint8_t realalignsize; + uint8_t classinfosize; + uint64_t maxStaticDataSize; + TargetC c; + TargetCPP cpp; + TargetObjC objc; + _d_dynamicArray< const char > architectureName; + CPU cpu; + bool isX86_64; + bool isLP64; + _d_dynamicArray< const char > obj_ext; + _d_dynamicArray< const char > lib_ext; + _d_dynamicArray< const char > dll_ext; + bool run_noext; + bool omfobj; + template + struct FPTypeProperties final + { + real_t max; + real_t min_normal; + real_t nan; + real_t infinity; + real_t epsilon; + int64_t dig; + int64_t mant_dig; + int64_t max_exp; + int64_t min_exp; + int64_t max_10_exp; + int64_t min_10_exp; + FPTypeProperties() + { + } + }; -class MinExp final : public BinExp -{ + FPTypeProperties FloatProperties; + FPTypeProperties DoubleProperties; + FPTypeProperties<_d_real > RealProperties; +private: + Type* tvalist; + const Param* params; public: - void accept(Visitor* v) override; -}; + void _init(const Param& params); + void setCPU(); + void deinitialize(); + uint32_t alignsize(Type* type); + uint32_t fieldalign(Type* type); + Type* va_listType(const Loc& loc, Scope* sc); + int32_t isVectorTypeSupported(int32_t sz, Type* type); + bool isVectorOpSupported(Type* type, EXP op, Type* t2 = nullptr); + LINK systemLinkage(); + TypeTuple* toArgTypes(Type* t); + bool isReturnOnStack(TypeFunction* tf, bool needsThis); + bool preferPassByRef(Type* t); +private: + enum class TargetInfoKeys + { + cppRuntimeLibrary = 0, + cppStd = 1, + floatAbi = 2, + objectFormat = 3, + CET = 4, + }; -class CatExp final : public BinExp -{ public: - Expression* lowering; - Expression* resolveLoc(const Loc& loc, Scope* sc) override; - void accept(Visitor* v) override; + Expression* getTargetInfo(const char* name, const Loc& loc); + bool isCalleeDestroyingArgs(TypeFunction* tf); + bool libraryObjectMonitors(FuncDeclaration* fd, Statement* fbody); + bool supportsLinkerDirective() const; + Target() : + os((OS)1u), + osMajor(0u), + ptrsize(), + realsize(), + realpad(), + realalignsize(), + classinfosize(), + maxStaticDataSize(), + c(), + cpp(), + objc(), + architectureName(), + cpu((CPU)11u), + isX86_64(true), + isLP64(), + obj_ext(), + lib_ext(), + dll_ext(), + run_noext(), + omfobj(false), + FloatProperties(), + DoubleProperties(), + RealProperties(), + tvalist(), + params() + { + } + Target(OS os, uint8_t osMajor = 0u, uint8_t ptrsize = 0u, uint8_t realsize = 0u, uint8_t realpad = 0u, uint8_t realalignsize = 0u, uint8_t classinfosize = 0u, uint64_t maxStaticDataSize = 0LLU, TargetC c = TargetC(), TargetCPP cpp = TargetCPP(), TargetObjC objc = TargetObjC(), _d_dynamicArray< const char > architectureName = {}, CPU cpu = (CPU)11u, bool isX86_64 = true, bool isLP64 = false, _d_dynamicArray< const char > obj_ext = {}, _d_dynamicArray< const char > lib_ext = {}, _d_dynamicArray< const char > dll_ext = {}, bool run_noext = false, bool omfobj = false, FPTypeProperties FloatProperties = FPTypeProperties(), FPTypeProperties DoubleProperties = FPTypeProperties(), FPTypeProperties<_d_real > RealProperties = FPTypeProperties<_d_real >(), Type* tvalist = nullptr, const Param* params = nullptr) : + os(os), + osMajor(osMajor), + ptrsize(ptrsize), + realsize(realsize), + realpad(realpad), + realalignsize(realalignsize), + classinfosize(classinfosize), + maxStaticDataSize(maxStaticDataSize), + c(c), + cpp(cpp), + objc(objc), + architectureName(architectureName), + cpu(cpu), + isX86_64(isX86_64), + isLP64(isLP64), + obj_ext(obj_ext), + lib_ext(lib_ext), + dll_ext(dll_ext), + run_noext(run_noext), + omfobj(omfobj), + FloatProperties(FloatProperties), + DoubleProperties(DoubleProperties), + RealProperties(RealProperties), + tvalist(tvalist), + params(params) + {} }; -class MulExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern Target target; -class DivExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern bool tpsemantic(TemplateParameter* tp, Scope* sc, Array* parameters); -class ModExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern bool genTypeInfo(Expression* e, const Loc& loc, Type* torig, Scope* sc); -class PowExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern Type* getTypeInfoType(const Loc& loc, Type* t, Scope* sc, bool genObjCode = true); -class ShlExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern bool isSpeculativeType(Type* t); -class ShrExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern bool builtinTypeInfo(Type* t); -class UshrExp final : public BinExp +class SemanticTimeTransitiveVisitor : public SemanticTimePermissiveVisitor { public: - void accept(Visitor* v) override; + using SemanticTimePermissiveVisitor::visit; + void visit(ExpStatement* s) override; + void visit(MixinStatement* s) override; + void visit(CompoundStatement* s) override; + virtual void visitVarDecl(VarDeclaration* v); + void visit(CompoundDeclarationStatement* s) override; + void visit(ScopeStatement* s) override; + void visit(WhileStatement* s) override; + void visit(DoStatement* s) override; + void visit(ForStatement* s) override; + void visit(ForeachStatement* s) override; + void visit(ForeachRangeStatement* s) override; + void visit(StaticForeachStatement* s) override; + void visit(IfStatement* s) override; + void visit(ConditionalStatement* s) override; + void visit(PragmaStatement* s) override; + void visit(StaticAssertStatement* s) override; + void visit(SwitchStatement* s) override; + void visit(CaseStatement* s) override; + void visit(CaseRangeStatement* s) override; + void visit(DefaultStatement* s) override; + void visit(GotoCaseStatement* s) override; + void visit(ReturnStatement* s) override; + void visit(SynchronizedStatement* s) override; + void visit(WithStatement* s) override; + void visit(TryCatchStatement* s) override; + void visit(TryFinallyStatement* s) override; + void visit(ScopeGuardStatement* s) override; + void visit(ThrowStatement* s) override; + void visit(LabelStatement* s) override; + void visit(ImportStatement* s) override; + virtual void visit(Catch* c); + virtual void visitType(Type* t); + virtual void visitFunctionType(TypeFunction* t, TemplateDeclaration* td); + void visit(TypeVector* t) override; + void visit(TypeSArray* t) override; + void visit(TypeDArray* t) override; + void visit(TypeAArray* t) override; + void visit(TypePointer* t) override; + void visit(TypeReference* t) override; + void visit(TypeFunction* t) override; + void visit(TypeDelegate* t) override; + virtual void visitTypeQualified(TypeQualified* t); + void visit(TypeIdentifier* t) override; + void visit(TypeInstance* t) override; + void visit(TypeTypeof* t) override; + void visit(TypeReturn* t) override; + void visit(TypeTuple* t) override; + void visit(TypeSlice* t) override; + void visit(TypeTraits* t) override; + void visit(TypeMixin* t) override; + void visit(StaticAssert* s) override; + void visit(EnumMember* em) override; + virtual void visitAttribDeclaration(AttribDeclaration* d); + void visit(AttribDeclaration* d) override; + void visit(StorageClassDeclaration* d) override; + void visit(DeprecatedDeclaration* d) override; + void visit(LinkDeclaration* d) override; + void visit(CPPMangleDeclaration* d) override; + void visit(VisibilityDeclaration* d) override; + void visit(AlignDeclaration* d) override; + void visit(AnonDeclaration* d) override; + void visit(PragmaDeclaration* d) override; + void visit(ConditionalDeclaration* d) override; + void visit(MixinDeclaration* d) override; + void visit(UserAttributeDeclaration* d) override; + virtual void visitFuncBody(FuncDeclaration* f); + virtual void visitBaseClasses(ClassDeclaration* d); + virtual bool visitEponymousMember(TemplateDeclaration* d); + virtual void visitTemplateParameters(Array* parameters); + void visit(TemplateDeclaration* d) override; + virtual void visitObject(RootObject* oarg); + virtual void visitTiargs(TemplateInstance* ti); + void visit(TemplateInstance* ti) override; + void visit(TemplateMixin* tm) override; + void visit(EnumDeclaration* d) override; + void visit(Nspace* d) override; + void visit(StructDeclaration* d) override; + void visit(UnionDeclaration* d) override; + void visit(ClassDeclaration* d) override; + void visit(InterfaceDeclaration* d) override; + void visit(AliasDeclaration* d) override; + void visit(AliasAssign* d) override; + void visit(VarDeclaration* d) override; + void visit(FuncDeclaration* f) override; + void visit(FuncLiteralDeclaration* f) override; + void visit(PostBlitDeclaration* d) override; + void visit(DtorDeclaration* d) override; + void visit(CtorDeclaration* d) override; + void visit(StaticCtorDeclaration* d) override; + void visit(StaticDtorDeclaration* d) override; + void visit(InvariantDeclaration* d) override; + void visit(UnitTestDeclaration* d) override; + void visit(NewDeclaration* d) override; + void visit(StructInitializer* si) override; + void visit(ArrayInitializer* ai) override; + void visit(ExpInitializer* ei) override; + void visit(CInitializer* ci) override; + void visit(ArrayLiteralExp* e) override; + void visit(AssocArrayLiteralExp* e) override; + void visit(TypeExp* e) override; + void visit(ScopeExp* e) override; + void visit(NewExp* e) override; + void visit(NewAnonClassExp* e) override; + void visit(TupleExp* e) override; + void visit(FuncExp* e) override; + void visit(DeclarationExp* e) override; + void visit(TypeidExp* e) override; + void visit(TraitsExp* e) override; + void visit(IsExp* e) override; + void visit(UnaExp* e) override; + void visit(BinExp* e) override; + void visit(MixinExp* e) override; + void visit(ImportExp* e) override; + void visit(AssertExp* e) override; + void visit(DotIdExp* e) override; + void visit(DotTemplateInstanceExp* e) override; + void visit(CallExp* e) override; + void visit(PtrExp* e) override; + void visit(DeleteExp* e) override; + void visit(CastExp* e) override; + void visit(IntervalExp* e) override; + void visit(ArrayExp* e) override; + void visit(PostExp* e) override; + void visit(CondExp* e) override; + void visit(GenericExp* e) override; + void visit(ThrowExp* e) override; + void visit(TemplateTypeParameter* tp) override; + void visit(TemplateThisParameter* tp) override; + void visit(TemplateAliasParameter* tp) override; + void visit(TemplateValueParameter* tp) override; + void visit(StaticIfCondition* c) override; + void visit(Parameter* p) override; + void visit(Module* m) override; + void visit(PeelStatement* s) override; + void visit(UnrolledLoopStatement* s) override; + void visit(DebugStatement* s) override; + void visit(ForwardingStatement* s) override; + void visit(StructLiteralExp* e) override; + void visit(CompoundLiteralExp* e) override; + void visit(DotTemplateExp* e) override; + void visit(DotVarExp* e) override; + void visit(DelegateExp* e) override; + void visit(DotTypeExp* e) override; + void visit(VectorExp* e) override; + void visit(VectorArrayExp* e) override; + void visit(SliceExp* e) override; + void visit(ArrayLengthExp* e) override; + void visit(DelegatePtrExp* e) override; + void visit(DelegateFuncptrExp* e) override; + void visit(DotExp* e) override; + void visit(IndexExp* e) override; + void visit(RemoveExp* e) override; + void visit(LoweredAssignExp* e) override; }; -class AndExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern _d_real creall(complex_t x); -class OrExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern _d_real cimagl(complex_t x); -class XorExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern void browse(const char* url); -class LogicalExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern void error(const Loc& loc, const char* format, ...); -class CmpExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern void error(const char* filename, uint32_t linnum, uint32_t charnum, const char* format, ...); -class InExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern void errorSupplemental(const Loc& loc, const char* format, ...); -class RemoveExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern void warning(const Loc& loc, const char* format, ...); -class EqualExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern void warningSupplemental(const Loc& loc, const char* format, ...); -class IdentityExp final : public BinExp -{ -public: - void accept(Visitor* v) override; -}; +extern void deprecation(const Loc& loc, const char* format, ...); -class CondExp final : public BinExp -{ -public: - Expression* econd; - CondExp* syntaxCopy() override; - bool isLvalue() override; - Expression* toLvalue(Scope* sc, Expression* ex) override; - Expression* modifiableLvalue(Scope* sc, Expression* e) override; - void accept(Visitor* v) override; -}; +extern void deprecationSupplemental(const Loc& loc, const char* format, ...); -class DefaultInitExp : public Expression -{ -public: - void accept(Visitor* v) override; -}; +extern void message(const Loc& loc, const char* format, ...); -class FileInitExp final : public DefaultInitExp -{ -public: - Expression* resolveLoc(const Loc& loc, Scope* sc) override; - void accept(Visitor* v) override; -}; +extern void message(const char* format, ...); -class LineInitExp final : public DefaultInitExp -{ -public: - Expression* resolveLoc(const Loc& loc, Scope* sc) override; - void accept(Visitor* v) override; -}; +extern void tip(const char* format, ...); -class ModuleInitExp final : public DefaultInitExp -{ -public: - Expression* resolveLoc(const Loc& loc, Scope* sc) override; - void accept(Visitor* v) override; -}; +extern void verrorReport(const Loc& loc, const char* format, va_list ap, ErrorKind kind, const char* p1 = nullptr, const char* p2 = nullptr); -class FuncInitExp final : public DefaultInitExp -{ -public: - Expression* resolveLoc(const Loc& loc, Scope* sc) override; - void accept(Visitor* v) override; -}; +extern void verrorReportSupplemental(const Loc& loc, const char* format, va_list ap, ErrorKind kind); -class PrettyFuncInitExp final : public DefaultInitExp -{ -public: - Expression* resolveLoc(const Loc& loc, Scope* sc) override; - void accept(Visitor* v) override; -}; +extern void fatal(); -class ObjcClassReferenceExp final : public Expression -{ -public: - ClassDeclaration* classDeclaration; - void accept(Visitor* v) override; -}; +extern void halt(); -class GenericExp final : public Expression +struct Output final { -public: - Expression* cntlExp; - Array* types; - Array* exps; - GenericExp* syntaxCopy() override; - void accept(Visitor* v) override; + bool doOutput; + bool fullOutput; + _d_dynamicArray< const char > dir; + _d_dynamicArray< const char > name; + Array files; + OutBuffer* buffer; + int32_t bufferLines; + Output() : + doOutput(), + fullOutput(), + dir(), + name(), + files(), + buffer(), + bufferLines() + { + } + Output(bool doOutput, bool fullOutput = false, _d_dynamicArray< const char > dir = {}, _d_dynamicArray< const char > name = {}, Array files = Array(), OutBuffer* buffer = nullptr, int32_t bufferLines = 0) : + doOutput(doOutput), + fullOutput(fullOutput), + dir(dir), + name(name), + files(files), + buffer(buffer), + bufferLines(bufferLines) + {} }; -extern Expression* resolveProperties(Scope* sc, Expression* e); - -extern Expression* expressionSemantic(Expression* e, Scope* sc); - -extern const char* toChars(const Initializer* const i); - -extern void json_generate(Array& modules, OutBuffer& buf); - -extern JsonFieldFlags tryParseJsonField(const char* fieldName); - -class NOGCVisitor final : public StoppableVisitor +struct Help final { -public: - using StoppableVisitor::visit; - FuncDeclaration* f; - bool checkOnly; - bool err; - void doCond(Expression* exp); - void visit(Expression* e) override; - void visit(DeclarationExp* e) override; - void visit(CallExp* e) override; - void visit(ArrayLiteralExp* e) override; - void visit(AssocArrayLiteralExp* e) override; - void visit(NewExp* e) override; - void visit(DeleteExp* e) override; - void visit(IndexExp* e) override; - void visit(AssignExp* e) override; - void visit(CatAssignExp* e) override; - void visit(CatExp* e) override; + bool manual; + bool usage; + bool mcpu; + bool transition; + bool check; + bool checkAction; + bool revert; + bool preview; + bool externStd; + bool hc; + Help() : + manual(), + usage(), + mcpu(), + transition(), + check(), + checkAction(), + revert(), + preview(), + externStd(), + hc() + { + } + Help(bool manual, bool usage = false, bool mcpu = false, bool transition = false, bool check = false, bool checkAction = false, bool revert = false, bool preview = false, bool externStd = false, bool hc = false) : + manual(manual), + usage(usage), + mcpu(mcpu), + transition(transition), + check(check), + checkAction(checkAction), + revert(revert), + preview(preview), + externStd(externStd), + hc(hc) + {} }; -class Objc +struct Verbose final { -public: - static void _init(); - static void deinitialize(); - virtual void setObjc(ClassDeclaration* cd) = 0; - virtual void setObjc(InterfaceDeclaration* ) = 0; - virtual const char* toPrettyChars(ClassDeclaration* classDeclaration, bool qualifyTypes) const = 0; - virtual void setSelector(FuncDeclaration* , Scope* sc) = 0; - virtual void validateSelector(FuncDeclaration* fd) = 0; - virtual void checkLinkage(FuncDeclaration* fd) = 0; - virtual bool isVirtual(const FuncDeclaration* const fd) const = 0; - virtual void setAsOptional(FuncDeclaration* functionDeclaration, Scope* sc) const = 0; - virtual void validateOptional(FuncDeclaration* functionDeclaration) const = 0; - virtual ClassDeclaration* getParent(FuncDeclaration* fd, ClassDeclaration* cd) const = 0; - virtual void addToClassMethodList(FuncDeclaration* fd, ClassDeclaration* cd) const = 0; - virtual AggregateDeclaration* isThis(FuncDeclaration* funcDeclaration) const = 0; - virtual VarDeclaration* createSelectorParameter(FuncDeclaration* fd, Scope* sc) const = 0; - virtual void setMetaclass(InterfaceDeclaration* interfaceDeclaration, Scope* sc) const = 0; - virtual void setMetaclass(ClassDeclaration* classDeclaration, Scope* sc) const = 0; - virtual ClassDeclaration* getRuntimeMetaclass(ClassDeclaration* classDeclaration) const = 0; - virtual void addSymbols(AttribDeclaration* attribDeclaration, Array* classes, Array* categories) const = 0; - virtual void addSymbols(ClassDeclaration* classDeclaration, Array* classes, Array* categories) const = 0; - virtual void checkOffsetof(Expression* expression, AggregateDeclaration* aggregateDeclaration) const = 0; - virtual void checkTupleof(Expression* expression, TypeClass* type) const = 0; + bool verbose; + bool showColumns; + bool tls; + bool templates; + bool templatesListInstances; + bool gc; + bool field; + bool complex; + bool vin; + bool showGaggedErrors; + bool printErrorContext; + bool logo; + bool color; + bool cov; + MessageStyle messageStyle; + uint32_t errorLimit; + uint32_t errorSupplementLimit; + uint32_t errorSupplementCount(); + Verbose() : + verbose(), + showColumns(), + tls(), + templates(), + templatesListInstances(), + gc(), + field(), + complex(true), + vin(), + showGaggedErrors(), + printErrorContext(), + logo(), + color(), + cov(), + messageStyle((MessageStyle)0u), + errorLimit(20u), + errorSupplementLimit(6u) + { + } + Verbose(bool verbose, bool showColumns = false, bool tls = false, bool templates = false, bool templatesListInstances = false, bool gc = false, bool field = false, bool complex = true, bool vin = false, bool showGaggedErrors = false, bool printErrorContext = false, bool logo = false, bool color = false, bool cov = false, MessageStyle messageStyle = (MessageStyle)0u, uint32_t errorLimit = 20u, uint32_t errorSupplementLimit = 6u) : + verbose(verbose), + showColumns(showColumns), + tls(tls), + templates(templates), + templatesListInstances(templatesListInstances), + gc(gc), + field(field), + complex(complex), + vin(vin), + showGaggedErrors(showGaggedErrors), + printErrorContext(printErrorContext), + logo(logo), + color(color), + cov(cov), + messageStyle(messageStyle), + errorLimit(errorLimit), + errorSupplementLimit(errorSupplementLimit) + {} }; -template -class PermissiveVisitor : public ParseTimeVisitor +struct Param final { -public: - typedef ParseTimeVisitor visit; - virtual void visit(typename AST::Dsymbol ) override; - virtual void visit(typename AST::Parameter ) override; - virtual void visit(typename AST::Statement ) override; - virtual void visit(typename AST::Type ) override; - virtual void visit(typename AST::Expression ) override; - virtual void visit(typename AST::TemplateParameter ) override; - virtual void visit(typename AST::Condition ) override; - virtual void visit(typename AST::Initializer ) override; + bool obj; + bool multiobj; + bool trace; + bool tracegc; + bool vcg_ast; + DiagnosticReporting useDeprecated; + bool useUnitTests; + bool useInline; + bool release; + bool preservePaths; + DiagnosticReporting warnings; + bool cov; + uint8_t covPercent; + bool ctfe_cov; + bool ignoreUnsupportedPragmas; + bool useModuleInfo; + bool useTypeInfo; + bool useExceptions; + bool useGC; + bool betterC; + bool addMain; + bool allInst; + bool bitfields; + CppStdRevision cplusplus; + Help help; + Verbose v; + FeatureState useDIP25; + FeatureState useDIP1000; + bool ehnogc; + bool useDIP1021; + FeatureState fieldwise; + bool fixAliasThis; + FeatureState rvalueRefParam; + FeatureState noSharedAccess; + bool previewIn; + bool inclusiveInContracts; + bool shortenedMethods; + bool fixImmutableConv; + bool fix16997; + FeatureState dtorFields; + FeatureState systemVariables; + CHECKENABLE useInvariants; + CHECKENABLE useIn; + CHECKENABLE useOut; + CHECKENABLE useArrayBounds; + CHECKENABLE useAssert; + CHECKENABLE useSwitchError; + CHECKENABLE boundscheck; + CHECKACTION checkAction; + _d_dynamicArray< const char > argv0; + Array modFileAliasStrings; + Array* imppath; + Array* fileImppath; + _d_dynamicArray< const char > objdir; + _d_dynamicArray< const char > objname; + _d_dynamicArray< const char > libname; + Output ddoc; + Output dihdr; + Output cxxhdr; + Output json; + JsonFieldFlags jsonFieldFlags; + Output makeDeps; + Output mixinOut; + Output moduleDeps; + uint32_t debuglevel; + uint32_t versionlevel; + bool run; + Array runargs; + Array cppswitches; + const char* cpp; + Array objfiles; + Array linkswitches; + Array linkswitchIsForCC; + Array libfiles; + Array dllfiles; + _d_dynamicArray< const char > deffile; + _d_dynamicArray< const char > resfile; + _d_dynamicArray< const char > exefile; + _d_dynamicArray< const char > mapfile; + bool parsingUnittestsRequired(); + Param() : + obj(true), + multiobj(), + trace(), + tracegc(), + vcg_ast(), + useDeprecated((DiagnosticReporting)1u), + useUnitTests(), + useInline(false), + release(), + preservePaths(), + warnings((DiagnosticReporting)2u), + cov(), + covPercent(), + ctfe_cov(false), + ignoreUnsupportedPragmas(true), + useModuleInfo(true), + useTypeInfo(true), + useExceptions(true), + useGC(true), + betterC(), + addMain(), + allInst(), + bitfields(), + cplusplus((CppStdRevision)201103u), + help(), + v(), + useDIP25((FeatureState)2u), + ehnogc(), + useDIP1021(), + fixAliasThis(), + previewIn(), + inclusiveInContracts(), + shortenedMethods(true), + fixImmutableConv(), + fix16997(true), + useInvariants((CHECKENABLE)0u), + useIn((CHECKENABLE)0u), + useOut((CHECKENABLE)0u), + useArrayBounds((CHECKENABLE)0u), + useAssert((CHECKENABLE)0u), + useSwitchError((CHECKENABLE)0u), + boundscheck((CHECKENABLE)0u), + checkAction((CHECKACTION)0u), + argv0(), + modFileAliasStrings(), + imppath(), + fileImppath(), + objdir(), + objname(), + libname(), + ddoc(), + dihdr(), + cxxhdr(), + json(), + makeDeps(), + mixinOut(), + moduleDeps(), + debuglevel(), + versionlevel(), + run(), + runargs(), + cppswitches(), + cpp(), + objfiles(), + linkswitches(), + linkswitchIsForCC(), + libfiles(), + dllfiles(), + deffile(), + resfile(), + exefile(), + mapfile() + { + } + Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool vcg_ast = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = true, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool useGC = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, Help help = Help(), Verbose v = Verbose(), FeatureState useDIP25 = (FeatureState)2u, FeatureState useDIP1000 = (FeatureState)0u, bool ehnogc = false, bool useDIP1021 = false, FeatureState fieldwise = (FeatureState)0u, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)0u, FeatureState noSharedAccess = (FeatureState)0u, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)0u, FeatureState systemVariables = (FeatureState)0u, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, _d_dynamicArray< const char > argv0 = {}, Array modFileAliasStrings = Array(), Array* imppath = nullptr, Array* fileImppath = nullptr, _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, uint32_t versionlevel = 0u, bool run = false, Array runargs = Array(), Array cppswitches = Array(), const char* cpp = nullptr, Array objfiles = Array(), Array linkswitches = Array(), Array linkswitchIsForCC = Array(), Array libfiles = Array(), Array dllfiles = Array(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}) : + obj(obj), + multiobj(multiobj), + trace(trace), + tracegc(tracegc), + vcg_ast(vcg_ast), + useDeprecated(useDeprecated), + useUnitTests(useUnitTests), + useInline(useInline), + release(release), + preservePaths(preservePaths), + warnings(warnings), + cov(cov), + covPercent(covPercent), + ctfe_cov(ctfe_cov), + ignoreUnsupportedPragmas(ignoreUnsupportedPragmas), + useModuleInfo(useModuleInfo), + useTypeInfo(useTypeInfo), + useExceptions(useExceptions), + useGC(useGC), + betterC(betterC), + addMain(addMain), + allInst(allInst), + bitfields(bitfields), + cplusplus(cplusplus), + help(help), + v(v), + useDIP25(useDIP25), + useDIP1000(useDIP1000), + ehnogc(ehnogc), + useDIP1021(useDIP1021), + fieldwise(fieldwise), + fixAliasThis(fixAliasThis), + rvalueRefParam(rvalueRefParam), + noSharedAccess(noSharedAccess), + previewIn(previewIn), + inclusiveInContracts(inclusiveInContracts), + shortenedMethods(shortenedMethods), + fixImmutableConv(fixImmutableConv), + fix16997(fix16997), + dtorFields(dtorFields), + systemVariables(systemVariables), + useInvariants(useInvariants), + useIn(useIn), + useOut(useOut), + useArrayBounds(useArrayBounds), + useAssert(useAssert), + useSwitchError(useSwitchError), + boundscheck(boundscheck), + checkAction(checkAction), + argv0(argv0), + modFileAliasStrings(modFileAliasStrings), + imppath(imppath), + fileImppath(fileImppath), + objdir(objdir), + objname(objname), + libname(libname), + ddoc(ddoc), + dihdr(dihdr), + cxxhdr(cxxhdr), + json(json), + jsonFieldFlags(jsonFieldFlags), + makeDeps(makeDeps), + mixinOut(mixinOut), + moduleDeps(moduleDeps), + debuglevel(debuglevel), + versionlevel(versionlevel), + run(run), + runargs(runargs), + cppswitches(cppswitches), + cpp(cpp), + objfiles(objfiles), + linkswitches(linkswitches), + linkswitchIsForCC(linkswitchIsForCC), + libfiles(libfiles), + dllfiles(dllfiles), + deffile(deffile), + resfile(resfile), + exefile(exefile), + mapfile(mapfile) + {} }; -extern void semantic2(Dsymbol* dsym, Scope* sc); - -extern void semantic3(Dsymbol* dsym, Scope* sc); - -extern void semanticTypeInfoMembers(StructDeclaration* sd); - -extern Statement* statementSemantic(Statement* s, Scope* sc); - -struct Target final +struct Global final { - enum class OS : uint8_t - { - none = 0u, - linux = 1u, - Windows = 2u, - OSX = 4u, - OpenBSD = 8u, - FreeBSD = 16u, - Solaris = 32u, - DragonFlyBSD = 64u, - all = 127u, - Posix = 125u, - }; - - OS os; - uint8_t osMajor; - uint8_t ptrsize; - uint8_t realsize; - uint8_t realpad; - uint8_t realalignsize; - uint8_t classinfosize; - uint64_t maxStaticDataSize; - TargetC c; - TargetCPP cpp; - TargetObjC objc; - _d_dynamicArray< const char > architectureName; - CPU cpu; - bool isX86_64; - bool isLP64; - _d_dynamicArray< const char > obj_ext; - _d_dynamicArray< const char > lib_ext; - _d_dynamicArray< const char > dll_ext; - bool run_noext; - bool omfobj; - template - struct FPTypeProperties final - { - real_t max; - real_t min_normal; - real_t nan; - real_t infinity; - real_t epsilon; - int64_t dig; - int64_t mant_dig; - int64_t max_exp; - int64_t min_exp; - int64_t max_10_exp; - int64_t min_10_exp; - FPTypeProperties() - { - } - }; - - FPTypeProperties FloatProperties; - FPTypeProperties DoubleProperties; - FPTypeProperties<_d_real > RealProperties; -private: - Type* tvalist; - const Param* params; -public: - void _init(const Param& params); - void setCPU(); - void deinitialize(); - uint32_t alignsize(Type* type); - uint32_t fieldalign(Type* type); - Type* va_listType(const Loc& loc, Scope* sc); - int32_t isVectorTypeSupported(int32_t sz, Type* type); - bool isVectorOpSupported(Type* type, EXP op, Type* t2 = nullptr); - LINK systemLinkage(); - TypeTuple* toArgTypes(Type* t); - bool isReturnOnStack(TypeFunction* tf, bool needsThis); - bool preferPassByRef(Type* t); -private: - enum class TargetInfoKeys - { - cppRuntimeLibrary = 0, - cppStd = 1, - floatAbi = 2, - objectFormat = 3, - CET = 4, - }; + _d_dynamicArray< const char > inifilename; + _d_dynamicArray< const char > copyright; + _d_dynamicArray< const char > written; + Array* path; + Array* filePath; + char datetime[26LLU]; + CompileEnv compileEnv; + Param params; + uint32_t errors; + uint32_t warnings; + uint32_t gag; + uint32_t gaggedErrors; + uint32_t gaggedWarnings; + void* console; + Array* versionids; + Array* debugids; + bool hasMainFunction; + uint32_t varSequenceNumber; + FileManager* fileManager; + enum : int32_t { recursionLimit = 500 }; -public: - Expression* getTargetInfo(const char* name, const Loc& loc); - bool isCalleeDestroyingArgs(TypeFunction* tf); - bool libraryObjectMonitors(FuncDeclaration* fd, Statement* fbody); - bool supportsLinkerDirective() const; - Target() : - os((OS)1u), - osMajor(0u), - ptrsize(), - realsize(), - realpad(), - realalignsize(), - classinfosize(), - maxStaticDataSize(), - c(), - cpp(), - objc(), - architectureName(), - cpu((CPU)11u), - isX86_64(true), - isLP64(), - obj_ext(), - lib_ext(), - dll_ext(), - run_noext(), - omfobj(false), - FloatProperties(), - DoubleProperties(), - RealProperties(), - tvalist(), - params() + ErrorSink* errorSink; + ErrorSink* errorSinkNull; + FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ); + uint32_t startGagging(); + bool endGagging(uint32_t oldGagged); + void increaseErrorCount(); + void _init(); + uint32_t versionNumber(); + const char* const versionChars(); + Global() : + inifilename(), + copyright(73, "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved"), + written(24, "written by Walter Bright"), + path(), + filePath(), + compileEnv(), + params(), + errors(), + warnings(), + gag(), + gaggedErrors(), + gaggedWarnings(), + console(), + versionids(), + debugids(), + hasMainFunction(), + varSequenceNumber(1u), + fileManager(), + errorSink(), + errorSinkNull(), + preprocess() { } - Target(OS os, uint8_t osMajor = 0u, uint8_t ptrsize = 0u, uint8_t realsize = 0u, uint8_t realpad = 0u, uint8_t realalignsize = 0u, uint8_t classinfosize = 0u, uint64_t maxStaticDataSize = 0LLU, TargetC c = TargetC(), TargetCPP cpp = TargetCPP(), TargetObjC objc = TargetObjC(), _d_dynamicArray< const char > architectureName = {}, CPU cpu = (CPU)11u, bool isX86_64 = true, bool isLP64 = false, _d_dynamicArray< const char > obj_ext = {}, _d_dynamicArray< const char > lib_ext = {}, _d_dynamicArray< const char > dll_ext = {}, bool run_noext = false, bool omfobj = false, FPTypeProperties FloatProperties = FPTypeProperties(), FPTypeProperties DoubleProperties = FPTypeProperties(), FPTypeProperties<_d_real > RealProperties = FPTypeProperties<_d_real >(), Type* tvalist = nullptr, const Param* params = nullptr) : - os(os), - osMajor(osMajor), - ptrsize(ptrsize), - realsize(realsize), - realpad(realpad), - realalignsize(realalignsize), - classinfosize(classinfosize), - maxStaticDataSize(maxStaticDataSize), - c(c), - cpp(cpp), - objc(objc), - architectureName(architectureName), - cpu(cpu), - isX86_64(isX86_64), - isLP64(isLP64), - obj_ext(obj_ext), - lib_ext(lib_ext), - dll_ext(dll_ext), - run_noext(run_noext), - omfobj(omfobj), - FloatProperties(FloatProperties), - DoubleProperties(DoubleProperties), - RealProperties(RealProperties), - tvalist(tvalist), - params(params) + Global(_d_dynamicArray< const char > inifilename, _d_dynamicArray< const char > copyright = { 73, "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved" }, _d_dynamicArray< const char > written = { 24, "written by Walter Bright" }, Array* path = nullptr, Array* filePath = nullptr, CompileEnv compileEnv = CompileEnv(), Param params = Param(), uint32_t errors = 0u, uint32_t warnings = 0u, uint32_t gag = 0u, uint32_t gaggedErrors = 0u, uint32_t gaggedWarnings = 0u, void* console = nullptr, Array* versionids = nullptr, Array* debugids = nullptr, bool hasMainFunction = false, uint32_t varSequenceNumber = 1u, FileManager* fileManager = nullptr, ErrorSink* errorSink = nullptr, ErrorSink* errorSinkNull = nullptr, FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ) = nullptr) : + inifilename(inifilename), + copyright(copyright), + written(written), + path(path), + filePath(filePath), + compileEnv(compileEnv), + params(params), + errors(errors), + warnings(warnings), + gag(gag), + gaggedErrors(gaggedErrors), + gaggedWarnings(gaggedWarnings), + console(console), + versionids(versionids), + debugids(debugids), + hasMainFunction(hasMainFunction), + varSequenceNumber(varSequenceNumber), + fileManager(fileManager), + errorSink(errorSink), + errorSinkNull(errorSinkNull), + preprocess(preprocess) {} }; -extern Target target; - -extern bool tpsemantic(TemplateParameter* tp, Scope* sc, Array* parameters); - -extern bool genTypeInfo(Expression* e, const Loc& loc, Type* torig, Scope* sc); - -extern Type* getTypeInfoType(const Loc& loc, Type* t, Scope* sc, bool genObjCode = true); - -extern bool isSpeculativeType(Type* t); - -extern bool builtinTypeInfo(Type* t); - -class SemanticTimeTransitiveVisitor : public SemanticTimePermissiveVisitor -{ -public: - using SemanticTimePermissiveVisitor::visit; - void visit(ExpStatement* s) override; - void visit(MixinStatement* s) override; - void visit(CompoundStatement* s) override; - virtual void visitVarDecl(VarDeclaration* v); - void visit(CompoundDeclarationStatement* s) override; - void visit(ScopeStatement* s) override; - void visit(WhileStatement* s) override; - void visit(DoStatement* s) override; - void visit(ForStatement* s) override; - void visit(ForeachStatement* s) override; - void visit(ForeachRangeStatement* s) override; - void visit(StaticForeachStatement* s) override; - void visit(IfStatement* s) override; - void visit(ConditionalStatement* s) override; - void visit(PragmaStatement* s) override; - void visit(StaticAssertStatement* s) override; - void visit(SwitchStatement* s) override; - void visit(CaseStatement* s) override; - void visit(CaseRangeStatement* s) override; - void visit(DefaultStatement* s) override; - void visit(GotoCaseStatement* s) override; - void visit(ReturnStatement* s) override; - void visit(SynchronizedStatement* s) override; - void visit(WithStatement* s) override; - void visit(TryCatchStatement* s) override; - void visit(TryFinallyStatement* s) override; - void visit(ScopeGuardStatement* s) override; - void visit(ThrowStatement* s) override; - void visit(LabelStatement* s) override; - void visit(ImportStatement* s) override; - virtual void visit(Catch* c); - virtual void visitType(Type* t); - virtual void visitFunctionType(TypeFunction* t, TemplateDeclaration* td); - void visit(TypeVector* t) override; - void visit(TypeSArray* t) override; - void visit(TypeDArray* t) override; - void visit(TypeAArray* t) override; - void visit(TypePointer* t) override; - void visit(TypeReference* t) override; - void visit(TypeFunction* t) override; - void visit(TypeDelegate* t) override; - virtual void visitTypeQualified(TypeQualified* t); - void visit(TypeIdentifier* t) override; - void visit(TypeInstance* t) override; - void visit(TypeTypeof* t) override; - void visit(TypeReturn* t) override; - void visit(TypeTuple* t) override; - void visit(TypeSlice* t) override; - void visit(TypeTraits* t) override; - void visit(TypeMixin* t) override; - void visit(StaticAssert* s) override; - void visit(EnumMember* em) override; - virtual void visitAttribDeclaration(AttribDeclaration* d); - void visit(AttribDeclaration* d) override; - void visit(StorageClassDeclaration* d) override; - void visit(DeprecatedDeclaration* d) override; - void visit(LinkDeclaration* d) override; - void visit(CPPMangleDeclaration* d) override; - void visit(VisibilityDeclaration* d) override; - void visit(AlignDeclaration* d) override; - void visit(AnonDeclaration* d) override; - void visit(PragmaDeclaration* d) override; - void visit(ConditionalDeclaration* d) override; - void visit(MixinDeclaration* d) override; - void visit(UserAttributeDeclaration* d) override; - virtual void visitFuncBody(FuncDeclaration* f); - virtual void visitBaseClasses(ClassDeclaration* d); - virtual bool visitEponymousMember(TemplateDeclaration* d); - virtual void visitTemplateParameters(Array* parameters); - void visit(TemplateDeclaration* d) override; - virtual void visitObject(RootObject* oarg); - virtual void visitTiargs(TemplateInstance* ti); - void visit(TemplateInstance* ti) override; - void visit(TemplateMixin* tm) override; - void visit(EnumDeclaration* d) override; - void visit(Nspace* d) override; - void visit(StructDeclaration* d) override; - void visit(UnionDeclaration* d) override; - void visit(ClassDeclaration* d) override; - void visit(InterfaceDeclaration* d) override; - void visit(AliasDeclaration* d) override; - void visit(AliasAssign* d) override; - void visit(VarDeclaration* d) override; - void visit(FuncDeclaration* f) override; - void visit(FuncLiteralDeclaration* f) override; - void visit(PostBlitDeclaration* d) override; - void visit(DtorDeclaration* d) override; - void visit(CtorDeclaration* d) override; - void visit(StaticCtorDeclaration* d) override; - void visit(StaticDtorDeclaration* d) override; - void visit(InvariantDeclaration* d) override; - void visit(UnitTestDeclaration* d) override; - void visit(NewDeclaration* d) override; - void visit(StructInitializer* si) override; - void visit(ArrayInitializer* ai) override; - void visit(ExpInitializer* ei) override; - void visit(CInitializer* ci) override; - void visit(ArrayLiteralExp* e) override; - void visit(AssocArrayLiteralExp* e) override; - void visit(TypeExp* e) override; - void visit(ScopeExp* e) override; - void visit(NewExp* e) override; - void visit(NewAnonClassExp* e) override; - void visit(TupleExp* e) override; - void visit(FuncExp* e) override; - void visit(DeclarationExp* e) override; - void visit(TypeidExp* e) override; - void visit(TraitsExp* e) override; - void visit(IsExp* e) override; - void visit(UnaExp* e) override; - void visit(BinExp* e) override; - void visit(MixinExp* e) override; - void visit(ImportExp* e) override; - void visit(AssertExp* e) override; - void visit(DotIdExp* e) override; - void visit(DotTemplateInstanceExp* e) override; - void visit(CallExp* e) override; - void visit(PtrExp* e) override; - void visit(DeleteExp* e) override; - void visit(CastExp* e) override; - void visit(IntervalExp* e) override; - void visit(ArrayExp* e) override; - void visit(PostExp* e) override; - void visit(CondExp* e) override; - void visit(GenericExp* e) override; - void visit(ThrowExp* e) override; - void visit(TemplateTypeParameter* tp) override; - void visit(TemplateThisParameter* tp) override; - void visit(TemplateAliasParameter* tp) override; - void visit(TemplateValueParameter* tp) override; - void visit(StaticIfCondition* c) override; - void visit(Parameter* p) override; - void visit(Module* m) override; - void visit(PeelStatement* s) override; - void visit(UnrolledLoopStatement* s) override; - void visit(DebugStatement* s) override; - void visit(ForwardingStatement* s) override; - void visit(StructLiteralExp* e) override; - void visit(CompoundLiteralExp* e) override; - void visit(DotTemplateExp* e) override; - void visit(DotVarExp* e) override; - void visit(DelegateExp* e) override; - void visit(DotTypeExp* e) override; - void visit(VectorExp* e) override; - void visit(VectorArrayExp* e) override; - void visit(SliceExp* e) override; - void visit(ArrayLengthExp* e) override; - void visit(DelegatePtrExp* e) override; - void visit(DelegateFuncptrExp* e) override; - void visit(DotExp* e) override; - void visit(IndexExp* e) override; - void visit(RemoveExp* e) override; - void visit(LoweredAssignExp* e) override; -}; - -extern _d_real creall(complex_t x); - -extern _d_real cimagl(complex_t x); - -extern void browse(const char* url); - -extern void error(const Loc& loc, const char* format, ...); - -extern void error(const char* filename, uint32_t linnum, uint32_t charnum, const char* format, ...); - -extern void errorSupplemental(const Loc& loc, const char* format, ...); - -extern void warning(const Loc& loc, const char* format, ...); - -extern void warningSupplemental(const Loc& loc, const char* format, ...); - -extern void deprecation(const Loc& loc, const char* format, ...); - -extern void deprecationSupplemental(const Loc& loc, const char* format, ...); - -extern void message(const Loc& loc, const char* format, ...); - -extern void message(const char* format, ...); - -extern void tip(const char* format, ...); - -extern void verrorReport(const Loc& loc, const char* format, va_list ap, ErrorKind kind, const char* p1 = nullptr, const char* p2 = nullptr); - -extern void verrorReportSupplemental(const Loc& loc, const char* format, va_list ap, ErrorKind kind); - -extern void fatal(); - -extern void halt(); +extern Global global; struct Id final { @@ -8684,6 +8654,8 @@ struct Id final static Identifier* _d_newitemTTrace; static Identifier* _d_newarrayT; static Identifier* _d_newarrayTTrace; + static Identifier* _d_newarraymTX; + static Identifier* _d_newarraymTXTrace; static Identifier* _d_assert_fail; static Identifier* dup; static Identifier* _aaApply; @@ -8853,6 +8825,7 @@ struct Id final static Identifier* udaSelector; static Identifier* udaOptional; static Identifier* udaMustUse; + static Identifier* udaStandalone; static Identifier* TRUE; static Identifier* FALSE; static Identifier* ImportC; diff --git a/dmd/func.d b/dmd/func.d index be66c8831e6..78f18e8cadd 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -8,7 +8,7 @@ * - `invariant` * - `unittest` * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d) @@ -744,6 +744,7 @@ version (IN_LLVM) int result = 0; if (fd.ident == ident) { + import dmd.typesem : covariant; const cov = type.covariant(fd.type); if (cov != Covariant.distinct) { @@ -770,6 +771,8 @@ version (IN_LLVM) final int findVtblIndex(Dsymbols* vtbl, int dim) { //printf("findVtblIndex() %s\n", toChars()); + import dmd.typesem : covariant; + FuncDeclaration mismatch = null; StorageClass mismatchstc = 0; int mismatchvi = -1; @@ -996,6 +999,7 @@ version (IN_LLVM) */ if (t.ty == Tfunction) { + import dmd.typesem : covariant; auto tf = cast(TypeFunction)f.type; if (tf.covariant(t) == Covariant.yes && tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant) @@ -1206,6 +1210,7 @@ version (IN_LLVM) args.push(e); } + import dmd.typesem : callMatch; MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1); if (m > MATCH.nomatch) { @@ -3290,13 +3295,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 { @@ -3410,14 +3408,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; } @@ -3471,15 +3466,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; @@ -3496,8 +3501,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"); @@ -3584,11 +3593,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()) { @@ -4287,6 +4302,9 @@ extern (C++) class StaticCtorDeclaration : FuncDeclaration */ extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration { + /// Exclude this constructor from cyclic dependency check + bool standalone; + extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc) { super(loc, endloc, "_sharedStaticCtor", stc); @@ -4670,7 +4688,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); diff --git a/dmd/globals.d b/dmd/globals.d index be98c9eeeae..4444deef882 100644 --- a/dmd/globals.d +++ b/dmd/globals.d @@ -1,7 +1,7 @@ /** * Stores command line options and contains other miscellaneous declarations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/globals.d, _globals.d) @@ -201,7 +201,7 @@ extern (C++) struct Param bool cov; // generate code coverage data ubyte covPercent; // 0..100 code coverage percentage required bool ctfe_cov = false; // generate coverage data for ctfe - bool ignoreUnsupportedPragmas; // rather than error on them + bool ignoreUnsupportedPragmas = true; // rather than error on them bool useModuleInfo = true; // generate runtime module information bool useTypeInfo = true; // generate runtime type information bool useExceptions = true; // support exception handling @@ -329,6 +329,12 @@ version (IN_LLVM) bool dllexport; // dllexport ~all defined symbols? DLLImport dllimport; // dllimport data symbols not defined in any root module? } // IN_LLVM + + /// + bool parsingUnittestsRequired() + { + return useUnitTests || ddoc.doOutput || dihdr.doOutput; + } } enum mars_ext = "d"; // for D source files @@ -360,7 +366,7 @@ extern (C++) struct Global { const(char)[] inifilename; /// filename of configuration file as given by `-conf=`, or default value - string copyright = "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved"; + string copyright = "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved"; string written = "written by Walter Bright"; Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path diff --git a/dmd/globals.h b/dmd/globals.h index bd12a17d590..f476608ae12 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/gluelayer.d b/dmd/gluelayer.d index 6caf6e81716..cfbc3f66503 100644 --- a/dmd/gluelayer.d +++ b/dmd/gluelayer.d @@ -3,7 +3,7 @@ * * This 'glues' either the DMC or GCC back-end to the front-end. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d, _gluelayer.d) diff --git a/dmd/hdrgen.d b/dmd/hdrgen.d index 97bf7745eca..92b6ae0d738 100644 --- a/dmd/hdrgen.d +++ b/dmd/hdrgen.d @@ -3,7 +3,7 @@ * * Also used to convert AST nodes to D code in general, e.g. for error messages or `printf` debugging. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d, _hdrgen.d) @@ -35,12 +35,12 @@ import dmd.dtemplate; import dmd.dversion; import dmd.expression; import dmd.func; -import dmd.globals; import dmd.id; import dmd.identifier; import dmd.init; import dmd.mtype; import dmd.nspace; +import dmd.optimize; import dmd.parse; import dmd.root.complex; import dmd.root.ctfloat; @@ -49,7 +49,6 @@ import dmd.rootobject; import dmd.root.string; import dmd.statement; import dmd.staticassert; -import dmd.target; import dmd.tokens; import dmd.visitor; @@ -59,6 +58,8 @@ struct HdrGenState bool ddoc; /// true if generating Ddoc file bool fullDump; /// true if generating a full AST dump file bool importcHdr; /// true if generating a .di file from an ImportC file + bool doFuncBodies; /// include function bodies in output + bool vcg_ast; /// write out codegen-ast bool fullQual; /// fully qualify types when printing int tpltMember; @@ -77,9 +78,10 @@ enum TEST_EMIT_ALL = 0; * Generate a header (.di) file for Module m. * Params: * m = Module to generate header for + * doFuncBodies = generate function definitions rather than just declarations * buf = buffer to write the data to */ -extern (C++) void genhdrfile(Module m, ref OutBuffer buf) +extern (C++) void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf) { version (IN_LLVM) { @@ -93,6 +95,7 @@ version (IN_LLVM) HdrGenState hgs; hgs.hdrgen = true; hgs.importcHdr = (m.filetype == FileType.c); + hgs.doFuncBodies = doFuncBodies; toCBuffer(m, buf, hgs); } @@ -113,6 +116,14 @@ public extern (C++) const(char)* toChars(const Statement s) return buf.extractSlice().ptr; } +public extern (C++) const(char)* toChars(const Expression e) +{ + HdrGenState hgs; + OutBuffer buf; + toCBuffer(e, buf, hgs); + return buf.extractChars(); +} + public extern (C++) const(char)* toChars(const Initializer i) { OutBuffer buf; @@ -121,6 +132,17 @@ public extern (C++) const(char)* toChars(const Initializer i) return buf.extractChars(); } +public extern (C++) const(char)* toChars(const Type t) +{ + OutBuffer buf; + buf.reserve(16); + HdrGenState hgs; + hgs.fullQual = (t.ty == Tclass && !t.mod); + + toCBuffer(t, buf, null, hgs); + return buf.extractChars(); +} + public const(char)[] toString(const Initializer i) { OutBuffer buf; @@ -133,16 +155,18 @@ public const(char)[] toString(const Initializer i) * Dumps the full contents of module `m` to `buf`. * Params: * buf = buffer to write to. + * vcg_ast = write out codegen ast * m = module to visit all members of. */ -extern (C++) void moduleToBuffer(ref OutBuffer buf, Module m) +extern (C++) void moduleToBuffer(ref OutBuffer buf, bool vcg_ast, Module m) { HdrGenState hgs; hgs.fullDump = true; + hgs.vcg_ast = vcg_ast; toCBuffer(m, buf, hgs); } -void moduleToBuffer2(Module m, ref OutBuffer buf, HdrGenState* hgs) +void moduleToBuffer2(Module m, ref OutBuffer buf, ref HdrGenState hgs) { if (m.md) { @@ -176,7 +200,7 @@ void moduleToBuffer2(Module m, ref OutBuffer buf, HdrGenState* hgs) } } -private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) +private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState hgs) { void visitDefaultCase(Statement s) { @@ -245,7 +269,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) auto d = ds.exp.isDeclarationExp().declaration; if (auto v = d.isVarDeclaration()) { - visitVarDecl(v, anywritten, buf, *hgs); + visitVarDecl(v, anywritten, buf, hgs); } else d.dsymbolToBuffer(buf, hgs); @@ -808,7 +832,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) buf.level++; while (t) { - buf.writestring(t.toChars()); + buf.writestring(t.toString()); if (t.next && t.value != TOK.min && t.value != TOK.comma && t.next.value != TOK.comma && @@ -849,9 +873,9 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, HdrGenState* hgs) visit.VisitStatement(s); } -private void dsymbolToBuffer(Dsymbol s, ref OutBuffer buf, HdrGenState* hgs) +private void dsymbolToBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { - toCBuffer(s, buf, *hgs); + toCBuffer(s, buf, hgs); } void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) @@ -865,13 +889,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { buf.writestring(s.kind()); buf.writeByte('('); - s.exp.expressionToBuffer(buf, &hgs); + s.exp.expressionToBuffer(buf, hgs); if (s.msgs) { foreach (m; (*s.msgs)[]) { buf.writestring(", "); - m.expressionToBuffer(buf, &hgs); + m.expressionToBuffer(buf, hgs); } } buf.writestring(");"); @@ -903,13 +927,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitEnumMember(EnumMember em) { if (em.type) - typeToBuffer(em.type, em.ident, buf, &hgs); + typeToBuffer(em.type, em.ident, buf, hgs); else buf.writestring(em.ident.toString()); if (em.value) { buf.writestring(" = "); - em.value.expressionToBuffer(buf, &hgs); + em.value.expressionToBuffer(buf, hgs); } } @@ -926,7 +950,8 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) } foreach (const pid; imp.packages) { - buf.printf("%s.", pid.toChars()); + buf.write(pid.toString()); + buf.writeByte('.'); } buf.writestring(imp.id.toString()); if (imp.names.length) @@ -1002,7 +1027,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitDeprecatedDeclaration(DeprecatedDeclaration d) { buf.writestring("deprecated("); - d.msg.expressionToBuffer(buf, &hgs); + d.msg.expressionToBuffer(buf, hgs); buf.writestring(") "); visitAttribDeclaration(d); } @@ -1055,7 +1080,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (i) buf.writeByte(' '); - buf.printf("align (%s)", exp.toChars()); + buf.writestring("align ("); + toCBuffer(exp, buf, hgs); + buf.writeByte(')'); } if (d.decl && d.decl.length < 2) buf.writeByte(' '); @@ -1090,7 +1117,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.args && d.args.length) { buf.writestring(", "); - argsToBuffer(d.args, buf, &hgs); + argsToBuffer(d.args, buf, hgs); } buf.writeByte(')'); @@ -1098,17 +1125,17 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) // https://issues.dlang.org/show_bug.cgi?id=14690 // Unconditionally perform a full output dump // for `pragma(inline)` declarations. - bool savedFullDump = global.params.dihdr.fullOutput; + const saved = hgs.doFuncBodies; if (d.ident == Id.Pinline) - global.params.dihdr.fullOutput = true; + hgs.doFuncBodies = true; visitAttribDeclaration(d); - global.params.dihdr.fullOutput = savedFullDump; + hgs.doFuncBodies = saved; } void visitConditionalDeclaration(ConditionalDeclaration d) { - d.condition.conditionToBuffer(buf, &hgs); + d.condition.conditionToBuffer(buf, hgs); if (d.decl || d.elsedecl) { buf.writenl(); @@ -1154,12 +1181,12 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, p.storageClass)) buf.writeByte(' '); if (p.type) - typeToBuffer(p.type, p.ident, buf, &hgs); + typeToBuffer(p.type, p.ident, buf, hgs); else buf.writestring(p.ident.toString()); } buf.writestring("; "); - s.aggr.expressionToBuffer(buf, &hgs); + s.aggr.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); } @@ -1171,13 +1198,13 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(Token.toString(s.op)); buf.writestring(" ("); if (s.prm.type) - typeToBuffer(s.prm.type, s.prm.ident, buf, &hgs); + typeToBuffer(s.prm.type, s.prm.ident, buf, hgs); else buf.writestring(s.prm.ident.toString()); buf.writestring("; "); - s.lwr.expressionToBuffer(buf, &hgs); + s.lwr.expressionToBuffer(buf, hgs); buf.writestring(" .. "); - s.upr.expressionToBuffer(buf, &hgs); + s.upr.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); } @@ -1205,7 +1232,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitMixinDeclaration(MixinDeclaration d) { buf.writestring("mixin("); - argsToBuffer(d.exps, buf, &hgs, null); + argsToBuffer(d.exps, buf, hgs, null); buf.writestring(");"); buf.writenl(); } @@ -1213,7 +1240,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitUserAttributeDeclaration(UserAttributeDeclaration d) { buf.writestring("@("); - argsToBuffer(d.atts, buf, &hgs); + argsToBuffer(d.atts, buf, hgs); buf.writeByte(')'); visitAttribDeclaration(d); } @@ -1223,7 +1250,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (!constraint) return; buf.writestring(" if ("); - constraint.expressionToBuffer(buf, &hgs); + constraint.expressionToBuffer(buf, hgs); buf.writeByte(')'); } @@ -1241,7 +1268,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); requireDo = false; @@ -1249,7 +1276,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) else { buf.writenl(); - frequire.statementToBuffer(buf, &hgs); + frequire.statementToBuffer(buf, hgs); requireDo = true; } } @@ -1269,7 +1296,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(fensure.id.toString()); } buf.writestring("; "); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writeByte(')'); buf.writenl(); requireDo = false; @@ -1283,7 +1310,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte(')'); } buf.writenl(); - fensure.ensure.statementToBuffer(buf, &hgs); + fensure.ensure.statementToBuffer(buf, hgs); requireDo = true; } } @@ -1293,7 +1320,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void bodyToBuffer(FuncDeclaration f) { - if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) + if (!f.fbody || (hgs.hdrgen && hgs.doFuncBodies == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) { if (!f.fbody && (f.fensures || f.frequires)) { @@ -1331,7 +1358,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte('{'); buf.writenl(); buf.level++; - f.fbody.statementToBuffer(buf, &hgs); + f.fbody.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); @@ -1349,7 +1376,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (i) buf.writestring(", "); - typeToBuffer(b.type, null, buf, &hgs); + typeToBuffer(b.type, null, buf, hgs); } } @@ -1365,7 +1392,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) assert(fd.type); if (stcToBuffer(buf, fd.storage_class)) buf.writeByte(' '); - functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, &hgs, d); + functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d); visitTemplateConstraint(d.constraint); hgs.tpltMember++; bodyToBuffer(fd); @@ -1407,7 +1434,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, vd.storage_class)) buf.writeByte(' '); if (vd.type) - typeToBuffer(vd.type, vd.ident, buf, &hgs); + typeToBuffer(vd.type, vd.ident, buf, hgs); else buf.writestring(vd.ident.toString()); buf.writeByte('('); @@ -1418,9 +1445,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(" = "); ExpInitializer ie = vd._init.isExpInitializer(); if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, &hgs); + (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); else - vd._init.initializerToBuffer(buf, &hgs); + vd._init.initializerToBuffer(buf, hgs); } buf.writeByte(';'); buf.writenl(); @@ -1468,21 +1495,21 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitTemplateInstance(TemplateInstance ti) { buf.writestring(ti.name.toChars()); - tiargsToBuffer(ti, buf, &hgs); + tiargsToBuffer(ti, buf, hgs); if (hgs.fullDump) { buf.writenl(); - dumpTemplateInstance(ti, buf, &hgs); + dumpTemplateInstance(ti, buf, hgs); } } void visitTemplateMixin(TemplateMixin tm) { buf.writestring("mixin "); - typeToBuffer(tm.tqual, null, buf, &hgs); - tiargsToBuffer(tm, buf, &hgs); - if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0) + typeToBuffer(tm.tqual, null, buf, hgs); + tiargsToBuffer(tm, buf, hgs); + if (tm.ident && memcmp(tm.ident.toString().ptr, cast(const(char)*) "__mixin", 7) != 0) { buf.writeByte(' '); buf.writestring(tm.ident.toString()); @@ -1490,7 +1517,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writeByte(';'); buf.writenl(); if (hgs.fullDump) - dumpTemplateInstance(tm, buf, &hgs); + dumpTemplateInstance(tm, buf, hgs); } void visitEnumDeclaration(EnumDeclaration d) @@ -1506,7 +1533,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.memtype) { buf.writestring(" : "); - typeToBuffer(d.memtype, null, buf, &hgs); + typeToBuffer(d.memtype, null, buf, hgs); } if (!d.members) { @@ -1654,7 +1681,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); - typeToBuffer(d.type, d.ident, buf, &hgs); + typeToBuffer(d.type, d.ident, buf, hgs); } else if (d.ident) { @@ -1663,7 +1690,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) buf.writestring(" = "); if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); - typeToBuffer(d.type, null, buf, &hgs); + typeToBuffer(d.type, null, buf, hgs); hgs.declstring = false; } buf.writeByte(';'); @@ -1677,7 +1704,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (d.aliassym) toCBuffer(d.aliassym, buf, hgs); else // d.type - typeToBuffer(d.type, null, buf, &hgs); + typeToBuffer(d.type, null, buf, hgs); buf.writeByte(';'); buf.writenl(); } @@ -1697,7 +1724,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, f.storage_class)) buf.writeByte(' '); auto tf = f.type.isTypeFunction(); - typeToBuffer(tf, f.ident, buf, &hgs); + typeToBuffer(tf, f.ident, buf, hgs); if (hgs.hdrgen) { @@ -1711,7 +1738,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) bodyToBuffer(f); hgs.autoMember--; } - else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false && !hgs.insideFuncBody) + else if (hgs.tpltMember == 0 && hgs.doFuncBodies == false && !hgs.insideFuncBody) { if (!f.fbody) { @@ -1745,8 +1772,8 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) TypeFunction tf = cast(TypeFunction)f.type; if (!f.inferRetType && tf.next) - typeToBuffer(tf.next, null, buf, &hgs); - parametersToBuffer(tf.parameterList, buf, &hgs); + typeToBuffer(tf.next, null, buf, hgs); + parametersToBuffer(tf.parameterList, buf, hgs); // https://issues.dlang.org/show_bug.cgi?id=20074 void printAttribute(string str) @@ -1769,7 +1796,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (rs && rs.exp) { buf.writestring(" => "); - rs.exp.expressionToBuffer(buf, &hgs); + rs.exp.expressionToBuffer(buf, hgs); } else { @@ -1838,7 +1865,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) { assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); - (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, &hgs); + (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writestring(");"); buf.writenl(); } @@ -1863,9 +1890,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); Identifier id = d.isAnonymous() ? null : d.ident; - typeToBuffer(d.type, id, buf, &hgs); + typeToBuffer(d.type, id, buf, hgs); buf.writestring(" : "); - d.width.expressionToBuffer(buf, &hgs); + d.width.expressionToBuffer(buf, hgs); buf.writeByte(';'); buf.writenl(); } @@ -1879,7 +1906,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitModule(Module m) { - moduleToBuffer2(m, buf, &hgs); + moduleToBuffer2(m, buf, hgs); } extern (C++) @@ -1948,7 +1975,7 @@ private void visitTemplateParameters(TemplateParameters* parameters, ref OutBuff { if (i) buf.writestring(", "); - p.templateParameterToBuffer(buf, &hgs); + toCBuffer(p, buf, hgs); } } @@ -1968,11 +1995,15 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, { auto ie = v._init.isExpInitializer(); if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, &hgs); + (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); else - v._init.initializerToBuffer(buf, &hgs); + v._init.initializerToBuffer(buf, hgs); } + const commentIt = hgs.importcHdr && isSpecialCName(v.ident); + if (commentIt) + buf.writestring("/+"); + if (anywritten) { buf.writestring(", "); @@ -1989,7 +2020,7 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, if (stcToBuffer(buf, stc)) buf.writeByte(' '); if (v.type) - typeToBuffer(v.type, v.ident, buf, &hgs); + typeToBuffer(v.type, v.ident, buf, hgs); else if (useTypeof) { buf.writestring("typeof("); @@ -2005,13 +2036,36 @@ private void visitVarDecl(VarDeclaration v, bool anywritten, ref OutBuffer buf, buf.writestring(" = "); vinit(v); } + if (commentIt) + buf.writestring("+/"); } +/************************************* + * The names __DATE__, __TIME__,__EOF__, __VENDOR__, __TIMESTAMP__, __VERSION__ + * are special to the D lexer and cannot be used as D source variable names. + * Params: + * id = name to check + * Returns: + * true if special C name + */ +private bool isSpecialCName(Identifier id) +{ + auto s = id.toString(); + if (s.length >= 7 && s[0] == '_' && s[1] == '_' && + (id == Id.DATE || + id == Id.TIME || + id == Id.EOFX || + id == Id.VENDOR || + id == Id.TIMESTAMP || + id == Id.VERSIONX)) + return true; + return false; +} /********************************************* * Print expression to buffer. */ -private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { void visit(Expression e) { @@ -2020,7 +2074,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* void visitInteger(IntegerExp e) { - const dinteger_t v = e.toInteger(); + const ulong v = e.toInteger(); if (e.type) { Type t = e.type; @@ -2037,7 +2091,8 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* { if ((cast(EnumMember)em).value.toInteger == v) { - buf.printf("%s.%s", sym.toChars(), em.ident.toChars()); + const id = em.ident.toString(); + buf.printf("%s.%.*s", sym.toChars(), cast(int)id.length, id.ptr); return ; } } @@ -2097,15 +2152,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* break; case Tpointer: buf.writestring("cast("); - buf.writestring(t.toChars()); - buf.writeByte(')'); - if (target.ptrsize == 8) - goto case Tuns64; - else if (target.ptrsize == 4 || - target.ptrsize == 2) - goto case Tuns32; - else - assert(0); + + HdrGenState hgs2; // should re-examine need for new hgs + hgs2.fullQual = (t.ty == Tclass && !t.mod); + toCBuffer(t, buf, null, hgs2); + + buf.writestring(")cast(size_t)"); + goto case Tuns64; case Tvoid: buf.writestring("cast(void)0"); @@ -2114,11 +2167,8 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* default: /* This can happen if errors, such as * the type is painted on like in fromConstInitializer(). + * Just ignore */ - if (!global.errors) - { - assert(0); - } break; } } @@ -2264,7 +2314,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* { e.sds.dsymbolToBuffer(buf, hgs); } - else if (hgs !is null && hgs.ddoc) + else if (hgs.ddoc) { // fixes bug 6491 if (auto m = e.sds.isModule()) @@ -2381,7 +2431,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* // which isn't correct as regular D code. buf.writeByte('('); - visitVarDecl(var, false, buf, *hgs); + visitVarDecl(var, false, buf, hgs); buf.writeByte(';'); buf.writeByte(')'); @@ -2424,7 +2474,10 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* typeToBuffer(e.targ, e.id, buf, hgs); if (e.tok2 != TOK.reserved) { - buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2)); + buf.writeByte(' '); + buf.writestring(Token.toString(e.tok)); + buf.writeByte(' '); + buf.writestring(Token.toString(e.tok2)); } else if (e.tspec) { @@ -2437,7 +2490,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* if (e.parameters && e.parameters.length) { buf.writestring(", "); - visitTemplateParameters(e.parameters, buf, *hgs); + visitTemplateParameters(e.parameters, buf, hgs); } buf.writeByte(')'); } @@ -2450,7 +2503,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, HdrGenState* void visitLoweredAssignExp(LoweredAssignExp e) { - if (global.params.vcg_ast) + if (hgs.vcg_ast) { expressionToBuffer(e.lowering, buf, hgs); return; @@ -2890,10 +2943,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 @@ -2915,12 +2968,12 @@ public: if (tp.specType) { buf.writestring(" : "); - typeToBuffer(tp.specType, null, *buf, hgs); + typeToBuffer(tp.specType, null, *buf, *hgs); } if (tp.defaultType) { buf.writestring(" = "); - typeToBuffer(tp.defaultType, null, *buf, hgs); + typeToBuffer(tp.defaultType, null, *buf, *hgs); } } @@ -2934,33 +2987,33 @@ public: { buf.writestring("alias "); if (tp.specType) - typeToBuffer(tp.specType, tp.ident, *buf, hgs); + typeToBuffer(tp.specType, tp.ident, *buf, *hgs); else buf.writestring(tp.ident.toString()); if (tp.specAlias) { buf.writestring(" : "); - objectToBuffer(tp.specAlias, *buf, hgs); + objectToBuffer(tp.specAlias, *buf, *hgs); } if (tp.defaultAlias) { buf.writestring(" = "); - objectToBuffer(tp.defaultAlias, *buf, hgs); + objectToBuffer(tp.defaultAlias, *buf, *hgs); } } override void visit(TemplateValueParameter tp) { - typeToBuffer(tp.valType, tp.ident, *buf, hgs); + typeToBuffer(tp.valType, tp.ident, *buf, *hgs); if (tp.specValue) { buf.writestring(" : "); - tp.specValue.expressionToBuffer(*buf, hgs); + tp.specValue.expressionToBuffer(*buf, *hgs); } if (tp.defaultValue) { buf.writestring(" = "); - tp.defaultValue.expressionToBuffer(*buf, hgs); + tp.defaultValue.expressionToBuffer(*buf, *hgs); } } @@ -2971,9 +3024,9 @@ public: } } -private void conditionToBuffer(Condition c, ref OutBuffer buf, HdrGenState* hgs) +private void conditionToBuffer(Condition c, ref OutBuffer buf, ref HdrGenState hgs) { - scope v = new ConditionPrettyPrintVisitor(&buf, hgs); + scope v = new ConditionPrettyPrintVisitor(&buf, &hgs); c.accept(v); } @@ -3013,19 +3066,19 @@ public: override void visit(StaticIfCondition c) { buf.writestring("static if ("); - c.exp.expressionToBuffer(*buf, hgs); + c.exp.expressionToBuffer(*buf, *hgs); buf.writeByte(')'); } } void toCBuffer(const Statement s, ref OutBuffer buf, ref HdrGenState hgs) { - (cast()s).statementToBuffer(buf, &hgs); + (cast()s).statementToBuffer(buf, hgs); } void toCBuffer(const Type t, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs) { - typeToBuffer(cast() t, ident, buf, &hgs); + typeToBuffer(cast() t, ident, buf, hgs); } // used from TemplateInstance::toChars() and TemplateMixin::toChars() @@ -3035,12 +3088,12 @@ void toCBufferInstance(const TemplateInstance ti, ref OutBuffer buf, bool qualif hgs.fullQual = qualifyTypes; buf.writestring(ti.name.toChars()); - tiargsToBuffer(cast() ti, buf, &hgs); + tiargsToBuffer(cast() ti, buf, hgs); } void toCBuffer(const Initializer iz, ref OutBuffer buf, ref HdrGenState hgs) { - initializerToBuffer(cast() iz, buf, &hgs); + initializerToBuffer(cast() iz, buf, hgs); } bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe @@ -3233,7 +3286,7 @@ extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure @safe } // Print the full function signature with correct ident, attributes and template args -void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td) +void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier ident, ref HdrGenState hgs, TemplateDeclaration td) { //printf("TypeFunction::toCBuffer() this = %p\n", this); visitFuncIdentWithPrefix(tf, ident, td, buf, hgs); @@ -3243,12 +3296,12 @@ void functionToBufferFull(TypeFunction tf, ref OutBuffer buf, const Identifier i void functionToBufferWithIdent(TypeFunction tf, ref OutBuffer buf, const(char)* ident, bool isStatic) { HdrGenState hgs; - visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs, isStatic); + visitFuncIdentWithPostfix(tf, ident.toDString(), buf, hgs, isStatic); } void toCBuffer(const Expression e, ref OutBuffer buf, ref HdrGenState hgs) { - expressionPrettyPrint(cast()e, buf, &hgs); + expressionPrettyPrint(cast()e, buf, hgs); } /************************************************** @@ -3263,16 +3316,10 @@ void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments) { if (i) buf.writestring(", "); - typeToBuffer(arg.type, null, buf, &hgs); + typeToBuffer(arg.type, null, buf, hgs); } } -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) @@ -3282,7 +3329,7 @@ void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects) { if (i) buf.writestring(", "); - objectToBuffer(o, buf, &hgs); + objectToBuffer(o, buf, hgs); } } @@ -3296,7 +3343,7 @@ extern (C++) const(char)* parametersTypeToChars(ParameterList pl) { OutBuffer buf; HdrGenState hgs; - parametersToBuffer(pl, buf, &hgs); + parametersToBuffer(pl, buf, hgs); return buf.extractChars(); } @@ -3314,7 +3361,7 @@ const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQua HdrGenState hgs; hgs.fullQual = fullQual; - parameterToBuffer(parameter, buf, &hgs); + parameterToBuffer(parameter, buf, hgs); if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.length - 1]) { @@ -3332,7 +3379,7 @@ const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQua * hgs = context */ -private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, HdrGenState* hgs) +private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('('); foreach (i; 0 .. pl.length) @@ -3370,7 +3417,7 @@ private void parametersToBuffer(ParameterList pl, ref OutBuffer buf, HdrGenState * buf = buffer to write it to * hgs = context */ -private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) +private void parameterToBuffer(Parameter p, ref OutBuffer buf, ref HdrGenState hgs) { if (p.userAttribDecl) { @@ -3393,7 +3440,7 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) if (p.storageClass & STC.in_) { buf.writestring("in "); - if (global.params.previewIn && p.storageClass & STC.ref_) + if ((p.storageClass & (STC.constscoperef | STC.ref_)) == (STC.constscoperef | STC.ref_)) stc &= ~STC.ref_; } else if (p.storageClass & STC.lazy_) @@ -3408,14 +3455,15 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC.returnScope))) buf.writeByte(' '); + const(char)[] s; if (p.storageClass & STC.alias_) { if (p.ident) buf.writestring(p.ident.toString()); } - else if (p.type.ty == Tident && - (cast(TypeIdentifier)p.type).ident.toString().length > 3 && - strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0) + else if (p.type.isTypeIdentifier() && + (s = p.type.isTypeIdentifier().ident.toString()).length > 3 && + s[0..3] == "__T") { // print parameter name, instead of undetermined type parameter buf.writestring(p.ident.toString()); @@ -3442,7 +3490,7 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, HdrGenState* hgs) * basis = replace `null`s in argument list with this expression (for sparse array literals) * names = if non-null, use these as the names for the arguments */ -private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, HdrGenState* hgs, Expression basis = null, Identifiers* names = null) +private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, ref HdrGenState hgs, Expression basis = null, Identifiers* names = null) { if (!expressions || !expressions.length) return; @@ -3493,26 +3541,23 @@ private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, HdrGenSta } } -private void sizeToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void sizeToBuffer(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { if (e.type == Type.tsize_t) { Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e); ex = ex.optimize(WANTvalue); - const dinteger_t uval = ex.op == EXP.int64 ? ex.toInteger() : cast(dinteger_t)-1; - if (cast(sinteger_t)uval >= 0) - { - dinteger_t sizemax = void; - if (target.ptrsize == 8) - sizemax = 0xFFFFFFFFFFFFFFFFUL; - else if (target.ptrsize == 4) - sizemax = 0xFFFFFFFFU; - else if (target.ptrsize == 2) - sizemax = 0xFFFFU; - else - assert(0); - if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL) + const ulong uval = ex.op == EXP.int64 ? ex.toInteger() : cast(ulong)-1; + if (cast(long)uval >= 0) + { + if (uval <= 0xFFFFU) + { + buf.print(uval); + return; + } + if (uval <= 0x7FFF_FFFF_FFFF_FFFFUL) { + buf.writestring("cast(size_t)"); buf.print(uval); return; } @@ -3521,7 +3566,7 @@ private void sizeToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) expToBuffer(e, PREC.assign, buf, hgs); } -private void expressionToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hgs) +private void expressionToBuffer(Expression e, ref OutBuffer buf, ref HdrGenState hgs) { expressionPrettyPrint(e, buf, hgs); } @@ -3530,7 +3575,7 @@ private void expressionToBuffer(Expression e, ref OutBuffer buf, HdrGenState* hg * Write expression out to buf, but wrap it * in ( ) if its precedence is less than pr. */ -private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, HdrGenState* hgs) +private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, ref HdrGenState hgs) { debug { @@ -3564,7 +3609,7 @@ private void expToBuffer(Expression e, PREC pr, ref OutBuffer buf, HdrGenState* /************************************************** * An entry point to pretty-print type. */ -private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, HdrGenState* hgs, +private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, ref HdrGenState hgs, ubyte modMask = 0) { if (auto tf = t.isTypeFunction()) @@ -3580,7 +3625,7 @@ private void typeToBuffer(Type t, const Identifier ident, ref OutBuffer buf, Hdr } } -private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, HdrGenState* hgs) +private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, ref HdrGenState hgs) { // Tuples and functions don't use the type constructor syntax if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple) @@ -3616,7 +3661,7 @@ private void visitWithMask(Type t, ubyte modMask, ref OutBuffer buf, HdrGenState } -private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, HdrGenState* hgs) +private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('{'); buf.writenl(); @@ -3639,7 +3684,7 @@ private void dumpTemplateInstance(TemplateInstance ti, ref OutBuffer buf, HdrGen } -private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* hgs) +private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, ref HdrGenState hgs) { buf.writeByte('!'); if (ti.nest) @@ -3659,7 +3704,9 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* { if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.length == 0)) { - buf.writestring(t.toChars()); + HdrGenState hgs2; // re-examine need for new hgs + hgs2.fullQual = (t.ty == Tclass && !t.mod); + toCBuffer(t, buf, null, hgs2); return; } } @@ -3667,7 +3714,7 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* { if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_) { - buf.writestring(e.toChars()); + toCBuffer(e, buf, hgs); return; } } @@ -3688,7 +3735,7 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, HdrGenState* * This makes a 'pretty' version of the template arguments. * It's analogous to genIdent() which makes a mangled version. */ -private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs) +private void objectToBuffer(RootObject oarg, ref OutBuffer buf, ref HdrGenState hgs) { //printf("objectToBuffer()\n"); /* The logic of this should match what genIdent() does. The _dynamic_cast() @@ -3709,8 +3756,10 @@ private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs } else if (Dsymbol s = isDsymbol(oarg)) { - const p = s.ident ? s.ident.toChars() : s.toChars(); - buf.writestring(p); + if (s.ident) + buf.writestring(s.ident.toString()); + else + buf.writestring(s.toChars()); } else if (auto v = isTuple(oarg)) { @@ -3741,7 +3790,7 @@ private void objectToBuffer(RootObject oarg, ref OutBuffer buf, HdrGenState* hgs } -private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref OutBuffer buf, HdrGenState* hgs, bool isStatic) +private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref OutBuffer buf, ref HdrGenState hgs, bool isStatic) { if (t.inuse) { @@ -3786,7 +3835,7 @@ private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, ref O } private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td, - ref OutBuffer buf, HdrGenState* hgs) + ref OutBuffer buf, ref HdrGenState hgs) { if (t.inuse) { @@ -3842,7 +3891,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te { if (i) buf.writestring(", "); - p.templateParameterToBuffer(buf, hgs); + toCBuffer(p, buf, hgs); } buf.writeByte(')'); } @@ -3855,7 +3904,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te } -private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState* hgs) +private void initializerToBuffer(Initializer inx, ref OutBuffer buf, ref HdrGenState hgs) { void visitError(ErrorInitializer iz) { @@ -3867,6 +3916,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"); @@ -3923,7 +3977,7 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState if (d.exp) { buf.writeByte('['); - toCBuffer(d.exp, buf, *hgs); + toCBuffer(d.exp, buf, hgs); buf.writeByte(']'); } else @@ -3944,7 +3998,7 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState } -private void typeToBufferx(Type t, ref OutBuffer buf, HdrGenState* hgs) +private void typeToBufferx(Type t, ref OutBuffer buf, ref HdrGenState hgs) { void visitType(Type t) { @@ -4134,13 +4188,13 @@ private void typeToBufferx(Type t, ref OutBuffer buf, HdrGenState* hgs) buf.writestring("const "); if (hgs.importcHdr && t.id) { - buf.writestring(t.id.toChars()); + buf.writestring(t.id.toString()); return; } - buf.writestring(Token.toChars(t.tok)); + buf.writestring(Token.toString(t.tok)); buf.writeByte(' '); if (t.id) - buf.writestring(t.id.toChars()); + buf.writestring(t.id.toString()); if (t.tok == TOK.enum_ && t.base && t.base.ty != TY.Tint32) { buf.writestring(" : "); diff --git a/dmd/hdrgen.h b/dmd/hdrgen.h index e43a35510c2..e38ca569354 100644 --- a/dmd/hdrgen.h +++ b/dmd/hdrgen.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Dave Fladebo * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -15,7 +15,7 @@ class Module; -void genhdrfile(Module *m, OutBuffer &buf); +void genhdrfile(Module *m, bool doFuncBodies, OutBuffer &buf); void genCppHdrFiles(Modules &ms); -void moduleToBuffer(OutBuffer& buf, Module *m); +void moduleToBuffer(OutBuffer& buf, bool vcg_ast, Module *m); const char *parametersTypeToChars(ParameterList pl); diff --git a/dmd/iasmgcc.d b/dmd/iasmgcc.d index 5494fecd70c..db51e734155 100644 --- a/dmd/iasmgcc.d +++ b/dmd/iasmgcc.d @@ -1,7 +1,7 @@ /** * Inline assembler for the GCC D compiler. * - * Copyright (C) 2018-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2018-2024 by The D Language Foundation, All Rights Reserved * Authors: Iain Buclaw * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d, _iasmgcc.d) @@ -302,7 +302,7 @@ Ldone: extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) { //printf("GccAsmStatement.semantic()\n"); - const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + const bool doUnittests = global.params.parsingUnittestsRequired(); scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink, &global.compileEnv, doUnittests); // Make a safe copy of the token list before parsing. @@ -341,7 +341,7 @@ extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) e = e.expressionSemantic(sc); // Check argument is a valid lvalue/rvalue. if (i < s.outputargs) - e = e.modifiableLvalue(sc, null); + e = e.modifiableLvalue(sc); else if (e.checkValue()) e = ErrorExp.get(); (*s.args)[i] = e; diff --git a/dmd/id.d b/dmd/id.d index 24a82cc5dea..68f8c16be5a 100644 --- a/dmd/id.d +++ b/dmd/id.d @@ -1,7 +1,7 @@ /** * Contains the `Id` struct with a list of predefined symbols the compiler knows about. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/id.d, _id.d) @@ -323,6 +323,8 @@ immutable Msgtable[] msgtable = { "_d_newitemTTrace" }, { "_d_newarrayT" }, { "_d_newarrayTTrace" }, + { "_d_newarraymTX" }, + { "_d_newarraymTXTrace" }, { "_d_assert_fail" }, { "dup" }, { "_aaApply" }, @@ -519,6 +521,7 @@ immutable Msgtable[] msgtable = { "udaSelector", "selector" }, { "udaOptional", "optional"}, { "udaMustUse", "mustuse" }, + { "udaStandalone", "standalone" }, // C names, for undefined identifier error messages { "NULL" }, diff --git a/dmd/id.h b/dmd/id.h index afaddc29374..03e46a63170 100644 --- a/dmd/id.h +++ b/dmd/id.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2017-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2017-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/identifier.d b/dmd/identifier.d index c2b2fbafa25..8ace310937d 100644 --- a/dmd/identifier.d +++ b/dmd/identifier.d @@ -1,7 +1,7 @@ /** * Defines an identifier, which is the name of a `Dsymbol`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d, _identifier.d) diff --git a/dmd/identifier.h b/dmd/identifier.h index e7b3ba60b0f..afd3664bfa8 100644 --- a/dmd/identifier.h +++ b/dmd/identifier.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/impcnvtab.d b/dmd/impcnvtab.d index b45880a2887..b899f810aab 100644 --- a/dmd/impcnvtab.d +++ b/dmd/impcnvtab.d @@ -6,7 +6,7 @@ * Specification: $(LINK2 https://dlang.org/spec/type.html#integer-promotions, Integer Promotions), * $(LINK2 https://dlang.org/spec/type.html#usual-arithmetic-conversions, Usual Arithmetic Conversions). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d, _impcnvtab.d) diff --git a/dmd/imphint.d b/dmd/imphint.d index 9e9466a38eb..ea2f13d9179 100644 --- a/dmd/imphint.d +++ b/dmd/imphint.d @@ -3,7 +3,7 @@ * * For example, prompt to `import std.stdio` when using `writeln`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d, _imphint.d) diff --git a/dmd/import.h b/dmd/import.h index 31ee61a65fb..bfbb5510134 100644 --- a/dmd/import.h +++ b/dmd/import.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -41,11 +41,7 @@ class Import final : public Dsymbol const char *kind() const override; Visibility visible() override; Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees - void importAll(Scope *sc) override; Dsymbol *toAlias() override; - 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; } diff --git a/dmd/importc.d b/dmd/importc.d index 98ac9038a0a..69a85ceec93 100644 --- a/dmd/importc.d +++ b/dmd/importc.d @@ -3,7 +3,7 @@ * * Specification: C11 * - * Copyright: Copyright (C) 2021-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2021-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/importc.d, _importc.d) @@ -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; diff --git a/dmd/init.d b/dmd/init.d index ebcd011f8a1..62bd41eea93 100644 --- a/dmd/init.d +++ b/dmd/init.d @@ -1,7 +1,7 @@ /** * Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d) @@ -12,21 +12,15 @@ module dmd.init; import core.stdc.stdio; -import core.checkedint; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; -import dmd.dsymbol; import dmd.expression; -import dmd.globals; -import dmd.hdrgen; import dmd.identifier; import dmd.location; import dmd.mtype; -import dmd.common.outbuffer; import dmd.rootobject; -import dmd.tokens; import dmd.visitor; enum NeedInterpret : int @@ -68,6 +62,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 +110,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 +283,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 +374,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; diff --git a/dmd/init.h b/dmd/init.h index 67d0527a3b2..b4e15e3fa98 100644 --- a/dmd/init.h +++ b/dmd/init.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -20,6 +20,7 @@ class Expression; class Type; class ErrorInitializer; class VoidInitializer; +class DefaultInitializer; class StructInitializer; class ArrayInitializer; class ExpInitializer; @@ -37,6 +38,7 @@ class Initializer : public ASTNode ErrorInitializer *isErrorInitializer(); VoidInitializer *isVoidInitializer(); + DefaultInitializer *isDefaultInitializer(); StructInitializer *isStructInitializer(); ArrayInitializer *isArrayInitializer(); ExpInitializer *isExpInitializer(); @@ -53,6 +55,14 @@ class VoidInitializer final : public Initializer 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: diff --git a/dmd/initsem.d b/dmd/initsem.d index 2020f0512cc..5fe3b932599 100644 --- a/dmd/initsem.d +++ b/dmd/initsem.d @@ -1,7 +1,7 @@ /** * Semantic analysis of initializers. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d, _initsem.d) @@ -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; @@ -38,6 +39,7 @@ import dmd.init; import dmd.location; import dmd.mtype; import dmd.opover; +import dmd.optimize; import dmd.statement; import dmd.target; import dmd.tokens; @@ -105,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() @@ -118,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; @@ -190,7 +199,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ uint length; const(uint) amax = 0x80000000; bool errors = false; - //printf("ArrayInitializer::semantic(%s), ai: %s %p\n", t.toChars(), i.toChars(), i); + //printf("ArrayInitializer::semantic(%s), ai: %s\n", t.toChars(), toChars(i)); if (i.sem) // if semantic() already run { return i; @@ -591,7 +600,17 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ Initializer visitC(CInitializer ci) { - //printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), ci.toChars()); + //printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), toChars(ci)); + static if (0) + if (auto ts = tx.isTypeStruct()) + { + import dmd.common.outbuffer; + OutBuffer buf; + HdrGenState hgs; + toCBuffer(ts.sym, buf, hgs); + printf("%s\n", buf.peekChars()); + } + /* Rewrite CInitializer into ExpInitializer, ArrayInitializer, or StructInitializer */ t = t.toBasetype(); @@ -784,8 +803,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ Loop1: for (size_t index = 0; index < ci.initializerList.length; ) { - CInitializer cprev; - L1: DesigInit di = ci.initializerList[index]; Designators* dlist = di.designatorList; if (dlist) @@ -813,14 +830,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ continue Loop1; } } - if (cprev) - { - /* The peeling didn't work, so unpeel it - */ - ci = cprev; - di = ci.initializerList[index]; - goto L2; - } error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars()); return err(); } @@ -828,16 +837,55 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { if (fieldi == nfields) break; - if (index == 0 && ci.initializerList.length == 1 && di.initializer.isCInitializer()) + + auto ix = di.initializer; + + /* If a C initializer is wrapped in a C initializer, with no designators, + * peel off the outer one + */ + if (ix.isCInitializer()) + { + CInitializer cix = ix.isCInitializer(); + if (cix.initializerList.length == 1) + { + DesigInit dix = cix.initializerList[0]; + if (!dix.designatorList) + { + Initializer inix = dix.initializer; + if (inix.isCInitializer()) + ix = inix; + } + } + } + + if (auto cix = ix.isCInitializer()) { - /* Try peeling off this set of { } and see if it works + /* ImportC loses the structure from anonymous structs, but this is retained + * by the initializer syntax. if a CInitializer has a Designator, it is probably + * a nested anonymous struct */ - cprev = ci; - ci = di.initializer.isCInitializer(); - goto L1; + if (cix.initializerList.length) + { + DesigInit dix = cix.initializerList[0]; + Designators* dlistx = dix.designatorList; + if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident) + { + auto id = (*dlistx)[0].ident; + foreach (k, f; sd.fields[]) // linear search for now + { + if (f.ident == id) + { + fieldi = k; + si.addInit(id, dix.initializer); + ++fieldi; + ++index; + continue Loop1; + } + } + } + } } - L2: VarDeclaration field; while (1) // skip field if it overlaps with previously seen fields { @@ -848,10 +896,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ if (fieldi == nfields) break; } + auto tn = field.type.toBasetype(); auto tnsa = tn.isTypeSArray(); auto tns = tn.isTypeStruct(); - auto ix = di.initializer; + if (tnsa && ix.isExpInitializer()) { ExpInitializer ei = ix.isExpInitializer(); @@ -990,7 +1039,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else { - error(ci.loc, "unrecognized C initializer `%s`", toChars(ci)); + error(ci.loc, "unrecognized C initializer `%s` for type `%s`", toChars(ci), t.toChars()); return err(); } } @@ -1016,6 +1065,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; @@ -1174,6 +1229,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(); diff --git a/dmd/inline.d b/dmd/inline.d index 4017a65784a..0be289e569b 100644 --- a/dmd/inline.d +++ b/dmd/inline.d @@ -4,7 +4,7 @@ * The AST is traversed, and every function call is considered for inlining using `inlinecost.d`. * The function call is then inlined if this cost is below a threshold. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inline.d, _inline.d) @@ -671,7 +671,6 @@ public: version (IN_LLVM) {} else { vto.csym = null; - vto.isym = null; } ids.from.push(vd); @@ -730,7 +729,7 @@ version (IN_LLVM) {} else auto lowering = ne.lowering; if (lowering) if (auto ce = lowering.isCallExp()) - if (ce.f.ident == Id._d_newarrayT) + if (ce.f.ident == Id._d_newarrayT || ce.f.ident == Id._d_newarraymTX) { ne.lowering = doInlineAs!Expression(lowering, ids); goto LhasLowering; @@ -850,7 +849,6 @@ version (IN_LLVM) {} else version (IN_LLVM) {} else { vto.csym = null; - vto.isym = null; } ids.from.push(vd); @@ -882,7 +880,6 @@ version (IN_LLVM) {} else version (IN_LLVM) {} else { vto.csym = null; - vto.isym = null; } ids.from.push(vd); @@ -2219,9 +2216,10 @@ private void expandInline(Loc callLoc, FuncDeclaration fd, FuncDeclaration paren auto e = doInlineAs!Expression(fd.fbody, ids); fd.inlineNest--; + import dmd.expressionsem : toLvalue; // https://issues.dlang.org/show_bug.cgi?id=11322 if (tf.isref) - e = e.toLvalue(null, null); + e = e.toLvalue(null, "`ref` return"); /* If the inlined function returns a copy of a struct, * and then the return value is used subsequently as an diff --git a/dmd/inlinecost.d b/dmd/inlinecost.d index d69a96814e6..90334c8ca58 100644 --- a/dmd/inlinecost.d +++ b/dmd/inlinecost.d @@ -1,7 +1,7 @@ /** * Compute the cost of inlining a function call by counting expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inlinecost.d, _inlinecost.d) diff --git a/dmd/intrange.d b/dmd/intrange.d index 442668f6337..29c8b505cde 100644 --- a/dmd/intrange.d +++ b/dmd/intrange.d @@ -1,7 +1,7 @@ /** * Implement $(LINK2 https://digitalmars.com/articles/b62.html, Value Range Propagation). * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d, _intrange.d) diff --git a/dmd/json.d b/dmd/json.d index 11ab8169099..9819c3a90cc 100644 --- a/dmd/json.d +++ b/dmd/json.d @@ -1,7 +1,7 @@ /** * Code for generating .json descriptions of the module when passing the `-X` flag to dmd. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/json.d, _json.d) diff --git a/dmd/json.h b/dmd/json.h index 09fdecdb9ee..8a949114feb 100644 --- a/dmd/json.h +++ b/dmd/json.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/lambdacomp.d b/dmd/lambdacomp.d index ec070d8ec0b..a1db8d52548 100644 --- a/dmd/lambdacomp.d +++ b/dmd/lambdacomp.d @@ -5,7 +5,7 @@ * The serialization is a string which contains the type of the parameters and the string * represantation of the lambda expression. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lamdbacomp.d, _lambdacomp.d) @@ -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; @@ -243,7 +244,7 @@ public: { // we must check what the identifier expression is. Dsymbol scopesym; - Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); + Dsymbol s = sc.search(exp.loc, exp.ident, scopesym); if (s) { auto v = s.isVarDeclaration(); diff --git a/dmd/lexer.d b/dmd/lexer.d index ac51e073e8a..efc84a3b7a7 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/lex.html, Lexical) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d, _lexer.d) @@ -2008,23 +2008,17 @@ class Lexer case 'u': dchar d1; size_t idx; - auto msg = utf_decodeChar(str, idx, d1); - dchar d2 = 0; - if (idx < n && !msg) - msg = utf_decodeChar(str, idx, d2); - if (msg) - error(loc, "%.*s", cast(int)msg.length, msg.ptr); - else if (idx < n) - error(loc, "max number of chars in 16 bit character literal is 2, had %d", - cast(int)((n + 1) >> 1)); - else if (d1 > 0x1_0000) - error(loc, "%d does not fit in 16 bits", d1); - else if (d2 > 0x1_0000) - error(loc, "%d does not fit in 16 bits", d2); - u = d1; - if (d2) - u = (d1 << 16) | d2; - break; + while (idx < n) + { + string msg = utf_decodeChar(str, idx, d1); + if (msg) + error(loc, "%.*s", cast(int)msg.length, msg.ptr); + } + if (d1 >= 0x1_0000) + error(loc, "x%x does not fit in 16 bits", d1); + t.unsvalue = d1; + t.value = TOK.wcharLiteral; // C11 6.4.4.4-9 + return; case 'U': dchar d; @@ -2035,8 +2029,9 @@ class Lexer else if (idx < n) error(loc, "max number of chars in 32 bit character literal is 1, had %d", cast(int)((n + 3) >> 2)); - u = d; - break; + t.unsvalue = d; + t.value = TOK.dcharLiteral; // C11 6.4.4.4-9 + return; default: assert(0); @@ -3261,6 +3256,24 @@ version (IN_LLVM) { /* *always* map C `long double` literals to D `real` ones */ scanloc.linnum = scanloc.linnum + 1; line = p; } + + /**************************** + * Print the tokens from the current `token` to the end, + * while not advancing the parser forward. + * Useful for debugging. + */ + void printRestOfTokens() + { + auto tk = &token; + while (1) + { + printf("%s ", (*tk).toChars()); + if (tk.value == TOK.endOfFile || tk.value == TOK.endOfLine) + break; + tk = peek(tk); + } + printf("\n"); + } } diff --git a/dmd/location.d b/dmd/location.d index 9fe48b88844..d71ea588c91 100644 --- a/dmd/location.d +++ b/dmd/location.d @@ -1,7 +1,7 @@ /** * Encapsulates file/line/column locations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/location.d, _location.d) diff --git a/dmd/main.d b/dmd/main.d index ee989d2e316..9a240392295 100644 --- a/dmd/main.d +++ b/dmd/main.d @@ -6,7 +6,7 @@ * utilities needed for arguments parsing, path manipulation, etc... * This file is not shared with other compilers which use the DMD front-end. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/main.d, _main.d) @@ -546,7 +546,7 @@ version (IN_LLVM) message("import %s", m.toChars()); buf.reset(); // reuse the buffer - genhdrfile(m, buf); + genhdrfile(m, params.dihdr.fullOutput, buf); if (!writeFile(m.loc, m.hdrfile.toString(), buf[])) fatal(); } @@ -702,7 +702,7 @@ version (IN_LLVM) { auto buf = OutBuffer(); buf.doindent = 1; - moduleToBuffer(buf, mod); + moduleToBuffer(buf, params.vcg_ast, mod); // write the output to $(filename).cg auto cgFilename = FileName.addExt(mod.srcfile.toString(), "cg"); diff --git a/dmd/mangle.h b/dmd/mangle.h index aa246988f2e..68064a9210a 100644 --- a/dmd/mangle.h +++ b/dmd/mangle.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/mars.d b/dmd/mars.d index 48fb7760184..9c091b1075a 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -4,7 +4,7 @@ * utilities needed for arguments parsing, path manipulation, etc... * This file is not shared with other compilers which use the DMD front-end. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mars.d, _mars.d) @@ -390,6 +390,8 @@ void setDefaultLibrary(ref Param params, const ref Target target) if (driverParams.debuglibname is null) driverParams.debuglibname = driverParams.defaultlibname; + else if (!driverParams.debuglibname.length) // if `-debuglib=` (i.e. an empty debuglib) + driverParams.debuglibname = null; } } // !IN_LLVM @@ -898,6 +900,44 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param } else if (arg == "-shared") driverParams.dll = true; + else if (startsWith(p + 1, "visibility=")) + { + const(char)[] vis = arg["-visibility=".length .. $]; + + switch (vis) + { + case "default": + driverParams.exportVisibility = ExpVis.default_; + break; + case "hidden": + driverParams.exportVisibility = ExpVis.hidden; + break; + case "public": + driverParams.exportVisibility = ExpVis.public_; + break; + default: + error("unknown visibility '%.*s', must be 'default', 'hidden' or 'public'", cast(int) vis.length, vis.ptr); + } + } + else if (startsWith(p + 1, "dllimport=")) + { + const(char)[] imp = arg["-dllimport=".length .. $]; + + switch (imp) + { + case "none": + driverParams.symImport = SymImport.none; + break; + case "defaultLibsOnly": + driverParams.symImport = SymImport.defaultLibsOnly; + break; + case "all": + driverParams.symImport = SymImport.all; + break; + default: + error("unknown dllimport '%.*s', must be 'none', 'defaultLibsOnly' or 'all'", cast(int) imp.length, imp.ptr); + } + } else if (arg == "-fIBT") { driverParams.ibt = true; diff --git a/dmd/module.h b/dmd/module.h index 35628ec90ca..ecf8a9d6526 100644 --- a/dmd/module.h +++ b/dmd/module.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -51,7 +51,6 @@ class Package : public ScopeDsymbol 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(); @@ -97,7 +96,7 @@ class Module final : public Package Identifier *searchCacheIdent; Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags + SearchOptFlags searchCacheFlags; // cached flags d_bool insearch; // module from command line we're imported from, @@ -130,10 +129,8 @@ class Module final : public Package const char *kind() const override; bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise. Module *parse(); // syntactic parse - void importAll(Scope *sc) override; int needModuleInfo(); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; - bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override; + bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all) override; Dsymbol *symtabInsert(Dsymbol *s) override; static void runDeferredSemantic(); static void runDeferredSemantic2(); @@ -195,3 +192,4 @@ struct ModuleDeclaration }; extern void getLocalClasses(Module* mod, Array& aclasses); +FuncDeclaration *findGetMembers(ScopeDsymbol *dsym); diff --git a/dmd/mtype.d b/dmd/mtype.d index 485a959b4f5..0660842077a 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -1,7 +1,7 @@ /** * Defines a D type. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d) @@ -19,7 +19,6 @@ import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; -import dmd.attrib; import dmd.astenums; import dmd.ast_node; import dmd.gluelayer; @@ -35,7 +34,6 @@ import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; -import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.hdrgen; @@ -526,274 +524,12 @@ version (IN_LLVM) return mcache; } - /******************************* - * Covariant means that 'this' can substitute for 't', - * i.e. a pure function is a match for an impure type. - * Params: - * t = type 'this' is covariant with - * pstc = if not null, store STCxxxx which would make it covariant - * cppCovariant = true if extern(C++) function types should follow C++ covariant rules - * Returns: - * An enum value of either `Covariant.yes` or a reason it's not covariant. - */ - final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false) - { - version (none) - { - printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars()); - printf("deco = %p, %p\n", deco, t.deco); - // printf("ty = %d\n", next.ty); - printf("mod = %x, %x\n", mod, t.mod); - } - if (pstc) - *pstc = 0; - StorageClass stc = 0; - - bool notcovariant = false; - - if (equals(t)) - return Covariant.yes; - - TypeFunction t1 = this.isTypeFunction(); - TypeFunction t2 = t.isTypeFunction(); - - if (!t1 || !t2) - goto Ldistinct; - - if (t1.parameterList.varargs != t2.parameterList.varargs) - goto Ldistinct; - - if (t1.parameterList.parameters && t2.parameterList.parameters) - { - if (t1.parameterList.length != t2.parameterList.length) - goto Ldistinct; - - foreach (i, fparam1; t1.parameterList) - { - Parameter fparam2 = t2.parameterList[i]; - Type tp1 = fparam1.type; - Type tp2 = fparam2.type; - - if (!tp1.equals(tp2)) - { - if (tp1.ty == tp2.ty) - { - if (auto tc1 = tp1.isTypeClass()) - { - if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) - goto Lcov; - } - else if (auto ts1 = tp1.isTypeStruct()) - { - if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) - goto Lcov; - } - else if (tp1.ty == Tpointer) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - else if (tp1.ty == Tarray) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - else if (tp1.ty == Tdelegate) - { - if (tp2.implicitConvTo(tp1)) - goto Lcov; - } - } - goto Ldistinct; - } - Lcov: - notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); - - /* https://issues.dlang.org/show_bug.cgi?id=23135 - * extern(C++) mutable parameters are not covariant with const. - */ - if (t1.linkage == LINK.cpp && cppCovariant) - { - notcovariant |= tp1.isNaked() != tp2.isNaked(); - if (auto tpn1 = tp1.nextOf()) - notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked(); - } - } - } - else if (t1.parameterList.parameters != t2.parameterList.parameters) - { - if (t1.parameterList.length || t2.parameterList.length) - goto Ldistinct; - } - - // The argument lists match - if (notcovariant) - goto Lnotcovariant; - if (t1.linkage != t2.linkage) - goto Lnotcovariant; - - { - // Return types - Type t1n = t1.next; - Type t2n = t2.next; - - if (!t1n || !t2n) // happens with return type inference - goto Lnotcovariant; - - if (t1n.equals(t2n)) - goto Lcovariant; - if (t1n.ty == Tclass && t2n.ty == Tclass) - { - /* If same class type, but t2n is const, then it's - * covariant. Do this test first because it can work on - * forward references. - */ - if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) - goto Lcovariant; - - // If t1n is forward referenced: - ClassDeclaration cd = (cast(TypeClass)t1n).sym; - if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) - cd.dsymbolSemantic(null); - if (!cd.isBaseInfoComplete()) - { - return Covariant.fwdref; - } - } - if (t1n.ty == Tstruct && t2n.ty == Tstruct) - { - if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) - goto Lcovariant; - } - else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) - { - if (t1.isref && t2.isref) - { - // Treat like pointers to t1n and t2n - if (t1n.constConv(t2n) < MATCH.constant) - goto Lnotcovariant; - } - goto Lcovariant; - } - else if (t1n.ty == Tnull) - { - // NULL is covariant with any pointer type, but not with any - // dynamic arrays, associative arrays or delegates. - // https://issues.dlang.org/show_bug.cgi?id=8589 - // https://issues.dlang.org/show_bug.cgi?id=19618 - Type t2bn = t2n.toBasetype(); - if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass) - goto Lcovariant; - } - // bottom type is covariant to any type - else if (t1n.ty == Tnoreturn) - goto Lcovariant; - } - goto Lnotcovariant; - - Lcovariant: - if (t1.isref != t2.isref) - goto Lnotcovariant; - - if (!t1.isref && (t1.isScopeQual || t2.isScopeQual)) - { - StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0; - StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0; - if (t1.isreturn) - { - stc1 |= STC.return_; - if (!t1.isScopeQual) - stc1 |= STC.ref_; - } - if (t2.isreturn) - { - stc2 |= STC.return_; - if (!t2.isScopeQual) - stc2 |= STC.ref_; - } - if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) - goto Lnotcovariant; - } - - // We can subtract 'return ref' from 'this', but cannot add it - else if (t1.isreturn && !t2.isreturn) - goto Lnotcovariant; - - /* https://issues.dlang.org/show_bug.cgi?id=23135 - * extern(C++) mutable member functions are not covariant with const. - */ - if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked()) - goto Lnotcovariant; - - /* Can convert mutable to const - */ - if (!MODimplicitConv(t2.mod, t1.mod)) - { - version (none) - { - //stop attribute inference with const - // If adding 'const' will make it covariant - if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) - stc |= STC.const_; - else - goto Lnotcovariant; - } - else - { - goto Ldistinct; - } - } - - /* Can convert pure to impure, nothrow to throw, and nogc to gc - */ - if (!t1.purity && t2.purity) - stc |= STC.pure_; - - if (!t1.isnothrow && t2.isnothrow) - stc |= STC.nothrow_; - - if (!t1.isnogc && t2.isnogc) - stc |= STC.nogc; - - /* Can convert safe/trusted to system - */ - if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) - { - // Should we infer trusted or safe? Go with safe. - stc |= STC.safe; - } - - if (stc) - { - if (pstc) - *pstc = stc; - goto Lnotcovariant; - } - - //printf("\tcovaraint: 1\n"); - return Covariant.yes; - - Ldistinct: - //printf("\tcovaraint: 0\n"); - return Covariant.distinct; - - Lnotcovariant: - //printf("\tcovaraint: 2\n"); - return Covariant.no; - } - /******************************** * For pretty-printing a type. */ final override const(char)* toChars() const { - OutBuffer buf; - buf.reserve(16); - HdrGenState hgs; - hgs.fullQual = (ty == Tclass && !mod); - - toCBuffer(this, buf, null, hgs); - return buf.extractChars(); + return dmd.hdrgen.toChars(this); } /// ditto @@ -1065,17 +801,6 @@ version (IN_LLVM) return isscalar(); } - /********************************* - * Check type to see if it is based on a deprecated symbol. - */ - void checkDeprecated(const ref Loc loc, Scope* sc) - { - if (Dsymbol s = toDsymbol(sc)) - { - s.checkDeprecated(loc, sc); - } - } - final bool isConst() const nothrow pure @nogc @safe { return (mod & MODFlags.const_) != 0; @@ -2849,13 +2574,6 @@ extern (C++) abstract class TypeNext : Type this.next = next; } - override final void checkDeprecated(const ref Loc loc, Scope* sc) - { - Type.checkDeprecated(loc, sc); - if (next) // next can be NULL if TypeFunction and auto return type - next.checkDeprecated(loc, sc); - } - override final int hasWild() const { if (ty == Tfunction) @@ -4441,7 +4159,7 @@ extern (C++) final class TypeFunction : TypeNext auto stc = p.storageClass; // When the preview switch is enable, `in` parameters are `scope` - if (stc & STC.in_ && global.params.previewIn) + if (stc & STC.constscoperef) return stc | STC.scope_; if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure) @@ -4636,27 +4354,7 @@ extern (C++) final class TypeFunction : TypeNext return t.merge(); } - // arguments get specially formatted - private const(char)* getParamError(Expression arg, Parameter par) - { - if (global.gag && !global.params.v.showGaggedErrors) - return null; - // show qualification when toChars() is the same but types are different - // https://issues.dlang.org/show_bug.cgi?id=19948 - // when comparing the type with strcmp, we need to drop the qualifier - bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) && - strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0; - auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars(); - OutBuffer buf; - // only mention rvalue if it's relevant - const rv = !arg.isLvalue() && par.isReference(); - buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", - rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, - parameterToChars(par, this, qual)); - return buf.extractChars(); - } - - private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args) + extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args) { if (global.gag && !global.params.v.showGaggedErrors) return null; @@ -4665,185 +4363,6 @@ extern (C++) final class TypeFunction : TypeNext return buf.extractChars(); } - /******************************** - * 'args' are being matched to function 'this' - * Determine match level. - * Params: - * tthis = type of `this` pointer, null if not member function - * argumentList = arguments to function call - * flag = 1: performing a partial ordering match - * pMessage = address to store error message, or null - * sc = context - * Returns: - * MATCHxxxx - */ - extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) - { - //printf("TypeFunction::callMatch() %s\n", toChars()); - MATCH match = MATCH.exact; // assume exact match - ubyte wildmatch = 0; - - if (tthis) - { - Type t = tthis; - if (t.toBasetype().ty == Tpointer) - t = t.toBasetype().nextOf(); // change struct* to struct - if (t.mod != mod) - { - if (MODimplicitConv(t.mod, mod)) - match = MATCH.constant; - else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_)) - { - match = MATCH.constant; - } - else - return MATCH.nomatch; - } - if (isWild()) - { - if (t.isWild()) - wildmatch |= MODFlags.wild; - else if (t.isConst()) - wildmatch |= MODFlags.const_; - else if (t.isImmutable()) - wildmatch |= MODFlags.immutable_; - else - wildmatch |= MODFlags.mutable; - } - } - - const nparams = parameterList.length; - if (argumentList.length > nparams) - { - if (parameterList.varargs == VarArg.none) - { - // suppress early exit if an error message is wanted, - // so we can check any matching args are valid - if (!pMessage) - return MATCH.nomatch; - } - // too many args; no match - match = MATCH.convert; // match ... with a "conversion" match level - } - - // https://issues.dlang.org/show_bug.cgi?id=22997 - if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) - { - OutBuffer buf; - buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); - if (pMessage) - *pMessage = buf.extractChars(); - return MATCH.nomatch; - } - auto resolvedArgs = resolveNamedArgs(argumentList, pMessage); - Expression[] args; - if (!resolvedArgs) - { - if (!pMessage || *pMessage) - return MATCH.nomatch; - - // if no message was provided, it was because of overflow which will be diagnosed below - match = MATCH.nomatch; - args = argumentList.arguments ? (*argumentList.arguments)[] : null; - } - else - { - args = (*resolvedArgs)[]; - } - - foreach (u, p; parameterList) - { - if (u >= args.length) - break; - - Expression arg = args[u]; - if (!arg) - continue; // default argument - - Type tprm = p.type; - Type targ = arg.type; - - if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)) - { - const isRef = p.isReference(); - wildmatch |= targ.deduceWild(tprm, isRef); - } - } - if (wildmatch) - { - /* Calculate wild matching modifier - */ - if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) - wildmatch = MODFlags.const_; - else if (wildmatch & MODFlags.immutable_) - wildmatch = MODFlags.immutable_; - else if (wildmatch & MODFlags.wild) - wildmatch = MODFlags.wild; - else - { - assert(wildmatch & MODFlags.mutable); - wildmatch = MODFlags.mutable; - } - } - - foreach (u, p; parameterList) - { - MATCH m; - - assert(p); - - // One or more arguments remain - if (u < args.length) - { - Expression arg = args[u]; - if (!arg) - continue; // default argument - m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage); - } - else if (p.defaultArg) - continue; - - /* prefer matching the element type rather than the array - * type when more arguments are present with T[]... - */ - if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams) - goto L1; - - //printf("\tm = %d\n", m); - if (m == MATCH.nomatch) // if no match - { - L1: - if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param - { - auto trailingArgs = args[u .. $]; - if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage)) - return vmatch < match ? vmatch : match; - // Error message was already generated in `matchTypeSafeVarArgs` - return MATCH.nomatch; - } - if (pMessage && u >= args.length) - *pMessage = getMatchError("missing argument for parameter #%d: `%s`", - u + 1, parameterToChars(p, this, false)); - // If an error happened previously, `pMessage` was already filled - else if (pMessage && !*pMessage) - *pMessage = getParamError(args[u], p); - - return MATCH.nomatch; - } - if (m < match) - match = m; // pick worst match - } - - if (pMessage && !parameterList.varargs && args.length > nparams) - { - // all parameters had a match, but there are surplus args - *pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length); - return MATCH.nomatch; - } - //printf("match = %d\n", match); - return match; - } - /******************************** * Convert an `argumentList`, which may contain named arguments, into * a list of arguments in the order of the parameter list. @@ -6932,34 +6451,28 @@ extern (C++) final class Parameter : ASTNode * Params: * returnByRef = true if the function returns by ref * p = Parameter to compare with - * previewIn = Whether `-preview=in` is being used, and thus if - * `in` means `scope [ref]`. - * * Returns: * true = `this` can be used in place of `p` * false = nope */ - bool isCovariant(bool returnByRef, const Parameter p, bool previewIn = global.params.previewIn) + bool isCovariant(bool returnByRef, const Parameter p) const pure nothrow @nogc @safe { ulong thisSTC = this.storageClass; ulong otherSTC = p.storageClass; - if (previewIn) - { - if (thisSTC & STC.in_) - thisSTC |= STC.scope_; - if (otherSTC & STC.in_) - otherSTC |= STC.scope_; - } + if (thisSTC & STC.constscoperef) + thisSTC |= STC.scope_; + if (otherSTC & STC.constscoperef) + otherSTC |= STC.scope_; - const mask = STC.ref_ | STC.out_ | STC.lazy_ | (previewIn ? STC.in_ : 0); + const mask = STC.ref_ | STC.out_ | STC.lazy_ | (((thisSTC | otherSTC) & STC.constscoperef) ? STC.in_ : 0); if ((thisSTC & mask) != (otherSTC & mask)) return false; return isCovariantScope(returnByRef, thisSTC, otherSTC); } - extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe + extern (D) static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe { // Workaround for failing covariance when finding a common type of delegates, // some of which have parameters with inferred scope @@ -7238,7 +6751,7 @@ enum ScopeRef * Returns: * corresponding string */ -const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe +const(char)* ScopeRefToChars(ScopeRef sr) pure nothrow @nogc @safe { with (ScopeRef) { @@ -7258,328 +6771,6 @@ const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe } } -/** - * Used by `callMatch` to check if the copy constructor may be called to - * copy the argument - * - * This is done by seeing if a call to the copy constructor can be made: - * ``` - * typeof(tprm) __copytmp; - * copytmp.__copyCtor(arg); - * ``` - */ -private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, - Expression arg, Type tprm, Scope* sc, const(char)** pMessage) -{ - auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); - tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; - tmp.dsymbolSemantic(sc); - Expression ve = new VarExp(arg.loc, tmp); - Expression e = new DotIdExp(arg.loc, ve, Id.ctor); - e = new CallExp(arg.loc, e, arg); - //printf("e = %s\n", e.toChars()); - if (.trySemantic(e, sc)) - return true; - - if (pMessage) - { - /* https://issues.dlang.org/show_bug.cgi?id=22202 - * - * If a function was deduced by semantic on the CallExp, - * it means that resolveFuncCall completed succesfully. - * Therefore, there exists a callable copy constructor, - * however, it cannot be called because scope constraints - * such as purity, safety or nogc. - */ - OutBuffer buf; - auto callExp = e.isCallExp(); - if (auto f = callExp.f) - { - char[] s; - if (!f.isPure && sc.func.setImpure()) - s ~= "pure "; - if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) - s ~= "@safe "; - if (!f.isNogc && sc.func.setGC(arg.loc, null)) - s ~= "nogc "; - if (s) - { - s[$-1] = '\0'; - buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); - } - else if (f.isGenerated() && f.isDisabled()) - { - /* https://issues.dlang.org/show_bug.cgi?id=23097 - * Compiler generated copy constructor failed. - */ - buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", - argStruct.toChars()); - } - else - { - /* Although a copy constructor may exist, no suitable match was found. - * i.e: `inout` constructor creates `const` object, not mutable. - * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202. - */ - goto Lnocpctor; - } - } - else - { - Lnocpctor: - buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", - argStruct.toChars(), arg.type.toChars(), tprm.toChars()); - } - - *pMessage = buf.extractChars(); - } - return false; -} - -/** - * Match a single parameter to an argument. - * - * This function is called by `TypeFunction.callMatch` while iterating over - * the list of parameter. Here we check if `arg` is a match for `p`, - * which is mostly about checking if `arg.type` converts to `p`'s type - * and some check about value reference. - * - * Params: - * tf = The `TypeFunction`, only used for error reporting - * p = The parameter of `tf` being matched - * arg = Argument being passed (bound) to `p` - * wildmatch = Wild (`inout`) matching level, derived from the full argument list - * flag = A non-zero value means we're doing a partial ordering check - * (no value semantic check) - * sc = Scope we are in - * pMessage = A buffer to write the error in, or `null` - * - * Returns: Whether `trailingArgs` match `p`. - */ -private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, - Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) -{ - //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); - MATCH m; - Type targ = arg.type; - Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; - - if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) - m = MATCH.convert; - else if (flag) - { - // for partial ordering, value is an irrelevant mockup, just look at the type - m = targ.implicitConvTo(tprm); - } - else - { - const isRef = p.isReference(); - StructDeclaration argStruct, prmStruct; - - // first look for a copy constructor - if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) - { - // if the argument and the parameter are of the same unqualified struct type - argStruct = (cast(TypeStruct)targ).sym; - prmStruct = (cast(TypeStruct)tprm).sym; - } - - // check if the copy constructor may be called to copy the argument - if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) - { - if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) - return MATCH.nomatch; - m = MATCH.exact; - } - else - { - import dmd.dcast : cimplicitConvTo; - m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); - } - } - - // Non-lvalues do not match ref or out parameters - if (p.isReference()) - { - // https://issues.dlang.org/show_bug.cgi?id=13783 - // Don't use toBasetype() to handle enum types. - Type ta = targ; - Type tp = tprm; - //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); - - if (m && !arg.isLvalue()) - { - if (p.storageClass & STC.out_) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - - if (arg.op == EXP.string_ && tp.ty == Tsarray) - { - if (ta.ty != Tsarray) - { - Type tn = tp.nextOf().castMod(ta.nextOf().mod); - dinteger_t dim = (cast(StringExp)arg).len; - ta = tn.sarrayOf(dim); - } - } - else if (arg.op == EXP.slice && tp.ty == Tsarray) - { - // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] - if (ta.ty != Tsarray) - { - Type tn = ta.nextOf(); - dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); - ta = tn.sarrayOf(dim); - } - } - else if ((p.storageClass & STC.in_) && global.params.previewIn) - { - // Allow converting a literal to an `in` which is `ref` - if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) - { - Type tn = tp.nextOf(); - dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); - ta = tn.sarrayOf(dim); - } - - // Need to make this a rvalue through a temporary - m = MATCH.convert; - } - else if (global.params.rvalueRefParam != FeatureState.enabled || - p.storageClass & STC.out_ || - !arg.type.isCopyable()) // can't copy to temp for ref parameter - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - else - { - /* in functionParameters() we'll convert this - * rvalue into a temporary - */ - m = MATCH.convert; - } - } - - /* If the match is not already perfect or if the arg - is not a lvalue then try the `alias this` chain - see https://issues.dlang.org/show_bug.cgi?id=15674 - and https://issues.dlang.org/show_bug.cgi?id=21905 - */ - if (ta != tp || !arg.isLvalue()) - { - Type firsttab = ta.toBasetype(); - while (1) - { - Type tab = ta.toBasetype(); - Type tat = tab.aliasthisOf(); - if (!tat || !tat.implicitConvTo(tprm)) - break; - if (tat == tab || tat == firsttab) - break; - ta = tat; - } - } - - /* A ref variable should work like a head-const reference. - * e.g. disallows: - * ref T <- an lvalue of const(T) argument - * ref T[dim] <- an lvalue of const(T[dim]) argument - */ - if (!ta.constConv(tp)) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - } - return m; -} - -/** - * Match the remaining arguments `trailingArgs` with parameter `p`. - * - * Assume we already checked that `p` is the last parameter of `tf`, - * and we want to know whether the arguments would match `p`. - * - * Params: - * tf = The `TypeFunction`, only used for error reporting - * p = The last parameter of `tf` which is variadic - * trailingArgs = The remaining arguments that should match `p` - * pMessage = A buffer to write the error in, or `null` - * - * Returns: Whether `trailingArgs` match `p`. - */ -private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, - Expression[] trailingArgs, const(char)** pMessage) -{ - Type tb = p.type.toBasetype(); - - switch (tb.ty) - { - case Tsarray: - TypeSArray tsa = cast(TypeSArray)tb; - dinteger_t sz = tsa.dim.toInteger(); - if (sz != trailingArgs.length) - { - if (pMessage) - *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", - sz, trailingArgs.length); - return MATCH.nomatch; - } - goto case Tarray; - case Tarray: - { - MATCH match = MATCH.exact; - TypeArray ta = cast(TypeArray)tb; - foreach (arg; trailingArgs) - { - MATCH m; - assert(arg); - - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type tret = p.isLazyArray(); - if (tret) - { - if (ta.next.equals(arg.type)) - m = MATCH.exact; - else if (tret.toBasetype().ty == Tvoid) - m = MATCH.convert; - else - { - m = arg.implicitConvTo(tret); - if (m == MATCH.nomatch) - m = arg.implicitConvTo(ta.next); - } - } - else - m = arg.implicitConvTo(ta.next); - - if (m == MATCH.nomatch) - { - if (pMessage) *pMessage = tf.getParamError(arg, p); - return MATCH.nomatch; - } - if (m < match) - match = m; - } - return match; - } - case Tclass: - // We leave it up to the actual constructor call to do the matching. - return MATCH.exact; - - default: - // We can have things as `foo(int[int] wat...)` but they only match - // with an associative array proper. - if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); - return MATCH.nomatch; - } -} - /** * Creates an appropriate vector type for `tv` that will hold one boolean * result for each element of the vector type. The result of vector comparisons @@ -7762,3 +6953,36 @@ TypeIdentifier getException() tid.addIdent(Id.Exception); return tid; } + +/************************************** + * Check and set 'att' if 't' is a recursive 'alias this' type + * + * The goal is to prevent endless loops when there is a cycle in the alias this chain. + * Since there is no multiple `alias this`, the chain either ends in a leaf, + * or it loops back on itself as some point. + * + * Example: S0 -> (S1 -> S2 -> S3 -> S1) + * + * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. + * `S1` is a recursive alias this type, but since `att` is initialized to `null`, + * this still returns `false`, but `att1` is set to `S1`. + * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, + * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. + * + * Params: + * att = type reference used to detect recursion. Should be initialized to `null`. + * t = type of 'alias this' rewrite to attempt + * + * Returns: + * `false` if the rewrite is safe, `true` if it would loop back around + */ +bool isRecursiveAliasThis(ref Type att, Type t) +{ + //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); + auto tb = t.toBasetype(); + if (att && tb.equivalent(att)) + return true; + else if (!att && tb.checkAliasThisRec()) + att = tb; + return false; +} diff --git a/dmd/mtype.h b/dmd/mtype.h index 2a4561dc26a..d6e53f18464 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -41,6 +41,7 @@ using type = class IrType; typedef struct TYPE type; #endif +extern const char* toChars(const Type* const t); Type *typeSemantic(Type *t, const Loc &loc, Scope *sc); Type *merge(Type *type); @@ -230,7 +231,6 @@ class Type : public ASTNode // kludge for template.isType() DYNCAST dyncast() const override final { return DYNCAST_TYPE; } size_t getUniqueID() const; - Covariant covariant(Type *, StorageClass * = NULL, bool = false); const char *toChars() const override; char *toPrettyChars(bool QualifyTypes = false); static void _init(); @@ -254,7 +254,6 @@ class Type : public ASTNode virtual bool isString(); virtual bool isAssignable(); virtual bool isBoolean(); - virtual void checkDeprecated(const Loc &loc, Scope *sc); bool isConst() const { return (mod & MODconst) != 0; } bool isImmutable() const { return (mod & MODimmutable) != 0; } bool isMutable() const { return (mod & (MODconst | MODimmutable | MODwild)) == 0; } @@ -369,7 +368,6 @@ class TypeNext : public Type public: Type *next; - void checkDeprecated(const Loc &loc, Scope *sc) override final; int hasWild() const override final; Type *nextOf() override final; Type *makeConst() override final; @@ -934,3 +932,4 @@ class TypeTag final : public Type // If the type is a class or struct, returns the symbol for it, else null. AggregateDeclaration *isAggregate(Type *t); +Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false); diff --git a/dmd/mustuse.d b/dmd/mustuse.d index 693464919e0..b5601a214dc 100644 --- a/dmd/mustuse.d +++ b/dmd/mustuse.d @@ -1,7 +1,7 @@ /** * Compile-time checks associated with the @mustuse attribute. * - * Copyright: Copyright (C) 2022-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2022-2024 by The D Language Foundation, All Rights Reserved * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d, _mustuse.d) * Documentation: https://dlang.org/phobos/dmd_mustuse.html @@ -222,20 +222,7 @@ private bool hasMustUseAttribute(Dsymbol sym, Scope* sc) */ private bool isMustUseAttribute(Expression e) { - import dmd.attrib : isCoreUda; + import dmd.attrib : isEnumAttribute; import dmd.id : Id; - - // Logic based on dmd.objc.Supported.declaredAsOptionalCount - auto typeExp = e.isTypeExp; - if (!typeExp) - return false; - - auto typeEnum = typeExp.type.isTypeEnum(); - if (!typeEnum) - return false; - - if (isCoreUda(typeEnum.sym, Id.udaMustUse)) - return true; - - return false; + return isEnumAttribute(e, Id.udaMustUse); } diff --git a/dmd/nogc.d b/dmd/nogc.d index e59b01019f4..9e45e4549ff 100644 --- a/dmd/nogc.d +++ b/dmd/nogc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#nogc-functions, No-GC Functions) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d, _nogc.d) diff --git a/dmd/nspace.d b/dmd/nspace.d index 2d3367af804..52c2b79a4e5 100644 --- a/dmd/nspace.d +++ b/dmd/nspace.d @@ -36,7 +36,7 @@ * are valid D identifier. * * See_Also: https://github.com/dlang/dmd/pull/10031 - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d) @@ -46,22 +46,14 @@ module dmd.nspace; -import dmd.aggregate; import dmd.arraytypes; -import dmd.astenums; -import dmd.dscope; import dmd.dsymbol; -import dmd.dsymbolsem; -import dmd.errors; import dmd.expression; -import dmd.globals; import dmd.identifier; import dmd.location; import dmd.visitor; import core.stdc.stdio; -private enum LOG = false; - /// Ditto extern (C++) final class Nspace : ScopeDsymbol { @@ -85,77 +77,12 @@ 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); - if (members) - { - assert(sc); - sc = sc.push(this); - sc.linkage = LINK.cpp; // namespaces default to C++ linkage - sc.parent = this; - members.foreachDsymbol(s => s.setScope(sc)); - sc.pop(); - } - } - - 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()); return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; } - override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) - { - //printf("Nspace::setFieldOffset() %s\n", toChars()); - if (_scope) // if fwd reference - dsymbolSemantic(this, null); // try to resolve it - members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) ); - } - override const(char)* kind() const { return "namespace"; diff --git a/dmd/nspace.h b/dmd/nspace.h index e9fb7bdc777..cbee2fb7914 100644 --- a/dmd/nspace.h +++ b/dmd/nspace.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -21,11 +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; Nspace *isNspace() override { return this; } void accept(Visitor *v) override { v->visit(this); } diff --git a/dmd/ob.d b/dmd/ob.d index dc94aecc61b..785912e1968 100644 --- a/dmd/ob.d +++ b/dmd/ob.d @@ -1,7 +1,7 @@ /** * Flow analysis for Ownership/Borrowing * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ob.d, _ob.d) @@ -197,7 +197,7 @@ enum PtrState : ubyte /************ */ -const(char)* toChars(PtrState state) +const(char)* PtrStateToChars(PtrState state) { return toString(state).ptr; } @@ -2490,7 +2490,7 @@ void checkObErrors(ref ObState obstate) if (s1 != s2 && (s1 == PtrState.Owner || s2 == PtrState.Owner)) { auto v = obstate.vars[i]; - .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, s1.toChars(), s2.toChars()); + .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, PtrStateToChars(s1), PtrStateToChars(s2)); } pvs1.combine(*pvs2, i, ob.gen); } diff --git a/dmd/objc.d b/dmd/objc.d index 030fe7bb066..866b078defd 100644 --- a/dmd/objc.d +++ b/dmd/objc.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/objc_interface.html, Interfacing to Objective-C) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/objc.d, _objc.d) diff --git a/dmd/objc.h b/dmd/objc.h index 40f634e9122..0390115aeb1 100644 --- a/dmd/objc.h +++ b/dmd/objc.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2015-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2015-2024 by The D Language Foundation, All Rights Reserved * written by Michel Fortin * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/opover.d b/dmd/opover.d index addcd0103d0..d596b8487f2 100644 --- a/dmd/opover.d +++ b/dmd/opover.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/operatoroverloading.html, Operator Overloading) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/opover.d, _opover.d) @@ -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; @@ -34,6 +35,7 @@ import dmd.id; import dmd.identifier; import dmd.location; import dmd.mtype; +import dmd.optimize; import dmd.statement; import dmd.tokens; import dmd.typesem; diff --git a/dmd/optimize.d b/dmd/optimize.d index 4a9fbe360b5..f86abde5c3e 100644 --- a/dmd/optimize.d +++ b/dmd/optimize.d @@ -1,7 +1,7 @@ /** * Perform constant folding. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d, _optimize.d) @@ -272,9 +272,9 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type) * Returns: * Constant folded version of `e` */ -Expression Expression_optimize(Expression e, int result, bool keepLvalue) +Expression optimize(Expression e, int result, bool keepLvalue = false) { - //printf("Expression_optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue); + //printf("optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue); Expression ret = e; void errorReturn() @@ -288,7 +288,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) { if (!e) return false; - Expression ex = Expression_optimize(e, flags, keepLvalue); + Expression ex = optimize(e, flags, keepLvalue); if (ex.op == EXP.error) { ret = ex; // store error result @@ -591,7 +591,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) Expression add = new AddExp(ae.loc, ex, new IntegerExp(ae.e2.loc, offset, ae.e2.type)); add.type = e.type; - ret = Expression_optimize(add, result, keepLvalue); + ret = optimize(add, result, keepLvalue); return; } } @@ -931,7 +931,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) void visitCatAssign(CatAssignExp e) { if (auto lowering = e.lowering) - Expression_optimize(lowering, result, keepLvalue); + optimize(lowering, result, keepLvalue); else visitBinAssign(e); } @@ -1247,7 +1247,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) ret = new CastExp(e.loc, ret, Type.tvoid); ret.type = e.type; } - ret = Expression_optimize(ret, result, false); + ret = optimize(ret, result, false); return; } expOptimize(e.e2, WANTvalue); @@ -1302,7 +1302,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) // `["c"] ~ "a" ~ "b"` becoming `["c"] ~ "ab"` scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2); cex.type = e.type; - Expression ex = Expression_optimize(cex, result, false); + Expression ex = optimize(cex, result, false); if (ex != cex) { e.e1 = ce1.e1; @@ -1331,9 +1331,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) return; const opt = e.econd.toBool(); if (opt.hasValue(true)) - ret = Expression_optimize(e.e1, result, keepLvalue); + ret = optimize(e.e1, result, keepLvalue); else if (opt.hasValue(false)) - ret = Expression_optimize(e.e2, result, keepLvalue); + ret = optimize(e.e2, result, keepLvalue); else { expOptimize(e.e1, result, keepLvalue); diff --git a/dmd/osmodel.mak b/dmd/osmodel.mak index 0ee63c140f0..309209530dc 100644 --- a/dmd/osmodel.mak +++ b/dmd/osmodel.mak @@ -2,44 +2,47 @@ # # Detects and sets the macros: # -# OS = one of {osx,linux,freebsd,openbsd,netbsd,dragonflybsd,solaris} +# OS = one of {windows,osx,linux,freebsd,openbsd,netbsd,dragonflybsd,solaris} # MODEL = one of { 32, 64 } # MODEL_FLAG = one of { -m32, -m64 } # ARCH = one of { x86, x86_64, aarch64 } # -# Note: -# Keep this file in sync between druntime, phobos, and dmd repositories! -# Source: https://github.com/dlang/dmd/blob/master/src/osmodel.mak +# On Windows, also sets up a bash shell. ifeq (,$(OS)) - uname_S:=$(shell uname -s) - ifeq (Darwin,$(uname_S)) - OS:=osx - endif - ifeq (Linux,$(uname_S)) - OS:=linux - endif - ifeq (FreeBSD,$(uname_S)) - OS:=freebsd - endif - ifeq (OpenBSD,$(uname_S)) - OS:=openbsd - endif - ifeq (NetBSD,$(uname_S)) - OS:=netbsd - endif - ifeq (DragonFly,$(uname_S)) - OS:=dragonflybsd - endif - ifeq (Solaris,$(uname_S)) - OS:=solaris - endif - ifeq (SunOS,$(uname_S)) - OS:=solaris - endif - ifeq (,$(OS)) - $(error Unrecognized or unsupported OS for uname: $(uname_S)) + ifneq (,$(LOCALAPPDATA)) + # assume Windows + OS:=windows + else + uname_S:=$(shell uname -s) + ifeq (Darwin,$(uname_S)) + OS:=osx + endif + ifeq (Linux,$(uname_S)) + OS:=linux + endif + ifeq (FreeBSD,$(uname_S)) + OS:=freebsd + endif + ifeq (OpenBSD,$(uname_S)) + OS:=openbsd + endif + ifeq (NetBSD,$(uname_S)) + OS:=netbsd + endif + ifeq (DragonFly,$(uname_S)) + OS:=dragonflybsd + endif + ifeq (Solaris,$(uname_S)) + OS:=solaris + endif + ifeq (SunOS,$(uname_S)) + OS:=solaris + endif + ifeq (,$(OS)) + $(error Unrecognized or unsupported OS for uname: $(uname_S)) + endif endif endif @@ -49,28 +52,50 @@ ifeq (MACOS,$(OS)) OS:=osx endif -ifeq (,$(MODEL)) - ifeq ($(OS), solaris) - uname_M:=$(shell isainfo -n) - else - uname_M:=$(shell uname -m) +# Windows predefines OS to e.g. `Windows_NT` +ifneq (,$(findstring Win,$(OS))) + OS:=windows +endif + +# set up bash shell on Windows +ifeq (windows,$(OS)) + # Note: setting SHELL to an absolute path to bash.exe does NOT suffice. + # The GNU tools like {rm,cp,mkdir}.exe need to be in PATH. + ifeq (,$(findstring C:\Program Files\Git\usr\bin,$(PATH))) + export PATH:=C:\Program Files\Git\usr\bin;$(PATH) endif - ifneq (,$(findstring $(uname_M),x86_64 amd64)) + # setting SHELL is very special on Windows: https://www.gnu.org/software/make/manual/html_node/Choosing-the-Shell.html#Choosing-a-Shell-in-DOS-and-Windows + SHELL=bash.exe + $(info Using make SHELL "$(SHELL)", should be bash.) +endif + +ifeq (,$(MODEL)) + ifeq (windows,$(OS)) MODEL:=64 ARCH:=x86_64 - endif - ifneq (,$(findstring $(uname_M),aarch64 arm64)) - # LDC: don't set MODEL - #MODEL:=64 - ARCH:=aarch64 - endif - ifneq (,$(findstring $(uname_M),i386 i586 i686)) - MODEL:=32 - ARCH:=x86 - endif - ifeq (,$(MODEL)) - # LDC: only warn - $(warning Cannot figure 32/64 model and arch from uname -m: $(uname_M)) + else + ifeq ($(OS), solaris) + uname_M:=$(shell isainfo -n) + else + uname_M:=$(shell uname -m) + endif + ifneq (,$(findstring $(uname_M),x86_64 amd64)) + MODEL:=64 + ARCH:=x86_64 + endif + ifneq (,$(findstring $(uname_M),aarch64 arm64)) + # LDC: don't set MODEL + #MODEL:=64 + ARCH:=aarch64 + endif + ifneq (,$(findstring $(uname_M),i386 i586 i686)) + MODEL:=32 + ARCH:=x86 + endif + ifeq (,$(MODEL)) + # LDC: only warn + $(warning Cannot figure 32/64 model and arch from uname -m: $(uname_M)) + endif endif endif diff --git a/dmd/parse.d b/dmd/parse.d index 51e522d71e4..a012e0c7c5b 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/grammar.html, D Grammar) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d) @@ -2899,6 +2899,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (transitionIn) eSink.message(scanloc, "Usage of 'in' on parameter"); stc = STC.in_; + if (compileEnv.previewIn) + stc |= STC.constscoperef; goto L2; case TOK.out_: @@ -2936,9 +2938,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: { - stc = storageClass & (STC.IOR | STC.lazy_); - // if stc is not a power of 2 - if (stc & (stc - 1) && !(stc == (STC.in_ | STC.ref_))) + const stcx = storageClass & (STC.in_ | STC.ref_ | STC.out_ | STC.lazy_); + // if stcx is not a power of 2 + if (stcx & (stcx - 1) && !(stcx == (STC.in_ | STC.ref_))) error("incompatible parameter storage classes"); //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_))) //error("scope cannot be ref or out"); @@ -4878,30 +4880,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 +4894,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 +4938,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 +7225,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() @@ -8421,7 +8430,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.TemplateParameters* tpl = null; nextToken(); - if (token.value == TOK.leftParenthesis) + if (token.value != TOK.leftParenthesis) + { + error("expected `(` following `is`, not `%s`", token.toChars()); + goto Lerr; + } + else { nextToken(); if (token.value == TOK.identifier && peekNext() == TOK.leftParenthesis) @@ -8469,11 +8483,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else check(TOK.rightParenthesis); } - else - { - error("`type identifier : specialization` expected following `is`"); - goto Lerr; - } e = new AST.IsExp(loc, targ, ident, tok, tspec, tok2, tpl); break; } diff --git a/dmd/parsetimevisitor.d b/dmd/parsetimevisitor.d index a4a9434334e..3d0a5854625 100644 --- a/dmd/parsetimevisitor.d +++ b/dmd/parsetimevisitor.d @@ -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); } } diff --git a/dmd/postordervisitor.d b/dmd/postordervisitor.d index 70bd1300feb..fe189d47e94 100644 --- a/dmd/postordervisitor.d +++ b/dmd/postordervisitor.d @@ -1,7 +1,7 @@ /** * A depth-first visitor for expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/apply.d, _apply.d) diff --git a/dmd/printast.d b/dmd/printast.d index e1deb2c8786..02dc65390b0 100644 --- a/dmd/printast.d +++ b/dmd/printast.d @@ -1,7 +1,7 @@ /** * Provides an AST printer for debugging. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/printast.d, _printast.d) diff --git a/dmd/root/aav.d b/dmd/root/aav.d index 1d450505a4d..8929679e37e 100644 --- a/dmd/root/aav.d +++ b/dmd/root/aav.d @@ -1,7 +1,7 @@ /** * Associative array implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d, root/_aav.d) diff --git a/dmd/root/array.d b/dmd/root/array.d index f36ddb4f29e..81355774de3 100644 --- a/dmd/root/array.d +++ b/dmd/root/array.d @@ -2,7 +2,7 @@ /** * Dynamic array implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/array.d, root/_array.d) diff --git a/dmd/root/array.h b/dmd/root/array.h index 024a24b0cfb..4bbabc9cf6a 100644 --- a/dmd/root/array.h +++ b/dmd/root/array.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 2011-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/bitarray.d b/dmd/root/bitarray.d index 66adab65877..c32d59eec36 100644 --- a/dmd/root/bitarray.d +++ b/dmd/root/bitarray.d @@ -1,7 +1,7 @@ /** * Implementation of a bit array. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d, root/_bitarray.d) diff --git a/dmd/root/bitarray.h b/dmd/root/bitarray.h index 617cc9e2cfa..2cd7152f725 100644 --- a/dmd/root/bitarray.h +++ b/dmd/root/bitarray.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 2011-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/complex.d b/dmd/root/complex.d index 57d1e340eff..de4c8d34678 100644 --- a/dmd/root/complex.d +++ b/dmd/root/complex.d @@ -1,7 +1,7 @@ /** * Implements a complex number type. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/complex.d, _complex.d) diff --git a/dmd/root/complex_t.h b/dmd/root/complex_t.h index de2040b88f7..8134f9e2591 100644 --- a/dmd/root/complex_t.h +++ b/dmd/root/complex_t.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/ctfloat.d b/dmd/root/ctfloat.d index fa56200c81e..521a9eabd26 100644 --- a/dmd/root/ctfloat.d +++ b/dmd/root/ctfloat.d @@ -1,7 +1,7 @@ /** * Collects functions for compile-time floating-point calculations. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d, root/_ctfloat.d) diff --git a/dmd/root/ctfloat.h b/dmd/root/ctfloat.h index 6e8e8808b0f..23f7dd04d1b 100644 --- a/dmd/root/ctfloat.h +++ b/dmd/root/ctfloat.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/dcompat.h b/dmd/root/dcompat.h index fa51370e3fb..d8087c3a90c 100644 --- a/dmd/root/dcompat.h +++ b/dmd/root/dcompat.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/dsystem.h b/dmd/root/dsystem.h index c0634d66bb5..76cb6ea875e 100644 --- a/dmd/root/dsystem.h +++ b/dmd/root/dsystem.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/file.d b/dmd/root/file.d index df9cf8ccdd0..1b55a206102 100644 --- a/dmd/root/file.d +++ b/dmd/root/file.d @@ -1,7 +1,7 @@ /** * Read a file from disk and store it in memory. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/file.d, root/_file.d) @@ -24,7 +24,7 @@ import dmd.root.rmem; import dmd.root.string; import dmd.common.file; -import dmd.common.string; +import dmd.common.smallbuffer; nothrow: diff --git a/dmd/root/filename.d b/dmd/root/filename.d index 4cf2b75a708..ce4954b5bff 100644 --- a/dmd/root/filename.d +++ b/dmd/root/filename.d @@ -1,7 +1,7 @@ /** * Encapsulate path and file names. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.d, root/_filename.d) @@ -37,7 +37,7 @@ version (Windows) import core.sys.windows.windef; import core.sys.windows.winnls; - import dmd.common.string : extendedPathThen; + import dmd.common.smallbuffer : extendedPathThen; extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc; extern (Windows) void SetLastError(DWORD) nothrow @nogc; @@ -1185,7 +1185,7 @@ version(Windows) */ private auto toWStringzThen(alias F)(const(char)[] str) nothrow { - import dmd.common.string : SmallBuffer, toWStringz; + import dmd.common.smallbuffer : SmallBuffer, toWStringz; if (!str.length) return F(""w.ptr); diff --git a/dmd/root/filename.h b/dmd/root/filename.h index 7185c166d40..5f8520da7dc 100644 --- a/dmd/root/filename.h +++ b/dmd/root/filename.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/hash.d b/dmd/root/hash.d index 2acee35c4f3..441620e60b4 100644 --- a/dmd/root/hash.d +++ b/dmd/root/hash.d @@ -1,7 +1,7 @@ /** * Hash functions for arbitrary binary data. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Martin Nowak, Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d, root/_hash.d) diff --git a/dmd/root/longdouble.d b/dmd/root/longdouble.d index f26a1a8d989..bf203bbcacf 100644 --- a/dmd/root/longdouble.d +++ b/dmd/root/longdouble.d @@ -1,7 +1,7 @@ /** * 80-bit floating point value implementation if the C/D compiler does not support them natively. * - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Rainer Schuetze * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/longdouble.h b/dmd/root/longdouble.h index 2c8a6fee793..8671678d65e 100644 --- a/dmd/root/longdouble.h +++ b/dmd/root/longdouble.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Rainer Schuetze * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/man.d b/dmd/root/man.d index 916542886af..8a84edf8f47 100644 --- a/dmd/root/man.d +++ b/dmd/root/man.d @@ -1,7 +1,7 @@ /** * Open an online manual page. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/man.d, root/_man.d) diff --git a/dmd/root/object.h b/dmd/root/object.h index 8e505f036c7..f56cb176017 100644 --- a/dmd/root/object.h +++ b/dmd/root/object.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/optional.d b/dmd/root/optional.d index bc1016b102a..e7d0e1ef785 100644 --- a/dmd/root/optional.d +++ b/dmd/root/optional.d @@ -1,7 +1,7 @@ /** * Implementation of an 'Optional' type * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.d, root/_optional.d) diff --git a/dmd/root/optional.h b/dmd/root/optional.h index 353332c2199..a92deddc638 100644 --- a/dmd/root/optional.h +++ b/dmd/root/optional.h @@ -3,7 +3,7 @@ /** * Optional implementation. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.h, root/_optional.h) diff --git a/dmd/root/port.d b/dmd/root/port.d index a80d751aee2..7a3e4920b62 100644 --- a/dmd/root/port.d +++ b/dmd/root/port.d @@ -1,7 +1,7 @@ /** * Portable routines for functions that have different implementations on different platforms. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d, root/_port.d) diff --git a/dmd/root/port.h b/dmd/root/port.h index 6fa3c000e5a..6c7dddd43ae 100644 --- a/dmd/root/port.h +++ b/dmd/root/port.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/region.d b/dmd/root/region.d index 9fc57f1e3a8..a9fab162537 100644 --- a/dmd/root/region.d +++ b/dmd/root/region.d @@ -1,7 +1,7 @@ /** * Region storage allocator implementation. * - * Copyright: Copyright (C) 2019-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2019-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d, root/_region.d) diff --git a/dmd/root/rmem.d b/dmd/root/rmem.d index 92667ee8bf6..065e303b6fb 100644 --- a/dmd/root/rmem.d +++ b/dmd/root/rmem.d @@ -1,7 +1,7 @@ /** * Allocate memory using `malloc` or the GC depending on the configuration. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d, root/_rmem.d) diff --git a/dmd/root/rmem.h b/dmd/root/rmem.h index 36aa2646fdc..09c0fc07ccc 100644 --- a/dmd/root/rmem.h +++ b/dmd/root/rmem.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/speller.d b/dmd/root/speller.d index b646bdda0cc..ae09cba37fc 100644 --- a/dmd/root/speller.d +++ b/dmd/root/speller.d @@ -3,7 +3,7 @@ * * Does not have any dependencies on the rest of DMD. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/speller.d, root/_speller.d) @@ -42,7 +42,7 @@ private: import core.stdc.stdlib; import core.stdc.string; -import dmd.common.string : SmallBuffer; +import dmd.common.smallbuffer : SmallBuffer; enum isSearchFunction(alias fun) = is(searchFunctionType!fun); alias searchFunctionType(alias fun) = typeof(() {int x; return fun("", x);}()); diff --git a/dmd/root/string.d b/dmd/root/string.d index 8b204ab4cad..e82b0d2fe6d 100644 --- a/dmd/root/string.d +++ b/dmd/root/string.d @@ -1,7 +1,7 @@ /** * Contains various string related functions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/string.d, root/_string.d) @@ -69,7 +69,7 @@ The return value of `T` auto toCStringThen(alias dg)(const(char)[] src) nothrow { import dmd.root.rmem : mem; - import dmd.common.string : SmallBuffer; + import dmd.common.smallbuffer : SmallBuffer; const len = src.length + 1; char[512] small = void; diff --git a/dmd/root/stringtable.d b/dmd/root/stringtable.d index de293eb9b55..1fba919dec5 100644 --- a/dmd/root/stringtable.d +++ b/dmd/root/stringtable.d @@ -1,7 +1,7 @@ /** * A specialized associative array with string keys stored in a variable length structure. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d, root/_stringtable.d) diff --git a/dmd/root/utf.d b/dmd/root/utf.d index d7ba17f8a0b..7d732f2fbe8 100644 --- a/dmd/root/utf.d +++ b/dmd/root/utf.d @@ -1,7 +1,7 @@ /** * Functions related to UTF encoding. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/utf.d, _utf.d) diff --git a/dmd/rootobject.d b/dmd/rootobject.d index 7867ad5de31..7c926fea055 100644 --- a/dmd/rootobject.d +++ b/dmd/rootobject.d @@ -1,7 +1,7 @@ /** * Provide the root object that AST classes in dmd inherit from. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, https://www.digitalmars.com * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/rootobject.d, _rootobject.d) diff --git a/dmd/safe.d b/dmd/safe.d index bd531c0081e..af81bff0dd1 100644 --- a/dmd/safe.d +++ b/dmd/safe.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/function.html#function-safety, Function Safety) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/safe.d, _safe.d) diff --git a/dmd/sapply.d b/dmd/sapply.d index 13fe6916531..340fbad78d4 100644 --- a/dmd/sapply.d +++ b/dmd/sapply.d @@ -1,7 +1,7 @@ /** * Provides a depth-first statement visitor. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sparse.d, _sparse.d) diff --git a/dmd/scope.h b/dmd/scope.h index 055c01968ac..b79665ec8b4 100644 --- a/dmd/scope.h +++ b/dmd/scope.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -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 @@ -130,5 +133,5 @@ struct Scope AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value, // do not set wasRead for it - Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone); + Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); }; diff --git a/dmd/semantic2.d b/dmd/semantic2.d index e864527883e..e849a7c4496 100644 --- a/dmd/semantic2.d +++ b/dmd/semantic2.d @@ -1,7 +1,7 @@ /** * Performs the semantic2 stage, which deals with initializer expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d, _semantic2.d) @@ -103,6 +103,13 @@ private extern(C++) final class Semantic2Visitor : Visitor override void visit(StaticAssert sa) { //printf("StaticAssert::semantic2() %s\n", sa.toChars()); + if (const e = sa.exp.isStringExp()) + { + // deprecated in 2.107 + deprecation(e.loc, "static assert condition cannot be a string literal"); + deprecationSupplemental(e.loc, "If intentional, use `%s !is null` instead to preserve behaviour", + e.toChars()); + } auto sds = new ScopeDsymbol(); sc = sc.push(sds); sc.tinst = null; @@ -832,7 +839,8 @@ private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag) } /** - * Try lower a variable's static Associative Array to a newaa struct. + * Try lower a variable's Associative Array initializer to a newaa struct + * so it can be put in static data. * Params: * vd = Variable to lower * sc = Scope @@ -842,11 +850,20 @@ void lowerStaticAAs(VarDeclaration vd, Scope* sc) if (vd.storage_class & STC.manifest) return; if (auto ei = vd._init.isExpInitializer()) - { - scope v = new StaticAAVisitor(sc); - v.vd = vd; - ei.exp.accept(v); - } + lowerStaticAAs(ei.exp, sc); +} + +/** + * Try lower all Associative Array literals in an expression to a newaa struct + * so it can be put in static data. + * Params: + * e = Expression to traverse + * sc = Scope + */ +void lowerStaticAAs(Expression e, Scope* sc) +{ + scope v = new StaticAAVisitor(sc); + e.accept(v); } /// Visit Associative Array literals and lower them to structs for static initialization @@ -854,7 +871,6 @@ private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor { alias visit = SemanticTimeTransitiveVisitor.visit; Scope* sc; - VarDeclaration vd; this(Scope* sc) scope @safe { diff --git a/dmd/semantic3.d b/dmd/semantic3.d index ce5589f7a72..33a046e1634 100644 --- a/dmd/semantic3.d +++ b/dmd/semantic3.d @@ -1,7 +1,7 @@ /** * Performs the semantic3 stage, which deals with function bodies. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d, _semantic3.d) @@ -54,6 +54,7 @@ import dmd.nspace; import dmd.ob; import dmd.objc; import dmd.opover; +import dmd.optimize; import dmd.parse; import dmd.root.filename; import dmd.common.outbuffer; @@ -529,7 +530,8 @@ private extern(C++) final class Semantic3Visitor : Visitor { Parameter narg = Parameter.getNth(t.arguments, j); assert(narg.ident); - VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration(); + Dsymbol pscopesym; + VarDeclaration v = sc2.search(Loc.initial, narg.ident, pscopesym).isVarDeclaration(); assert(v); (*exps)[j] = new VarExp(v.loc, v); } @@ -927,7 +929,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (f.isref) { // Function returns a reference - exp = exp.toLvalue(sc2, exp); + exp = exp.toLvalue(sc2, "`ref` return"); checkReturnEscapeRef(sc2, exp, false); exp = exp.optimize(WANTvalue, /*keepLvalue*/ true); } diff --git a/dmd/sideeffect.d b/dmd/sideeffect.d index 80c9a46958f..59398a70cb8 100644 --- a/dmd/sideeffect.d +++ b/dmd/sideeffect.d @@ -1,7 +1,7 @@ /** * Find side-effects of expressions. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d, _sideeffect.d) diff --git a/dmd/statement.d b/dmd/statement.d index 1b74e01ee4c..03a2c3a716e 100644 --- a/dmd/statement.d +++ b/dmd/statement.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d) @@ -20,19 +20,15 @@ import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; import dmd.errors; -import dmd.gluelayer; import dmd.cond; import dmd.declaration; import dmd.dsymbol; import dmd.expression; import dmd.func; -import dmd.globals; -import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.location; import dmd.mtype; -import dmd.common.outbuffer; import dmd.rootobject; import dmd.sapply; import dmd.staticassert; @@ -339,6 +335,8 @@ extern (C++) final class ErrorStatement : Statement extern (D) this() { super(Loc.initial, STMT.Error); + + import dmd.globals; assert(global.gaggedErrors || global.errors); } @@ -1825,7 +1823,7 @@ extern (C++) class AsmStatement : Statement */ extern (C++) final class InlineAsmStatement : AsmStatement { - code* asmcode; + void* asmcode; uint asmalign; // alignment of this statement uint regs; // mask of registers modified (must match regm_t in back end) bool refparam; // true if function parameter is referenced diff --git a/dmd/statement.h b/dmd/statement.h index 15a2a799055..452a30ac3ef 100644 --- a/dmd/statement.h +++ b/dmd/statement.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -759,7 +759,7 @@ class AsmStatement : public Statement class InlineAsmStatement final : public AsmStatement { public: - code *asmcode; + void *asmcode; unsigned asmalign; // alignment of this statement unsigned regs; // mask of registers modified (must match regm_t in back end) d_bool refparam; // true if function parameter is referenced diff --git a/dmd/statement_rewrite_walker.d b/dmd/statement_rewrite_walker.d index dcdd9630002..221c5021c52 100644 --- a/dmd/statement_rewrite_walker.d +++ b/dmd/statement_rewrite_walker.d @@ -1,7 +1,7 @@ /** * Provides a visitor for statements that allows rewriting the currently visited node. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d, _statement_rewrite_walker.d) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index 32441311c7c..652ef298d9f 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d, _statementsem.d) @@ -55,6 +55,7 @@ import dmd.location; import dmd.mtype; import dmd.mustuse; import dmd.nogc; +import dmd.optimize; import dmd.opover; import dmd.parse; import dmd.common.outbuffer; @@ -567,8 +568,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) ds._body = ds._body.semanticScope(sc, ds, ds, null); sc.inLoop = inLoopSave; - if (ds.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)ds.condition).noderef = true; + if (auto dotid = ds.condition.isDotIdExp()) + dotid.noderef = true; // check in syntax level ds.condition = checkAssignmentAsCondition(ds.condition, sc); @@ -640,8 +641,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (fs.condition) { - if (fs.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)fs.condition).noderef = true; + if (auto dotid = fs.condition.isDotIdExp()) + dotid.noderef = true; // check in syntax level fs.condition = checkAssignmentAsCondition(fs.condition, sc); @@ -728,8 +729,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (fs.aggr.op == EXP.error) return setError(); Expression oaggr = fs.aggr; // remember original for error messages - if (fs.aggr.type && fs.aggr.type.toBasetype().ty == Tstruct && - (cast(TypeStruct)(fs.aggr.type.toBasetype())).sym.dtor && + if (fs.aggr.type && fs.aggr.type.toBasetype().isTypeStruct() && + fs.aggr.type.toBasetype().isTypeStruct().sym.dtor && !fs.aggr.isTypeExp() && !fs.aggr.isLvalue()) { // https://issues.dlang.org/show_bug.cgi?id=14653 @@ -803,9 +804,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Parameter fparam = fparameters[0]; if ((fparam.type.ty == Tpointer || fparam.type.ty == Tdelegate) && - fparam.type.nextOf().ty == Tfunction) + fparam.type.nextOf().isTypeFunction()) { - TypeFunction tf = cast(TypeFunction)fparam.type.nextOf(); + auto tf = fparam.type.nextOf().isTypeFunction(); foreachParamCount = tf.parameterList.length; foundMismatch = true; } @@ -1644,8 +1645,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } else { - if (ifs.condition.op == EXP.dotIdentifier) - (cast(DotIdExp)ifs.condition).noderef = true; + if (auto dotid = ifs.condition.isDotIdExp()) + dotid.noderef = true; ifs.condition = ifs.condition.expressionSemantic(scd); ifs.condition = resolveProperties(scd, ifs.condition); @@ -1942,8 +1943,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc) while (!ss.condition.isErrorExp()) { // preserve enum type for final switches - if (ss.condition.type.ty == Tenum) - te = cast(TypeEnum)ss.condition.type; + if (auto tenum = ss.condition.type.isTypeEnum()) + te = tenum; if (ss.condition.type.isString()) { // If it's not an array, cast it to one @@ -2270,14 +2271,13 @@ version (IN_LLVM) Expression e = cs.exp; // Remove all the casts the user and/or implicitCastTo may introduce // otherwise we'd sometimes fail the check below. - while (e.op == EXP.cast_) - e = (cast(CastExp)e).e1; + while (e.isCastExp()) + e = e.isCastExp().e1; /* This is where variables are allowed as case expressions. */ - if (e.op == EXP.variable) + if (auto ve = e.isVarExp()) { - VarExp ve = cast(VarExp)e; VarDeclaration v = ve.var.isVarDeclaration(); Type t = cs.exp.type.toBasetype(); if (v && (t.isintegral() || t.ty == Tclass)) @@ -2309,7 +2309,8 @@ version (IN_LLVM) continue; assert(scx.sw == sw); - if (!scx.search(cs.exp.loc, v.ident, null)) + Dsymbol pscopesym; + if (!scx.search(cs.exp.loc, v.ident, pscopesym)) { error(cs.loc, "`case` variable `%s` declared at %s cannot be declared in `switch` body", v.toChars(), v.loc.toChars()); @@ -2584,10 +2585,9 @@ version (IN_LLVM) if (fd.fes) fd = fd.fes.func; // fd is now function enclosing foreach - TypeFunction tf = cast(TypeFunction)fd.type; - assert(tf.ty == Tfunction); + auto tf = fd.type.isTypeFunction(); - if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult) + if (rs.exp && rs.exp.isVarExp() && rs.exp.isVarExp().var == fd.vresult) { // return vresult; if (sc.fes) @@ -2675,7 +2675,7 @@ version (IN_LLVM) rs.exp.checkSharedAccess(sc, returnSharedRef); // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 - if (rs.exp.op == EXP.type) + if (rs.exp.isTypeExp()) rs.exp = resolveAliasThis(sc, rs.exp); rs.exp = resolveProperties(sc, rs.exp); @@ -2691,14 +2691,14 @@ version (IN_LLVM) // Extract side-effect part rs.exp = Expression.extractLast(rs.exp, e0); - if (rs.exp.op == EXP.call) + if (rs.exp.isCallExp()) rs.exp = valueNoDtor(rs.exp); /* Void-return function can have void / noreturn typed expression * on return statement. */ auto texp = rs.exp.type; - const convToVoid = texp.ty == Tvoid || texp.ty == Tnoreturn; + const convToVoid = texp.ty == Tvoid || texp.isTypeNoreturn(); if (tbret && tbret.ty == Tvoid || convToVoid) { @@ -2747,7 +2747,7 @@ version (IN_LLVM) { tf.next = rs.exp.type; } - else if (tret.ty != Terror && !rs.exp.type.equals(tret)) + else if (!tret.isTypeError() && !rs.exp.type.equals(tret)) { int m1 = rs.exp.type.implicitConvTo(tret); int m2 = tret.implicitConvTo(rs.exp.type); @@ -2848,7 +2848,7 @@ version (IN_LLVM) // Found an actual return value before else if (tf.next.ty != Tvoid && !resType.toBasetype().isTypeNoreturn()) { - if (tf.next.ty != Terror) + if (!tf.next.isTypeError()) { error(rs.loc, "mismatched function return type inference of `void` and `%s`", tf.next.toChars()); } @@ -2866,7 +2866,7 @@ version (IN_LLVM) if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return { - if (tbret.ty != Terror) + if (!tbret.isTypeError()) { if (e0) error(rs.loc, "expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars()); @@ -2960,7 +2960,7 @@ version (IN_LLVM) } if (e0) { - if (e0.op == EXP.declaration || e0.op == EXP.comma) + if (e0.isDeclarationExp() || e0.isCommaExp()) { rs.exp = Expression.combine(e0, rs.exp); } @@ -3294,9 +3294,9 @@ version (IN_LLVM) sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } - else if (ws.exp.op == EXP.type) + else if (auto et = ws.exp.isTypeExp()) { - Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc); + Dsymbol s = et.type.toDsymbol(sc); if (!s || !s.isScopeDsymbol()) { error(ws.loc, "`with` type `%s` has no members", ws.exp.toChars()); @@ -3834,16 +3834,15 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) if (FuncDeclaration fd = sc.parent.isFuncDeclaration()) fd.hasReturnExp |= 2; - if (exp.op == EXP.new_) + if (auto ne = exp.isNewExp()) { - NewExp ne = cast(NewExp) exp; ne.thrownew = true; } exp = exp.expressionSemantic(sc); exp = resolveProperties(sc, exp); exp = checkGC(sc, exp); - if (exp.op == EXP.error) + if (exp.isErrorExp()) return false; if (!exp.type.isNaked()) { @@ -3868,16 +3867,16 @@ 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`"); } - (cast(FuncExp)flde).fd.tookAddressOf = 1; + flde.isFuncExp().fd.tookAddressOf = 1; } else { - if (global.params.useDIP1000 == FeatureState.enabled) - ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' + if (sc2.useDIP1000 == FeatureState.enabled) + ++flde.isFuncExp().fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' } assert(tab.ty == Tstruct || tab.ty == Tclass); assert(sapply); @@ -3888,7 +3887,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, ec = new DotIdExp(fs.loc, fs.aggr, sapply.ident); ec = new CallExp(fs.loc, ec, flde); ec = ec.expressionSemantic(sc2); - if (ec.op == EXP.error) + if (ec.isErrorExp()) return null; if (ec.type != Type.tint32) { @@ -3905,11 +3904,12 @@ private extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde, /* Call: * aggr(flde) */ - if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() && - !(cast(DelegateExp)fs.aggr).func.needThis()) + if (auto de = fs.aggr.isDelegateExp()) + if (de.func.isNested() && + !de.func.needThis()) { // https://issues.dlang.org/show_bug.cgi?id=3560 - fs.aggr = (cast(DelegateExp)fs.aggr).e1; + fs.aggr = de.e1; } ec = new CallExp(fs.loc, fs.aggr, flde); ec = ec.expressionSemantic(sc2); @@ -4196,7 +4196,7 @@ else fld.tookAddressOf = 0; if (flde.op == EXP.error) return null; - return cast(FuncExp)flde; + return flde.isFuncExp(); } @@ -4370,9 +4370,9 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St { if (auto es = statement.isExpStatement()) { - if (es.exp && es.exp.op == EXP.declaration) + if (es.exp && es.exp.isDeclarationExp()) { - auto de = cast(DeclarationExp)es.exp; + auto de = es.exp.isDeclarationExp(); auto v = de.declaration.isVarDeclaration(); if (v && !v.isDataseg()) { @@ -4498,7 +4498,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState } Type tab = fs.aggr.type.toBasetype(); - TypeTuple tuple = cast(TypeTuple)tab; + TypeTuple tuple = tab.isTypeTuple(); Statements* statements; Dsymbols* declarations; @@ -4510,12 +4510,12 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars()); size_t n; TupleExp te = null; - if (fs.aggr.op == EXP.tuple) // expression tuple + if (auto ate = fs.aggr.isTupleExp()) // expression tuple { - te = cast(TupleExp)fs.aggr; + te = ate; n = te.exps.length; } - else if (fs.aggr.op == EXP.type) // type tuple + else if (fs.aggr.isTypeExp()) // type tuple { n = Parameter.dim(tuple.arguments); } @@ -4985,7 +4985,7 @@ private Statements* flatten(Statement statement, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + const bool doUnittests = global.params.parsingUnittestsRequired(); auto loc = adjustLocForMixin(str, cs.loc, global.params.mixinOut); scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); p.transitionIn = global.params.v.vin; diff --git a/dmd/staticassert.d b/dmd/staticassert.d index 15c46b304ba..08780ca0781 100644 --- a/dmd/staticassert.d +++ b/dmd/staticassert.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/version.html#static-assert, Static Assert) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d, _staticassert.d) @@ -14,14 +14,11 @@ module dmd.staticassert; import dmd.arraytypes; -import dmd.dscope; import dmd.dsymbol; import dmd.expression; -import dmd.globals; import dmd.location; import dmd.id; import dmd.identifier; -import dmd.mtype; import dmd.visitor; /*********************************************************** @@ -52,15 +49,10 @@ 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) + override bool oneMember(out Dsymbol ps, Identifier ident) { //printf("StaticAssert::oneMember())\n"); - *ps = null; + ps = null; return true; } diff --git a/dmd/staticassert.h b/dmd/staticassert.h index 2b7d300f6af..ed76de07012 100644 --- a/dmd/staticassert.h +++ b/dmd/staticassert.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -21,8 +21,7 @@ class StaticAssert : public Dsymbol Expressions *msg; StaticAssert *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; const char *kind() const override; StaticAssert *isStaticAssert() override { return this; } void accept(Visitor *v) override { v->visit(this); } diff --git a/dmd/staticcond.d b/dmd/staticcond.d index 923f1a99e80..72afe029641 100644 --- a/dmd/staticcond.d +++ b/dmd/staticcond.d @@ -1,7 +1,7 @@ /** * Lazily evaluate static conditions for `static if`, `static assert` and template constraints. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d, _staticcond.d) @@ -22,6 +22,7 @@ import dmd.expressionsem; import dmd.globals; import dmd.identifier; import dmd.mtype; +import dmd.optimize; import dmd.root.array; import dmd.common.outbuffer; import dmd.tokens; diff --git a/dmd/stmtstate.d b/dmd/stmtstate.d index 7b2ea972f0e..e1ed16594a8 100644 --- a/dmd/stmtstate.d +++ b/dmd/stmtstate.d @@ -1,7 +1,7 @@ /** * Used to help transform statement AST into flow graph. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d, _stmtstate.d) diff --git a/dmd/strictvisitor.d b/dmd/strictvisitor.d index 82e91c6aa76..39fcb68f0b8 100644 --- a/dmd/strictvisitor.d +++ b/dmd/strictvisitor.d @@ -234,5 +234,6 @@ extern(C++) class StrictVisitor(AST) : ParseTimeVisitor!AST override void visit(AST.StructInitializer) { assert(0); } override void visit(AST.ArrayInitializer) { assert(0); } override void visit(AST.VoidInitializer) { assert(0); } + override void visit(AST.DefaultInitializer) { assert(0); } override void visit(AST.CInitializer) { assert(0); } } diff --git a/dmd/target.d b/dmd/target.d index 131bf5d1036..072dafab7b4 100644 --- a/dmd/target.d +++ b/dmd/target.d @@ -15,7 +15,7 @@ * - $(LINK2 https://github.com/ldc-developers/ldc, LDC repository) * - $(LINK2 https://github.com/D-Programming-GDC/gcc, GDC repository) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d) @@ -485,7 +485,7 @@ else // !IN_LLVM realsize = 10; realpad = 0; realalignsize = 2; - if (ptrsize == 4) + if (omfobj) { /* Optlink cannot deal with individual data chunks * larger than 16Mb diff --git a/dmd/target.h b/dmd/target.h index 5f5cd0e9c68..2aeacdb347d 100644 --- a/dmd/target.h +++ b/dmd/target.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2013-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2013-2024 by The D Language Foundation, All Rights Reserved * written by Iain Buclaw * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/template.h b/dmd/template.h index 90fd295ec9a..114cced1600 100644 --- a/dmd/template.h +++ b/dmd/template.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -294,7 +294,7 @@ class TemplateInstance : public ScopeDsymbol TemplateInstance *syntaxCopy(Dsymbol *) override; Dsymbol *toAlias() override final; // resolve real symbol const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; const char *toChars() const override; const char* toPrettyCharsHelper() override final; Identifier *getIdent() override final; @@ -313,9 +313,8 @@ class TemplateMixin final : public TemplateInstance TemplateMixin *syntaxCopy(Dsymbol *s) override; const char *kind() const override; - bool oneMember(Dsymbol **ps, Identifier *ident) override; + bool oneMember(Dsymbol *&ps, Identifier *ident) override; bool hasPointers() override; - void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *toChars() const override; TemplateMixin *isTemplateMixin() override { return this; } diff --git a/dmd/templateparamsem.d b/dmd/templateparamsem.d index 7762363c8d6..89749d6b7f3 100644 --- a/dmd/templateparamsem.d +++ b/dmd/templateparamsem.d @@ -1,7 +1,7 @@ /** * Semantic analysis of template parameters. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d, _templateparamsem.d) diff --git a/dmd/tokens.d b/dmd/tokens.d index 317a6e6c382..589bc2b53cd 100644 --- a/dmd/tokens.d +++ b/dmd/tokens.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/lex.html#tokens, Tokens) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d, _tokens.d) @@ -947,93 +947,111 @@ nothrow: } extern (C++) const(char)* toChars() const + { + return toString().ptr; + } + + /********************************* + * Returns: + * a zero-terminated string representation of the token, + * sometimes reusing a static buffer, sometimes leaking memory + */ + extern (D) const(char)[] toString() const { const bufflen = 3 + 3 * floatvalue.sizeof + 1; - __gshared char[bufflen] buffer; - const(char)* p = &buffer[0]; + __gshared char[bufflen + 2] buffer; // extra 2 for suffixes + char* p = &buffer[0]; switch (value) { case TOK.int32Literal: - snprintf(&buffer[0], bufflen, "%d", cast(int)intvalue); - break; + const length = snprintf(p, bufflen, "%d", cast(int)intvalue); + return p[0 .. length]; + case TOK.uns32Literal: case TOK.wchar_tLiteral: - snprintf(&buffer[0], bufflen, "%uU", cast(uint)unsvalue); - break; + const length = snprintf(p, bufflen, "%uU", cast(uint)unsvalue); + return p[0 .. length]; + case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.charLiteral: - { - OutBuffer buf; - buf.writeSingleCharLiteral(cast(dchar) intvalue); - buf.writeByte('\0'); - p = buf.extractChars(); - } - break; + OutBuffer buf; + buf.writeSingleCharLiteral(cast(dchar) intvalue); + return buf.extractSlice(true); + case TOK.int64Literal: - snprintf(&buffer[0], bufflen, "%lldL", cast(long)intvalue); - break; + const length = snprintf(p, bufflen, "%lldL", cast(long)intvalue); + return p[0 .. length]; + case TOK.uns64Literal: - snprintf(&buffer[0], bufflen, "%lluUL", cast(ulong)unsvalue); - break; + const length = snprintf(p, bufflen, "%lluUL", cast(ulong)unsvalue); + return p[0 .. length]; + case TOK.float32Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "f"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'f'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.float64Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + return p[0 .. length]; + case TOK.float80Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "L"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'L'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.imaginary32Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "fi"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length ] = 'f'; + p[length + 1] = 'i'; + p[length + 2] = 0; + return p[0 .. length + 2]; + case TOK.imaginary64Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "i"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length] = 'i'; + p[length + 1] = 0; + return p[0 .. length + 1]; + case TOK.imaginary80Literal: - CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); - strcat(&buffer[0], "Li"); - break; + const length = CTFloat.sprint(p, bufflen, 'g', floatvalue); + p[length ] = 'L'; + p[length + 1] = 'i'; + p[length + 2] = 0; + return p[0 .. length + 2]; + case TOK.string_: + OutBuffer buf; + buf.writeByte('"'); + for (size_t i = 0; i < len;) { - OutBuffer buf; - buf.writeByte('"'); - for (size_t i = 0; i < len;) - { - dchar c; - utf_decodeChar(ustring[0 .. len], i, c); - writeCharLiteral(buf, c); - } - buf.writeByte('"'); - if (postfix) - buf.writeByte(postfix); - buf.writeByte(0); - p = buf.extractChars(); + dchar c; + utf_decodeChar(ustring[0 .. len], i, c); + writeCharLiteral(buf, c); } - break; + buf.writeByte('"'); + if (postfix) + buf.writeByte(postfix); + return buf.extractSlice(true); + case TOK.hexadecimalString: + OutBuffer buf; + buf.writeByte('x'); + buf.writeByte('"'); + foreach (size_t i; 0 .. len) { - OutBuffer buf; - buf.writeByte('x'); - buf.writeByte('"'); - foreach (size_t i; 0 .. len) - { - if (i) - buf.writeByte(' '); - buf.printf("%02x", ustring[i]); - } - buf.writeByte('"'); - if (postfix) - buf.writeByte(postfix); - buf.writeByte(0); - p = buf.extractData(); - break; + if (i) + buf.writeByte(' '); + buf.printf("%02x", ustring[i]); } + buf.writeByte('"'); + if (postfix) + buf.writeByte(postfix); + return buf.extractSlice(true); + case TOK.identifier: case TOK.enum_: case TOK.struct_: @@ -1062,13 +1080,11 @@ nothrow: case TOK.complex64: case TOK.complex80: case TOK.void_: - p = ident.toChars(); - break; + return ident.toString(); + default: - p = toChars(value); - break; + return tochars[value]; } - return p; } static const(char)* toChars(TOK value) diff --git a/dmd/tokens.h b/dmd/tokens.h index 560942d1e47..f944663e430 100644 --- a/dmd/tokens.h +++ b/dmd/tokens.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/traits.d b/dmd/traits.d index 91bead83319..219347e4df7 100644 --- a/dmd/traits.d +++ b/dmd/traits.d @@ -3,7 +3,7 @@ * * Specification: $(LINK2 https://dlang.org/spec/traits.html, Traits) * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/traits.d, _traits.d) @@ -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; @@ -42,6 +43,7 @@ import dmd.identifier; import dmd.location; import dmd.mtype; import dmd.nogc; +import dmd.optimize; import dmd.parse; import dmd.root.array; import dmd.root.speller; @@ -91,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) @@ -246,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) @@ -263,7 +272,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) offset = classoff; } - visitTopLevelClass(tc); + visitTopLevelClass(tcx); } else visit(t); @@ -280,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); @@ -471,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) { @@ -507,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(); } @@ -528,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()); @@ -792,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 } @@ -1296,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(); @@ -1654,12 +1665,12 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } else if (auto ed = sm.isEnumDeclaration()) { - ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg); + _foreach(null, ed.members, &pushIdentsDg); } return 0; } - ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg); + _foreach(sc, sds.members, &pushIdentsDg); auto cd = sds.isClassDeclaration(); if (cd && e.ident == Id.allMembers) { @@ -1673,7 +1684,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { auto cb = (*cd.baseclasses)[i].sym; assert(cb); - ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg); + _foreach(null, cb.members, &pushIdentsDg); if (cb.baseclasses.length) pushBaseMembersDg(cb); } @@ -1737,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); @@ -1867,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) { @@ -1875,16 +1886,24 @@ Expression semanticTraits(TraitsExp e, Scope* sc) return dimError(1); auto o = (*e.args)[0]; - Type t = isType(o); - AggregateDeclaration ad = t ? isAggregate(t) : null; - // Interfaces don't have an init symbol and hence cause linker errors - if (!ad || ad.isInterfaceDeclaration()) + ErrorExp badArgument() { error(e.loc, "struct / class type expected as argument to __traits(initSymbol) instead of `%s`", o.toChars()); return ErrorExp.get(); } + Type t = isType(o); + + if (!t || t.isTypeEnum()) + return badArgument(); + + AggregateDeclaration ad = isAggregate(t); + + // Interfaces don't have an init symbol and hence cause linker errors + if (!ad || ad.isInterfaceDeclaration()) + return badArgument(); + Declaration d = new SymbolDeclaration(ad.loc, ad); d.type = Type.tvoid.arrayOf().constOf(); d.storage_class |= STC.rvalue; diff --git a/dmd/typesem.d b/dmd/typesem.d index bbe11f63d4b..c9646ebe4f4 100644 --- a/dmd/typesem.d +++ b/dmd/typesem.d @@ -1,7 +1,7 @@ /** * Semantic analysis for D types. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d) @@ -53,6 +53,7 @@ import dmd.visitor; import dmd.mtype; import dmd.objc; import dmd.opover; +import dmd.optimize; import dmd.parse; import dmd.root.complex; import dmd.root.ctfloat; @@ -227,7 +228,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb Type t = s.getType(); // type symbol, type alias, or type tuple? uint errorsave = global.errors; - int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports; + SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports; Dsymbol sm = s.searchX(loc, sc, id, flags); if (sm) @@ -371,6 +372,64 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb pt = t.merge(); } +/*************************************** + * Search for identifier id as a member of `this`. + * `id` may be a template instance. + * + * Params: + * loc = location to print the error messages + * sc = the scope where the symbol is located + * id = the id of the symbol + * flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports` + * + * Returns: + * symbol found, NULL if not + */ +private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags) +{ + //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); + Dsymbol s = dsym.toAlias(); + Dsymbol sm; + if (Declaration d = s.isDeclaration()) + { + if (d.inuse) + { + .error(loc, "circular reference to `%s`", d.toPrettyChars()); + return null; + } + } + switch (id.dyncast()) + { + case DYNCAST.identifier: + sm = s.search(loc, cast(Identifier)id, flags); + break; + case DYNCAST.dsymbol: + { + // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol st = cast(Dsymbol)id; + TemplateInstance ti = st.isTemplateInstance(); + sm = s.search(loc, ti.name); + if (!sm) + return null; + sm = sm.toAlias(); + TemplateDeclaration td = sm.isTemplateDeclaration(); + if (!td) + return null; // error but handled later + ti.tempdecl = td; + if (!ti.semanticRun) + ti.dsymbolSemantic(sc); + sm = ti.toAlias(); + break; + } + case DYNCAST.type: + case DYNCAST.expression: + default: + assert(0); + } + return sm; +} + /****************************************** * We've mistakenly parsed `t` as a type. * Redo `t` as an Expression only if there are no type modifiers. @@ -427,6 +486,537 @@ Expression typeToExpression(Type t) } } +/******************************** + * 'args' are being matched to function type 'tf' + * Determine match level. + * Params: + * tf = function type + * tthis = type of `this` pointer, null if not member function + * argumentList = arguments to function call + * flag = 1: performing a partial ordering match + * pMessage = address to store error message, or null + * sc = context + * Returns: + * MATCHxxxx + */ +extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) +{ + //printf("TypeFunction::callMatch() %s\n", tf.toChars()); + MATCH match = MATCH.exact; // assume exact match + ubyte wildmatch = 0; + + if (tthis) + { + Type t = tthis; + if (t.toBasetype().ty == Tpointer) + t = t.toBasetype().nextOf(); // change struct* to struct + if (t.mod != tf.mod) + { + if (MODimplicitConv(t.mod, tf.mod)) + match = MATCH.constant; + else if ((tf.mod & MODFlags.wild) && MODimplicitConv(t.mod, (tf.mod & ~MODFlags.wild) | MODFlags.const_)) + { + match = MATCH.constant; + } + else + return MATCH.nomatch; + } + if (tf.isWild()) + { + if (t.isWild()) + wildmatch |= MODFlags.wild; + else if (t.isConst()) + wildmatch |= MODFlags.const_; + else if (t.isImmutable()) + wildmatch |= MODFlags.immutable_; + else + wildmatch |= MODFlags.mutable; + } + } + + ParameterList* parameterList = &tf.parameterList; + const nparams = parameterList.length; + if (argumentList.length > nparams) + { + if (parameterList.varargs == VarArg.none) + { + // suppress early exit if an error message is wanted, + // so we can check any matching args are valid + if (!pMessage) + return MATCH.nomatch; + } + // too many args; no match + match = MATCH.convert; // match ... with a "conversion" match level + } + + // https://issues.dlang.org/show_bug.cgi?id=22997 + if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) + { + OutBuffer buf; + buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); + if (pMessage) + *pMessage = buf.extractChars(); + return MATCH.nomatch; + } + auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage); + Expression[] args; + if (!resolvedArgs) + { + if (!pMessage || *pMessage) + return MATCH.nomatch; + + // if no message was provided, it was because of overflow which will be diagnosed below + match = MATCH.nomatch; + args = argumentList.arguments ? (*argumentList.arguments)[] : null; + } + else + { + args = (*resolvedArgs)[]; + } + + foreach (u, p; *parameterList) + { + if (u >= args.length) + break; + + Expression arg = args[u]; + if (!arg) + continue; // default argument + + Type tprm = p.type; + Type targ = arg.type; + + if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)) + { + const isRef = p.isReference(); + wildmatch |= targ.deduceWild(tprm, isRef); + } + } + if (wildmatch) + { + /* Calculate wild matching modifier + */ + if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1)) + wildmatch = MODFlags.const_; + else if (wildmatch & MODFlags.immutable_) + wildmatch = MODFlags.immutable_; + else if (wildmatch & MODFlags.wild) + wildmatch = MODFlags.wild; + else + { + assert(wildmatch & MODFlags.mutable); + wildmatch = MODFlags.mutable; + } + } + + foreach (u, p; *parameterList) + { + MATCH m; + + assert(p); + + // One or more arguments remain + if (u < args.length) + { + Expression arg = args[u]; + if (!arg) + continue; // default argument + m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage); + } + else if (p.defaultArg) + continue; + + /* prefer matching the element type rather than the array + * type when more arguments are present with T[]... + */ + if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams) + goto L1; + + //printf("\tm = %d\n", m); + if (m == MATCH.nomatch) // if no match + { + L1: + if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param + { + auto trailingArgs = args[u .. $]; + if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage)) + return vmatch < match ? vmatch : match; + // Error message was already generated in `matchTypeSafeVarArgs` + return MATCH.nomatch; + } + if (pMessage && u >= args.length) + *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`", + u + 1, parameterToChars(p, tf, false)); + // If an error happened previously, `pMessage` was already filled + else if (pMessage && !*pMessage) + *pMessage = tf.getParamError(args[u], p); + + return MATCH.nomatch; + } + if (m < match) + match = m; // pick worst match + } + + if (pMessage && !parameterList.varargs && args.length > nparams) + { + // all parameters had a match, but there are surplus args + *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length); + return MATCH.nomatch; + } + //printf("match = %d\n", match); + return match; +} + +/** + * Used by `callMatch` to check if the copy constructor may be called to + * copy the argument + * + * This is done by seeing if a call to the copy constructor can be made: + * ``` + * typeof(tprm) __copytmp; + * copytmp.__copyCtor(arg); + * ``` + */ +private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, + Expression arg, Type tprm, Scope* sc, const(char)** pMessage) +{ + auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); + tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; + tmp.dsymbolSemantic(sc); + Expression ve = new VarExp(arg.loc, tmp); + Expression e = new DotIdExp(arg.loc, ve, Id.ctor); + e = new CallExp(arg.loc, e, arg); + //printf("e = %s\n", e.toChars()); + if (.trySemantic(e, sc)) + return true; + + if (pMessage) + { + /* https://issues.dlang.org/show_bug.cgi?id=22202 + * + * If a function was deduced by semantic on the CallExp, + * it means that resolveFuncCall completed succesfully. + * Therefore, there exists a callable copy constructor, + * however, it cannot be called because scope constraints + * such as purity, safety or nogc. + */ + OutBuffer buf; + auto callExp = e.isCallExp(); + if (auto f = callExp.f) + { + char[] s; + if (!f.isPure && sc.func.setImpure()) + s ~= "pure "; + if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) + s ~= "@safe "; + if (!f.isNogc && sc.func.setGC(arg.loc, null)) + s ~= "nogc "; + if (f.isDisabled() && !f.isGenerated()) + { + /* https://issues.dlang.org/show_bug.cgi?id=24301 + * Copy constructor is explicitly disabled + */ + buf.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`", + f.type.toChars()); + } + else if (s) + { + s[$-1] = '\0'; + buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); + } + else if (f.isGenerated() && f.isDisabled()) + { + /* https://issues.dlang.org/show_bug.cgi?id=23097 + * Compiler generated copy constructor failed. + */ + buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", + argStruct.toChars()); + } + else + { + /* Although a copy constructor may exist, no suitable match was found. + * i.e: `inout` constructor creates `const` object, not mutable. + * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202. + */ + goto Lnocpctor; + } + } + else + { + Lnocpctor: + buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", + argStruct.toChars(), arg.type.toChars(), tprm.toChars()); + } + + *pMessage = buf.extractChars(); + } + return false; +} + +/** + * Match a single parameter to an argument. + * + * This function is called by `TypeFunction.callMatch` while iterating over + * the list of parameter. Here we check if `arg` is a match for `p`, + * which is mostly about checking if `arg.type` converts to `p`'s type + * and some check about value reference. + * + * Params: + * tf = The `TypeFunction`, only used for error reporting + * p = The parameter of `tf` being matched + * arg = Argument being passed (bound) to `p` + * wildmatch = Wild (`inout`) matching level, derived from the full argument list + * flag = A non-zero value means we're doing a partial ordering check + * (no value semantic check) + * sc = Scope we are in + * pMessage = A buffer to write the error in, or `null` + * + * Returns: Whether `trailingArgs` match `p`. + */ +private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, + Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) +{ + //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); + MATCH m; + Type targ = arg.type; + Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; + + if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid) + m = MATCH.convert; + else if (flag) + { + // for partial ordering, value is an irrelevant mockup, just look at the type + m = targ.implicitConvTo(tprm); + } + else + { + const isRef = p.isReference(); + StructDeclaration argStruct, prmStruct; + + // first look for a copy constructor + if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) + { + // if the argument and the parameter are of the same unqualified struct type + argStruct = (cast(TypeStruct)targ).sym; + prmStruct = (cast(TypeStruct)tprm).sym; + } + + // check if the copy constructor may be called to copy the argument + if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) + { + if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) + return MATCH.nomatch; + m = MATCH.exact; + } + else + { + import dmd.dcast : cimplicitConvTo; + m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm); + } + } + + // Non-lvalues do not match ref or out parameters + if (p.isReference()) + { + // https://issues.dlang.org/show_bug.cgi?id=13783 + // Don't use toBasetype() to handle enum types. + Type ta = targ; + Type tp = tprm; + //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars()); + + if (m && !arg.isLvalue()) + { + if (p.storageClass & STC.out_) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + + if (arg.op == EXP.string_ && tp.ty == Tsarray) + { + if (ta.ty != Tsarray) + { + Type tn = tp.nextOf().castMod(ta.nextOf().mod); + dinteger_t dim = (cast(StringExp)arg).len; + ta = tn.sarrayOf(dim); + } + } + else if (arg.op == EXP.slice && tp.ty == Tsarray) + { + // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] + if (ta.ty != Tsarray) + { + Type tn = ta.nextOf(); + dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); + ta = tn.sarrayOf(dim); + } + } + else if (p.storageClass & STC.constscoperef) + { + // Allow converting a literal to an `in` which is `ref` + if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray) + { + Type tn = tp.nextOf(); + dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger(); + ta = tn.sarrayOf(dim); + } + + // Need to make this a rvalue through a temporary + m = MATCH.convert; + } + else if (global.params.rvalueRefParam != FeatureState.enabled || + p.storageClass & STC.out_ || + !arg.type.isCopyable()) // can't copy to temp for ref parameter + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + else + { + /* in functionParameters() we'll convert this + * rvalue into a temporary + */ + m = MATCH.convert; + } + } + + /* If the match is not already perfect or if the arg + is not a lvalue then try the `alias this` chain + see https://issues.dlang.org/show_bug.cgi?id=15674 + and https://issues.dlang.org/show_bug.cgi?id=21905 + */ + if (ta != tp || !arg.isLvalue()) + { + Type firsttab = ta.toBasetype(); + while (1) + { + Type tab = ta.toBasetype(); + Type tat = tab.aliasthisOf(); + if (!tat || !tat.implicitConvTo(tprm)) + break; + if (tat == tab || tat == firsttab) + break; + ta = tat; + } + } + + /* A ref variable should work like a head-const reference. + * e.g. disallows: + * ref T <- an lvalue of const(T) argument + * ref T[dim] <- an lvalue of const(T[dim]) argument + */ + if (!ta.constConv(tp)) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + } + return m; +} + +// arguments get specially formatted +private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter par) +{ + if (global.gag && !global.params.v.showGaggedErrors) + return null; + // show qualification when toChars() is the same but types are different + // https://issues.dlang.org/show_bug.cgi?id=19948 + // when comparing the type with strcmp, we need to drop the qualifier + bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) && + strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0; + auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars(); + OutBuffer buf; + // only mention rvalue if it's relevant + const rv = !arg.isLvalue() && par.isReference(); + buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`", + rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at, + parameterToChars(par, tf, qual)); + return buf.extractChars(); +} + +/** + * Match the remaining arguments `trailingArgs` with parameter `p`. + * + * Assume we already checked that `p` is the last parameter of `tf`, + * and we want to know whether the arguments would match `p`. + * + * Params: + * tf = The `TypeFunction`, only used for error reporting + * p = The last parameter of `tf` which is variadic + * trailingArgs = The remaining arguments that should match `p` + * pMessage = A buffer to write the error in, or `null` + * + * Returns: Whether `trailingArgs` match `p`. + */ +private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p, + Expression[] trailingArgs, const(char)** pMessage) +{ + Type tb = p.type.toBasetype(); + + switch (tb.ty) + { + case Tsarray: + TypeSArray tsa = cast(TypeSArray)tb; + dinteger_t sz = tsa.dim.toInteger(); + if (sz != trailingArgs.length) + { + if (pMessage) + *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu", + sz, trailingArgs.length); + return MATCH.nomatch; + } + goto case Tarray; + case Tarray: + { + MATCH match = MATCH.exact; + TypeArray ta = cast(TypeArray)tb; + foreach (arg; trailingArgs) + { + MATCH m; + assert(arg); + + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type tret = p.isLazyArray(); + if (tret) + { + if (ta.next.equals(arg.type)) + m = MATCH.exact; + else if (tret.toBasetype().ty == Tvoid) + m = MATCH.convert; + else + { + m = arg.implicitConvTo(tret); + if (m == MATCH.nomatch) + m = arg.implicitConvTo(ta.next); + } + } + else + m = arg.implicitConvTo(ta.next); + + if (m == MATCH.nomatch) + { + if (pMessage) *pMessage = tf.getParamError(arg, p); + return MATCH.nomatch; + } + if (m < match) + match = m; + } + return match; + } + case Tclass: + // We leave it up to the actual constructor call to do the matching. + return MATCH.exact; + + default: + // We can have things as `foo(int[int] wat...)` but they only match + // with an associative array proper. + if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p); + return MATCH.nomatch; + } +} + /****************************************** * Perform semantic analysis on a type. * Params: @@ -1096,9 +1686,9 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // default arg must be an lvalue if (isRefOrOut && !isAuto && - !(global.params.previewIn && (fparam.storageClass & STC.in_)) && + !(fparam.storageClass & STC.constscoperef) && global.params.rvalueRefParam != FeatureState.enabled) - e = e.toLvalue(sc, e); + e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from"); fparam.defaultArg = e; return (e.op != EXP.error); @@ -1202,13 +1792,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) switch (tf.linkage) { case LINK.cpp: - if (global.params.previewIn) + if (fparam.storageClass & STC.constscoperef) fparam.storageClass |= STC.ref_; break; case LINK.default_, LINK.d: break; default: - if (global.params.previewIn) + if (fparam.storageClass & STC.constscoperef) { .error(loc, "cannot use `in` parameters with `extern(%s)` functions", linkageToChars(tf.linkage)); @@ -1238,7 +1828,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (tb2.ty == Tstruct && !tb2.isTypeStruct().sym.members || tb2.ty == Tenum && !tb2.isTypeEnum().sym.memtype) { - if (global.params.previewIn && (fparam.storageClass & STC.in_)) + if (fparam.storageClass & STC.constscoperef) { .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`", fparam.toChars(), fparam.type.toChars()); @@ -1320,7 +1910,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) fparam.storageClass &= ~(STC.TYPECTOR); // -preview=in: add `ref` storage class to suited `in` params - if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_) + if ((fparam.storageClass & (STC.constscoperef | STC.ref_)) == STC.constscoperef) { auto ts = t.baseElemOf().isTypeStruct(); const isPOD = !ts || ts.sym.isPOD(); @@ -1736,11 +2326,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) Type visitTag(TypeTag mtype) { //printf("TypeTag.semantic() %s\n", mtype.toChars()); + Type returnType(Type t) + { + return t.deco ? t : t.merge(); + } + if (mtype.resolved) { /* struct S s, *p; */ - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* Find the current scope by skipping tag scopes. @@ -1813,20 +2408,20 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) { mtype.id = Identifier.generateId("__tag"[]); declareTag(); - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* look for pre-existing declaration */ Dsymbol scopesym; - auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace); + auto s = sc2.search(mtype.loc, mtype.id, scopesym, SearchOpt.ignoreErrors | SearchOpt.tagNameSpace); if (!s || s.isModule()) { // no pre-existing declaration, so declare it if (mtype.tok == TOK.enum_ && !mtype.members) .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3 declareTag(); - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } /* A redeclaration only happens if both declarations are in @@ -1926,7 +2521,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) declareTag(); } } - return mtype.resolved.addSTC(mtype.mod); + return returnType(mtype.resolved.addSTC(mtype.mod)); } switch (type.ty) @@ -2694,7 +3289,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type } Dsymbol scopesym; - Dsymbol s = sc.search(loc, mt.ident, &scopesym); + Dsymbol s = sc.search(loc, mt.ident, scopesym); /* * https://issues.dlang.org/show_bug.cgi?id=1170 * https://issues.dlang.org/show_bug.cgi?id=10739 @@ -2717,7 +3312,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type mixinTempl.dsymbolSemantic(sc); } sds.members.foreachDsymbol( s => semanticOnMixin(s) ); - s = sc.search(loc, mt.ident, &scopesym); + s = sc.search(loc, mt.ident, scopesym); } } @@ -3735,8 +4330,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag return e; } - immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0; - s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports); + immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0; + s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports); L1: if (!s) { @@ -3748,7 +4343,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag } // check before alias resolution; the alias itself might be deprecated! if (s.isAliasDeclaration) - e.checkDeprecated(sc, s); + s.checkDeprecated(e.loc, sc); s = s.toAlias(); if (auto em = s.isEnumMember()) @@ -4015,8 +4610,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag return e; } - int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0; - s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports); + SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all; + s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports); L1: if (!s) @@ -4664,7 +5259,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) return *pt; } - Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports); + Dsymbol s = mConfig.searchX(Loc.initial, sc, id, SearchOpt.ignorePrivateImports); if (!s) { error(loc, "`%s` not found in core.stdc.config", id.toChars()); @@ -4689,6 +5284,263 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) return *pt; } +/******************************* + * Covariant means that 'src' can substitute for 't', + * i.e. a pure function is a match for an impure type. + * Params: + * src = source type + * t = type 'src' is covariant with + * pstc = if not null, store STCxxxx which would make it covariant + * cppCovariant = true if extern(C++) function types should follow C++ covariant rules + * Returns: + * An enum value of either `Covariant.yes` or a reason it's not covariant. + */ +Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false) +{ + version (none) + { + printf("Type::covariant(t = %s) %s\n", t.toChars(), src.toChars()); + printf("deco = %p, %p\n", src.deco, t.deco); + // printf("ty = %d\n", next.ty); + printf("mod = %x, %x\n", src.mod, t.mod); + } + if (pstc) + *pstc = 0; + StorageClass stc = 0; + + bool notcovariant = false; + + if (src.equals(t)) + return Covariant.yes; + + TypeFunction t1 = src.isTypeFunction(); + TypeFunction t2 = t.isTypeFunction(); + + if (!t1 || !t2) + goto Ldistinct; + + if (t1.parameterList.varargs != t2.parameterList.varargs) + goto Ldistinct; + + if (t1.parameterList.parameters && t2.parameterList.parameters) + { + if (t1.parameterList.length != t2.parameterList.length) + goto Ldistinct; + + foreach (i, fparam1; t1.parameterList) + { + Parameter fparam2 = t2.parameterList[i]; + Type tp1 = fparam1.type; + Type tp2 = fparam2.type; + + if (!tp1.equals(tp2)) + { + if (tp1.ty == tp2.ty) + { + if (auto tc1 = tp1.isTypeClass()) + { + if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) + goto Lcov; + } + else if (auto ts1 = tp1.isTypeStruct()) + { + if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod)) + goto Lcov; + } + else if (tp1.ty == Tpointer) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + else if (tp1.ty == Tarray) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + else if (tp1.ty == Tdelegate) + { + if (tp2.implicitConvTo(tp1)) + goto Lcov; + } + } + goto Ldistinct; + } + Lcov: + notcovariant |= !fparam1.isCovariant(t1.isref, fparam2); + + /* https://issues.dlang.org/show_bug.cgi?id=23135 + * extern(C++) mutable parameters are not covariant with const. + */ + if (t1.linkage == LINK.cpp && cppCovariant) + { + notcovariant |= tp1.isNaked() != tp2.isNaked(); + if (auto tpn1 = tp1.nextOf()) + notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked(); + } + } + } + else if (t1.parameterList.parameters != t2.parameterList.parameters) + { + if (t1.parameterList.length || t2.parameterList.length) + goto Ldistinct; + } + + // The argument lists match + if (notcovariant) + goto Lnotcovariant; + if (t1.linkage != t2.linkage) + goto Lnotcovariant; + + { + // Return types + Type t1n = t1.next; + Type t2n = t2.next; + + if (!t1n || !t2n) // happens with return type inference + goto Lnotcovariant; + + if (t1n.equals(t2n)) + goto Lcovariant; + if (t1n.ty == Tclass && t2n.ty == Tclass) + { + /* If same class type, but t2n is const, then it's + * covariant. Do this test first because it can work on + * forward references. + */ + if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) + goto Lcovariant; + + // If t1n is forward referenced: + ClassDeclaration cd = (cast(TypeClass)t1n).sym; + if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete()) + cd.dsymbolSemantic(null); + if (!cd.isBaseInfoComplete()) + { + return Covariant.fwdref; + } + } + if (t1n.ty == Tstruct && t2n.ty == Tstruct) + { + if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod)) + goto Lcovariant; + } + else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n)) + { + if (t1.isref && t2.isref) + { + // Treat like pointers to t1n and t2n + if (t1n.constConv(t2n) < MATCH.constant) + goto Lnotcovariant; + } + goto Lcovariant; + } + else if (t1n.ty == Tnull) + { + // NULL is covariant with any pointer type, but not with any + // dynamic arrays, associative arrays or delegates. + // https://issues.dlang.org/show_bug.cgi?id=8589 + // https://issues.dlang.org/show_bug.cgi?id=19618 + Type t2bn = t2n.toBasetype(); + if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass) + goto Lcovariant; + } + // bottom type is covariant to any type + else if (t1n.ty == Tnoreturn) + goto Lcovariant; + } + goto Lnotcovariant; + +Lcovariant: + if (t1.isref != t2.isref) + goto Lnotcovariant; + + if (!t1.isref && (t1.isScopeQual || t2.isScopeQual)) + { + StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0; + StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0; + if (t1.isreturn) + { + stc1 |= STC.return_; + if (!t1.isScopeQual) + stc1 |= STC.ref_; + } + if (t2.isreturn) + { + stc2 |= STC.return_; + if (!t2.isScopeQual) + stc2 |= STC.ref_; + } + if (!Parameter.isCovariantScope(t1.isref, stc1, stc2)) + goto Lnotcovariant; + } + + // We can subtract 'return ref' from 'this', but cannot add it + else if (t1.isreturn && !t2.isreturn) + goto Lnotcovariant; + + /* https://issues.dlang.org/show_bug.cgi?id=23135 + * extern(C++) mutable member functions are not covariant with const. + */ + if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked()) + goto Lnotcovariant; + + /* Can convert mutable to const + */ + if (!MODimplicitConv(t2.mod, t1.mod)) + { + version (none) + { + //stop attribute inference with const + // If adding 'const' will make it covariant + if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_))) + stc |= STC.const_; + else + goto Lnotcovariant; + } + else + { + goto Ldistinct; + } + } + + /* Can convert pure to impure, nothrow to throw, and nogc to gc + */ + if (!t1.purity && t2.purity) + stc |= STC.pure_; + + if (!t1.isnothrow && t2.isnothrow) + stc |= STC.nothrow_; + + if (!t1.isnogc && t2.isnogc) + stc |= STC.nogc; + + /* Can convert safe/trusted to system + */ + if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted) + { + // Should we infer trusted or safe? Go with safe. + stc |= STC.safe; + } + + if (stc) + { + if (pstc) + *pstc = stc; + goto Lnotcovariant; + } + + //printf("\tcovaraint: 1\n"); + return Covariant.yes; + +Ldistinct: + //printf("\tcovaraint: 0\n"); + return Covariant.distinct; + +Lnotcovariant: + //printf("\tcovaraint: 2\n"); + return Covariant.no; +} + /******************************* Private *****************************************/ private: @@ -5009,7 +5861,7 @@ RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + const bool doUnittests = global.params.parsingUnittestsRequired(); auto locm = adjustLocForMixin(str, loc, global.params.mixinOut); scope p = new Parser!ASTCodegen(locm, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); p.transitionIn = global.params.v.vin; diff --git a/dmd/typinf.d b/dmd/typinf.d index f0906ff5593..097a5fcf4ce 100644 --- a/dmd/typinf.d +++ b/dmd/typinf.d @@ -1,7 +1,7 @@ /** * Generate `TypeInfo` objects, which are needed for run-time introspection of types. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d, _typinf.d) diff --git a/dmd/typinf.h b/dmd/typinf.h index 76f623a0a3e..02a2c7dfa3e 100644 --- a/dmd/typinf.h +++ b/dmd/typinf.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -15,6 +15,8 @@ class Expression; class Type; struct Scope; +class FuncDeclaration; +class ScopeDsymbol; bool genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc); Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc, bool genObjCode = true); diff --git a/dmd/utils.d b/dmd/utils.d index bb389b65903..75ee78cdd2e 100644 --- a/dmd/utils.d +++ b/dmd/utils.d @@ -1,7 +1,7 @@ /** * This module defines some utility functions for DMD. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utils.d, _utils.d) diff --git a/dmd/version.h b/dmd/version.h index 697d46ee211..dd83fd67dff 100644 --- a/dmd/version.h +++ b/dmd/version.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -20,7 +20,6 @@ class DebugSymbol final : public Dsymbol 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 @@ class VersionSymbol final : public Dsymbol 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); } diff --git a/dmd/visitor.d b/dmd/visitor.d index 5722e10d256..abfd8caa584 100644 --- a/dmd/visitor.d +++ b/dmd/visitor.d @@ -1,7 +1,7 @@ /** * Provides a visitor class visiting all AST nodes present in the compiler. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/visitor.d, _visitor.d) diff --git a/dmd/visitor.h b/dmd/visitor.h index 3d8c3e60220..7fa08cb0e8b 100644 --- a/dmd/visitor.h +++ b/dmd/visitor.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2013-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2013-2024 by The D Language Foundation, All Rights Reserved * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * https://www.boost.org/LICENSE_1_0.txt @@ -176,6 +176,7 @@ class NewDeclaration; class Initializer; class VoidInitializer; +class DefaultInitializer; class ErrorInitializer; class StructInitializer; class ArrayInitializer; @@ -591,6 +592,7 @@ class ParseTimeVisitor 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); } }; diff --git a/dmd/vsoptions.d b/dmd/vsoptions.d index afb235ffa48..6f8e77c24b0 100644 --- a/dmd/vsoptions.d +++ b/dmd/vsoptions.d @@ -1,7 +1,7 @@ /** * When compiling on Windows with the Microsoft toolchain, try to detect the Visual Studio setup. * - * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/link.d, _vsoptions.d) @@ -486,8 +486,6 @@ public: return FileName.exists(proposed) ? proposed : null; } -version (IN_LLVM) -{ const(char)* getVCIncludeDir() const { const(char)* proposed; @@ -499,7 +497,6 @@ version (IN_LLVM) return FileName.exists(proposed) ? proposed : null; } -} /** * get the path to the universal CRT libraries @@ -561,8 +558,6 @@ version (IN_LLVM) {} else return null; } -version (IN_LLVM) -{ const(char)* getSDKIncludePath() const { if (WindowsSdkDir) @@ -586,7 +581,6 @@ version (IN_LLVM) return null; } -} private: extern(D): @@ -595,7 +589,7 @@ extern(D): // one with the largest version that also contains the test file static const(char)* findLatestSDKDir(const(char)* baseDir, string testfile) { - import dmd.common.string : SmallBuffer, toWStringz; + import dmd.common.smallbuffer : SmallBuffer, toWStringz; const(char)* pattern = FileName.combine(baseDir, "*"); wchar[1024] support = void; diff --git a/dmd/vsoptions.h b/dmd/vsoptions.h index b39601bf92c..155a139f9ca 100644 --- a/dmd/vsoptions.h +++ b/dmd/vsoptions.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2009-2023 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2009-2024 by The D Language Foundation, All Rights Reserved * written by Walter Bright * https://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -25,14 +25,10 @@ struct VSOptions void initialize(); const char *getVCBinDir(bool x64, const char *&addpath) const; const char *getVCLibDir(bool x64) const; -#if IN_LLVM const char *getVCIncludeDir() const; -#endif const char *getUCRTLibPath(bool x64) const; const char *getSDKLibPath(bool x64) const; -#if IN_LLVM const char *getSDKIncludePath() const; -#endif }; #endif // _WIN32 diff --git a/runtime/druntime/Makefile b/runtime/druntime/Makefile new file mode 100644 index 00000000000..50e4104d2c6 --- /dev/null +++ b/runtime/druntime/Makefile @@ -0,0 +1,643 @@ +# This makefile is designed to be run by gnu make. +# - Windows: you may download a prebuilt zipped .exe from https://github.com/dlang/dmd/releases/download/nightly/gnumake-4.4-win64.zip. +# You also need a Git for Windows installation, for bash and common GNU tools like cp,mkdir,mv,rm,touch,which. +# - FreeBSD: the default make program on FreeBSD is not gnu make; to install gnu make: +# pkg install gmake +# and then run as gmake rather than make. +# +# Examples: +# - Build druntime: +# make -j$(nproc) +# - Build and run druntime tests: +# make -j$(nproc) unittest +# - Build and run druntime tests in debug mode only: +# make -j$(nproc) unittest-debug + +QUIET:= + +DUB=dub +TOOLS_DIR=../../tools + +include ../compiler/src/osmodel.mak + +ifeq (windows,$(OS)) + DOTEXE:=.exe + DOTDLL:=.dll + DOTLIB:=.lib + DOTOBJ:=.obj +else + DOTEXE:= + DOTDLL:=$(if $(findstring $(OS),osx),.dylib,.so) + DOTLIB:=.a + DOTOBJ:=.o +endif + +ifeq (osx,$(OS)) + export MACOSX_DEPLOYMENT_TARGET=10.9 +endif + +# Default to a release built, override with BUILD=debug +ifeq (,$(BUILD)) + BUILD_WAS_SPECIFIED=0 + BUILD=release +else + BUILD_WAS_SPECIFIED=1 +endif + +ifneq ($(BUILD),release) + ifneq ($(BUILD),debug) + $(error Unrecognized BUILD=$(BUILD), must be 'debug' or 'release') + endif +endif + +DMD=../generated/$(OS)/$(BUILD)/$(MODEL)/dmd$(DOTEXE) +INSTALL_DIR=../../install + +# directory where the html files for the documentation are placed +DOC_OUTPUT_DIR=doc +IMPDIR=import + +OPTIONAL_COVERAGE:=$(if $(TEST_COVERAGE),-cov=ctfe,) + +# default to PIC, use PIC=1/0 to en-/disable PIC. +# Note that shared libraries and C files are always compiled with PIC. +ifeq (windows,$(OS)) + override PIC:= +else + ifeq ($(PIC),) + PIC:=1 + endif + ifeq ($(PIC),1) + override PIC:=-fPIC + else + override PIC:= + endif +endif + +# build with shared library support +# (defaults to true on supported platforms, can be overridden w/ make SHARED=0) +SHARED=$(if $(findstring $(OS),linux freebsd dragonflybsd),1,) + +LINKDL=$(if $(findstring $(OS),linux),-L-ldl,) + +MAKEFILE = $(firstword $(MAKEFILE_LIST)) + +DDOCFLAGS=-conf= -c -w -o- -Iimport -version=CoreDdoc + +# Set CFLAGS +CFLAGS=$(if $(findstring $(OS),windows),,$(MODEL_FLAG) -fPIC -DHAVE_UNISTD_H) +ifeq ($(BUILD),debug) + CFLAGS += -g +else + CFLAGS += -O3 +endif +ifeq (solaris,$(OS)) + CFLAGS+=-D_REENTRANT # for thread-safe errno +endif +ifeq (osx,$(OS)) + ifeq (64,$(MODEL)) + CFLAGS+=--target=x86_64-darwin-apple # ARM cpu is not supported by dmd + endif +endif + +# Set DFLAGS +UDFLAGS:=-conf= -Isrc -Iimport -w -de -preview=dip1000 -preview=fieldwise $(MODEL_FLAG) $(PIC) $(OPTIONAL_COVERAGE) -preview=dtorfields +ifeq ($(BUILD),debug) + UDFLAGS += -g -debug + DFLAGS:=$(UDFLAGS) +else + UDFLAGS += -O -release + DFLAGS:=$(UDFLAGS) -inline # unittests don't compile with -inline +endif + +SHAREDFLAGS:=$(if $(findstring $(OS),windows),-visibility=public -mscrtlib=msvcrt,-fPIC) +SOLIBS:=$(if $(findstring $(OS),windows),msvcrt.lib legacy_stdio_definitions.lib,-L-lpthread -L-lm) + +UTFLAGS:=-version=CoreUnittest -unittest -checkaction=context + +# Set PHOBOS_DFLAGS (for linking against Phobos) +PHOBOS_PATH=../../phobos +SHARED=$(if $(findstring $(OS),linux freebsd),1,) +ROOT_DIR := $(shell pwd) +PHOBOS_DFLAGS=-conf= $(MODEL_FLAG) -I$(ROOT_DIR)/import -I$(PHOBOS_PATH) -L-L$(PHOBOS_PATH)/generated/$(OS)/$(BUILD)/$(MODEL) $(PIC) +ifeq (1,$(SHARED)) +PHOBOS_DFLAGS+=-defaultlib=libphobos2$(DOTDLL) -L-rpath=$(PHOBOS_PATH)/generated/$(OS)/$(BUILD)/$(MODEL) +endif + +ROOT_OF_THEM_ALL = ../generated +ROOT = $(ROOT_OF_THEM_ALL)/$(OS)/$(BUILD)/$(MODEL) +OBJDIR=obj/$(OS)/$(BUILD)/$(MODEL) +DRUNTIME=$(ROOT)/$(if $(findstring $(OS),windows),,lib)druntime$(DOTLIB) +DRUNTIMESO_BASE=$(ROOT)/$(if $(findstring $(OS),windows),druntime_shared,libdruntime) +DRUNTIMESO=$(DRUNTIMESO_BASE)$(DOTDLL) +DRUNTIMESOOBJ=$(DRUNTIMESO)$(DOTOBJ) +DRUNTIMESOLIB=$(DRUNTIMESO)$(DOTLIB) + +STDDOC= + +include mak/COPY +COPY:=$(subst \,/,$(COPY)) + +include mak/DOCS +DOCS:=$(subst \,/,$(DOCS)) + +include mak/SRCS +SRCS:=$(subst \,/,$(SRCS)) + +# NOTE: trace.d and cover.d are not necessary for a successful build +# as both are used for debugging features (profiling and coverage) + +# use timelimit to avoid deadlocks if available +TIMELIMIT:=$(if $(shell which timelimit 2>/dev/null || true),timelimit -t 10 ,) + +######################## All of'em ############################## + +ifneq (,$(SHARED)) +target : copy dll $(DRUNTIME) +else +target : copy $(DRUNTIME) +endif + +######################## Doc .html file generation ############################## + +doc: $(DOCS) + +$(DOC_OUTPUT_DIR)/%.html : import/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_%.html : import/core/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_experimental_%.html : import/core/experimental/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_gc_%.html : import/core/gc/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_%.html : import/core/internal/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_array_%.html : import/core/internal/array/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_backtrace_%.html : import/core/internal/backtrace/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_container_%.html : import/core/internal/container/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_elf_%.html : import/core/internal/elf/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_gc_%.html : import/core/internal/gc/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_gc_impl_%.html : import/core/internal/gc/impl/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_gc_impl_conservative_%.html : import/core/internal/gc/impl/conservative/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_gc_impl_manual_%.html : import/core/internal/gc/impl/manual/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_gc_impl_proto_%.html : import/core/internal/gc/impl/proto/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_util_%.html : import/core/internal/util/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_internal_vararg_%.html : import/core/internal/vararg/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_stdc_%.html : import/core/stdc/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_stdcpp_%.html : import/core/stdcpp/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sync.html : import/core/sync/package.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sync_%.html : import/core/sync/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_bionic_%.html : import/core/sys/bionic/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_darwin_%.html : import/core/sys/darwin/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_darwin_mach_%.html : import/core/sys/darwin/mach/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_darwin_netinet_%.html : import/core/sys/darwin/netinet/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_darwin_sys_%.html : import/core/sys/darwin/sys/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_dragonflybsd_%.html : import/core/sys/dragonflybsd/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_dragonflybsd_netinet_%.html : import/core/sys/dragonflybsd/netinet/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_dragonflybsd_sys_%.html : import/core/sys/dragonflybsd/sys/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_elf_%.html : import/core/sys/elf/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_freebsd_%.html : import/core/sys/freebsd/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_freebsd_netinet_%.html : import/core/sys/freebsd/netinet/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_freebsd_sys_%.html : import/core/sys/freebsd/sys/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_linux_%.html : import/core/sys/linux/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_linux_netinet_%.html : import/core/sys/linux/netinet/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_linux_sys_%.html : import/core/sys/linux/sys/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_netbsd_%.html : import/core/sys/netbsd/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_netbsd_sys_%.html : import/core/sys/netbsd/sys/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_openbsd_%.html : import/core/sys/openbsd/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_openbsd_sys_%.html : import/core/sys/openbsd/sys/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_posix_%.html : import/core/sys/posix/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_posix_arpa_%.html : import/core/sys/posix/arpa/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_posix_net_%.html : import/core/sys/posix/net/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_posix_netinet_%.html : import/core/sys/posix/netinet/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_posix_stdc_%.html : import/core/sys/posix/stdc/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_posix_sys_%.html : import/core/sys/posix/sys/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_solaris_%.html : import/core/sys/solaris/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_solaris_sys_%.html : import/core/sys/solaris/sys/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_windows_%.html : import/core/sys/windows/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_sys_windows_stdc_%.html : import/core/sys/windows/stdc/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_thread.html : import/core/thread/package.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_thread_%.html : import/core/thread/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/core_builtins.html : import/core/builtins.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/etc_linux_%.html : import/etc/linux/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/gc_%.html : import/gc/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/gc_impl_%.html : import/gc/impl/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/gc_impl_conservative_%.html : import/gc/impl/conservative/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/gc_impl_manual_%.html : import/gc/impl/manual/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/gc_impl_proto_%.html : import/gc/impl/proto/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + +# -Isrc added here because rt.* modules isn't purposed to import, +# i.e., not copied to import/ dir, but we want to generate documentation for them too +$(DOC_OUTPUT_DIR)/rt_%.html : src/rt/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Isrc -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/rt_typeinfo_%.html : src/rt/typeinfo/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Isrc -Df$@ project.ddoc $(DOCFMT) $< + +$(DOC_OUTPUT_DIR)/rt_util_%.html : src/rt/util/%.d $(DMD) + $(DMD) $(DDOCFLAGS) -Isrc -Df$@ project.ddoc $(DOCFMT) $< + +######################## Header file copy ############################## + +import: copy + +copy: $(COPY) + +$(IMPDIR)/%.di : src/%.di + @mkdir -p $(dir $@) + @cp $< $@ + +$(IMPDIR)/%.d : src/%.d + @mkdir -p $(dir $@) + @cp $< $@ + +$(IMPDIR)/%.h : src/%.h + @mkdir -p $(dir $@) + @cp $< $@ + +######################## Build DMD if non-existent ############################## + +../generated/$(OS)/$(BUILD)/$(MODEL)/dmd$(DOTEXE): + $(MAKE) -C .. dmd BUILD=$(BUILD) OS=$(OS) MODEL=$(MODEL) DMD="" + +# alias using the absolute path (the Phobos Makefile specifies an absolute path) +$(abspath ../generated/$(OS)/$(BUILD)/$(MODEL)/dmd$(DOTEXE)): ../generated/$(OS)/$(BUILD)/$(MODEL)/dmd$(DOTEXE) + +################### C/ASM Targets ############################ + +# Although dmd is compiling the .c files, the preprocessor used on Windows is cl.exe. +# Until https://issues.dlang.org/show_bug.cgi?id=24111 is fixed, the INCLUDE +# enviroment variable needs to be set with the path to the VC system include files. + +OBJS:=$(ROOT)/errno_c$(DOTOBJ) +ifeq (32omf,$(MODEL)) + # minit.asm is only used for -m32omf on Windows; there's a pre-built minit.obj + OBJS+=src/rt/minit$(DOTOBJ) +else ifneq (windows,$(OS)) + OBJS+=$(ROOT)/threadasm$(DOTOBJ) $(ROOT)/valgrind$(DOTOBJ) +endif + +$(ROOT)/%$(DOTOBJ) : src/rt/%.c $(DMD) + @mkdir -p $(dir $@) + $(DMD) -c $(DFLAGS) -I. $< -of$@ + +$(ROOT)/errno_c$(DOTOBJ) : src/core/stdc/errno.c $(DMD) + @mkdir -p $(dir $@) + $(DMD) -c $(DFLAGS) -I. -P=-I. $< -of$@ + +$(ROOT)/threadasm$(DOTOBJ) : src/core/threadasm.S + @mkdir -p $(dir $@) + $(CC) -c $(CFLAGS) $< -o$@ + +$(ROOT)/valgrind$(DOTOBJ) : src/etc/valgrind/valgrind.c src/etc/valgrind/valgrind.h src/etc/valgrind/memcheck.h + @mkdir -p `dirname $@` + $(CC) -c $(CFLAGS) $< -o$@ + +######################## Create a shared library ############################## + +$(DRUNTIMESO) $(DRUNTIMESOLIB) dll: DFLAGS+=-version=Shared $(SHAREDFLAGS) +dll: $(DRUNTIMESOLIB) +dll_so: $(DRUNTIMESO) + +$(DRUNTIMESO): $(OBJS) $(SRCS) $(DMD) + $(DMD) -shared -debuglib= -defaultlib= -of$(DRUNTIMESO) $(DFLAGS) $(SRCS) $(OBJS) $(LINKDL) $(SOLIBS) + +$(DRUNTIMESOLIB): $(OBJS) $(SRCS) $(DMD) + $(DMD) -c $(if $(findstring $(OS),windows),,-fPIC) -of$(DRUNTIMESOOBJ) $(DFLAGS) $(SRCS) + $(DMD) -conf= -lib -of$(DRUNTIMESOLIB) $(DRUNTIMESOOBJ) $(OBJS) + +################### Library generation ######################### + +$(DRUNTIME): $(OBJS) $(SRCS) $(DMD) + $(DMD) -lib -of$(DRUNTIME) -Xfdruntime.json $(DFLAGS) $(SRCS) $(OBJS) + +lib: $(DRUNTIME) + +UT_MODULES:=$(patsubst src/%.d,$(ROOT)/unittest/%,$(SRCS)) +HAS_ADDITIONAL_TESTS:=$(shell test -d test && echo 1) +ifeq ($(HAS_ADDITIONAL_TESTS),1) + ADDITIONAL_TESTS:=test/init_fini test/exceptions test/coverage test/profile test/cycles test/allocations test/typeinfo \ + test/aa test/cpuid test/gc test/hash test/lifetime \ + test/thread test/unittest test/imports test/betterc test/stdcpp test/config test/traits + ifneq (,$(SHARED)) + ADDITIONAL_TESTS+=test/shared + else ifeq (windows,$(OS)) + # although a druntime DLL isn't supported yet, there are Windows-specific general DLL tests + ADDITIONAL_TESTS+=test/shared + endif + ifeq (windows,$(OS)) + ADDITIONAL_TESTS+=test/uuid + else + ADDITIONAL_TESTS+=test/valgrind + endif +endif + +.PHONY : unittest +ifeq (1,$(BUILD_WAS_SPECIFIED)) +ifeq (32omf,$(MODEL)) +unittest : + @echo "Skipping druntime unittests because they cannot be linked on Win32 + OMF due to OPTLINK issues." +else +unittest : $(UT_MODULES) $(addsuffix /.run,$(ADDITIONAL_TESTS)) +endif +else +unittest : unittest-debug unittest-release +unittest-%: target + $(MAKE) -f $(MAKEFILE) unittest OS=$(OS) MODEL=$(MODEL) DMD=$(DMD) BUILD=$* +endif + +ifeq ($(OS),linux) + old_kernel:=$(shell [ "$$(uname -r | cut -d'-' -f1)" \< "2.6.39" ] && echo 1) + ifeq ($(old_kernel),1) + UDFLAGS+=-version=Linux_Pre_2639 + endif +endif + +DISABLED_TESTS = + +$(addprefix $(ROOT)/unittest/,$(DISABLED_TESTS)) : + @echo $@ - disabled + +ifeq (,$(SHARED)) + +$(ROOT)/unittest/test_runner$(DOTEXE): $(OBJS) $(SRCS) src/test_runner.d $(DMD) + $(DMD) $(UDFLAGS) $(UTFLAGS) -of$@ src/test_runner.d $(SRCS) $(OBJS) -defaultlib= $(if $(findstring $(OS),windows),user32.lib,-L-lpthread -L-lm) + +else + +UT_DRUNTIME:=$(ROOT)/unittest/libdruntime-ut$(DOTDLL) +UT_DRUNTIMELIB:=$(ROOT)/unittest/libdruntime-ut$(if $(findstring $(OS),windows),$(DOTLIB),$(DOTDLL)) + +$(UT_DRUNTIME): UDFLAGS+=-version=Shared $(SHAREDFLAGS) +$(UT_DRUNTIME): $(OBJS) $(SRCS) $(DMD) + $(DMD) $(UDFLAGS) -shared $(UTFLAGS) -of$@ $(SRCS) $(OBJS) $(LINKDL) -defaultlib= $(if $(findstring $(OS),windows),user32.lib -L/IMPLIB:$(UT_DRUNTIMELIB),) $(SOLIBS) + +$(ROOT)/unittest/test_runner$(DOTEXE): $(UT_DRUNTIME) src/test_runner.d $(DMD) + $(DMD) $(UDFLAGS) -of$@ src/test_runner.d -L$(UT_DRUNTIMELIB) -defaultlib= $(if $(findstring $(OS),windows),-dllimport=defaultLibsOnly user32.lib,-L-lpthread -L-lm) + +endif + +TESTS_EXTRACTOR=$(ROOT)/tests_extractor$(DOTEXE) +BETTERCTESTS_DIR=$(ROOT)/betterctests + +# macro that returns the module name given the src path +moduleName=$(subst rt.invariant,invariant,$(subst object_,object,$(subst /,.,$(1)))) + +$(ROOT)/unittest/% : $(ROOT)/unittest/test_runner$(DOTEXE) + @mkdir -p $(dir $@) +# make the file very old so it builds and runs again if it fails + @touch -t 197001230123 $@ +# run unittest in its own directory + $(QUIET)$(TIMELIMIT)$< $(call moduleName,$*) +# succeeded, render the file new again + @touch $@ + +ifeq (,$(SHARED)) +$(addsuffix /.run,$(ADDITIONAL_TESTS)): $(DRUNTIME) +else +$(addsuffix /.run,$(filter-out test/shared,$(ADDITIONAL_TESTS))): $(DRUNTIME) +test/shared/.run: $(DRUNTIMESO) +endif + +test/%/.run: test/%/Makefile $(DMD) + $(QUIET)$(MAKE) -C test/$* MODEL=$(MODEL) OS=$(OS) DMD=$(abspath $(DMD)) BUILD=$(BUILD) \ + DRUNTIME=$(abspath $(DRUNTIME)) DRUNTIMESO=$(abspath $(DRUNTIMESO)) LINKDL=$(LINKDL) \ + QUIET=$(QUIET) TIMELIMIT='$(TIMELIMIT)' PIC=$(PIC) + +#################### benchmark suite ########################## + +$(ROOT)/benchmark$(DOTEXE): benchmark/runbench.d target $(DMD) + $(DMD) $(PHOBOS_DFLAGS) -de $< -of$@ + +benchmark: $(ROOT)/benchmark$(DOTEXE) + DMD=$(DMD) $< + +benchmark-compile-only: $(ROOT)/benchmark$(DOTEXE) $(DMD) + DMD=$(DMD) $< --repeat=0 --dflags="$(PHOBOS_DFLAGS) -de" + +#################### test for undesired white spaces ########################## +MANIFEST = $(shell git ls-tree --name-only -r HEAD) + +CWS_MAKEFILES = $(filter mak/% %.mak %/Makefile,$(MANIFEST)) +NOT_MAKEFILES = $(filter-out $(CWS_MAKEFILES) src/rt/minit.obj test/%.exp,$(MANIFEST)) +GREP = grep + +checkwhitespace: +# restrict to linux, other platforms don't have a version of grep that supports -P +ifeq (linux,$(OS)) + $(GREP) -n -U -P "([ \t]$$|\r)" $(CWS_MAKEFILES) ; test "$$?" -ne 0 + $(GREP) -n -U -P "( $$|\r|\t)" $(NOT_MAKEFILES) ; test "$$?" -ne 0 +endif + +detab: + detab $(MANIFEST) + tolf $(MANIFEST) + + +gitzip: + git archive --format=zip HEAD > druntime.zip + +zip: druntime.zip + +druntime.zip: $(MANIFEST) + rm -rf $@ + zip $@ $^ + +ifneq (,$(findstring Darwin_64_32, $(PWD))) +install: + echo "Darwin_64_32_disabled" +else +install: target + mkdir -p '$(INSTALL_DIR)'/src/druntime/import + cp -r import/* '$(INSTALL_DIR)'/src/druntime/import/ +endif + +clean: $(addsuffix /.clean,$(ADDITIONAL_TESTS)) + rm -rf $(ROOT_OF_THEM_ALL) $(IMPDIR) $(DOC_OUTPUT_DIR) druntime.zip + +test/%/.clean: test/%/Makefile + $(MAKE) -C test/$* clean + +%/.directory : + mkdir -p $* || exists $* + touch $@ + +################################################################################ +# Build the test extractor. +# - extracts and runs public unittest examples to checks for missing imports +# - extracts and runs @betterC unittests +################################################################################ + +$(TESTS_EXTRACTOR): $(TOOLS_DIR)/tests_extractor.d | $(LIB) + $(DUB) build --force --single $< + mv $(TOOLS_DIR)/tests_extractor$(DOTEXE) $@ + +test_extractor: $(TESTS_EXTRACTOR) + +################################################################################ +# Check and run @betterC tests +# ---------------------------- +# +# Extract @betterC tests of a module and run them in -betterC +# +# make betterc -j20 # all tests +# make src/core/memory.betterc # individual module +################################################################################ + +betterc: | $(TESTS_EXTRACTOR) $(BETTERCTESTS_DIR)/.directory + $(MAKE) $$(find src -type f -name '*.d' | sed 's/[.]d/.betterc/') + +%.betterc: %.d | $(TESTS_EXTRACTOR) $(BETTERCTESTS_DIR)/.directory + @$(TESTS_EXTRACTOR) --betterC --attributes betterC \ + --inputdir $< --outputdir $(BETTERCTESTS_DIR) + @$(DMD) $(NODEFAULTLIB) -betterC $(UDFLAGS) $(UTFLAGS) -od$(BETTERCTESTS_DIR) -run $(BETTERCTESTS_DIR)/$(subst /,_,$<) + +################################################################################ + +# Submission to Druntime are required to conform to the DStyle +# The tests below automate some, but not all parts of the DStyle guidelines. +# See: http://dlang.org/dstyle.html +style: checkwhitespace style_lint + +style_lint: + @echo "Check for trailing whitespace" + $(GREP) -nr '[[:blank:]]$$' $(MANIFEST) ; test $$? -eq 1 + + @echo "Enforce whitespace before opening parenthesis" + $(GREP) -nrE "\<(for|foreach|foreach_reverse|if|while|switch|catch|version)\(" $$(find src -name '*.d') ; test $$? -eq 1 + + @echo "Enforce no whitespace after opening parenthesis" + $(GREP) -nrE "\<(version) \( " $$(find src -name '*.d') ; test $$? -eq 1 + +################################################################################ +# Check for missing imports in public unittest examples. +################################################################################ + +PUBLICTESTS_DIR=$(ROOT)/publictests +publictests: $(addsuffix .publictests, $(basename $(SRCS))) + +################################################################################ +# Extract public tests of a module and test them in an separate file (i.e. without its module) +# This is done to check for potentially missing imports in the examples, e.g. +# make src/core/time.publictests +################################################################################ +%.publictests: %.d $(TESTS_EXTRACTOR) $(DRUNTIME) | $(PUBLICTESTS_DIR)/.directory + @$(TESTS_EXTRACTOR) --inputdir $< --outputdir $(PUBLICTESTS_DIR) + @$(DMD) -main $(UDFLAGS) -unittest -defaultlib= -debuglib= -od$(PUBLICTESTS_DIR) $(DRUNTIME) -run $(PUBLICTESTS_DIR)/$(subst /,_,$<) + +################################################################################ + +.PHONY : buildkite-test +buildkite-test: unittest benchmark-compile-only + +.DELETE_ON_ERROR: # GNU Make directive (delete output files on error) diff --git a/runtime/druntime/posix.mak b/runtime/druntime/posix.mak index 0735a976f7f..062a7c12e7b 100644 --- a/runtime/druntime/posix.mak +++ b/runtime/druntime/posix.mak @@ -1,591 +1,11 @@ -# This makefile is designed to be run by gnu make. -# The default make program on FreeBSD 8.1 is not gnu make; to install gnu make: -# pkg_add -r gmake -# and then run as gmake rather than make. +$(warning ===== DEPRECATION NOTICE ===== ) +$(warning ===== DEPRECATION: posix.mak is deprecated. Please use generic Makefile instead.) +$(warning ============================== ) -QUIET:= +# forward everything to Makefile -DMD_DIR=../compiler -DUB=dub -TOOLS_DIR=../../tools +target: + $(MAKE) -f Makefile $@ -include $(DMD_DIR)/src/osmodel.mak - -# Default to a release built, override with BUILD=debug -ifeq (,$(BUILD)) -BUILD_WAS_SPECIFIED=0 -BUILD=release -else -BUILD_WAS_SPECIFIED=1 -endif - -ifneq ($(BUILD),release) - ifneq ($(BUILD),debug) - $(error Unrecognized BUILD=$(BUILD), must be 'debug' or 'release') - endif -endif - -DMD=$(DMD_DIR)/../generated/$(OS)/$(BUILD)/$(MODEL)/dmd -INSTALL_DIR=../../install - -# directory where the html files for the documentation are placed -DOC_OUTPUT_DIR=doc -IMPDIR=import - -OPTIONAL_COVERAGE:=$(if $(TEST_COVERAGE),-cov=ctfe,) - -# default to PIC, use PIC=1/0 to en-/disable PIC. -# Note that shared libraries and C files are always compiled with PIC. -ifeq ($(PIC),) - PIC:=1 -endif -ifeq ($(PIC),1) - override PIC:=-fPIC -else - override PIC:= -endif - -ifeq (osx,$(OS)) - DOTDLL:=.dylib - DOTLIB:=.a - export MACOSX_DEPLOYMENT_TARGET=10.9 -else - DOTDLL:=.so - DOTLIB:=.a -endif - -# build with shared library support -# (defaults to true on supported platforms, can be overridden w/ make SHARED=0) -SHARED=$(if $(findstring $(OS),linux freebsd dragonflybsd),1,) - -LINKDL=$(if $(findstring $(OS),linux),-L-ldl,) - -MAKEFILE = $(firstword $(MAKEFILE_LIST)) - -DDOCFLAGS=-conf= -c -w -o- -Isrc -Iimport -version=CoreDdoc - -# Set CFLAGS -CFLAGS=$(MODEL_FLAG) -fPIC -DHAVE_UNISTD_H -ifeq ($(BUILD),debug) - CFLAGS += -g -else - CFLAGS += -O3 -endif -ifeq (solaris,$(OS)) - CFLAGS+=-D_REENTRANT # for thread-safe errno -endif -ifeq (osx,$(OS)) - ifeq (64,$(MODEL)) - CFLAGS+=--target=x86_64-darwin-apple # ARM cpu is not supported by dmd - endif -endif - -# Set DFLAGS -UDFLAGS:=-conf= -Isrc -Iimport -w -de -preview=dip1000 -preview=fieldwise $(MODEL_FLAG) $(PIC) $(OPTIONAL_COVERAGE) -preview=dtorfields -ifeq ($(BUILD),debug) - UDFLAGS += -g -debug - DFLAGS:=$(UDFLAGS) -else - UDFLAGS += -O -release - DFLAGS:=$(UDFLAGS) -inline # unittests don't compile with -inline -endif - -UTFLAGS:=-version=CoreUnittest -unittest -checkaction=context - -# Set PHOBOS_DFLAGS (for linking against Phobos) -PHOBOS_PATH=../../phobos -SHARED=$(if $(findstring $(OS),linux freebsd),1,) -ROOT_DIR := $(shell pwd) -PHOBOS_DFLAGS=-conf= $(MODEL_FLAG) -I$(ROOT_DIR)/import -I$(PHOBOS_PATH) -L-L$(PHOBOS_PATH)/generated/$(OS)/$(BUILD)/$(MODEL) $(PIC) -ifeq (1,$(SHARED)) -PHOBOS_DFLAGS+=-defaultlib=libphobos2.so -L-rpath=$(PHOBOS_PATH)/generated/$(OS)/$(BUILD)/$(MODEL) -endif - -ROOT_OF_THEM_ALL = ../generated -ROOT = $(ROOT_OF_THEM_ALL)/$(OS)/$(BUILD)/$(MODEL) -OBJDIR=obj/$(OS)/$(BUILD)/$(MODEL) -DRUNTIME_BASE=druntime-$(OS)$(MODEL) -DRUNTIME=$(ROOT)/libdruntime.a -DRUNTIMESO=$(ROOT)/libdruntime.so -DRUNTIMESOOBJ=$(ROOT)/libdruntime.so.o -DRUNTIMESOLIB=$(ROOT)/libdruntime.so.a - -STDDOC= - -include mak/COPY -COPY:=$(subst \,/,$(COPY)) - -include mak/DOCS -DOCS:=$(subst \,/,$(DOCS)) - -include mak/SRCS -SRCS:=$(subst \,/,$(SRCS)) - -# NOTE: trace.d and cover.d are not necessary for a successful build -# as both are used for debugging features (profiling and coverage) -# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and -# minit.asm is not used by dmd for Linux - -OBJS= $(ROOT)/errno_c.o $(ROOT)/threadasm.o $(ROOT)/valgrind.o - -# use timelimit to avoid deadlocks if available -TIMELIMIT:=$(if $(shell which timelimit 2>/dev/null || true),timelimit -t 10 ,) - -######################## All of'em ############################## - -ifneq (,$(SHARED)) -target : copy dll $(DRUNTIME) -else -target : copy $(DRUNTIME) -endif - -######################## Doc .html file generation ############################## - -doc: $(DOCS) - -$(DOC_OUTPUT_DIR)/%.html : src/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_%.html : src/core/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_experimental_%.html : src/core/experimental/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_gc_%.html : src/core/gc/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_%.html : src/core/internal/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_array_%.html : src/core/internal/array/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_backtrace_%.html : src/core/internal/backtrace/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_container_%.html : src/core/internal/container/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_elf_%.html : src/core/internal/elf/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_gc_%.html : src/core/internal/gc/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_gc_impl_%.html : src/core/internal/gc/impl/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_gc_impl_conservative_%.html : src/core/internal/gc/impl/conservative/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_gc_impl_manual_%.html : src/core/internal/gc/impl/manual/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_gc_impl_proto_%.html : src/core/internal/gc/impl/proto/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_util_%.html : src/core/internal/util/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_internal_vararg_%.html : src/core/internal/vararg/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_stdc_%.html : src/core/stdc/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_stdcpp_%.html : src/core/stdcpp/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sync.html : src/core/sync/package.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sync_%.html : src/core/sync/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_bionic_%.html : src/core/sys/bionic/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_darwin_%.html : src/core/sys/darwin/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_darwin_mach_%.html : src/core/sys/darwin/mach/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_darwin_netinet_%.html : src/core/sys/darwin/netinet/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_darwin_sys_%.html : src/core/sys/darwin/sys/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_dragonflybsd_%.html : src/core/sys/dragonflybsd/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_dragonflybsd_netinet_%.html : src/core/sys/dragonflybsd/netinet/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_dragonflybsd_sys_%.html : src/core/sys/dragonflybsd/sys/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_elf_%.html : src/core/sys/elf/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_freebsd_%.html : src/core/sys/freebsd/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_freebsd_netinet_%.html : src/core/sys/freebsd/netinet/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_freebsd_sys_%.html : src/core/sys/freebsd/sys/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_linux_%.html : src/core/sys/linux/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_linux_netinet_%.html : src/core/sys/linux/netinet/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_linux_sys_%.html : src/core/sys/linux/sys/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_netbsd_%.html : src/core/sys/netbsd/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_netbsd_sys_%.html : src/core/sys/netbsd/sys/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_openbsd_%.html : src/core/sys/openbsd/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_openbsd_sys_%.html : src/core/sys/openbsd/sys/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_posix_%.html : src/core/sys/posix/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_posix_arpa_%.html : src/core/sys/posix/arpa/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_posix_net_%.html : src/core/sys/posix/net/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_posix_netinet_%.html : src/core/sys/posix/netinet/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_posix_stdc_%.html : src/core/sys/posix/stdc/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_posix_sys_%.html : src/core/sys/posix/sys/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_solaris_%.html : src/core/sys/solaris/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_solaris_sys_%.html : src/core/sys/solaris/sys/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_windows_%.html : src/core/sys/windows/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_sys_windows_stdc_%.html : src/core/sys/windows/stdc/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_thread.html : src/core/thread/package.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_thread_%.html : src/core/thread/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/core_builtins.html : src/core/builtins.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/etc_linux_%.html : src/etc/linux/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/gc_%.html : src/gc/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/gc_impl_%.html : src/gc/impl/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/gc_impl_conservative_%.html : src/gc/impl/conservative/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/gc_impl_manual_%.html : src/gc/impl/manual/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/gc_impl_proto_%.html : src/gc/impl/proto/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/rt_%.html : src/rt/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/rt_typeinfo_%.html : src/rt/typeinfo/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -$(DOC_OUTPUT_DIR)/rt_util_%.html : src/rt/util/%.d $(DMD) - $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< - -######################## Header file copy ############################## - -import: copy - -copy: $(COPY) - -$(IMPDIR)/object.d : src/object.d - @mkdir -p $(dir $@) - @cp $< $@ - -$(IMPDIR)/%.di : src/%.di - @mkdir -p $(dir $@) - @cp $< $@ - -$(IMPDIR)/%.d : src/%.d - @mkdir -p $(dir $@) - @cp $< $@ - -$(IMPDIR)/%.h : src/%.h - @mkdir -p $(dir $@) - @cp $< $@ - -######################## Build DMD if non-existent ############################## - -$(DMD): - $(MAKE) -C $(DMD_DIR)/src -f posix.mak BUILD=$(BUILD) OS=$(OS) MODEL=$(MODEL) - -################### C/ASM Targets ############################ - -$(ROOT)/%.o : src/rt/%.c $(DMD) - @mkdir -p $(dir $@) - $(DMD) -c $(DFLAGS) -I. $< -of$@ - -$(ROOT)/errno_c.o : src/core/stdc/errno.c $(DMD) - @mkdir -p $(dir $@) - $(DMD) -c $(DFLAGS) -I. $< -of$@ - -$(ROOT)/threadasm.o : src/core/threadasm.S - @mkdir -p $(dir $@) - $(CC) -c $(CFLAGS) $< -o$@ - -$(ROOT)/valgrind.o : src/etc/valgrind/valgrind.c src/etc/valgrind/valgrind.h src/etc/valgrind/memcheck.h - @mkdir -p `dirname $@` - $(CC) -c $(CFLAGS) $< -o$@ - -######################## Create a shared library ############################## - -$(DRUNTIMESO) $(DRUNTIMESOLIB) dll: DFLAGS+=-version=Shared -fPIC -dll: $(DRUNTIMESOLIB) - -$(DRUNTIMESO): $(OBJS) $(SRCS) $(DMD) - $(DMD) -shared -debuglib= -defaultlib= -of$(DRUNTIMESO) $(DFLAGS) $(SRCS) $(OBJS) $(LINKDL) -L-lpthread -L-lm - -$(DRUNTIMESOLIB): $(OBJS) $(SRCS) $(DMD) - $(DMD) -c -fPIC -of$(DRUNTIMESOOBJ) $(DFLAGS) $(SRCS) - $(DMD) -conf= -lib -of$(DRUNTIMESOLIB) $(DRUNTIMESOOBJ) $(OBJS) - -################### Library generation ######################### - -$(DRUNTIME): $(OBJS) $(SRCS) $(DMD) - $(DMD) -lib -of$(DRUNTIME) -Xfdruntime.json $(DFLAGS) $(SRCS) $(OBJS) - -lib: $(DRUNTIME) - -UT_MODULES:=$(patsubst src/%.d,$(ROOT)/unittest/%,$(SRCS)) -HAS_ADDITIONAL_TESTS:=$(shell test -d test && echo 1) -ifeq ($(HAS_ADDITIONAL_TESTS),1) - ADDITIONAL_TESTS:=test/init_fini test/exceptions test/coverage test/profile test/cycles test/allocations test/typeinfo \ - test/aa test/cpuid test/gc test/hash test/lifetime \ - test/thread test/unittest test/imports test/betterc test/stdcpp test/config \ - test/traits test/valgrind - ADDITIONAL_TESTS+=$(if $(SHARED),test/shared,) -endif - -.PHONY : unittest -ifeq (1,$(BUILD_WAS_SPECIFIED)) -unittest : $(UT_MODULES) $(addsuffix /.run,$(ADDITIONAL_TESTS)) -else -unittest : unittest-debug unittest-release -unittest-%: target - $(MAKE) -f $(MAKEFILE) unittest OS=$(OS) MODEL=$(MODEL) DMD=$(DMD) BUILD=$* -endif - -ifeq ($(OS),linux) - old_kernel:=$(shell [ "$$(uname -r | cut -d'-' -f1)" \< "2.6.39" ] && echo 1) - ifeq ($(old_kernel),1) - UDFLAGS+=-version=Linux_Pre_2639 - endif -endif - -DISABLED_TESTS = - -$(addprefix $(ROOT)/unittest/,$(DISABLED_TESTS)) : - @echo $@ - disabled - -ifeq (,$(SHARED)) - -$(ROOT)/unittest/test_runner: $(OBJS) $(SRCS) src/test_runner.d $(DMD) - $(DMD) $(UDFLAGS) $(UTFLAGS) -of$@ src/test_runner.d $(SRCS) $(OBJS) -debuglib= -defaultlib= -L-lpthread -L-lm - -else - -UT_DRUNTIME:=$(ROOT)/unittest/libdruntime-ut$(DOTDLL) - -$(UT_DRUNTIME): UDFLAGS+=-version=Shared -fPIC -$(UT_DRUNTIME): $(OBJS) $(SRCS) $(DMD) - $(DMD) $(UDFLAGS) -shared $(UTFLAGS) -of$@ $(SRCS) $(OBJS) $(LINKDL) -debuglib= -defaultlib= -L-lpthread -L-lm - -$(ROOT)/unittest/test_runner: $(UT_DRUNTIME) src/test_runner.d $(DMD) - $(DMD) $(UDFLAGS) -of$@ src/test_runner.d -L$(UT_DRUNTIME) -debuglib= -defaultlib= -L-lpthread -L-lm - -endif - -TESTS_EXTRACTOR=$(ROOT)/tests_extractor -BETTERCTESTS_DIR=$(ROOT)/betterctests - -# macro that returns the module name given the src path -moduleName=$(subst rt.invariant,invariant,$(subst object_,object,$(subst /,.,$(1)))) - -$(ROOT)/unittest/% : $(ROOT)/unittest/test_runner - @mkdir -p $(dir $@) -# make the file very old so it builds and runs again if it fails - @touch -t 197001230123 $@ -# run unittest in its own directory - $(QUIET)$(TIMELIMIT)$< $(call moduleName,$*) -# succeeded, render the file new again - @touch $@ - -$(addsuffix /.run,$(filter-out test/shared,$(ADDITIONAL_TESTS))): $(DRUNTIME) -test/shared/.run: $(DRUNTIMESO) - -test/%/.run: test/%/Makefile $(DMD) - $(QUIET)$(MAKE) -C test/$* MODEL=$(MODEL) OS=$(OS) DMD=$(abspath $(DMD)) BUILD=$(BUILD) \ - DRUNTIME=$(abspath $(DRUNTIME)) DRUNTIMESO=$(abspath $(DRUNTIMESO)) LINKDL=$(LINKDL) \ - QUIET=$(QUIET) TIMELIMIT='$(TIMELIMIT)' PIC=$(PIC) - -#################### benchmark suite ########################## - -$(ROOT)/benchmark: benchmark/runbench.d target $(DMD) - $(DMD) $(PHOBOS_DFLAGS) -de $< -of$@ - -benchmark: $(ROOT)/benchmark - DMD=$(DMD) $< - -benchmark-compile-only: $(ROOT)/benchmark $(DMD) - DMD=$(DMD) $< --repeat=0 --dflags="$(PHOBOS_DFLAGS) -de" - -#################### test for undesired white spaces ########################## -MANIFEST = $(shell git ls-tree --name-only -r HEAD) - -CWS_MAKEFILES = $(filter mak/% %.mak %/Makefile,$(MANIFEST)) -NOT_MAKEFILES = $(filter-out $(CWS_MAKEFILES) src/rt/minit.obj test/%.exp,$(MANIFEST)) -GREP = grep - -checkwhitespace: -# restrict to linux, other platforms don't have a version of grep that supports -P -ifeq (linux,$(OS)) - $(GREP) -n -U -P "([ \t]$$|\r)" $(CWS_MAKEFILES) ; test "$$?" -ne 0 - $(GREP) -n -U -P "( $$|\r|\t)" $(NOT_MAKEFILES) ; test "$$?" -ne 0 -endif - -detab: - detab $(MANIFEST) - tolf $(MANIFEST) - - -gitzip: - git archive --format=zip HEAD > druntime.zip - -zip: druntime.zip - -druntime.zip: $(MANIFEST) - rm -rf $@ - zip $@ $^ - -ifneq (,$(findstring Darwin_64_32, $(PWD))) -install: - echo "Darwin_64_32_disabled" -else -install: target - mkdir -p $(INSTALL_DIR)/src/druntime/import - cp -r import/* $(INSTALL_DIR)/src/druntime/import/ -endif - -clean: $(addsuffix /.clean,$(ADDITIONAL_TESTS)) - rm -rf $(ROOT_OF_THEM_ALL) $(IMPDIR) $(DOC_OUTPUT_DIR) druntime.zip - -test/%/.clean: test/%/Makefile - $(MAKE) -C test/$* clean - -%/.directory : - mkdir -p $* || exists $* - touch $@ - -################################################################################ -# Build the test extractor. -# - extracts and runs public unittest examples to checks for missing imports -# - extracts and runs @betterC unittests -################################################################################ - -$(TESTS_EXTRACTOR): $(TOOLS_DIR)/tests_extractor.d | $(LIB) - $(DUB) build --force --single $< - mv $(TOOLS_DIR)/tests_extractor $@ - -test_extractor: $(TESTS_EXTRACTOR) - -################################################################################ -# Check and run @betterC tests -# ---------------------------- -# -# Extract @betterC tests of a module and run them in -betterC -# -# make -f betterc -j20 # all tests -# make -f posix.mak src/core/memory.betterc # individual module -################################################################################ - -betterc: | $(TESTS_EXTRACTOR) $(BETTERCTESTS_DIR)/.directory - $(MAKE) -f posix.mak $$(find src -type f -name '*.d' | sed 's/[.]d/.betterc/') - -%.betterc: %.d | $(TESTS_EXTRACTOR) $(BETTERCTESTS_DIR)/.directory - @$(TESTS_EXTRACTOR) --betterC --attributes betterC \ - --inputdir $< --outputdir $(BETTERCTESTS_DIR) - @$(DMD) $(NODEFAULTLIB) -betterC $(UDFLAGS) $(UTFLAGS) -od$(BETTERCTESTS_DIR) -run $(BETTERCTESTS_DIR)/$(subst /,_,$<) - -################################################################################ - -# Submission to Druntime are required to conform to the DStyle -# The tests below automate some, but not all parts of the DStyle guidelines. -# See: http://dlang.org/dstyle.html -style: checkwhitespace style_lint - -style_lint: - @echo "Check for trailing whitespace" - $(GREP) -nr '[[:blank:]]$$' $(MANIFEST) ; test $$? -eq 1 - - @echo "Enforce whitespace before opening parenthesis" - $(GREP) -nrE "\<(for|foreach|foreach_reverse|if|while|switch|catch|version)\(" $$(find src -name '*.d') ; test $$? -eq 1 - - @echo "Enforce no whitespace after opening parenthesis" - $(GREP) -nrE "\<(version) \( " $$(find src -name '*.d') ; test $$? -eq 1 - -################################################################################ -# Check for missing imports in public unittest examples. -################################################################################ - -PUBLICTESTS_DIR=$(ROOT)/publictests -publictests: $(addsuffix .publictests, $(basename $(SRCS))) - -################################################################################ -# Extract public tests of a module and test them in an separate file (i.e. without its module) -# This is done to check for potentially missing imports in the examples, e.g. -# make -f posix.mak src/core/time.publictests -################################################################################ -%.publictests: %.d $(TESTS_EXTRACTOR) $(DRUNTIME) | $(PUBLICTESTS_DIR)/.directory - @$(TESTS_EXTRACTOR) --inputdir $< --outputdir $(PUBLICTESTS_DIR) - @$(DMD) -main $(UDFLAGS) -unittest -defaultlib= -debuglib= -od$(PUBLICTESTS_DIR) $(DRUNTIME) -run $(PUBLICTESTS_DIR)/$(subst /,_,$<) - -################################################################################ - -.PHONY : buildkite-test -buildkite-test: unittest benchmark-compile-only - -.DELETE_ON_ERROR: # GNU Make directive (delete output files on error) +%: + $(MAKE) -f Makefile $@ diff --git a/runtime/druntime/src/__builtins.di b/runtime/druntime/src/__builtins.di index c3ac5cff355..a96e4b09fcf 100644 --- a/runtime/druntime/src/__builtins.di +++ b/runtime/druntime/src/__builtins.di @@ -84,6 +84,10 @@ version (CRuntime_Microsoft) version (DigitalMars) { + immutable float __nan = float.nan; + + float __builtin_nanf()(char*) { return float.nan; } + double __builtin_inf()() { return double.infinity; } float __builtin_inff()() { return float.infinity; } real __builtin_infl()() { return real.infinity; } diff --git a/runtime/druntime/src/core/attribute.d b/runtime/druntime/src/core/attribute.d index c2a7c334eb7..79ad25ab358 100644 --- a/runtime/druntime/src/core/attribute.d +++ b/runtime/druntime/src/core/attribute.d @@ -290,3 +290,15 @@ version (UdaGNUAbiTag) struct gnuAbiTag * --- */ enum mustuse; + +/** + * Use this attribute to indicate that a shared module constructor does not depend on any + * other module constructor being run first. This avoids errors on cyclic module constructors. + * + * However, it is now up to the user to enforce safety. + * The module constructor must be marked `@system` as a result. + * Prefer to refactor the module constructor causing the cycle so it's in its own module if possible. + * + * This is only allowed on `shared` static constructors, not thread-local module constructors. + */ +enum standalone; diff --git a/runtime/druntime/src/core/internal/array/construction.d b/runtime/druntime/src/core/internal/array/construction.d index 54f8767139c..655acc8db57 100644 --- a/runtime/druntime/src/core/internal/array/construction.d +++ b/runtime/druntime/src/core/internal/array/construction.d @@ -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!"); + } +} diff --git a/runtime/druntime/src/core/internal/array/operations.d b/runtime/druntime/src/core/internal/array/operations.d index 3e2331484b3..7e5b5f43e9b 100644 --- a/runtime/druntime/src/core/internal/array/operations.d +++ b/runtime/druntime/src/core/internal/array/operations.d @@ -33,7 +33,7 @@ version (LDC) version = GNU_OR_LDC; * * Returns: the slice containing the result */ -T[] arrayOp(T : T[], Args...)(T[] res, Filter!(isType, Args) args) @trusted @nogc pure nothrow +T[] arrayOp(T : T[], Args...)(T[] res, Filter!(isType, Args) args) @trusted { alias scalarizedExp = staticMap!(toElementType, Args); alias check = typeCheck!(true, T, scalarizedExp); // must support all scalar ops @@ -541,7 +541,7 @@ unittest } // test handling of v op= exp -unittest +@nogc nothrow pure @safe unittest { uint[32] c; arrayOp!(uint[], uint, "+=")(c[], 2); @@ -556,7 +556,7 @@ unittest } // proper error message for UDT lacking certain ops -unittest +@nogc nothrow pure @safe unittest { static assert(!is(typeof(&arrayOp!(int[4][], int[4], "+=")))); static assert(!is(typeof(&arrayOp!(int[4][], int[4], "u-", "=")))); @@ -585,7 +585,7 @@ unittest } // test mixed type array op -unittest +@nogc nothrow pure @safe unittest { uint[32] a = 0xF; float[32] res = 2.0f; @@ -595,7 +595,7 @@ unittest } // test mixed type array op -unittest +@nogc nothrow pure @safe unittest { static struct S { @@ -613,7 +613,7 @@ unittest } // test scalar after operation argument -unittest +@nogc nothrow pure @safe unittest { float[32] res, a = 2, b = 3; float c = 4; @@ -622,7 +622,7 @@ unittest assert(v == 2 * 3 + 4); } -unittest +@nogc nothrow pure @safe unittest { // https://issues.dlang.org/show_bug.cgi?id=17964 uint bug(){ @@ -635,7 +635,7 @@ unittest } // https://issues.dlang.org/show_bug.cgi?id=19796 -unittest +nothrow pure @safe unittest { double[] data = [0.5]; double[] result; @@ -645,7 +645,7 @@ unittest } // https://issues.dlang.org/show_bug.cgi?id=21110 -unittest +pure unittest { import core.exception; @@ -668,3 +668,20 @@ unittest void func() { dst[] = a[] + b[]; } assertThrown!AssertError(func(), "Array operations with mismatched lengths must throw an error"); } + +// https://issues.dlang.org/show_bug.cgi?id=24272 +unittest +{ + static struct B + { + B opOpAssign(string op)(B other) + { + static int g; + g++; + throw new Exception(""); + } + } + + B[] bArr; + bArr[] += B(); +} diff --git a/runtime/druntime/src/core/internal/atomic.d b/runtime/druntime/src/core/internal/atomic.d index 6792efb2892..82d9ea19d60 100644 --- a/runtime/druntime/src/core/internal/atomic.d +++ b/runtime/druntime/src/core/internal/atomic.d @@ -211,6 +211,8 @@ version (DigitalMars) enum SizedReg(int reg, T = size_t) = registerNames[reg][RegIndex!T]; } + enum IsAtomicLockFree(T) = T.sizeof <= size_t.sizeof * 2; + inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted if (CanCAS!T) { @@ -811,6 +813,11 @@ version (DigitalMars) } } + void atomicSignalFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted + { + // no-op, dmd doesn't reorder instructions + } + void pause() pure nothrow @nogc @trusted { version (D_InlineAsm_X86) @@ -818,7 +825,7 @@ version (DigitalMars) asm pure nothrow @nogc @trusted { naked; - rep; nop; + pause; ret; } } @@ -827,8 +834,7 @@ version (DigitalMars) asm pure nothrow @nogc @trusted { naked; - // pause; // TODO: DMD should add this opcode to its inline asm - rep; nop; + pause; ret; } } @@ -844,37 +850,57 @@ else version (GNU) import gcc.builtins; import gcc.config; + // Targets where MemoryOrder.acq_rel is sufficiently cheaper than using + // MemoryOrder.seq, used when the MemoryOrder requested is not valid for + // a given atomic operation. + version (IA64) + private enum PreferAcquireRelease = true; + else version (PPC) + private enum PreferAcquireRelease = true; + else version (PPC64) + private enum PreferAcquireRelease = true; + else + private enum PreferAcquireRelease = false; + + enum IsAtomicLockFree(T) = __atomic_is_lock_free(T.sizeof, null); + inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted if (CanCAS!T) { + // MemoryOrder.rel and MemoryOrder.acq_rel are not valid for load. static assert(order != MemoryOrder.rel, "invalid MemoryOrder for atomicLoad()"); + static if (order == MemoryOrder.acq_rel) + enum smodel = PreferAcquireRelease ? MemoryOrder.acq : MemoryOrder.seq; + else + enum smodel = order; + static if (GNU_Have_Atomics || GNU_Have_LibAtomic) { static if (T.sizeof == ubyte.sizeof) { - ubyte value = __atomic_load_1(cast(shared)src, order); + ubyte value = __atomic_load_1(cast(shared)src, smodel); return *cast(typeof(return)*)&value; } else static if (T.sizeof == ushort.sizeof) { - ushort value = __atomic_load_2(cast(shared)src, order); + ushort value = __atomic_load_2(cast(shared)src, smodel); return *cast(typeof(return)*)&value; } else static if (T.sizeof == uint.sizeof) { - uint value = __atomic_load_4(cast(shared)src, order); + uint value = __atomic_load_4(cast(shared)src, smodel); return *cast(typeof(return)*)&value; } else static if (T.sizeof == ulong.sizeof && GNU_Have_64Bit_Atomics) { - ulong value = __atomic_load_8(cast(shared)src, order); + ulong value = __atomic_load_8(cast(shared)src, smodel); return *cast(typeof(return)*)&value; } else static if (GNU_Have_LibAtomic) { T value; - __atomic_load(T.sizeof, cast(shared)src, &value, order); + __atomic_load(T.sizeof, cast(shared)src, &value, smodel); return *cast(typeof(return)*)&value; } else @@ -891,20 +917,26 @@ else version (GNU) void atomicStore(MemoryOrder order = MemoryOrder.seq, T)(T* dest, T value) pure nothrow @nogc @trusted if (CanCAS!T) { + // MemoryOrder.acq and MemoryOrder.acq_rel are not valid for store. static assert(order != MemoryOrder.acq, "Invalid MemoryOrder for atomicStore()"); + static if (order == MemoryOrder.acq_rel) + enum smodel = PreferAcquireRelease ? MemoryOrder.rel : MemoryOrder.seq; + else + enum smodel = order; + static if (GNU_Have_Atomics || GNU_Have_LibAtomic) { static if (T.sizeof == ubyte.sizeof) - __atomic_store_1(cast(shared)dest, *cast(ubyte*)&value, order); + __atomic_store_1(cast(shared)dest, *cast(ubyte*)&value, smodel); else static if (T.sizeof == ushort.sizeof) - __atomic_store_2(cast(shared)dest, *cast(ushort*)&value, order); + __atomic_store_2(cast(shared)dest, *cast(ushort*)&value, smodel); else static if (T.sizeof == uint.sizeof) - __atomic_store_4(cast(shared)dest, *cast(uint*)&value, order); + __atomic_store_4(cast(shared)dest, *cast(uint*)&value, smodel); else static if (T.sizeof == ulong.sizeof && GNU_Have_64Bit_Atomics) - __atomic_store_8(cast(shared)dest, *cast(ulong*)&value, order); + __atomic_store_8(cast(shared)dest, *cast(ulong*)&value, smodel); else static if (GNU_Have_LibAtomic) - __atomic_store(T.sizeof, cast(shared)dest, cast(void*)&value, order); + __atomic_store(T.sizeof, cast(shared)dest, cast(void*)&value, smodel); else static assert(0, "Invalid template type specified."); } @@ -977,30 +1009,36 @@ else version (GNU) { static if (GNU_Have_Atomics || GNU_Have_LibAtomic) { + // MemoryOrder.acq is not valid for exchange. + static if (order == MemoryOrder.acq) + enum smodel = PreferAcquireRelease ? MemoryOrder.acq_rel : MemoryOrder.seq; + else + enum smodel = order; + static if (T.sizeof == byte.sizeof) { - ubyte res = __atomic_exchange_1(cast(shared)dest, *cast(ubyte*)&value, order); + ubyte res = __atomic_exchange_1(cast(shared)dest, *cast(ubyte*)&value, smodel); return *cast(typeof(return)*)&res; } else static if (T.sizeof == short.sizeof) { - ushort res = __atomic_exchange_2(cast(shared)dest, *cast(ushort*)&value, order); + ushort res = __atomic_exchange_2(cast(shared)dest, *cast(ushort*)&value, smodel); return *cast(typeof(return)*)&res; } else static if (T.sizeof == int.sizeof) { - uint res = __atomic_exchange_4(cast(shared)dest, *cast(uint*)&value, order); + uint res = __atomic_exchange_4(cast(shared)dest, *cast(uint*)&value, smodel); return *cast(typeof(return)*)&res; } else static if (T.sizeof == long.sizeof && GNU_Have_64Bit_Atomics) { - ulong res = __atomic_exchange_8(cast(shared)dest, *cast(ulong*)&value, order); + ulong res = __atomic_exchange_8(cast(shared)dest, *cast(ulong*)&value, smodel); return *cast(typeof(return)*)&res; } else static if (GNU_Have_LibAtomic) { T res = void; - __atomic_exchange(T.sizeof, cast(shared)dest, cast(void*)&value, &res, order); + __atomic_exchange(T.sizeof, cast(shared)dest, cast(void*)&value, &res, smodel); return res; } else @@ -1048,21 +1086,42 @@ else version (GNU) static if (GNU_Have_Atomics || GNU_Have_LibAtomic) { + static if (fail == MemoryOrder.rel || fail == MemoryOrder.acq_rel) + { + // MemoryOrder.rel and MemoryOrder.acq_rel are not valid failure models. + enum smodel = (succ != MemoryOrder.seq && PreferAcquireRelease) + ? MemoryOrder.acq_rel : MemoryOrder.seq; + enum fmodel = (succ != MemoryOrder.seq && PreferAcquireRelease) + ? MemoryOrder.raw : MemoryOrder.seq; + } + else static if (fail > succ) + { + // Failure memory model cannot be stronger than success. + enum smodel = (fail != MemoryOrder.seq && PreferAcquireRelease) + ? MemoryOrder.acq_rel : MemoryOrder.seq; + enum fmodel = fail; + } + else + { + enum smodel = succ; + enum fmodel = fail; + } + static if (T.sizeof == byte.sizeof) res = __atomic_compare_exchange_1(cast(shared)dest, compare, *cast(ubyte*)&value, - weak, succ, fail); + weak, smodel, fmodel); else static if (T.sizeof == short.sizeof) res = __atomic_compare_exchange_2(cast(shared)dest, compare, *cast(ushort*)&value, - weak, succ, fail); + weak, smodel, fmodel); else static if (T.sizeof == int.sizeof) res = __atomic_compare_exchange_4(cast(shared)dest, compare, *cast(uint*)&value, - weak, succ, fail); + weak, smodel, fmodel); else static if (T.sizeof == long.sizeof && GNU_Have_64Bit_Atomics) res = __atomic_compare_exchange_8(cast(shared)dest, compare, *cast(ulong*)&value, - weak, succ, fail); + weak, smodel, fmodel); else static if (GNU_Have_LibAtomic) res = __atomic_compare_exchange(T.sizeof, cast(shared)dest, compare, cast(void*)&value, - succ, fail); + smodel, fmodel); else static assert(0, "Invalid template type specified."); } @@ -1108,6 +1167,11 @@ else version (GNU) } } + void atomicSignalFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted + { + __atomic_signal_fence(order); + } + void pause() pure nothrow @nogc @trusted { version (X86) diff --git a/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d b/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d index 018b563fd1b..8bec7f71503 100644 --- a/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d +++ b/runtime/druntime/src/core/internal/gc/impl/conservative/gc.d @@ -3340,7 +3340,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)); @@ -3442,7 +3442,7 @@ Lmark: stopGC = true; while (atomicLoad(stoppedThreads) < startedThreads && !allThreadsDead) { - evStart.set(); + evStart.setIfInitialized(); evDone.wait(dur!"msecs"(1)); } @@ -3471,7 +3471,7 @@ Lmark: { evStart.wait(); pullFromScanStack(); - evDone.set(); + evDone.setIfInitialized(); } stoppedThreads.atomicOp!"+="(1); } @@ -4993,8 +4993,8 @@ version (D_LP64) unittest // only run if the system has enough physical memory size_t sz = 2L^^32; //import core.stdc.stdio; - //printf("availphys = %lld", os_physical_mem()); - if (os_physical_mem() > sz) + //printf("availphys = %lld", os_physical_mem(true)); + if (os_physical_mem(true) > sz) { import core.memory; GC.collect(); diff --git a/runtime/druntime/src/core/internal/gc/os.d b/runtime/druntime/src/core/internal/gc/os.d index 38b60cbbcc4..0db1753575b 100644 --- a/runtime/druntime/src/core/internal/gc/os.d +++ b/runtime/druntime/src/core/internal/gc/os.d @@ -254,23 +254,26 @@ bool isLowOnMem(size_t mapped) nothrow @nogc /** Get the size of available physical memory + Params: + avail = if supported on the current platform, return the currently unused memory + rather than the installed physical memory Returns: size of installed physical RAM */ version (Windows) { - ulong os_physical_mem() nothrow @nogc + ulong os_physical_mem(bool avail) nothrow @nogc { import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS; MEMORYSTATUS stat; GlobalMemoryStatus(&stat); - return stat.dwTotalPhys; // limited to 4GB for Win32 + return avail ? stat.dwAvailPhys : stat.dwTotalPhys; // limited to 4GB for Win32 } } else version (Darwin) { extern (C) int sysctl(const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen) @nogc nothrow; - ulong os_physical_mem() nothrow @nogc + ulong os_physical_mem(bool avail) nothrow @nogc { enum { @@ -287,11 +290,15 @@ else version (Darwin) } else version (Posix) { - ulong os_physical_mem() nothrow @nogc + ulong os_physical_mem(bool avail) nothrow @nogc { - import core.sys.posix.unistd : sysconf, _SC_PAGESIZE, _SC_PHYS_PAGES; + import core.sys.posix.unistd; const pageSize = sysconf(_SC_PAGESIZE); - const pages = sysconf(_SC_PHYS_PAGES); + static if (__traits(compiles, _SC_AVPHYS_PAGES)) // not available on all platforms + const sc = avail ? _SC_AVPHYS_PAGES : _SC_PHYS_PAGES; + else + const sc = _SC_PHYS_PAGES; + const pages = sysconf(sc); return pageSize * pages; } } diff --git a/runtime/druntime/src/core/internal/newaa.d b/runtime/druntime/src/core/internal/newaa.d index 654791a5dec..2fd93651a22 100644 --- a/runtime/druntime/src/core/internal/newaa.d +++ b/runtime/druntime/src/core/internal/newaa.d @@ -154,13 +154,14 @@ AAShell makeAA(K, V)(V[K] src) @trusted K.sizeof, V.sizeof, E.value.offsetof, flags, hashFn)); } -version(unittest): -struct Foo { - ubyte x; - double d; -} -int[Foo] utaa = [Foo(1, 2.0) : 5]; -unittest { +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)); diff --git a/runtime/druntime/src/core/math.d b/runtime/druntime/src/core/math.d index 8ec16576f6d..947bcdd3dce 100644 --- a/runtime/druntime/src/core/math.d +++ b/runtime/druntime/src/core/math.d @@ -37,15 +37,6 @@ public: nothrow: @safe: -/***************************************** - * Returns x rounded to a long value using the FE_TONEAREST rounding mode. - * If the integer value of x is - * greater than long.max, the result is - * indeterminate. - */ -deprecated("rndtonl is to be removed by 2.100. Please use round instead") -extern (C) real rndtonl(real x); - pure: /*********************************** * Returns cosine of x. x is in radians. diff --git a/runtime/druntime/src/core/stdc/fenv.d b/runtime/druntime/src/core/stdc/fenv.d index 288f9c25dc6..0051ecdb7c9 100644 --- a/runtime/druntime/src/core/stdc/fenv.d +++ b/runtime/druntime/src/core/stdc/fenv.d @@ -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 diff --git a/runtime/druntime/src/core/stdc/stdarg.d b/runtime/druntime/src/core/stdc/stdarg.d index 5b79813ae1b..0ba1ebe34e3 100644 --- a/runtime/druntime/src/core/stdc/stdarg.d +++ b/runtime/druntime/src/core/stdc/stdarg.d @@ -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; diff --git a/runtime/druntime/src/core/stdc/stdatomic.d b/runtime/druntime/src/core/stdc/stdatomic.d new file mode 100644 index 00000000000..ae17e040da7 --- /dev/null +++ b/runtime/druntime/src/core/stdc/stdatomic.d @@ -0,0 +1,1124 @@ +/** + * A D implementation of the C stdatomic.h header. + * + * $(NOTE If it compiles it should produce similar assembly to the system C toolchain + * and should not introduce when optimizing unnecessary behaviors, + * if you do not care about this guarantee use the _impl suffix.) + * + * $(NOTE The D shared type qualifier is the closest to the _Atomic type qualifier from C. It may be changed from shared in the future.) + * + * Copyright: Copyright Richard (Rikki) Andrew Cattermole 2023. + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Authors: Richard (Rikki) Andrew cattermole + * Source: $(DRUNTIMESRC core/stdc/stdatomic.d) + */ +module core.stdc.stdatomic; +import core.atomic : MemoryOrder; +import core.internal.atomic; +import core.stdc.config; +import core.stdc.stdint; + +@safe nothrow @nogc: + +/// +enum memory_order +{ + /// No ordering provided + memory_order_relaxed = MemoryOrder.raw, + /// As per cppreference.com circa 2015 no compiler supports consume memory order and in practice it devolves to acquire. + memory_order_consume = MemoryOrder.acq, + /// Prevent reordering before operation + memory_order_acquire = MemoryOrder.acq, + /// Prevent reordering after operation + memory_order_release = MemoryOrder.rel, + /// Prevent reordering before and after operation + memory_order_acq_rel = MemoryOrder.acq_rel, + /// Prevent reordering before for read operations and after for writes. + memory_order_seq_cst = MemoryOrder.seq +} + +/// +enum +{ + /// + __STDC_VERSION_STDATOMIC_H__ = 202311, + + /// + ATOMIC_BOOL_LOCK_FREE = IsAtomicLockFree!bool ? 2 : 0, + /// + ATOMIC_CHAR_LOCK_FREE = IsAtomicLockFree!char ? 2 : 0, + /// + ATOMIC_CHAR16_T_LOCK_FREE = IsAtomicLockFree!wchar ? 2 : 0, + /// + ATOMIC_CHAR32_T_LOCK_FREE = IsAtomicLockFree!dchar ? 2 : 0, + /// + ATOMIC_WCHAR_T_LOCK_FREE = ATOMIC_CHAR16_T_LOCK_FREE, + /// + ATOMIC_SHORT_LOCK_FREE = IsAtomicLockFree!short ? 2 : 0, + /// + ATOMIC_INT_LOCK_FREE = IsAtomicLockFree!int ? 2 : 0, + /// + ATOMIC_LONG_LOCK_FREE = IsAtomicLockFree!c_long ? 2 : 0, + /// + ATOMIC_LLONG_LOCK_FREE = IsAtomicLockFree!ulong ? 2 : 0, + /// + ATOMIC_POINTER_LOCK_FREE = IsAtomicLockFree!(void*) ? 2 : 0, + /// + ATOMIC_CHAR8_T_LOCK_FREE = ATOMIC_CHAR_LOCK_FREE, +} + +version (DigitalMars) +{ + alias atomic_signal_fence = atomic_signal_fence_impl; /// + + // these all use inline assembly, so will unlikely produce the codegen a user will expect + version(none) + { + alias atomic_flag_clear = atomic_flag_clear_impl; /// + alias atomic_flag_clear_explicit = atomic_flag_clear_explicit_impl; /// + alias atomic_flag_test_and_set = atomic_flag_test_and_set_impl; /// + alias atomic_flag_test_and_set_explicit = atomic_flag_test_and_set_explicit_impl; /// + alias atomic_thread_fence = atomic_thread_fence_impl; /// + alias atomic_store = atomic_store_impl; /// + alias atomic_store_explicit = atomic_store_explicit_impl; /// + alias atomic_load = atomic_load_impl; /// + alias atomic_load_explicit = atomic_load_explicit_impl; /// + alias atomic_exchange = atomic_exchange_impl; /// + alias atomic_exchange_explicit = atomic_exchange_explicit_impl; /// + alias atomic_compare_exchange_strong = atomic_compare_exchange_strong_impl; /// + alias atomic_compare_exchange_weak = atomic_compare_exchange_weak_impl; /// + alias atomic_compare_exchange_strong_explicit = atomic_compare_exchange_strong_explicit_impl; /// + alias atomic_compare_exchange_weak_explicit = atomic_compare_exchange_weak_explicit_impl; /// + alias atomic_fetch_add = atomic_fetch_add_impl; /// + alias atomic_fetch_add_explicit = atomic_fetch_add_explicit_impl; /// + alias atomic_fetch_sub = atomic_fetch_sub_impl; /// + alias atomic_fetch_sub_explicit = atomic_fetch_sub_explicit_impl; /// + alias atomic_fetch_or = atomic_fetch_or_impl; /// + alias atomic_fetch_or_explicit = atomic_fetch_or_explicit_impl; /// + alias atomic_fetch_xor = atomic_fetch_xor_impl; /// + alias atomic_fetch_xor_explicit = atomic_fetch_xor_explicit_impl; /// + alias atomic_fetch_and = atomic_fetch_and_impl; /// + alias atomic_fetch_and_explicit = atomic_fetch_and_explicit_impl; /// + } +} +else version(GNU) +{ + alias atomic_flag_clear = atomic_flag_clear_impl; /// + alias atomic_flag_clear_explicit = atomic_flag_clear_explicit_impl; /// + alias atomic_flag_test_and_set = atomic_flag_test_and_set_impl; /// + alias atomic_flag_test_and_set_explicit = atomic_flag_test_and_set_explicit_impl; /// + alias atomic_signal_fence = atomic_signal_fence_impl; /// + alias atomic_thread_fence = atomic_thread_fence_impl; /// + alias atomic_store = atomic_store_impl; /// + alias atomic_store_explicit = atomic_store_explicit_impl; /// + alias atomic_load = atomic_load_impl; /// + alias atomic_load_explicit = atomic_load_explicit_impl; /// + alias atomic_exchange = atomic_exchange_impl; /// + alias atomic_exchange_explicit = atomic_exchange_explicit_impl; /// + alias atomic_compare_exchange_strong = atomic_compare_exchange_strong_impl; /// + alias atomic_compare_exchange_weak = atomic_compare_exchange_weak_impl; /// + alias atomic_compare_exchange_strong_explicit = atomic_compare_exchange_strong_explicit_impl; /// + alias atomic_compare_exchange_weak_explicit = atomic_compare_exchange_weak_explicit_impl; /// + alias atomic_fetch_add = atomic_fetch_add_impl; /// + alias atomic_fetch_add_explicit = atomic_fetch_add_explicit_impl; /// + alias atomic_fetch_sub = atomic_fetch_sub_impl; /// + alias atomic_fetch_sub_explicit = atomic_fetch_sub_explicit_impl; /// + alias atomic_fetch_or = atomic_fetch_or_impl; /// + alias atomic_fetch_or_explicit = atomic_fetch_or_explicit_impl; /// + alias atomic_fetch_xor = atomic_fetch_xor_impl; /// + alias atomic_fetch_xor_explicit = atomic_fetch_xor_explicit_impl; /// + alias atomic_fetch_and = atomic_fetch_and_impl; /// + alias atomic_fetch_and_explicit = atomic_fetch_and_explicit_impl; /// +} + +/// +pragma(inline, true) +bool atomic_is_lock_free(A)(const shared(A)* obj) +{ + return IsAtomicLockFree!A; +} + +/// Guaranteed to be a atomic boolean type +struct atomic_flag +{ + private bool b; +} + +/// +enum ATOMIC_FLAG_INIT = atomic_flag.init; + +/// +pragma(inline, true) +void atomic_flag_clear_impl()(atomic_flag* obj) +{ + assert(obj !is null); + + atomicStore(&obj.b, false); +} + +/// +pragma(inline, true) +void atomic_flag_clear_explicit_impl()(atomic_flag* obj, memory_order order) +{ + assert(obj !is null); + + final switch (order) + { + case memory_order.memory_order_relaxed: + atomicStore!(memory_order.memory_order_relaxed)(&obj.b, false); + break; + + case memory_order.memory_order_acquire: + // Ideally this would error at compile time but alas it is not an intrinsic. + // Note: this is not a valid memory order for this operation. + atomicStore!(memory_order.memory_order_seq_cst)(&obj.b, false); + break; + + case memory_order.memory_order_release: + atomicStore!(memory_order.memory_order_release)(&obj.b, false); + break; + + case memory_order.memory_order_acq_rel: + atomicStore!(memory_order.memory_order_acq_rel)(&obj.b, false); + break; + + case memory_order.memory_order_seq_cst: + atomicStore(&obj.b, false); + break; + } +} + +/// +pragma(inline, true) +bool atomic_flag_test_and_set_impl()(atomic_flag* obj) +{ + assert(obj !is null); + return atomicExchange(&obj.b, true); +} + +/// +unittest +{ + atomic_flag flag; + assert(!atomic_flag_test_and_set_impl(&flag)); + atomic_flag_clear_impl(&flag); +} + +/// +pragma(inline, true) +bool atomic_flag_test_and_set_explicit_impl()(atomic_flag* obj, memory_order order) +{ + assert(obj !is null); + + final switch (order) + { + case memory_order.memory_order_relaxed: + return atomicExchange!(memory_order.memory_order_relaxed)(&obj.b, true); + + case memory_order.memory_order_acquire: + return atomicExchange!(memory_order.memory_order_acquire)(&obj.b, true); + + case memory_order.memory_order_release: + return atomicExchange!(memory_order.memory_order_release)(&obj.b, true); + + case memory_order.memory_order_acq_rel: + return atomicExchange!(memory_order.memory_order_acq_rel)(&obj.b, true); + + case memory_order.memory_order_seq_cst: + return atomicExchange(&obj.b, true); + } +} + +/// +unittest +{ + atomic_flag flag; + assert(!atomic_flag_test_and_set_explicit_impl(&flag, memory_order.memory_order_seq_cst)); + atomic_flag_clear_explicit_impl(&flag, memory_order.memory_order_seq_cst); +} + +/** + * Initializes an atomic variable, the destination should not have any expression associated with it prior to this call. + * + * We use an out parameter instead of a pointer for destination in an attempt to communicate to the compiler that it initializers. + */ +pragma(inline, true) +void atomic_init(A, C)(out shared(A) obj, C desired) @trusted +{ + obj = cast(shared) desired; +} + +/// +unittest +{ + shared int val; + atomic_init(val, 2); +} + +/// No-op function, doesn't apply to D +pragma(inline, true) +A kill_dependency(A)(A y) @trusted +{ + return y; +} + +/// Don't allow reordering, does not emit any instructions. +pragma(inline, true) +void atomic_signal_fence_impl()(memory_order order) +{ + final switch (order) + { + case memory_order.memory_order_relaxed: + atomicSignalFence!(memory_order.memory_order_relaxed); + break; + + case memory_order.memory_order_acquire: + atomicSignalFence!(memory_order.memory_order_acquire); + break; + + case memory_order.memory_order_release: + atomicSignalFence!(memory_order.memory_order_release); + break; + + case memory_order.memory_order_acq_rel: + atomicSignalFence!(memory_order.memory_order_acq_rel); + break; + + case memory_order.memory_order_seq_cst: + atomicSignalFence!(memory_order.memory_order_seq_cst); + break; + } +} + +/// +unittest +{ + atomic_signal_fence_impl(memory_order.memory_order_seq_cst); +} + +/// Don't allow reordering, and emit a fence instruction. +pragma(inline, true) +void atomic_thread_fence_impl()(memory_order order) +{ + final switch (order) + { + case memory_order.memory_order_relaxed: + atomicFence!(memory_order.memory_order_relaxed); + break; + + case memory_order.memory_order_acquire: + atomicFence!(memory_order.memory_order_acquire); + break; + + case memory_order.memory_order_release: + atomicFence!(memory_order.memory_order_release); + break; + + case memory_order.memory_order_acq_rel: + atomicFence!(memory_order.memory_order_acq_rel); + break; + + case memory_order.memory_order_seq_cst: + atomicFence!(memory_order.memory_order_seq_cst); + break; + } +} + +/// +unittest +{ + atomic_thread_fence_impl(memory_order.memory_order_seq_cst); +} + +/// +alias atomic_bool = shared(bool); +/// +alias atomic_char = shared(char); +/// +alias atomic_schar = shared(byte); +/// +alias atomic_uchar = shared(ubyte); +/// +alias atomic_short = shared(short); +/// +alias atomic_ushort = shared(ushort); +/// +alias atomic_int = shared(int); +/// +alias atomic_uint = shared(uint); +/// +alias atomic_long = shared(c_long); +/// +alias atomic_ulong = shared(c_ulong); +/// +alias atomic_llong = shared(long); +/// +alias atomic_ullong = shared(ulong); +/// +alias atomic_char8_t = shared(char); +/// +alias atomic_char16_t = shared(wchar); +/// +alias atomic_char32_t = shared(dchar); +/// +alias atomic_wchar_t = shared(wchar); + +/// +alias atomic_int_least8_t = shared(int_least8_t); +/// +alias atomic_uint_least8_t = shared(uint_least8_t); +/// +alias atomic_int_least16_t = shared(int_least16_t); +/// +alias atomic_uint_least16_t = shared(uint_least16_t); +/// +alias atomic_int_least32_t = shared(int_least32_t); +/// +alias atomic_uint_least32_t = shared(uint_least32_t); +/// +alias atomic_int_least64_t = shared(int_least64_t); +/// +alias atomic_uint_least64_t = shared(uint_least64_t); +/// +alias atomic_int_fast8_t = shared(int_fast8_t); +/// +alias atomic_uint_fast8_t = shared(uint_fast8_t); +/// +alias atomic_int_fast16_t = shared(int_fast16_t); +/// +alias atomic_uint_fast16_t = shared(uint_fast16_t); +/// +alias atomic_int_fast32_t = shared(int_fast32_t); +/// +alias atomic_uint_fast32_t = shared(uint_fast32_t); +/// +alias atomic_int_fast64_t = shared(int_fast64_t); +/// +alias atomic_uint_fast64_t = shared(uint_fast64_t); +/// +alias atomic_intptr_t = shared(intptr_t); +/// +alias atomic_uintptr_t = shared(uintptr_t); +/// +alias atomic_size_t = shared(size_t); +/// +alias atomic_ptrdiff_t = shared(ptrdiff_t); +/// +alias atomic_intmax_t = shared(intmax_t); +/// +alias atomic_uintmax_t = shared(uintmax_t); + +/// +pragma(inline, true) +void atomic_store_impl(A, C)(shared(A)* obj, C desired) @trusted +{ + assert(obj !is null); + atomicStore(obj, cast(A)desired); +} + +/// +unittest +{ + shared(int) obj; + atomic_store_impl(&obj, 3); +} + +/// +pragma(inline, true) +void atomic_store_explicit_impl(A, C)(shared(A)* obj, C desired, memory_order order) @trusted +{ + assert(obj !is null); + + final switch (order) + { + case memory_order.memory_order_relaxed: + atomicStore!(memory_order.memory_order_relaxed)(obj, cast(A)desired); + break; + + case memory_order.memory_order_acquire: + // Ideally this would error at compile time but alas it is not an intrinsic. + // Note: this is not a valid memory order for this operation. + atomicStore!(memory_order.memory_order_release)(obj, cast(A)desired); + break; + + case memory_order.memory_order_release: + atomicStore!(memory_order.memory_order_release)(obj, cast(A)desired); + break; + + case memory_order.memory_order_acq_rel: + atomicStore!(memory_order.memory_order_acq_rel)(obj, cast(A)desired); + break; + + case memory_order.memory_order_seq_cst: + atomicStore!(memory_order.memory_order_seq_cst)(obj, cast(A)desired); + break; + } +} + +/// +unittest +{ + shared(int) obj; + atomic_store_explicit_impl(&obj, 3, memory_order.memory_order_seq_cst); +} + +/// +pragma(inline, true) +A atomic_load_impl(A)(const shared(A)* obj) @trusted +{ + assert(obj !is null); + return atomicLoad(cast(shared(A)*)obj); +} + +/// +unittest +{ + shared(int) obj = 3; + assert(atomic_load_impl(&obj) == 3); +} + +/// +pragma(inline, true) +A atomic_load_explicit_impl(A)(const shared(A)* obj, memory_order order) @trusted +{ + assert(obj !is null); + + final switch (order) + { + case memory_order.memory_order_relaxed: + return atomicLoad!(memory_order.memory_order_relaxed)(obj); + + case memory_order.memory_order_acquire: + return atomicLoad!(memory_order.memory_order_acquire)(obj); + + case memory_order.memory_order_release: + // Ideally this would error at compile time but alas it is not an intrinsic. + // Note: this is not a valid memory order for this operation. + return atomicLoad!(memory_order.memory_order_acquire)(obj); + + case memory_order.memory_order_acq_rel: + return atomicLoad!(memory_order.memory_order_acq_rel)(obj); + + case memory_order.memory_order_seq_cst: + return atomicLoad!(memory_order.memory_order_seq_cst)(obj); + } +} + +/// +unittest +{ + shared(int) obj = 3; + assert(atomic_load_explicit_impl(&obj, memory_order.memory_order_seq_cst) == 3); +} + +/// +pragma(inline, true) +A atomic_exchange_impl(A, C)(shared(A)* obj, C desired) @trusted +{ + assert(obj !is null); + return atomicExchange(cast(shared(A)*)obj, cast(A)desired); +} + +/// +unittest +{ + shared(int) obj = 3; + assert(atomic_exchange_impl(&obj, 2) == 3); +} + +/// +pragma(inline, true) +A atomic_exchange_explicit_impl(A, C)(shared(A)* obj, C desired, memory_order order) @trusted +{ + assert(obj !is null); + + final switch (order) + { + case memory_order.memory_order_relaxed: + return atomicExchange!(memory_order.memory_order_relaxed)(obj, cast(A)desired); + + case memory_order.memory_order_acquire: + return atomicExchange!(memory_order.memory_order_acquire)(obj, cast(A)desired); + + case memory_order.memory_order_release: + return atomicExchange!(memory_order.memory_order_release)(obj, cast(A)desired); + + case memory_order.memory_order_acq_rel: + return atomicExchange!(memory_order.memory_order_acq_rel)(obj, cast(A)desired); + + case memory_order.memory_order_seq_cst: + return atomicExchange!(memory_order.memory_order_seq_cst)(obj, cast(A)desired); + } +} + +/// +unittest +{ + shared(int) obj = 3; + assert(atomic_exchange_explicit_impl(&obj, 2, memory_order.memory_order_seq_cst) == 3); +} + +/// +pragma(inline, true) +bool atomic_compare_exchange_strong_impl(A, C)(shared(A)* obj, A* expected, C desired) @trusted +{ + return atomicCompareExchangeStrong(cast(A*)obj, expected, cast(A)desired); +} + +/// +unittest +{ + shared(int) obj = 3; + int expected = 3; + assert(atomic_compare_exchange_strong_impl(&obj, &expected, 2)); +} + +/// +pragma(inline, true) +bool atomic_compare_exchange_weak_impl(A, C)(shared(A)* obj, A* expected, C desired) @trusted +{ + return atomicCompareExchangeStrong(cast(A*)obj, expected, cast(A)desired); +} + +/// +unittest +{ + shared(int) obj = 3; + int expected = 3; + static assert(__traits(compiles, {atomic_compare_exchange_weak_impl(&obj, &expected, 2);})); +} + +/// +pragma(inline, true) +bool atomic_compare_exchange_strong_explicit_impl(A, C)(shared(A)* obj, A* expected, C desired, memory_order succ, memory_order fail) @trusted +{ + assert(obj !is null); + // We use these giant switch inside switch statements + // because as of 2023 they are capable of being for the most part inlined by gdc & ldc when using literal arguments for memory_order. + + final switch(succ) + { + case memory_order.memory_order_relaxed: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + case memory_order.memory_order_acquire: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + case memory_order.memory_order_release: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + case memory_order.memory_order_acq_rel: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + case memory_order.memory_order_seq_cst: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + } +} + +/// +unittest +{ + shared(int) obj = 3; + int expected = 3; + assert(atomic_compare_exchange_strong_explicit_impl(&obj, &expected, 2, memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)); +} + +/// +pragma(inline, true) +bool atomic_compare_exchange_weak_explicit_impl(A, C)(shared(A)* obj, A* expected, C desired, memory_order succ, memory_order fail) @trusted +{ + assert(obj !is null); + // We use these giant switch inside switch statements + // because as of 2023 they are capable of being for the most part inlined by gdc & ldc when using literal arguments for memory_order. + + final switch(succ) + { + case memory_order.memory_order_relaxed: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + } + case memory_order.memory_order_acquire: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + case memory_order.memory_order_release: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + case memory_order.memory_order_acq_rel: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + case memory_order.memory_order_seq_cst: + final switch(fail) + { + case memory_order.memory_order_relaxed: + return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acquire: + return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_release: + return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_acq_rel: + return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired); + case memory_order.memory_order_seq_cst: + return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired); + } + } +} + +/// +unittest +{ + shared(int) obj = 3; + int expected = 3; + atomic_compare_exchange_weak_explicit_impl(&obj, &expected, 2, memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst); +} + +/// +pragma(inline, true) +A atomic_fetch_add_impl(A, M)(shared(A)* obj, M arg) @trusted +{ + assert(obj !is null); + return atomicFetchAdd(cast(A*)obj, arg); +} + +/// +unittest +{ + shared(int) val; + atomic_fetch_add_impl(&val, 3); + assert(atomic_load_impl(&val) == 3); +} + +pragma(inline, true) +A atomic_fetch_sub_impl(A, M)(shared(A)* obj, M arg) @trusted +{ + assert(obj !is null); + return atomicFetchSub(cast(A*)obj, arg); +} + +/// +unittest +{ + shared(int) val = 3; + atomic_fetch_sub_impl(&val, 3); + assert(atomic_load_impl(&val) == 0); +} + +/// +pragma(inline, true) +A atomic_fetch_add_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted +{ + assert(obj !is null); + + final switch(order) + { + case memory_order.memory_order_relaxed: + return atomicFetchAdd!(memory_order.memory_order_relaxed)(cast(A*)obj, arg); + case memory_order.memory_order_acquire: + return atomicFetchAdd!(memory_order.memory_order_acquire)(cast(A*)obj, arg); + case memory_order.memory_order_release: + return atomicFetchAdd!(memory_order.memory_order_release)(cast(A*)obj, arg); + case memory_order.memory_order_acq_rel: + return atomicFetchAdd!(memory_order.memory_order_acq_rel)(cast(A*)obj, arg); + case memory_order.memory_order_seq_cst: + return atomicFetchAdd!(memory_order.memory_order_seq_cst)(cast(A*)obj, arg); + } +} + +/// +unittest +{ + shared(int) val; + atomic_fetch_add_explicit_impl(&val, 3, memory_order.memory_order_seq_cst); + assert(atomic_load_impl(&val) == 3); +} + +/// +pragma(inline, true) +A atomic_fetch_sub_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted +{ + assert(obj !is null); + + final switch(order) + { + case memory_order.memory_order_relaxed: + return atomicFetchSub!(memory_order.memory_order_relaxed)(cast(A*)obj, arg); + case memory_order.memory_order_acquire: + return atomicFetchSub!(memory_order.memory_order_acquire)(cast(A*)obj, arg); + case memory_order.memory_order_release: + return atomicFetchSub!(memory_order.memory_order_release)(cast(A*)obj, arg); + case memory_order.memory_order_acq_rel: + return atomicFetchSub!(memory_order.memory_order_acq_rel)(cast(A*)obj, arg); + case memory_order.memory_order_seq_cst: + return atomicFetchSub!(memory_order.memory_order_seq_cst)(cast(A*)obj, arg); + } +} + +/// +unittest +{ + shared(int) val = 3; + atomic_fetch_sub_explicit_impl(&val, 3, memory_order.memory_order_seq_cst); + assert(atomic_load_impl(&val) == 0); +} + +/// +pragma(inline, true) +A atomic_fetch_or_impl(A, M)(shared(A)* obj, M arg) @trusted +{ + assert(obj !is null); + + // copied from atomicOp + + A set, get = atomicLoad(cast(A*)obj); + + do + { + set = get | arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set)); + + return get; +} + +/// +unittest +{ + shared(int) val = 5; + atomic_fetch_or_impl(&val, 3); + assert(atomic_load_impl(&val) == 7); +} + +/// +pragma(inline, true) +A atomic_fetch_or_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted +{ + assert(obj !is null); + + A set, get; + + final switch(order) + { + case memory_order.memory_order_relaxed: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get | arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_acquire: + get = atomicLoad!(memory_order.memory_order_acquire)(cast(A*)obj); + do + { + set = get | arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_release: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get | arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_acq_rel: + get = atomicLoad!(memory_order.memory_order_acq_rel)(cast(A*)obj); + do + { + set = get | arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_seq_cst: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get | arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set)); + break; + } + + return get; +} + +/// +unittest +{ + shared(int) val = 5; + atomic_fetch_or_explicit_impl(&val, 3, memory_order.memory_order_seq_cst); + assert(atomic_load_impl(&val) == 7); +} + +/// +pragma(inline, true) +A atomic_fetch_xor_impl(A, M)(shared(A)* obj, M arg) @trusted +{ + assert(obj !is null); + + // copied from atomicOp + + A set, get = atomicLoad(cast(A*)obj); + + do + { + set = get ^ arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set)); + + return get; +} + +/// +unittest +{ + shared(int) val = 5; + atomic_fetch_xor_impl(&val, 3); + assert(atomic_load_impl(&val) == 6); +} + +/// +pragma(inline, true) +A atomic_fetch_xor_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted +{ + assert(obj !is null); + + A set, get; + + final switch(order) + { + case memory_order.memory_order_relaxed: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get ^ arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_acquire: + get = atomicLoad!(memory_order.memory_order_acquire)(cast(A*)obj); + do + { + set = get ^ arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_release: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get ^ arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_acq_rel: + get = atomicLoad!(memory_order.memory_order_acq_rel)(cast(A*)obj); + do + { + set = get ^ arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_seq_cst: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get ^ arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set)); + break; + } + + return get; +} + +/// +unittest +{ + shared(int) val = 5; + atomic_fetch_xor_explicit_impl(&val, 3, memory_order.memory_order_seq_cst); + assert(atomic_load_impl(&val) == 6); +} + +/// +pragma(inline, true) +A atomic_fetch_and_impl(A, M)(shared(A)* obj, M arg) @trusted +{ + assert(obj !is null); + + // copied from atomicOp + + A set, get = atomicLoad(cast(A*)obj); + + do + { + set = get & arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set)); + + return get; +} + +/// +unittest +{ + shared(int) val = 5; + atomic_fetch_and_impl(&val, 3); + assert(atomic_load_impl(&val) == 1); +} + +/// +pragma(inline, true) +A atomic_fetch_and_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted +{ + assert(obj !is null); + + A set, get; + + final switch(order) + { + case memory_order.memory_order_relaxed: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get & arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_acquire: + get = atomicLoad!(memory_order.memory_order_acquire)(cast(A*)obj); + do + { + set = get & arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_release: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get & arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_acq_rel: + get = atomicLoad!(memory_order.memory_order_acq_rel)(cast(A*)obj); + do + { + set = get & arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, &get, cast(A)set)); + break; + + case memory_order.memory_order_seq_cst: + get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj); + do + { + set = get & arg; + } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set)); + break; + } + + return get; +} + +/// +unittest +{ + shared(int) val = 5; + atomic_fetch_and_explicit_impl(&val, 3, memory_order.memory_order_seq_cst); + assert(atomic_load_impl(&val) == 1); +} diff --git a/runtime/druntime/src/core/stdcpp/new_.d b/runtime/druntime/src/core/stdcpp/new_.d index b21bfc7673f..67dfdb71c05 100644 --- a/runtime/druntime/src/core/stdcpp/new_.d +++ b/runtime/druntime/src/core/stdcpp/new_.d @@ -65,6 +65,8 @@ T cpp_new(T, Args...)(auto ref Args args) if (is(T == class)) /// void cpp_delete(T)(T* ptr) if (!is(T == class)) { + if (ptr is null) + return; destroy!false(*ptr); __cpp_delete(ptr); } @@ -72,6 +74,8 @@ void cpp_delete(T)(T* ptr) if (!is(T == class)) /// void cpp_delete(T)(T instance) if (is(T == class)) { + if (instance is null) + return; destroy!false(instance); __cpp_delete(cast(void*) instance); } diff --git a/runtime/druntime/src/core/sync/event.d b/runtime/druntime/src/core/sync/event.d index 37951061d93..048607f6ed2 100644 --- a/runtime/druntime/src/core/sync/event.d +++ b/runtime/druntime/src/core/sync/event.d @@ -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); diff --git a/runtime/druntime/src/core/sys/elf/package.d b/runtime/druntime/src/core/sys/elf/package.d index b120ee58f69..60e05d97036 100644 --- a/runtime/druntime/src/core/sys/elf/package.d +++ b/runtime/druntime/src/core/sys/elf/package.d @@ -339,6 +339,8 @@ enum EM_CSKY = 252; enum EM_NUM = 253; +enum EM_LOONGARCH = 258; + enum EM_ALPHA = 0x9026; enum EV_NONE = 0; diff --git a/runtime/druntime/src/core/sys/linux/sys/auxv.d b/runtime/druntime/src/core/sys/linux/sys/auxv.d index 5f098e98e02..1099fae497f 100644 --- a/runtime/druntime/src/core/sys/linux/sys/auxv.d +++ b/runtime/druntime/src/core/sys/linux/sys/auxv.d @@ -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; +} diff --git a/runtime/druntime/src/core/sys/linux/sys/mman.d b/runtime/druntime/src/core/sys/linux/sys/mman.d index 7ed78ef6436..e4765af1490 100644 --- a/runtime/druntime/src/core/sys/linux/sys/mman.d +++ b/runtime/druntime/src/core/sys/linux/sys/mman.d @@ -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 diff --git a/runtime/druntime/src/core/sys/posix/net/if_.d b/runtime/druntime/src/core/sys/posix/net/if_.d index 3713673e4bc..7fadcd884c4 100644 --- a/runtime/druntime/src/core/sys/posix/net/if_.d +++ b/runtime/druntime/src/core/sys/posix/net/if_.d @@ -143,6 +143,21 @@ else version (CRuntime_Bionic) uint if_nametoindex(const scope char*); char* if_indextoname(uint, char*); } +else version (CRuntime_Musl) +{ + struct if_nameindex_t + { + uint if_index; + char* if_name; + } + + enum IF_NAMESIZE = 16; + + uint if_nametoindex(const scope char*); + char* if_indextoname(uint, char*); + if_nameindex_t* if_nameindex(); + void if_freenameindex(if_nameindex_t*); +} else version (CRuntime_UClibc) { struct if_nameindex_t diff --git a/runtime/druntime/src/core/thread/fiber.d b/runtime/druntime/src/core/thread/fiber.d index ff88c6748e8..638b65ed766 100644 --- a/runtime/druntime/src/core/thread/fiber.d +++ b/runtime/druntime/src/core/thread/fiber.d @@ -155,8 +155,12 @@ private } else version (LoongArch64) { - version = AsmLoongArch64_Posix; - version = AsmExternal; + version (Posix) + { + version = AsmLoongArch64_Posix; + version = AsmExternal; + version = AlignFiberStackTo16Byte; + } } version (Posix) @@ -1821,24 +1825,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) { diff --git a/runtime/druntime/src/core/thread/osthread.d b/runtime/druntime/src/core/thread/osthread.d index 575aa584ca1..ce71965fab2 100644 --- a/runtime/druntime/src/core/thread/osthread.d +++ b/runtime/druntime/src/core/thread/osthread.d @@ -2225,6 +2225,13 @@ extern (C) void thread_init() @nogc nothrow static extern(C) void initChildAfterFork() { auto thisThread = Thread.getThis(); + if (!thisThread) + { + // It is possible that runtime was not properly initialized in the current process or thread - + // it may happen after `fork` call when using a dynamically loaded shared library written in D from a multithreaded non-D program. + // In such case getThis will return null. + return; + } thisThread.m_addr = pthread_self(); assert( thisThread.m_addr != thisThread.m_addr.init ); thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr ); diff --git a/runtime/druntime/src/core/vararg.d b/runtime/druntime/src/core/vararg.d index 2c3e9659fb6..e6dd47d06d3 100644 --- a/runtime/druntime/src/core/vararg.d +++ b/runtime/druntime/src/core/vararg.d @@ -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; diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index 02ecd49f523..0ab12184761 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -33,6 +33,7 @@ #define __attribute __attribute__ #define __alignof _Alignof #define __vector_size__ vector_size +#define __typeof typeof /******************** * Clang nullability extension used by macOS headers. @@ -60,6 +61,11 @@ #define __int32 int #define __int64 long long +/* Linux builtin types */ +typedef unsigned short __uint16_t; +typedef unsigned int __uint32_t; +typedef unsigned long long __uint64_t; + /********************* * Obsolete detritus */ @@ -154,9 +160,9 @@ #ifndef __aarch64__ #define _Float32 float -#define _Float32x float +#define _Float32x double #define _Float64 double -#define _Float64x double +#define _Float64x long double #define _Float128 long double #define __float128 long double #endif diff --git a/runtime/druntime/src/object.d b/runtime/druntime/src/object.d index 5c4eaf6d4ac..38c24539cf5 100644 --- a/runtime/druntime/src/object.d +++ b/runtime/druntime/src/object.d @@ -555,6 +555,12 @@ unittest private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow; +/** Makes ownee use owner's mutex. + * This will initialize owner's mutex if it hasn't been set yet. + * Params: + * ownee = object to change + * owner = source object + */ void setSameMutex(shared Object ownee, shared Object owner) { import core.atomic : atomicLoad; @@ -2978,19 +2984,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; @@ -4730,6 +4736,7 @@ version (D_ProfileGC) 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_arrayappendcTX; public import core.internal.array.comparison : __cmp; @@ -4739,6 +4746,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; diff --git a/runtime/druntime/src/rt/aaA.d b/runtime/druntime/src/rt/aaA.d index ba63f0cabb8..0610080c002 100644 --- a/runtime/druntime/src/rt/aaA.d +++ b/runtime/druntime/src/rt/aaA.d @@ -41,7 +41,7 @@ version (LDC) // Don't wrap in a struct to maintain ABI compatibility. alias AA = Impl*; - private bool empty(scope const AA impl) pure nothrow @nogc + private bool empty(scope const AA impl) pure nothrow @nogc @safe { return impl is null || !impl.length; } @@ -54,7 +54,7 @@ else 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; } @@ -104,7 +104,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; @@ -175,7 +175,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 @@ -667,7 +667,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) { diff --git a/runtime/druntime/src/rt/lifetime.d b/runtime/druntime/src/rt/lifetime.d index 513300b9186..ea782a20a56 100644 --- a/runtime/druntime/src/rt/lifetime.d +++ b/runtime/druntime/src/rt/lifetime.d @@ -1081,98 +1081,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). diff --git a/runtime/druntime/src/rt/msvc.d b/runtime/druntime/src/rt/msvc.d index 9b0b0593a54..263e3bd1fb6 100644 --- a/runtime/druntime/src/rt/msvc.d +++ b/runtime/druntime/src/rt/msvc.d @@ -230,6 +230,8 @@ else // !LDC } } // !LDC +// MSVCRT.lib only provides _strdup +mixin declareAlternateName!("strdup", "_strdup"); /** * 32-bit x86 MS VC runtimes lack most single-precision math functions. diff --git a/runtime/druntime/src/rt/sections.d b/runtime/druntime/src/rt/sections.d index c9c89b2d226..7db4842818f 100644 --- a/runtime/druntime/src/rt/sections.d +++ b/runtime/druntime/src/rt/sections.d @@ -90,7 +90,10 @@ static assert(is(typeof(&initTLSRanges) RT == return) && is(typeof(&finiTLSRanges) == void function(RT) nothrow @nogc) && is(typeof(&scanTLSRanges) == void function(RT, scope void delegate(void*, void*) nothrow) nothrow)); -version (Shared) +version (Windows) +{ +} +else version (Shared) { static assert(is(typeof(&pinLoadedLibraries) == void* function() nothrow @nogc)); static assert(is(typeof(&unpinLoadedLibraries) == void function(void*) nothrow @nogc)); diff --git a/runtime/druntime/src/rt/tracegc.d b/runtime/druntime/src/rt/tracegc.d index 6ff9c2b433c..24aa19bc6b0 100644 --- a/runtime/druntime/src/rt/tracegc.d +++ b/runtime/druntime/src/rt/tracegc.d @@ -17,8 +17,6 @@ module rt.tracegc; // version = tracegc; -extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims); -extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims); extern (C) void _d_callfinalizer(void* p); extern (C) void _d_callinterfacefinalizer(void *p); extern (C) void _d_delclass(Object* p); diff --git a/runtime/druntime/test/aa/Makefile b/runtime/druntime/test/aa/Makefile index 8d31593adc2..839237a9292 100644 --- a/runtime/druntime/test/aa/Makefile +++ b/runtime/druntime/test/aa/Makefile @@ -5,12 +5,12 @@ TESTS:=test_aa .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/test_aa.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/allocations/Makefile b/runtime/druntime/test/allocations/Makefile index fb4a6cd3fc9..99936bf1482 100644 --- a/runtime/druntime/test/allocations/Makefile +++ b/runtime/druntime/test/allocations/Makefile @@ -8,20 +8,20 @@ SED:=sed .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/alloc_from_assert.done: $(ROOT)/alloc_from_assert +$(ROOT)/alloc_from_assert.done: $(ROOT)/alloc_from_assert$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/alloc_from_assert $(RUN_ARGS) @touch $@ $(ROOT)/overflow_from_zero.done: STDERR_EXP="Memory allocation failed" $(ROOT)/overflow_from_existing.done: STDERR_EXP="Memory allocation failed" -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(NEGATE) $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) 2>&1 1>/dev/null | head -n 2 | grep -qF $(STDERR_EXP) @touch $@ -$(ROOT)/unittest_assert: DFLAGS+=-unittest -version=CoreUnittest -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/unittest_assert$(DOTEXE): DFLAGS+=-unittest -version=CoreUnittest +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/allocations/win64.mak b/runtime/druntime/test/allocations/win64.mak deleted file mode 100644 index 617fb9ee6a3..00000000000 --- a/runtime/druntime/test/allocations/win64.mak +++ /dev/null @@ -1,12 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 -DRUNTIMELIB=druntime64.lib - -test: alloc_from_assert - -alloc_from_assert: - $(DMD) -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) test\allocations\src\$@.d - $@.exe - del $@.* diff --git a/runtime/druntime/test/betterc/Makefile b/runtime/druntime/test/betterc/Makefile index 53d90c1fa08..2b5b32b2fdb 100644 --- a/runtime/druntime/test/betterc/Makefile +++ b/runtime/druntime/test/betterc/Makefile @@ -3,15 +3,23 @@ include ../common.mak TESTS:=test18828 test19416 test19421 test19561 test20088 test20613 test19924 test22336 test19933 .PHONY: all clean -all: $(addprefix $(ROOT)/,$(addsuffix ,$(TESTS))) $(addprefix $(ROOT)/,test19924.done) +all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/test19924.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Running $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ -$(ROOT)/%: $(SRC)/%.d - $(QUIET)$(DMD) -betterC -of$@ $< +# for the Windows MinGW CI job: +ifneq (,$(findstring -mscrtlib=msvcrt120,$(DFLAGS))) +# DFLAGS=-mscrtlib=msvcrt120 takes precedence over any command line flags, so +# specify vcruntime140.lib explicitly for using mingw with Universal CRT. +$(ROOT)/test19933$(DOTEXE): $(SRC)/test19933.d + $(QUIET)$(DMD) $(MODEL_FLAG) -I../../src -betterC -of$@ $< -Lvcruntime140.lib -Llegacy_stdio_definitions.lib -L/NODEFAULTLIB:msvcrt120.lib +endif + +$(ROOT)/%$(DOTEXE): $(SRC)/%.d + $(QUIET)$(DMD) $(MODEL_FLAG) -I../../src -betterC -of$@ $< clean: rm -rf $(ROOT) diff --git a/runtime/druntime/test/betterc/win64.mak b/runtime/druntime/test/betterc/win64.mak deleted file mode 100644 index eb78f088ff1..00000000000 --- a/runtime/druntime/test/betterc/win64.mak +++ /dev/null @@ -1,50 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 - -TESTS=test18828 test19416 test19421 test19561 test20088 test20613 test19924 test22336 test19933$(MINGW) - -test: $(TESTS) - -test18828: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test19416: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test19421: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test19561: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test20088: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test20613: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test19924: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test22336: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test19933: - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -run test\betterc\src\$@.d - del $@.* - -test19933_mingw: - # DFLAGS=-mscrtlib=msvcrt120 takes precedence over any command line flags, so - # specify vcruntime140.lib explicitly for using mingw with Universal CRT - $(DMD) -m$(MODEL) -conf= -Isrc -betterC -Lvcruntime140.lib -Llegacy_stdio_definitions.lib -L/NODEFAULTLIB:msvcrt120.lib -run test\betterc\src\test19933.d - del $@.* diff --git a/runtime/druntime/test/common.mak b/runtime/druntime/test/common.mak index 1c64433b76e..a52c23210f0 100644 --- a/runtime/druntime/test/common.mak +++ b/runtime/druntime/test/common.mak @@ -1,5 +1,5 @@ -# set from top makefile -# LDC: we have no top makefile, include osmodel.mak for OS +# set explicitly in the make cmdline in druntime/Makefile (`test/%/.run` rule): +# LDC: we have no top makefile, include osmodel.mak for OS and set up bash shell include ../../../../dmd/osmodel.mak #OS:= MODEL:= @@ -10,44 +10,43 @@ DRUNTIMESO:= LINKDL:= QUIET:= TIMELIMIT:= -LDL:=$(subst -L,,$(LINKDL)) # -ldl +PIC:= +LDL:=$(subst -L,,$(LINKDL)) # -ldl SRC:=src GENERATED:=./generated ROOT:=$(GENERATED)/$(OS)/$(BUILD)/$(MODEL) +DRUNTIME_IMPLIB:=$(subst .dll,.lib,$(DRUNTIMESO)) -ifneq (default,$(MODEL)) - MODEL_FLAG:=-m$(MODEL) -endif -CFLAGS_BASE:= $(MODEL_FLAG) $(PIC) -Wall -#ifeq (osx,$(OS)) -# ifeq (64,$(MODEL)) -# CFLAGS_BASE+=--target=x86_64-darwin-apple # ARM cpu is not supported by dmd -# endif +MODEL_FLAG:=$(if $(findstring $(MODEL),default),,-m$(MODEL)) +CFLAGS_BASE:=$(if $(findstring $(OS),windows),/Wall,$(MODEL_FLAG) $(PIC) -Wall) +#ifeq (osx64,$(OS)$(MODEL)) +# CFLAGS_BASE+=--target=x86_64-darwin-apple # ARM cpu is not supported by dmd #endif -# LDC: use -defaultlib=druntime-ldc instead of `-defaultlib= -L$(DRUNTIME[SO])` -DFLAGS:=$(MODEL_FLAG) $(PIC) -w -I../../src -I../../import -I$(SRC) -defaultlib=druntime-ldc -preview=dip1000 -ifeq (,$(findstring win,$(OS))) - DFLAGS += -L-lpthread -L-lm $(LINKDL) -endif +# LDC: use `-defaultlib=druntime-ldc [-link-defaultlib-shared]` instead of `-defaultlib= -L$(DRUNTIME[_IMPLIB])` +DFLAGS:=$(MODEL_FLAG) $(PIC) -w -I../../src -I../../import -I$(SRC) -defaultlib=druntime-ldc -preview=dip1000 $(if $(findstring $(OS),windows),,-L-lpthread -L-lm $(LINKDL)) # LINK_SHARED may be set by importing makefile # LDC: -link-defaultlib-shared takes care of rpath, linking ldc_rt.dso.o etc. DFLAGS+=$(if $(LINK_SHARED),-link-defaultlib-shared,) ifeq ($(BUILD),debug) - # LDC: link against debug druntime - DFLAGS += -g -debug -link-defaultlib-debug - ifeq (,$(findstring win,$(OS))) - CFLAGS := $(CFLAGS_BASE) -g - else - CFLAGS := $(CFLAGS_BASE) /Zi - endif + # LDC: link against debug druntime + DFLAGS+=-g -debug -link-defaultlib-debug + CFLAGS:=$(CFLAGS_BASE) $(if $(findstring $(OS),windows),/Zi,-g) else - DFLAGS += -O -release - ifeq (,$(findstring win,$(OS))) - CFLAGS := $(CFLAGS_BASE) -O3 - else - CFLAGS := $(CFLAGS_BASE) /O2 - endif + DFLAGS+=-O -release + CFLAGS:=$(CFLAGS_BASE) $(if $(findstring $(OS),windows),/O2,-O3) endif -CXXFLAGS_BASE := $(CFLAGS_BASE) +CXXFLAGS_BASE:=$(CFLAGS_BASE) CXXFLAGS:=$(CFLAGS) + +ifeq (windows,$(OS)) + DOTEXE:=.exe + DOTDLL:=.dll + DOTLIB:=.lib + DOTOBJ:=.obj +else + DOTEXE:= + DOTDLL:=$(if $(findstring $(OS),osx),.dylib,.so) + DOTLIB:=.a + DOTOBJ:=.o +endif diff --git a/runtime/druntime/test/config/Makefile b/runtime/druntime/test/config/Makefile index 73ab6118ce6..fd77e770d2a 100644 --- a/runtime/druntime/test/config/Makefile +++ b/runtime/druntime/test/config/Makefile @@ -5,15 +5,15 @@ TESTS:=test19433 test20459 test22523 .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< -$(ROOT)/test19433.done: $(ROOT)/test19433 +$(ROOT)/test19433.done: $(ROOT)/test19433$(DOTEXE) @echo Testing test19433 $(QUIET)$(ROOT)/test19433 --DRT-dont-eat-me @touch $@ -$(ROOT)/test20459.done: $(ROOT)/test20459 +$(ROOT)/test20459.done: $(ROOT)/test20459$(DOTEXE) @echo Testing test20459 $(QUIET)$(ROOT)/test20459 foo bar -- --DRT-gcopts=profile:1 @touch $@ @@ -21,8 +21,8 @@ $(ROOT)/test20459.done: $(ROOT)/test20459 $(ROOT)/test22523.done: $(SRC)/test22523.d @echo Testing $< - $(QUIET)$(DMD) $(DFLAGS) -unittest -of$(ROOT)/test22523 $< - $(QUIET) $(ROOT)/test22523 -- --DRT-testmode=run-main + $(QUIET)$(DMD) $(DFLAGS) -unittest -of$(ROOT)/test22523$(DOTEXE) $< + $(QUIET)$(ROOT)/test22523 -- --DRT-testmode=run-main @touch $@ clean: diff --git a/runtime/druntime/test/coverage/Makefile b/runtime/druntime/test/coverage/Makefile index 249b8d2ec44..6325399318e 100644 --- a/runtime/druntime/test/coverage/Makefile +++ b/runtime/druntime/test/coverage/Makefile @@ -9,36 +9,36 @@ DIFF:=diff --strip-trailing-cr SED:=sed ifeq ($(OS),$(filter $(OS),freebsd osx)) - SED_INPLACE:=-i '' + SED_INPLACE:=-i '' else - SED_INPLACE:=-i'' + SED_INPLACE:=-i'' endif .PHONY: all clean all: $(NORMAL_TESTS) $(MERGE_TESTS) $(ROOT)/no_code.done $(ROOT)/merge_override.done -$(NORMAL_TESTS): $(ROOT)/%.done: $(ROOT)/% +$(NORMAL_TESTS): $(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* @rm -f $(ROOT)/src-$*.lst $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) -ifneq (,$(findstring win,$(OS))) - sed -i 's:^src\\:src/:g' $(ROOT)/src-$*.lst +ifeq (windows,$(OS)) + $(QUIET)$(SED) $(SED_INPLACE) 's:^src\\:src/:g' $(ROOT)/src-$*.lst endif $(QUIET)$(DIFF) src-$*.lst.exp $(ROOT)/src-$*.lst @touch $@ -$(MERGE_TESTS): $(ROOT)/%.done: $(ROOT)/% +$(MERGE_TESTS): $(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* @rm -f $(ROOT)/src-$*.lst $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) -ifneq (,$(findstring win,$(OS))) - sed -i 's:^src\\:src/:g' $(ROOT)/src-$*.lst +ifeq (windows,$(OS)) + $(QUIET)$(SED) $(SED_INPLACE) 's:^src\\:src/:g' $(ROOT)/src-$*.lst endif $(QUIET)$(DIFF) src-$*.lst.exp $(ROOT)/src-$*.lst @touch $@ -$(ROOT)/merge_override.done: $(ROOT)/%.done: $(ROOT)/% +$(ROOT)/merge_override.done: $(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* @rm -f $(ROOT)/src-$*.lst $(QUIET)$(SED) $(SED_INPLACE) 's/CHANGEVAR/CHANGE_VAR/g' src/$*.d @@ -47,31 +47,37 @@ ifneq (,$(findstring win,$(OS))) sed -i 's:^src\\:src/:g' $(ROOT)/src-$*.lst endif $(QUIET)$(SED) $(SED_INPLACE) 's/CHANGE_VAR/CHANGEVAR/g' src/$*.d +ifeq (windows,$(OS)) + $(QUIET)$(SED) $(SED_INPLACE) 's:^src\\:src/:g' $(ROOT)/src-$*.lst +endif $(QUIET)$(DIFF) src-$*.lst_1.exp $(ROOT)/src-$*.lst $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) ifneq (,$(findstring win,$(OS))) sed -i 's:^src\\:src/:g' $(ROOT)/src-$*.lst endif $(QUIET)$(SED) $(SED_INPLACE) 's/CHANGEVAR/CHANGE_VAR/g' src/$*.d +ifeq (windows,$(OS)) + $(QUIET)$(SED) $(SED_INPLACE) 's:^src\\:src/:g' $(ROOT)/src-$*.lst +endif $(QUIET)$(DIFF) src-$*.lst_2.exp $(ROOT)/src-$*.lst @touch $@ -$(ROOT)/no_code.done: $(ROOT)/%.done: $(ROOT)/% +$(ROOT)/no_code.done: $(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* @rm -f $(ROOT)/src-$*.lst $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) $(QUIET)$(ROOT)/$* $(ROOT) $(RUN_ARGS) -ifneq (,$(findstring win,$(OS))) - sed -i 's:^src\\:src/:g' $(ROOT)/src-$*.lst - sed -i 's:^src\\:src/:g' $(ROOT)/src-$*_imp.lst +ifeq (windows,$(OS)) + $(QUIET)$(SED) $(SED_INPLACE) 's:^src\\:src/:g' $(ROOT)/src-$*.lst + $(QUIET)$(SED) $(SED_INPLACE) 's:^src\\:src/:g' $(ROOT)/src-$*_imp.lst endif $(QUIET)$(DIFF) src-$*.lst.exp $(ROOT)/src-$*.lst $(QUIET)$(DIFF) src-$*_imp.lst.exp $(ROOT)/src-$*_imp.lst @touch $@ -$(ROOT)/no_code: $(SRC)/no_code_imp.d -$(ROOT)/%: $(SRC)/%.d - $(QUIET)$(DMD) $(DFLAGS) -of$(ROOT)/$* $^ +$(ROOT)/no_code$(DOTEXE): $(SRC)/no_code_imp.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d + $(QUIET)$(DMD) $(DFLAGS) -of$@ $^ clean: rm -rf $(GENERATED) *.lst diff --git a/runtime/druntime/test/cpuid/Makefile b/runtime/druntime/test/cpuid/Makefile index 3998382d1d0..98c499518f6 100644 --- a/runtime/druntime/test/cpuid/Makefile +++ b/runtime/druntime/test/cpuid/Makefile @@ -5,12 +5,12 @@ TESTS:=cpuid .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$< $(RUN_ARGS) @touch $@ -$(ROOT)/cpuid: $(SRC)/cpuid.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/cpuid/win64.mak b/runtime/druntime/test/cpuid/win64.mak deleted file mode 100644 index a64c8d7ecfa..00000000000 --- a/runtime/druntime/test/cpuid/win64.mak +++ /dev/null @@ -1,12 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 -DRUNTIMELIB=druntime64.lib - -test: cpuid - -cpuid: - $(DMD) -g -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) test\cpuid\src\cpuid.d - cpuid.exe - del cpuid.exe cpuid.obj diff --git a/runtime/druntime/test/cycles/Makefile b/runtime/druntime/test/cycles/Makefile index 537fd7f4a76..1079ad8ca0f 100644 --- a/runtime/druntime/test/cycles/Makefile +++ b/runtime/druntime/test/cycles/Makefile @@ -11,25 +11,17 @@ all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(ROOT)/cycle_ignore.done: RETCODE=0 $(ROOT)/cycle_ignore.done: LINES=0 $(ROOT)/cycle_abort.done: RETCODE=1 -ifneq (,$(findstring win,$(OS))) -$(ROOT)/cycle_abort.done: LINES=8 -else -$(ROOT)/cycle_abort.done: LINES=7 -endif +$(ROOT)/cycle_abort.done: LINES=$(if $(findstring $(OS),windows),8,7) $(ROOT)/cycle_print.done: RETCODE=0 $(ROOT)/cycle_print.done: LINES=6 $(ROOT)/cycle_deprecate.done: RETCODE=1 -ifneq (,$(findstring win,$(OS))) -$(ROOT)/cycle_deprecate.done: LINES=9 -else -$(ROOT)/cycle_deprecate.done: LINES=8 -endif -$(ROOT)/%.done: $(ROOT)/test_cycles +$(ROOT)/cycle_deprecate.done: LINES=$(if $(findstring $(OS),windows),9,8) +$(ROOT)/%.done: $(ROOT)/test_cycles$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/test_cycles --DRT-oncycle=$(patsubst cycle_%.done,%, $(notdir $@)) > $@ 2>&1; test $$? -eq $(RETCODE) test `cat $@ | wc -l` -eq $(LINES) -$(ROOT)/test_cycles: $(SRC)/*.d +$(ROOT)/test_cycles$(DOTEXE): $(SRC)/*.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $^ clean: diff --git a/runtime/druntime/test/exceptions/Makefile b/runtime/druntime/test/exceptions/Makefile index ba81a49fe21..f238a528aac 100644 --- a/runtime/druntime/test/exceptions/Makefile +++ b/runtime/druntime/test/exceptions/Makefile @@ -1,31 +1,34 @@ include ../common.mak TESTS=stderr_msg unittest_assert invalid_memory_operation unknown_gc static_dtor \ - future_message refcounted rt_trap_exceptions_drt catch_in_finally \ - message_with_null + future_message refcounted rt_trap_exceptions_drt catch_in_finally \ + message_with_null ifeq ($(OS)-$(BUILD),linux-debug) - TESTS+=line_trace line_trace_21656 long_backtrace_trunc rt_trap_exceptions cpp_demangle - LINE_TRACE_DFLAGS:=-L--export-dynamic + TESTS+=line_trace line_trace_21656 long_backtrace_trunc rt_trap_exceptions cpp_demangle + LINE_TRACE_DFLAGS:=-L--export-dynamic endif ifeq ($(OS),linux) - TESTS+=rt_trap_exceptions_drt_gdb + TESTS+=rt_trap_exceptions_drt_gdb endif ifeq ($(OS)-$(BUILD),freebsd-debug) - TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle - LINE_TRACE_DFLAGS:=-L--export-dynamic + TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle + LINE_TRACE_DFLAGS:=-L--export-dynamic endif ifeq ($(OS)-$(BUILD),dragonflybsd-debug) - TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle - LINE_TRACE_DFLAGS:=-L--export-dynamic + TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle + LINE_TRACE_DFLAGS:=-L--export-dynamic endif ifeq ($(OS)-$(BUILD),osx-debug) - TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle - LINE_TRACE_DFLAGS:= + TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle + LINE_TRACE_DFLAGS:= +endif +ifeq ($(OS)-$(BUILD),windows-debug) + TESTS+=winstack endif ifeq ($(BUILD),debug) - TESTS+=assert_fail + TESTS+=assert_fail endif DIFF:=diff @@ -35,7 +38,7 @@ GDB:=gdb .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/line_trace.done: $(ROOT)/line_trace +$(ROOT)/line_trace.done: $(ROOT)/line_trace$(DOTEXE) @echo Testing line_trace $(QUIET)$(TIMELIMIT)$(ROOT)/line_trace $(RUN_ARGS) > $(ROOT)/line_trace.output # Use sed to canonicalize line_trace.output and compare against expected output in line_trace.exp @@ -44,7 +47,7 @@ $(ROOT)/line_trace.done: $(ROOT)/line_trace @touch $@ # https://issues.dlang.org/show_bug.cgi?id=21656 -$(ROOT)/line_trace_21656.done: $(ROOT)/line_trace +$(ROOT)/line_trace_21656.done: $(ROOT)/line_trace$(DOTEXE) @echo Testing line_trace_21656 @mkdir -p $(ROOT)/line_trace_21656 @touch $(ROOT)/line_trace_21656/line_trace @@ -53,7 +56,7 @@ $(ROOT)/line_trace_21656.done: $(ROOT)/line_trace @rm -rf $(ROOT)/line_trace_21656 @touch $@ -$(ROOT)/long_backtrace_trunc.done: $(ROOT)/long_backtrace_trunc +$(ROOT)/long_backtrace_trunc.done: $(ROOT)/long_backtrace_trunc$(DOTEXE) @echo Testing long_backtrace_trunc $(QUIET)$(TIMELIMIT)$(ROOT)/long_backtrace_trunc $(RUN_ARGS) > $(ROOT)/long_backtrace_trunc.output # Use sed to canonicalize long_backtrace_trunc.output and compare against expected output in long_backtrace_trunc.exp @@ -61,12 +64,17 @@ $(ROOT)/long_backtrace_trunc.done: $(ROOT)/long_backtrace_trunc @rm -f $(ROOT)/long_backtrace_trunc.output @touch $@ -$(ROOT)/chain.done: $(ROOT)/chain +$(ROOT)/chain.done: $(ROOT)/chain$(DOTEXE) @echo Testing chain $(QUIET)$(TIMELIMIT)$(ROOT)/chain $(RUN_ARGS) > $(ROOT)/chain.output @rm -f $(ROOT)/chain.output @touch $@ +$(ROOT)/winstack.done: $(ROOT)/winstack$(DOTEXE) + @echo Testing winstack + $(QUIET)$(TIMELIMIT)$(ROOT)/winstack $(RUN_ARGS) + @touch $@ + $(ROOT)/stderr_msg.done: STDERR_EXP="stderr_msg msg" $(ROOT)/unittest_assert.done: STDERR_EXP="unittest_assert msg" $(ROOT)/invalid_memory_operation.done: STDERR_EXP="InvalidMemoryOperationError" @@ -82,7 +90,7 @@ $(ROOT)/cpp_demangle.done: STDERR_EXP="thrower(int)" $(ROOT)/message_with_null.done: STDERR_EXP=" world" -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) 2>$(ROOT)/$*.stderr || true @@ -105,7 +113,7 @@ $(ROOT)/rt_trap_exceptions_drt.done: RUN_ARGS="--DRT-trapExceptions=0" $(ROOT)/rt_trap_exceptions_drt.done: NEGATE=! -$(ROOT)/rt_trap_exceptions_drt_gdb.done: $(ROOT)/rt_trap_exceptions_drt +$(ROOT)/rt_trap_exceptions_drt_gdb.done: $(ROOT)/rt_trap_exceptions_drt$(DOTEXE) @echo Testing rt_trap_exceptions_drt_gdb $(QUIET)$(TIMELIMIT) $(GDB) -n -ex 'set confirm off' -ex run -ex 'bt full' -ex q --args $< --DRT-trapExceptions=0 \ > $(ROOT)/rt_trap_exceptions_drt_gdb.output 2>&1 || true @@ -115,23 +123,23 @@ $(ROOT)/rt_trap_exceptions_drt_gdb.done: $(ROOT)/rt_trap_exceptions_drt ! grep "No stack." > /dev/null < $(ROOT)/rt_trap_exceptions_drt_gdb.output @touch $@ -$(ROOT)/refcounted.done: $(ROOT)/refcounted +$(ROOT)/refcounted.done: $(ROOT)/refcounted$(DOTEXE) $(QUIET) $< @touch $@ -ifeq (ldmd,$(findstring ldmd,$(DMD))) +ifneq (,$(findstring ldmd,$(DMD))) # LDC: Make sure allocation intended to provoke exception is not elided. -$(ROOT)/invalid_memory_operation: DFLAGS+=-disable-gc2stack +$(ROOT)/invalid_memory_operation$(DOTEXE): DFLAGS+=-disable-gc2stack endif -$(ROOT)/unittest_assert: DFLAGS+=-unittest -version=CoreUnittest -$(ROOT)/line_trace: DFLAGS+=$(LINE_TRACE_DFLAGS) -$(ROOT)/long_backtrace_trunc: DFLAGS+=$(LINE_TRACE_DFLAGS) -$(ROOT)/rt_trap_exceptions: DFLAGS+=$(LINE_TRACE_DFLAGS) -$(ROOT)/rt_trap_exceptions_drt: DFLAGS+=-g -$(ROOT)/refcounted: DFLAGS+=-dip1008 -$(ROOT)/cpp_demangle: DFLAGS+=-L-lstdc++ $(LINE_TRACE_DFLAGS) - -$(ROOT)/%: $(SRC)/%.d $(DMD) $(DRUNTIME) +$(ROOT)/unittest_assert$(DOTEXE): DFLAGS+=-unittest -version=CoreUnittest +$(ROOT)/line_trace$(DOTEXE): DFLAGS+=$(LINE_TRACE_DFLAGS) +$(ROOT)/long_backtrace_trunc$(DOTEXE): DFLAGS+=$(LINE_TRACE_DFLAGS) +$(ROOT)/rt_trap_exceptions$(DOTEXE): DFLAGS+=$(LINE_TRACE_DFLAGS) +$(ROOT)/rt_trap_exceptions_drt$(DOTEXE): DFLAGS+=-g +$(ROOT)/refcounted$(DOTEXE): DFLAGS+=-dip1008 +$(ROOT)/cpp_demangle$(DOTEXE): DFLAGS+=-L-lstdc++ $(LINE_TRACE_DFLAGS) + +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(DMD) $(DRUNTIME) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/exceptions/win64.mak b/runtime/druntime/test/exceptions/win64.mak deleted file mode 100644 index ea4d19e599c..00000000000 --- a/runtime/druntime/test/exceptions/win64.mak +++ /dev/null @@ -1,10 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 -DRUNTIMELIB=druntime64.lib - -test: - $(DMD) -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -g test\exceptions\src\winstack.d - winstack.exe - del winstack.* diff --git a/runtime/druntime/test/gc/Makefile b/runtime/druntime/test/gc/Makefile index 452fc619b93..d1be90ccfb5 100644 --- a/runtime/druntime/test/gc/Makefile +++ b/runtime/druntime/test/gc/Makefile @@ -1,28 +1,29 @@ include ../common.mak -TESTS := attributes sentinel printf memstomp invariant logging \ - precise precisegc \ - recoverfree nocollect -# LDC: disable POSIX-specific tests on Windows -ifeq (,$(findstring win,$(OS))) -TESTS += sentinel1 sentinel2 \ - forkgc forkgc2 \ - sigmaskgc startbackgc concurrent precise_concurrent hospital +TESTS:=attributes sentinel printf memstomp invariant logging \ + precise precisegc \ + recoverfree nocollect + +ifneq ($(OS),windows) + # some .d files are for Posix only + TESTS+=sentinel1 sentinel2 forkgc forkgc2 sigmaskgc startbackgc + # and some tests require the `fork` GC, only supported on Posix + TEST+=concurrent precise_concurrent hospital endif ifeq ($(OS),linux) - TESTS+=issue22843 + TESTS+=issue22843 endif -SRC_GC = ../../src/core/internal/gc/impl/conservative/gc.d -SRC = $(SRC_GC) ../../src/rt/lifetime.d +SRC_GC=../../src/core/internal/gc/impl/conservative/gc.d +SRC=$(SRC_GC) ../../src/rt/lifetime.d # ../../src/object.d causes duplicate symbols -UDFLAGS = $(DFLAGS) -unittest -version=CoreUnittest +UDFLAGS=$(DFLAGS) -unittest -version=CoreUnittest .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ @@ -30,7 +31,7 @@ $(ROOT)/%.done: $(ROOT)/% # https://issues.dlang.org/show_bug.cgi?id=22843 # needs to run under valgrind # versions before 3.13.0 don't handle clone() correctly, skip them -$(ROOT)/issue22843.done: $(ROOT)/issue22843 +$(ROOT)/issue22843.done: $(ROOT)/issue22843$(DOTEXE) @echo Testing issue22843 $(QUIET)if ! command -v valgrind >/dev/null; then \ echo valgrind not installed, skipping; \ @@ -41,70 +42,70 @@ $(ROOT)/issue22843.done: $(ROOT)/issue22843 fi @touch $@ -$(ROOT)/sentinel: $(SRC) +$(ROOT)/sentinel$(DOTEXE): $(SRC) $(DMD) -debug=SENTINEL $(UDFLAGS) -main -of$@ $(SRC) -$(ROOT)/sentinel1: $(SRC) sentinel1.d +$(ROOT)/sentinel1$(DOTEXE): $(SRC) sentinel1.d $(DMD) -debug=SENTINEL -debug=GC_RECURSIVE_LOCK $(DFLAGS) sentinel1.d -of$@ $(SRC) -$(ROOT)/sentinel2: $(SRC) sentinel2.d +$(ROOT)/sentinel2$(DOTEXE): $(SRC) sentinel2.d $(DMD) -debug=SENTINEL -debug=GC_RECURSIVE_LOCK $(DFLAGS) sentinel2.d -gx -of$@ $(SRC) -$(ROOT)/printf: $(SRC) +$(ROOT)/printf$(DOTEXE): $(SRC) $(DMD) -debug=PRINTF -debug=PRINTF_TO_FILE -debug=COLLECT_PRINTF $(UDFLAGS) -main -of$@ $(SRC_GC) -$(ROOT)/memstomp: $(SRC) +$(ROOT)/memstomp$(DOTEXE): $(SRC) $(DMD) -debug=MEMSTOMP $(UDFLAGS) -main -of$@ $(SRC) -$(ROOT)/invariant: $(SRC) +$(ROOT)/invariant$(DOTEXE): $(SRC) $(DMD) -debug -debug=INVARIANT -debug=PTRCHECK -debug=PTRCHECK2 $(UDFLAGS) -main -of$@ $(SRC) -$(ROOT)/logging: $(SRC) +$(ROOT)/logging$(DOTEXE): $(SRC) $(DMD) -debug=LOGGING $(UDFLAGS) -main -of$@ $(SRC) -$(ROOT)/precise: $(SRC) +$(ROOT)/precise$(DOTEXE): $(SRC) $(DMD) -debug -debug=INVARIANT -debug=MEMSTOMP $(UDFLAGS) -main -of$@ $(SRC) -$(ROOT)/precise.done: RUN_ARGS += --DRT-gcopt=gc:precise +$(ROOT)/precise.done: RUN_ARGS+=--DRT-gcopt=gc:precise -$(ROOT)/precisegc: $(SRC) precisegc.d +$(ROOT)/precisegc$(DOTEXE): $(SRC) precisegc.d $(DMD) $(UDFLAGS) -gx -of$@ $(SRC) precisegc.d -$(ROOT)/concurrent: $(SRC) +$(ROOT)/concurrent$(DOTEXE): $(SRC) $(DMD) $(UDFLAGS) -main -of$@ $(SRC) -$(ROOT)/concurrent.done: RUN_ARGS += --DRT-gcopt=fork:1 +$(ROOT)/concurrent.done: RUN_ARGS+=--DRT-gcopt=fork:1 -$(ROOT)/precise_concurrent: $(SRC) +$(ROOT)/precise_concurrent$(DOTEXE): $(SRC) $(DMD) $(UDFLAGS) -main -of$@ $(SRC) -$(ROOT)/precise_concurrent.done: RUN_ARGS += "--DRT-gcopt=gc:precise fork:1" +$(ROOT)/precise_concurrent.done: RUN_ARGS+="--DRT-gcopt=gc:precise fork:1" -$(ROOT)/attributes: attributes.d +$(ROOT)/attributes$(DOTEXE): attributes.d $(DMD) $(UDFLAGS) -of$@ attributes.d -$(ROOT)/forkgc: forkgc.d +$(ROOT)/forkgc$(DOTEXE): forkgc.d $(DMD) $(UDFLAGS) -of$@ forkgc.d -$(ROOT)/forkgc2: forkgc2.d +$(ROOT)/forkgc2$(DOTEXE): forkgc2.d $(DMD) $(UDFLAGS) -of$@ forkgc2.d -$(ROOT)/sigmaskgc: sigmaskgc.d +$(ROOT)/sigmaskgc$(DOTEXE): sigmaskgc.d $(DMD) $(UDFLAGS) -of$@ sigmaskgc.d -$(ROOT)/startbackgc: startbackgc.d - $(DMD) $(UDFLAGS) -of$@ sigmaskgc.d +$(ROOT)/startbackgc$(DOTEXE): startbackgc.d + $(DMD) $(UDFLAGS) -of$@ startbackgc.d -$(ROOT)/recoverfree: recoverfree.d +$(ROOT)/recoverfree$(DOTEXE): recoverfree.d $(DMD) $(DFLAGS) -of$@ recoverfree.d -$(ROOT)/nocollect: nocollect.d +$(ROOT)/nocollect$(DOTEXE): nocollect.d $(DMD) $(DFLAGS) -of$@ nocollect.d -$(ROOT)/hospital: hospital.d +$(ROOT)/hospital$(DOTEXE): hospital.d $(DMD) $(DFLAGS) -d -of$@ hospital.d -$(ROOT)/hospital.done: RUN_ARGS += --DRT-gcopt=fork:1 +$(ROOT)/hospital.done: RUN_ARGS+=--DRT-gcopt=fork:1 -$(ROOT)/issue22843: issue22843.d +$(ROOT)/issue22843$(DOTEXE): issue22843.d $(DMD) $(UDFLAGS) -of$@ issue22843.d -$(ROOT)/issue22843.done: RUN_ARGS += "--DRT-gcopt=fork:1 initReserve:0 minPoolSize:1" +$(ROOT)/issue22843.done: RUN_ARGS+="--DRT-gcopt=fork:1 initReserve:0 minPoolSize:1" clean: rm -rf $(ROOT) diff --git a/runtime/druntime/test/gc/win64.mak b/runtime/druntime/test/gc/win64.mak deleted file mode 100644 index e29092e37d2..00000000000 --- a/runtime/druntime/test/gc/win64.mak +++ /dev/null @@ -1,58 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 -DRUNTIMELIB=druntime64.lib - -SRC_GC = src/core/internal/gc/impl/conservative/gc.d -SRC = $(SRC_GC) src/rt/lifetime.d src/object.d -_DFLAGS = -m$(MODEL) -g -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -UDFLAGS = $(_DFLAGS) -unittest -version=CoreUnittest -RM = del - -test: sentinel printf memstomp invariant logging precise precisegc recoverfree nocollect - -sentinel: - $(DMD) -debug=SENTINEL $(UDFLAGS) -main -of$@.exe $(SRC) - .\$@.exe - $(RM) $@.exe $@.obj $@.ilk $@.pdb - -printf: - $(DMD) -debug=PRINTF -debug=PRINTF_TO_FILE -debug=COLLECT_PRINTF $(UDFLAGS) -main -of$@.exe $(SRC_GC) - .\$@.exe - $(RM) $@.exe $@.obj $@.ilk $@.pdb gcx.log - -memstomp: - $(DMD) -debug=MEMSTOMP $(UDFLAGS) -main -of$@.exe $(SRC) - .\$@.exe - $(RM) $@.exe $@.obj $@.ilk $@.pdb - -invariant: - $(DMD) -debug -debug=INVARIANT -debug=PTRCHECK -debug=PTRCHECK2 $(UDFLAGS) -main -of$@.exe $(SRC) - .\$@.exe - $(RM) $@.exe $@.obj $@.ilk $@.pdb - -logging: - $(DMD) -debug=LOGGING $(UDFLAGS) -of$@.exe -main $(SRC) - .\$@.exe - $(RM) $@.exe $@.obj $@.ilk $@.pdb - -precise: - $(DMD) -debug -debug=INVARIANT -debug=MEMSTOMP $(UDFLAGS) -main -of$@.exe $(SRC) - .\$@.exe --DRT-gcopt=gc:precise - $(RM) $@.exe $@.obj $@.ilk $@.pdb - -precisegc: - $(DMD) $(UDFLAGS) -of$@.exe -gx $(SRC) test/gc/precisegc.d - .\$@.exe - $(RM) $@.exe $@.obj $@.ilk $@.pdb - -recoverfree: - $(DMD) $(_DFLAGS) -of$@.exe -gx test/gc/recoverfree.d - .\$@.exe - $(RM) $@.exe $@.obj $@.ilk $@.pdb - -nocollect: - $(DMD) $(_DFLAGS) -of$@.exe -gx test/gc/nocollect.d - .\$@.exe - $(RM) $@.exe $@.obj $@.ilk $@.pdb diff --git a/runtime/druntime/test/hash/Makefile b/runtime/druntime/test/hash/Makefile index dfd07c88c55..53e0e37936a 100644 --- a/runtime/druntime/test/hash/Makefile +++ b/runtime/druntime/test/hash/Makefile @@ -5,12 +5,12 @@ TESTS:=test_hash .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/test_hash.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/imports/Makefile b/runtime/druntime/test/imports/Makefile index e4f67668885..078c863798f 100644 --- a/runtime/druntime/test/imports/Makefile +++ b/runtime/druntime/test/imports/Makefile @@ -8,7 +8,7 @@ all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(ROOT)/%.done: @echo Testing $* @mkdir -p $(basename $@) - $(QUIET)$(DMD) -version=Shared -o- -deps=$@ -Isrc -I../../import src/$* + $(QUIET)$(DMD) -version=Shared -o- -deps=$@ -Isrc -I../../import src/$*.d clean: rm -rf $(GENERATED) diff --git a/runtime/druntime/test/init_fini/Makefile b/runtime/druntime/test/init_fini/Makefile index 846966f7637..0956df48ee9 100644 --- a/runtime/druntime/test/init_fini/Makefile +++ b/runtime/druntime/test/init_fini/Makefile @@ -5,12 +5,12 @@ TESTS:=thread_join runtime_args test18996 custom_gc .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/init_fini/win64.mak b/runtime/druntime/test/init_fini/win64.mak deleted file mode 100644 index b020fec9f66..00000000000 --- a/runtime/druntime/test/init_fini/win64.mak +++ /dev/null @@ -1,12 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 -DRUNTIMELIB=druntime64.lib - -test: custom_gc - -custom_gc: - $(DMD) -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) test\init_fini\src\custom_gc.d - custom_gc.exe - del custom_gc.exe custom_gc.obj diff --git a/runtime/druntime/test/lifetime/Makefile b/runtime/druntime/test/lifetime/Makefile index 40499c3522d..c8cb5895cda 100644 --- a/runtime/druntime/test/lifetime/Makefile +++ b/runtime/druntime/test/lifetime/Makefile @@ -5,12 +5,12 @@ TESTS:=large_aggregate_destroy_21097 .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/profile/Makefile b/runtime/druntime/test/profile/Makefile index 04775622e27..86c17b39565 100644 --- a/runtime/druntime/test/profile/Makefile +++ b/runtime/druntime/test/profile/Makefile @@ -6,6 +6,7 @@ TESTS:=profile DIFF:=diff --strip-trailing-cr GREP:=grep +SED:=sed ifeq (freebsd,$(OS)) SHELL=/usr/local/bin/bash @@ -15,7 +16,7 @@ else ifeq (netbsd,$(OS)) SHELL=/usr/pkg/bin/bash else ifeq (dragonflybsd,$(OS)) SHELL=/usr/local/bin/bash -else +else ifneq (windows,$(OS)) # already using a bash shell on Windows via common.mak SHELL=/bin/bash endif @@ -24,7 +25,7 @@ all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) # LDC: enable assertions for BUILD=RELEASE (=> `-O -release`) $(ROOT)/profile.done: DFLAGS+=-profile -check=assert=on -$(ROOT)/profile.done: $(ROOT)/%.done: $(ROOT)/% +$(ROOT)/profile.done: $(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* @rm -f $(ROOT)/mytrace.log $(ROOT)/mytrace.def $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(ROOT)/mytrace.log $(ROOT)/mytrace.def @@ -36,17 +37,17 @@ $(ROOT)/profile.done: $(ROOT)/%.done: $(ROOT)/% @touch $@ $(ROOT)/profilegc.done: DFLAGS+=-profile=gc -$(ROOT)/profilegc.done: $(ROOT)/%.done: $(ROOT)/% +$(ROOT)/profilegc.done: $(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* @rm -f $(ROOT)/myprofilegc.log $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(ROOT)/myprofilegc.log $(QUIET)$(DIFF) \ - <($(GREP) -vF 'core.' myprofilegc.log.$(OS).$(MODEL).exp) \ + <($(GREP) -vF 'core.' myprofilegc.log.$(OS).$(shell echo $(MODEL) | cut -c 1-2).exp) \ <($(GREP) -vF 'core.' $(ROOT)/myprofilegc.log) @touch $@ $(ROOT)/both.done: DFLAGS+=-profile -profile=gc -$(ROOT)/both.done: $(ROOT)/%.done: $(ROOT)/% +$(ROOT)/both.done: $(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* @rm -f $(ROOT)/both.log $(ROOT)/both.def $(ROOT)/bothgc.log $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(ROOT)/both.log $(ROOT)/both.def $(ROOT)/bothgc.log @@ -55,12 +56,18 @@ $(ROOT)/both.done: $(ROOT)/%.done: $(ROOT)/% $(QUIET) cat $(ROOT)/both.def $(QUIET) sort $(ROOT)/both.def -o $(ROOT)/both.def $(QUIET)(sort bothnew.def.exp | $(DIFF) - $(ROOT)/both.def) +ifeq (windows,$(OS)) + $(QUIET)$(DIFF) \ + <($(GREP) -vF 'core.' bothgc.log.exp) \ + <($(GREP) -vF 'core.' $(ROOT)/bothgc.log | $(SED) 's: src\\\\: src/:g') +else $(QUIET)$(DIFF) \ <($(GREP) -vF 'core.' bothgc.log.exp) \ <($(GREP) -vF 'core.' $(ROOT)/bothgc.log) +endif @touch $@ -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$(ROOT)/$* $< clean: diff --git a/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp b/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp index 5a6a451dd62..8a04f4737ac 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp @@ -1,7 +1,7 @@ bytes allocated, allocations, type, function, file:line 256 1 immutable(char)[][int] D main src/profilegc.d:23 - 128 1 float[][] D main src/profilegc.d:18 - 128 1 int[][] D main src/profilegc.d:15 + 128 1 float D main src/profilegc.d:18 + 128 1 int D main src/profilegc.d:15 64 1 double[] profilegc.main src/profilegc.d:56 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 @@ -14,6 +14,8 @@ bytes allocated, allocations, type, function, file:line 16 1 float D main src/profilegc.d:17 16 1 int D main src/profilegc.d:13 16 1 int D main src/profilegc.d:14 + 16 1 uint[] D main src/profilegc.d:15 + 16 1 uint[] D main src/profilegc.d:18 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp b/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp index 1e8905e2da4..e3e2476a5a7 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp @@ -1,11 +1,13 @@ bytes allocated, allocations, type, function, file:line 496 1 immutable(char)[][int] D main src/profilegc.d:23 - 160 1 float[][] D main src/profilegc.d:18 - 160 1 int[][] D main src/profilegc.d:15 + 160 1 float D main src/profilegc.d:18 + 160 1 int D main src/profilegc.d:15 64 1 double[] profilegc.main src/profilegc.d:56 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 32 1 C D main src/profilegc.d:12 + 32 1 ulong[] D main src/profilegc.d:15 + 32 1 ulong[] D main src/profilegc.d:18 32 1 void[] profilegc.main src/profilegc.d:55 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 diff --git a/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp b/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp index 5a6a451dd62..9d929c3cca4 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp @@ -1,7 +1,7 @@ bytes allocated, allocations, type, function, file:line 256 1 immutable(char)[][int] D main src/profilegc.d:23 - 128 1 float[][] D main src/profilegc.d:18 - 128 1 int[][] D main src/profilegc.d:15 + 128 1 float D main src/profilegc.d:18 + 128 1 int D main src/profilegc.d:15 64 1 double[] profilegc.main src/profilegc.d:56 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 @@ -16,4 +16,6 @@ bytes allocated, allocations, type, function, file:line 16 1 int D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 + 16 1 uint[] D main src/profilegc.d:15 + 16 1 uint[] D main src/profilegc.d:18 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp b/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp index 1e8905e2da4..e3e2476a5a7 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp @@ -1,11 +1,13 @@ bytes allocated, allocations, type, function, file:line 496 1 immutable(char)[][int] D main src/profilegc.d:23 - 160 1 float[][] D main src/profilegc.d:18 - 160 1 int[][] D main src/profilegc.d:15 + 160 1 float D main src/profilegc.d:18 + 160 1 int D main src/profilegc.d:15 64 1 double[] profilegc.main src/profilegc.d:56 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 32 1 C D main src/profilegc.d:12 + 32 1 ulong[] D main src/profilegc.d:15 + 32 1 ulong[] D main src/profilegc.d:18 32 1 void[] profilegc.main src/profilegc.d:55 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 diff --git a/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp b/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp index 87edaf1d909..e5afe3345e0 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp @@ -1,7 +1,7 @@ bytes allocated, allocations, type, function, file:line 176 1 immutable(char)[][int] D main src/profilegc.d:23 - 128 1 float[][] D main src/profilegc.d:18 - 128 1 int[][] D main src/profilegc.d:15 + 128 1 float D main src/profilegc.d:18 + 128 1 int D main src/profilegc.d:15 64 1 float[] D main src/profilegc.d:42 64 1 int[] D main src/profilegc.d:41 64 1 double[] profilegc.main src/profilegc.d:56 @@ -14,6 +14,8 @@ bytes allocated, allocations, type, function, file:line 16 1 float D main src/profilegc.d:17 16 1 int D main src/profilegc.d:13 16 1 int D main src/profilegc.d:14 + 16 1 uint[] D main src/profilegc.d:15 + 16 1 uint[] D main src/profilegc.d:18 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp b/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp index 1e8905e2da4..e3e2476a5a7 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp @@ -1,11 +1,13 @@ bytes allocated, allocations, type, function, file:line 496 1 immutable(char)[][int] D main src/profilegc.d:23 - 160 1 float[][] D main src/profilegc.d:18 - 160 1 int[][] D main src/profilegc.d:15 + 160 1 float D main src/profilegc.d:18 + 160 1 int D main src/profilegc.d:15 64 1 double[] profilegc.main src/profilegc.d:56 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 32 1 C D main src/profilegc.d:12 + 32 1 ulong[] D main src/profilegc.d:15 + 32 1 ulong[] D main src/profilegc.d:18 32 1 void[] profilegc.main src/profilegc.d:55 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 diff --git a/runtime/druntime/test/profile/myprofilegc.log.windows.32.exp b/runtime/druntime/test/profile/myprofilegc.log.windows.32.exp new file mode 100644 index 00000000000..8b4cdf6e751 --- /dev/null +++ b/runtime/druntime/test/profile/myprofilegc.log.windows.32.exp @@ -0,0 +1,21 @@ +bytes allocated, allocations, type, function, file:line + 256 1 immutable(char)[][int] D main src\profilegc.d:23 + 128 1 float D main src\profilegc.d:18 + 128 1 int D main src\profilegc.d:15 + 64 1 double[] profilegc.main src\profilegc.d:56 + 48 1 float[] D main src\profilegc.d:42 + 48 1 int[] D main src\profilegc.d:41 + 32 1 void[] profilegc.main src\profilegc.d:55 + 16 1 C D main src\profilegc.d:12 + 16 1 char[] D main src\profilegc.d:34 + 16 1 char[] D main src\profilegc.d:36 + 16 1 closure profilegc.main.foo src\profilegc.d:45 + 16 1 float D main src\profilegc.d:16 + 16 1 float D main src\profilegc.d:17 + 16 1 int D main src\profilegc.d:13 + 16 1 int D main src\profilegc.d:14 + 16 1 int[] D main src\profilegc.d:22 + 16 1 int[] D main src\profilegc.d:37 + 16 1 uint[] D main src\profilegc.d:15 + 16 1 uint[] D main src\profilegc.d:18 + 16 1 wchar[] D main src\profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.windows.64.exp b/runtime/druntime/test/profile/myprofilegc.log.windows.64.exp new file mode 100644 index 00000000000..05408557a84 --- /dev/null +++ b/runtime/druntime/test/profile/myprofilegc.log.windows.64.exp @@ -0,0 +1,21 @@ +bytes allocated, allocations, type, function, file:line + 496 1 immutable(char)[][int] D main src\profilegc.d:23 + 160 1 float D main src\profilegc.d:18 + 160 1 int D main src\profilegc.d:15 + 64 1 double[] profilegc.main src\profilegc.d:56 + 48 1 float[] D main src\profilegc.d:42 + 48 1 int[] D main src\profilegc.d:41 + 32 1 C D main src\profilegc.d:12 + 32 1 ulong[] D main src\profilegc.d:15 + 32 1 ulong[] D main src\profilegc.d:18 + 32 1 void[] profilegc.main src\profilegc.d:55 + 16 1 char[] D main src\profilegc.d:34 + 16 1 char[] D main src\profilegc.d:36 + 16 1 closure profilegc.main.foo src\profilegc.d:45 + 16 1 float D main src\profilegc.d:16 + 16 1 float D main src\profilegc.d:17 + 16 1 int D main src\profilegc.d:13 + 16 1 int D main src\profilegc.d:14 + 16 1 int[] D main src\profilegc.d:22 + 16 1 int[] D main src\profilegc.d:37 + 16 1 wchar[] D main src\profilegc.d:35 diff --git a/runtime/druntime/test/shared/Makefile b/runtime/druntime/test/shared/Makefile index f974be44438..01b5b4f4e86 100644 --- a/runtime/druntime/test/shared/Makefile +++ b/runtime/druntime/test/shared/Makefile @@ -1,8 +1,64 @@ +# LDC: druntime DLL supported on Windows LINK_SHARED:=1 -include ../common.mak +include ../common.mak # affected by LINK_SHARED! -TESTS:=link load linkD linkDR loadDR dynamiccast +.PHONY: all clean + +ifeq (windows,$(OS)) + +# LDC: required for executables to implicitly dllimport DLL data symbols +DFLAGS+=-dllimport=all + +TESTS:=loadlibwin dllrefcount dllgc dynamiccast +ifeq ($(SHARED),1) +DFLAGS+=-version=SharedRuntime +endif + +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) + @echo Testing $* + $(QUIET)$(TIMELIMIT)$< $(RUN_ARGS) + @touch $@ + +$(ROOT)/dynamiccast.done: $(ROOT)/%.done: $(ROOT)/%$(DOTEXE) + @echo Testing $* + $(QUIET)rm -f $(ROOT)/dynamiccast_end{bar,main} + $(QUIET)$(TIMELIMIT)$< $(RUN_ARGS) + $(QUIET)test -f $(ROOT)/dynamiccast_endbar + $(QUIET)test -f $(ROOT)/dynamiccast_endmain + @touch $@ + +$(ROOT)/dllrefcount$(DOTEXE): $(SRC)/dllrefcount.d + $(QUIET)$(DMD) $(DFLAGS) -of$@ $< + +$(ROOT)/loadlibwin$(DOTEXE): $(SRC)/loadlibwin.d + $(QUIET)$(DMD) $(DFLAGS) -of$@ $< + +# LDC: this test is designed for .exe & .dll with separate druntimes +$(ROOT)/dllgc$(DOTEXE): DFLAGS+=-link-defaultlib-shared=false -dllimport=none + +$(ROOT)/dllgc$(DOTEXE): $(SRC)/dllgc.d + $(QUIET)$(DMD) $(DFLAGS) -version=DLL -shared -of$(ROOT)/dllgc$(DOTDLL) $< + $(QUIET)$(DMD) $(DFLAGS) -of$@ $< + +$(ROOT)/dynamiccast$(DOTEXE): $(SRC)/dynamiccast.d + $(QUIET)$(DMD) $(DFLAGS) -version=DLL -shared -of$(ROOT)/dynamiccast$(DOTDLL) $< + $(QUIET)$(DMD) $(DFLAGS) -of$@ $< + +# LDC addition: test teardown with separate druntimes, with the DLL using the .exe GC +dll_gc_proxy_teardown: DFLAGS+=-link-defaultlib-shared=false -dllimport=none +dll_gc_proxy_teardown: $(SRC)/dll_gc_proxy_teardown.d + $(QUIET)$(DMD) $(DFLAGS) -shared -L/EXPORT:gc_setProxy -L/EXPORT:gc_clrProxy -version=DLL -of$(ROOT)/dll_gc_proxy_teardown$(DOTDLL) $< + $(QUIET)$(DMD) $(DFLAGS) -shared -L/EXPORT:gc_setProxy -L/EXPORT:gc_clrProxy -version=DLL -version=NoUnload -of$(ROOT)/dll_gc_proxy_teardown_nounload$(DOTDLL) $< + $(QUIET)$(DMD) $(DFLAGS) -of$(ROOT)/load_dll_gc_proxy_teardown$(DOTEXE) $< + $(QUIET)$(DMD) $(DFLAGS) -version=NoUnload -of$(ROOT)/load_dll_gc_proxy_teardown_nounload$(DOTEXE) $< + $(QUIET)$(ROOT)/load_dll_gc_proxy_teardown$(DOTEXE) + $(QUIET)$(ROOT)/load_dll_gc_proxy_teardown_nounload$(DOTEXE) + +# LDC: include Posix tests too +endif # Windows + +TESTS+=link load linkD linkDR loadDR dynamiccast TESTS+=link_linkdep link_loaddep load_loaddep load_13414 # LDC: disable 3 tests on Mac, 1 on Windows ifneq ($(OS),osx) @@ -23,133 +79,65 @@ endif EXPORT_DYNAMIC=$(if $(findstring $(OS),linux freebsd dragonflybsd),-L--export-dynamic,) NO_AS_NEEDED=$(if $(findstring $(OS),linux freebsd dragonflybsd),-L--no-as-needed,) -.PHONY: all clean - -# LDC: add Windows tests -ifeq (,$(findstring win,$(OS))) - -all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -LIB_EXT:=so -DLL_EXT:=so +all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(if $(findstring $(OS),windows),dll_gc_proxy_teardown,) $(ROOT)/loadDR.done $(ROOT)/host.done: RUN_ARGS:=$(DRUNTIMESO) -else -# Windows - -# required for executables to implicitly dllimport DLL data symbols -DFLAGS+=-dllimport=all - -all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) loadlibwin dllrefcount dllgc dll_gc_proxy_teardown -LIB_EXT:=lib -DLL_EXT:=dll -CC:=cl.exe - -$(ROOT)/loadDR.done $(ROOT)/host.done: RUN_ARGS:=$(subst .lib,.dll,$(DRUNTIMESO)) - -dllrefcount: - $(DMD) $(DFLAGS) src/dllrefcount.d -of$(ROOT)/dllrefcount.exe - $(ROOT)/dllrefcount.exe - -loadlibwin: - $(DMD) $(DFLAGS) src/loadlibwin.d -of$(ROOT)/loadlibwin.exe - $(ROOT)/loadlibwin.exe - -dllgc: - $(DMD) $(DFLAGS) -version=DLL -shared -of$(ROOT)/dllgc.dll src/dllgc.d - $(DMD) $(DFLAGS) -of$(ROOT)/loaddllgc.exe src/dllgc.d - $(ROOT)/loaddllgc.exe - -# LDC: this test is designed for .exe & .dll with separate druntimes -dllgc: DFLAGS+=-link-defaultlib-shared=false -dllimport=none - -# LDC addition: test teardown with separate druntimes, with the DLL using the .exe GC -dll_gc_proxy_teardown: DFLAGS+=-link-defaultlib-shared=false -dllimport=none -dll_gc_proxy_teardown: - $(DMD) $(DFLAGS) -shared -L/EXPORT:gc_setProxy -L/EXPORT:gc_clrProxy -version=DLL -of$(ROOT)/dll_gc_proxy_teardown.dll src/dll_gc_proxy_teardown.d - $(DMD) $(DFLAGS) -shared -L/EXPORT:gc_setProxy -L/EXPORT:gc_clrProxy -version=DLL -version=NoUnload -of$(ROOT)/dll_gc_proxy_teardown_nounload.dll src/dll_gc_proxy_teardown.d - $(DMD) $(DFLAGS) -of$(ROOT)/load_dll_gc_proxy_teardown.exe src/dll_gc_proxy_teardown.d - $(DMD) $(DFLAGS) -version=NoUnload -of$(ROOT)/load_dll_gc_proxy_teardown_nounload.exe src/dll_gc_proxy_teardown.d - $(ROOT)/load_dll_gc_proxy_teardown.exe - $(ROOT)/load_dll_gc_proxy_teardown_nounload.exe - -# end Windows -endif +$(ROOT)/dynamiccast.done: CLEANUP:=rm $(ROOT)/dynamiccast_endmain$(DOTEXE) $(ROOT)/dynamiccast_endbar$(DOTEXE) -$(ROOT)/dynamiccast.done: CLEANUP:=rm $(ROOT)/dynamiccast_endmain $(ROOT)/dynamiccast_endbar - -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$< $(RUN_ARGS) $(CLEANUP) @touch $@ -$(ROOT)/link: $(SRC)/link.d $(ROOT)/lib.$(DLL_EXT) $(DRUNTIMESO) - $(QUIET)$(DMD) $(DFLAGS) -of$@ $< -L$(ROOT)/lib.$(LIB_EXT) +$(ROOT)/link$(DOTEXE): $(SRC)/link.d $(ROOT)/lib$(DOTDLL) $(DRUNTIMESO) + $(QUIET)$(DMD) $(DFLAGS) -of$@ $< -L$(ROOT)/lib$(DOTDLL) -$(ROOT)/link_linkdep: $(SRC)/link_linkdep.d $(ROOT)/lib.$(DLL_EXT) $(ROOT)/liblinkdep.$(DLL_EXT) $(DRUNTIMESO) - $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) -L$(ROOT)/liblinkdep.$(LIB_EXT) -L$(ROOT)/lib.$(LIB_EXT) +$(ROOT)/link_linkdep$(DOTEXE): $(SRC)/link_linkdep.d $(ROOT)/lib$(DOTDLL) $(ROOT)/liblinkdep$(DOTDLL) $(DRUNTIMESO) + $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) -L$(ROOT)/liblinkdep$(DOTDLL) -L$(ROOT)/lib$(DOTDLL) -$(ROOT)/load_linkdep: $(SRC)/load_linkdep.d $(ROOT)/lib.$(DLL_EXT) $(ROOT)/liblinkdep.$(DLL_EXT) $(DRUNTIMESO) +$(ROOT)/load_linkdep$(DOTEXE): $(SRC)/load_linkdep.d $(ROOT)/lib$(DOTDLL) $(ROOT)/liblinkdep$(DOTDLL) $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) $(LINKDL) -$(ROOT)/link_loaddep: $(SRC)/link_loaddep.d $(ROOT)/lib.$(DLL_EXT) $(ROOT)/libloaddep.$(DLL_EXT) $(DRUNTIMESO) - $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) -L$(ROOT)/libloaddep.$(LIB_EXT) +$(ROOT)/link_loaddep$(DOTEXE): $(SRC)/link_loaddep.d $(ROOT)/lib$(DOTDLL) $(ROOT)/libloaddep$(DOTDLL) $(DRUNTIMESO) + $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) -L$(ROOT)/libloaddep$(DOTDLL) -$(ROOT)/load_loaddep: $(SRC)/load_loaddep.d $(ROOT)/lib.$(DLL_EXT) $(ROOT)/libloaddep.$(DLL_EXT) $(DRUNTIMESO) +$(ROOT)/load_loaddep$(DOTEXE): $(SRC)/load_loaddep.d $(ROOT)/lib$(DOTDLL) $(ROOT)/libloaddep$(DOTDLL) $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKFLAGS) $(LINKDL) -$(ROOT)/load $(ROOT)/finalize: $(ROOT)/%: $(SRC)/%.d $(ROOT)/lib.$(DLL_EXT) $(DRUNTIMESO) +$(ROOT)/load$(DOTEXE) $(ROOT)/finalize$(DOTEXE): $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(ROOT)/lib$(DOTDLL) $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKDL) -$(ROOT)/load_13414: $(ROOT)/%: $(SRC)/%.d $(ROOT)/lib_13414.$(DLL_EXT) $(DRUNTIMESO) +$(ROOT)/load_13414$(DOTEXE): $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(ROOT)/lib_13414$(DOTDLL) $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< $(LINKDL) -$(ROOT)/dynamiccast: $(SRC)/dynamiccast.d $(ROOT)/dynamiccast.$(DLL_EXT) $(DRUNTIMESO) +$(ROOT)/dynamiccast$(DOTEXE): $(SRC)/dynamiccast.d $(ROOT)/dynamiccast$(DOTDLL) $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $(SRC)/dynamiccast.d $(LINKDL) -$(ROOT)/dynamiccast.$(DLL_EXT): $(SRC)/dynamiccast.d $(DRUNTIMESO) +$(ROOT)/dynamiccast$(DOTDLL): $(SRC)/dynamiccast.d $(DRUNTIMESO) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< -version=DLL -fPIC -shared $(LINKDL) -ifeq (,$(findstring win,$(OS))) - -$(ROOT)/linkD: $(SRC)/linkD.c $(ROOT)/lib.$(DLL_EXT) $(DRUNTIMESO) - $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(ROOT)/lib.$(DLL_EXT) $(LDL) -pthread +# TODO: cl.exe flags +$(ROOT)/linkD$(DOTEXE): $(SRC)/linkD.c $(ROOT)/lib$(DOTDLL) $(DRUNTIMESO) + $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(ROOT)/lib$(DOTDLL) $(LDL) -pthread -$(ROOT)/linkDR: $(SRC)/linkDR.c $(ROOT)/lib.$(DLL_EXT) $(DRUNTIMESO) +$(ROOT)/linkDR$(DOTEXE): $(SRC)/linkDR.c $(ROOT)/lib$(DOTDLL) $(DRUNTIMESO) $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(DRUNTIMESO) $(LDL) -pthread -$(ROOT)/loadDR: $(SRC)/loadDR.c $(ROOT)/lib.$(DLL_EXT) $(DRUNTIMESO) +$(ROOT)/loadDR$(DOTEXE): $(SRC)/loadDR.c $(ROOT)/lib$(DOTDLL) $(DRUNTIMESO) $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(LDL) -pthread -$(ROOT)/host: $(SRC)/host.c $(ROOT)/plugin1.$(DLL_EXT) $(ROOT)/plugin2.$(DLL_EXT) +$(ROOT)/host$(DOTEXE): $(SRC)/host.c $(ROOT)/plugin1$(DOTDLL) $(ROOT)/plugin2$(DOTDLL) $(QUIET)$(CC) $(CFLAGS) -o $@ $< $(LDL) -pthread -else -# Windows - -$(ROOT)/linkD: $(SRC)/linkD.c $(ROOT)/lib.$(DLL_EXT) $(DRUNTIMESO) - $(QUIET)$(CC) $(CFLAGS) /Fo$@.obj /Fe$@.exe $< $(ROOT)/lib.$(LIB_EXT) - -$(ROOT)/linkDR: $(SRC)/linkDR.c $(ROOT)/lib.$(DLL_EXT) $(DRUNTIMESO) - $(QUIET)$(CC) $(CFLAGS) /Fo$@.obj /Fe$@.exe $< $(DRUNTIMESO) - -$(ROOT)/loadDR: $(SRC)/loadDR.c $(ROOT)/lib.$(DLL_EXT) $(DRUNTIMESO) - $(QUIET)$(CC) $(CFLAGS) /Fo$@.obj /Fe$@.exe $< - -$(ROOT)/host: $(SRC)/host.c $(ROOT)/plugin1.$(DLL_EXT) $(ROOT)/plugin2.$(DLL_EXT) - $(QUIET)$(CC) $(CFLAGS) /Fo$@.obj /Fe$@.exe $< - -# end Windows -endif - -$(ROOT)/liblinkdep.$(DLL_EXT): $(ROOT)/lib.$(DLL_EXT) -$(ROOT)/liblinkdep.$(DLL_EXT): DFLAGS+=-L$(ROOT)/lib.$(LIB_EXT) +$(ROOT)/liblinkdep$(DOTDLL): $(ROOT)/lib$(DOTDLL) +$(ROOT)/liblinkdep$(DOTDLL): DFLAGS+=-L$(ROOT)/lib$(DOTDLL) -$(ROOT)/plugin1.$(DLL_EXT) $(ROOT)/plugin2.$(DLL_EXT): $(SRC)/plugin.d $(DRUNTIMESO) +$(ROOT)/plugin1$(DOTDLL) $(ROOT)/plugin2$(DOTDLL): $(SRC)/plugin.d $(DRUNTIMESO) $(QUIET)$(DMD) -fPIC -shared $(DFLAGS) -of$@ $< -$(ROOT)/%.$(DLL_EXT): $(SRC)/%.d $(DRUNTIMESO) +$(ROOT)/%$(DOTDLL): $(SRC)/%.d $(DRUNTIMESO) $(QUIET)$(DMD) -fPIC -shared $(DFLAGS) -of$@ $< $(LINKDL) clean: diff --git a/runtime/druntime/test/shared/src/dynamiccast.d b/runtime/druntime/test/shared/src/dynamiccast.d index 2efcff21f67..9bd19de0645 100644 --- a/runtime/druntime/test/shared/src/dynamiccast.d +++ b/runtime/druntime/test/shared/src/dynamiccast.d @@ -72,7 +72,8 @@ else return null; } - version (DigitalMars) version (Win64) version = DMD_Win64; + version (DigitalMars) version (Win64) version = NoExceptions; + version (SharedRuntime) version (DigitalMars) version (Win32) version = NoExceptions; void main(string[] args) { @@ -101,7 +102,7 @@ else auto o = getFunc!(Object function(Object))("foo")(c); assert(cast(C) o); - version (DMD_Win64) + version (NoExceptions) { // FIXME: apparent crash & needs more work, see https://github.com/dlang/druntime/pull/2874 fclose(fopen("dynamiccast_endbar", "w")); diff --git a/runtime/druntime/test/shared/win64.mak b/runtime/druntime/test/shared/win64.mak deleted file mode 100644 index 9658562dffd..00000000000 --- a/runtime/druntime/test/shared/win64.mak +++ /dev/null @@ -1,31 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 -DRUNTIMELIB=druntime64.lib - -test: loadlibwin dllrefcount dllgc dynamiccast - -dllrefcount: - $(DMD) -g -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) test\shared\src\dllrefcount.d - dllrefcount.exe - del dllrefcount.exe dllrefcount.obj - -loadlibwin: - $(DMD) -g -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) test\shared\src\loadlibwin.d - loadlibwin.exe - del loadlibwin.exe loadlibwin.obj - -dllgc: - $(DMD) -g -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -version=DLL -shared -ofdllgc.dll test\shared\src\dllgc.d - $(DMD) -g -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -ofloaddllgc.exe test\shared\src\dllgc.d - loaddllgc.exe - del loaddllgc.exe loaddllgc.obj dllgc.dll dllgc.obj - -dynamiccast: - $(DMD) -g -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -version=DLL -shared -ofdynamiccast.dll test\shared\src\dynamiccast.d - $(DMD) -g -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -ofdynamiccast.exe test\shared\src\dynamiccast.d - dynamiccast.exe - cmd /c "if not exist dynamiccast_endbar exit 1" - cmd /c "if not exist dynamiccast_endmain exit 1" - del dynamiccast.exe dynamiccast.dll dynamiccast.obj dynamiccast_endbar dynamiccast_endmain diff --git a/runtime/druntime/test/stdcpp/Makefile b/runtime/druntime/test/stdcpp/Makefile index b8b8fbc44e5..0aea85c80fa 100644 --- a/runtime/druntime/test/stdcpp/Makefile +++ b/runtime/druntime/test/stdcpp/Makefile @@ -1,35 +1,45 @@ include ../common.mak -# LDC: enable on Windows too (port from win64.mak) -ifneq (,$(findstring win,$(OS))) +.PHONY: all clean -CXX:=cl.exe -TESTS:=array allocator memory new string utility vector +ifeq (windows,$(OS)) -.PHONY: all clean +CC:=cl +EXTRA_CXXFLAGS:=/nologo /EHsc +EXTRA_DFLAGS:= + +TESTS:=allocator array memory new string utility vector + +MSC_VER:=$(strip $(shell $(CC) /nologo /EP msc_ver.c)) +ifeq ($(shell test $(MSC_VER) -gt 1900; echo $$?),0) + EXTRA_CXXFLAGS+=/std:c++17 + EXTRA_DFLAGS+=-extern-std=c++17 + TESTS+=string_view +endif all: $(addprefix $(ROOT)/,$(TESTS)) $(ROOT)/%: $(SRC)/%.cpp $(SRC)/%_test.d - mkdir -p $(dir $@) - - $(CXX) /MT /EHsc $(CXXFLAGS_BASE) -c /Fo$(ROOT)/$*_cpp.obj $< - $(DMD) -mscrtlib=libcmt $(DFLAGS) -main -unittest -version=CoreUnittest $(ROOT)/$*_cpp.obj -run $(SRC)/$*_test.d + @echo Testing $* + @mkdir -p $(dir $@) - $(CXX) /MD /EHsc $(CXXFLAGS_BASE) -c /Fo$(ROOT)/$*_cpp.obj $< - $(DMD) -mscrtlib=msvcrt $(DFLAGS) -main -unittest -version=CoreUnittest $(ROOT)/$*_cpp.obj -run $(SRC)/$*_test.d + $(QUIET)$(CC) /MT $(EXTRA_CXXFLAGS) -c /Fo$@_cpp$(DOTOBJ) $< + $(QUIET)$(DMD) -mscrtlib=libcmt $(DFLAGS) $(EXTRA_DFLAGS) -main -unittest -version=CoreUnittest -version=_MSC_VER_$(MSC_VER) -of$@$(DOTEXE) $@_cpp$(DOTOBJ) $(SRC)/$*_test.d + $(QUIET)$(TIMELIMIT)$@ $(RUN_ARGS) - $(CXX) /MTd /EHsc $(CXXFLAGS_BASE) -c /Fo$(ROOT)/$*_cpp.obj $< - $(DMD) -mscrtlib=libcmtd $(DFLAGS) -main -unittest -version=CoreUnittest $(ROOT)/$*_cpp.obj -run $(SRC)/$*_test.d + $(QUIET)$(CC) /MD $(EXTRA_CXXFLAGS) -c /Fo$@_cpp$(DOTOBJ) $< + $(QUIET)$(DMD) -mscrtlib=msvcrt $(DFLAGS) $(EXTRA_DFLAGS) -main -unittest -version=CoreUnittest -version=_MSC_VER_$(MSC_VER) -of$@$(DOTEXE) $@_cpp$(DOTOBJ) $(SRC)/$*_test.d + $(QUIET)$(TIMELIMIT)$@ $(RUN_ARGS) - $(CXX) /MDd /EHsc $(CXXFLAGS_BASE) -c /Fo$(ROOT)/$*_cpp.obj $< - $(DMD) -mscrtlib=msvcrtd $(DFLAGS) -main -unittest -version=CoreUnittest $(ROOT)/$*_cpp.obj -run $(SRC)/$*_test.d + $(QUIET)$(CC) /MTd $(EXTRA_CXXFLAGS) -c /Fo$@_cpp$(DOTOBJ) $< + $(QUIET)$(DMD) -mscrtlib=libcmtd $(DFLAGS) $(EXTRA_DFLAGS) -main -unittest -version=CoreUnittest -version=_MSC_VER_$(MSC_VER) -of$@$(DOTEXE) $@_cpp$(DOTOBJ) $(SRC)/$*_test.d + $(QUIET)$(TIMELIMIT)$@ $(RUN_ARGS) -clean: - rm -rf $(GENERATED) + $(QUIET)$(CC) /MDd $(EXTRA_CXXFLAGS) -c /Fo$@_cpp$(DOTOBJ) $< + $(QUIET)$(DMD) -mscrtlib=msvcrtd $(DFLAGS) $(EXTRA_DFLAGS) -main -unittest -version=CoreUnittest -version=_MSC_VER_$(MSC_VER) -of$@$(DOTEXE) $@_cpp$(DOTOBJ) $(SRC)/$*_test.d + $(QUIET)$(TIMELIMIT)$@ $(RUN_ARGS) -else -# non-Windows: +else # Posix: HASCPP17:=`echo wow | $(CXX) -std=c++17 -E -xc++ - > /dev/null 2>&1 && echo yes` @@ -39,82 +49,73 @@ TESTS17:=string_view OLDABITESTS:= ifeq (osx,$(OS)) - TESTS11+=memory -# TESTS+=string -# TESTS+=vector + TESTS11+=memory +# TESTS+=string +# TESTS+=vector endif ifeq (linux,$(OS)) - TESTS11+=exception typeinfo - TESTS+=typeinfo -# TESTS+=string -# TESTS+=vector - OLDABITESTS+=string + TESTS11+=exception typeinfo + TESTS+=typeinfo +# TESTS+=string +# TESTS+=vector + OLDABITESTS+=string endif ifeq (freebsd,$(OS)) - TESTS11+=memory - TESTS+=string -# TESTS+=vector + TESTS11+=memory + TESTS+=string +# TESTS+=vector endif # some build machines have ancient compilers, so we need to disable C++17 tests ifneq (yes,$(HASCPP17)) -TESTS17:= + TESTS17:= endif -# LDC: libexecinfo required on FreeBSD (not required with lld 9+ (`pragma(lib)` in druntime)) -EXTRA_LDC_LIBS:= -ifneq (,$(findstring freebsd,$(OS))) - EXTRA_LDC_LIBS+=-lexecinfo -endif - -.PHONY: all clean - -all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(addprefix $(ROOT)/,$(addsuffix _11.done,$(TESTS11))) $(addprefix $(ROOT)/,$(addsuffix _17.done,$(TESTS17))) $(addprefix $(ROOT)/,$(addsuffix _old.done,$(OLDABITESTS))) $(addprefix $(ROOT)/,$(addsuffix _libcpp.done,$(LIBCPPTESTS))) +all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) $(addprefix $(ROOT)/,$(addsuffix _11.done,$(TESTS11))) $(addprefix $(ROOT)/,$(addsuffix _17.done,$(TESTS17))) $(addprefix $(ROOT)/,$(addsuffix _old.done,$(OLDABITESTS))) # run C++98 tests -$(ROOT)/%.done : $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ # run C++11 tests -$(ROOT)/%_11.done : $(ROOT)/%_11 +$(ROOT)/%_11.done: $(ROOT)/%_11$(DOTEXE) @echo Testing $*_11 $(QUIET)$(TIMELIMIT)$(ROOT)/$*_11 $(RUN_ARGS) @touch $@ # run C++17 tests -$(ROOT)/%_17.done : $(ROOT)/%_17 +$(ROOT)/%_17.done: $(ROOT)/%_17$(DOTEXE) @echo Testing $*_17 $(QUIET)$(TIMELIMIT)$(ROOT)/$*_17 $(RUN_ARGS) @touch $@ # run libstdc++ _GLIBCXX_USE_CXX11_ABI=0 tests -$(ROOT)/%_old.done : $(ROOT)/%_old +$(ROOT)/%_old.done: $(ROOT)/%_old$(DOTEXE) @echo Testing $*_old $(QUIET)$(TIMELIMIT)$(ROOT)/$*_old $(RUN_ARGS) @touch $@ # build C++98 tests -$(ROOT)/%: $(SRC)/%.cpp $(SRC)/%_test.d - mkdir -p $(dir $@) - $(QUIET)$(DMD) $(DFLAGS) -extern-std=c++98 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_d.o $(SRC)/$*_test.d - $(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++98 -o $@ $< $(ROOT)/$*_d.o $(DRUNTIME) $(EXTRA_LDC_LIBS) -lpthread $(LDL) +$(ROOT)/%$(DOTEXE): $(SRC)/%.cpp $(SRC)/%_test.d + @mkdir -p $(dir $@) + $(QUIET)$(DMD) $(DFLAGS) -extern-std=c++98 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_d$(DOTOBJ) $(SRC)/$*_test.d + $(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++98 -o $@ $< $(ROOT)/$*_d$(DOTOBJ) $(DRUNTIME) -lpthread $(LDL) # build C++11 tests -$(ROOT)/%_11: $(SRC)/%.cpp $(SRC)/%_test.d - mkdir -p $(dir $@) - $(QUIET)$(DMD) $(DFLAGS) -extern-std=c++11 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_11_d.o $(SRC)/$*_test.d - $(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++11 -o $@ $< $(ROOT)/$*_11_d.o $(DRUNTIME) $(EXTRA_LDC_LIBS) -lpthread $(LDL) +$(ROOT)/%_11$(DOTEXE): $(SRC)/%.cpp $(SRC)/%_test.d + @mkdir -p $(dir $@) + $(QUIET)$(DMD) $(DFLAGS) -extern-std=c++11 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_11_d$(DOTOBJ) $(SRC)/$*_test.d + $(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++11 -o $@ $< $(ROOT)/$*_11_d$(DOTOBJ) $(DRUNTIME) -lpthread $(LDL) # build C++17 tests -$(ROOT)/%_17: $(SRC)/%.cpp $(SRC)/%_test.d - mkdir -p $(dir $@) - $(QUIET)$(DMD) $(DFLAGS) -extern-std=c++17 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_17_d.o $(SRC)/$*_test.d - $(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++17 -o $@ $< $(ROOT)/$*_17_d.o $(DRUNTIME) $(EXTRA_LDC_LIBS) -lpthread $(LDL) +$(ROOT)/%_17$(DOTEXE): $(SRC)/%.cpp $(SRC)/%_test.d + @mkdir -p $(dir $@) + $(QUIET)$(DMD) $(DFLAGS) -extern-std=c++17 -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_17_d$(DOTOBJ) $(SRC)/$*_test.d + $(QUIET)$(CXX) $(CXXFLAGS_BASE) -std=c++17 -o $@ $< $(ROOT)/$*_17_d$(DOTOBJ) $(DRUNTIME) -lpthread $(LDL) # build libstdc++ _GLIBCXX_USE_CXX11_ABI=0 tests -$(ROOT)/%_old: $(SRC)/%.cpp $(SRC)/%_test.d - mkdir -p $(dir $@) - $(QUIET)$(DMD) $(DFLAGS) -version=_GLIBCXX_USE_CXX98_ABI -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_old_d.o $(SRC)/$*_test.d - $(QUIET)$(CXX) $(CXXFLAGS_BASE) -D_GLIBCXX_USE_CXX11_ABI=0 -o $@ $< $(ROOT)/$*_old_d.o $(DRUNTIME) $(EXTRA_LDC_LIBS) -lpthread $(LDL) +$(ROOT)/%_old$(DOTEXE): $(SRC)/%.cpp $(SRC)/%_test.d + @mkdir -p $(dir $@) + $(QUIET)$(DMD) $(DFLAGS) -version=_GLIBCXX_USE_CXX98_ABI -main -unittest -version=CoreUnittest -c -of=$(ROOT)/$*_old_d$(DOTOBJ) $(SRC)/$*_test.d + $(QUIET)$(CXX) $(CXXFLAGS_BASE) -D_GLIBCXX_USE_CXX11_ABI=0 -o $@ $< $(ROOT)/$*_old_d$(DOTOBJ) $(DRUNTIME) -lpthread $(LDL) + +endif # end Posix clean: rm -rf $(GENERATED) - -endif -# end non-Windows diff --git a/runtime/druntime/test/stdcpp/msc_ver.c b/runtime/druntime/test/stdcpp/msc_ver.c new file mode 100644 index 00000000000..e390e3ba6bd --- /dev/null +++ b/runtime/druntime/test/stdcpp/msc_ver.c @@ -0,0 +1 @@ +_MSC_VER diff --git a/runtime/druntime/test/stdcpp/src/new_test.d b/runtime/druntime/test/stdcpp/src/new_test.d index 5e91c2bf097..b91967e5a9d 100644 --- a/runtime/druntime/test/stdcpp/src/new_test.d +++ b/runtime/druntime/test/stdcpp/src/new_test.d @@ -135,3 +135,56 @@ unittest assert(MyClassGC.numDeleted == 1); } } + +unittest +{ + import core.stdcpp.new_: cpp_new, cpp_delete; + + { + extern(C++) static struct S + { + __gshared int numDeleted; + __gshared int lastDeleted; + int i; + ~this() + { + lastDeleted = i; + numDeleted++; + } + } + S *s = cpp_new!S(12345); + cpp_delete(s); + assert(S.numDeleted == 1); + assert(S.lastDeleted == 12345); + s = null; + cpp_delete(s); + assert(S.numDeleted == 1); + assert(S.lastDeleted == 12345); + } + + { + extern(C++) static class C + { + __gshared int numDeleted; + __gshared int lastDeleted; + int i; + this(int i) + { + this.i = i; + } + ~this() + { + lastDeleted = i; + numDeleted++; + } + } + C c = cpp_new!C(54321); + cpp_delete(c); + assert(C.numDeleted == 1); + assert(C.lastDeleted == 54321); + c = null; + cpp_delete(c); + assert(C.numDeleted == 1); + assert(C.lastDeleted == 54321); + } +} diff --git a/runtime/druntime/test/stdcpp/win64.mak b/runtime/druntime/test/stdcpp/win64.mak deleted file mode 100644 index c84651f11ff..00000000000 --- a/runtime/druntime/test/stdcpp/win64.mak +++ /dev/null @@ -1,38 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 -DRUNTIMELIB=druntime64.lib -CC=cl - -TESTS=array allocator memory new string utility vector - -_MSC_VER=$(file < ..\..\ver.txt) -ADD_CFLAGS=$(file < ..\..\cflags.txt) -ADD_DFLAGS=$(file < ..\..\dflags.txt) -ADD_TESTS=$(file < ..\..\add_tests.txt) - -TESTS=$(TESTS) $(ADD_TESTS) - -test: $(TESTS) - -$(TESTS): - "$(CC)" -c /Fo$@_cpp.obj test\stdcpp\src\$@.cpp /EHsc /MT $(ADD_CFLAGS) - "$(DMD)" -of=$@.exe -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -main -unittest -version=CoreUnittest -version=_MSC_VER_$(_MSC_VER) -mscrtlib=libcmt $(ADD_DFLAGS) test\stdcpp\src\$@_test.d $@_cpp.obj - $@.exe - del $@.exe $@.obj $@_cpp.obj - - "$(CC)" -c /Fo$@_cpp.obj test\stdcpp\src\$@.cpp /EHsc /MD $(ADD_CFLAGS) - "$(DMD)" -of=$@.exe -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -main -unittest -version=CoreUnittest -version=_MSC_VER_$(_MSC_VER) -mscrtlib=msvcrt $(ADD_DFLAGS) test\stdcpp\src\$@_test.d $@_cpp.obj - $@.exe - del $@.exe $@.obj $@_cpp.obj - - "$(CC)" -c /Fo$@_cpp.obj test\stdcpp\src\$@.cpp /EHsc /MTd $(ADD_CFLAGS) - "$(DMD)" -of=$@.exe -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -main -unittest -version=CoreUnittest -version=_MSC_VER_$(_MSC_VER) -mscrtlib=libcmtd $(ADD_DFLAGS) test\stdcpp\src\$@_test.d $@_cpp.obj - $@.exe - del $@.exe $@.obj $@_cpp.obj - - "$(CC)" -c /Fo$@_cpp.obj test\stdcpp\src\$@.cpp /EHsc /MDd $(ADD_CFLAGS) - "$(DMD)" -of=$@.exe -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) -main -unittest -version=CoreUnittest -version=_MSC_VER_$(_MSC_VER) -mscrtlib=msvcrtd $(ADD_DFLAGS) test\stdcpp\src\$@_test.d $@_cpp.obj - $@.exe - del $@.exe $@.obj $@_cpp.obj diff --git a/runtime/druntime/test/thread/Makefile b/runtime/druntime/test/thread/Makefile index f832d4971fc..041c527c56a 100644 --- a/runtime/druntime/test/thread/Makefile +++ b/runtime/druntime/test/thread/Makefile @@ -1,44 +1,45 @@ include ../common.mak TESTS:=tlsgc_sections test_import tlsstack join_detach -# LDC: disable POSIX-specific tests on Windows -ifeq (,$(findstring win,$(OS))) -TESTS+=fiber_guard_page external_threads + +# some .d files support Posix only +ifneq ($(OS),windows) + TEST+=fiber_guard_page external_threads endif .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) # segfault || bus error (OSX) -$(ROOT)/fiber_guard_page.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/fiber_guard_page.done: $(ROOT)/%.done : $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS); rc=$$?; [ $$rc -eq 139 ] || [ $$rc -eq 138 ] @touch $@ -$(ROOT)/external_threads.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/external_threads.done: $(ROOT)/%.done : $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* @touch $@ -$(ROOT)/tlsgc_sections.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/tlsgc_sections.done: $(ROOT)/%.done : $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* @touch $@ -$(ROOT)/test_import.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/test_import.done: $(ROOT)/%.done : $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* @touch $@ -$(ROOT)/tlsstack.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/tlsstack.done: $(ROOT)/%.done : $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* @touch $@ -$(ROOT)/join_detach.done: $(ROOT)/%.done : $(ROOT)/% +$(ROOT)/join_detach.done: $(ROOT)/%.done : $(ROOT)/%$(DOTEXE) @echo Testing $* is currently disabled! -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/traits/Makefile b/runtime/druntime/test/traits/Makefile index 0a8ba2bd900..610f7d53193 100644 --- a/runtime/druntime/test/traits/Makefile +++ b/runtime/druntime/test/traits/Makefile @@ -5,12 +5,12 @@ TESTS:=all_satisfy .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/typeinfo/Makefile b/runtime/druntime/test/typeinfo/Makefile index e2bb0f5b9ca..338f19c8107 100644 --- a/runtime/druntime/test/typeinfo/Makefile +++ b/runtime/druntime/test/typeinfo/Makefile @@ -5,12 +5,12 @@ TESTS:=comparison isbaseof enum_ .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/%.done: $(ROOT)/% +$(ROOT)/%.done: $(ROOT)/%$(DOTEXE) @echo Testing $* $(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) @touch $@ -$(ROOT)/%: $(SRC)/%.d +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: diff --git a/runtime/druntime/test/unittest/Makefile b/runtime/druntime/test/unittest/Makefile index afec263077f..e7c8f032cbf 100644 --- a/runtime/druntime/test/unittest/Makefile +++ b/runtime/druntime/test/unittest/Makefile @@ -34,11 +34,12 @@ $(ROOT)/na.done: TESTTEXT= $(ROOT)/%.done: customhandler.d @echo Testing $* - $(QUIET)$(DMD) $(DFLAGS) -of$(ROOT)/tester_$(patsubst %.done,%, $(notdir $@)) customhandler.d -version=$(VER) + $(QUIET)$(DMD) $(DFLAGS) -of$(ROOT)/tester_$(patsubst %.done,%, $(notdir $@))$(DOTEXE) customhandler.d -version=$(VER) $(QUIET)$(TIMELIMIT)$(ROOT)/tester_$(patsubst %.done,%, $(notdir $@)) > $@ 2>&1; test $$? -eq $(RETCODE) $(QUIET)test $(HASMAIN) -eq 0 || grep -q main $@ $(QUIET)test $(HASMAIN) -eq 1 || ! grep -q main $@ $(QUIET)test -z "$(TESTTEXT)" || grep -q "$(TESTTEXT) unittests" $@ $(QUIET)test -n "$(TESTTEXT)" || ! grep -q "unittests" $@ + clean: rm -rf $(GENERATED) diff --git a/runtime/druntime/test/uuid/Makefile b/runtime/druntime/test/uuid/Makefile new file mode 100644 index 00000000000..0c52b8f273e --- /dev/null +++ b/runtime/druntime/test/uuid/Makefile @@ -0,0 +1,10 @@ +include ../common.mak + +.PHONY: all clean +all: $(ROOT)/test$(DOTEXE) + +$(ROOT)/%$(DOTEXE): %.d + $(QUIET)$(DMD) $(DFLAGS) -of$@ $< uuid.lib + +clean: + rm -rf $(ROOT) diff --git a/runtime/druntime/test/uuid/win64.mak b/runtime/druntime/test/uuid/win64.mak deleted file mode 100644 index 19396926293..00000000000 --- a/runtime/druntime/test/uuid/win64.mak +++ /dev/null @@ -1,9 +0,0 @@ -# built from the druntime top-level folder -# to be overwritten by caller -DMD=dmd -MODEL=64 -DRUNTIMELIB=druntime64.lib - -test: - $(DMD) -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIMELIB) test\uuid\test.d uuid.lib - del test.exe test.obj diff --git a/runtime/druntime/test/valgrind/Makefile b/runtime/druntime/test/valgrind/Makefile index 3ac82f72737..47f1792a986 100644 --- a/runtime/druntime/test/valgrind/Makefile +++ b/runtime/druntime/test/valgrind/Makefile @@ -1,8 +1,8 @@ include ../common.mak -TESTS := ok_append no_use_after_free no_oob no_oob_sentinel no_use_after_gc +TESTS:=ok_append no_use_after_free no_oob no_oob_sentinel no_use_after_gc -GC_SRC = \ +GC_SRC:= \ ../../src/core/internal/gc/impl/conservative/gc.d \ ../../src/etc/valgrind/valgrind.d \ ../../src/rt/lifetime.d @@ -10,7 +10,7 @@ GC_SRC = \ .PHONY: all clean all: $(addprefix $(ROOT)/,$(addsuffix .done,$(TESTS))) -$(ROOT)/ok_%.done: $(ROOT)/ok_% +$(ROOT)/ok_%.done: $(ROOT)/ok_%$(DOTEXE) @echo Testing ok_$* $(QUIET)if ! command -v valgrind >/dev/null; then \ echo valgrind not installed, skipping; \ @@ -19,7 +19,7 @@ $(ROOT)/ok_%.done: $(ROOT)/ok_% fi $(QUIET)touch $@ -$(ROOT)/no_%.done: $(ROOT)/no_% +$(ROOT)/no_%.done: $(ROOT)/no_%$(DOTEXE) @echo Testing no_$* $(QUIET)if ! command -v valgrind >/dev/null; then \ echo valgrind not installed, skipping; \ @@ -28,7 +28,8 @@ $(ROOT)/no_%.done: $(ROOT)/no_% fi $(QUIET)touch $@ -$(ROOT)/%: $(SRC)/%.d $(GC_SRC) +$(ROOT)/%$(DOTEXE): $(SRC)/%.d $(GC_SRC) $(QUIET)$(DMD) -debug=VALGRIND -debug=SENTINEL $(DFLAGS) -of$@ $< $(GC_SRC) + clean: rm -rf $(ROOT) diff --git a/runtime/druntime/win32.mak b/runtime/druntime/win32.mak deleted file mode 100644 index 75d7d5e10b0..00000000000 --- a/runtime/druntime/win32.mak +++ /dev/null @@ -1,169 +0,0 @@ -# Makefile to build D runtime library druntime.lib for Win32 OMF -# MS COFF builds use win64.mak for 32 and 64 bit - -# Ignored, only the default value is supported -#MODEL=32omf - -DMD_DIR=..\compiler -BUILD=release -OS=windows -DMD=$(DMD_DIR)\..\generated\$(OS)\$(BUILD)\32\dmd - -# Used for running MASM assembler on .asm files -CC=dmc - -MAKE=make -HOST_DMD=dmd - -DOCDIR=doc -IMPDIR=import - -# For compiling D and ImportC files -DFLAGS=-m32omf -conf= -O -release -preview=dip1000 -preview=fieldwise -preview=dtorfields -inline -w -Isrc -Iimport -# For unittest build -UDFLAGS=-m32omf -conf= -O -release -preview=dip1000 -preview=fieldwise -w -Isrc -Iimport -# Also for unittest build -UTFLAGS=-version=CoreUnittest -unittest -checkaction=context - -CFLAGS= - -DRUNTIME_BASE=druntime -DRUNTIME=lib\$(DRUNTIME_BASE).lib - -DOCFMT= - -target: copydir copy $(DRUNTIME) - -$(mak\COPY) -$(mak\DOCS) -$(mak\SRCS) - -# NOTE: trace.d and cover.d are not necessary for a successful build -# as both are used for debugging features (profiling and coverage) -# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and -# minit.asm is not used by dmd for Linux - -OBJS= errno_c_32omf.obj src\rt\minit.obj -OBJS_TO_DELETE= errno_c_32omf.obj - -######################## Header file copy ############################## - -import: copy - -copydir: - "$(MAKE)" -f mak/WINDOWS copydir DMD="$(DMD)" HOST_DMD="$(HOST_DMD)" MODEL=32 IMPDIR="$(IMPDIR)" - -copy: - "$(MAKE)" -f mak/WINDOWS copy DMD="$(DMD)" HOST_DMD="$(HOST_DMD)" MODEL=32 IMPDIR="$(IMPDIR)" - -################### Win32 Import Libraries ################### - -IMPLIBS= \ - lib\win32\glu32.lib \ - lib\win32\odbc32.lib \ - lib\win32\opengl32.lib \ - lib\win32\rpcrt4.lib \ - lib\win32\shell32.lib \ - lib\win32\version.lib \ - lib\win32\wininet.lib \ - lib\win32\winspool.lib - -implibsdir: - if not exist lib\win32 mkdir lib\win32 - -implibs: implibsdir $(IMPLIBS) - -lib\win32\glu32.lib: def\glu32.def - implib $@ $** - -lib\win32\odbc32.lib: def\odbc32.def - implib $@ $** - -lib\win32\opengl32.lib: def\opengl32.def - implib $@ $** - -lib\win32\rpcrt4.lib: def\rpcrt4.def - implib $@ $** - -lib\win32\shell32.lib: def\shell32.def - implib $@ $** - -lib\win32\version.lib: def\version.def - implib $@ $** - -lib\win32\wininet.lib: def\wininet.def - implib $@ $** - -lib\win32\winspool.lib: def\winspool.def - implib $@ $** - -################### C\ASM Targets ############################ - -errno_c_32omf.obj: src\core\stdc\errno.c - $(DMD) -c -of=$@ $(DFLAGS) -v -P=-I. src\core\stdc\errno.c - -# only rebuild explicitly -rebuild_minit_obj: src\rt\minit.asm - $(CC) -c $(CFLAGS) src\rt\minit.asm - -################### Library generation ######################### - -$(DRUNTIME): $(OBJS) $(SRCS) win32.mak - *$(DMD) -lib -of$(DRUNTIME) -Xfdruntime.json $(DFLAGS) $(SRCS) $(OBJS) - -################### Unittests ######################### -# Unittest are not run because OPTLINK tends to crash when linking -# unittest.exe. Note that the unittests are still run for -m32mscoff -# and -m64 which are configured in win64.mak - -unittest: unittest.obj - @echo "Unittests cannot be linked on Win32 + OMF due to OPTLINK issues" - -# Split compilation into a different step to avoid unnecessary rebuilds -unittest.obj: $(SRCS) win32.mak - *$(DMD) $(UDFLAGS) $(UTFLAGS) -c -of$@ $(SRCS) - -################### tests ###################################### - -test_aa: - $(DMD) -m32omf -conf= -Isrc -defaultlib=$(DRUNTIME) -run test\aa\src\test_aa.d - -test_allocations: - "$(MAKE)" -f test\allocations\win64.mak "DMD=$(DMD)" MODEL=32omf "VCDIR=$(VCDIR)" DRUNTIMELIB=$(DRUNTIME) "CC=$(CC)" test - -test_cpuid: - "$(MAKE)" -f test\cpuid\win64.mak "DMD=$(DMD)" MODEL=32omf "VCDIR=$(VCDIR)" DRUNTIMELIB=$(DRUNTIME) "CC=$(CC)" test - -test_exceptions: - "$(MAKE)" -f test\exceptions\win64.mak "DMD=$(DMD)" MODEL=32omf "VCDIR=$(VCDIR)" DRUNTIMELIB=$(DRUNTIME) "CC=$(CC)" test - -test_hash: - $(DMD) -m32omf -conf= -Isrc -defaultlib=$(DRUNTIME) -run test\hash\src\test_hash.d - -test_gc: - "$(MAKE)" -f test\gc\win64.mak "DMD=$(DMD)" MODEL=32omf "VCDIR=$(VCDIR)" DRUNTIMELIB=$(DRUNTIME) "CC=$(CC)" test - -custom_gc: - $(MAKE) -f test\init_fini\win64.mak "DMD=$(DMD)" MODEL=32omf "VCDIR=$(VCDIR)" DRUNTIMELIB=$(DRUNTIME) "CC=$(CC)" test - -test_shared: - $(MAKE) -f test\shared\win64.mak "DMD=$(DMD)" MODEL=32omf "VCDIR=$(VCDIR)" DRUNTIMELIB=$(DRUNTIME) "CC=$(CC)" test - -test_all: test_aa test_allocations test_cpuid test_exceptions test_hash test_gc custom_gc test_shared - -################### zip/install/clean ########################## - -zip: druntime.zip - -druntime.zip: - del druntime.zip - git ls-tree --name-only -r HEAD >MANIFEST.tmp - zip32 -T -ur druntime @MANIFEST.tmp - del MANIFEST.tmp - -install: druntime.zip - unzip -o druntime.zip -d \dmd2\src\druntime - -clean: - del $(DRUNTIME) $(OBJS_TO_DELETE) - rmdir /S /Q $(DOCDIR) $(IMPDIR) diff --git a/runtime/druntime/win64.mak b/runtime/druntime/win64.mak deleted file mode 100644 index be7a3cae83f..00000000000 --- a/runtime/druntime/win64.mak +++ /dev/null @@ -1,140 +0,0 @@ -# Makefile to build D runtime library lib\druntime64.lib for 64 bit Windows and -# lib\druntime32mscoff.lib for 32 bit Windows. Both are for use with the MSVC toolchain. - -# Determines whether lib\druntime32mscoff.lib is built or lib\druntime64.lib -# Set to `32mscoff` for a 32-bit build, `64` for 64-bit build. -MODEL=64 - -# Assume MSVC cl.exe in PATH is set up for the target MODEL. -# Otherwise set it explicitly, e.g., to `C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx86\x86\cl.exe`. -CC=cl - -DMD_DIR=..\compiler - -BUILD=release -OS=windows - -# The D compiler used to build things -DMD=$(DMD_DIR)\..\generated\$(OS)\$(BUILD)\$(MODEL)\dmd - -DOCDIR=doc -IMPDIR=import - -# Make program to use. Designed to be run with make.exe which can be obtained from -# https://downloads.dlang.org/other/dm857c.zip -MAKE=make - -HOST_DMD=dmd - -DFLAGS=-m$(MODEL) -conf= -O -release -preview=dip1000 -preview=fieldwise -preview=dtorfields -inline -w -Isrc -Iimport -UDFLAGS=-m$(MODEL) -conf= -O -release -preview=dip1000 -preview=fieldwise -w -version=_MSC_VER_$(_MSC_VER) -Isrc -Iimport -DDOCFLAGS=-conf= -c -w -o- -Isrc -Iimport -version=CoreDdoc - -UTFLAGS=-version=CoreUnittest -unittest -checkaction=context - -DRUNTIME_BASE=druntime$(MODEL) -DRUNTIME=lib\$(DRUNTIME_BASE).lib - -DOCFMT= - -target: copydir copy $(DRUNTIME) - -$(mak\COPY) -$(mak\DOCS) -$(mak\SRCS) - -# NOTE: trace.d and cover.d are not necessary for a successful build -# as both are used for debugging features (profiling and coverage) - -OBJS= errno_c_$(MODEL).obj -OBJS_TO_DELETE= errno_c_$(MODEL).obj - -######################## Header file copy ############################## - -import: copy - -copydir: - "$(MAKE)" -f mak/WINDOWS copydir DMD="$(DMD)" HOST_DMD="$(HOST_DMD)" MODEL=$(MODEL) IMPDIR="$(IMPDIR)" - -copy: - "$(MAKE)" -f mak/WINDOWS copy DMD="$(DMD)" HOST_DMD="$(HOST_DMD)" MODEL=$(MODEL) IMPDIR="$(IMPDIR)" - -################### C\ASM Targets ############################ - -# Although dmd is compiling the .c files, the preprocessor used is cl.exe. The INCLUDE -# environment variable needs to be set with the path to the VC system include files. - -errno_c_$(MODEL).obj: src\core\stdc\errno.c - $(DMD) -c -of=$@ $(DFLAGS) -P=-I. src\core\stdc\errno.c - -################### Library generation ######################### - -$(DRUNTIME): $(OBJS) $(SRCS) win64.mak - *"$(DMD)" -lib -of$(DRUNTIME) -Xfdruntime.json $(DFLAGS) $(SRCS) $(OBJS) - -# due to -conf= on the command line, LINKCMD and LIB need to be set in the environment -unittest: $(SRCS) $(DRUNTIME) - *"$(DMD)" $(UDFLAGS) -version=druntime_unittest $(UTFLAGS) -ofunittest.exe -main $(SRCS) $(DRUNTIME) -debuglib=$(DRUNTIME) -defaultlib=$(DRUNTIME) user32.lib - .\unittest.exe - -################### tests ###################################### - -test_uuid: - "$(MAKE)" -f test\uuid\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -test_aa: - "$(DMD)" -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIME) -run test\aa\src\test_aa.d - -test_allocations: - "$(MAKE)" -f test\allocations\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -test_betterc: - "$(MAKE)" -f test\betterc\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -test_betterc_mingw: - "$(MAKE)" -f test\betterc\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) MINGW=_mingw test - -test_cpuid: - "$(MAKE)" -f test\cpuid\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -test_exceptions: - "$(MAKE)" -f test\exceptions\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -test_hash: - "$(DMD)" -m$(MODEL) -conf= -Isrc -defaultlib=$(DRUNTIME) -run test\hash\src\test_hash.d - -test_stdcpp: - setmscver.bat - "$(MAKE)" -f test\stdcpp\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -test_gc: - "$(MAKE)" -f test\gc\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -custom_gc: - $(MAKE) -f test\init_fini\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -test_shared: - $(MAKE) -f test\shared\win64.mak "DMD=$(DMD)" MODEL=$(MODEL) DRUNTIMELIB=$(DRUNTIME) test - -test_common: test_shared test_aa test_allocations test_cpuid test_exceptions test_hash test_gc custom_gc - -test_mingw: test_common test_betterc_mingw - -test_all: test_common test_betterc test_uuid test_stdcpp - -################### zip/install/clean ########################## - -zip: druntime.zip - -druntime.zip: import - del druntime.zip - git ls-tree --name-only -r HEAD >MANIFEST.tmp - zip32 -T -ur druntime @MANIFEST.tmp - del MANIFEST.tmp - -install: druntime.zip - unzip -o druntime.zip -d \dmd2\src\druntime - -clean: - del $(DRUNTIME) $(OBJS_TO_DELETE) - rmdir /S /Q $(DOCDIR) $(IMPDIR) diff --git a/tests/dmd/Makefile b/tests/dmd/Makefile deleted file mode 100644 index 5e2062aca22..00000000000 --- a/tests/dmd/Makefile +++ /dev/null @@ -1,256 +0,0 @@ -$(warning ===== DEPRECATION: test/Makefile is deprecated. Please use test/run.d instead.) - -ifeq (Windows_NT,$(OS)) - ifeq ($(findstring WOW64, $(shell uname)),WOW64) - OS:=windows - MODEL:=64 - else - OS:=windows - MODEL:=32 - endif -endif -ifeq (Win_32,$(OS)) - OS:=windows - MODEL:=32 -endif -ifeq (Win_32_64,$(OS)) - OS:=windows - MODEL:=64 -endif -ifeq (Win_64,$(OS)) - OS:=windows - MODEL:=64 -endif - -include ../src/osmodel.mak - -export OS -BUILD=release - -ifeq (freebsd,$(OS)) - SHELL=/usr/local/bin/bash -else ifeq (openbsd,$(OS)) - SHELL=/usr/local/bin/bash -else ifeq (netbsd,$(OS)) - SHELL=/usr/pkg/bin/bash -else ifeq (dragonflybsd,$(OS)) - SHELL=/usr/local/bin/bash -else - SHELL=/bin/bash -endif -QUIET=@ -BASH_RESULTS_DIR=$(RESULTS_DIR) -export RESULTS_DIR=test_results -export MODEL - -ifeq ($(findstring win,$(OS)),win) - SHELL=bash.exe - BASH_RESULTS_DIR=$(subst /,\\\\,$(RESULTS_DIR)) - - export EXE=.exe - - PIC?=0 - - DRUNTIME_PATH=..\..\druntime - PHOBOS_PATH=..\..\..\phobos - export DFLAGS=-I$(DRUNTIME_PATH)\import -I$(PHOBOS_PATH) - # LDC: don't override crucial LIB environment variable - #export LIB=$(PHOBOS_PATH) - - # auto-tester might run the testsuite with a different $(MODEL) than DMD - # has been compiled with. Hence we manually check which binary exists. - # For windows the $(OS) during build is: `windows` - ifeq (,$(wildcard ../../generated/windows/$(BUILD)/64/dmd$(EXE))) - DMD_MODEL=32 - else - DMD_MODEL=64 - endif - export DMD=../../generated/windows/$(BUILD)/$(DMD_MODEL)/dmd$(EXE) - -else - export EXE= - - # auto-tester might run the testsuite with a different $(MODEL) than DMD - # has been compiled with. Hence we manually check which binary exists. - ifeq (,$(wildcard ../../generated/$(OS)/$(BUILD)/64/dmd)) - DMD_MODEL=32 - else - DMD_MODEL=64 - endif - export DMD=../../generated/$(OS)/$(BUILD)/$(DMD_MODEL)/dmd - - # default to PIC, use PIC=1/0 to en-/disable PIC. - # Note that shared libraries and C files are always compiled with PIC. - ifeq ($(PIC),) - PIC:=1 - endif - ifeq ($(PIC),1) - export PIC_FLAG:=-fPIC - else - export PIC_FLAG:= - endif - - DRUNTIME_PATH=../../druntime - PHOBOS_PATH=../../../phobos - # link against shared libraries (defaults to true on supported platforms, can be overridden w/ make SHARED=0) - SHARED=$(if $(findstring $(OS),linux freebsd),1,) - DFLAGS=-I$(DRUNTIME_PATH)/import -I$(PHOBOS_PATH) -L-L$(PHOBOS_PATH)/generated/$(OS)/$(BUILD)/$(MODEL) - ifeq (1,$(SHARED)) - DFLAGS+=-defaultlib=libphobos2.so -L-rpath=$(PHOBOS_PATH)/generated/$(OS)/$(BUILD)/$(MODEL) - endif - export DFLAGS -endif - -# Try to find a suitable dmd if HOST_DMD is missing -ifeq ($(HOST_DMD),) - # Legacy support, some CI's use HOST_DC instead of HOST_DMD - ifneq ($(HOST_DC),) - $(warning Please use HOST_DMD instead of HOST_DC!) - HOST_DMD = $(HOST_DC) - else - HOST_DMD = dmd - endif -endif - -#### - -export GDB_FLAGS - -# disable tests based on arch -ifeq ($(OS),linux) - ARCH:=$(shell uname -m) - - ifneq (,$(filter arm% aarch64% ppc64le%,$(ARCH))) - # tell d_do_test.d to ignore MODEL - export NO_ARCH_VARIANT=1 - endif -endif - -#### - -# Required version for -lowmem -LOW_MEM_MIN_VERSION = v2.086.0 -VERSION = $(filter v2.%, $(shell $(HOST_DMD) --version 2>/dev/null)) -RUN_FLAGS = -g -i -Itools -version=NoMain - -ifeq ($(VERSION),) - # dmd was not found in $PATH - USE_GENERATED=1 -endif - -# Detect whether the host dmd satisfies MIN_VERSION -ifeq ($(LOW_MEM_MIN_VERSION), $(firstword $(sort $(LOW_MEM_MIN_VERSION) $(VERSION)))) - # dmd found in $PATH is too old - RUN_FLAGS := $(RUN_FLAGS) -lowmem -endif - -ifneq ($(USE_GENERATED),) - # Use the generated dmd instead of the host compiler - HOST_DMD=$(DMD) - RUN_HOST_DMD=$(HOST_DMD) -conf= -else - RUN_HOST_DMD = $(HOST_DMD) -endif - -# Ensure valid paths on windows -export HOST_DMD:=$(subst \,/,$(HOST_DMD)) - -RUNNER:=$(RESULTS_DIR)/run$(EXE) -EXECUTE_RUNNER:=$(RUNNER) --environment - -# N determines the amount of parallel jobs, see ci/run.sh -ifneq ($(N),) - EXECUTE_RUNNER:=$(EXECUTE_RUNNER) --jobs=$N -endif - -# Workaround https://issues.dlang.org/show_bug.cgi?id=23517 -ifeq (osx,$(OS)) - export MACOSX_DEPLOYMENT_TARGET=11 -endif - -ifeq (windows,$(OS)) -all: - echo "Windows builds have been disabled" -else -all: run_tests -endif - -quick: $(RUNNER) - $(EXECUTE_RUNNER) $@ - -clean: - @echo "Removing output directory: $(RESULTS_DIR)" - $(QUIET)if [ -e $(RESULTS_DIR) ]; then rm -rf $(RESULTS_DIR); fi - @echo "Remove coverage listing files: *.lst" - $(QUIET)rm -rf *.lst - @echo "Remove trace files: trace.def, trace.log" - $(QUIET)rm -rf trace.log trace.def - -$(RESULTS_DIR)/.created: - @echo Creating output directory: $(RESULTS_DIR) - $(QUIET)if [ ! -d $(RESULTS_DIR) ]; then mkdir $(RESULTS_DIR); fi - $(QUIET)touch $(RESULTS_DIR)/.created - -run_tests: run_all_tests - -unit_tests: $(RUNNER) - @echo "Running unit tests" - $(EXECUTE_RUNNER) $@ - -run_runnable_tests: $(RUNNER) - $(EXECUTE_RUNNER) $@ - -start_runnable_tests: $(RUNNER) - @echo "Running runnable tests" - $(EXECUTE_RUNNER) run_runnable_tests - -run_runnable_cxx_tests: $(RUNNER) - $(EXECUTE_RUNNER) $@ - -start_runnable_cxx_tests: - @echo "Running runnable_cxx tests" - $(QUIET)$(MAKE) $(DMD_TESTSUITE_MAKE_ARGS) --no-print-directory run_runnable_cxx_tests - -run_compilable_tests: $(RUNNER) - $(EXECUTE_RUNNER) $@ - -start_compilable_tests: $(RUNNER) - @echo "Running compilable tests" - $(EXECUTE_RUNNER) run_compilable_tests - -run_fail_compilation_tests: $(RUNNER) - $(EXECUTE_RUNNER) $@ - -start_fail_compilation_tests: $(RUNNER) - @echo "Running fail compilation tests" - $(EXECUTE_RUNNER) run_fail_compilation_tests - -run_dshell_tests: $(RUNNER) - $(EXECUTE_RUNNER) $@ - -start_dshell_tests: $(RUNNER) - @echo "Running dshell tests" - $(EXECUTE_RUNNER) run_dshell_tests - -run_all_tests: $(RUNNER) - $(EXECUTE_RUNNER) - -start_all_tests: $(RUNNER) - @echo "Running all tests" - $(EXECUTE_RUNNER) all - -$(RESULTS_DIR)/d_do_test$(EXE): tools/d_do_test.d tools/sanitize_json.d $(RESULTS_DIR)/.created - @echo "Building d_do_test tool" - @echo "OS: '$(OS)'" - @echo "MODEL: '$(MODEL)'" - @echo "PIC: '$(PIC_FLAG)'" - $(RUN_HOST_DMD) $(MODEL_FLAG) $(PIC_FLAG) $(RUN_FLAGS) -unittest -run $< - $(RUN_HOST_DMD) $(MODEL_FLAG) $(PIC_FLAG) $(RUN_FLAGS) -od$(RESULTS_DIR) -of$@ $< - -# Build d_do_test here to run it's unittests -# TODO: Migrate this to run.d -$(RUNNER): run.d $(RESULTS_DIR)/d_do_test$(EXE) - $(RUN_HOST_DMD) $(MODEL_FLAG) $(PIC_FLAG) -g -od$(RESULTS_DIR) -of$(RUNNER) -i -release $< - -# run.d is not reentrant because each invocation might attempt to build the required tools -.NOTPARALLEL: diff --git a/tests/dmd/README.md b/tests/dmd/README.md index 19952856d6e..f0827f258f7 100644 --- a/tests/dmd/README.md +++ b/tests/dmd/README.md @@ -204,6 +204,7 @@ Valid platforms: Valid models: - 32 - 32mscoff (windows only) +- 32omf (windows only) - 64 Note that test parameters *MUST* be followed by a colon (intermediate whitespace is allowed). @@ -423,7 +424,7 @@ depend on the current platform and target: Supported conditions: - OS: posix, windows, ... - - Model: 64, 32mscoff and 32 (also matches 32mscoff) + - Model: 64, 32mscoff, 32omf and 32 (also matches 32mscoff + 32omf) $r:$ any text matching (using $ inside of is not supported, use multiple regexes instead) diff --git a/tests/dmd/compilable/cattributes.i b/tests/dmd/compilable/cattributes.i index 60b2f4c8b94..67a38bea8a4 100644 --- a/tests/dmd/compilable/cattributes.i +++ b/tests/dmd/compilable/cattributes.i @@ -31,3 +31,11 @@ int testx(int a, int b, int c, int d, int e, int f) { return a + b + c + d + e + f + abcx + defx() + ghix() + jklx; } + +/*****************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=24094 + +void test24094() { + __declspec(align(16)) short data[64]; +} diff --git a/tests/dmd/compilable/ctod.i b/tests/dmd/compilable/ctod.i index 4c77fabadad..94116aba475 100644 --- a/tests/dmd/compilable/ctod.i +++ b/tests/dmd/compilable/ctod.i @@ -22,6 +22,16 @@ extern (C) int x = void; } Foo abc(); + union S + { + int x = void; + } + alias T = S; + /+enum int __DATE__ = 1+/; + /+enum int __TIME__ = 1+/; + /+enum int __TIMESTAMP__ = 1+/; + /+enum int __EOF__ = 1+/; + /+enum int __VENDOR__ = 1+/; } --- */ @@ -43,3 +53,19 @@ struct Foo { }; struct Foo abc(void); + +// https://issues.dlang.org/show_bug.cgi?id=24276 + +union S +{ + int x; +}; +typedef S T; + +// https://issues.dlang.org/show_bug.cgi?id=24200 + +#define __DATE__ 1 +#define __TIME__ 1 +#define __TIMESTAMP__ 1 +#define __EOF__ 1 +#define __VENDOR__ 1 diff --git a/tests/dmd/compilable/diag20916.d b/tests/dmd/compilable/diag20916.d index ebdf3eec392..1993e0e0200 100644 --- a/tests/dmd/compilable/diag20916.d +++ b/tests/dmd/compilable/diag20916.d @@ -7,7 +7,7 @@ compilable/diag20916.d(42): instantiated from here: `jump1!(Foo)` compilable/diag20916.d(32): Deprecation: function `diag20916.FooBar.toString` is deprecated compilable/diag20916.d(37): instantiated from here: `jump2!(Foo)` compilable/diag20916.d(42): instantiated from here: `jump1!(Foo)` -compilable/diag20916.d(32): Deprecation: template `diag20916.Bar.toString()()` is deprecated +compilable/diag20916.d(32): Deprecation: template `diag20916.Bar.toString()() const` is deprecated compilable/diag20916.d(37): instantiated from here: `jump2!(Bar)` compilable/diag20916.d(43): instantiated from here: `jump1!(Bar)` compilable/diag20916.d(21): Deprecation: variable `diag20916.Something.something` is deprecated diff --git a/tests/dmd/compilable/imports/defines.c b/tests/dmd/compilable/imports/defines.c index 6bd07366544..8a5601a2d08 100644 --- a/tests/dmd/compilable/imports/defines.c +++ b/tests/dmd/compilable/imports/defines.c @@ -26,3 +26,7 @@ _Static_assert(F80 == 9.0L, "9"); #define SSS "hello" _Static_assert(SSS[0] == 'h', "10"); + +#define ABC 12 +#define GHI (size) abbadabba +#define DEF (ABC + 5) diff --git a/tests/dmd/compilable/imports/test24280b.i b/tests/dmd/compilable/imports/test24280b.i new file mode 100644 index 00000000000..2b120e2be33 --- /dev/null +++ b/tests/dmd/compilable/imports/test24280b.i @@ -0,0 +1,37 @@ +struct S; + +struct timespec +{ + int s; +}; + +typedef struct timespec Clock; + +Clock now() +{ + Clock result; + return result; +} + +struct S +{ + Clock clock; +}; + +/* https://issues.dlang.org/show_bug.cgi?id=24303 */ + +typedef struct {} Slice; + +struct Lang +{ + Slice *slices; +}; + +void langmap(struct Lang *self) +{ + Slice slice = *self->slices; +} + +/* https://issues.dlang.org/show_bug.cgi?id=24306 */ + +struct T { }; diff --git a/tests/dmd/compilable/issue16020.d b/tests/dmd/compilable/issue16020.d index cfd078cdcd1..38a5d624320 100644 --- a/tests/dmd/compilable/issue16020.d +++ b/tests/dmd/compilable/issue16020.d @@ -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)); diff --git a/tests/dmd/compilable/issue20339.d b/tests/dmd/compilable/issue20339.d new file mode 100644 index 00000000000..3d5bdd80a02 --- /dev/null +++ b/tests/dmd/compilable/issue20339.d @@ -0,0 +1,44 @@ +/* +TEST_OUTPUT: +--- +4 +false +false +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=20339 + +struct S +{ + pragma(msg, cast(int)S.sizeof); + + this(this){} + ~this(){} + + int f; +} + +static assert(__traits(isPOD, S) == false); + + +pragma(msg, __traits(isPOD, T)); + +struct T +{ + this(this){} + ~this(){} +} + +static assert(__traits(isPOD, T) == false); + + +struct U +{ + pragma(msg, __traits(isPOD, U)); + + this(this){} + ~this(){} +} + +static assert(__traits(isPOD, U) == false); diff --git a/tests/dmd/compilable/previewin.d b/tests/dmd/compilable/previewin.d index 8926fbd6aa7..558005c5280 100644 --- a/tests/dmd/compilable/previewin.d +++ b/tests/dmd/compilable/previewin.d @@ -79,14 +79,11 @@ version (Win64) { void checkReal(in real p) { - // ref for x87 real, value for double-precision real - static assert(__traits(isRef, p) == (real.sizeof > 8)); } struct RGB { ubyte r, g, b; } void checkNonPowerOf2(in RGB p) { - static assert(__traits(isRef, p)); } } else version (X86_64) // Posix x86_64 @@ -94,7 +91,6 @@ else version (X86_64) // Posix x86_64 struct Empty {} // 1 dummy byte passed on the stack void checkEmptyStruct(in Empty p) { - static assert(!__traits(isRef, p)); } static if (is(__vector(double[4]))) @@ -102,7 +98,6 @@ else version (X86_64) // Posix x86_64 struct AvxVectorWrapper { __vector(double[4]) a; } // 256 bits void checkAvxVector(in AvxVectorWrapper p) { - static assert(!__traits(isRef, p)); } } } @@ -111,6 +106,5 @@ else version (AArch64) alias HVA = __vector(float[4])[4]; // can be passed in 4 vector registers void checkHVA(in HVA p) { - static assert(!__traits(isRef, p)); } } diff --git a/tests/dmd/compilable/stdcheaders.c b/tests/dmd/compilable/stdcheaders.c index 63bbcb88caa..49008212a42 100644 --- a/tests/dmd/compilable/stdcheaders.c +++ b/tests/dmd/compilable/stdcheaders.c @@ -25,6 +25,7 @@ #ifndef __APPLE__ // /Applications/Xcode-14.2.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/tgmath.h(39): Error: named parameter required before `...` #include +float x = NAN; #endif #ifndef _MSC_VER // setjmp.h(51): Error: missing tag `identifier` after `struct diff --git a/tests/dmd/compilable/test23214.c b/tests/dmd/compilable/test23214.c index 9aa38bef542..b5b83b66d46 100644 --- a/tests/dmd/compilable/test23214.c +++ b/tests/dmd/compilable/test23214.c @@ -1,3 +1,13 @@ // https://issues.dlang.org/show_bug.cgi?id=23214 typedef unsigned __int64 uintptr_t; + +// https://issues.dlang.org/show_bug.cgi?id=24304 + +__uint16_t u16; +__uint32_t u32; +__uint64_t u64; + +_Static_assert(sizeof(u16) == 2, "1"); +_Static_assert(sizeof(u32) == 4, "2"); +_Static_assert(sizeof(u64) == 8, "3"); diff --git a/tests/dmd/compilable/test23875.c b/tests/dmd/compilable/test23875.c index 6d6f44ec75a..c5ee060cc65 100644 --- a/tests/dmd/compilable/test23875.c +++ b/tests/dmd/compilable/test23875.c @@ -26,3 +26,19 @@ __attribute__((__vector_size__(16))) int pluto(int i) return i ? v1 : v2; } + +// https://issues.dlang.org/show_bug.cgi?id=24125 + +typedef int __i128 __attribute__ ((__vector_size__ (16), __may_alias__)); + +__i128 test1() +{ + return (__i128){ 1, 2, 3, 4 }; +} + +typedef float __m128 __attribute__ ((__vector_size__ (16), __may_alias__)); + +__m128 test2() +{ + return (__m128){ 1, 2, 3, 4 }; +} diff --git a/tests/dmd/compilable/test24069.i b/tests/dmd/compilable/test24069.i new file mode 100644 index 00000000000..881934ffb98 --- /dev/null +++ b/tests/dmd/compilable/test24069.i @@ -0,0 +1,17 @@ + +// https://issues.dlang.org/show_bug.cgi?id=24069 + +typedef void (*fp_t)(int*); + +float parse1(void f(int*)); // float (void (*)(int *)) +float parse2(void (int*)); +typedef int Dat; +float parse3(void (Dat*)); + +void test(float i) +{ + fp_t x; + parse1(x); + parse2(x); + parse3(x); +} diff --git a/tests/dmd/compilable/test24280.i b/tests/dmd/compilable/test24280.i new file mode 100644 index 00000000000..377e6869861 --- /dev/null +++ b/tests/dmd/compilable/test24280.i @@ -0,0 +1,24 @@ +// EXTRA_SOURCES: imports/test24280b.i + +struct timespec +{ + int s; +}; + +/* https://issues.dlang.org/show_bug.cgi?id=24303 */ + +typedef struct {} Slice; + +struct Lang +{ + Slice *slices; +}; + +void langmap(struct Lang *self) +{ + Slice slice = *self->slices; +} + +/* https://issues.dlang.org/show_bug.cgi?id=24306 */ + +struct T; diff --git a/tests/dmd/compilable/test9565.d b/tests/dmd/compilable/test9565.d index 9e3ee6a8170..ef412f7e7d6 100644 --- a/tests/dmd/compilable/test9565.d +++ b/tests/dmd/compilable/test9565.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -o- +// REQUIRED_ARGS: -o- -m32 // PERMUTE_ARGS: template TypeTuple(T...) { alias TypeTuple = T; } @@ -30,7 +30,7 @@ void main() // index == NegExp static assert((arr[-4 ]).stringof == "arr[" ~ castPrefix ~ "-4]"); - static assert((arr[-4U ]).stringof == "arr[4294967292]"); + static assert((arr[-4U ]).stringof == "arr[cast(size_t)4294967292]"); static assert((arr[int.min] ).stringof == "arr[" ~ castPrefix ~ "-2147483648]"); static if (is(size_t == ulong)) { diff --git a/tests/dmd/compilable/testcstuff1.c b/tests/dmd/compilable/testcstuff1.c index 3a1f66358e1..379f4a7a7e9 100644 --- a/tests/dmd/compilable/testcstuff1.c +++ b/tests/dmd/compilable/testcstuff1.c @@ -210,15 +210,16 @@ __declspec(restrict) void* testrestrictdeclspec() // Character literals _Static_assert(sizeof('a') == 4, "ok"); -_Static_assert(sizeof(u'a') == 4, "ok"); +_Static_assert(sizeof(u'a') == 2, "ok"); _Static_assert(sizeof(U'a') == 4, "ok"); _Static_assert('a' == 0x61, "ok"); _Static_assert('ab' == 0x6162, "ok"); _Static_assert('abc' == 0x616263, "ok"); _Static_assert('abcd' == 0x61626364, "ok"); _Static_assert(u'a' == 0x61, "ok"); -_Static_assert(u'ab' == 0x610062, "ok"); +_Static_assert(u'ab' == 0x62, "ok"); _Static_assert(U'a' == 0x61, "ok"); +_Static_assert(U'a' - 500 > 0, "ok"); _Static_assert(u'\u1234' == 0x1234, "ok"); _Static_assert(L'\u1234' == 0x1234, "ok"); diff --git a/tests/dmd/compilable/testdefines.d b/tests/dmd/compilable/testdefines.d index 4507266c751..9dd8cf2af8d 100644 --- a/tests/dmd/compilable/testdefines.d +++ b/tests/dmd/compilable/testdefines.d @@ -12,3 +12,6 @@ static assert(F64 == 8.0); static assert(F80 == 9.0L); static assert(SSS == "hello"); + +static assert(ABC == 12); +static assert(DEF == 17); diff --git a/tests/dmd/fail_compilation/array_bool.d b/tests/dmd/fail_compilation/array_bool.d new file mode 100644 index 00000000000..923766a93fe --- /dev/null +++ b/tests/dmd/fail_compilation/array_bool.d @@ -0,0 +1,22 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/array_bool.d(13): Deprecation: assert condition cannot be a string literal +fail_compilation/array_bool.d(13): If intentional, use `"foo" !is null` instead to preserve behaviour +fail_compilation/array_bool.d(14): Deprecation: static assert condition cannot be a string literal +fail_compilation/array_bool.d(14): If intentional, use `"foo" !is null` instead to preserve behaviour +--- +*/ +void main() +{ + assert("foo"); + static assert("foo"); + + assert("foo".ptr); // OK + static assert("foo".ptr); // OK + + enum e = "bar"; + static assert(e); // OK + assert(e); // OK +} diff --git a/tests/dmd/fail_compilation/b20011.d b/tests/dmd/fail_compilation/b20011.d index 7baad47f378..3ddcdaaf76b 100644 --- a/tests/dmd/fail_compilation/b20011.d +++ b/tests/dmd/fail_compilation/b20011.d @@ -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)` diff --git a/tests/dmd/fail_compilation/compgoto.i b/tests/dmd/fail_compilation/compgoto.i new file mode 100644 index 00000000000..6163ffcca60 --- /dev/null +++ b/tests/dmd/fail_compilation/compgoto.i @@ -0,0 +1,18 @@ +/* TEST_OUTPUT: +--- +fail_compilation/compgoto.i(105): Error: unary `&&` computed goto extension is not supported +fail_compilation/compgoto.i(106): Error: `goto *` computed goto extension is not supported +--- + */ + +// https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html + +#line 100 + +void test() +{ + void *ptr; + foo: + ptr = &&foo; + goto *ptr; +} diff --git a/tests/dmd/fail_compilation/const_ctor.d b/tests/dmd/fail_compilation/const_ctor.d new file mode 100644 index 00000000000..ae37023f0a1 --- /dev/null +++ b/tests/dmd/fail_compilation/const_ctor.d @@ -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); +} diff --git a/tests/dmd/fail_compilation/ctor_attr.d b/tests/dmd/fail_compilation/ctor_attr.d new file mode 100644 index 00000000000..337ded09fd2 --- /dev/null +++ b/tests/dmd/fail_compilation/ctor_attr.d @@ -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); +} diff --git a/tests/dmd/fail_compilation/diag10415.d b/tests/dmd/fail_compilation/diag10415.d index 207f6a4aa15..74444327ecb 100644 --- a/tests/dmd/fail_compilation/diag10415.d +++ b/tests/dmd/fail_compilation/diag10415.d @@ -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 --- diff --git a/tests/dmd/fail_compilation/diag10862.d b/tests/dmd/fail_compilation/diag10862.d index 3e154979e8c..2c9384159ff 100644 --- a/tests/dmd/fail_compilation/diag10862.d +++ b/tests/dmd/fail_compilation/diag10862.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/diag10926.d b/tests/dmd/fail_compilation/diag10926.d index f98a5b27dea..9bad6336d18 100644 --- a/tests/dmd/fail_compilation/diag10926.d +++ b/tests/dmd/fail_compilation/diag10926.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/diag11425.d b/tests/dmd/fail_compilation/diag11425.d index f8edc5c7867..dfcddaa5f67 100644 --- a/tests/dmd/fail_compilation/diag11425.d +++ b/tests/dmd/fail_compilation/diag11425.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/diag11425.d(13): Error: variable `x` is shadowing variable `diag11425.main.x` +fail_compilation/diag11425.d(14): Error: variable `x` is shadowing variable `diag11425.main.x` +fail_compilation/diag11425.d(11): declared here --- */ diff --git a/tests/dmd/fail_compilation/diag14102.d b/tests/dmd/fail_compilation/diag14102.d index e93d40b224e..b88dd7803cf 100644 --- a/tests/dmd/fail_compilation/diag14102.d +++ b/tests/dmd/fail_compilation/diag14102.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/diag4596.d b/tests/dmd/fail_compilation/diag4596.d index f6b49d6bd13..d43342bdc58 100644 --- a/tests/dmd/fail_compilation/diag4596.d +++ b/tests/dmd/fail_compilation/diag4596.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/diag8101b.d b/tests/dmd/fail_compilation/diag8101b.d index a55ef731ad2..626fb827878 100644 --- a/tests/dmd/fail_compilation/diag8101b.d +++ b/tests/dmd/fail_compilation/diag8101b.d @@ -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 diff --git a/tests/dmd/fail_compilation/diagin.d b/tests/dmd/fail_compilation/diagin.d index 1748e92a841..5b8e33162cd 100644 --- a/tests/dmd/fail_compilation/diagin.d +++ b/tests/dmd/fail_compilation/diagin.d @@ -1,5 +1,5 @@ /* -PERMUTE_ARGS: -preview=in +REQUIRED_ARGS: -preview=in TEST_OUTPUT: --- fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()` diff --git a/tests/dmd/fail_compilation/dip1000_deprecation.d b/tests/dmd/fail_compilation/dip1000_deprecation.d deleted file mode 100644 index 77ab52046fc..00000000000 --- a/tests/dmd/fail_compilation/dip1000_deprecation.d +++ /dev/null @@ -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(); -} diff --git a/tests/dmd/fail_compilation/fail10299.d b/tests/dmd/fail_compilation/fail10299.d index f0eaeba821a..d9cfb047724 100644 --- a/tests/dmd/fail_compilation/fail10299.d +++ b/tests/dmd/fail_compilation/fail10299.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/fail110.d b/tests/dmd/fail_compilation/fail110.d index a13922b0fde..4ba2a8c487e 100644 --- a/tests/dmd/fail_compilation/fail110.d +++ b/tests/dmd/fail_compilation/fail110.d @@ -1,9 +1,12 @@ /* TEST_OUTPUT: --- -fail_compilation/fail110.d(16): Error: variable `i` is shadowing variable `fail110.main.i` -fail_compilation/fail110.d(17): Error: variable `i` is shadowing variable `fail110.main.i` -fail_compilation/fail110.d(18): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(19): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here +fail_compilation/fail110.d(20): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here +fail_compilation/fail110.d(21): Error: variable `i` is shadowing variable `fail110.main.i` +fail_compilation/fail110.d(17): declared here --- */ diff --git a/tests/dmd/fail_compilation/fail13116.d b/tests/dmd/fail_compilation/fail13116.d index ac520d79997..156da435c7b 100644 --- a/tests/dmd/fail_compilation/fail13116.d +++ b/tests/dmd/fail_compilation/fail13116.d @@ -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 diff --git a/tests/dmd/fail_compilation/fail13336a.d b/tests/dmd/fail_compilation/fail13336a.d index e3f990c2fdf..6307e902551 100644 --- a/tests/dmd/fail_compilation/fail13336a.d +++ b/tests/dmd/fail_compilation/fail13336a.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/fail13336b.d b/tests/dmd/fail_compilation/fail13336b.d index b8fb12d1427..f8959a2183c 100644 --- a/tests/dmd/fail_compilation/fail13336b.d +++ b/tests/dmd/fail_compilation/fail13336b.d @@ -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) diff --git a/tests/dmd/fail_compilation/fail17491.d b/tests/dmd/fail_compilation/fail17491.d index 0fb9708b430..718948c2832 100644 --- a/tests/dmd/fail_compilation/fail17491.d +++ b/tests/dmd/fail_compilation/fail17491.d @@ -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 diff --git a/tests/dmd/fail_compilation/fail19890a.d b/tests/dmd/fail_compilation/fail19890a.d index e5efdd534f1..461950576b5 100644 --- a/tests/dmd/fail_compilation/fail19890a.d +++ b/tests/dmd/fail_compilation/fail19890a.d @@ -1,7 +1,8 @@ -/* DISABLED: LDC // no static array size limits +/* REQUIRED_ARGS: -m32 +DISABLED: LDC // no static array size limits TEST_OUTPUT: --- -fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail19890a.d(8): Error: `void[cast(size_t)4294967295]` size 1 * 4294967295 exceeds 0x7fffffff size limit for static array --- */ diff --git a/tests/dmd/fail_compilation/fail19890b.d b/tests/dmd/fail_compilation/fail19890b.d index 81842fa73ed..a977b1a843e 100644 --- a/tests/dmd/fail_compilation/fail19890b.d +++ b/tests/dmd/fail_compilation/fail19890b.d @@ -1,7 +1,8 @@ -/* DISABLED: LDC // no static array size limits +/* REQUIRED_ARGS: -m32 +DISABLED: LDC // no static array size limits TEST_OUTPUT: --- -fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail19890b.d(8): Error: `void[cast(size_t)4294967294]` size 1 * 4294967294 exceeds 0x7fffffff size limit for static array --- */ diff --git a/tests/dmd/fail_compilation/fail212.d b/tests/dmd/fail_compilation/fail212.d index 5f308638b9c..780cd8279e5 100644 --- a/tests/dmd/fail_compilation/fail212.d +++ b/tests/dmd/fail_compilation/fail212.d @@ -1,10 +1,14 @@ /* TEST_OUTPUT: --- -fail_compilation/fail212.d(14): Error: function `fail212.S.bar` without `this` cannot be `const` +fail_compilation/fail212.d(10): Error: function `fail212.baz` without `this` cannot be `const` +fail_compilation/fail212.d(10): did you mean to use `const(int)` as the return type? +fail_compilation/fail212.d(18): Error: function `fail212.S.bar` without `this` cannot be `const` --- */ +const int baz(); + struct S { void foo() const diff --git a/tests/dmd/fail_compilation/fail21243.d b/tests/dmd/fail_compilation/fail21243.d index 2e170d096c5..0b4117d5bc6 100644 --- a/tests/dmd/fail_compilation/fail21243.d +++ b/tests/dmd/fail_compilation/fail21243.d @@ -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; diff --git a/tests/dmd/fail_compilation/fail217.d b/tests/dmd/fail_compilation/fail217.d index 11ad76fabdc..ecae1a38e6d 100644 --- a/tests/dmd/fail_compilation/fail217.d +++ b/tests/dmd/fail_compilation/fail217.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/fail2195.d b/tests/dmd/fail_compilation/fail2195.d index 0eff0663d4b..6f6cd53b0e3 100644 --- a/tests/dmd/fail_compilation/fail2195.d +++ b/tests/dmd/fail_compilation/fail2195.d @@ -3,7 +3,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail2195.d(16): Deprecation: variable `variable` is shadowing variable `fail2195.main.variable`. Rename the `foreach` variable. +fail_compilation/fail2195.d(17): Deprecation: variable `variable` is shadowing variable `fail2195.main.variable` +fail_compilation/fail2195.d(14): declared here --- */ diff --git a/tests/dmd/fail_compilation/fail24224.d b/tests/dmd/fail_compilation/fail24224.d new file mode 100644 index 00000000000..db87f5305d7 --- /dev/null +++ b/tests/dmd/fail_compilation/fail24224.d @@ -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); +} diff --git a/tests/dmd/fail_compilation/fail24301.d b/tests/dmd/fail_compilation/fail24301.d new file mode 100644 index 00000000000..be09c883e1c --- /dev/null +++ b/tests/dmd/fail_compilation/fail24301.d @@ -0,0 +1,19 @@ +/+ +TEST_OUTPUT: +--- +fail_compilation/fail24301.d(18): Error: function `fail24301.fun(S __param_0)` is not callable using argument types `(S)` +fail_compilation/fail24301.d(18): `ref S(ref S)` copy constructor cannot be used because it is annotated with `@disable` +--- ++/ +struct S +{ + @disable this(ref S); +} + +@safe void fun(S) {} + +@safe void main() +{ + S s; + fun(s); +} diff --git a/tests/dmd/fail_compilation/fail4611.d b/tests/dmd/fail_compilation/fail4611.d index d7d34763fde..6c1d6dab8ee 100644 --- a/tests/dmd/fail_compilation/fail4611.d +++ b/tests/dmd/fail_compilation/fail4611.d @@ -1,7 +1,8 @@ -/* DISABLED: LDC // no arraysize limit to work around an optlink bug (https://issues.dlang.org/show_bug.cgi?id=14859) +/* REQUIRED_ARGS: -m32 +DISABLED: LDC // no arraysize limit to work around an optlink bug (https://issues.dlang.org/show_bug.cgi?id=14859) TEST_OUTPUT: --- -fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array +fail_compilation/fail4611.d(15): Error: `Vec[cast(size_t)2147483647]` size 4 * 2147483647 exceeds 0x7fffffff size limit for static array --- */ diff --git a/tests/dmd/fail_compilation/fail6795.d b/tests/dmd/fail_compilation/fail6795.d index 584a4679ccd..26d44296498 100644 --- a/tests/dmd/fail_compilation/fail6795.d +++ b/tests/dmd/fail_compilation/fail6795.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/fail7424d.d b/tests/dmd/fail_compilation/fail7424d.d index 38f47ba0913..920956bf2f9 100644 --- a/tests/dmd/fail_compilation/fail7424d.d +++ b/tests/dmd/fail_compilation/fail7424d.d @@ -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 diff --git a/tests/dmd/fail_compilation/fail7424e.d b/tests/dmd/fail_compilation/fail7424e.d index e92b4693d51..ddf9d1a89b3 100644 --- a/tests/dmd/fail_compilation/fail7424e.d +++ b/tests/dmd/fail_compilation/fail7424e.d @@ -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 diff --git a/tests/dmd/fail_compilation/fail7424f.d b/tests/dmd/fail_compilation/fail7424f.d index 1af14f83d7e..2f7f8f36153 100644 --- a/tests/dmd/fail_compilation/fail7424f.d +++ b/tests/dmd/fail_compilation/fail7424f.d @@ -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 diff --git a/tests/dmd/fail_compilation/fail7424i.d b/tests/dmd/fail_compilation/fail7424i.d index 6352166add5..4e922d6f5be 100644 --- a/tests/dmd/fail_compilation/fail7424i.d +++ b/tests/dmd/fail_compilation/fail7424i.d @@ -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 diff --git a/tests/dmd/fail_compilation/fail7603a.d b/tests/dmd/fail_compilation/fail7603a.d index 76a92c2b193..a106a566a5c 100644 --- a/tests/dmd/fail_compilation/fail7603a.d +++ b/tests/dmd/fail_compilation/fail7603a.d @@ -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) { } diff --git a/tests/dmd/fail_compilation/fail7603b.d b/tests/dmd/fail_compilation/fail7603b.d index 9b84d3f6a4d..a6524221afd 100644 --- a/tests/dmd/fail_compilation/fail7603b.d +++ b/tests/dmd/fail_compilation/fail7603b.d @@ -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) { } diff --git a/tests/dmd/fail_compilation/fail7603c.d b/tests/dmd/fail_compilation/fail7603c.d index 25a7399dd7a..3d030fc9668 100644 --- a/tests/dmd/fail_compilation/fail7603c.d +++ b/tests/dmd/fail_compilation/fail7603c.d @@ -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; diff --git a/tests/dmd/fail_compilation/fail93.d b/tests/dmd/fail_compilation/fail93.d index b9ad2941be7..29893959b17 100644 --- a/tests/dmd/fail_compilation/fail93.d +++ b/tests/dmd/fail_compilation/fail93.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail93.d(13): Error: variable `i` is shadowing variable `fail93.main.i` +fail_compilation/fail93.d(14): Error: variable `i` is shadowing variable `fail93.main.i` +fail_compilation/fail93.d(13): declared here --- */ diff --git a/tests/dmd/fail_compilation/fail9537.d b/tests/dmd/fail_compilation/fail9537.d index e08badf34a9..4d593e39ddb 100644 --- a/tests/dmd/fail_compilation/fail9537.d +++ b/tests/dmd/fail_compilation/fail9537.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/fail9773.d b/tests/dmd/fail_compilation/fail9773.d index b49ffe13dfc..26447a73914 100644 --- a/tests/dmd/fail_compilation/fail9773.d +++ b/tests/dmd/fail_compilation/fail9773.d @@ -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 = "") diff --git a/tests/dmd/fail_compilation/fail9891.d b/tests/dmd/fail_compilation/fail9891.d index 791e734349f..0c2384fccfa 100644 --- a/tests/dmd/fail_compilation/fail9891.d +++ b/tests/dmd/fail_compilation/fail9891.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/fail_arrayop2.d b/tests/dmd/fail_compilation/fail_arrayop2.d index c3c735ed552..0db6a45c9a2 100644 --- a/tests/dmd/fail_compilation/fail_arrayop2.d +++ b/tests/dmd/fail_compilation/fail_arrayop2.d @@ -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[]` diff --git a/tests/dmd/fail_compilation/fail_scope.d b/tests/dmd/fail_compilation/fail_scope.d index a9e5429366a..9851ffc1c74 100644 --- a/tests/dmd/fail_compilation/fail_scope.d +++ b/tests/dmd/fail_compilation/fail_scope.d @@ -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; } diff --git a/tests/dmd/fail_compilation/failcstuff1.c b/tests/dmd/fail_compilation/failcstuff1.c index 39524cb6a12..0e6e1c85692 100644 --- a/tests/dmd/fail_compilation/failcstuff1.c +++ b/tests/dmd/fail_compilation/failcstuff1.c @@ -17,11 +17,20 @@ fail_compilation/failcstuff1.c(206): Error: storage class not allowed in specifi fail_compilation/failcstuff1.c(207): Error: storage class not allowed in specifier-qualified-list fail_compilation/failcstuff1.c(208): Error: storage class not allowed in specifier-qualified-list fail_compilation/failcstuff1.c(251): Error: identifier or `(` expected +fail_compilation/failcstuff1.c(251): Error: expected identifier for declarator +fail_compilation/failcstuff1.c(251): Error: expected identifier for declaration fail_compilation/failcstuff1.c(252): Error: identifier or `(` expected +fail_compilation/failcstuff1.c(252): Error: expected identifier for declarator +fail_compilation/failcstuff1.c(252): Error: expected identifier for declaration fail_compilation/failcstuff1.c(253): Error: identifier or `(` expected +fail_compilation/failcstuff1.c(253): Error: expected identifier for declarator +fail_compilation/failcstuff1.c(253): Error: expected identifier for declaration fail_compilation/failcstuff1.c(258): Error: identifier or `(` expected +fail_compilation/failcstuff1.c(258): Error: expected identifier for declarator fail_compilation/failcstuff1.c(259): Error: identifier or `(` expected +fail_compilation/failcstuff1.c(259): Error: expected identifier for declarator fail_compilation/failcstuff1.c(260): Error: identifier or `(` expected +fail_compilation/failcstuff1.c(260): Error: expected identifier for declarator fail_compilation/failcstuff1.c(301): Error: illegal type combination fail_compilation/failcstuff1.c(352): Error: found `2` when expecting `:` fail_compilation/failcstuff1.c(352): Error: found `:` instead of statement @@ -39,12 +48,10 @@ fail_compilation/failcstuff1.c(460): Error: variable length arrays are not suppo fail_compilation/failcstuff1.c(460): Error: variable length array used outside of function prototype fail_compilation/failcstuff1.c(461): Error: array type has incomplete element type `int[0]` fail_compilation/failcstuff1.c(462): Error: `=`, `;` or `,` expected to end declaration instead of `const` -fail_compilation/failcstuff1.c(502): Error: identifier or `(` expected -fail_compilation/failcstuff1.c(502): Error: found `;` when expecting `)` -fail_compilation/failcstuff1.c(503): Error: `=`, `;` or `,` expected to end declaration instead of `int` -fail_compilation/failcstuff1.c(504): Error: identifier or `(` expected -fail_compilation/failcstuff1.c(504): Error: found `;` when expecting `)` -fail_compilation/failcstuff1.c(505): Error: `=`, `;` or `,` expected to end declaration instead of `int` +fail_compilation/failcstuff1.c(502): Error: no type-specifier for parameter +fail_compilation/failcstuff1.c(502): Error: found `0` when expecting `,` +fail_compilation/failcstuff1.c(502): Error: expected identifier for declarator +fail_compilation/failcstuff1.c(504): Error: expected identifier for declarator fail_compilation/failcstuff1.c(551): Error: missing comma or semicolon after declaration of `pluto`, found `p` instead fail_compilation/failcstuff1.c(601): Error: `=`, `;` or `,` expected to end declaration instead of `'s'` fail_compilation/failcstuff1.c(652): Error: multiple storage classes in declaration specifiers diff --git a/tests/dmd/fail_compilation/failcstuff2.c b/tests/dmd/fail_compilation/failcstuff2.c index 44fa9e6afcb..fe86b7206ea 100644 --- a/tests/dmd/fail_compilation/failcstuff2.c +++ b/tests/dmd/fail_compilation/failcstuff2.c @@ -1,23 +1,23 @@ // check semantic analysis of C files /* TEST_OUTPUT: --- -fail_compilation/failcstuff2.c(113): Error: `cast(int)var` is not an lvalue and cannot be modified +fail_compilation/failcstuff2.c(113): Error: cannot modify expression `cast(int)var` because it is not an lvalue fail_compilation/failcstuff2.c(114): Error: `sizeof` is not a member of `int` -fail_compilation/failcstuff2.c(115): Error: `cast(short)3` is not an lvalue and cannot be modified +fail_compilation/failcstuff2.c(115): Error: cannot modify expression `cast(short)3` because it is not an lvalue fail_compilation/failcstuff2.c(116): Error: cannot modify constant `4` fail_compilation/failcstuff2.c(117): Error: cannot modify constant `5` -fail_compilation/failcstuff2.c(118): Error: cannot modify constant `6` -fail_compilation/failcstuff2.c(119): Error: `cast(int)var` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(120): Error: `cast(int)var` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(121): Error: `cast(int)var` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(122): Error: `cast(int)var` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(123): Error: `cast(int)var` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(124): Error: `makeS22067().field` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(125): Error: `makeS22067().field` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(126): Error: `makeS22067().field` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(127): Error: `makeS22067().field` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(153): Error: `cast(short)var` is not an lvalue and cannot be modified -fail_compilation/failcstuff2.c(154): Error: `cast(long)var` is not an lvalue and cannot be modified +fail_compilation/failcstuff2.c(118): Error: cannot take address of constant `6` +fail_compilation/failcstuff2.c(119): Error: cannot modify expression `cast(int)var` because it is not an lvalue +fail_compilation/failcstuff2.c(120): Error: cannot modify expression `cast(int)var` because it is not an lvalue +fail_compilation/failcstuff2.c(121): Error: cannot modify expression `cast(int)var` because it is not an lvalue +fail_compilation/failcstuff2.c(122): Error: cannot modify expression `cast(int)var` because it is not an lvalue +fail_compilation/failcstuff2.c(123): Error: cannot take address of expression `cast(int)var` because it is not an lvalue +fail_compilation/failcstuff2.c(124): Error: cannot take address of expression `makeS22067().field` because it is not an lvalue +fail_compilation/failcstuff2.c(125): Error: cannot modify expression `makeS22067().field` because it is not an lvalue +fail_compilation/failcstuff2.c(126): Error: cannot modify expression `makeS22067().field` because it is not an lvalue +fail_compilation/failcstuff2.c(127): Error: cannot modify expression `makeS22067().field` because it is not an lvalue +fail_compilation/failcstuff2.c(153): Error: cannot modify expression `cast(short)var` because it is not an lvalue +fail_compilation/failcstuff2.c(154): Error: cannot modify expression `cast(long)var` because it is not an lvalue fail_compilation/failcstuff2.c(354): Error: variable `arr` cannot be read at compile time fail_compilation/failcstuff2.c(360): Error: variable `str` cannot be read at compile time fail_compilation/failcstuff2.c(352): Error: cannot take address of register variable `reg1` diff --git a/tests/dmd/fail_compilation/ice10419.d b/tests/dmd/fail_compilation/ice10419.d index 827f0451824..fed8c608569 100644 --- a/tests/dmd/fail_compilation/ice10419.d +++ b/tests/dmd/fail_compilation/ice10419.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/ice12841.d b/tests/dmd/fail_compilation/ice12841.d index c5894d2c7ee..343624dbc39 100644 --- a/tests/dmd/fail_compilation/ice12841.d +++ b/tests/dmd/fail_compilation/ice12841.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/ice13459.d b/tests/dmd/fail_compilation/ice13459.d index d34fc60db6a..6998e685a75 100644 --- a/tests/dmd/fail_compilation/ice13459.d +++ b/tests/dmd/fail_compilation/ice13459.d @@ -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 diff --git a/tests/dmd/fail_compilation/ice20264.d b/tests/dmd/fail_compilation/ice20264.d index 0d697e22c9f..df6667d9e4b 100644 --- a/tests/dmd/fail_compilation/ice20264.d +++ b/tests/dmd/fail_compilation/ice20264.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/ice9284.d b/tests/dmd/fail_compilation/ice9284.d index 47fd44c6b01..c9ab014b6e6 100644 --- a/tests/dmd/fail_compilation/ice9284.d +++ b/tests/dmd/fail_compilation/ice9284.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/immutable_ctor.d b/tests/dmd/fail_compilation/immutable_ctor.d new file mode 100644 index 00000000000..408e4027fd6 --- /dev/null +++ b/tests/dmd/fail_compilation/immutable_ctor.d @@ -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; +} diff --git a/tests/dmd/fail_compilation/issue16020.d b/tests/dmd/fail_compilation/issue16020.d index fe4ad78f1ac..79eda2ea08c 100644 --- a/tests/dmd/fail_compilation/issue16020.d +++ b/tests/dmd/fail_compilation/issue16020.d @@ -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(); diff --git a/tests/dmd/fail_compilation/issue20704.d b/tests/dmd/fail_compilation/issue20704.d index 1e1f2e6f34b..ba91b063572 100644 --- a/tests/dmd/fail_compilation/issue20704.d +++ b/tests/dmd/fail_compilation/issue20704.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/misc_parser_err_cov1.d b/tests/dmd/fail_compilation/misc_parser_err_cov1.d index 9de436b0119..a170b77b88c 100644 --- a/tests/dmd/fail_compilation/misc_parser_err_cov1.d +++ b/tests/dmd/fail_compilation/misc_parser_err_cov1.d @@ -7,7 +7,7 @@ fail_compilation/misc_parser_err_cov1.d(30): Error: basic type expected, not `)` fail_compilation/misc_parser_err_cov1.d(31): Error: `__traits(identifier, args...)` expected fail_compilation/misc_parser_err_cov1.d(31): Error: semicolon expected following auto declaration, not `o` fail_compilation/misc_parser_err_cov1.d(31): Error: expression expected, not `)` -fail_compilation/misc_parser_err_cov1.d(32): Error: `type identifier : specialization` expected following `is` +fail_compilation/misc_parser_err_cov1.d(32): Error: expected `(` following `is`, not `;` fail_compilation/misc_parser_err_cov1.d(33): Error: semicolon expected following auto declaration, not `auto` fail_compilation/misc_parser_err_cov1.d(33): Error: found `+` when expecting `(` following `mixin` fail_compilation/misc_parser_err_cov1.d(35): Error: `key:value` expected for associative array literal diff --git a/tests/dmd/fail_compilation/pragmas.d b/tests/dmd/fail_compilation/pragmas.d index 5a4b5d95d07..d967ab5451b 100644 --- a/tests/dmd/fail_compilation/pragmas.d +++ b/tests/dmd/fail_compilation/pragmas.d @@ -5,7 +5,6 @@ TEST_OUTPUT: --- fail_compilation/pragmas.d(103): Error: one boolean expression expected for `pragma(inline)`, not 2 fail_compilation/pragmas.d(108): Error: one boolean expression expected for `pragma(inline)`, not 2 -fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)` --- */ @@ -28,5 +27,5 @@ void test3() void test4() { - pragma(unrecognized, "string"); + pragma(unrecognized, "string"); // permitted, just ignored } diff --git a/tests/dmd/fail_compilation/standalone_modctor.d b/tests/dmd/fail_compilation/standalone_modctor.d new file mode 100644 index 00000000000..cb36ed6b790 --- /dev/null +++ b/tests/dmd/fail_compilation/standalone_modctor.d @@ -0,0 +1,15 @@ +/** +TEST_OUTPUT: +--- +fail_compilation/standalone_modctor.d(11): Error: `@standalone` can only be used on shared static constructors +fail_compilation/standalone_modctor.d(12): Error: a module constructor using `@standalone` must be `@system` or `@trusted` +fail_compilation/standalone_modctor.d(13): Error: a module constructor using `@standalone` must be `@system` or `@trusted` +--- +*/ +import core.attribute : standalone; + +@standalone static this() {} +@standalone shared static this() {} +@standalone shared static this() @safe {} +@standalone shared static this() @trusted {} +@standalone shared static this() @system {} diff --git a/tests/dmd/fail_compilation/staticarrayoverflow.d b/tests/dmd/fail_compilation/staticarrayoverflow.d index 77d20ba168a..4b730304273 100644 --- a/tests/dmd/fail_compilation/staticarrayoverflow.d +++ b/tests/dmd/fail_compilation/staticarrayoverflow.d @@ -2,13 +2,13 @@ REQUIRED_ARGS: -m64 TEST_OUTPUT: --- -fail_compilation/staticarrayoverflow.d(23): Error: static array `S[1879048192]` size overflowed to 7516192768000 +fail_compilation/staticarrayoverflow.d(23): Error: static array `S[cast(size_t)1879048192]` size overflowed to 7516192768000 fail_compilation/staticarrayoverflow.d(23): Error: variable `staticarrayoverflow.y` size overflow -fail_compilation/staticarrayoverflow.d(25): Error: static array `S[8070450532247928832]` size overflowed to 8070450532247928832 +fail_compilation/staticarrayoverflow.d(25): Error: static array `S[cast(size_t)8070450532247928832]` size overflowed to 8070450532247928832 fail_compilation/staticarrayoverflow.d(25): Error: variable `staticarrayoverflow.a` size overflow fail_compilation/staticarrayoverflow.d(26): Error: static array `S[0][18446744073709551615LU]` size overflowed to 18446744073709551615 fail_compilation/staticarrayoverflow.d(26): Error: variable `staticarrayoverflow.b` size overflow -fail_compilation/staticarrayoverflow.d(27): Error: static array `S[0][4294967295]` size overflowed to 4294967295 +fail_compilation/staticarrayoverflow.d(27): Error: static array `S[0][cast(size_t)4294967295]` size overflowed to 4294967295 fail_compilation/staticarrayoverflow.d(27): Error: variable `staticarrayoverflow.c` size overflow --- */ diff --git a/tests/dmd/fail_compilation/test16381.d b/tests/dmd/fail_compilation/test16381.d index fd92798366c..5847e0459b6 100644 --- a/tests/dmd/fail_compilation/test16381.d +++ b/tests/dmd/fail_compilation/test16381.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/test22048.d b/tests/dmd/fail_compilation/test22048.d index e0560689f8d..72b91546a2b 100644 --- a/tests/dmd/fail_compilation/test22048.d +++ b/tests/dmd/fail_compilation/test22048.d @@ -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` --- */ diff --git a/tests/dmd/fail_compilation/test22070.c b/tests/dmd/fail_compilation/test22070.c index 3387ccef682..0aa32b23287 100644 --- a/tests/dmd/fail_compilation/test22070.c +++ b/tests/dmd/fail_compilation/test22070.c @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test22070.c(10): Error: `&""` is not an lvalue and cannot be modified +fail_compilation/test22070.c(10): Error: cannot take address of expression `&""` because it is not an lvalue --- */ diff --git a/tests/dmd/fail_compilation/test22102.c b/tests/dmd/fail_compilation/test22102.c index 25596b6e18d..8714d633209 100644 --- a/tests/dmd/fail_compilation/test22102.c +++ b/tests/dmd/fail_compilation/test22102.c @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/test22102.c(254): Error: identifier or `(` expected -fail_compilation/test22102.c(254): Error: found `;` when expecting `)` -fail_compilation/test22102.c(255): Error: `=`, `;` or `,` expected to end declaration instead of `int22102` +fail_compilation/test22102.c(254): Error: expected identifier for declarator +fail_compilation/test22102.c(255): Error: no type-specifier for parameter +fail_compilation/test22102.c(255): Error: found `0` when expecting `,` +fail_compilation/test22102.c(255): Error: expected identifier for declarator --- */ /***************************************************/ diff --git a/tests/dmd/fail_compilation/test22339.c b/tests/dmd/fail_compilation/test22339.c index 14e4c7f2e89..f46f35805c8 100644 --- a/tests/dmd/fail_compilation/test22339.c +++ b/tests/dmd/fail_compilation/test22339.c @@ -3,10 +3,14 @@ fail_compilation/test22339.c(101): Error: expression expected, not `.` fail_compilation/test22339.c(101): Error: found `'a'` when expecting `}` fail_compilation/test22339.c(101): Error: identifier or `(` expected +fail_compilation/test22339.c(101): Error: expected identifier for declarator +fail_compilation/test22339.c(101): Error: expected identifier for declaration fail_compilation/test22339.c(101): Error: `=`, `;` or `,` expected to end declaration instead of `}` fail_compilation/test22339.c(102): Error: expression expected, not `.` fail_compilation/test22339.c(102): Error: found `'\x03'` when expecting `}` fail_compilation/test22339.c(102): Error: identifier or `(` expected +fail_compilation/test22339.c(102): Error: expected identifier for declarator +fail_compilation/test22339.c(102): Error: expected identifier for declaration fail_compilation/test22339.c(102): Error: `=`, `;` or `,` expected to end declaration instead of `}` --- */ diff --git a/tests/dmd/fail_compilation/test23037.c b/tests/dmd/fail_compilation/test23037.c index 98beb350ec4..bc2594926c6 100644 --- a/tests/dmd/fail_compilation/test23037.c +++ b/tests/dmd/fail_compilation/test23037.c @@ -11,9 +11,11 @@ fail_compilation/test23037.c(202): Error: no type-specifier for struct member fail_compilation/test23037.c(203): Error: type-specifier omitted before declaration of `x` fail_compilation/test23037.c(204): Error: type-specifier omitted for parameter `x` fail_compilation/test23037.c(205): Error: type-specifier omitted before bit field declaration of `x` -fail_compilation/test23037.c(206): Error: no type-specifier for declarator -fail_compilation/test23037.c(206): Error: found `;` when expecting `)` -fail_compilation/test23037.c(207): Error: `=`, `;` or `,` expected to end declaration instead of `const` +fail_compilation/test23037.c(206): Error: expected identifier for declarator +fail_compilation/test23037.c(206): Error: expected identifier for declaration +fail_compilation/test23037.c(207): Error: no type-specifier for declarator +fail_compilation/test23037.c(207): Error: expected identifier for declarator +fail_compilation/test23037.c(207): Error: expected identifier for declaration --- */ diff --git a/tests/dmd/fail_compilation/test24157.d b/tests/dmd/fail_compilation/test24157.d index 5022014a9a1..d78c9b628ef 100644 --- a/tests/dmd/fail_compilation/test24157.d +++ b/tests/dmd/fail_compilation/test24157.d @@ -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 --- */ diff --git a/tests/dmd/fail_compilation/test24295.d b/tests/dmd/fail_compilation/test24295.d new file mode 100644 index 00000000000..58b6e92df8f --- /dev/null +++ b/tests/dmd/fail_compilation/test24295.d @@ -0,0 +1,13 @@ +// REQUIRED_ARGS: -betterC + +/* +TEST_OUTPUT: +--- +fail_compilation/test24295.d(12): Error: expression `new int[](1$?:32=u|64=LU$)` allocates with the GC and cannot be used with switch `-betterC` +--- +*/ + +void f() +{ + int[] overlaps = new int[1]; +} diff --git a/tests/dmd/fail_compilation/testTypeof.c b/tests/dmd/fail_compilation/testTypeof.c index 4c02b329eba..dd7781fca5f 100644 --- a/tests/dmd/fail_compilation/testTypeof.c +++ b/tests/dmd/fail_compilation/testTypeof.c @@ -1,7 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/testTypeof.c(8): Error: `typeof` operator expects an expression or type name in parentheses -fail_compilation/testTypeof.c(8): Error: identifier or `(` expected +fail_compilation/testTypeof.c(10): Error: `typeof` operator expects an expression or type name in parentheses +fail_compilation/testTypeof.c(10): Error: identifier or `(` expected +fail_compilation/testTypeof.c(10): Error: expected identifier for declarator +fail_compilation/testTypeof.c(10): Error: expected identifier for declaration --- */ diff --git a/tests/dmd/fail_compilation/testrvaluecpctor.d b/tests/dmd/fail_compilation/testrvaluecpctor.d index 50cebabfda4..1173d14480d 100644 --- a/tests/dmd/fail_compilation/testrvaluecpctor.d +++ b/tests/dmd/fail_compilation/testrvaluecpctor.d @@ -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)` --- */ diff --git a/tests/dmd/fail_compilation/tolvalue.d b/tests/dmd/fail_compilation/tolvalue.d new file mode 100644 index 00000000000..e911dff7729 --- /dev/null +++ b/tests/dmd/fail_compilation/tolvalue.d @@ -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++; +} diff --git a/tests/dmd/run.d b/tests/dmd/run.d index a8119367dd5..3bed3fd03fe 100755 --- a/tests/dmd/run.d +++ b/tests/dmd/run.d @@ -50,24 +50,29 @@ immutable slowRunnableTests = [ enum toolsDir = testPath("tools"); -enum TestTools -{ - unitTestRunner = TestTool("unit_test_runner", [toolsDir.buildPath("paths")]), - testRunner = TestTool("d_do_test", ["-I" ~ toolsDir, "-i", "-version=NoMain"]), - jsonSanitizer = TestTool("sanitize_json"), - dshellPrebuilt = TestTool("dshell_prebuilt", null, Yes.linksWithTests), -} +enum TestTool unitTestRunner = { name: "unit_test_runner", extraArgs: [toolsDir.buildPath("paths")] }; +enum TestTool testRunner = { name: "d_do_test", extraArgs: ["-I" ~ toolsDir, "-i", "-version=NoMain"] }; +enum TestTool testRunnerUnittests = { name: "d_do_test-ut", + customSourceFile: toolsDir.buildPath("d_do_test.d"), + extraArgs: testRunner.extraArgs ~ ["-g", "-unittest"], + runAfterBuild: true }; +enum TestTool jsonSanitizer = { name: "sanitize_json" }; +enum TestTool dshellPrebuilt = { name: "dshell_prebuilt", linksWithTests: true }; immutable struct TestTool { /// The name of the tool. string name; + string customSourceFile; + /// Extra arguments that should be supplied to the compiler when compiling the tool. string[] extraArgs; /// Indicates the tool is a binary that links with tests - Flag!"linksWithTests" linksWithTests; + bool linksWithTests; + + bool runAfterBuild; alias name this; } @@ -156,11 +161,11 @@ Options: if (runUnitTests) { - ensureToolsExists(env, TestTools.unitTestRunner); + ensureToolsExists(env, unitTestRunner); return spawnProcess(unitTestRunnerCommand ~ args, env, Config.none, scriptDir).wait(); } - ensureToolsExists(env, EnumMembers!TestTools); + ensureToolsExists(env, unitTestRunner, testRunner, testRunnerUnittests, jsonSanitizer, dshellPrebuilt); if (args == ["tools"]) return 0; @@ -277,55 +282,70 @@ void ensureToolsExists(const string[string] env, const TestTool[] tools ...) foreach (tool; tools.parallel(1)) { string targetBin; - string sourceFile; + string sourceFile = tool.customSourceFile; if (tool.linksWithTests) { targetBin = resultsDir.buildPath(tool).objName; - sourceFile = toolsDir.buildPath(tool, tool ~ ".d"); + if (sourceFile is null) + sourceFile = toolsDir.buildPath(tool, tool ~ ".d"); } else { targetBin = resultsDir.buildPath(tool).exeName; - sourceFile = toolsDir.buildPath(tool ~ ".d"); + if (sourceFile is null) + sourceFile = toolsDir.buildPath(tool ~ ".d"); } if (targetBin.timeLastModified.ifThrown(SysTime.init) >= sourceFile.timeLastModified) + { log("%s is already up-to-date", tool); + continue; + } + + string[] buildCommand; + bool overrideEnv; + if (tool.linksWithTests) + { + // This will compile the dshell library thus needs the actual + // DMD compiler under test + buildCommand = [ + env["DMD"], + "-conf=", + "-m"~env["MODEL"], + "-of" ~ targetBin, + "-c", + sourceFile + ] ~ getPicFlags(env); + overrideEnv = true; + } else { - string[] command; - bool overrideEnv; - if (tool.linksWithTests) - { - // This will compile the dshell library thus needs the actual - // DMD compiler under test - command = [ - env["DMD"], - "-conf=", - "-m"~env["MODEL"], - "-of" ~ targetBin, - "-c", - sourceFile - ] ~ getPicFlags(env); - overrideEnv = true; - } - else - { - string model = env["MODEL"]; - if (model == "32omf") model = "32"; - - command = [ - hostDMD, - "-m"~model, - "-of"~targetBin, - sourceFile - ] ~ getPicFlags(env) ~ tool.extraArgs; - } + string model = env["MODEL"]; + if (model == "32omf") model = "32"; + + buildCommand = [ + hostDMD, + "-m"~model, + "-of"~targetBin, + sourceFile + ] ~ getPicFlags(env) ~ tool.extraArgs; + } - writefln("Executing: %-(%s %)", command); + writefln("Executing: %-(%s %)", buildCommand); + stdout.flush(); + if (spawnProcess(buildCommand, overrideEnv ? env : null).wait) + { + stderr.writefln("failed to build '%s'", targetBin); + atomicOp!"+="(failCount, 1); + continue; + } + + if (tool.runAfterBuild) + { + writefln("Executing: %s", targetBin); stdout.flush(); - if (spawnProcess(command, overrideEnv ? env : null).wait) + if (spawnProcess([targetBin], null).wait) { - stderr.writefln("failed to build '%s'", targetBin); + stderr.writefln("'%s' failed", targetBin); atomicOp!"+="(failCount, 1); } } @@ -398,7 +418,7 @@ Target[] predefinedTargets(string[] targets) Target target = { filename: filename, args: [ - resultsDir.buildPath(TestTools.testRunner.name.exeName), + resultsDir.buildPath(testRunner.name.exeName), Target.normalizedTestName(filename) ] }; diff --git a/tests/dmd/runnable/cov2.d b/tests/dmd/runnable/cov2.d index 90c574b7024..185bb58fdd0 100644 --- a/tests/dmd/runnable/cov2.d +++ b/tests/dmd/runnable/cov2.d @@ -49,6 +49,17 @@ void test3() total += i; } +/***************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24264 +// EXTRA_SOURCES: imports/ccov2.c + +import ccov2; + +int test24264() +{ + return def(); +} + /***************************************************/ void if_false() @@ -66,6 +77,7 @@ int main(string[] args) test1(); test2(); test3(); + test24264(); if_false(); return 0; } diff --git a/tests/dmd/runnable/cstuff4.c b/tests/dmd/runnable/cstuff4.c new file mode 100644 index 00000000000..b4984ee4b81 --- /dev/null +++ b/tests/dmd/runnable/cstuff4.c @@ -0,0 +1,25 @@ +// https://issues.dlang.org/show_bug.cgi?id=24264 + +struct S +{ + int small; + int symbol; +}; + +inline int getSym(struct S self) +{ + return self.symbol; +} + +_Bool + symIs0(struct S self) +{ + return getSym(self) == 0; +} + +int main(void) +{ + struct S s = {0, 0}; + __check(symIs0(s)); + return 0; +} diff --git a/tests/dmd/runnable/extra-files/runnable-cov2.lst b/tests/dmd/runnable/extra-files/runnable-cov2.lst index ee295488a94..14d3f7f26ca 100644 --- a/tests/dmd/runnable/extra-files/runnable-cov2.lst +++ b/tests/dmd/runnable/extra-files/runnable-cov2.lst @@ -47,6 +47,17 @@ 1| long total = 0; 20000002| for (size_t i = 0; i < 10_000_000; i++) 10000000| total += i; + |} + | + |/***************************************************/ + |// https://issues.dlang.org/show_bug.cgi?id=24264 + |// EXTRA_SOURCES: imports/ccov2.c + | + |import ccov2; + | + |int test24264() + |{ + 1| return def(); |} | |/***************************************************/ @@ -66,6 +77,7 @@ 1| test1(); 1| test2(); 1| test3(); + 1| test24264(); 1| if_false(); 1| return 0; |} diff --git a/tests/dmd/runnable/gdb22905.d b/tests/dmd/runnable/gdb22905.d new file mode 100644 index 00000000000..842f61414b1 --- /dev/null +++ b/tests/dmd/runnable/gdb22905.d @@ -0,0 +1,20 @@ +/* +EXTRA_SOURCES: imports/gdb22905b.d imports/gdb22905c.d +REQUIRED_ARGS: -g +GDB_SCRIPT: +--- +b gdb22905c.d:6 +commands +bt +cont +end +run +--- +GDB_MATCH: _D7imports9gdb22905b5funcBFZv .. at runnable/imports/gdb22905b.d:7 +*/ +import imports.gdb22905b; + +void main() +{ + funcB(); +} diff --git a/tests/dmd/runnable/imports/ccov2.c b/tests/dmd/runnable/imports/ccov2.c new file mode 100644 index 00000000000..855002de6eb --- /dev/null +++ b/tests/dmd/runnable/imports/ccov2.c @@ -0,0 +1,7 @@ +int def() +{ + int i; + for (i = 0; i < 10; ++i) + ; + return i; +} diff --git a/tests/dmd/runnable/imports/gdb22905b.d b/tests/dmd/runnable/imports/gdb22905b.d new file mode 100644 index 00000000000..77cd1189666 --- /dev/null +++ b/tests/dmd/runnable/imports/gdb22905b.d @@ -0,0 +1,8 @@ +module imports.gdb22905b; +import imports.gdb22905c; + +pragma(inline, false) +void funcB() +{ + funcC(0); +} diff --git a/tests/dmd/runnable/imports/gdb22905c.d b/tests/dmd/runnable/imports/gdb22905c.d new file mode 100644 index 00000000000..eb26308659c --- /dev/null +++ b/tests/dmd/runnable/imports/gdb22905c.d @@ -0,0 +1,13 @@ +module imports.gdb22905c; + +pragma(inline, false) +void funcC(T)(T param, void delegate() dg = null) +{ + return; +} + +struct S +{ + void function() f; + void *ptr; +} diff --git a/tests/dmd/runnable/imports/standalone_b.d b/tests/dmd/runnable/imports/standalone_b.d new file mode 100644 index 00000000000..bc5500b7b8c --- /dev/null +++ b/tests/dmd/runnable/imports/standalone_b.d @@ -0,0 +1,11 @@ +module standalone_b; + +import standalone_modctor; +import core.attribute : standalone; + +immutable int* y; + +@standalone @system shared static this() +{ + y = new int(2); +} diff --git a/tests/dmd/runnable/initializer.c b/tests/dmd/runnable/initializer.c index d222aa440b9..3f373568711 100644 --- a/tests/dmd/runnable/initializer.c +++ b/tests/dmd/runnable/initializer.c @@ -846,6 +846,30 @@ void test24154() /*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24155 + +struct S24155 { int x, y; }; + +struct S24155 s = { }; + +void abc(int i) +{ + assert(s.x == 0 && s.y == 0, __LINE__); + struct S24155 s1 = { }; + assert(s1.x == 0 && s1.y == 0, __LINE__); + struct S24155 s2 = { { i }, { } }; + assert(s2.x == i && s2.y == 0, __LINE__); + struct S24155 s3 = { { }, { i } }; + assert(s3.x == 0 && s3.y == i, __LINE__); +} + +void test24155() +{ + abc(1); +} + +/*******************************************/ + int main() { test1(); @@ -895,6 +919,7 @@ int main() test22925(); test47(); test24154(); + test24155(); return 0; } diff --git a/tests/dmd/runnable/previewin.d b/tests/dmd/runnable/previewin.d index 117070dfe5e..50f22ee22bf 100644 --- a/tests/dmd/runnable/previewin.d +++ b/tests/dmd/runnable/previewin.d @@ -154,27 +154,25 @@ struct WithDtor @safe pure nothrow @nogc: // By value -void testin1(in uint p) { static assert(!__traits(isRef, p)); } +void testin1(in uint p) { } // By ref because of size -void testin2(in ulong[64] p) { static assert(__traits(isRef, p)); } +void testin2(in ulong[64] p) { } // By value or ref depending on size (or structs always passed by reference) -void testin3(in ValueT p) { static assert(!__traits(isRef, p) || true); } -void testin3(in RefT p) { static assert(__traits(isRef, p)); } +void testin3(in ValueT p) { } +void testin3(in RefT p) { } // By ref because of size (or arrays always passed by reference) -void testin4(in ValueT[64] p) { static assert(__traits(isRef, p)); } -void testin4(in RefT[4] p) { static assert(__traits(isRef, p)); } +void testin4(in ValueT[64] p) { } +void testin4(in RefT[4] p) { } // By ref because of non-copyability -void testin5(in NonCopyable noncopy) { static assert(__traits(isRef, noncopy)); } -static assert(testin5.mangleof == "_D9previewin7testin5FNaNbNiNfIKSQBe11NonCopyableZv"); // incl. `ref` +void testin5(in NonCopyable noncopy) { } // By ref because of postblit -void testin6(in WithPostblit withpostblit) { static assert(__traits(isRef, withpostblit)); } +void testin6(in WithPostblit withpostblit) { } // By ref because of copy ctor -void testin7(in WithCopyCtor withcopy) { static assert(__traits(isRef, withcopy)); } +void testin7(in WithCopyCtor withcopy) { } // By ref because of dtor void testin8(in WithDtor withdtor, scope bool* isTestOver) { - static assert(__traits(isRef, withdtor)); if (isTestOver) *isTestOver = true; } diff --git a/tests/dmd/runnable/standalone_modctor.d b/tests/dmd/runnable/standalone_modctor.d new file mode 100644 index 00000000000..26544076836 --- /dev/null +++ b/tests/dmd/runnable/standalone_modctor.d @@ -0,0 +1,19 @@ +// REQUIRED_ARGS: -Irunnable/imports +// EXTRA_SOURCES: imports/standalone_b.d +// PERMUTE_ARGS: -cov + +import standalone_b; +import core.attribute : standalone; + +immutable int* x; + +@standalone @system shared static this() +{ + x = new int(1); +} + +void main() +{ + assert(*x == 1); + assert(*y == 2); +} diff --git a/tests/dmd/runnable/staticaa.d b/tests/dmd/runnable/staticaa.d index 606b70e908a..e5b25d1f66a 100644 --- a/tests/dmd/runnable/staticaa.d +++ b/tests/dmd/runnable/staticaa.d @@ -154,6 +154,17 @@ void testLocalStatic() @trusted ///////////////////////////////////////////// +// https://issues.dlang.org/show_bug.cgi?id=24311 +enum E : int[int] { x = [123: 456] } + +void testEnumInit() +{ + E e = E.init; + assert(e[123] == 456); +} + +///////////////////////////////////////////// + void main() { testSimple(); @@ -163,4 +174,5 @@ void main() testClassInit(); testImmutable(); testLocalStatic(); + testEnumInit(); } diff --git a/tests/dmd/runnable/test23011.c b/tests/dmd/runnable/test23011.c index e6c320e8cd4..4c49747021e 100644 --- a/tests/dmd/runnable/test23011.c +++ b/tests/dmd/runnable/test23011.c @@ -1,4 +1,4 @@ -/* DISABLED: win32 win32mscoff win64 osx32 osx64 +/* DISABLED: win osx */ /* https://issues.dlang.org/show_bug.cgi?id=23011 diff --git a/tests/dmd/runnable/test24042.c b/tests/dmd/runnable/test24042.c new file mode 100644 index 00000000000..c6cde72c53d --- /dev/null +++ b/tests/dmd/runnable/test24042.c @@ -0,0 +1,138 @@ +// https://issues.dlang.org/show_bug.cgi?id=24031 + +#include + +/**************************************/ + +struct ES { + struct { + char data[24]; + }; + int length; +}; + +struct ES empty = {.data = {1}, .length = 2}; + +void test1() +{ + assert(empty.data[0] == 1); + assert(empty.length == 2); +} + +/**************************************/ + +struct SH { + int k; + struct { + struct { + struct { + int s; + } f; + }; + }; +}; + +struct SH data = (struct SH) { + .k = 1, + {{.f = {.s = 2}}} +}; + +void test2() +{ + assert(data.k == 1); + assert(data.f.s == 2); +} + +/**************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=24266 + +struct S3 +{ + int context[4]; + int id; +}; + +void test3() +{ + struct S3 tn = (struct S3) {{1}, 4}; + assert(tn.context[0] == 1); + assert(tn.context[1] == 0); + assert(tn.context[2] == 0); + assert(tn.context[3] == 0); + assert(tn.id == 4); +} + +/**************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24274 + +struct S0 +{ + struct + { + char short_data[24]; + }; + int length; +}; + +void test4() +{ + struct S0 s0 = { {.short_data = {1}}, .length = 2}; + assert(s0.short_data[0] == 1); + assert(s0.length == 2); +} + +/**************************************/ + +struct S1 +{ + struct + { + int long_data; + char short_data[24]; + }; + int length; +}; + +void test5() +{ + struct S1 s1 = { {.short_data = {7}}, .length = 8}; + assert(s1.long_data == 0); + assert(s1.short_data[0] == 7); + assert(s1.length == 8); +} + +/**************************************/ + +struct S6 +{ + int abc[4]; +}; + +void test6() +{ + struct S6 s = {{4},5,6,7}; + assert(s.abc[0] == 4); + assert(s.abc[1] == 0); + assert(s.abc[2] == 0); + assert(s.abc[3] == 0); + + struct S6 t = {4,{5},6,7}; + assert(t.abc[0] == 4); + assert(t.abc[1] == 5); + assert(t.abc[2] == 6); + assert(t.abc[3] == 7); +} + +/**************************************/ + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + return 0; +} diff --git a/tests/dmd/runnable/testpdb.d b/tests/dmd/runnable/testpdb.d index 99b4d9c9980..f1fc086d81e 100644 --- a/tests/dmd/runnable/testpdb.d +++ b/tests/dmd/runnable/testpdb.d @@ -1156,7 +1156,7 @@ bool openDebugInfo(IDiaDataSource* source, IDiaSession* session, IDiaSymbol* glo { wchar[MAX_PATH] exepath; DWORD len = GetModuleFileNameW(null, exepath.ptr, MAX_PATH); - len < MAX_PATH || assert("executable path too long"); + len < MAX_PATH || assert(false, "executable path too long"); HRESULT hr = CoInitialize(NULL); diff --git a/tests/dmd/runnable_cxx/extra-files/test24292.cpp b/tests/dmd/runnable_cxx/extra-files/test24292.cpp new file mode 100644 index 00000000000..2fab9afbbd8 --- /dev/null +++ b/tests/dmd/runnable_cxx/extra-files/test24292.cpp @@ -0,0 +1,46 @@ +template +struct List +{ + T* begin; +}; + +struct StructWithDestructor +{ + ~StructWithDestructor(); + + int i; +}; + +struct StructWithCopyCtor +{ + StructWithCopyCtor(); + StructWithCopyCtor(const StructWithCopyCtor &other); + + int i; +}; + +StructWithDestructor::~StructWithDestructor() +{ +} + +StructWithCopyCtor::StructWithCopyCtor() +{ +} + +StructWithCopyCtor::StructWithCopyCtor(const StructWithCopyCtor &other) : i(other.i) +{ +} + +StructWithDestructor getStructWithDestructor() +{ + StructWithDestructor r; + r.i = 12345; + return r; +} + +StructWithCopyCtor getStructWithCopyCtor() +{ + StructWithCopyCtor r; + r.i = 54321; + return r; +} diff --git a/tests/dmd/runnable_cxx/test24292.d b/tests/dmd/runnable_cxx/test24292.d new file mode 100644 index 00000000000..b71f925639c --- /dev/null +++ b/tests/dmd/runnable_cxx/test24292.d @@ -0,0 +1,50 @@ +// EXTRA_CPP_SOURCES: test24292.cpp + +extern(C++) struct List(T) +{ + // Any of the following static ifs can trigger the problem. + static if (T.sizeof > 4) {} + static if (__traits(isZeroInit, T)) {} + static if (__traits(isPOD, T)) {} + + T* begin; +} + +extern(C++) struct StructWithDestructor +{ + ~this(); + + alias L = List!StructWithDestructor; + int i; +} + +extern(C++) struct StructWithCopyCtor +{ + this(ref const(StructWithCopyCtor)); + + alias L = List!StructWithCopyCtor; + int i; +} + +extern(D) struct StructWithPostblit +{ + this(this) {} + + alias L = List!StructWithPostblit; + int i; +} + +static assert(!__traits(isPOD, StructWithDestructor)); +static assert(!__traits(isPOD, StructWithCopyCtor)); +static assert(!__traits(isPOD, StructWithPostblit)); + +extern(C++) StructWithDestructor getStructWithDestructor(); +extern(C++) StructWithCopyCtor getStructWithCopyCtor(); + +void main() +{ + StructWithDestructor structWithDestructor = getStructWithDestructor(); + assert(structWithDestructor.i == 12345); + StructWithCopyCtor structWithCopyCtor = getStructWithCopyCtor(); + assert(structWithCopyCtor.i == 54321); +} diff --git a/tests/dmd/tools/d_do_test.d b/tests/dmd/tools/d_do_test.d index 6624379bbdc..ca6c9ab4b47 100755 --- a/tests/dmd/tools/d_do_test.d +++ b/tests/dmd/tools/d_do_test.d @@ -140,7 +140,6 @@ struct EnvData bool coverage_build; /// `COVERAGE`: coverage build, skip linking & executing to save time bool autoUpdate; /// `AUTO_UPDATE`: update `(TEST|RUN)_OUTPUT` on missmatch bool printRuntime; /// `PRINT_RUNTIME`: Print time spent on a single test - bool usingMicrosoftCompiler; /// Using Visual Studio toolchain bool tryDisabled; /// `TRY_DISABLED`:Silently try disabled tests (ignore failure and report success) version (LDC) bool noArchVariant; } @@ -175,6 +174,15 @@ immutable(EnvData) processEnvironment() envData.compiler = "dmd"; //should be replaced for other compilers envData.ccompiler = environment.get("CC"); envData.model = envGetRequired("MODEL"); + if (envData.os == "windows" && envData.model == "32") + { + // FIXME: we need to translate the default 32-bit model (COFF) on Windows to legacy `32mscoff`. + // Reason: OMF-specific tests are currently specified like this: + // DISABLED: win32mscoff win64 … + // and `DISABLED: win32` would disable it for `win32omf` too. + // So we'd need something like an `ENABLED: win32omf` parameter to restrict tests to specific platforms. + envData.model = "32mscoff"; + } envData.required_args = environment.get("REQUIRED_ARGS"); envData.dobjc = environment.get("D_OBJC") == "1"; envData.coverage_build = environment.get("DMD_TEST_COVERAGE") == "1"; @@ -195,7 +203,9 @@ immutable(EnvData) processEnvironment() else if (envData.model == "32omf") envData.ccompiler = "dmc"; else if (envData.model == "64") - envData.ccompiler = `C:\"Program Files (x86)"\"Microsoft Visual Studio 10.0"\VC\bin\amd64\cl.exe`; + envData.ccompiler = "cl"; + else if (envData.model == "32mscoff") + envData.ccompiler = "cl"; else { writeln("Unknown $OS$MODEL combination: ", envData.os, envData.model); @@ -203,8 +213,6 @@ immutable(EnvData) processEnvironment() } } - envData.usingMicrosoftCompiler = envData.ccompiler.toLower.endsWith("cl.exe"); - version (Windows) {} else { version(X86_64) @@ -525,8 +533,8 @@ private bool consumeNextToken(ref string file, const string token, ref const Env file = file.stripLeft!(ch => ch == ' '); // Don't read line breaks // Check if the current environment matches an entry in oss, which can either - // be an OS (e.g. "linux") or a combination of OS + MODEL (e.g. "windows32"). - // The latter is important on windows because m32 might require other + // be an OS (e.g. "linux") or a combination of OS + MODEL (e.g. "windows32omf"). + // The latter is important on windows because m32omf might require other // parameters than m32mscoff/m64. if (!oss.canFind!(o => o.skipOver(envData.os) && (o.empty || o == envData.model))) continue; // Parameter was skipped @@ -648,9 +656,9 @@ string getDisabledReason(string[] disabledPlatforms, const ref EnvData envData) unittest { - immutable EnvData win32 = { os: "windows", model: "32", }; - immutable EnvData win32mscoff = { os: "windows", model: "32mscoff", }; - immutable EnvData win64 = { os: "windows", model: "64", }; + immutable EnvData win32omf = { os: "windows", model: "32omf" }; + immutable EnvData win32mscoff = { os: "windows", model: "32mscoff" }; + immutable EnvData win64 = { os: "windows", model: "64" }; assert(getDisabledReason(null, win64) is null); @@ -661,10 +669,10 @@ unittest assert(getDisabledReason([ "linux", "win32" ], win64) is null); assert(getDisabledReason([ "win32mscoff" ], win32mscoff) == "on win32mscoff"); - assert(getDisabledReason([ "win32mscoff" ], win32) is null); + assert(getDisabledReason([ "win32mscoff" ], win32omf) is null); assert(getDisabledReason([ "win32" ], win32mscoff) == "on win32"); - assert(getDisabledReason([ "win32" ], win32) == "on win32"); + assert(getDisabledReason([ "win32" ], win32omf) == "on win32"); } /** * Reads the test configuration from the source code (using `findTestParameter` and @@ -1155,17 +1163,17 @@ bool collectExtraSources (in string input_dir, in string output_dir, in string[] auto curSrc = input_dir ~ envData.sep ~"extra-files" ~ envData.sep ~ cur; auto curObj = output_dir ~ envData.sep ~ cur ~ envData.obj; string command = quoteSpaces(compiler); - if (envData.usingMicrosoftCompiler) + if (envData.model == "32omf") // dmc.exe { - command ~= ` /c /nologo `~curSrc~` /Fo`~curObj; + command ~= " -c "~curSrc~" -o"~curObj; } - else if (/*LDC*/ envData.noArchVariant || (envData.compiler == "dmd" && envData.os == "windows" && envData.model == "32omf")) + else if (envData.os == "windows") // cl.exe { - command ~= " -c "~curSrc~" -o"~curObj; + command ~= ` /c /nologo `~curSrc~` /Fo`~curObj; } else { - command ~= " -m"~envData.model~" -c "~curSrc~" -o "~curObj; + command ~= (/*LDC*/ envData.noArchVariant ? null : " -m"~envData.model) ~ " -c "~curSrc~" -o "~curObj; } if (cxxflags) command ~= " " ~ cxxflags; @@ -1928,7 +1936,7 @@ int tryMain(string[] args) { toCleanup ~= test_app_dmd; version(Windows) - if (envData.usingMicrosoftCompiler) + if (envData.model != "32omf") { toCleanup ~= test_app_dmd_base ~ to!string(permuteIndex) ~ ".ilk"; toCleanup ~= test_app_dmd_base ~ to!string(permuteIndex) ~ ".pdb"; diff --git a/tests/dmd/unit/compilable/searching.d b/tests/dmd/unit/compilable/searching.d index 2efb4f20b37..5add95dfc8f 100644 --- a/tests/dmd/unit/compilable/searching.d +++ b/tests/dmd/unit/compilable/searching.d @@ -8,6 +8,7 @@ module compilable.searching; import support : afterEach, beforeEach, compiles; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.dclass : ClassDeclaration; import dmd.declaration : VarDeclaration; import dmd.dtemplate : TemplateDeclaration; @@ -174,7 +175,7 @@ Dsymbol findSymbol(Dsymbol sym, string name, bool allowMissing = false) const oldErrors = global.errors; Identifier id = Identifier.idPool(name); - Dsymbol found = sym.search(Loc.initial, id, IgnoreErrors); + Dsymbol found = sym.search(Loc.initial, id, SearchOpt.ignoreErrors); assert(global.errors == oldErrors, "Searching " ~ name ~ " caused errors!"); assert(allowMissing || found, name ~ " not found!"); diff --git a/tests/dmd/unit/deinitialization.d b/tests/dmd/unit/deinitialization.d index d3458802af9..e96d9558ce9 100644 --- a/tests/dmd/unit/deinitialization.d +++ b/tests/dmd/unit/deinitialization.d @@ -123,8 +123,7 @@ unittest @("Expression.deinitialize") unittest { - import dmd.ctfeexpr : CTFEExp; - import dmd.expression : Expression; + import dmd.expression : Expression, CTFEExp; static void assertInitialState() { diff --git a/tests/dmd/unit/semantic/covariance.d b/tests/dmd/unit/semantic/covariance.d index e68742cd22c..dc2123146d9 100644 --- a/tests/dmd/unit/semantic/covariance.d +++ b/tests/dmd/unit/semantic/covariance.d @@ -7,6 +7,7 @@ module semantic.covariance; import dmd.astenums : STC, StorageClass; import dmd.func : FuncDeclaration; import dmd.mtype : Covariant, Type; +import dmd.typesem : covariant; import support;