aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2023-07-09 22:08:36 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2023-07-09 22:08:36 +0200
commit3b007164b3ef114c3c86c42ca2455f8f2696fb0d (patch)
tree340037c67d4a2a57774103d54fa103390611f6e5 /gcc
parentd6c1d7c4009bfe759719675ce3bc03ca503b9bf4 (diff)
downloadgcc-3b007164b3ef114c3c86c42ca2455f8f2696fb0d.zip
gcc-3b007164b3ef114c3c86c42ca2455f8f2696fb0d.tar.gz
gcc-3b007164b3ef114c3c86c42ca2455f8f2696fb0d.tar.bz2
d: Merge upstream dmd, druntime 28a3b24c2e, phobos 8ab95ded5.
D front-end changes: - Import dmd v2.104.0-beta.1. - Better error message when attribute inference fails down the call stack. - Using `;' as an empty statement has been turned into an error. - Using `in' parameters with non- `extern(D)' or `extern(C++)' functions is deprecated. - `in ref' on parameters has been deprecated in favor of `-preview=in'. - Throwing `immutable', `const', `inout', and `shared' qualified objects is now deprecated. - User Defined Attributes now parse Template Arguments. D runtime changes: - Import druntime v2.104.0-beta.1. Phobos changes: - Import phobos v2.104.0-beta.1. - Better static assert messages when instantiating `std.algorithm.comparison.clamp' with wrong inputs. - `std.typecons.Rebindable' now supports all types. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 28a3b24c2e. * dmd/VERSION: Bump version to v2.104.0-beta.1. * d-codegen.cc (build_bounds_slice_condition): Update for new front-end interface. * d-lang.cc (d_init_options): Likewise. (d_handle_option): Likewise. (d_post_options): Initialize global.compileEnv. * expr.cc (ExprVisitor::visit (CatExp *)): Replace code generation with new front-end lowering. (ExprVisitor::visit (LoweredAssignExp *)): New method. (ExprVisitor::visit (StructLiteralExp *)): Don't generate static initializer symbols for structs defined in C sources. * runtime.def (ARRAYCATT): Remove. (ARRAYCATNTX): Remove. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 28a3b24c2e. * src/MERGE: Merge upstream phobos 8ab95ded5. gcc/testsuite/ChangeLog: * gdc.dg/rtti1.d: Move array concat testcase to ... * gdc.dg/nogc1.d: ... here. New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/d/d-codegen.cc4
-rw-r--r--gcc/d/d-lang.cc12
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/README.md2
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/aliasthis.d24
-rw-r--r--gcc/d/dmd/apply.d2
-rw-r--r--gcc/d/dmd/astenums.d25
-rw-r--r--gcc/d/dmd/attrib.d27
-rw-r--r--gcc/d/dmd/attrib.h4
-rw-r--r--gcc/d/dmd/blockexit.d110
-rw-r--r--gcc/d/dmd/canthrow.d13
-rw-r--r--gcc/d/dmd/clone.d7
-rw-r--r--gcc/d/dmd/common/string.d34
-rw-r--r--gcc/d/dmd/constfold.d2
-rw-r--r--gcc/d/dmd/cparse.d462
-rw-r--r--gcc/d/dmd/cppmangle.d151
-rw-r--r--gcc/d/dmd/ctfeexpr.d12
-rw-r--r--gcc/d/dmd/dcast.d4
-rw-r--r--gcc/d/dmd/declaration.d18
-rw-r--r--gcc/d/dmd/declaration.h7
-rw-r--r--gcc/d/dmd/dinterpret.d648
-rw-r--r--gcc/d/dmd/dmodule.d39
-rw-r--r--gcc/d/dmd/doc.d2
-rw-r--r--gcc/d/dmd/dscope.d10
-rw-r--r--gcc/d/dmd/dstruct.d16
-rw-r--r--gcc/d/dmd/dsymbol.d2
-rw-r--r--gcc/d/dmd/dsymbol.h2
-rw-r--r--gcc/d/dmd/dsymbolsem.d157
-rw-r--r--gcc/d/dmd/dtemplate.d120
-rw-r--r--gcc/d/dmd/dtoh.d4
-rw-r--r--gcc/d/dmd/errors.d8
-rw-r--r--gcc/d/dmd/errorsink.d20
-rw-r--r--gcc/d/dmd/escape.d2
-rw-r--r--gcc/d/dmd/expression.d512
-rw-r--r--gcc/d/dmd/expression.h58
-rw-r--r--gcc/d/dmd/expressionsem.d345
-rw-r--r--gcc/d/dmd/foreachvar.d2
-rw-r--r--gcc/d/dmd/func.d140
-rw-r--r--gcc/d/dmd/globals.d74
-rw-r--r--gcc/d/dmd/globals.h17
-rw-r--r--gcc/d/dmd/hdrgen.d268
-rw-r--r--gcc/d/dmd/iasm.d19
-rw-r--r--gcc/d/dmd/iasmgcc.d9
-rw-r--r--gcc/d/dmd/id.d15
-rw-r--r--gcc/d/dmd/init.d84
-rw-r--r--gcc/d/dmd/initsem.d35
-rw-r--r--gcc/d/dmd/json.d10
-rw-r--r--gcc/d/dmd/lexer.d145
-rw-r--r--gcc/d/dmd/mtype.d146
-rw-r--r--gcc/d/dmd/nogc.d6
-rw-r--r--gcc/d/dmd/ob.d2
-rw-r--r--gcc/d/dmd/opover.d65
-rw-r--r--gcc/d/dmd/optimize.d2
-rw-r--r--gcc/d/dmd/parse.d226
-rw-r--r--gcc/d/dmd/parsetimevisitor.d4
-rw-r--r--gcc/d/dmd/printast.d19
-rw-r--r--gcc/d/dmd/semantic3.d2
-rw-r--r--gcc/d/dmd/sideeffect.d1
-rw-r--r--gcc/d/dmd/statement.d125
-rw-r--r--gcc/d/dmd/statement.h8
-rw-r--r--gcc/d/dmd/statementsem.d884
-rw-r--r--gcc/d/dmd/tokens.d16
-rw-r--r--gcc/d/dmd/tokens.h10
-rw-r--r--gcc/d/dmd/traits.d235
-rw-r--r--gcc/d/dmd/transitivevisitor.d6
-rw-r--r--gcc/d/dmd/typesem.d154
-rw-r--r--gcc/d/dmd/typinf.d1
-rw-r--r--gcc/d/dmd/visitor.d9
-rw-r--r--gcc/d/dmd/visitor.h10
-rw-r--r--gcc/d/expr.cc91
-rw-r--r--gcc/d/runtime.def7
-rw-r--r--gcc/testsuite/gdc.dg/nogc1.d8
-rw-r--r--gcc/testsuite/gdc.dg/rtti1.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_functions.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/c23789.i31
-rw-r--r--gcc/testsuite/gdc.test/compilable/interpret3.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18493.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19688.d (renamed from gcc/testsuite/gdc.test/runnable/test19688.d)0
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21667.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test23789.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/test23862.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test23863.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/user_defined_attributes.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/warn3882.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nogc.d56
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nothrow.d45
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_pure.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/bug9631.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecatedinref.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecations_preview_in.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10319.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10415.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag11769.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag14818.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag20268.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8101b.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9312.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9620.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9831.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10968.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11375.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12236.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13120.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13577.d28
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail16600.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17518.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17955.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail196.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19948.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20609.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22202.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail23773.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail23822.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail23826.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail23861.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail332.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375q.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4559.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10651.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11626.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11982.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13225.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice23097.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9540.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parseStc.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/previewin.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retscope2.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retscope6.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/testInference.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d35
-rw-r--r--gcc/testsuite/gdc.test/runnable/eh2.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/link11069z.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/link13415a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/mainx23837.c10
-rw-r--r--gcc/testsuite/gdc.test/runnable/mangle.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/test23837.d15
-rw-r--r--gcc/testsuite/gdc.test/runnable/test42.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/xtest46.d23
153 files changed, 4297 insertions, 2259 deletions
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 9bae060..689d1c5 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -1986,14 +1986,14 @@ build_bounds_slice_condition (SliceExp *se, tree lower, tree upper, tree length)
tree condition = NULL_TREE;
/* Enforces that `upper <= length`. */
- if (!se->upperIsInBounds && length != NULL_TREE)
+ if (!se->upperIsInBounds () && length != NULL_TREE)
condition = fold_build2 (GT_EXPR, d_bool_type, upper, length);
else
length = integer_zero_node;
/* Enforces that `lower <= upper`. No need to check `lower <= length` as
we've already ensured that `upper <= length`. */
- if (!se->lowerIsLessThanUpper)
+ if (!se->lowerIsLessThanUpper ())
{
tree lwr_cond = fold_build2 (GT_EXPR, d_bool_type, lower, upper);
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 235e22a..7cb86bf 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -293,7 +293,7 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options)
/* Set default values. */
global._init ();
- global.vendor = lang_hooks.name;
+ global.compileEnv.vendor = lang_hooks.name;
global.params.argv0 = xstrdup (decoded_options[0].arg);
global.params.errorLimit = flag_max_errors;
@@ -562,7 +562,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.useDIP1021 = value;
global.params.bitfields = value;
global.params.dtorFields = FeatureState::enabled;
- global.params.fieldwise = value;
+ global.params.fieldwise = FeatureState::enabled;
global.params.fixAliasThis = value;
global.params.previewIn = value;
global.params.fix16997 = value;
@@ -594,7 +594,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
case OPT_fpreview_fieldwise:
- global.params.fieldwise = value;
+ global.params.fieldwise = FeatureState::enabled;
break;
case OPT_fpreview_fixaliasthis:
@@ -934,6 +934,12 @@ d_post_options (const char ** fn)
global.params.obj = !flag_syntax_only;
+ /* The front-end parser only has access to `compileEnv', synchronize its
+ fields with params. */
+ global.compileEnv.previewIn = global.params.previewIn;
+ global.compileEnv.ddocOutput = global.params.ddoc.doOutput;
+ global.compileEnv.shortenedMethods = global.params.shortenedMethods;
+
/* Add in versions given on the command line. */
if (global.params.versionids)
{
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 1205cd9..95ea67d 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-a45f4e9f43e9fdbf0b666175e5e66b1ce4f561f6
+28a3b24c2e45de39cd3df528142fd06b6456e8fd
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md
index cecd008..57f56f3 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -19,7 +19,7 @@ this license for that file.
| Folder | Purpose |
|--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [dmd/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd) | The dmd driver and front-end |
-| [dmd/backend/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/backend) | Code generation for x86 or x86-64. Shared by the [Digital Mars C compiler](https://github.com/DigitalMars/Compiler/), but not [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). |
+| [dmd/backend/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/backend) | Code generation for x86 or x86-64. Based on [DMC](https://github.com/DigitalMars/Compiler/)'s backend, but not kept in sync anymore. Not used by [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). |
| [dmd/common/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/common) | Code shared by the front-end and back-end |
| [dmd/root/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/root) | Meant as a portable utility library, but ["it wasn't very good and the only project left using it is dmd"](https://github.com/dlang/dmd/pull/9844#issuecomment-498479516). |
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 8316aaf..7cf9127 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.103.1
+v2.104.0-beta.1
diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d
index ef839fa..ce38459 100644
--- a/gcc/d/dmd/aliasthis.d
+++ b/gcc/d/dmd/aliasthis.d
@@ -78,7 +78,7 @@ extern (C++) final class AliasThis : Dsymbol
* Params:
* sc = context
* e = expression forming the `this`
- * gag = if true do not print errors, return null instead
+ * 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:
@@ -93,7 +93,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
{
Loc loc = e.loc;
Type tthis = (e.op == EXP.type ? e.type : null);
- const flags = DotExpFlag.noAliasThis | (gag ? DotExpFlag.gag : 0);
+ 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)
@@ -200,15 +200,29 @@ bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
/**************************************
* 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
- * t = 'alias this' type
+ * att = type reference used to detect recursion. Should be initialized to `null`.
+ * t = type of 'alias this' rewrite to attempt
*
* Returns:
- * Whether the 'alias this' is recursive or not
+ * `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;
diff --git a/gcc/d/dmd/apply.d b/gcc/d/dmd/apply.d
index 59ba9f5..d18b81f 100644
--- a/gcc/d/dmd/apply.d
+++ b/gcc/d/dmd/apply.d
@@ -170,7 +170,7 @@ public:
{
if (e.stageflags & stageApply)
return;
- int old = e.stageflags;
+ const old = e.stageflags;
e.stageflags |= stageApply;
doCond(e.elements.peekSlice()) || applyTo(e);
e.stageflags = old;
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
index 6e88208..77f36f3 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -214,8 +214,8 @@ enum TY : ubyte
Tmixin,
Tnoreturn,
Ttag,
- TMAX
}
+enum TMAX = TY.max + 1;
alias Tarray = TY.Tarray;
alias Tsarray = TY.Tsarray;
@@ -265,7 +265,6 @@ alias Ttraits = TY.Ttraits;
alias Tmixin = TY.Tmixin;
alias Tnoreturn = TY.Tnoreturn;
alias Ttag = TY.Ttag;
-alias TMAX = TY.TMAX;
enum TFlags
{
@@ -328,6 +327,7 @@ enum VarArg : ubyte
variadic = 1, /// (T t, ...) can be C-style (core.stdc.stdarg) or D-style (core.vararg)
typesafe = 2, /// (T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions
/// or https://dlang.org/spec/function.html#typesafe_variadic_functions
+ KRvariadic = 3, /// K+R C style variadics (no function prototype)
}
/*************************
@@ -339,7 +339,7 @@ enum STMT : ubyte
Error,
Peel,
Exp, DtorExp,
- Compile,
+ Mixin,
Compound, CompoundDeclaration, CompoundAsm,
UnrolledLoop,
Scope,
@@ -439,3 +439,22 @@ enum FileType : ubyte
ddoc, /// Ddoc documentation file (.dd)
c, /// C source file
}
+
+extern (C++) struct structalign_t
+{
+ private:
+ ushort value = 0; // unknown
+ enum STRUCTALIGN_DEFAULT = 1234; // default = match whatever the corresponding C compiler does
+ bool pack; // use #pragma pack semantics
+
+ public:
+ pure @safe @nogc nothrow:
+ bool isDefault() const { return value == STRUCTALIGN_DEFAULT; }
+ void setDefault() { value = STRUCTALIGN_DEFAULT; }
+ bool isUnknown() const { return value == 0; } // value is not set
+ void setUnknown() { value = 0; }
+ void set(uint value) { this.value = cast(ushort)value; }
+ uint get() const { return value; }
+ bool isPack() const { return pack; }
+ void setPack(bool pack) { this.pack = pack; }
+}
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index dbe78ef..c08382c 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -62,6 +62,12 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
this.decl = decl;
}
+ extern (D) this(const ref Loc loc, Dsymbols* decl)
+ {
+ super(loc, null);
+ this.decl = decl;
+ }
+
extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
{
super(loc, ident);
@@ -228,6 +234,12 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration
this.stc = stc;
}
+ extern (D) this(const ref Loc loc, StorageClass stc, Dsymbols* decl)
+ {
+ super(loc, decl);
+ this.stc = stc;
+ }
+
override StorageClassDeclaration syntaxCopy(Dsymbol s)
{
assert(!s);
@@ -1279,7 +1291,8 @@ extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
* mixin("int x");
* https://dlang.org/spec/module.html#mixin-declaration
*/
-extern (C++) final class CompileDeclaration : AttribDeclaration
+// Note: was CompileDeclaration
+extern (C++) final class MixinDeclaration : AttribDeclaration
{
Expressions* exps;
ScopeDsymbol scopesym;
@@ -1288,19 +1301,19 @@ extern (C++) final class CompileDeclaration : AttribDeclaration
extern (D) this(const ref Loc loc, Expressions* exps)
{
super(loc, null, null);
- //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
+ //printf("MixinDeclaration(loc = %d)\n", loc.linnum);
this.exps = exps;
}
- override CompileDeclaration syntaxCopy(Dsymbol s)
+ override MixinDeclaration syntaxCopy(Dsymbol s)
{
- //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
- return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps));
+ //printf("MixinDeclaration::syntaxCopy('%s')\n", toChars());
+ return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps));
}
override void addMember(Scope* sc, ScopeDsymbol sds)
{
- //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
+ //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
this.scopesym = sds;
}
@@ -1314,7 +1327,7 @@ extern (C++) final class CompileDeclaration : AttribDeclaration
return "mixin";
}
- override inout(CompileDeclaration) isCompileDeclaration() inout
+ override inout(MixinDeclaration) isMixinDeclaration() inout
{
return this;
}
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index 113653e..1e75598 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -221,7 +221,7 @@ public:
// Mixin declarations
-class CompileDeclaration final : public AttribDeclaration
+class MixinDeclaration final : public AttribDeclaration
{
public:
Expressions *exps;
@@ -229,7 +229,7 @@ public:
ScopeDsymbol *scopesym;
d_bool compiled;
- CompileDeclaration *syntaxCopy(Dsymbol *s) override;
+ MixinDeclaration *syntaxCopy(Dsymbol *s) override;
void addMember(Scope *sc, ScopeDsymbol *sds) override;
void setScope(Scope *sc) override;
const char *kind() const override;
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index bd5b78e..db738b4 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -63,34 +63,21 @@ enum BE : int
*/
int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
{
- extern (C++) final class BlockExit : Visitor
- {
- alias visit = Visitor.visit;
- public:
- FuncDeclaration func;
- bool mustNotThrow;
- int result;
-
- extern (D) this(FuncDeclaration func, bool mustNotThrow) scope
- {
- this.func = func;
- this.mustNotThrow = mustNotThrow;
- result = BE.none;
- }
+ int result = BE.none;
- override void visit(Statement s)
+ void visitDefaultCase(Statement s)
{
printf("Statement::blockExit(%p)\n", s);
printf("%s\n", s.toChars());
assert(0);
}
- override void visit(ErrorStatement s)
+ void visitError(ErrorStatement s)
{
result = BE.none;
}
- override void visit(ExpStatement s)
+ void visitExp(ExpStatement s)
{
result = BE.fallthru;
if (s.exp)
@@ -115,13 +102,18 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
}
}
- override void visit(CompileStatement s)
+ void visitDtorExp(DtorExpStatement s)
+ {
+ visitExp(s);
+ }
+
+ void visitMixin(MixinStatement s)
{
assert(global.errors);
result = BE.fallthru;
}
- override void visit(CompoundStatement cs)
+ void visitCompound(CompoundStatement cs)
{
//printf("CompoundStatement.blockExit(%p) %d result = x%X\n", cs, cs.statements.length, result);
result = BE.fallthru;
@@ -175,7 +167,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
}
}
- override void visit(UnrolledLoopStatement uls)
+ void visitUnrolledLoop(UnrolledLoopStatement uls)
{
result = BE.fallthru;
foreach (s; *uls.statements)
@@ -190,19 +182,19 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
}
}
- override void visit(ScopeStatement s)
+ void visitScope(ScopeStatement s)
{
//printf("ScopeStatement::blockExit(%p)\n", s.statement);
result = blockExit(s.statement, func, mustNotThrow);
}
- override void visit(WhileStatement s)
+ void visitWhile(WhileStatement s)
{
assert(global.errors);
result = BE.fallthru;
}
- override void visit(DoStatement s)
+ void visitDo(DoStatement s)
{
if (s._body)
{
@@ -227,7 +219,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result &= ~(BE.break_ | BE.continue_);
}
- override void visit(ForStatement s)
+ void visitFor(ForStatement s)
{
result = BE.fallthru;
if (s._init)
@@ -259,7 +251,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result |= canThrow(s.increment, func, mustNotThrow);
}
- override void visit(ForeachStatement s)
+ void visitForeach(ForeachStatement s)
{
result = BE.fallthru;
result |= canThrow(s.aggr, func, mustNotThrow);
@@ -268,13 +260,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result |= blockExit(s._body, func, mustNotThrow) & ~(BE.break_ | BE.continue_);
}
- override void visit(ForeachRangeStatement s)
+ void visitForeachRange(ForeachRangeStatement s)
{
assert(global.errors);
result = BE.fallthru;
}
- override void visit(IfStatement s)
+ void visitIf(IfStatement s)
{
//printf("IfStatement::blockExit(%p)\n", s);
result = BE.none;
@@ -297,24 +289,24 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
//printf("IfStatement::blockExit(%p) = x%x\n", s, result);
}
- override void visit(ConditionalStatement s)
+ void visitConditional(ConditionalStatement s)
{
result = blockExit(s.ifbody, func, mustNotThrow);
if (s.elsebody)
result |= blockExit(s.elsebody, func, mustNotThrow);
}
- override void visit(PragmaStatement s)
+ void visitPragma(PragmaStatement s)
{
result = BE.fallthru;
}
- override void visit(StaticAssertStatement s)
+ void visitStaticAssert(StaticAssertStatement s)
{
result = BE.fallthru;
}
- override void visit(SwitchStatement s)
+ void visitSwitch(SwitchStatement s)
{
result = BE.none;
result |= canThrow(s.condition, func, mustNotThrow);
@@ -332,63 +324,63 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result |= BE.fallthru;
}
- override void visit(CaseStatement s)
+ void visitCase(CaseStatement s)
{
result = blockExit(s.statement, func, mustNotThrow);
}
- override void visit(DefaultStatement s)
+ void visitDefault(DefaultStatement s)
{
result = blockExit(s.statement, func, mustNotThrow);
}
- override void visit(GotoDefaultStatement s)
+ void visitGotoDefault(GotoDefaultStatement s)
{
result = BE.goto_;
}
- override void visit(GotoCaseStatement s)
+ void visitGotoCase(GotoCaseStatement s)
{
result = BE.goto_;
}
- override void visit(SwitchErrorStatement s)
+ void visitSwitchError(SwitchErrorStatement s)
{
// Switch errors are non-recoverable
result = BE.halt;
}
- override void visit(ReturnStatement s)
+ void visitReturn(ReturnStatement s)
{
result = BE.return_;
if (s.exp)
result |= canThrow(s.exp, func, mustNotThrow);
}
- override void visit(BreakStatement s)
+ void visitBreak(BreakStatement s)
{
//printf("BreakStatement::blockExit(%p) = x%x\n", s, s.ident ? BE.goto_ : BE.break_);
result = s.ident ? BE.goto_ : BE.break_;
}
- override void visit(ContinueStatement s)
+ void visitContinue(ContinueStatement s)
{
result = s.ident ? BE.continue_ | BE.goto_ : BE.continue_;
}
- override void visit(SynchronizedStatement s)
+ void visitSynchronized(SynchronizedStatement s)
{
result = blockExit(s._body, func, mustNotThrow);
}
- override void visit(WithStatement s)
+ void visitWith(WithStatement s)
{
result = BE.none;
result |= canThrow(s.exp, func, mustNotThrow);
result |= blockExit(s._body, func, mustNotThrow);
}
- override void visit(TryCatchStatement s)
+ void visitTryCatch(TryCatchStatement s)
{
assert(s._body);
result = blockExit(s._body, func, false);
@@ -428,7 +420,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result |= catchresult;
}
- override void visit(TryFinallyStatement s)
+ void visitTryFinally(TryFinallyStatement s)
{
result = BE.fallthru;
if (s._body)
@@ -470,13 +462,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result |= finalresult & ~BE.fallthru;
}
- override void visit(ScopeGuardStatement s)
+ void visitScopeGuard(ScopeGuardStatement s)
{
// At this point, this statement is just an empty placeholder
result = BE.fallthru;
}
- override void visit(ThrowStatement s)
+ void visitThrow(ThrowStatement s)
{
if (s.internalThrow)
{
@@ -486,16 +478,16 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
return;
}
- result = checkThrow(s.loc, s.exp, mustNotThrow);
+ result = checkThrow(s.loc, s.exp, mustNotThrow, func);
}
- override void visit(GotoStatement s)
+ void visitGoto(GotoStatement s)
{
//printf("GotoStatement::blockExit(%p)\n", s);
result = BE.goto_;
}
- override void visit(LabelStatement s)
+ void visitLabel(LabelStatement s)
{
//printf("LabelStatement::blockExit(%p)\n", s);
result = blockExit(s.statement, func, mustNotThrow);
@@ -503,30 +495,31 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result |= BE.fallthru;
}
- override void visit(CompoundAsmStatement s)
+ void visitCompoundAsm(CompoundAsmStatement s)
{
// Assume the worst
result = BE.fallthru | BE.return_ | BE.goto_ | BE.halt;
if (!(s.stc & STC.nothrow_))
{
- if (mustNotThrow && !(s.stc & STC.nothrow_))
- s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
+ if(func)
+ func.setThrow(s.loc, "`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
+ if (mustNotThrow)
+ s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); // TODO
else
result |= BE.throw_;
}
}
- override void visit(ImportStatement s)
+ void visitImport(ImportStatement s)
{
result = BE.fallthru;
}
- }
if (!s)
return BE.fallthru;
- scope BlockExit be = new BlockExit(func, mustNotThrow);
- s.accept(be);
- return be.result;
+ mixin VisitStatement!void visit;
+ visit.VisitStatement(s);
+ return result;
}
/++
@@ -537,10 +530,11 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
+ loc = location of the `throw`
+ exp = expression yielding the throwable
+ mustNotThrow = inside of a `nothrow` scope?
+ + func = function containing the `throw`
+
+ Returns: `BE.[err]throw` depending on the type of `exp`
+/
-BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow)
+BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow, FuncDeclaration func)
{
import dmd.errors : error;
@@ -554,6 +548,8 @@ BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow)
}
if (mustNotThrow)
loc.error("`%s` is thrown but not caught", exp.type.toChars());
+ else if (func)
+ func.setThrow(loc, "`%s` is thrown but not caught", exp.type);
return BE.throw_;
}
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index 0c237e6..7dfec8a 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -53,7 +53,7 @@ enum CT : BE
*/
extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustNotThrow)
{
- //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
+ //printf("Expression::canThrow(%d) %s\n", mustNotThrow, e.toChars());
// stop walking if we determine this expression can throw
extern (C++) final class CanThrow : StoppableVisitor
{
@@ -76,11 +76,16 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN
{
if (mustNotThrow)
{
- e.error("%s `%s` is not `nothrow`",
- f.kind(), f.toPrettyChars());
+ e.error("%s `%s` is not `nothrow`", f.kind(), f.toPrettyChars());
+ if (!f.isDtorDeclaration())
+ errorSupplementalInferredAttr(f, 10, false, STC.nothrow_);
e.checkOverridenDtor(null, f, dd => dd.type.toTypeFunction().isnothrow, "not nothrow");
}
+ else if (func)
+ {
+ func.setThrowCall(e.loc, f);
+ }
result |= CT.exception;
}
}
@@ -205,7 +210,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN
override void visit(ThrowExp te)
{
- const res = checkThrow(te.loc, te.e1, mustNotThrow);
+ const res = checkThrow(te.loc, te.e1, mustNotThrow, func);
assert((res & ~(CT.exception | CT.error)) == 0);
result |= res;
}
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 19bf83e..60e373c 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -840,7 +840,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
" else " ~
" h = h * 33 + typeid(T).getHash(cast(const void*)&p.tupleof[i]);" ~
"return h;";
- fop.fbody = new CompileStatement(loc, new StringExp(loc, code));
+ fop.fbody = new MixinStatement(loc, new StringExp(loc, code));
Scope* sc2 = sc.push();
sc2.stc = 0;
sc2.linkage = LINK.d;
@@ -1261,8 +1261,9 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
// if this field's postblit is not `nothrow`, add a `scope(failure)`
// block to destroy any prior successfully postblitted fields should
- // this field's postblit fail
- if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow)
+ // this field's postblit fail.
+ // Don't generate it for betterC code since it cannot throw exceptions.
+ if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow && !global.params.betterC)
{
// create a list of destructors that need to be called
Expression[] dtorCalls;
diff --git a/gcc/d/dmd/common/string.d b/gcc/d/dmd/common/string.d
index 1111cec..a1614fd 100644
--- a/gcc/d/dmd/common/string.d
+++ b/gcc/d/dmd/common/string.d
@@ -13,7 +13,7 @@ module dmd.common.string;
nothrow:
/**
-Defines a temporary array using a fixed-length buffer as back store. If the length
+Defines a temporary array of `Element`s using a fixed-length buffer as back store. If the length
of the buffer suffices, it is readily used. Otherwise, `malloc` is used to
allocate memory for the array and `free` is used for deallocation in the
destructor.
@@ -21,19 +21,26 @@ destructor.
This type is meant to use exclusively as an automatic variable. It is not
default constructible or copyable.
*/
-struct SmallBuffer(T)
+struct SmallBuffer(Element)
{
import core.stdc.stdlib : malloc, free;
- private T[] _extent;
+ private Element[] _extent;
private bool needsFree;
nothrow:
+ @nogc:
@disable this(); // no default ctor
- @disable this(ref const SmallBuffer!T); // noncopyable, nonassignable
-
- this(size_t len, T[] buffer)
+ @disable this(ref const SmallBuffer!Element); // noncopyable, nonassignable
+
+ /***********
+ * Construct a SmallBuffer
+ * Params:
+ * len = number of elements in array
+ * buffer = slice to use as backing-store, if len will fit in it
+ */
+ scope this(size_t len, return scope Element[] buffer)
{
if (len <= buffer.length)
{
@@ -41,7 +48,8 @@ struct SmallBuffer(T)
}
else
{
- _extent = (cast(typeof(_extent.ptr)) malloc(len * _extent[0].sizeof))[0 .. len];
+ assert(len < sizeof.max / Element.sizeof);
+ _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len];
_extent.ptr || assert(0, "Out of memory.");
needsFree = true;
}
@@ -54,16 +62,22 @@ struct SmallBuffer(T)
free(_extent.ptr);
}
- void create(size_t len)
+ /******
+ * Resize existing SmallBuffer.
+ * Params:
+ * len = number of elements after resize
+ */
+ scope void create(size_t len)
{
if (len <= _extent.length)
{
- _extent = _extent[0 .. len];
+ _extent = _extent[0 .. len]; // reuse existing storage
}
else
{
__dtor();
- _extent = (cast(typeof(_extent.ptr)) malloc(len * _extent[0].sizeof))[0 .. len];
+ assert(len < sizeof.max / Element.sizeof);
+ _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len];
_extent.ptr || assert(0, "Out of memory.");
needsFree = true;
}
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index e4be63c..415606b 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -1437,7 +1437,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
StringExp es = ue.exp().isStringExp();
es.type = type;
- es.committed = 1;
+ es.committed = true;
}
else
{
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index a18f810..9b7db1f 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -14,22 +14,18 @@
module dmd.cparse;
import core.stdc.stdio;
-import core.stdc.string;
+import core.stdc.string : memcpy;
+
import dmd.astenums;
import dmd.errorsink;
-import dmd.globals;
import dmd.id;
import dmd.identifier;
import dmd.lexer;
import dmd.location;
import dmd.parse;
-import dmd.errors;
import dmd.root.array;
-import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.root.rmem;
-import dmd.root.rootobject;
-import dmd.root.string;
import dmd.tokens;
/***********************************************************
@@ -71,9 +67,10 @@ final class CParser(AST) : Parser!AST
extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
ErrorSink errorSink,
- const ref TARGET target, OutBuffer* defines) scope
+ const ref TARGET target, OutBuffer* defines, const CompileEnv* compileEnv) scope
{
- super(_module, input, doDocComment, errorSink);
+ const bool doUnittests = false;
+ super(_module, input, doDocComment, errorSink, compileEnv, doUnittests);
//printf("CParser.this()\n");
mod = _module;
@@ -202,7 +199,7 @@ final class CParser(AST) : Parser!AST
else if (token.value == TOK.leftCurly)
s = cparseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
else
- s = cparseStatement(ParseStatementFlags.semiOk);
+ s = cparseStatement(0);
s = new AST.LabelStatement(loc, ident, s);
break;
}
@@ -307,6 +304,7 @@ final class CParser(AST) : Parser!AST
case TOK.extern_:
case TOK.static_:
case TOK._Thread_local:
+ case TOK.__thread:
case TOK.auto_:
case TOK.register:
@@ -376,7 +374,7 @@ final class CParser(AST) : Parser!AST
auto statements = new AST.Statements();
while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
{
- statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+ statements.push(cparseStatement(ParseStatementFlags.curlyScope));
}
if (endPtr)
*endPtr = token.ptr;
@@ -510,6 +508,14 @@ final class CParser(AST) : Parser!AST
nextToken();
auto exp = cparseAssignExp();
+ AST.Expression expHigh;
+ if (token.value == TOK.dotDotDot)
+ {
+ /* Case Ranges https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html
+ */
+ nextToken();
+ expHigh = cparseAssignExp();
+ }
check(TOK.colon);
if (flags & ParseStatementFlags.curlyScope)
@@ -517,7 +523,7 @@ final class CParser(AST) : Parser!AST
auto statements = new AST.Statements();
while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
{
- auto cur = cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
+ auto cur = cparseStatement(ParseStatementFlags.curlyScope);
statements.push(cur);
// https://issues.dlang.org/show_bug.cgi?id=21739
@@ -532,10 +538,13 @@ final class CParser(AST) : Parser!AST
}
else
{
- s = cparseStatement(ParseStatementFlags.semi);
+ s = cparseStatement(0);
}
s = new AST.ScopeStatement(loc, s, token.loc);
- s = new AST.CaseStatement(loc, exp, s);
+ if (expHigh)
+ s = new AST.CaseRangeStatement(loc, exp, expHigh, s);
+ else
+ s = new AST.CaseStatement(loc, exp, s);
break;
}
@@ -549,12 +558,12 @@ final class CParser(AST) : Parser!AST
auto statements = new AST.Statements();
while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
{
- statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+ statements.push(cparseStatement(ParseStatementFlags.curlyScope));
}
s = new AST.CompoundStatement(loc, statements);
}
else
- s = cparseStatement(ParseStatementFlags.semi);
+ s = cparseStatement(0);
s = new AST.ScopeStatement(loc, s, token.loc);
s = new AST.DefaultStatement(loc, s);
break;
@@ -604,7 +613,20 @@ final class CParser(AST) : Parser!AST
}
case TOK.asm_:
- s = parseAsm();
+ switch (peekNext())
+ {
+ case TOK.goto_:
+ case TOK.inline:
+ case TOK.volatile:
+ case TOK.leftParenthesis:
+ s = cparseGnuAsm();
+ break;
+
+ default:
+ // ImportC extensions: parse as a D asm block.
+ s = parseAsm();
+ break;
+ }
break;
default:
@@ -777,7 +799,10 @@ final class CParser(AST) : Parser!AST
case TOK.leftParenthesis:
nextToken();
- e = cparseExpression();
+ if (token.value == TOK.leftCurly)
+ e = cparseStatementExpression(); // gcc extension
+ else
+ e = cparseExpression();
check(TOK.rightParenthesis);
break;
@@ -1600,6 +1625,41 @@ final class CParser(AST) : Parser!AST
return e;
}
+ /*****************************
+ * gcc extension: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
+ * Represent as a function literal, then call the function literal.
+ * Parser is on opening curly brace.
+ */
+ private AST.Expression cparseStatementExpression()
+ {
+ AST.ParameterList parameterList;
+ StorageClass stc = 0;
+ const loc = token.loc;
+ typedefTab.push(null);
+ auto fbody = cparseStatement(ParseStatementFlags.scope_);
+ typedefTab.pop(); // end of function scope
+
+ // Rewrite last ExpStatement (if there is one) as a ReturnStatement
+ auto ss = fbody.isScopeStatement();
+ auto cs = ss.statement.isCompoundStatement();
+ assert(cs);
+ if (const len = (*cs.statements).length)
+ {
+ auto s = (*cs.statements)[len - 1];
+ if (auto es = s.isExpStatement())
+ (*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp);
+ }
+
+ auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
+ auto fd = new AST.FuncLiteralDeclaration(loc, token.loc, tf, TOK.delegate_, null, null, 0);
+ fd.fbody = fbody;
+
+ auto fe = new AST.FuncExp(loc, fd);
+ auto args = new AST.Expressions();
+ auto e = new AST.CallExp(loc, fe, args); // call the function literal
+ return e;
+ }
+
//}
/********************************************************************************/
/********************************* Declaration Parser ***************************/
@@ -1660,6 +1720,12 @@ final class CParser(AST) : Parser!AST
auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
(tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) :
new AST.EnumDeclaration(tt.loc, tt.id, tt.base);
+ if (!tt.packalign.isUnknown())
+ {
+ // saw `struct __declspec(align(N)) Tag ...`
+ auto st = stag.isStructDeclaration();
+ st.alignment = tt.packalign;
+ }
stag.members = tt.members;
tt.members = null;
if (!symbols)
@@ -1759,7 +1825,7 @@ final class CParser(AST) : Parser!AST
case TOK.asm_:
case TOK.__attribute__:
if (token.value == TOK.asm_)
- asmName = cparseSimpleAsmExpr();
+ asmName = cparseGnuAsmLabel();
if (token.value == TOK.__attribute__)
{
cparseGnuAttributes(specifier);
@@ -1892,6 +1958,7 @@ final class CParser(AST) : Parser!AST
if (specifier.scw & SCW.x_Thread_local)
error("functions cannot be `_Thread_local`"); // C11 6.7.1-4
auto fd = new AST.FuncDeclaration(token.loc, Loc.initial, id, specifiersToSTC(level, specifier), dt, specifier.noreturn);
+ specifiersToFuncDeclaration(fd, specifier);
s = fd;
}
else
@@ -1901,7 +1968,9 @@ final class CParser(AST) : Parser!AST
if (!hasInitializer &&
!(specifier.scw & (SCW.xextern | SCW.xstatic | SCW.x_Thread_local) || level == LVL.global))
initializer = new AST.VoidInitializer(token.loc);
- s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier));
+ auto vd = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier));
+ specifiersToVarDeclaration(vd, specifier);
+ s = vd;
}
if (level != LVL.global)
insertIdToTypedefTab(id); // non-typedef declarations can hide typedefs in outer scopes
@@ -2012,8 +2081,7 @@ final class CParser(AST) : Parser!AST
auto pl = ft.parameterList;
if (pl.varargs != AST.VarArg.none && pl.length)
error("function identifier-list cannot end with `...`");
- ft.parameterList.varargs = AST.VarArg.variadic; // but C11 allows extra arguments
- importBuiltins = true; // will need __va_list_tag
+ ft.parameterList.varargs = AST.VarArg.KRvariadic; // but C11 allows extra arguments
auto plLength = pl.length;
if (symbols.length != plLength)
error(token.loc, "%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
@@ -2038,6 +2106,10 @@ final class CParser(AST) : Parser!AST
error("storage class and type are not allowed in identifier-list");
foreach (s; (*symbols)[]) // yes, quadratic
{
+ auto ad = s.isAttribDeclaration();
+ if (ad)
+ s = (*ad.decl)[0]; // AlignDeclaration wrapping the declaration
+
auto d = s.isDeclaration();
if (d && p.ident == d.ident && d.type)
{
@@ -2062,6 +2134,7 @@ final class CParser(AST) : Parser!AST
typedefTab.pop(); // end of function scope
auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, specifiersToSTC(LVL.global, specifier), ft, specifier.noreturn);
+ specifiersToFuncDeclaration(fd, specifier);
if (addFuncName)
{
@@ -2234,6 +2307,7 @@ final class CParser(AST) : Parser!AST
case TOK.typedef_: scwx = SCW.xtypedef; break;
case TOK.inline: scwx = SCW.xinline; break;
case TOK._Noreturn: scwx = SCW.x_Noreturn; break;
+ case TOK.__thread:
case TOK._Thread_local: scwx = SCW.x_Thread_local; break;
// Type qualifiers
@@ -2269,15 +2343,23 @@ final class CParser(AST) : Parser!AST
const sloc = token.loc;
nextToken();
+ Specifier tagSpecifier;
+
/* GNU Extensions
* struct-or-union-specifier:
* struct-or-union gnu-attributes (opt) identifier (opt) { struct-declaration-list } gnu-attributes (opt)
* struct-or-union gnu-attribute (opt) identifier
*/
- if (token.value == TOK.__attribute__)
- cparseGnuAttributes(specifier);
-
- t = cparseStruct(sloc, structOrUnion, symbols);
+ while (1)
+ {
+ if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(tagSpecifier);
+ else if (token.value == TOK.__declspec)
+ cparseDeclspec(tagSpecifier);
+ else
+ break;
+ }
+ t = cparseStruct(sloc, structOrUnion, tagSpecifier.packalign, symbols);
tkwx = TKW.xtag;
break;
}
@@ -2298,8 +2380,8 @@ final class CParser(AST) : Parser!AST
if (isTypeName(tk) && tk.value == TOK.rightParenthesis)
{
nextToken();
+ nextToken();
t = cparseTypeName();
- // TODO - implement the "atomic" part of t
tkwx = TKW.x_Atomic;
break;
}
@@ -2468,6 +2550,12 @@ final class CParser(AST) : Parser!AST
error("`inline` and `_Noreturn` function specifiers not allowed for `_Thread_local`");
scw &= ~scwx;
}
+ if (level == LVL.local &&
+ scw & (SCW.x_Thread_local) && !(scw & (SCW.xstatic | SCW.xextern)))
+ {
+ error("`_Thread_local` in block scope must be accompanied with `static` or `extern`"); // C11 6.7.1-3
+ scw &= ~scwx;
+ }
if (level & (LVL.parameter | LVL.prototype) &&
scw & ~SCW.xregister)
{
@@ -2568,6 +2656,7 @@ final class CParser(AST) : Parser!AST
}
case TKW.xtag:
+ case TKW.x_Atomic: // no atomics for you
break; // t is already set
default:
@@ -2806,7 +2895,10 @@ final class CParser(AST) : Parser!AST
auto parameterList = cparseParameterList();
const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
- AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, 0);
+ StorageClass stc = specifier._nothrow ? STC.nothrow_ : 0;
+ if (specifier._pure)
+ stc |= STC.pure_;
+ AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, stc);
// tf = tf.addSTC(storageClass); // TODO
insertTx(ts, tf, t); // ts -> ... -> tf -> t
@@ -2959,8 +3051,7 @@ final class CParser(AST) : Parser!AST
if (token.value == TOK.rightParenthesis) // func()
{
nextToken();
- importBuiltins = true; // will need __va_list_tag
- return AST.ParameterList(parameters, AST.VarArg.variadic, varargsStc);
+ return AST.ParameterList(parameters, AST.VarArg.KRvariadic, varargsStc);
}
/* Create function prototype scope
@@ -3084,9 +3175,15 @@ final class CParser(AST) : Parser!AST
* extended-decl-modifier extended-decl-modifier-seq
*
* extended-decl-modifier:
+ * align(number)
+ * deprecated(depMsg)
* dllimport
* dllexport
+ * naked
+ * noinline
* noreturn
+ * nothrow
+ * thread
* Params:
* specifier = filled in with the attribute(s)
*/
@@ -3096,8 +3193,6 @@ final class CParser(AST) : Parser!AST
/* Check for dllexport, dllimport
* Ignore the rest
*/
- bool dllimport; // TODO implement
- bool dllexport; // TODO implement
nextToken(); // move past __declspec
check(TOK.leftParenthesis);
while (1)
@@ -3113,12 +3208,22 @@ final class CParser(AST) : Parser!AST
{
if (token.ident == Id.dllimport)
{
- dllimport = true;
+ specifier.dllimport = true;
nextToken();
}
else if (token.ident == Id.dllexport)
{
- dllexport = true;
+ specifier.dllexport = true;
+ nextToken();
+ }
+ else if (token.ident == Id.naked)
+ {
+ specifier.naked = true;
+ nextToken();
+ }
+ else if (token.ident == Id.noinline)
+ {
+ specifier.scw |= SCW.xnoinline;
nextToken();
}
else if (token.ident == Id.noreturn)
@@ -3126,6 +3231,49 @@ final class CParser(AST) : Parser!AST
specifier.noreturn = true;
nextToken();
}
+ else if (token.ident == Id._nothrow)
+ {
+ specifier._nothrow = true;
+ nextToken();
+ }
+ else if (token.ident == Id.thread)
+ {
+ specifier.scw |= SCW.x_Thread_local;
+ nextToken();
+ }
+ else if (token.ident == Id._align)
+ {
+ // Microsoft spec is very imprecise as to how this actually works
+ nextToken();
+ check(TOK.leftParenthesis);
+ if (token.value == TOK.int32Literal)
+ {
+ const n = token.unsvalue;
+ if (n < 1 || n & (n - 1) || 8192 < n)
+ error("__decspec(align(%lld)) must be an integer positive power of 2 and be <= 8,192", cast(ulong)n);
+ specifier.packalign.set(cast(uint)n);
+ specifier.packalign.setPack(true);
+ nextToken();
+ }
+ else
+ {
+ error("alignment value expected, not `%s`", token.toChars());
+ nextToken();
+ }
+
+ check(TOK.rightParenthesis);
+ }
+ else if (token.ident == Id._deprecated)
+ {
+ specifier._deprecated = true;
+ nextToken();
+ if (token.value == TOK.leftParenthesis) // optional deprecation message
+ {
+ nextToken();
+ specifier.depMsg = cparseExpression();
+ check(TOK.rightParenthesis);
+ }
+ }
else
{
nextToken();
@@ -3133,6 +3281,8 @@ final class CParser(AST) : Parser!AST
cparseParens();
}
}
+ else if (token.value == TOK.restrict) // ImportC assigns no semantics to `restrict`, so just ignore the keyword.
+ nextToken();
else
{
error("extended-decl-modifier expected");
@@ -3142,7 +3292,8 @@ final class CParser(AST) : Parser!AST
}
/*************************
- * Simple asm parser
+ * Parser for asm label. It appears after the declarator, and has apparently
+ * nothing to do with inline assembler.
* https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html
* simple-asm-expr:
* asm ( asm-string-literal )
@@ -3150,17 +3301,107 @@ final class CParser(AST) : Parser!AST
* asm-string-literal:
* string-literal
*/
- private AST.StringExp cparseSimpleAsmExpr()
+ private AST.StringExp cparseGnuAsmLabel()
{
nextToken(); // move past asm
check(TOK.leftParenthesis);
if (token.value != TOK.string_)
- error("string literal expected");
+ error("string literal expected for Asm Label, not `%s`", token.toChars());
auto label = cparsePrimaryExp();
check(TOK.rightParenthesis);
return cast(AST.StringExp) label;
}
+ /********************
+ * Parse C inline assembler statement in Gnu format.
+ * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
+ * asm asm-qualifiers ( AssemblerTemplate : OutputOperands : InputOperands : Clobbers : GotoLabels )
+ * Current token is on the `asm`.
+ * Returns:
+ * inline assembler expression as a Statement
+ */
+ private AST.Statement cparseGnuAsm()
+ {
+ // Defer parsing of AsmStatements until semantic processing.
+ const loc = token.loc;
+
+ nextToken();
+
+ // Consume all asm-qualifiers. As a future optimization, we could record
+ // the `inline` and `volatile` storage classes against the statement.
+ while (token.value == TOK.goto_ ||
+ token.value == TOK.inline ||
+ token.value == TOK.volatile)
+ nextToken();
+
+ check(TOK.leftParenthesis);
+ if (token.value != TOK.string_)
+ error("string literal expected for Assembler Template, not `%s`", token.toChars());
+ Token* toklist = null;
+ Token** ptoklist = &toklist;
+ //Identifier label = null;
+ auto statements = new AST.Statements();
+
+ int parens;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.leftParenthesis:
+ ++parens;
+ goto default;
+
+ case TOK.rightParenthesis:
+ --parens;
+ if (parens >= 0)
+ goto default;
+ break;
+
+ case TOK.semicolon:
+ error("matching `)` expected, not `;`");
+ break;
+
+ case TOK.endOfFile:
+ /* ( */
+ error("matching `)` expected, not end of file");
+ break;
+
+ case TOK.colonColon: // treat as two separate : tokens for iasmgcc
+ *ptoklist = allocateToken();
+ memcpy(*ptoklist, &token, Token.sizeof);
+ (*ptoklist).value = TOK.colon;
+ ptoklist = &(*ptoklist).next;
+
+ *ptoklist = allocateToken();
+ memcpy(*ptoklist, &token, Token.sizeof);
+ (*ptoklist).value = TOK.colon;
+ ptoklist = &(*ptoklist).next;
+
+ *ptoklist = null;
+ nextToken();
+ continue;
+
+ default:
+ *ptoklist = allocateToken();
+ memcpy(*ptoklist, &token, Token.sizeof);
+ ptoklist = &(*ptoklist).next;
+ *ptoklist = null;
+ nextToken();
+ continue;
+ }
+ if (toklist)
+ {
+ // Create AsmStatement from list of tokens we've saved
+ AST.Statement s = new AST.AsmStatement(token.loc, toklist);
+ statements.push(s);
+ }
+ break;
+ }
+ nextToken();
+ auto s = new AST.CompoundAsmStatement(loc, statements, 0);
+ return s;
+ }
+
/*************************
* __attribute__ parser
* https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
@@ -3222,25 +3463,75 @@ final class CParser(AST) : Parser!AST
*/
private void cparseGnuAttribute(ref Specifier specifier)
{
- /* Check for dllimport, dllexport, vector_size(bytes)
+ /* Check for dllimport, dllexport, naked, noreturn, vector_size(bytes)
* Ignore the rest
*/
- bool dllimport; // TODO implement
- bool dllexport; // TODO implement
-
if (!isGnuAttributeName())
return;
if (token.value == TOK.identifier)
{
- if (token.ident == Id.dllimport)
+ if (token.ident == Id.aligned)
{
- dllimport = true;
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ if (token.value == TOK.int32Literal)
+ {
+ const n = token.unsvalue;
+ if (n < 1 || n & (n - 1) || ushort.max < n)
+ error("__attribute__((aligned(%lld))) must be an integer positive power of 2 and be <= 32,768", cast(ulong)n);
+ specifier.packalign.set(cast(uint)n);
+ specifier.packalign.setPack(true);
+ nextToken();
+ }
+ else
+ {
+ error("alignment value expected, not `%s`", token.toChars());
+ nextToken();
+ }
+
+ check(TOK.rightParenthesis);
+ }
+ /* ignore __attribute__((aligned)), which sets the alignment to the largest value for any data
+ * type on the target machine. It's the opposite of __attribute__((packed))
+ */
+ }
+ else if (token.ident == Id.always_inline) // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
+ {
+ specifier.scw |= SCW.xinline;
+ nextToken();
+ }
+ else if (token.ident == Id._deprecated)
+ {
+ specifier._deprecated = true;
+ nextToken();
+ if (token.value == TOK.leftParenthesis) // optional deprecation message
+ {
+ nextToken();
+ specifier.depMsg = cparseExpression();
+ check(TOK.rightParenthesis);
+ }
+ }
+ else if (token.ident == Id.dllimport)
+ {
+ specifier.dllimport = true;
nextToken();
}
else if (token.ident == Id.dllexport)
{
- dllexport = true;
+ specifier.dllexport = true;
+ nextToken();
+ }
+ else if (token.ident == Id.naked)
+ {
+ specifier.naked = true;
+ nextToken();
+ }
+ else if (token.ident == Id.noinline)
+ {
+ specifier.scw |= SCW.xnoinline;
nextToken();
}
else if (token.ident == Id.noreturn)
@@ -3248,6 +3539,16 @@ final class CParser(AST) : Parser!AST
specifier.noreturn = true;
nextToken();
}
+ else if (token.ident == Id._nothrow)
+ {
+ specifier._nothrow = true;
+ nextToken();
+ }
+ else if (token.ident == Id._pure)
+ {
+ specifier._pure = true;
+ nextToken();
+ }
else if (token.ident == Id.vector_size)
{
nextToken();
@@ -3408,7 +3709,8 @@ final class CParser(AST) : Parser!AST
* https://en.cppreference.com/w/cpp/language/enum
* enum Identifier : Type
*/
- AST.Type base = AST.Type.tint32; // C11 6.7.2.2-4 implementation defined default base type
+ //AST.Type base = AST.Type.tint32; // C11 6.7.2.2-4 implementation defined default base type
+ AST.Type base = null; // C23 says base type is determined by enum member values
if (token.value == TOK.colon)
{
nextToken();
@@ -3488,7 +3790,7 @@ final class CParser(AST) : Parser!AST
* redeclaration, or reference to existing declaration.
* Defer to the semantic() pass with a TypeTag.
*/
- return new AST.TypeTag(loc, TOK.enum_, tag, base, members);
+ return new AST.TypeTag(loc, TOK.enum_, tag, structalign_t.init, base, members);
}
/*************************************
@@ -3510,11 +3812,12 @@ final class CParser(AST) : Parser!AST
* Params:
* loc = location of `struct` or `union`
* structOrUnion = TOK.struct_ or TOK.union_
+ * packalign = alignment to use for struct members
* symbols = symbols to add struct-or-union declaration to
* Returns:
* type of the struct
*/
- private AST.Type cparseStruct(Loc loc, TOK structOrUnion, ref AST.Dsymbols* symbols)
+ private AST.Type cparseStruct(Loc loc, TOK structOrUnion, structalign_t packalign, ref AST.Dsymbols* symbols)
{
Identifier tag;
@@ -3553,7 +3856,7 @@ final class CParser(AST) : Parser!AST
* redeclaration, or reference to existing declaration.
* Defer to the semantic() pass with a TypeTag.
*/
- return new AST.TypeTag(loc, structOrUnion, tag, null, members);
+ return new AST.TypeTag(loc, structOrUnion, tag, packalign, null, members);
}
/*************************************
@@ -3996,6 +4299,13 @@ final class CParser(AST) : Parser!AST
case TOK.union_:
case TOK.enum_:
t = peek(t);
+ if (t.value == TOK.__attribute__ ||
+ t.value == TOK.__declspec)
+ {
+ t = peek(t);
+ if (!skipParens(t, &t))
+ return false;
+ }
if (t.value == TOK.identifier)
{
t = peek(t);
@@ -4019,6 +4329,7 @@ final class CParser(AST) : Parser!AST
case TOK.typedef_:
case TOK.extern_:
case TOK.static_:
+ case TOK.__thread:
case TOK._Thread_local:
case TOK.auto_:
case TOK.register:
@@ -4620,6 +4931,8 @@ final class CParser(AST) : Parser!AST
// C11 6.7.4 Function specifiers
xinline = 0x40,
x_Noreturn = 0x80,
+
+ xnoinline = 0x100,
}
/// C11 6.7.3 Type qualifiers
@@ -4639,6 +4952,14 @@ final class CParser(AST) : Parser!AST
struct Specifier
{
bool noreturn; /// noreturn attribute
+ bool naked; /// naked attribute
+ bool _nothrow; /// nothrow attribute
+ bool _pure; /// pure attribute
+ bool dllimport; /// dllimport attribute
+ bool dllexport; /// dllexport attribute
+ bool _deprecated; /// deprecated attribute
+ AST.Expression depMsg; /// deprecated message
+
SCW scw; /// storage-class specifiers
MOD mod; /// type qualifiers
AST.Expressions* alignExps; /// alignment
@@ -4662,6 +4983,8 @@ final class CParser(AST) : Parser!AST
{
if (specifier.scw & SCW.xextern)
stc = AST.STC.extern_;
+ else if (specifier.scw & SCW.xstatic)
+ stc = AST.STC.static_;
}
else if (level == LVL.local)
{
@@ -4713,10 +5036,42 @@ final class CParser(AST) : Parser!AST
stc = AST.STC.gshared;
}
}
+ if (specifier._deprecated && !specifier.depMsg)
+ stc |= AST.STC.deprecated_;
return stc;
}
/***********************
+ * Add attributes from Specifier to function
+ * Params:
+ * fd = function to apply them to
+ * specifier = specifiers
+ */
+ void specifiersToFuncDeclaration(AST.FuncDeclaration fd, const ref Specifier specifier)
+ {
+ fd.isNaked = specifier.naked;
+ fd.dllImport = specifier.dllimport;
+ fd.dllExport = specifier.dllexport;
+
+ if (specifier.scw & SCW.xnoinline)
+ fd.inlining = PINLINE.never;
+ else if (specifier.scw & SCW.xinline)
+ fd.inlining = PINLINE.always;
+ }
+
+ /***********************
+ * Add attributes from Specifier to variable
+ * Params:
+ * vd = function to apply them to
+ * specifier = specifiers
+ */
+ void specifiersToVarDeclaration(AST.VarDeclaration vd, const ref Specifier specifier)
+ {
+ vd.dllImport = specifier.dllimport;
+ vd.dllExport = specifier.dllexport;
+ }
+
+ /***********************
* Return suitable signed integer type for the given size
* Params:
* size = size of type
@@ -4826,7 +5181,7 @@ final class CParser(AST) : Parser!AST
auto lenfn = new AST.IntegerExp(loc, fn.length + 1, AST.Type.tuns32); // +1 for terminating 0
auto tfn = new AST.TypeSArray(AST.Type.tchar, lenfn);
efn.type = tfn.immutableOf();
- efn.committed = 1;
+ efn.committed = true;
auto sfn = new AST.VarDeclaration(loc, tfn, Id.__func__, ifn, STC.gshared | STC.immutable_);
auto e = new AST.DeclarationExp(loc, sfn);
return new AST.ExpStatement(loc, e);
@@ -4879,6 +5234,17 @@ final class CParser(AST) : Parser!AST
private AST.Dsymbol applySpecifier(AST.Dsymbol s, ref Specifier specifier)
{
//printf("applySpecifier() %s\n", s.toChars());
+ if (specifier._deprecated)
+ {
+ if (specifier.depMsg)
+ {
+ // Wrap declaration in a DeprecatedDeclaration
+ auto decls = new AST.Dsymbols(1);
+ (*decls)[0] = s;
+ s = new AST.DeprecatedDeclaration(specifier.depMsg, decls);
+ }
+ }
+
if (specifier.alignExps)
{
//printf(" applying _Alignas %s, packalign %d\n", (*specifier.alignExps)[0].toChars(), cast(int)specifier.packalign);
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 32b3851..40092c3 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -211,7 +211,7 @@ private final class CppMangleVisitor : Visitor
*/
void mangleReturnType(TypeFunction preSemantic)
{
- auto tf = cast(TypeFunction)this.context.res.asFuncDecl().type;
+ auto tf = this.context.res.asFuncDecl().type.isTypeFunction();
Type rt = preSemantic.nextOf();
// https://issues.dlang.org/show_bug.cgi?id=22739
// auto return type means that rt is null.
@@ -347,14 +347,14 @@ private final class CppMangleVisitor : Visitor
*
* Params:
* off = Offset to insert at
- * fd = Type of the function to mangle the return type of
+ * tf = Type of the function to mangle the return type of
*/
void writeRemainingTags(size_t off, TypeFunction tf)
{
- scope remainingVisitor = new LeftoverVisitor(&this.abiTags.written);
- tf.next.accept(remainingVisitor);
+ Array!StringExp toWrite;
+ leftOver(tf, &this.abiTags.written, &toWrite);
OutBuffer b2;
- foreach (se; remainingVisitor.toWrite)
+ foreach (se; toWrite)
{
auto tag = se.peekString();
// We can only insert a slice, and each insert is a memmove,
@@ -496,9 +496,9 @@ private final class CppMangleVisitor : Visitor
mangle_function(d.isFuncDeclaration());
buf.writestring("EE");
}
- else if (e && e.op == EXP.variable && (cast(VarExp)e).var.isVarDeclaration())
+ else if (e && e.isVarExp() && e.isVarExp().var.isVarDeclaration())
{
- VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration();
+ VarDeclaration vd = e.isVarExp().var.isVarDeclaration();
buf.writeByte('L');
mangle_variable(vd, true);
buf.writeByte('E');
@@ -757,9 +757,9 @@ private final class CppMangleVisitor : Visitor
bool isIdent_char(Identifier ident, RootObject o)
{
Type t = isType(o);
- if (!t || t.ty != Tstruct)
+ if (!t || !t.isTypeStruct())
return false;
- Dsymbol s = (cast(TypeStruct)t).toDsymbol(null);
+ Dsymbol s = t.toDsymbol(null);
if (s.ident != ident)
return false;
Dsymbol p = s.toParent();
@@ -1059,7 +1059,7 @@ private final class CppMangleVisitor : Visitor
* ::= <data name>
* ::= <special-name>
*/
- TypeFunction tf = cast(TypeFunction)d.type;
+ TypeFunction tf = d.type.isTypeFunction();
if (TemplateDeclaration ftd = getFuncTemplateDecl(d))
{
@@ -1173,7 +1173,7 @@ private final class CppMangleVisitor : Visitor
this.context.ti = ti;
this.context.fd = d;
this.context.res = d;
- TypeFunction preSemantic = cast(TypeFunction)d.originalType;
+ TypeFunction preSemantic = d.originalType.isTypeFunction();
auto nspace = ti.toParent();
if (nspace && nspace.isNspace())
this.writeChained(ti.toParent(), () => source_name(ti, true));
@@ -1347,7 +1347,7 @@ private final class CppMangleVisitor : Visitor
auto prev = this.context.push({
TypeFunction tf;
if (isDsymbol(this.context.res))
- tf = cast(TypeFunction)this.context.res.asFuncDecl().type;
+ tf = this.context.res.asFuncDecl().type.isTypeFunction();
else
tf = this.context.res.asType().isTypeFunction();
assert(tf);
@@ -1391,9 +1391,9 @@ private final class CppMangleVisitor : Visitor
*/
void headOfType(Type t)
{
- if (t.ty == Tclass)
+ if (auto tc = t.isTypeClass())
{
- mangleTypeClass(cast(TypeClass)t, true);
+ mangleTypeClass(tc, true);
}
else
{
@@ -1960,7 +1960,7 @@ extern(C++):
*/
override void visit(TypeIdentifier t)
{
- auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl;
+ auto decl = this.context.ti.tempdecl.isTemplateDeclaration();
assert(decl.parameters !is null);
auto idx = templateParamIndex(t.ident, decl.parameters);
// If not found, default to the post-semantic type
@@ -2019,7 +2019,7 @@ extern(C++):
{
// If the resolved AST has more args than the parse one,
// we have default arguments
- auto oparams = (cast(TemplateDeclaration)analyzed_ti.tempdecl).origParameters;
+ auto oparams = analyzed_ti.tempdecl.isTemplateDeclaration().origParameters;
foreach (idx, arg; (*oparams)[t.tiargs.length .. $])
{
this.context.res = (*analyzed_ti.tiargs)[idx + t.tiargs.length];
@@ -2044,7 +2044,7 @@ extern(C++):
assert(t.tiargs !is null);
bool needsTa;
- auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl;
+ auto decl = this.context.ti.tempdecl.isTemplateDeclaration();
// Attempt to substitute the template itself
auto idx = templateParamIndex(t.name, decl.parameters);
if (idx < decl.parameters.length)
@@ -2125,12 +2125,13 @@ private void visitObject(V : Visitor)(RootObject o, V this_)
/// Helper function to safely get a type out of a `RootObject`
private Type asType(RootObject o)
{
- Type ta = isType(o);
+ if (Type ta = isType(o))
+ return ta;
+
// When called with context.res as argument, it can be `FuncDeclaration`
- if (!ta && o.asFuncDecl())
- ta = (cast(FuncDeclaration)o).type;
- assert(ta !is null, o.toString());
- return ta;
+ if (auto fd = o.asFuncDecl())
+ return fd.type;
+ assert(0);
}
/// Helper function to safely get a `FuncDeclaration` out of a `RootObject`
@@ -2183,12 +2184,12 @@ private extern(C++) final class ComponentVisitor : Visitor
case DYNCAST.type:
auto t = cast(Type)base;
- if (t.ty == Tpointer)
- this.tpointer = cast(TypePointer)t;
- else if (t.ty == Treference)
- this.tref = cast(TypeReference)t;
- else if (t.ty == Tident)
- this.tident = cast(TypeIdentifier)t;
+ if (auto tp = t.isTypePointer())
+ this.tpointer = tp;
+ else if (auto tr = t.isTypeReference())
+ this.tref = tr;
+ else if (auto ti = t.isTypeIdentifier())
+ this.tident = ti;
else
goto default;
break;
@@ -2531,58 +2532,70 @@ unittest
assert(closestIndex([s1, s2, s4], s5, match) == 3 && !match);
}
-/**
+/***
* Visits the return type of a function and writes leftover ABI tags
+ * Params:
+ * tf = Type of the function to mangle the return type of
+ * previous = already written ones
+ * toWrite = where to put StringExp's to be written
*/
-extern(C++) private final class LeftoverVisitor : Visitor
+private
+void leftOver(TypeFunction tf, const(Array!StringExp)* previous, Array!StringExp* toWrite)
{
- /// List of tags to write
- private Array!StringExp toWrite;
- /// List of tags to ignore
- private const(Array!StringExp)* ignore;
-
- ///
- public this(const(Array!StringExp)* previous)
+ extern(C++) final class LeftoverVisitor : Visitor
{
- this.ignore = previous;
- }
+ /// List of tags to write
+ private Array!StringExp* toWrite;
+ /// List of tags to ignore
+ private const(Array!StringExp)* ignore;
- /// Reintroduce base class overloads
- public alias visit = Visitor.visit;
+ ///
+ public this(const(Array!StringExp)* previous, Array!StringExp* toWrite)
+ {
+ this.ignore = previous;
+ this.toWrite = toWrite;
+ }
- /// Least specialized overload of each direct child of `RootObject`
- public override void visit(Dsymbol o)
- {
- auto ale = ABITagContainer.forSymbol(o);
- if (!ale) return;
+ /// Reintroduce base class overloads
+ public alias visit = Visitor.visit;
- bool match;
- foreach (elem; *ale.elements)
+ /// Least specialized overload of each direct child of `RootObject`
+ public override void visit(Dsymbol o)
{
- auto se = elem.toStringExp();
- closestIndex((*this.ignore)[], se, match);
- if (match) continue;
- auto idx = closestIndex(this.toWrite[], se, match);
- if (!match)
- this.toWrite.insert(idx, se);
+ auto ale = ABITagContainer.forSymbol(o);
+ if (!ale) return;
+
+ bool match;
+ foreach (elem; *ale.elements)
+ {
+ auto se = elem.toStringExp();
+ closestIndex((*this.ignore)[], se, match);
+ if (match) continue;
+ auto idx = closestIndex((*this.toWrite)[], se, match);
+ if (!match)
+ (*this.toWrite).insert(idx, se);
+ }
}
- }
- /// Ditto
- public override void visit(Type o)
- {
- if (auto sym = o.toDsymbol(null))
- sym.accept(this);
- }
+ /// Ditto
+ public override void visit(Type o)
+ {
+ if (auto sym = o.toDsymbol(null))
+ sym.accept(this);
+ }
- /// Composite type
- public override void visit(TypePointer o)
- {
- o.next.accept(this);
- }
+ /// Composite type
+ public override void visit(TypePointer o)
+ {
+ o.next.accept(this);
+ }
- public override void visit(TypeReference o)
- {
- o.next.accept(this);
+ public override void visit(TypeReference o)
+ {
+ o.next.accept(this);
+ }
}
+
+ scope remainingVisitor = new LeftoverVisitor(previous, toWrite);
+ tf.next.accept(remainingVisitor);
}
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 8109e12..289ebeb 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -47,7 +47,7 @@ extern (C++) final class ClassReferenceExp : Expression
extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type)
{
- super(loc, EXP.classReference, __traits(classInstanceSize, ClassReferenceExp));
+ super(loc, EXP.classReference);
assert(lit && lit.sd && lit.sd.isClassDeclaration());
this.value = lit;
this.type = type;
@@ -132,7 +132,7 @@ extern (C++) final class ThrownExceptionExp : Expression
extern (D) this(const ref Loc loc, ClassReferenceExp victim)
{
- super(loc, EXP.thrownException, __traits(classInstanceSize, ThrownExceptionExp));
+ super(loc, EXP.thrownException);
this.thrown = victim;
this.type = victim.type;
}
@@ -170,7 +170,7 @@ extern (C++) final class CTFEExp : Expression
{
extern (D) this(EXP tok)
{
- super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp));
+ super(Loc.initial, tok);
type = Type.tvoid;
}
@@ -369,7 +369,6 @@ UnionExp copyLiteral(Expression e)
case EXP.dotVariable:
case EXP.int64:
case EXP.float64:
- case EXP.char_:
case EXP.complex80:
case EXP.void_:
case EXP.vector:
@@ -1468,7 +1467,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
memset(cast(char*)s + len * sz, 0, sz);
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
StringExp es = ue.exp().isStringExp();
- es.committed = 0;
+ es.committed = false;
es.type = type;
return ue;
}
@@ -1499,7 +1498,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
StringExp es = ue.exp().isStringExp();
es.sz = sz;
- es.committed = 0; //es1.committed;
+ es.committed = false; //es1.committed;
es.type = type;
return ue;
}
@@ -1837,7 +1836,6 @@ bool isCtfeValueValid(Expression newval)
{
case EXP.int64:
case EXP.float64:
- case EXP.char_:
case EXP.complex80:
return tb.isscalar();
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 2830b25..8ffbef3 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -1845,7 +1845,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
if (!e.committed)
{
se = e.copy().isStringExp();
- se.committed = 1;
+ se.committed = true;
copied = 1;
}
@@ -1887,7 +1887,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
assert(szx <= 255);
se.sz = cast(ubyte)szx;
se.len = cast(size_t)tb.isTypeSArray().dim.toInteger();
- se.committed = 1;
+ se.committed = true;
se.type = t;
/* If larger than source, pad with zeros.
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 7cd8df1..0e5df5e 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -738,7 +738,7 @@ extern (C++) final class AliasDeclaration : Declaration
extern (D) this(const ref Loc loc, Identifier ident, Type type)
{
super(loc, ident);
- //printf("AliasDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
+ //printf("AliasDeclaration(id = '%s', type = %p)\n", ident.toChars(), type);
//printf("type = '%s'\n", type.toChars());
this.type = type;
assert(type);
@@ -747,7 +747,7 @@ extern (C++) final class AliasDeclaration : Declaration
extern (D) this(const ref Loc loc, Identifier ident, Dsymbol s)
{
super(loc, ident);
- //printf("AliasDeclaration(id = '%s', s = %p)\n", id.toChars(), s);
+ //printf("AliasDeclaration(id = '%s', s = %p)\n", ident.toChars(), s);
assert(s != this);
this.aliassym = s;
assert(s);
@@ -1149,6 +1149,8 @@ extern (C++) class VarDeclaration : Declaration
bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument
bool isCmacro; /// it is a C macro turned into a C declaration
+ bool dllImport; /// __declspec(dllimport)
+ bool dllExport; /// __declspec(dllexport)
version (MARS)
{
bool inClosure; /// is inserted into a GC allocated closure
@@ -1314,7 +1316,7 @@ extern (C++) class VarDeclaration : Declaration
override final bool isExport() const
{
- return visibility.kind == Visibility.Kind.export_;
+ return visibility.kind == Visibility.Kind.export_ || dllExport;
}
override final bool isImportedSymbol() const
@@ -1325,6 +1327,7 @@ extern (C++) class VarDeclaration : Declaration
* export extern int sym3 = 0; // error, extern cannot have initializer
*/
bool result =
+ dllImport ||
visibility.kind == Visibility.Kind.export_ &&
storage_class & STC.extern_ &&
(storage_class & STC.static_ || parent.isModule());
@@ -1931,8 +1934,12 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
{
// 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)
+ 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
@@ -1941,7 +1948,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
{
- //printf("alignment is crossed\n");
+ if (log) printf("alignment is crossed\n");
startNewField();
}
}
@@ -1981,6 +1988,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
fieldState.bitOffset = pastField;
}
+ //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize);
//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
//printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
}
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index d75f64f..7a69382 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -623,6 +623,9 @@ public:
FuncDeclarations *inlinedNestedCallees;
AttributeViolation* safetyViolation;
+ AttributeViolation* nogcViolation;
+ AttributeViolation* pureViolation;
+ AttributeViolation* nothrowViolation;
// Formerly FUNCFLAGS
uint32_t flags;
@@ -672,6 +675,10 @@ public:
bool isCrtCtor(bool v);
bool isCrtDtor() const;
bool isCrtDtor(bool v);
+ bool dllImport() const;
+ bool dllImport(bool v);
+ bool dllExport() const;
+ bool dllExport(bool v);
// Data for a function declaration that is needed for the Objective-C
// integration.
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index e6ef704..4ef6a39 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -642,7 +642,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
e = CTFEExp.cantexp;
break;
}
- e = interpret(pue, fd.fbody, &istatex);
+ e = interpretStatement(pue, fd.fbody, &istatex);
if (CTFEExp.isCantExp(e))
{
debug (LOG)
@@ -738,21 +738,30 @@ void incUsageCtfe(InterState* istate, const ref Loc loc)
}
}
-private extern (C++) final class Interpreter : Visitor
+/***********************************
+ * Interpret the statement.
+ * Params:
+ * s = Statement to interpret
+ * istate = context
+ * Returns:
+ * NULL continue to next statement
+ * EXP.cantExpression cannot interpret statement at compile time
+ * !NULL expression from return statement, or thrown exception
+ */
+
+Expression interpretStatement(Statement s, InterState* istate)
{
- alias visit = Visitor.visit;
-public:
- InterState* istate;
- CTFEGoal goal;
- Expression result;
- UnionExp* pue; // storage for `result`
+ UnionExp ue = void;
+ auto result = interpretStatement(&ue, s, istate);
+ if (result == ue.exp())
+ result = ue.copy();
+ return result;
+}
- extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) scope
- {
- this.pue = pue;
- this.istate = istate;
- this.goal = goal;
- }
+///
+Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate)
+{
+ Expression result;
// If e is EXP.throw_exception or EXP.cantExpression,
// set it to 'result' and returns true.
@@ -767,26 +776,13 @@ public:
return false;
}
- static Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
- {
- if (exps is original)
- {
- if (!original)
- exps = new Expressions();
- else
- exps = original.copy();
- ++ctfeGlobals.numArrayAllocs;
- }
- return exps;
- }
-
/******************************** Statement ***************************/
- override void visit(Statement s)
+ void visitDefaultCase(Statement s)
{
debug (LOG)
{
- printf("%s Statement::interpret()\n", s.loc.toChars());
+ printf("%s Statement::interpret() %s\n", s.loc.toChars(), s.toChars());
}
if (istate.start)
{
@@ -799,7 +795,7 @@ public:
result = CTFEExp.cantexp;
}
- override void visit(ExpStatement s)
+ void visitExp(ExpStatement s)
{
debug (LOG)
{
@@ -819,7 +815,12 @@ public:
return;
}
- override void visit(CompoundStatement s)
+ void visitDtorExp(DtorExpStatement s)
+ {
+ visitExp(s);
+ }
+
+ void visitCompound(CompoundStatement s)
{
debug (LOG)
{
@@ -832,7 +833,7 @@ public:
foreach (i; 0 .. dim)
{
Statement sx = (*s.statements)[i];
- result = interpret(pue, sx, istate);
+ result = interpretStatement(pue, sx, istate);
if (result)
break;
}
@@ -842,7 +843,12 @@ public:
}
}
- override void visit(UnrolledLoopStatement s)
+ void visitCompoundAsm(CompoundAsmStatement s)
+ {
+ visitCompound(s);
+ }
+
+ void visitUnrolledLoop(UnrolledLoopStatement s)
{
debug (LOG)
{
@@ -855,7 +861,7 @@ public:
foreach (i; 0 .. dim)
{
Statement sx = (*s.statements)[i];
- Expression e = interpret(pue, sx, istate);
+ Expression e = interpretStatement(pue, sx, istate);
if (!e) // succeeds to interpret, or goto target was not found
continue;
if (exceptionOrCant(e))
@@ -888,7 +894,7 @@ public:
}
}
- override void visit(IfStatement s)
+ void visitIf(IfStatement s)
{
debug (LOG)
{
@@ -900,9 +906,9 @@ public:
if (istate.start)
{
Expression e = null;
- e = interpret(s.ifbody, istate);
+ e = interpretStatement(s.ifbody, istate);
if (!e && istate.start)
- e = interpret(s.elsebody, istate);
+ e = interpretStatement(s.elsebody, istate);
result = e;
return;
}
@@ -914,9 +920,9 @@ public:
return;
if (isTrueBool(e))
- result = interpret(pue, s.ifbody, istate);
+ result = interpretStatement(pue, s.ifbody, istate);
else if (e.toBool().hasValue(false))
- result = interpret(pue, s.elsebody, istate);
+ result = interpretStatement(pue, s.elsebody, istate);
else
{
// no error, or assert(0)?
@@ -924,7 +930,7 @@ public:
}
}
- override void visit(ScopeStatement s)
+ void visitScope(ScopeStatement s)
{
debug (LOG)
{
@@ -933,78 +939,10 @@ public:
if (istate.start == s)
istate.start = null;
- result = interpret(pue, s.statement, istate);
+ result = interpretStatement(pue, s.statement, istate);
}
- /**
- Given an expression e which is about to be returned from the current
- function, generate an error if it contains pointers to local variables.
-
- Only checks expressions passed by value (pointers to local variables
- may already be stored in members of classes, arrays, or AAs which
- were passed as mutable function parameters).
- Returns:
- true if it is safe to return, false if an error was generated.
- */
- static bool stopPointersEscaping(const ref Loc loc, Expression e)
- {
- if (!e.type.hasPointers())
- return true;
- if (isPointer(e.type))
- {
- Expression x = e;
- if (auto eaddr = e.isAddrExp())
- x = eaddr.e1;
- VarDeclaration v;
- while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null)
- {
- if (v.storage_class & STC.ref_)
- {
- x = getValue(v);
- if (auto eaddr = e.isAddrExp())
- eaddr.e1 = x;
- continue;
- }
- if (ctfeGlobals.stack.isInCurrentFrame(v))
- {
- error(loc, "returning a pointer to a local stack variable");
- return false;
- }
- else
- break;
- }
- // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
- // pointing to a local struct or static array.
- }
- if (auto se = e.isStructLiteralExp())
- {
- return stopPointersEscapingFromArray(loc, se.elements);
- }
- if (auto ale = e.isArrayLiteralExp())
- {
- return stopPointersEscapingFromArray(loc, ale.elements);
- }
- if (auto aae = e.isAssocArrayLiteralExp())
- {
- if (!stopPointersEscapingFromArray(loc, aae.keys))
- return false;
- return stopPointersEscapingFromArray(loc, aae.values);
- }
- return true;
- }
-
- // Check all elements of an array for escaping local variables. Return false if error
- static bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
- {
- foreach (e; *elems)
- {
- if (e && !stopPointersEscaping(loc, e))
- return false;
- }
- return true;
- }
-
- override void visit(ReturnStatement s)
+ void visitReturn(ReturnStatement s)
{
debug (LOG)
{
@@ -1061,7 +999,7 @@ public:
if (isRuntimeHook(s.exp, Id._d_arrayappendT) || isRuntimeHook(s.exp, Id._d_arrayappendTTrace))
{
auto rs = new ReturnStatement(s.loc, e);
- rs.accept(this);
+ visitReturn(rs);
return;
}
@@ -1082,20 +1020,7 @@ public:
result = e;
}
- static Statement findGotoTarget(InterState* istate, Identifier ident)
- {
- Statement target = null;
- if (ident)
- {
- LabelDsymbol label = istate.fd.searchLabel(ident);
- assert(label && label.statement);
- LabelStatement ls = label.statement;
- target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
- }
- return target;
- }
-
- override void visit(BreakStatement s)
+ void visitBreak(BreakStatement s)
{
debug (LOG)
{
@@ -1113,7 +1038,7 @@ public:
result = CTFEExp.breakexp;
}
- override void visit(ContinueStatement s)
+ void visitContinue(ContinueStatement s)
{
debug (LOG)
{
@@ -1131,7 +1056,7 @@ public:
result = CTFEExp.continueexp;
}
- override void visit(WhileStatement s)
+ void visitWhile(WhileStatement s)
{
debug (LOG)
{
@@ -1140,7 +1065,7 @@ public:
assert(0); // rewritten to ForStatement
}
- override void visit(DoStatement s)
+ void visitDo(DoStatement s)
{
debug (LOG)
{
@@ -1151,7 +1076,7 @@ public:
while (1)
{
- Expression e = interpret(s._body, istate);
+ Expression e = interpretStatement(s._body, istate);
if (!e && istate.start) // goto target was not found
return;
assert(!istate.start);
@@ -1201,7 +1126,7 @@ public:
assert(result is null);
}
- override void visit(ForStatement s)
+ void visitFor(ForStatement s)
{
debug (LOG)
{
@@ -1211,7 +1136,7 @@ public:
istate.start = null;
UnionExp ueinit = void;
- Expression ei = interpret(&ueinit, s._init, istate);
+ Expression ei = interpretStatement(&ueinit, s._init, istate);
if (exceptionOrCant(ei))
return;
assert(!ei); // s.init never returns from function, or jumps out from it
@@ -1230,7 +1155,7 @@ public:
assert(isTrueBool(e));
}
- Expression e = interpret(pue, s._body, istate);
+ Expression e = interpretStatement(pue, s._body, istate);
if (!e && istate.start) // goto target was not found
return;
assert(!istate.start);
@@ -1273,17 +1198,17 @@ public:
assert(result is null);
}
- override void visit(ForeachStatement s)
+ void visitForeach(ForeachStatement s)
{
assert(0); // rewritten to ForStatement
}
- override void visit(ForeachRangeStatement s)
+ void visitForeachRange(ForeachRangeStatement s)
{
assert(0); // rewritten to ForStatement
}
- override void visit(SwitchStatement s)
+ void visitSwitch(SwitchStatement s)
{
debug (LOG)
{
@@ -1294,7 +1219,7 @@ public:
istate.start = null;
if (istate.start)
{
- Expression e = interpret(s._body, istate);
+ Expression e = interpretStatement(s._body, istate);
if (istate.start) // goto target was not found
return;
if (exceptionOrCant(e))
@@ -1344,7 +1269,7 @@ public:
/* Jump to scase
*/
istate.start = scase;
- Expression e = interpret(pue, s._body, istate);
+ Expression e = interpretStatement(pue, s._body, istate);
assert(!istate.start); // jump must not fail
if (e && e.op == EXP.break_)
{
@@ -1359,7 +1284,7 @@ public:
result = e;
}
- override void visit(CaseStatement s)
+ void visitCase(CaseStatement s)
{
debug (LOG)
{
@@ -1369,10 +1294,10 @@ public:
if (istate.start == s)
istate.start = null;
- result = interpret(pue, s.statement, istate);
+ result = interpretStatement(pue, s.statement, istate);
}
- override void visit(DefaultStatement s)
+ void visitDefault(DefaultStatement s)
{
debug (LOG)
{
@@ -1382,10 +1307,10 @@ public:
if (istate.start == s)
istate.start = null;
- result = interpret(pue, s.statement, istate);
+ result = interpretStatement(pue, s.statement, istate);
}
- override void visit(GotoStatement s)
+ void visitGoto(GotoStatement s)
{
debug (LOG)
{
@@ -1404,7 +1329,7 @@ public:
result = CTFEExp.gotoexp;
}
- override void visit(GotoCaseStatement s)
+ void visitGotoCase(GotoCaseStatement s)
{
debug (LOG)
{
@@ -1423,7 +1348,7 @@ public:
result = CTFEExp.gotoexp;
}
- override void visit(GotoDefaultStatement s)
+ void visitGotoDefault(GotoDefaultStatement s)
{
debug (LOG)
{
@@ -1442,7 +1367,7 @@ public:
result = CTFEExp.gotoexp;
}
- override void visit(LabelStatement s)
+ void visitLabel(LabelStatement s)
{
debug (LOG)
{
@@ -1451,10 +1376,10 @@ public:
if (istate.start == s)
istate.start = null;
- result = interpret(pue, s.statement, istate);
+ result = interpretStatement(pue, s.statement, istate);
}
- override void visit(TryCatchStatement s)
+ void visitTryCatch(TryCatchStatement s)
{
debug (LOG)
{
@@ -1465,18 +1390,18 @@ public:
if (istate.start)
{
Expression e = null;
- e = interpret(pue, s._body, istate);
+ e = interpretStatement(pue, s._body, istate);
foreach (ca; *s.catches)
{
if (e || !istate.start) // goto target was found
break;
- e = interpret(pue, ca.handler, istate);
+ e = interpretStatement(pue, ca.handler, istate);
}
result = e;
return;
}
- Expression e = interpret(s._body, istate);
+ Expression e = interpretStatement(s._body, istate);
// An exception was thrown
if (e && e.isThrownExceptionExp())
@@ -1497,7 +1422,7 @@ public:
ctfeGlobals.stack.push(ca.var);
setValue(ca.var, ex.thrown);
}
- e = interpret(ca.handler, istate);
+ e = interpretStatement(ca.handler, istate);
if (CTFEExp.isGotoExp(e))
{
/* This is an optimization that relies on the locality of the jump target.
@@ -1509,7 +1434,7 @@ public:
InterState istatex = *istate;
istatex.start = istate.gotoTarget; // set starting statement
istatex.gotoTarget = null;
- Expression eh = interpret(ca.handler, &istatex);
+ Expression eh = interpretStatement(ca.handler, &istatex);
if (!istatex.start)
{
istate.gotoTarget = null;
@@ -1522,39 +1447,7 @@ public:
result = e;
}
- static ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
- {
- debug (LOG)
- {
- printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
- }
- // Little sanity check to make sure it's really a Throwable
- ClassReferenceExp boss = oldest.thrown;
- const next = 5; // index of Throwable.next
- assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
- ClassReferenceExp collateral = newest.thrown;
- if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException())
- {
- /* Find the index of the Error.bypassException field
- */
- auto bypass = next + 1;
- if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
- bypass += 1; // skip over _refcount field
- assert((*collateral.value.elements)[bypass].type.ty == Tclass);
-
- // The new exception bypass the existing chain
- (*collateral.value.elements)[bypass] = boss;
- return newest;
- }
- while ((*boss.value.elements)[next].op == EXP.classReference)
- {
- boss = (*boss.value.elements)[next].isClassReferenceExp();
- }
- (*boss.value.elements)[next] = collateral;
- return oldest;
- }
-
- override void visit(TryFinallyStatement s)
+ void visitTryFinally(TryFinallyStatement s)
{
debug (LOG)
{
@@ -1565,14 +1458,14 @@ public:
if (istate.start)
{
Expression e = null;
- e = interpret(pue, s._body, istate);
+ e = interpretStatement(pue, s._body, istate);
// Jump into/out from finalbody is disabled in semantic analysis.
// and jump inside will be handled by the ScopeStatement == finalbody.
result = e;
return;
}
- Expression ex = interpret(s._body, istate);
+ Expression ex = interpretStatement(s._body, istate);
if (CTFEExp.isCantExp(ex))
{
result = ex;
@@ -1585,7 +1478,7 @@ public:
InterState istatex = *istate;
istatex.start = istate.gotoTarget; // set starting statement
istatex.gotoTarget = null;
- Expression bex = interpret(s._body, &istatex);
+ Expression bex = interpretStatement(s._body, &istatex);
if (istatex.start)
{
// The goto target is outside the current scope.
@@ -1601,7 +1494,7 @@ public:
ex = bex;
}
- Expression ey = interpret(s.finalbody, istate);
+ Expression ey = interpretStatement(s.finalbody, istate);
if (CTFEExp.isCantExp(ey))
{
result = ey;
@@ -1618,7 +1511,7 @@ public:
result = ex;
}
- override void visit(ThrowStatement s)
+ void visitThrow(ThrowStatement s)
{
debug (LOG)
{
@@ -1631,35 +1524,15 @@ public:
istate.start = null;
}
- interpretThrow(s.exp, s.loc);
- }
-
- /// Interpret `throw <exp>` found at the specified location `loc`
- private void interpretThrow(Expression exp, const ref Loc loc)
- {
- incUsageCtfe(istate, loc);
-
- Expression e = interpretRegion(exp, istate);
- if (exceptionOrCant(e))
- return;
-
- if (e.op == EXP.classReference)
- {
- result = ctfeEmplaceExp!ThrownExceptionExp(loc, e.isClassReferenceExp());
- }
- else
- {
- exp.error("to be thrown `%s` must be non-null", exp.toChars());
- result = ErrorExp.get();
- }
+ interpretThrow(result, s.exp, s.loc, istate);
}
- override void visit(ScopeGuardStatement s)
+ void visitScopeGuard(ScopeGuardStatement s)
{
assert(0);
}
- override void visit(WithStatement s)
+ void visitWith(WithStatement s)
{
debug (LOG)
{
@@ -1669,14 +1542,14 @@ public:
istate.start = null;
if (istate.start)
{
- result = s._body ? interpret(s._body, istate) : null;
+ result = s._body ? interpretStatement(s._body, istate) : null;
return;
}
// If it is with(Enum) {...}, just execute the body.
if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
{
- result = interpret(pue, s._body, istate);
+ result = interpretStatement(pue, s._body, istate);
return;
}
@@ -1692,7 +1565,7 @@ public:
}
ctfeGlobals.stack.push(s.wthis);
setValue(s.wthis, e);
- e = interpret(s._body, istate);
+ e = interpretStatement(s._body, istate);
if (CTFEExp.isGotoExp(e))
{
/* This is an optimization that relies on the locality of the jump target.
@@ -1704,7 +1577,7 @@ public:
InterState istatex = *istate;
istatex.start = istate.gotoTarget; // set starting statement
istatex.gotoTarget = null;
- Expression ex = interpret(s._body, &istatex);
+ Expression ex = interpretStatement(s._body, &istatex);
if (!istatex.start)
{
istate.gotoTarget = null;
@@ -1715,7 +1588,7 @@ public:
result = e;
}
- override void visit(AsmStatement s)
+ void visitAsm(AsmStatement s)
{
debug (LOG)
{
@@ -1731,7 +1604,17 @@ public:
result = CTFEExp.cantexp;
}
- override void visit(ImportStatement s)
+ void visitInlineAsm(InlineAsmStatement s)
+ {
+ visitAsm(s);
+ }
+
+ void visitGccAsm(GccAsmStatement s)
+ {
+ visitAsm(s);
+ }
+
+ void visitImport(ImportStatement s)
{
debug (LOG)
{
@@ -1745,6 +1628,45 @@ public:
}
}
+ if (!s)
+ return null;
+
+ mixin VisitStatement!void visit;
+ visit.VisitStatement(s);
+ return result;
+}
+
+///
+
+private extern (C++) final class Interpreter : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ InterState* istate;
+ CTFEGoal goal;
+ Expression result;
+ UnionExp* pue; // storage for `result`
+
+ extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) scope
+ {
+ this.pue = pue;
+ this.istate = istate;
+ this.goal = goal;
+ }
+
+ // If e is EXP.throw_exception or EXP.cantExpression,
+ // set it to 'result' and returns true.
+ bool exceptionOrCant(Expression e)
+ {
+ if (exceptionOrCantInterpret(e))
+ {
+ // Make sure e is not pointing to a stack temporary
+ result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
+ return true;
+ }
+ return false;
+ }
+
/******************************** Expression ***************************/
override void visit(Expression e)
@@ -2519,7 +2441,7 @@ public:
{
debug (LOG)
{
- printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ printf("%s ArrayLiteralExp::interpret() %s, %s\n", e.loc.toChars(), e.type.toChars(), e.toChars());
}
if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
{
@@ -2527,7 +2449,8 @@ public:
return;
}
- Type tn = e.type.toBasetype().nextOf().toBasetype();
+ Type tb = e.type.toBasetype();
+ Type tn = tb.nextOf().toBasetype();
bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
auto basis = interpretRegion(e.basis, istate);
@@ -2536,6 +2459,7 @@ public:
auto expsx = e.elements;
size_t dim = expsx ? expsx.length : 0;
+
for (size_t i = 0; i < dim; i++)
{
Expression exp = (*expsx)[i];
@@ -4049,6 +3973,8 @@ public:
*/
private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
{
+ //printf("interpretAssignToSlice(e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
+
dinteger_t lowerbound;
dinteger_t upperbound;
dinteger_t firstIndex;
@@ -4108,7 +4034,7 @@ public:
return newval;
// For slice assignment, we check that the lengths match.
- if (!isBlockAssignment)
+ if (!isBlockAssignment && e1.type.ty != Tpointer)
{
const srclen = resolveArrayLength(newval);
if (srclen != (upperbound - lowerbound))
@@ -4323,8 +4249,8 @@ public:
Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
{
Expressions* w = ae.elements;
- assert(ae.type.ty == Tsarray || ae.type.ty == Tarray);
- bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
+ assert(ae.type.ty == Tsarray || ae.type.ty == Tarray || ae.type.ty == Tpointer);
+ bool directblk = (cast(TypeNext)ae.type).next.equivalent(newval.type);
for (size_t k = lwr; k < upr; k++)
{
if (!directblk && (*w)[k].op == EXP.arrayLiteral)
@@ -4848,25 +4774,6 @@ public:
result = CTFEExp.voidexp;
return;
}
- else if (fd.ident == Id._d_arraysetlengthT)
- {
- // In expressionsem.d `ea.length = eb;` got lowered to `_d_arraysetlengthT(ea, eb);`.
- // The following code will rewrite it back to `ea.length = eb` and then interpret that expression.
- assert(e.arguments.length == 2);
-
- Expression ea = (*e.arguments)[0];
- Expression eb = (*e.arguments)[1];
-
- auto ale = ctfeEmplaceExp!ArrayLengthExp(e.loc, ea);
- ale.type = Type.tsize_t;
- AssignExp ae = ctfeEmplaceExp!AssignExp(e.loc, ale, eb);
- ae.type = ea.type;
-
- // if (global.params.verbose)
- // message("interpret %s =>\n %s", e.toChars(), ae.toChars());
- result = interpretRegion(ae, istate);
- return;
- }
else if (isArrayConstructionOrAssign(fd.ident))
{
// In expressionsem.d, the following lowerings were performed:
@@ -5847,7 +5754,25 @@ public:
e2 = ue2.copy();
}
- *pue = ctfeCat(e.loc, e.type, e1, e2);
+ Expression prepareCatOperand(Expression exp)
+ {
+ /* Convert `elem ~ array` to `[elem] ~ array` if `elem` is itself an
+ * array. This is needed because interpreting the `CatExp` calls
+ * `Cat()`, which cannot handle concatenations between different
+ * types, except for strings and chars.
+ */
+ auto tb = e.type.toBasetype();
+ auto tbNext = tb.nextOf();
+ auto expTb = exp.type.toBasetype();
+
+ if (exp.type.implicitConvTo(tbNext) >= MATCH.convert &&
+ (tb.ty == Tarray || tb.ty == Tsarray) &&
+ (expTb.ty == Tarray || expTb.ty == Tsarray))
+ return new ArrayLiteralExp(exp.loc, e.type, exp);
+ return exp;
+ }
+
+ *pue = ctfeCat(e.loc, e.type, prepareCatOperand(e1), prepareCatOperand(e2));
result = pue.exp();
if (CTFEExp.isCantExp(result))
@@ -6208,15 +6133,18 @@ public:
{
printf("%s ThrowExpression::interpret()\n", te.loc.toChars());
}
- interpretThrow(te.e1, te.loc);
+ interpretThrow(result, te.e1, te.loc, istate);
}
override void visit(PtrExp e)
{
+ // Called for both lvalues and rvalues
+ const lvalue = goal == CTFEGoal.LValue;
debug (LOG)
{
- printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ printf("%s PtrExp::interpret(%d) %s, %s\n", e.loc.toChars(), lvalue, e.type.toChars(), e.toChars());
}
+
// Check for int<->float and long<->double casts.
if (auto soe1 = e.e1.isSymOffExp())
if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
@@ -6274,6 +6202,20 @@ public:
return;
}
+ if (!lvalue && result.isArrayLiteralExp() &&
+ result.type.isTypePointer())
+ {
+ /* A pointer variable can point to an array literal like `[3]`.
+ * Dereferencing it means accessing the first element value.
+ * Dereference it only if result should be an rvalue
+ */
+ auto ae = result.isArrayLiteralExp();
+ if (ae.elements.length == 1)
+ {
+ result = (*ae.elements)[0];
+ return;
+ }
+ }
if (result.isStringExp() || result.isArrayLiteralExp())
return;
@@ -6514,33 +6456,57 @@ public:
{
assert(0); // This should never be interpreted
}
+}
- /*********************************************
- * Checks if the given expresion is a call to the runtime hook `id`.
- * Params:
- * e = the expression to check
- * id = the identifier of the runtime hook
- * Returns:
- * `e` cast to `CallExp` if it's the hook, `null` otherwise
- */
- private CallExp isRuntimeHook(Expression e, Identifier id)
+/// Interpret `throw <exp>` found at the specified location `loc`
+private
+void interpretThrow(ref Expression result, Expression exp, const ref Loc loc, InterState* istate)
+{
+ incUsageCtfe(istate, loc);
+
+ Expression e = interpretRegion(exp, istate);
+ if (exceptionOrCantInterpret(e))
{
- if (auto ce = e.isCallExp())
+ // Make sure e is not pointing to a stack temporary
+ result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
+ }
+ else if (e.op == EXP.classReference)
+ {
+ result = ctfeEmplaceExp!ThrownExceptionExp(loc, e.isClassReferenceExp());
+ }
+ else
+ {
+ exp.error("to be thrown `%s` must be non-null", exp.toChars());
+ result = ErrorExp.get();
+ }
+}
+
+/*********************************************
+ * Checks if the given expresion is a call to the runtime hook `id`.
+ *
+ * Params:
+ * e = the expression to check
+ * id = the identifier of the runtime hook
+ * Returns:
+ * `e` cast to `CallExp` if it's the hook, `null` otherwise
+ */
+public CallExp isRuntimeHook(Expression e, Identifier id)
+{
+ if (auto ce = e.isCallExp())
+ {
+ if (auto ve = ce.e1.isVarExp())
{
- if (auto ve = ce.e1.isVarExp())
+ if (auto fd = ve.var.isFuncDeclaration())
{
- if (auto fd = ve.var.isFuncDeclaration())
- {
- // If `_d_HookTraceImpl` is found, resolve the underlying
- // hook and replace `e` and `fd` with it.
- removeHookTraceImpl(ce, fd);
- return fd.ident == id ? ce : null;
- }
+ // If `_d_HookTraceImpl` is found, resolve the underlying hook
+ // and replace `e` and `fd` with it.
+ removeHookTraceImpl(ce, fd);
+ return fd.ident == id ? ce : null;
}
}
-
- return null;
}
+
+ return null;
}
/********************************************
@@ -6558,10 +6524,12 @@ Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal g
{
if (!e)
return null;
+ //printf("+interpret() e : %s, %s\n", e.type.toChars(), e.toChars());
scope Interpreter v = new Interpreter(pue, istate, goal);
e.accept(v);
Expression ex = v.result;
assert(goal == CTFEGoal.Nothing || ex !is null);
+ //if (ex) printf("-interpret() ex: %s, %s\n", ex.type.toChars(), ex.toChars()); else printf("-interpret()\n");
return ex;
}
@@ -6608,34 +6576,135 @@ Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTF
return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
}
-/***********************************
- * Interpret the statement.
- * Params:
- * pue = non-null pointer to temporary storage that can be used to store the return value
- * s = Statement to interpret
- * istate = context
- * Returns:
- * NULL continue to next statement
- * EXP.cantExpression cannot interpret statement at compile time
- * !NULL expression from return statement, or thrown exception
+private
+Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
+{
+ if (exps is original)
+ {
+ if (!original)
+ exps = new Expressions();
+ else
+ exps = original.copy();
+ ++ctfeGlobals.numArrayAllocs;
+ }
+ return exps;
+}
+
+/**
+ Given an expression e which is about to be returned from the current
+ function, generate an error if it contains pointers to local variables.
+
+ Only checks expressions passed by value (pointers to local variables
+ may already be stored in members of classes, arrays, or AAs which
+ were passed as mutable function parameters).
+ Returns:
+ true if it is safe to return, false if an error was generated.
*/
-Expression interpret(UnionExp* pue, Statement s, InterState* istate)
+private
+bool stopPointersEscaping(const ref Loc loc, Expression e)
{
- if (!s)
- return null;
- scope Interpreter v = new Interpreter(pue, istate, CTFEGoal.Nothing);
- s.accept(v);
- return v.result;
+ if (!e.type.hasPointers())
+ return true;
+ if (isPointer(e.type))
+ {
+ Expression x = e;
+ if (auto eaddr = e.isAddrExp())
+ x = eaddr.e1;
+ VarDeclaration v;
+ while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null)
+ {
+ if (v.storage_class & STC.ref_)
+ {
+ x = getValue(v);
+ if (auto eaddr = e.isAddrExp())
+ eaddr.e1 = x;
+ continue;
+ }
+ if (ctfeGlobals.stack.isInCurrentFrame(v))
+ {
+ error(loc, "returning a pointer to a local stack variable");
+ return false;
+ }
+ else
+ break;
+ }
+ // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
+ // pointing to a local struct or static array.
+ }
+ if (auto se = e.isStructLiteralExp())
+ {
+ return stopPointersEscapingFromArray(loc, se.elements);
+ }
+ if (auto ale = e.isArrayLiteralExp())
+ {
+ return stopPointersEscapingFromArray(loc, ale.elements);
+ }
+ if (auto aae = e.isAssocArrayLiteralExp())
+ {
+ if (!stopPointersEscapingFromArray(loc, aae.keys))
+ return false;
+ return stopPointersEscapingFromArray(loc, aae.values);
+ }
+ return true;
}
-///
-Expression interpret(Statement s, InterState* istate)
+// Check all elements of an array for escaping local variables. Return false if error
+private
+bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
{
- UnionExp ue = void;
- auto result = interpret(&ue, s, istate);
- if (result == ue.exp())
- result = ue.copy();
- return result;
+ foreach (e; *elems)
+ {
+ if (e && !stopPointersEscaping(loc, e))
+ return false;
+ }
+ return true;
+}
+
+private
+Statement findGotoTarget(InterState* istate, Identifier ident)
+{
+ Statement target = null;
+ if (ident)
+ {
+ LabelDsymbol label = istate.fd.searchLabel(ident);
+ assert(label && label.statement);
+ LabelStatement ls = label.statement;
+ target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
+ }
+ return target;
+}
+
+private
+ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
+{
+ debug (LOG)
+ {
+ printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
+ }
+ // Little sanity check to make sure it's really a Throwable
+ ClassReferenceExp boss = oldest.thrown;
+ const next = 5; // index of Throwable.next
+ assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
+ ClassReferenceExp collateral = newest.thrown;
+ if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException())
+ {
+ /* Find the index of the Error.bypassException field
+ */
+ auto bypass = next + 1;
+ if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
+ bypass += 1; // skip over _refcount field
+ assert((*collateral.value.elements)[bypass].type.ty == Tclass);
+
+ // The new exception bypass the existing chain
+ (*collateral.value.elements)[bypass] = boss;
+ return newest;
+ }
+ while ((*boss.value.elements)[next].op == EXP.classReference)
+ {
+ boss = (*boss.value.elements)[next].isClassReferenceExp();
+ }
+ (*boss.value.elements)[next] = collateral;
+ return oldest;
}
/**
@@ -6978,7 +7047,6 @@ private Expression copyRegionExp(Expression e)
case EXP.null_:
case EXP.void_:
case EXP.symbolOffset:
- case EXP.char_:
break;
case EXP.cantExpression:
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index a5f7cd3..149a5b1 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -767,7 +767,7 @@ extern (C++) final class Module : Package
{
filetype = FileType.c;
- scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines);
+ scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines, &global.compileEnv);
p.nextToken();
checkCompiledImport();
members = p.parseModule();
@@ -776,7 +776,9 @@ extern (C++) final class Module : Package
}
else
{
- scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink);
+ const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
+ scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink, &global.compileEnv, doUnittests);
+ p.transitionIn = global.params.vin;
p.nextToken();
p.parseModuleDeclaration();
md = p.md;
@@ -1229,8 +1231,7 @@ extern (C++) final class Module : Package
return this.importedFrom == this;
}
- // true if the module source file is directly
- // listed in command line.
+ /// Returns: Whether this module is in the `core` package and has name `ident`
bool isCoreModule(Identifier ident) nothrow
{
return this.ident == ident && parent && parent.ident == Id.core && !parent.parent;
@@ -1287,6 +1288,20 @@ extern (C++) final class Module : Package
}
/****************************
+ * A Singleton that loads core.stdc.config
+ * Returns:
+ * Module of core.stdc.config, null if couldn't find it
+ */
+ extern (D) static Module loadCoreStdcConfig()
+ {
+ __gshared Module core_stdc_config;
+ auto pkgids = new Identifier[2];
+ pkgids[0] = Id.core;
+ pkgids[1] = Id.stdc;
+ return loadModuleFromLibrary(core_stdc_config, pkgids, Id.config);
+ }
+
+ /****************************
* A Singleton that loads core.atomic
* Returns:
* Module of core.atomic, null if couldn't find it
@@ -1294,7 +1309,9 @@ extern (C++) final class Module : Package
extern (D) static Module loadCoreAtomic()
{
__gshared Module core_atomic;
- return loadModuleFromLibrary(core_atomic, Id.core, Id.atomic);
+ auto pkgids = new Identifier[1];
+ pkgids[0] = Id.core;
+ return loadModuleFromLibrary(core_atomic, pkgids, Id.atomic);
}
/****************************
@@ -1305,26 +1322,26 @@ extern (C++) final class Module : Package
extern (D) static Module loadStdMath()
{
__gshared Module std_math;
- return loadModuleFromLibrary(std_math, Id.std, Id.math);
+ auto pkgids = new Identifier[1];
+ pkgids[0] = Id.std;
+ return loadModuleFromLibrary(std_math, pkgids, Id.math);
}
/**********************************
* Load a Module from the library.
* Params:
* mod = cached return value of this call
- * pkgid = package id
+ * pkgids = package identifiers
* modid = module id
* Returns:
* Module loaded, null if cannot load it
*/
- private static Module loadModuleFromLibrary(ref Module mod, Identifier pkgid, Identifier modid)
+ extern (D) private static Module loadModuleFromLibrary(ref Module mod, Identifier[] pkgids, Identifier modid)
{
if (mod)
return mod;
- auto ids = new Identifier[1];
- ids[0] = pkgid;
- auto imp = new Import(Loc.initial, ids[], modid, null, true);
+ auto imp = new Import(Loc.initial, pkgids[], modid, null, true);
// Module.load will call fatal() if there's no module available.
// Gag the error here, pushing the error handling to the caller.
const errors = global.startGagging();
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index 88e8996..7674f77 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -5184,7 +5184,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of
scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1,
global.errorSink,
- global.vendor, global.versionNumber());
+ &global.compileEnv);
OutBuffer res;
const(char)* lastp = cast(char*)buf[].ptr;
//printf("highlightCode2('%.*s')\n", cast(int)(buf.length - 1), buf[].ptr);
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index ab422fd..95cfec9 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -813,4 +813,14 @@ extern (C++) struct Scope
{
return this.intypeof || this.flags & SCOPE.compile;
}
+
+
+ /**
+ * Returns: true if the code needs to go all the way through to code generation.
+ * This implies things like needing lowering to simpler forms.
+ */
+ extern (D) bool needsCodegen()
+ {
+ return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0;
+ }
}
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 3268d56..49b9841 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -13,6 +13,8 @@
module dmd.dstruct;
+import core.stdc.stdio;
+
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
@@ -75,7 +77,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
{
if (sc.intypeof)
return;
- if (sc.flags & (SCOPE.ctfe | SCOPE.compile | SCOPE.ctfeBlock))
+ if (!sc.needsCodegen())
return;
}
@@ -567,7 +569,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
* Returns:
* true if it's all binary 0
*/
-private bool _isZeroInit(Expression exp)
+bool _isZeroInit(Expression exp)
{
switch (exp.op)
{
@@ -575,20 +577,22 @@ private bool _isZeroInit(Expression exp)
return exp.toInteger() == 0;
case EXP.null_:
- case EXP.false_:
return true;
case EXP.structLiteral:
{
- auto sle = cast(StructLiteralExp) exp;
+ auto sle = exp.isStructLiteralExp();
+ if (sle.sd.isNested())
+ return false;
+ const isCstruct = sle.sd.isCsymbol(); // C structs are default initialized to all zeros
foreach (i; 0 .. sle.sd.fields.length)
{
auto field = sle.sd.fields[i];
if (field.type.size(field.loc))
{
- auto e = (*sle.elements)[i];
+ auto e = sle.elements && i < sle.elements.length ? (*sle.elements)[i] : null;
if (e ? !_isZeroInit(e)
- : !field.type.isZeroInit(field.loc))
+ : !isCstruct && !field.type.isZeroInit(field.loc))
return false;
}
}
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index e7ce93e..2373313 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -1407,7 +1407,7 @@ extern (C++) class Dsymbol : ASTNode
inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; }
inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
inout(OverloadSet) isOverloadSet() inout { return null; }
- inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
+ inout(MixinDeclaration) isMixinDeclaration() inout { return null; }
inout(StaticAssert) isStaticAssert() inout { return null; }
inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; }
}
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 039a288..96fa8fd 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -321,7 +321,7 @@ public:
virtual CPPNamespaceDeclaration *isCPPNamespaceDeclaration() { return NULL; }
virtual VisibilityDeclaration *isVisibilityDeclaration() { return NULL; }
virtual OverloadSet *isOverloadSet() { return NULL; }
- virtual CompileDeclaration *isCompileDeclaration() { return NULL; }
+ virtual MixinDeclaration *isMixinDeclaration() { return NULL; }
virtual StaticAssert *isStaticAssert() { return NULL; }
virtual StaticIfDeclaration *isStaticIfDeclaration() { return NULL; }
void accept(Visitor *v) override { v->visit(this); }
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 0f0ed2a..506946f 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -1321,6 +1321,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (dsym.errors)
return;
+ if (!(global.params.bitfields || sc.flags & SCOPE.Cfile))
+ dsym.error("use -preview=bitfields for bitfield support");
+
if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration())
{
dsym.error("- bit-field must be member of struct, union, or class");
@@ -1923,9 +1926,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
attribSemantic(sfd);
}
- private Dsymbols* compileIt(CompileDeclaration cd)
+ private Dsymbols* compileIt(MixinDeclaration cd)
{
- //printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars());
+ //printf("MixinDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars());
OutBuffer buf;
if (expressionsToString(buf, sc, cd.exps))
return null;
@@ -1934,7 +1937,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
const len = buf.length;
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
- scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false, global.errorSink);
+ const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
+ 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.vin;
p.nextToken();
auto d = p.parseDeclDefs(0);
@@ -1952,9 +1958,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
/***********************************************************
* https://dlang.org/spec/module.html#mixin-declaration
*/
- override void visit(CompileDeclaration cd)
+ override void visit(MixinDeclaration cd)
{
- //printf("CompileDeclaration::semantic()\n");
+ //printf("MixinDeclaration::semantic()\n");
if (!cd.compiled)
{
cd.decl = compileIt(cd);
@@ -2252,32 +2258,39 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
/* C11 6.7.2.2
*/
- assert(ed.memtype);
- int nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0
+ Type commonType = ed.memtype;
+ if (!commonType)
+ commonType = Type.tint32;
+ ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0
// C11 6.7.2.2-2 value must be representable as an int.
// The sizemask represents all values that int will fit into,
// from 0..uint.max. We want to cover int.min..uint.max.
- const mask = Type.tint32.sizemask();
- IntRange ir = IntRange(SignExtendedNumber(~(mask >> 1), true),
- SignExtendedNumber(mask));
+ IntRange ir = IntRange.fromType(commonType);
- void emSemantic(EnumMember em, ref int nextValue)
+ void emSemantic(EnumMember em, ref ulong nextValue)
{
static void errorReturn(EnumMember em)
{
+ em.value = ErrorExp.get();
em.errors = true;
em.semanticRun = PASS.semanticdone;
}
em.semanticRun = PASS.semantic;
- em.type = Type.tint32;
+ em.type = commonType;
em._linkage = LINK.c;
em.storage_class |= STC.manifest;
if (em.value)
{
Expression e = em.value;
assert(e.dyncast() == DYNCAST.expression);
+
+ /* To merge the type of e with commonType, add 0 of type commonType
+ */
+ if (!ed.memtype)
+ e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType));
+
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
e = e.integralPromotions(sc);
@@ -2291,14 +2304,16 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
em.error("enum member must be an integral constant expression, not `%s` of type `%s`", e.toChars(), e.type.toChars());
return errorReturn(em);
}
- if (!ir.contains(getIntRange(ie)))
+ if (ed.memtype && !ir.contains(getIntRange(ie)))
{
// C11 6.7.2.2-2
- em.error("enum member value `%s` does not fit in an `int`", e.toChars());
+ em.error("enum member value `%s` does not fit in `%s`", e.toChars(), commonType.toChars());
return errorReturn(em);
}
- nextValue = cast(int)ie.toInteger();
- em.value = new IntegerExp(em.loc, nextValue, Type.tint32);
+ nextValue = ie.toInteger();
+ if (!ed.memtype)
+ commonType = e.type;
+ em.value = new IntegerExp(em.loc, nextValue, commonType);
}
else
{
@@ -2306,17 +2321,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
bool first = (em == (*em.ed.members)[0]);
if (!first)
{
- import core.checkedint : adds;
- bool overflow;
- nextValue = adds(nextValue, 1, overflow);
- if (overflow)
+ Expression max = getProperty(commonType, null, em.loc, Id.max, 0);
+ if (nextValue == max.toInteger())
{
- em.error("initialization with `%d+1` causes overflow for type `int`", nextValue - 1);
+ em.error("initialization with `%s+1` causes overflow for type `%s`", max.toChars(), commonType.toChars());
return errorReturn(em);
}
+ nextValue += 1;
}
- em.value = new IntegerExp(em.loc, nextValue, Type.tint32);
+ em.value = new IntegerExp(em.loc, nextValue, commonType);
}
+ em.type = commonType;
em.semanticRun = PASS.semanticdone;
}
@@ -2325,6 +2340,21 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (EnumMember em = s.isEnumMember())
emSemantic(em, nextValue);
});
+
+ if (!ed.memtype)
+ {
+ // cast all members to commonType
+ ed.members.foreachDsymbol( (s)
+ {
+ if (EnumMember em = s.isEnumMember())
+ {
+ em.type = commonType;
+ em.value = em.value.castTo(sc, commonType);
+ }
+ });
+ }
+
+ ed.memtype = commonType;
ed.semanticRun = PASS.semanticdone;
return;
}
@@ -4662,7 +4692,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
sd.visibility = sc.visibility;
- sd.alignment = sc.alignment();
+ if (sd.alignment.isUnknown()) // can be set already by `struct __declspec(align(N)) Tag { ... }`
+ sd.alignment = sc.alignment();
sd.storage_class |= sc.stc;
if (sd.storage_class & STC.abstract_)
@@ -7228,3 +7259,83 @@ PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args)
else
return PINLINE.never;
}
+
+/***************************************************
+ * Set up loc for a parse of a mixin. Append the input text to the mixin.
+ * Params:
+ * input = mixin text
+ * loc = location to adjust
+ * mixinOut = sink for mixin text data
+ * Returns:
+ * adjusted loc suitable for Parser
+ */
+
+Loc adjustLocForMixin(const(char)[] input, ref const Loc loc, ref Output mixinOut)
+{
+ Loc result;
+ if (mixinOut.doOutput)
+ {
+ const lines = mixinOut.bufferLines;
+ writeMixin(input, loc, mixinOut.bufferLines, *mixinOut.buffer);
+ result = Loc(mixinOut.name.ptr, lines + 2, loc.charnum);
+ }
+ else if (loc.filename)
+ {
+ /* Create a pseudo-filename for the mixin string, as it may not even exist
+ * in the source file.
+ */
+ auto len = strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1;
+ char* filename = cast(char*)mem.xmalloc(len);
+ snprintf(filename, len, "%s-mixin-%d", loc.filename, cast(int)loc.linnum);
+ result = Loc(filename, loc.linnum, loc.charnum);
+ }
+ else
+ result = loc;
+ return result;
+}
+
+/**************************************
+ * Append source code text to output for better debugging.
+ * Canonicalize line endings.
+ * Params:
+ * s = source code text
+ * loc = location of source code text
+ * lines = line count to update
+ * output = sink for output
+ */
+private void writeMixin(const(char)[] s, ref const Loc loc, ref int lines, ref OutBuffer buf)
+{
+ buf.writestring("// expansion at ");
+ buf.writestring(loc.toChars());
+ buf.writenl();
+
+ ++lines;
+
+ // write by line to create consistent line endings
+ size_t lastpos = 0;
+ for (size_t i = 0; i < s.length; ++i)
+ {
+ // detect LF and CRLF
+ const c = s[i];
+ if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n'))
+ {
+ buf.writestring(s[lastpos .. i]);
+ buf.writenl();
+ ++lines;
+ if (c == '\r')
+ ++i;
+ lastpos = i + 1;
+ }
+ }
+
+ if(lastpos < s.length)
+ buf.writestring(s[lastpos .. $]);
+
+ if (s.length == 0 || s[$-1] != '\n')
+ {
+ buf.writenl(); // ensure empty line after expansion
+ ++lines;
+ }
+ buf.writenl();
+ ++lines;
+}
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index ad3a6d4..ef743d6 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -741,9 +741,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
const(char)* toCharsMaybeConstraints(bool includeConstraints) const
{
- if (literal)
- return Dsymbol.toChars();
-
OutBuffer buf;
HdrGenState hgs;
@@ -1858,19 +1855,16 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
Type taai;
if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
{
- if (farg.op == EXP.string_)
+ if (StringExp se = farg.isStringExp())
{
- StringExp se = cast(StringExp)farg;
argtype = se.type.nextOf().sarrayOf(se.len);
}
- else if (farg.op == EXP.arrayLiteral)
+ else if (ArrayLiteralExp ae = farg.isArrayLiteralExp())
{
- ArrayLiteralExp ae = cast(ArrayLiteralExp)farg;
argtype = ae.type.nextOf().sarrayOf(ae.elements.length);
}
- else if (farg.op == EXP.slice)
+ else if (SliceExp se = farg.isSliceExp())
{
- SliceExp se = cast(SliceExp)farg;
if (Type tsa = toStaticArrayType(se))
argtype = tsa;
}
@@ -2283,18 +2277,23 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
Declaration d;
VarDeclaration v = null;
- if (ea && ea.op == EXP.type)
- ta = ea.type;
- else if (ea && ea.op == EXP.scope_)
- sa = (cast(ScopeExp)ea).sds;
- else if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
- sa = (cast(ThisExp)ea).var;
- else if (ea && ea.op == EXP.function_)
+ if (ea)
{
- if ((cast(FuncExp)ea).td)
- sa = (cast(FuncExp)ea).td;
- else
- sa = (cast(FuncExp)ea).fd;
+ if (ea.op == EXP.type)
+ ta = ea.type;
+ else if (auto se = ea.isScopeExp())
+ sa = se.sds;
+ else if (auto te = ea.isThisExp())
+ sa = te.var;
+ else if (auto se = ea.isSuperExp())
+ sa = se.var;
+ else if (auto fe = ea.isFuncExp())
+ {
+ if (fe.td)
+ sa = fe.td;
+ else
+ sa = fe.fd;
+ }
}
if (ta)
@@ -3856,9 +3855,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
if (tparam.ty == Tsarray)
{
TypeSArray tsa = cast(TypeSArray)tparam;
- if (tsa.dim.op == EXP.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
+ if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter)
{
- Identifier id = (cast(VarExp)tsa.dim).var.ident;
+ Identifier id = tsa.dim.isVarExp().var.ident;
i = templateIdentifierLookup(id, parameters);
assert(i != IDX_NOTFOUND);
tp = (*parameters)[i];
@@ -4250,12 +4249,12 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
/* If it is one of the template parameters for this template,
* we should not attempt to interpret it. It already has a value.
*/
- if (e2.op == EXP.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
+ if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter))
{
/*
* (T:Number!(e2), int e2)
*/
- j = templateIdentifierLookup((cast(VarExp)e2).var.ident, parameters);
+ j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters);
if (j != IDX_NOTFOUND)
goto L1;
// The template parameter was not from this template
@@ -5236,7 +5235,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
override void visit(DotTemplateInstanceExp e)
{
//printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(cast(UnaExp)e);
+ visit(e.isUnaExp());
if (!result && e.ti.tiargs)
{
foreach (oa; *e.ti.tiargs)
@@ -5254,7 +5253,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
override void visit(CallExp e)
{
//printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(cast(UnaExp)e);
+ visit(e.isUnaExp());
if (!result && e.arguments)
{
foreach (ea; *e.arguments)
@@ -5269,7 +5268,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
override void visit(CastExp e)
{
//printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(cast(UnaExp)e);
+ visit(e.isUnaExp());
// e.to can be null for cast() with no type
if (!result && e.to)
result = e.to.reliesOnTemplateParameters(tparams);
@@ -5278,7 +5277,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
override void visit(SliceExp e)
{
//printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(cast(UnaExp)e);
+ visit(e.isUnaExp());
if (!result && e.lwr)
e.lwr.accept(this);
if (!result && e.upr)
@@ -5296,7 +5295,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
override void visit(ArrayExp e)
{
//printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(cast(UnaExp)e);
+ visit(e.isUnaExp());
if (!result && e.arguments)
{
foreach (ea; *e.arguments)
@@ -5317,7 +5316,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
//printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
e.econd.accept(this);
if (!result)
- visit(cast(BinExp)e);
+ visit(e.isBinExp());
}
}
@@ -6727,7 +6726,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
ea = ea.expressionSemantic(sc);
// must not interpret the args, excepting template parameters
- if (ea.op != EXP.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
+ if (!ea.isVarExp() || (ea.isVarExp().var.storage_class & STC.templateparameter))
{
ea = ea.optimize(WANTvalue);
}
@@ -6738,13 +6737,13 @@ extern (C++) class TemplateInstance : ScopeDsymbol
ea = ea.expressionSemantic(sc);
sc = sc.endCTFE();
- if (ea.op == EXP.variable)
+ if (auto varExp = ea.isVarExp())
{
/* If the parameter is a function that is not called
* explicitly, i.e. `foo!func` as opposed to `foo!func()`,
* then it is a dsymbol, not the return value of `func()`
*/
- Declaration vd = (cast(VarExp)ea).var;
+ Declaration vd = varExp.var;
if (auto fd = vd.isFuncDeclaration())
{
sa = fd;
@@ -6767,10 +6766,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol
}
}
//printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
- if (ea.op == EXP.tuple)
+ if (TupleExp te = ea.isTupleExp())
{
// Expand tuple
- TupleExp te = cast(TupleExp)ea;
size_t dim = te.exps.length;
tiargs.remove(j);
if (dim)
@@ -6796,12 +6794,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol
}
if (ea.op == EXP.scope_)
{
- sa = (cast(ScopeExp)ea).sds;
+ sa = ea.isScopeExp().sds;
goto Ldsym;
}
- if (ea.op == EXP.function_)
+ if (FuncExp fe = ea.isFuncExp())
{
- FuncExp fe = cast(FuncExp)ea;
/* A function literal, that is passed to template and
* already semanticed as function pointer, never requires
* outer frame. So convert it to global function is valid.
@@ -6823,23 +6820,23 @@ extern (C++) class TemplateInstance : ScopeDsymbol
if (ea.op == EXP.dotVariable && !(flags & 1))
{
// translate expression to dsymbol.
- sa = (cast(DotVarExp)ea).var;
+ sa = ea.isDotVarExp().var;
goto Ldsym;
}
- if (ea.op == EXP.template_)
+ if (auto te = ea.isTemplateExp())
{
- sa = (cast(TemplateExp)ea).td;
+ sa = te.td;
goto Ldsym;
}
if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1))
{
// translate expression to dsymbol.
- sa = (cast(DotTemplateExp)ea).td;
+ sa = ea.isDotTemplateExp().td;
goto Ldsym;
}
- if (ea.op == EXP.dot)
+ if (auto de = ea.isDotExp())
{
- if (auto se = (cast(DotExp)ea).e2.isScopeExp())
+ if (auto se = de.e2.isScopeExp())
{
sa = se.sds;
goto Ldsym;
@@ -7340,22 +7337,22 @@ extern (C++) class TemplateInstance : ScopeDsymbol
Tuple va = isTuple(o);
if (ea)
{
- if (ea.op == EXP.variable)
+ if (auto ve = ea.isVarExp())
{
- sa = (cast(VarExp)ea).var;
+ sa = ve.var;
goto Lsa;
}
- if (ea.op == EXP.this_)
+ if (auto te = ea.isThisExp())
{
- sa = (cast(ThisExp)ea).var;
+ sa = te.var;
goto Lsa;
}
- if (ea.op == EXP.function_)
+ if (auto fe = ea.isFuncExp())
{
- if ((cast(FuncExp)ea).td)
- sa = (cast(FuncExp)ea).td;
+ if (fe.td)
+ sa = fe.td;
else
- sa = (cast(FuncExp)ea).fd;
+ sa = fe.fd;
goto Lsa;
}
// Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
@@ -7727,13 +7724,13 @@ bool definitelyValueParameter(Expression e)
*/
// x.y.f cannot be a value
- FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration();
+ FuncDeclaration f = e.isDotVarExp().var.isFuncDeclaration();
if (f)
return false;
while (e.op == EXP.dotVariable)
{
- e = (cast(DotVarExp)e).e1;
+ e = e.isDotVarExp().e1;
}
// this.x.y and super.x.y couldn't possibly be valid values.
if (e.op == EXP.this_ || e.op == EXP.super_)
@@ -7747,7 +7744,7 @@ bool definitelyValueParameter(Expression e)
if (e.op != EXP.variable)
return true;
- VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
+ VarDeclaration v = e.isVarExp().var.isVarDeclaration();
// func.x.y is not an alias
if (!v)
return true;
@@ -8242,10 +8239,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
Type ta = isType(oarg);
RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
Expression ea = isExpression(oarg);
- if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
- sa = (cast(ThisExp)ea).var;
- else if (ea && ea.op == EXP.scope_)
- sa = (cast(ScopeExp)ea).sds;
+ if (ea)
+ {
+ if (auto te = ea.isThisExp())
+ sa = te.var;
+ else if (auto se = ea.isSuperExp())
+ sa = se.var;
+ else if (auto se = ea.isScopeExp())
+ sa = se.sds;
+ }
if (sa)
{
if ((cast(Dsymbol)sa).isAggregateDeclaration())
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 7c3ff4b..f00b8db 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -84,9 +84,9 @@ extern(C++) void genCppHdrFiles(ref Modules ms)
m.accept(v);
if (global.params.cxxhdr.fullOutput)
- buf.printf("// Automatically generated by %s Compiler v%d", global.vendor.ptr, global.versionNumber());
+ buf.printf("// Automatically generated by %s Compiler v%d", global.compileEnv.vendor.ptr, global.versionNumber());
else
- buf.printf("// Automatically generated by %s Compiler", global.vendor.ptr);
+ buf.printf("// Automatically generated by %s Compiler", global.compileEnv.vendor.ptr);
buf.writenl();
buf.writenl();
diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d
index f107f7b..287dc49 100644
--- a/gcc/d/dmd/errors.d
+++ b/gcc/d/dmd/errors.d
@@ -66,6 +66,14 @@ class ErrorSinkCompiler : ErrorSink
vdeprecationSupplemental(loc, format, ap);
va_end(ap);
}
+
+ void message(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vmessage(loc, format, ap);
+ va_end(ap);
+ }
}
diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d
index b519db7..e57c2b6 100644
--- a/gcc/d/dmd/errorsink.d
+++ b/gcc/d/dmd/errorsink.d
@@ -27,6 +27,8 @@ abstract class ErrorSink
void warning(const ref Loc loc, const(char)* format, ...);
+ void message(const ref Loc loc, const(char)* format, ...);
+
void deprecation(const ref Loc loc, const(char)* format, ...);
void deprecationSupplemental(const ref Loc loc, const(char)* format, ...);
@@ -47,6 +49,8 @@ class ErrorSinkNull : ErrorSink
void warning(const ref Loc loc, const(char)* format, ...) { }
+ void message(const ref Loc loc, const(char)* format, ...) { }
+
void deprecation(const ref Loc loc, const(char)* format, ...) { }
void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
@@ -117,5 +121,21 @@ class ErrorSinkStderr : ErrorSink
va_end(ap);
}
+ void message(const ref Loc loc, const(char)* format, ...)
+ {
+ const p = loc.toChars();
+ if (*p)
+ {
+ fprintf(stderr, "%s: ", p);
+ //mem.xfree(cast(void*)p); // loc should provide the free()
+ }
+
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+ }
+
void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
}
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 420fa7f..4f1edaa 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -2377,7 +2377,7 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
foreach (u, p; f.parameterList)
{
auto v = (*funcdecl.parameters)[u];
- if (!v.isScope() && inferScope(v))
+ if (!v.isScope() && v.type.hasPointers() && inferScope(v))
{
//printf("Inferring scope for %s\n", v.toChars());
p.storageClass |= STC.scope_ | STC.scopeinferred;
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index df5e9dd..067d22f 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -720,20 +720,21 @@ enum WANTexpand = 1; // expand const/immutable variables if possible
*/
extern (C++) abstract class Expression : ASTNode
{
- const EXP op; // to minimize use of dynamic_cast
- ubyte size; // # of bytes in Expression so we can copy() it
- bool parens; // if this is a parenthesized expression
Type type; // !=null means that semantic() has been run
Loc loc; // file location
+ const EXP op; // to minimize use of dynamic_cast
+ bool parens; // if this is a parenthesized expression
- extern (D) this(const ref Loc loc, EXP op, int size) scope
+ extern (D) this(const ref Loc loc, EXP op) scope
{
//printf("Expression::Expression(op = %d) this = %p\n", op, this);
this.loc = loc;
this.op = op;
- this.size = cast(ubyte)size;
}
+ /// Returns: class instance size of this expression (implemented manually because `extern(C++)`)
+ final size_t size() nothrow @nogc pure @safe const { return expSize[op]; }
+
static void _init()
{
CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
@@ -1219,12 +1220,15 @@ extern (C++) abstract class Expression : ASTNode
return false;
// If the call has a pure parent, then the called func must be pure.
- if (!f.isPure() && checkImpure(sc))
+ if (!f.isPure() && checkImpure(sc, loc, null, f))
{
error("`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_);
+
checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
return true;
}
@@ -1355,7 +1359,7 @@ extern (C++) abstract class Expression : ASTNode
if (v.ident == Id.gate)
return false;
- if (checkImpure(sc))
+ if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v))
{
error("`pure` %s `%s` cannot access mutable static data `%s`",
sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
@@ -1431,11 +1435,11 @@ extern (C++) abstract class Expression : ASTNode
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)
+ 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());
+ : sc.func.setImpure(loc, fmt, arg0));
}
/*********************************************
@@ -1484,7 +1488,8 @@ extern (C++) abstract class Expression : ASTNode
error("`@safe` %s `%s` cannot call `@system` %s `%s`",
sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
prettyChars);
- f.errorSupplementalInferredSafety(/*max depth*/ 10, /*deprecation*/ false);
+ if (!f.isDtorDeclaration)
+ errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe);
.errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
@@ -1498,7 +1503,7 @@ extern (C++) abstract class Expression : ASTNode
if (sc.func.isSafeBypassingInference())
{
.deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
- errorSupplementalInferredSafety(f, 10, true);
+ errorSupplementalInferredAttr(f, 10, true, STC.safe);
}
else if (!sc.func.safetyViolation)
{
@@ -1528,7 +1533,7 @@ extern (C++) abstract class Expression : ASTNode
if (!f.isNogc())
{
- if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGC())
+ if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f))
{
if (loc.linnum == 0) // e.g. implicitly generated dtor
loc = sc.func.loc;
@@ -1537,10 +1542,15 @@ extern (C++) abstract class Expression : ASTNode
// 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_newclassT))
+ || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
+ {
error("`@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);
+ }
+
checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
return true;
@@ -1775,6 +1785,7 @@ extern (C++) abstract class Expression : ASTNode
inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; }
+ inout(LoweredAssignExp) isLoweredAssignExp() { return op == EXP.loweredAssignExp ? cast(typeof(return))this : null; }
inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; }
inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
@@ -1866,7 +1877,7 @@ extern (C++) final class IntegerExp : Expression
extern (D) this(const ref Loc loc, dinteger_t value, Type type)
{
- super(loc, EXP.int64, __traits(classInstanceSize, IntegerExp));
+ super(loc, EXP.int64);
//printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
assert(type);
if (!type.isscalar())
@@ -1882,7 +1893,7 @@ extern (C++) final class IntegerExp : Expression
extern (D) this(dinteger_t value)
{
- super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp));
+ super(Loc.initial, EXP.int64);
this.type = Type.tint32;
this.value = cast(int)value;
}
@@ -2082,7 +2093,7 @@ extern (C++) final class ErrorExp : Expression
{
private extern (D) this()
{
- super(Loc.initial, EXP.error, __traits(classInstanceSize, ErrorExp));
+ super(Loc.initial, EXP.error);
type = Type.terror;
}
@@ -2130,7 +2141,7 @@ extern (C++) final class VoidInitExp : Expression
extern (D) this(VarDeclaration var)
{
- super(var.loc, EXP.void_, __traits(classInstanceSize, VoidInitExp));
+ super(var.loc, EXP.void_);
this.var = var;
this.type = var.type;
}
@@ -2156,7 +2167,7 @@ extern (C++) final class RealExp : Expression
extern (D) this(const ref Loc loc, real_t value, Type type)
{
- super(loc, EXP.float64, __traits(classInstanceSize, RealExp));
+ super(loc, EXP.float64);
//printf("RealExp::RealExp(%Lg)\n", value);
this.value = value;
this.type = type;
@@ -2239,7 +2250,7 @@ extern (C++) final class ComplexExp : Expression
extern (D) this(const ref Loc loc, complex_t value, Type type)
{
- super(loc, EXP.complex80, __traits(classInstanceSize, ComplexExp));
+ super(loc, EXP.complex80);
this.value = value;
this.type = type;
//printf("ComplexExp::ComplexExp(%s)\n", toChars());
@@ -2330,7 +2341,7 @@ extern (C++) class IdentifierExp : Expression
extern (D) this(const ref Loc loc, Identifier ident) scope
{
- super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp));
+ super(loc, EXP.identifier);
this.ident = ident;
}
@@ -2383,7 +2394,7 @@ extern (C++) final class DsymbolExp : Expression
extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
{
- super(loc, EXP.dSymbol, __traits(classInstanceSize, DsymbolExp));
+ super(loc, EXP.dSymbol);
this.s = s;
this.hasOverloads = hasOverloads;
}
@@ -2413,13 +2424,13 @@ extern (C++) class ThisExp : Expression
extern (D) this(const ref Loc loc)
{
- super(loc, EXP.this_, __traits(classInstanceSize, ThisExp));
+ super(loc, EXP.this_);
//printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
}
this(const ref Loc loc, const EXP tok)
{
- super(loc, tok, __traits(classInstanceSize, ThisExp));
+ super(loc, tok);
//printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
}
@@ -2485,7 +2496,7 @@ extern (C++) final class NullExp : Expression
{
extern (D) this(const ref Loc loc, Type type = null) scope
{
- super(loc, EXP.null_, __traits(classInstanceSize, NullExp));
+ super(loc, EXP.null_);
this.type = type;
}
@@ -2529,6 +2540,8 @@ extern (C++) final class NullExp : Expression
*/
extern (C++) final class StringExp : Expression
{
+ char postfix = NoPostfix; // 'c', 'w', 'd'
+ OwnedBy ownedByCtfe = OwnedBy.code;
private union
{
char* string; // if sz == 1
@@ -2537,14 +2550,22 @@ extern (C++) final class StringExp : Expression
} // (const if ownedByCtfe == OwnedBy.code)
size_t len; // number of code units
ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
- ubyte committed; // !=0 if type is committed
+
+ /**
+ * Whether the string literal's type is fixed
+ * Example:
+ * ---
+ * wstring x = "abc"; // OK, string literal is flexible
+ * wstring y = cast(string) "abc"; // Error: type was committed after cast
+ * ---
+ */
+ bool committed;
+
enum char NoPostfix = 0;
- char postfix = NoPostfix; // 'c', 'w', 'd'
- OwnedBy ownedByCtfe = OwnedBy.code;
extern (D) this(const ref Loc loc, const(void)[] string) scope
{
- super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
+ super(loc, EXP.string_);
this.string = cast(char*)string.ptr; // note that this.string should be const
this.len = string.length;
this.sz = 1; // work around LDC bug #1286
@@ -2552,7 +2573,7 @@ extern (C++) final class StringExp : Expression
extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope
{
- super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
+ super(loc, EXP.string_);
this.string = cast(char*)string.ptr; // note that this.string should be const
this.len = len;
this.sz = sz;
@@ -2750,7 +2771,7 @@ extern (C++) final class StringExp : Expression
if (sz != 1)
{
// Convert to UTF-8 string
- committed = 0;
+ committed = false;
Expression e = castTo(sc, Type.tchar.arrayOf());
e = e.optimize(WANTvalue);
auto se = e.isStringExp();
@@ -2939,7 +2960,7 @@ extern (C++) final class TupleExp : Expression
extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
{
- super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
+ super(loc, EXP.tuple);
//printf("TupleExp(this = %p)\n", this);
this.e0 = e0;
this.exps = exps;
@@ -2947,14 +2968,14 @@ extern (C++) final class TupleExp : Expression
extern (D) this(const ref Loc loc, Expressions* exps)
{
- super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
+ super(loc, EXP.tuple);
//printf("TupleExp(this = %p)\n", this);
this.exps = exps;
}
extern (D) this(const ref Loc loc, TupleDeclaration tup)
{
- super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
+ super(loc, EXP.tuple);
this.exps = new Expressions();
this.exps.reserve(tup.objects.length);
@@ -3031,6 +3052,9 @@ extern (C++) final class TupleExp : Expression
*/
extern (C++) final class ArrayLiteralExp : Expression
{
+ OwnedBy ownedByCtfe = OwnedBy.code;
+ bool onstack = false;
+
/** If !is null, elements[] can be sparse and basis is used for the
* "default" element value. In other words, non-null elements[i] overrides
* this 'basis' value.
@@ -3038,19 +3062,17 @@ extern (C++) final class ArrayLiteralExp : Expression
Expression basis;
Expressions* elements;
- OwnedBy ownedByCtfe = OwnedBy.code;
- bool onstack = false;
extern (D) this(const ref Loc loc, Type type, Expressions* elements)
{
- super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ super(loc, EXP.arrayLiteral);
this.type = type;
this.elements = elements;
}
extern (D) this(const ref Loc loc, Type type, Expression e)
{
- super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ super(loc, EXP.arrayLiteral);
this.type = type;
elements = new Expressions();
elements.push(e);
@@ -3058,7 +3080,7 @@ extern (C++) final class ArrayLiteralExp : Expression
extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
{
- super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ super(loc, EXP.arrayLiteral);
this.type = type;
this.basis = basis;
this.elements = elements;
@@ -3196,14 +3218,14 @@ extern (C++) final class ArrayLiteralExp : Expression
*/
extern (C++) final class AssocArrayLiteralExp : Expression
{
+ OwnedBy ownedByCtfe = OwnedBy.code;
+
Expressions* keys;
Expressions* values;
- OwnedBy ownedByCtfe = OwnedBy.code;
-
extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
{
- super(loc, EXP.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
+ super(loc, EXP.assocArrayLiteral);
assert(keys.length == values.length);
this.keys = keys;
this.values = values;
@@ -3271,7 +3293,15 @@ extern (C++) final class StructLiteralExp : Expression
Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
Type stype; /// final type of result (can be different from sd's type)
- Symbol* sym; /// back end symbol to initialize with literal
+ // `inlineCopy` is only used temporarily in the `inline.d` pass,
+ // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
+ union
+ {
+ Symbol* sym; /// back end symbol to initialize with literal
+
+ /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
+ StructLiteralExp inlinecopy;
+ }
/** pointer to the origin instance of the expression.
* once a new expression is created, origin is set to 'this'.
@@ -3280,15 +3310,13 @@ extern (C++) final class StructLiteralExp : Expression
*/
StructLiteralExp origin;
- /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
- StructLiteralExp inlinecopy;
/** anytime when recursive function is calling, 'stageflags' marks with bit flag of
* current stage and unmarks before return from this function.
* 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
* (with infinite recursion) of this expression.
*/
- int stageflags;
+ ubyte stageflags;
bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
@@ -3296,7 +3324,7 @@ extern (C++) final class StructLiteralExp : Expression
extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
{
- super(loc, EXP.structLiteral, __traits(classInstanceSize, StructLiteralExp));
+ super(loc, EXP.structLiteral);
this.sd = sd;
if (!elements)
elements = new Expressions();
@@ -3475,7 +3503,7 @@ extern (C++) final class CompoundLiteralExp : Expression
extern (D) this(const ref Loc loc, Type type_name, Initializer initializer)
{
- super(loc, EXP.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp));
+ super(loc, EXP.compoundLiteral);
super.type = type_name;
this.initializer = initializer;
//printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
@@ -3494,7 +3522,7 @@ extern (C++) final class TypeExp : Expression
{
extern (D) this(const ref Loc loc, Type type)
{
- super(loc, EXP.type, __traits(classInstanceSize, TypeExp));
+ super(loc, EXP.type);
//printf("TypeExp::TypeExp(%s)\n", type.toChars());
this.type = type;
}
@@ -3536,7 +3564,7 @@ extern (C++) final class ScopeExp : Expression
extern (D) this(const ref Loc loc, ScopeDsymbol sds)
{
- super(loc, EXP.scope_, __traits(classInstanceSize, ScopeExp));
+ super(loc, EXP.scope_);
//printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
//static int count; if (++count == 38) *(char*)0=0;
this.sds = sds;
@@ -3591,7 +3619,7 @@ extern (C++) final class TemplateExp : Expression
extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
{
- super(loc, EXP.template_, __traits(classInstanceSize, TemplateExp));
+ super(loc, EXP.template_);
//printf("TemplateExp(): %s\n", td.toChars());
this.td = td;
this.fd = fd;
@@ -3652,7 +3680,7 @@ extern (C++) final class NewExp : Expression
extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null)
{
- super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
+ super(loc, EXP.new_);
this.thisexp = thisexp;
this.newtype = newtype;
this.arguments = arguments;
@@ -3690,7 +3718,7 @@ extern (C++) final class NewAnonClassExp : Expression
extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
{
- super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
+ super(loc, EXP.newAnonymousClass);
this.thisexp = thisexp;
this.cd = cd;
this.arguments = arguments;
@@ -3715,9 +3743,9 @@ extern (C++) class SymbolExp : Expression
Dsymbol originalScope; // original scope before inlining
bool hasOverloads;
- extern (D) this(const ref Loc loc, EXP op, int size, Declaration var, bool hasOverloads)
+ extern (D) this(const ref Loc loc, EXP op, Declaration var, bool hasOverloads)
{
- super(loc, op, size);
+ super(loc, op);
assert(var);
this.var = var;
this.hasOverloads = hasOverloads;
@@ -3746,7 +3774,7 @@ extern (C++) final class SymOffExp : SymbolExp
.error(loc, "need `this` for address of `%s`", v.toChars());
hasOverloads = false;
}
- super(loc, EXP.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
+ super(loc, EXP.symbolOffset, var, hasOverloads);
this.offset = offset;
}
@@ -3772,7 +3800,7 @@ extern (C++) final class VarExp : SymbolExp
if (var.isVarDeclaration())
hasOverloads = false;
- super(loc, EXP.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
+ super(loc, EXP.variable, var, hasOverloads);
//printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
//if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
this.type = var.type;
@@ -3856,7 +3884,7 @@ extern (C++) final class OverExp : Expression
extern (D) this(const ref Loc loc, OverloadSet s)
{
- super(loc, EXP.overloadSet, __traits(classInstanceSize, OverExp));
+ super(loc, EXP.overloadSet);
//printf("OverExp(this = %p, '%s')\n", this, var.toChars());
vars = s;
type = Type.tvoid;
@@ -3890,7 +3918,7 @@ extern (C++) final class FuncExp : Expression
extern (D) this(const ref Loc loc, Dsymbol s)
{
- super(loc, EXP.function_, __traits(classInstanceSize, FuncExp));
+ super(loc, EXP.function_);
this.td = s.isTemplateDeclaration();
this.fd = s.isFuncLiteralDeclaration();
if (td)
@@ -4189,7 +4217,7 @@ extern (C++) final class DeclarationExp : Expression
extern (D) this(const ref Loc loc, Dsymbol declaration)
{
- super(loc, EXP.declaration, __traits(classInstanceSize, DeclarationExp));
+ super(loc, EXP.declaration);
this.declaration = declaration;
}
@@ -4222,7 +4250,7 @@ extern (C++) final class TypeidExp : Expression
extern (D) this(const ref Loc loc, RootObject o)
{
- super(loc, EXP.typeid_, __traits(classInstanceSize, TypeidExp));
+ super(loc, EXP.typeid_);
this.obj = o;
}
@@ -4247,7 +4275,7 @@ extern (C++) final class TraitsExp : Expression
extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
{
- super(loc, EXP.traits, __traits(classInstanceSize, TraitsExp));
+ super(loc, EXP.traits);
this.ident = ident;
this.args = args;
}
@@ -4272,7 +4300,7 @@ extern (C++) final class HaltExp : Expression
{
extern (D) this(const ref Loc loc)
{
- super(loc, EXP.halt, __traits(classInstanceSize, HaltExp));
+ super(loc, EXP.halt);
}
override void accept(Visitor v)
@@ -4296,7 +4324,7 @@ extern (C++) final class IsExp : Expression
extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope
{
- super(loc, EXP.is_, __traits(classInstanceSize, IsExp));
+ super(loc, EXP.is_);
this.targ = targ;
this.id = id;
this.tok = tok;
@@ -4332,11 +4360,10 @@ extern (C++) final class IsExp : Expression
extern (C++) abstract class UnaExp : Expression
{
Expression e1;
- Type att1; // Save alias this type to detect recursion
- extern (D) this(const ref Loc loc, EXP op, int size, Expression e1) scope
+ extern (D) this(const ref Loc loc, EXP op, Expression e1) scope
{
- super(loc, op, size);
+ super(loc, op);
this.e1 = e1;
}
@@ -4407,9 +4434,9 @@ extern (C++) abstract class BinExp : Expression
Type att1; // Save alias this type to detect recursion
Type att2; // Save alias this type to detect recursion
- extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) scope
+ extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope
{
- super(loc, op, size);
+ super(loc, op);
this.e1 = e1;
this.e2 = e2;
}
@@ -4698,9 +4725,9 @@ extern (C++) abstract class BinExp : Expression
*/
extern (C++) class BinAssignExp : BinExp
{
- extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) scope
+ extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope
{
- super(loc, op, size, e1, e2);
+ super(loc, op, e1, e2);
}
override final bool isLvalue()
@@ -4737,7 +4764,7 @@ extern (C++) final class MixinExp : Expression
extern (D) this(const ref Loc loc, Expressions* exps)
{
- super(loc, EXP.mixin_, __traits(classInstanceSize, MixinExp));
+ super(loc, EXP.mixin_);
this.exps = exps;
}
@@ -4785,7 +4812,7 @@ extern (C++) final class ImportExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, EXP.import_, __traits(classInstanceSize, ImportExp), e);
+ super(loc, EXP.import_, e);
}
override void accept(Visitor v)
@@ -4805,7 +4832,7 @@ extern (C++) final class AssertExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
{
- super(loc, EXP.assert_, __traits(classInstanceSize, AssertExp), e);
+ super(loc, EXP.assert_, e);
this.msg = msg;
}
@@ -4830,7 +4857,7 @@ extern (C++) final class ThrowExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, EXP.throw_, __traits(classInstanceSize, ThrowExp), e);
+ super(loc, EXP.throw_, e);
this.type = Type.tnoreturn;
}
@@ -4856,7 +4883,7 @@ extern (C++) final class DotIdExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, Identifier ident)
{
- super(loc, EXP.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
+ super(loc, EXP.dotIdentifier, e);
this.ident = ident;
}
@@ -4880,7 +4907,7 @@ extern (C++) final class DotTemplateExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
{
- super(loc, EXP.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
+ super(loc, EXP.dotTemplateDeclaration, e);
this.td = td;
}
@@ -4914,7 +4941,7 @@ extern (C++) final class DotVarExp : UnaExp
if (var.isVarDeclaration())
hasOverloads = false;
- super(loc, EXP.dotVariable, __traits(classInstanceSize, DotVarExp), e);
+ super(loc, EXP.dotVariable, e);
//printf("DotVarExp()\n");
this.var = var;
this.hasOverloads = hasOverloads;
@@ -4995,14 +5022,14 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
{
- super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
+ super(loc, EXP.dotTemplateInstance, e);
//printf("DotTemplateInstanceExp()\n");
this.ti = new TemplateInstance(loc, name, tiargs);
}
extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
{
- super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
+ super(loc, EXP.dotTemplateInstance, e);
this.ti = ti;
}
@@ -5095,7 +5122,7 @@ extern (C++) final class DelegateExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
{
- super(loc, EXP.delegate_, __traits(classInstanceSize, DelegateExp), e);
+ super(loc, EXP.delegate_, e);
this.func = f;
this.hasOverloads = hasOverloads;
this.vthis2 = vthis2;
@@ -5115,7 +5142,7 @@ extern (C++) final class DotTypeExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
{
- super(loc, EXP.dotType, __traits(classInstanceSize, DotTypeExp), e);
+ super(loc, EXP.dotType, e);
this.sym = s;
}
@@ -5169,19 +5196,19 @@ extern (C++) final class CallExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null)
{
- super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
+ super(loc, EXP.call, e);
this.arguments = exps;
this.names = names;
}
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
+ super(loc, EXP.call, e);
}
extern (D) this(const ref Loc loc, Expression e, Expression earg1)
{
- super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
+ super(loc, EXP.call, e);
this.arguments = new Expressions();
if (earg1)
this.arguments.push(earg1);
@@ -5189,7 +5216,7 @@ extern (C++) final class CallExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
{
- super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
+ super(loc, EXP.call, e);
auto arguments = new Expressions(2);
(*arguments)[0] = earg1;
(*arguments)[1] = earg2;
@@ -5345,7 +5372,7 @@ extern (C++) final class AddrExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, EXP.address, __traits(classInstanceSize, AddrExp), e);
+ super(loc, EXP.address, e);
}
extern (D) this(const ref Loc loc, Expression e, Type t)
@@ -5367,14 +5394,14 @@ extern (C++) final class PtrExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
+ super(loc, EXP.star, e);
//if (e.type)
// type = ((TypePointer *)e.type).next;
}
extern (D) this(const ref Loc loc, Expression e, Type t)
{
- super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
+ super(loc, EXP.star, e);
type = t;
}
@@ -5420,7 +5447,7 @@ extern (C++) final class NegExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, EXP.negate, __traits(classInstanceSize, NegExp), e);
+ super(loc, EXP.negate, e);
}
override void accept(Visitor v)
@@ -5436,7 +5463,7 @@ extern (C++) final class UAddExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e) scope
{
- super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e);
+ super(loc, EXP.uadd, e);
}
override void accept(Visitor v)
@@ -5452,7 +5479,7 @@ extern (C++) final class ComExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, EXP.tilde, __traits(classInstanceSize, ComExp), e);
+ super(loc, EXP.tilde, e);
}
override void accept(Visitor v)
@@ -5468,7 +5495,7 @@ extern (C++) final class NotExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, EXP.not, __traits(classInstanceSize, NotExp), e);
+ super(loc, EXP.not, e);
}
override void accept(Visitor v)
@@ -5488,7 +5515,7 @@ extern (C++) final class DeleteExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, bool isRAII)
{
- super(loc, EXP.delete_, __traits(classInstanceSize, DeleteExp), e);
+ super(loc, EXP.delete_, e);
this.isRAII = isRAII;
}
@@ -5512,7 +5539,7 @@ extern (C++) final class CastExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, Type t)
{
- super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
+ super(loc, EXP.cast_, e);
this.to = t;
}
@@ -5520,7 +5547,7 @@ extern (C++) final class CastExp : UnaExp
*/
extern (D) this(const ref Loc loc, Expression e, ubyte mod)
{
- super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
+ super(loc, EXP.cast_, e);
this.mod = mod;
}
@@ -5574,7 +5601,7 @@ extern (C++) final class VectorExp : UnaExp
extern (D) this(const ref Loc loc, Expression e, Type t)
{
- super(loc, EXP.vector, __traits(classInstanceSize, VectorExp), e);
+ super(loc, EXP.vector, e);
assert(t.ty == Tvector);
to = cast(TypeVector)t;
}
@@ -5610,7 +5637,7 @@ extern (C++) final class VectorArrayExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e1)
{
- super(loc, EXP.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
+ super(loc, EXP.vectorArray, e1);
}
override bool isLvalue()
@@ -5641,21 +5668,27 @@ extern (C++) final class SliceExp : UnaExp
Expression lwr; // null if implicit [length - 1]
VarDeclaration lengthVar;
- bool upperIsInBounds; // true if upr <= e1.length
- bool lowerIsLessThanUpper; // true if lwr <= upr
- bool arrayop; // an array operation, rather than a slice
+
+ private extern(D) static struct BitFields
+ {
+ bool upperIsInBounds; // true if upr <= e1.length
+ bool lowerIsLessThanUpper; // true if lwr <= upr
+ bool arrayop; // an array operation, rather than a slice
+ }
+ import dmd.common.bitfields : generateBitFields;
+ mixin(generateBitFields!(BitFields, ubyte));
/************************************************************/
extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
{
- super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
+ super(loc, EXP.slice, e1);
this.upr = ie ? ie.upr : null;
this.lwr = ie ? ie.lwr : null;
}
extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
{
- super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
+ super(loc, EXP.slice, e1);
this.upr = upr;
this.lwr = lwr;
}
@@ -5705,7 +5738,7 @@ extern (C++) final class ArrayLengthExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e1)
{
- super(loc, EXP.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
+ super(loc, EXP.arrayLength, e1);
}
override void accept(Visitor v)
@@ -5728,7 +5761,7 @@ extern (C++) final class ArrayExp : UnaExp
extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
{
- super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
+ super(loc, EXP.array, e1);
arguments = new Expressions();
if (index)
arguments.push(index);
@@ -5736,7 +5769,7 @@ extern (C++) final class ArrayExp : UnaExp
extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
{
- super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
+ super(loc, EXP.array, e1);
arguments = args;
}
@@ -5773,7 +5806,7 @@ extern (C++) final class DotExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.dot, __traits(classInstanceSize, DotExp), e1, e2);
+ super(loc, EXP.dot, e1, e2);
}
override void accept(Visitor v)
@@ -5799,7 +5832,7 @@ extern (C++) final class CommaExp : BinExp
extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
{
- super(loc, EXP.comma, __traits(classInstanceSize, CommaExp), e1, e2);
+ super(loc, EXP.comma, e1, e2);
allowCommaExp = isGenerated = generated;
}
@@ -5868,7 +5901,7 @@ extern (C++) final class IntervalExp : Expression
extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
{
- super(loc, EXP.interval, __traits(classInstanceSize, IntervalExp));
+ super(loc, EXP.interval);
this.lwr = lwr;
this.upr = upr;
}
@@ -5893,7 +5926,7 @@ extern (C++) final class DelegatePtrExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e1)
{
- super(loc, EXP.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
+ super(loc, EXP.delegatePointer, e1);
}
override bool isLvalue()
@@ -5931,7 +5964,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e1)
{
- super(loc, EXP.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
+ super(loc, EXP.delegateFunctionPointer, e1);
}
override bool isLvalue()
@@ -5971,13 +6004,13 @@ extern (C++) final class IndexExp : BinExp
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
+ super(loc, EXP.index, e1, e2);
//printf("IndexExp::IndexExp('%s')\n", toChars());
}
extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds)
{
- super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
+ super(loc, EXP.index, e1, e2);
this.indexIsInBounds = indexIsInBounds;
//printf("IndexExp::IndexExp('%s')\n", toChars());
}
@@ -6054,7 +6087,7 @@ extern (C++) final class PostExp : BinExp
{
extern (D) this(EXP op, const ref Loc loc, Expression e)
{
- super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1);
+ super(loc, op, e, IntegerExp.literal!1);
assert(op == EXP.minusMinus || op == EXP.plusPlus);
}
@@ -6071,7 +6104,7 @@ extern (C++) final class PreExp : UnaExp
{
extern (D) this(EXP op, const ref Loc loc, Expression e)
{
- super(loc, op, __traits(classInstanceSize, PreExp), e);
+ super(loc, op, e);
assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
}
@@ -6101,12 +6134,12 @@ extern (C++) class AssignExp : BinExp
/* op can be EXP.assign, EXP.construct, or EXP.blit */
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.assign, __traits(classInstanceSize, AssignExp), e1, e2);
+ super(loc, EXP.assign, e1, e2);
}
this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
{
- super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
+ super(loc, tok, e1, e2);
}
override final bool isLvalue()
@@ -6141,6 +6174,32 @@ extern (C++) class AssignExp : BinExp
}
/***********************************************************
+ * When an assignment expression is lowered to a druntime call
+ * this class is used to store the lowering.
+ * It essentially behaves the same as an AssignExp, but it is
+ * used to not waste space for other AssignExp that are not
+ * lowered to anything.
+ */
+extern (C++) final class LoweredAssignExp : AssignExp
+{
+ Expression lowering;
+ extern (D) this(AssignExp exp, Expression lowering)
+ {
+ super(exp.loc, EXP.loweredAssignExp, exp.e1, exp.e2);
+ this.lowering = lowering;
+ }
+
+ override const(char)* toChars() const
+ {
+ return lowering.toChars();
+ }
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
*/
extern (C++) final class ConstructExp : AssignExp
{
@@ -6204,7 +6263,7 @@ extern (C++) final class AddAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
+ super(loc, EXP.addAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6220,7 +6279,7 @@ extern (C++) final class MinAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
+ super(loc, EXP.minAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6236,7 +6295,7 @@ extern (C++) final class MulAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
+ super(loc, EXP.mulAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6252,7 +6311,7 @@ extern (C++) final class DivAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
+ super(loc, EXP.divAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6268,7 +6327,7 @@ extern (C++) final class ModAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
+ super(loc, EXP.modAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6284,7 +6343,7 @@ extern (C++) final class AndAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
+ super(loc, EXP.andAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6300,7 +6359,7 @@ extern (C++) final class OrAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
+ super(loc, EXP.orAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6316,7 +6375,7 @@ extern (C++) final class XorAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
+ super(loc, EXP.xorAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6332,7 +6391,7 @@ extern (C++) final class PowAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
+ super(loc, EXP.powAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6348,7 +6407,7 @@ extern (C++) final class ShlAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
+ super(loc, EXP.leftShiftAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6364,7 +6423,7 @@ extern (C++) final class ShrAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
+ super(loc, EXP.rightShiftAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6380,7 +6439,7 @@ extern (C++) final class UshrAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
+ super(loc, EXP.unsignedRightShiftAssign, e1, e2);
}
override void accept(Visitor v)
@@ -6405,12 +6464,12 @@ extern (C++) class CatAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
+ super(loc, EXP.concatenateAssign, e1, e2);
}
extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
{
- super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2);
+ super(loc, tok, e1, e2);
}
override void accept(Visitor v)
@@ -6462,7 +6521,7 @@ extern (C++) final class AddExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.add, __traits(classInstanceSize, AddExp), e1, e2);
+ super(loc, EXP.add, e1, e2);
}
override void accept(Visitor v)
@@ -6480,7 +6539,7 @@ extern (C++) final class MinExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.min, __traits(classInstanceSize, MinExp), e1, e2);
+ super(loc, EXP.min, e1, e2);
}
override void accept(Visitor v)
@@ -6496,9 +6555,11 @@ extern (C++) final class MinExp : BinExp
*/
extern (C++) final class CatExp : BinExp
{
+ Expression lowering; // call to druntime hook `_d_arraycatnTX`
+
extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope
{
- super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
+ super(loc, EXP.concatenate, e1, e2);
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -6523,7 +6584,7 @@ extern (C++) final class MulExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.mul, __traits(classInstanceSize, MulExp), e1, e2);
+ super(loc, EXP.mul, e1, e2);
}
override void accept(Visitor v)
@@ -6541,7 +6602,7 @@ extern (C++) final class DivExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.div, __traits(classInstanceSize, DivExp), e1, e2);
+ super(loc, EXP.div, e1, e2);
}
override void accept(Visitor v)
@@ -6559,7 +6620,7 @@ extern (C++) final class ModExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.mod, __traits(classInstanceSize, ModExp), e1, e2);
+ super(loc, EXP.mod, e1, e2);
}
override void accept(Visitor v)
@@ -6577,7 +6638,7 @@ extern (C++) final class PowExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.pow, __traits(classInstanceSize, PowExp), e1, e2);
+ super(loc, EXP.pow, e1, e2);
}
override void accept(Visitor v)
@@ -6595,7 +6656,7 @@ extern (C++) final class ShlExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
+ super(loc, EXP.leftShift, e1, e2);
}
override void accept(Visitor v)
@@ -6613,7 +6674,7 @@ extern (C++) final class ShrExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
+ super(loc, EXP.rightShift, e1, e2);
}
override void accept(Visitor v)
@@ -6631,7 +6692,7 @@ extern (C++) final class UshrExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
+ super(loc, EXP.unsignedRightShift, e1, e2);
}
override void accept(Visitor v)
@@ -6649,7 +6710,7 @@ extern (C++) final class AndExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.and, __traits(classInstanceSize, AndExp), e1, e2);
+ super(loc, EXP.and, e1, e2);
}
override void accept(Visitor v)
@@ -6667,7 +6728,7 @@ extern (C++) final class OrExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.or, __traits(classInstanceSize, OrExp), e1, e2);
+ super(loc, EXP.or, e1, e2);
}
override void accept(Visitor v)
@@ -6685,7 +6746,7 @@ extern (C++) final class XorExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.xor, __traits(classInstanceSize, XorExp), e1, e2);
+ super(loc, EXP.xor, e1, e2);
}
override void accept(Visitor v)
@@ -6704,7 +6765,7 @@ extern (C++) final class LogicalExp : BinExp
{
extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2)
{
- super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2);
+ super(loc, op, e1, e2);
assert(op == EXP.andAnd || op == EXP.orOr);
}
@@ -6726,7 +6787,7 @@ extern (C++) final class CmpExp : BinExp
{
extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2);
+ super(loc, op, e1, e2);
assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
}
@@ -6747,7 +6808,7 @@ extern (C++) final class InExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.in_, __traits(classInstanceSize, InExp), e1, e2);
+ super(loc, EXP.in_, e1, e2);
}
override void accept(Visitor v)
@@ -6765,7 +6826,7 @@ extern (C++) final class RemoveExp : BinExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, EXP.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
+ super(loc, EXP.remove, e1, e2);
type = Type.tbool;
}
@@ -6786,7 +6847,7 @@ extern (C++) final class EqualExp : BinExp
{
extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2);
+ super(loc, op, e1, e2);
assert(op == EXP.equal || op == EXP.notEqual);
}
@@ -6807,7 +6868,7 @@ extern (C++) final class IdentityExp : BinExp
{
extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2);
+ super(loc, op, e1, e2);
assert(op == EXP.identity || op == EXP.notIdentity);
}
@@ -6828,7 +6889,7 @@ extern (C++) final class CondExp : BinExp
extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope
{
- super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2);
+ super(loc, EXP.question, e1, e2);
this.econd = econd;
}
@@ -6966,9 +7027,9 @@ bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc
*/
extern (C++) class DefaultInitExp : Expression
{
- extern (D) this(const ref Loc loc, EXP op, int size)
+ extern (D) this(const ref Loc loc, EXP op)
{
- super(loc, op, size);
+ super(loc, op);
}
override void accept(Visitor v)
@@ -6984,7 +7045,7 @@ extern (C++) final class FileInitExp : DefaultInitExp
{
extern (D) this(const ref Loc loc, EXP tok)
{
- super(loc, tok, __traits(classInstanceSize, FileInitExp));
+ super(loc, tok);
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -7015,7 +7076,7 @@ extern (C++) final class LineInitExp : DefaultInitExp
{
extern (D) this(const ref Loc loc)
{
- super(loc, EXP.line, __traits(classInstanceSize, LineInitExp));
+ super(loc, EXP.line);
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -7038,7 +7099,7 @@ extern (C++) final class ModuleInitExp : DefaultInitExp
{
extern (D) this(const ref Loc loc)
{
- super(loc, EXP.moduleString, __traits(classInstanceSize, ModuleInitExp));
+ super(loc, EXP.moduleString);
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -7063,7 +7124,7 @@ extern (C++) final class FuncInitExp : DefaultInitExp
{
extern (D) this(const ref Loc loc)
{
- super(loc, EXP.functionString, __traits(classInstanceSize, FuncInitExp));
+ super(loc, EXP.functionString);
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -7094,7 +7155,7 @@ extern (C++) final class PrettyFuncInitExp : DefaultInitExp
{
extern (D) this(const ref Loc loc)
{
- super(loc, EXP.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
+ super(loc, EXP.prettyFunction);
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
@@ -7139,8 +7200,7 @@ extern (C++) final class ObjcClassReferenceExp : Expression
extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
{
- super(loc, EXP.objcClassReference,
- __traits(classInstanceSize, ObjcClassReferenceExp));
+ super(loc, EXP.objcClassReference);
this.classDeclaration = classDeclaration;
type = objc.getRuntimeMetaclass(classDeclaration).getType();
}
@@ -7163,7 +7223,7 @@ extern (C++) final class GenericExp : Expression
extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps)
{
- super(loc, EXP._Generic, __traits(classInstanceSize, GenericExp));
+ super(loc, EXP._Generic);
this.cntlExp = cntlExp;
this.types = types;
this.exps = exps;
@@ -7398,3 +7458,135 @@ private enum EbinaryAssign =
EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
];
+
+/// Given a member of the EXP enum, get the class instance size of the corresponding Expression class.
+/// Needed because the classes are `extern(C++)`
+private immutable ubyte[EXP.max+1] expSize = [
+ EXP.reserved: 0,
+ EXP.negate: __traits(classInstanceSize, NegExp),
+ EXP.cast_: __traits(classInstanceSize, CastExp),
+ EXP.null_: __traits(classInstanceSize, NullExp),
+ EXP.assert_: __traits(classInstanceSize, AssertExp),
+ EXP.array: __traits(classInstanceSize, ArrayExp),
+ EXP.call: __traits(classInstanceSize, CallExp),
+ EXP.address: __traits(classInstanceSize, AddrExp),
+ EXP.type: __traits(classInstanceSize, TypeExp),
+ EXP.throw_: __traits(classInstanceSize, ThrowExp),
+ EXP.new_: __traits(classInstanceSize, NewExp),
+ EXP.delete_: __traits(classInstanceSize, DeleteExp),
+ EXP.star: __traits(classInstanceSize, PtrExp),
+ EXP.symbolOffset: __traits(classInstanceSize, SymOffExp),
+ EXP.variable: __traits(classInstanceSize, VarExp),
+ EXP.dotVariable: __traits(classInstanceSize, DotVarExp),
+ EXP.dotIdentifier: __traits(classInstanceSize, DotIdExp),
+ EXP.dotTemplateInstance: __traits(classInstanceSize, DotTemplateInstanceExp),
+ EXP.dotType: __traits(classInstanceSize, DotTypeExp),
+ EXP.slice: __traits(classInstanceSize, SliceExp),
+ EXP.arrayLength: __traits(classInstanceSize, ArrayLengthExp),
+ EXP.dollar: __traits(classInstanceSize, DollarExp),
+ EXP.template_: __traits(classInstanceSize, TemplateExp),
+ EXP.dotTemplateDeclaration: __traits(classInstanceSize, DotTemplateExp),
+ EXP.declaration: __traits(classInstanceSize, DeclarationExp),
+ EXP.dSymbol: __traits(classInstanceSize, DsymbolExp),
+ EXP.typeid_: __traits(classInstanceSize, TypeidExp),
+ EXP.uadd: __traits(classInstanceSize, UAddExp),
+ EXP.remove: __traits(classInstanceSize, RemoveExp),
+ EXP.newAnonymousClass: __traits(classInstanceSize, NewAnonClassExp),
+ EXP.arrayLiteral: __traits(classInstanceSize, ArrayLiteralExp),
+ EXP.assocArrayLiteral: __traits(classInstanceSize, AssocArrayLiteralExp),
+ EXP.structLiteral: __traits(classInstanceSize, StructLiteralExp),
+ EXP.classReference: __traits(classInstanceSize, ClassReferenceExp),
+ EXP.thrownException: __traits(classInstanceSize, ThrownExceptionExp),
+ EXP.delegatePointer: __traits(classInstanceSize, DelegatePtrExp),
+ EXP.delegateFunctionPointer: __traits(classInstanceSize, DelegateFuncptrExp),
+ EXP.lessThan: __traits(classInstanceSize, CmpExp),
+ EXP.greaterThan: __traits(classInstanceSize, CmpExp),
+ EXP.lessOrEqual: __traits(classInstanceSize, CmpExp),
+ EXP.greaterOrEqual: __traits(classInstanceSize, CmpExp),
+ EXP.equal: __traits(classInstanceSize, EqualExp),
+ EXP.notEqual: __traits(classInstanceSize, EqualExp),
+ EXP.identity: __traits(classInstanceSize, IdentityExp),
+ EXP.notIdentity: __traits(classInstanceSize, IdentityExp),
+ EXP.index: __traits(classInstanceSize, IndexExp),
+ EXP.is_: __traits(classInstanceSize, IsExp),
+ EXP.leftShift: __traits(classInstanceSize, ShlExp),
+ EXP.rightShift: __traits(classInstanceSize, ShrExp),
+ EXP.leftShiftAssign: __traits(classInstanceSize, ShlAssignExp),
+ EXP.rightShiftAssign: __traits(classInstanceSize, ShrAssignExp),
+ EXP.unsignedRightShift: __traits(classInstanceSize, UshrExp),
+ EXP.unsignedRightShiftAssign: __traits(classInstanceSize, UshrAssignExp),
+ EXP.concatenate: __traits(classInstanceSize, CatExp),
+ EXP.concatenateAssign: __traits(classInstanceSize, CatAssignExp),
+ EXP.concatenateElemAssign: __traits(classInstanceSize, CatElemAssignExp),
+ EXP.concatenateDcharAssign: __traits(classInstanceSize, CatDcharAssignExp),
+ EXP.add: __traits(classInstanceSize, AddExp),
+ EXP.min: __traits(classInstanceSize, MinExp),
+ EXP.addAssign: __traits(classInstanceSize, AddAssignExp),
+ EXP.minAssign: __traits(classInstanceSize, MinAssignExp),
+ EXP.mul: __traits(classInstanceSize, MulExp),
+ EXP.div: __traits(classInstanceSize, DivExp),
+ EXP.mod: __traits(classInstanceSize, ModExp),
+ EXP.mulAssign: __traits(classInstanceSize, MulAssignExp),
+ EXP.divAssign: __traits(classInstanceSize, DivAssignExp),
+ EXP.modAssign: __traits(classInstanceSize, ModAssignExp),
+ EXP.and: __traits(classInstanceSize, AndExp),
+ EXP.or: __traits(classInstanceSize, OrExp),
+ EXP.xor: __traits(classInstanceSize, XorExp),
+ EXP.andAssign: __traits(classInstanceSize, AndAssignExp),
+ EXP.orAssign: __traits(classInstanceSize, OrAssignExp),
+ EXP.xorAssign: __traits(classInstanceSize, XorAssignExp),
+ EXP.assign: __traits(classInstanceSize, AssignExp),
+ EXP.not: __traits(classInstanceSize, NotExp),
+ EXP.tilde: __traits(classInstanceSize, ComExp),
+ EXP.plusPlus: __traits(classInstanceSize, PostExp),
+ EXP.minusMinus: __traits(classInstanceSize, PostExp),
+ EXP.construct: __traits(classInstanceSize, ConstructExp),
+ EXP.blit: __traits(classInstanceSize, BlitExp),
+ EXP.dot: __traits(classInstanceSize, DotExp),
+ EXP.comma: __traits(classInstanceSize, CommaExp),
+ EXP.question: __traits(classInstanceSize, CondExp),
+ EXP.andAnd: __traits(classInstanceSize, LogicalExp),
+ EXP.orOr: __traits(classInstanceSize, LogicalExp),
+ EXP.prePlusPlus: __traits(classInstanceSize, PreExp),
+ EXP.preMinusMinus: __traits(classInstanceSize, PreExp),
+ EXP.identifier: __traits(classInstanceSize, IdentifierExp),
+ EXP.string_: __traits(classInstanceSize, StringExp),
+ EXP.this_: __traits(classInstanceSize, ThisExp),
+ EXP.super_: __traits(classInstanceSize, SuperExp),
+ EXP.halt: __traits(classInstanceSize, HaltExp),
+ EXP.tuple: __traits(classInstanceSize, TupleExp),
+ EXP.error: __traits(classInstanceSize, ErrorExp),
+ EXP.void_: __traits(classInstanceSize, VoidInitExp),
+ EXP.int64: __traits(classInstanceSize, IntegerExp),
+ EXP.float64: __traits(classInstanceSize, RealExp),
+ EXP.complex80: __traits(classInstanceSize, ComplexExp),
+ EXP.import_: __traits(classInstanceSize, ImportExp),
+ EXP.delegate_: __traits(classInstanceSize, DelegateExp),
+ EXP.function_: __traits(classInstanceSize, FuncExp),
+ EXP.mixin_: __traits(classInstanceSize, MixinExp),
+ EXP.in_: __traits(classInstanceSize, InExp),
+ EXP.break_: __traits(classInstanceSize, CTFEExp),
+ EXP.continue_: __traits(classInstanceSize, CTFEExp),
+ EXP.goto_: __traits(classInstanceSize, CTFEExp),
+ EXP.scope_: __traits(classInstanceSize, ScopeExp),
+ EXP.traits: __traits(classInstanceSize, TraitsExp),
+ EXP.overloadSet: __traits(classInstanceSize, OverExp),
+ EXP.line: __traits(classInstanceSize, LineInitExp),
+ EXP.file: __traits(classInstanceSize, FileInitExp),
+ EXP.fileFullPath: __traits(classInstanceSize, FileInitExp),
+ EXP.moduleString: __traits(classInstanceSize, ModuleInitExp),
+ EXP.functionString: __traits(classInstanceSize, FuncInitExp),
+ EXP.prettyFunction: __traits(classInstanceSize, PrettyFuncInitExp),
+ EXP.pow: __traits(classInstanceSize, PowExp),
+ EXP.powAssign: __traits(classInstanceSize, PowAssignExp),
+ EXP.vector: __traits(classInstanceSize, VectorExp),
+ EXP.voidExpression: __traits(classInstanceSize, CTFEExp),
+ EXP.cantExpression: __traits(classInstanceSize, CTFEExp),
+ EXP.showCtfeContext: __traits(classInstanceSize, CTFEExp),
+ EXP.objcClassReference: __traits(classInstanceSize, ObjcClassReferenceExp),
+ EXP.vectorArray: __traits(classInstanceSize, VectorArrayExp),
+ EXP.compoundLiteral: __traits(classInstanceSize, CompoundLiteralExp),
+ EXP._Generic: __traits(classInstanceSize, GenericExp),
+ EXP.interval: __traits(classInstanceSize, IntervalExp),
+ EXP.loweredAssignExp : __traits(classInstanceSize, LoweredAssignExp),
+];
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 1bc78e7..a4b18b9 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -38,6 +38,7 @@ class TemplateDeclaration;
class ClassDeclaration;
class OverloadSet;
class StringExp;
+class LoweredAssignExp;
struct UnionExp;
#ifdef IN_GCC
typedef union tree_node Symbol;
@@ -79,12 +80,12 @@ enum class ModifyFlags
class Expression : public ASTNode
{
public:
- EXP op; // to minimize use of dynamic_cast
- unsigned char size; // # of bytes in Expression so we can copy() it
- d_bool parens; // if this is a parenthesized expression
Type *type; // !=NULL means that semantic() has been run
Loc loc; // file location
+ EXP op; // to minimize use of dynamic_cast
+ d_bool parens; // if this is a parenthesized expression
+ size_t size() const;
static void _init();
Expression *copy();
virtual Expression *syntaxCopy();
@@ -240,6 +241,7 @@ public:
UnaExp* isUnaExp();
BinExp* isBinExp();
BinAssignExp* isBinAssignExp();
+ LoweredAssignExp* isLoweredAssignExp();
void accept(Visitor *v) override { v->visit(this); }
};
@@ -370,12 +372,12 @@ public:
class StringExp final : public Expression
{
public:
+ utf8_t postfix; // 'c', 'w', 'd'
+ OwnedBy ownedByCtfe;
void *string; // char, wchar, or dchar data
size_t len; // number of chars, wchars, or dchars
unsigned char sz; // 1: char, 2: wchar, 4: dchar
- unsigned char committed; // !=0 if type is committed
- utf8_t postfix; // 'c', 'w', 'd'
- OwnedBy ownedByCtfe;
+ bool committed; // if type is committed
static StringExp *create(const Loc &loc, const char *s);
static StringExp *create(const Loc &loc, const void *s, d_size_t len);
@@ -419,10 +421,10 @@ public:
class ArrayLiteralExp final : public Expression
{
public:
- Expression *basis;
- Expressions *elements;
OwnedBy ownedByCtfe;
d_bool onstack;
+ Expression *basis;
+ Expressions *elements;
static ArrayLiteralExp *create(const Loc &loc, Expressions *elements);
static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements);
@@ -439,9 +441,9 @@ public:
class AssocArrayLiteralExp final : public Expression
{
public:
+ OwnedBy ownedByCtfe;
Expressions *keys;
Expressions *values;
- OwnedBy ownedByCtfe;
bool equals(const RootObject * const o) const override;
AssocArrayLiteralExp *syntaxCopy() override;
@@ -457,7 +459,13 @@ public:
Expressions *elements; // parallels sd->fields[] with NULL entries for fields to skip
Type *stype; // final type of result (can be different from sd's type)
- Symbol *sym; // back end symbol to initialize with literal
+ union
+ {
+ Symbol *sym; // back end symbol to initialize with literal
+
+ // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
+ StructLiteralExp *inlinecopy;
+ };
/** pointer to the origin instance of the expression.
* once a new expression is created, origin is set to 'this'.
@@ -466,15 +474,13 @@ public:
*/
StructLiteralExp *origin;
- // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
- StructLiteralExp *inlinecopy;
/** anytime when recursive function is calling, 'stageflags' marks with bit flag of
* current stage and unmarks before return from this function.
* 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
* (with infinite recursion) of this expression.
*/
- int stageflags;
+ uint8_t stageflags;
d_bool useStaticInit; // if this is true, use the StructDeclaration's init symbol
d_bool isOriginal; // used when moving instances to indicate `this is this.origin`
@@ -693,7 +699,6 @@ class UnaExp : public Expression
{
public:
Expression *e1;
- Type *att1; // Save alias this type to detect recursion
UnaExp *syntaxCopy() override;
Expression *incompatibleTypes();
@@ -937,9 +942,15 @@ public:
Expression *upr; // NULL if implicit 0
Expression *lwr; // NULL if implicit [length - 1]
VarDeclaration *lengthVar;
- d_bool upperIsInBounds; // true if upr <= e1.length
- d_bool lowerIsLessThanUpper; // true if lwr <= upr
- d_bool arrayop; // an array operation, rather than a slice
+
+ bool upperIsInBounds() const; // true if upr <= e1.length
+ bool upperIsInBounds(bool v);
+ bool lowerIsLessThanUpper() const; // true if lwr <= upr
+ bool lowerIsLessThanUpper(bool v);
+ bool arrayop() const; // an array operation, rather than a slice
+ bool arrayop(bool v);
+private:
+ uint8_t bitFields;
SliceExp *syntaxCopy() override;
bool isLvalue() override;
@@ -1076,6 +1087,15 @@ public:
void accept(Visitor *v) override { v->visit(this); }
};
+class LoweredAssignExp final : public AssignExp
+{
+public:
+ Expression *lowering;
+
+ const char *toChars() const override;
+ void accept(Visitor *v) override { v->visit(this); }
+};
+
class BlitExp final : public AssignExp
{
public:
@@ -1187,6 +1207,8 @@ public:
class CatExp final : public BinExp
{
public:
+ Expression *lowering; // call to druntime hook `_d_arraycatnTX`
+
void accept(Visitor *v) override { v->visit(this); }
};
@@ -1372,7 +1394,7 @@ struct UnionExp
UnionExp(Expression *e)
{
- memcpy(this, (void *)e, e->size);
+ memcpy(this, (void *)e, e->size());
}
/* Extract pointer to Expression
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 45dcb97..cf4aac4 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -65,7 +65,6 @@ import dmd.parse;
import dmd.printast;
import dmd.root.array;
import dmd.root.ctfloat;
-import dmd.root.file;
import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.root.rootobject;
@@ -635,7 +634,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
}
else if (auto dti = ce.e1.isDotTemplateInstanceExp())
{
- if (Expression ey = dti.dotTemplateSemanticProp(sc, 1))
+ if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag))
{
ce.e1 = ey;
return null;
@@ -1221,7 +1220,7 @@ private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc)
/***************************************
* Pull out any properties.
*/
-private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null)
+private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null)
{
//printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
Loc loc = e1.loc;
@@ -1295,7 +1294,14 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
{
Expression e = new CallExp(loc, e1);
if (e2)
+ {
e = new AssignExp(loc, e, e2);
+ if (saveAtts)
+ {
+ (cast(BinExp)e).att1 = saveAtts.att1;
+ (cast(BinExp)e).att2 = saveAtts.att2;
+ }
+ }
return e.expressionSemantic(sc);
}
}
@@ -1413,7 +1419,14 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
}
Expression e = new CallExp(loc, e1);
if (e2)
+ {
e = new AssignExp(loc, e, e2);
+ if (saveAtts)
+ {
+ (cast(BinExp)e).att1 = saveAtts.att1;
+ (cast(BinExp)e).att2 = saveAtts.att2;
+ }
+ }
return e.expressionSemantic(sc);
}
}
@@ -2177,7 +2190,11 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
// Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
// as lazy parameters to the next function, but that isn't escaping.
- else if (!(pStc & STC.lazy_))
+ // The arguments of `_d_arraycatnTX` are already handled in
+ // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
+ // check does not return an error, so the lowering of `a ~ b` to
+ // `_d_arraycatnTX(a, b)` still occurs.
+ else if (!(pStc & STC.lazy_) && (!fd || fd.ident != Id._d_arraycatnTX))
{
/* Argument value can escape from the called function.
* Check arg to see if it matters.
@@ -2208,6 +2225,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
// allocate the array literal as temporary static array on the stack
ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
+ tmp.storage_class |= STC.exptemp;
auto declareTmp = new DeclarationExp(ale.loc, tmp);
auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
p.type.substWildTo(MODFlags.mutable));
@@ -2266,7 +2284,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
default:
break;
}
- if (tf.parameterList.varargs == VarArg.variadic)
+ if (tf.parameterList.varargs == VarArg.variadic ||
+ tf.parameterList.varargs == VarArg.KRvariadic)
{
const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
if (arg.type.ty == Tarray)
@@ -2348,30 +2367,18 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
/* Remaining problems:
- * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
- * implemented by calling a function) we'll defer this for now.
- * 2. value structs (or static arrays of them) that need to be copy constructed
- * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
+ * 1. value structs (or static arrays of them) that need to be copy constructed
+ * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
* function gets called.
- * 4. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
- * 2, 3 and 4 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
+ * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
+ * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
* up properly. Pushing arguments on the stack then cannot fail.
*/
{
- /* TODO: tackle problem 1)
- */
- const bool leftToRight = true; // TODO: Any cases that need rightToLeft?
- if (!leftToRight)
- assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
-
- /* Does Problem (4) apply?
+ /* Does Problem (3) apply?
*/
const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
- const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1);
- const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1);
- const ptrdiff_t step = (leftToRight ? 1 : -1);
-
/* Compute indices of last throwing argument and first arg needing destruction.
* Used to not set up destructors unless an arg needs destruction on a throw
* in a later argument.
@@ -2379,7 +2386,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
ptrdiff_t lastthrow = -1; // last argument that may throw
ptrdiff_t firstdtor = -1; // first argument that needs destruction
ptrdiff_t lastdtor = -1; // last argument that needs destruction
- for (ptrdiff_t i = start; i != end; i += step)
+ for (ptrdiff_t i = 0; i != nargs; i++)
{
Expression arg = (*arguments)[i];
if (canThrow(arg, sc.func, false))
@@ -2396,12 +2403,12 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
}
- /* Do we need 'eprefix' for problems 3 or 4?
+ /* Do we need 'eprefix' for problems 2 or 3?
*/
const bool needsPrefix = callerDestroysArgs
? firstdtor >= 0 // true if any argument needs destruction
: firstdtor >= 0 && lastthrow >= 0 &&
- (lastthrow - firstdtor) * step > 0; // last throw after first destruction
+ (lastthrow - firstdtor) > 0; // last throw after first destruction
const ptrdiff_t lastPrefix = callerDestroysArgs
? lastdtor // up to last argument requiring destruction
: lastthrow; // up to last potentially throwing argument
@@ -2421,7 +2428,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
eprefix = ae.expressionSemantic(sc);
}
- for (ptrdiff_t i = start; i != end; i += step)
+ for (ptrdiff_t i = 0; i != nargs; i++)
{
Expression arg = (*arguments)[i];
//printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
@@ -2437,12 +2444,12 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
/* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
* Then declare a temporary variable for this arg and append that declaration
- * to 'eprefix', which will implicitly take care of potential problem 2) for
+ * to 'eprefix', which will implicitly take care of potential problem 1) for
* this arg.
* 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
* excluding all lazy parameters.
*/
- if (needsPrefix && (lastPrefix - i) * step >= 0)
+ if (needsPrefix && (lastPrefix - i) >= 0)
{
const bool needsDtor = !isRef && arg.type.needsDestruction() &&
// Problem 3: last throwing arg doesn't require dtor patching
@@ -2465,7 +2472,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
else
{
- /* Problem 3: Modify the destructor so it only runs if gate==false,
+ /* Problem 2: Modify the destructor so it only runs if gate==false,
* i.e., only if there was a throw while constructing the args
*/
if (!needsDtor)
@@ -2500,7 +2507,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
arg = arg.expressionSemantic(sc);
}
- /* Problem 3: Last throwing arg?
+ /* Problem 2: Last throwing arg?
* Then finalize eprefix => (eprefix, gate = true), i.e., disable the
* dtors right after constructing the last throwing arg.
* From now on, the callee will take care of destructing the args because
@@ -2514,7 +2521,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
else // not part of 'eprefix'
{
- /* Handle problem 2) by calling the copy constructor for value structs
+ /* Handle problem 1) by calling the copy constructor for value structs
* (or static arrays of them) if appropriate.
*/
Type tv = arg.type.baseElemOf();
@@ -2671,6 +2678,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (!e.type)
e.type = Type.tfloat64;
+ else if (e.type.isimaginary && sc.flags & SCOPE.Cfile)
+ {
+ /* Convert to core.stdc.config.complex
+ */
+ Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
+ if (t.ty == Terror)
+ return setError();
+
+ Type tf;
+ switch (e.type.ty)
+ {
+ case Timaginary32: tf = Type.tfloat32; break;
+ case Timaginary64: tf = Type.tfloat64; break;
+ case Timaginary80: tf = Type.tfloat80; break;
+ default:
+ assert(0);
+ }
+
+ /* Construct ts{re : 0.0, im : e}
+ */
+ TypeStruct ts = t.isTypeStruct;
+ Expressions* elements = new Expressions(2);
+ (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf);
+ (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
+ Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
+ result = sle.expressionSemantic(sc);
+ return;
+ }
else
e.type = e.type.typeSemantic(e.loc, sc);
result = e;
@@ -2933,7 +2968,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!s)
{
e.error("`%s` is not in a class or struct scope", e.toChars());
- goto Lerr;
+ return setError();
}
ClassDeclaration cd = s.isClassDeclaration();
if (cd)
@@ -2952,7 +2987,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
if (!fd)
- goto Lerr;
+ {
+ e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
+ return setError();
+ }
assert(fd.vthis);
e.var = fd.vthis;
@@ -2967,11 +3005,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
result = e;
- return;
-
- Lerr:
- e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
- result = ErrorExp.get();
}
override void visit(SuperExp e)
@@ -3001,7 +3034,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!s)
{
e.error("`%s` is not in a class scope", e.toChars());
- goto Lerr;
+ return setError();
}
cd = s.isClassDeclaration();
if (cd)
@@ -3010,7 +3043,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!cd)
{
e.error("class `%s` has no `super`", s.toChars());
- goto Lerr;
+ return setError();
}
e.type = cd.type;
result = e;
@@ -3109,7 +3142,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e.type = Type.tuns32.sarrayOf(e.len + 1);
else
e.type = Type.tdchar.immutableOf().arrayOf();
- e.committed = 1;
+ e.committed = true;
break;
case 'w':
@@ -3134,11 +3167,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e.type = Type.tuns16.sarrayOf(e.len + 1);
else
e.type = Type.twchar.immutableOf().arrayOf();
- e.committed = 1;
+ e.committed = true;
break;
case 'c':
- e.committed = 1;
+ e.committed = true;
goto default;
default:
@@ -3860,8 +3893,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = id.expressionSemantic(sc);
return;
}
- else if (!exp.onstack && !exp.type.isscope())
+ else if (sc.needsCodegen() && // interpreter doesn't need this lowered
+ !exp.onstack && !exp.type.isscope()) // these won't use the GC
{
+ /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
+ * or `_d_newclassTTrace`
+ */
auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT;
if (!verifyHookExist(exp.loc, *sc, hook, "new class"))
return setError();
@@ -4533,6 +4570,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
+ Type att = null;
Lagain:
//printf("Lagain: %s\n", toChars());
exp.f = null;
@@ -4743,7 +4781,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// overload of opCall, therefore it's a call
if (exp.e1.op != EXP.type)
{
- if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type))
+ if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type))
{
exp.e1 = resolveAliasThis(sc, exp.e1);
goto Lagain;
@@ -4832,10 +4870,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return null;
if (f)
{
- /* Error if match in more than one overload set,
+ /* Match in more than one overload set,
* even if one is a 'better' match than the other.
*/
- ScopeDsymbol.multiplyDefined(loc, f, f2);
+ if (f.isCsymbol() && f2.isCsymbol())
+ {
+ /* C has global name space, so just pick one, such as f.
+ * If f and f2 are not compatible, that's how C rolls.
+ */
+ }
+ else
+ ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
}
else
f = f2;
@@ -5203,13 +5248,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
{
bool err = false;
- if (!tf.purity && sc.func.setImpure())
+ if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1))
{
exp.error("`pure` %s `%s` cannot call impure %s `%s`",
sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
err = true;
}
- if (!tf.isnogc && sc.func.setGC())
+ if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1))
{
exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
@@ -6166,7 +6211,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
uint errors = global.errors;
const len = buf.length;
const str = buf.extractChars()[0 .. len];
- scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false, global.errorSink);
+ const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
+ 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.vin;
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
@@ -6295,19 +6343,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else
{
- auto readResult = File.read(resolvedNamez);
- if (!readResult.success)
- {
- e.error("cannot read file `%s`", resolvedNamez.ptr);
- return setError();
- }
- else
- {
- // take ownership of buffer (probably leaking)
- auto data = readResult.extractSlice();
- se = new StringExp(e.loc, data);
- global.fileManager.add(fileName, data);
- }
+ e.error("cannot read file `%s`", resolvedNamez.ptr);
+ return setError();
}
}
result = se.expressionSemantic(sc);
@@ -6321,7 +6358,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("AssertExp::semantic('%s')\n", exp.toChars());
}
- const generateMsg = !exp.msg && global.params.checkAction == CHECKACTION.context && global.params.useAssert == CHECKENABLE.on;
+ const generateMsg = !exp.msg &&
+ sc.needsCodegen() && // let ctfe interpreter handle the error message
+ global.params.checkAction == CHECKACTION.context &&
+ global.params.useAssert == CHECKENABLE.on;
Expression temporariesPrefix;
if (generateMsg)
@@ -6634,7 +6674,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
import dmd.statementsem;
- if (StatementSemanticVisitor.throwSemantic(te.loc, te.e1, sc))
+ if (throwSemantic(te.loc, te.e1, sc))
result = te;
else
setError();
@@ -6927,7 +6967,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
// Indicate we need to resolve by UFCS.
- Expression e = exp.dotTemplateSemanticProp(sc, 1);
+ Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
if (!e)
e = resolveUFCSProperties(sc, exp);
if (e is exp)
@@ -7824,7 +7864,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
- if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
+ if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen())
{
auto tFrom = t1b.nextOf();
auto tTo = tob.nextOf();
@@ -8914,6 +8954,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
assert((*ae.arguments)[0].op == EXP.interval);
ie = cast(IntervalExp)(*ae.arguments)[0];
}
+ Type att = null; // first cyclic `alias this` type
while (true)
{
if (ae.e1.op == EXP.error)
@@ -8988,7 +9029,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// No operator overloading member function found yet, but
// there might be an alias this to try.
- if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
+ if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
{
/* Rewrite (a[arguments] op e2) as:
* a.aliasthis[arguments] op e2
@@ -9016,7 +9057,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (auto dti = e1x.isDotTemplateInstanceExp())
{
- Expression e = dti.dotTemplateSemanticProp(sc, 1);
+ Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag);
if (!e)
{
return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
@@ -9070,7 +9111,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* or:
* f() = value
*/
- if (Expression e = resolvePropertiesX(sc, e1x, exp.e2))
+ if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
return setResult(e);
if (e1x.checkRightThis(sc))
@@ -9764,6 +9805,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setResult(res);
}
+ if (!sc.needsCodegen()) // if compile time creature only
+ {
+ exp.type = Type.tsize_t;
+ return setResult(exp);
+ }
+
// Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
Expression id = new IdentifierExp(ale.loc, Id.empty);
id = new DotIdExp(ale.loc, id, Id.object);
@@ -9785,10 +9832,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
arguments.push(ale.e1);
arguments.push(exp.e2);
- Expression ce = new CallExp(ale.loc, id, arguments);
- auto res = ce.expressionSemantic(sc);
+ Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc);
+ auto res = new LoweredAssignExp(exp, ce);
// if (global.params.verbose)
// message("lowered %s =>\n %s", exp.toChars(), res.toChars());
+ res.type = Type.tsize_t;
return setResult(res);
}
else if (auto se = exp.e1.isSliceExp())
@@ -10117,6 +10165,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
}
+
+ if (!sc.needsCodegen()) // interpreter can handle these
+ return setResult(res);
+
const lowerToArrayCtor =
( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
(rhsType.ty == Tsarray && rhs.isLvalue) ) &&
@@ -10505,7 +10557,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = res;
if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
- !(sc.flags & (SCOPE.ctfe | SCOPE.compile)))
+ sc.needsCodegen())
{
// if aa ordering is triggered, `res` will be a CommaExp
// and `.e2` will be the rewritten original expression.
@@ -10898,6 +10950,86 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
+ /**
+ * If the given expression is a `CatExp`, the function tries to lower it to
+ * `_d_arraycatnTX`.
+ *
+ * Params:
+ * ee = the `CatExp` to lower
+ * Returns:
+ * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
+ * `ee` otherwise
+ */
+ private Expression lowerToArrayCat(CatExp exp)
+ {
+ // String literals are concatenated by the compiler. No lowering is needed.
+ if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) ||
+ (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp())))
+ return exp;
+
+ Identifier hook = global.params.tracegc ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX;
+ if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays"))
+ {
+ setError();
+ return result;
+ }
+
+ void handleCatArgument(Expressions *arguments, Expression e)
+ {
+ if (auto ce = e.isCatExp())
+ {
+ Expression lowering = ce.lowering;
+
+ /* Skip `file`, `line`, and `funcname` if the hook of the parent
+ * `CatExp` is `_d_arraycatnTXTrace`.
+ */
+ if (auto callExp = isRuntimeHook(lowering, hook))
+ {
+ if (hook == Id._d_arraycatnTX)
+ arguments.pushSlice((*callExp.arguments)[]);
+ else
+ arguments.pushSlice((*callExp.arguments)[3 .. $]);
+ }
+ }
+ else
+ arguments.push(e);
+ }
+
+ 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()));
+ }
+
+ handleCatArgument(arguments, exp.e1);
+ handleCatArgument(arguments, exp.e2);
+
+ Expression id = new IdentifierExp(exp.loc, Id.empty);
+ id = new DotIdExp(exp.loc, id, Id.object);
+
+ auto tiargs = new Objects();
+ tiargs.push(exp.type);
+ id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
+ id = new CallExp(exp.loc, id, arguments);
+ return id.expressionSemantic(sc);
+ }
+
+ void trySetCatExpLowering(Expression exp)
+ {
+ /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
+ * used with `-betterC`, but only during CTFE.
+ */
+ if (global.params.betterC)
+ return;
+
+ if (auto ce = exp.isCatExp())
+ ce.lowering = lowerToArrayCat(ce);
+ }
+
override void visit(CatExp exp)
{
// https://dlang.org/spec/expression.html#cat_expressions
@@ -10985,14 +11117,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
exp.type = tb1next.arrayOf();
L2elem:
- if (tb2.ty == Tarray || tb2.ty == Tsarray)
- {
- // Make e2 into [e2]
- exp.e2 = new ArrayLiteralExp(exp.e2.loc, exp.type, exp.e2);
- }
- else if (checkNewEscape(sc, exp.e2, false))
+ if (checkNewEscape(sc, exp.e2, false))
return setError();
result = exp.optimize(WANTvalue);
+ trySetCatExpLowering(result);
return;
}
}
@@ -11023,14 +11151,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
exp.type = tb2next.arrayOf();
L1elem:
- if (tb1.ty == Tarray || tb1.ty == Tsarray)
- {
- // Make e1 into [e1]
- exp.e1 = new ArrayLiteralExp(exp.e1.loc, exp.type, exp.e1);
- }
- else if (checkNewEscape(sc, exp.e1, false))
+ if (checkNewEscape(sc, exp.e1, false))
return setError();
result = exp.optimize(WANTvalue);
+ trySetCatExpLowering(result);
return;
}
}
@@ -11053,6 +11177,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (Expression ex = typeCombine(exp, sc))
{
result = ex;
+ trySetCatExpLowering(result);
return;
}
exp.type = exp.type.toHeadMutable();
@@ -11085,6 +11210,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
result = e;
+ trySetCatExpLowering(result);
}
override void visit(MulExp exp)
@@ -11895,7 +12021,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
return setError();
}
- if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray))
+
+ if (sc.needsCodegen() &&
+ (t1.ty == Tarray || t1.ty == Tsarray) &&
+ (t2.ty == Tarray || t2.ty == Tsarray))
{
if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
return setError();
@@ -12762,7 +12891,7 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
{
// bypass checkPurity
- return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0);
+ return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref));
}
if (!exp.e1.isDotExp())
@@ -12814,11 +12943,11 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
* Params:
* exp = expression to resolve
* sc = context
- * flag = if 1 then do not emit error messages, just return null
+ * gag = do not emit error messages, just return `null`
* Returns:
* resolved expression, null if error
*/
-Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag)
+Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
{
//printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
@@ -13061,9 +13190,9 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag)
}
if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
{
- flag = 0;
+ gag = false;
}
- if (flag)
+ if (gag)
return null;
s = ie.sds.search_correct(exp.ident);
if (s && symbolIsVisible(sc, s))
@@ -13089,7 +13218,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag)
))
{
Type t1bn = t1b.nextOf();
- if (flag)
+ if (gag)
{
if (AggregateDeclaration ad = isAggregate(t1bn))
{
@@ -13103,11 +13232,12 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag)
* as:
* (*p).ident
*/
- if (flag && t1bn.ty == Tvoid)
+ if (gag && t1bn.ty == Tvoid)
return null;
Expression e = new PtrExp(exp.loc, exp.e1);
e = e.expressionSemantic(sc);
- return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
+ const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref);
+ return e.type.dotExp(sc, e, exp.ident, newFlag);
}
else if (exp.ident == Id.__xalignof &&
exp.e1.isVarExp() &&
@@ -13140,8 +13270,11 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag)
else
{
if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
- flag = 0;
- Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
+ gag = false;
+
+ const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
+
+ Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
if (e)
{
e = e.expressionSemantic(sc);
@@ -13150,9 +13283,16 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag)
}
}
-// Resolve e1.ident!tiargs without seeing UFCS.
-// If flag == 1, stop "not a property" error and return NULL.
-Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, int flag)
+/**
+ * Resolve `e1.ident!tiargs` without seeing UFCS.
+ * Params:
+ * exp = the `DotTemplateInstanceExp` to resolve
+ * sc = the semantic scope
+ * gag = stop "not a property" error and return `null`.
+ * Returns:
+ * `null` if error or not found, or the resolved expression.
+ */
+Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag)
{
static if (LOGSEMANTIC)
{
@@ -13186,11 +13326,11 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, int fl
/* No built-in type has templatized properties, so do shortcut.
* It is necessary in: 1024.max!"a < b"
*/
- if (flag)
+ if (gag)
return null;
}
- e = die.dotIdSemanticProp(sc, flag);
- if (flag)
+ e = die.dotIdSemanticProp(sc, gag);
+ if (gag)
{
if (!e ||
isDotOpDispatch(e))
@@ -13905,6 +14045,7 @@ Expression toBoolean(Expression exp, Scope* sc)
case EXP.assign:
case EXP.construct:
case EXP.blit:
+ case EXP.loweredAssignExp:
if (sc.flags & SCOPE.Cfile)
return exp;
// Things like:
diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d
index ba2825a..7a96469 100644
--- a/gcc/d/dmd/foreachvar.d
+++ b/gcc/d/dmd/foreachvar.d
@@ -299,7 +299,7 @@ void foreachExpAndVar(Statement s,
case STMT.Conditional:
case STMT.While:
case STMT.Forwarding:
- case STMT.Compile:
+ case STMT.Mixin:
case STMT.Peel:
case STMT.Synchronized:
assert(0); // should have been rewritten
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 4b6b5b5..8e11ab1 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -204,6 +204,7 @@ private struct FUNCFLAG
bool hasCatches; /// function has try-catch statements
bool skipCodegen; /// do not generate code for this function.
bool printf; /// is a printf-like function
+
bool scanf; /// is a scanf-like function
bool noreturn; /// the function does not return
bool isNRVO = true; /// Support for named return value optimization
@@ -214,11 +215,14 @@ private struct FUNCFLAG
bool hasNoEH; /// No exception unwinding is needed
bool inferRetType; /// Return type is to be inferred
bool hasDualContext; /// has a dual-context 'this' parameter
+
bool hasAlwaysInlines; /// Contains references to functions that must be inlined
bool isCrtCtor; /// Has attribute pragma(crt_constructor)
bool isCrtDtor; /// Has attribute pragma(crt_destructor)
bool hasEscapingSiblings;/// Has sibling functions that escape
bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
+ bool dllImport; /// __declspec(dllimport)
+ bool dllExport; /// __declspec(dllexport)
}
/***********************************************************
@@ -356,6 +360,9 @@ extern (C++) class FuncDeclaration : Declaration
/// In case of failed `@safe` inference, store the error that made the function `@system` for
/// better diagnostics
AttributeViolation* safetyViolation;
+ AttributeViolation* nogcViolation;
+ AttributeViolation* pureViolation;
+ AttributeViolation* nothrowViolation;
/// See the `FUNCFLAG` struct
import dmd.common.bitfields;
@@ -370,8 +377,8 @@ extern (C++) class FuncDeclaration : Declaration
extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
{
super(loc, ident);
- //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
- //printf("storage_class = x%x\n", storage_class);
+ //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
+ //.printf("storage_class = x%llx\n", storage_class);
this.storage_class = storage_class;
this.type = type;
if (type)
@@ -1294,14 +1301,14 @@ extern (C++) class FuncDeclaration : Declaration
override final bool isExport() const
{
- return visibility.kind == Visibility.Kind.export_;
+ return visibility.kind == Visibility.Kind.export_ || dllExport;
}
override final bool isImportedSymbol() const
{
//printf("isImportedSymbol()\n");
//printf("protection = %d\n", visibility);
- return (visibility.kind == Visibility.Kind.export_) && !fbody;
+ return (visibility.kind == Visibility.Kind.export_ || dllImport) && !fbody;
}
override final bool isCodeseg() const pure nothrow @nogc @safe
@@ -1441,17 +1448,27 @@ extern (C++) class FuncDeclaration : Declaration
}
/**************************************
- * The function is doing something impure,
- * so mark it as impure.
- * If there's a purity error, return true.
+ * The function is doing something impure, so mark it as impure.
+ *
+ * Params:
+ * loc = location of impure action
+ * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
+ * arg0 = (optional) argument to format string
+ *
+ * Returns: `true` if there's a purity error
*/
- extern (D) final bool setImpure()
+ extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
{
if (purityInprocess)
{
purityInprocess = false;
+ if (fmt)
+ pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
+ else if (arg0)
+ pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
+
if (fes)
- fes.func.setImpure();
+ fes.func.setImpure(loc, fmt, arg0);
}
else if (isPure())
return true;
@@ -1540,7 +1557,7 @@ extern (C++) class FuncDeclaration : Declaration
{
//printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
if (nogcInprocess)
- setGC();
+ setGC(loc, null);
return type.toTypeFunction().isnogc;
}
@@ -1552,10 +1569,16 @@ extern (C++) class FuncDeclaration : Declaration
/**************************************
* The function is doing something that may allocate with the GC,
* so mark it as not nogc (not no-how).
+ *
+ * Params:
+ * loc = location of impure action
+ * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
+ * arg0 = (optional) argument to format string
+ *
* Returns:
* true if function is marked as @nogc, meaning a user error occurred
*/
- extern (D) final bool setGC()
+ extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null)
{
//printf("setGC() %s\n", toChars());
if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
@@ -1567,15 +1590,59 @@ extern (C++) class FuncDeclaration : Declaration
if (nogcInprocess)
{
nogcInprocess = false;
+ if (fmt)
+ nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC
+ else if (arg0)
+ nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
+
type.toTypeFunction().isnogc = false;
if (fes)
- fes.func.setGC();
+ fes.func.setGC(Loc.init, null, null);
}
else if (isNogc())
return true;
return false;
}
+ /**************************************
+ * The function calls non-`@nogc` function f, mark it as not nogc.
+ * Params:
+ * f = function being called
+ * Returns:
+ * true if function is marked as @nogc, meaning a user error occurred
+ */
+ extern (D) final bool setGCCall(FuncDeclaration f)
+ {
+ return setGC(loc, null, f);
+ }
+
+ /**************************************
+ * The function is doing something that may throw an exception, register that in case nothrow is being inferred
+ *
+ * Params:
+ * loc = location of action
+ * fmt = format string for error message
+ * arg0 = (optional) argument to format string
+ */
+ extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
+ {
+ if (nothrowInprocess && !nothrowViolation)
+ {
+ nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
+ }
+ }
+
+ /**************************************
+ * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
+ * Params:
+ * loc = location of call
+ * f = function being called
+ */
+ extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
+ {
+ return setThrow(loc, null, f);
+ }
+
extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
{
if (!global.params.vgc)
@@ -2119,7 +2186,7 @@ extern (C++) class FuncDeclaration : Declaration
if (!needsClosure())
return false;
- if (setGC())
+ if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
{
error("is `@nogc` yet allocates closure for `%s()` with the GC", toChars());
if (global.gag) // need not report supplemental errors
@@ -4531,18 +4598,51 @@ struct AttributeViolation
/// fd = function to check
/// maxDepth = up to how many functions deep to report errors
/// deprecation = print deprecations instead of errors
-void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool deprecation)
+/// stc = storage class of attribute to check
+void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
{
auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
- if (auto s = fd.safetyViolation)
+
+ AttributeViolation* s;
+ const(char)* attr;
+ if (stc & STC.safe)
+ {
+ s = fd.safetyViolation;
+ attr = "@safe";
+ }
+ else if (stc & STC.pure_)
+ {
+ s = fd.pureViolation;
+ attr = "pure";
+ }
+ else if (stc & STC.nothrow_)
+ {
+ s = fd.nothrowViolation;
+ attr = "nothrow";
+ }
+ else if (stc & STC.nogc)
+ {
+ s = fd.nogcViolation;
+ attr = "@nogc";
+ }
+
+ if (s)
{
if (s.fmtStr)
{
errorFunc(s.loc, deprecation ?
- "which would be `@system` because of:" :
- "which was inferred `@system` because of:");
- errorFunc(s.loc, s.fmtStr,
- s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
+ "which wouldn't be `%s` because of:" :
+ "which wasn't inferred `%s` because of:", attr);
+ if (stc == STC.nogc || stc == STC.pure_)
+ {
+ auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
+ errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
+ }
+ else
+ {
+ errorFunc(s.loc, s.fmtStr,
+ s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
+ }
}
else if (s.arg0.dyncast() == DYNCAST.dsymbol)
{
@@ -4551,7 +4651,7 @@ void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool depr
if (maxDepth > 0)
{
errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
- errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation);
+ errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);
}
}
}
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index 1919d9a..45b4528 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -11,7 +11,10 @@
module dmd.globals;
+import core.stdc.stdio;
import core.stdc.stdint;
+import core.stdc.string;
+
import dmd.root.array;
import dmd.root.filename;
import dmd.common.outbuffer;
@@ -20,6 +23,8 @@ import dmd.errors;
import dmd.file_manager;
import dmd.identifier;
import dmd.location;
+import dmd.lexer : CompileEnv;
+import dmd.utils;
/// Defines a setting for how compiler warnings and deprecations are handled
enum DiagnosticReporting : ubyte
@@ -149,7 +154,7 @@ extern (C++) struct Param
FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params
bool ehnogc; // use @nogc exception handling
bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
- bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
+ FeatureState fieldwise; // do struct equality testing field-wise rather than by memcmp()
bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes
FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters
// https://dconf.org/2019/talks/alexandrescu.html
@@ -209,6 +214,7 @@ extern (C++) struct Param
bool run; // run resulting executable
Strings runargs; // arguments for executable
Array!(const(char)*) cppswitches; // C preprocessor switches
+ const(char)* cpp; // if not null, then this specifies the C preprocessor
// Linker stuff
Array!(const(char)*) objfiles;
@@ -222,30 +228,6 @@ extern (C++) struct Param
const(char)[] mapfile;
}
-extern (C++) struct structalign_t
-{
- private:
- ushort value = 0; // unknown
- enum STRUCTALIGN_DEFAULT = 1234; // default = match whatever the corresponding C compiler does
- bool pack; // use #pragma pack semantics
-
- public:
- pure @safe @nogc nothrow:
- bool isDefault() const { return value == STRUCTALIGN_DEFAULT; }
- void setDefault() { value = STRUCTALIGN_DEFAULT; }
- bool isUnknown() const { return value == 0; } // value is not set
- void setUnknown() { value = 0; }
- void set(uint value) { this.value = cast(ushort)value; }
- uint get() const { return value; }
- bool isPack() const { return pack; }
- void setPack(bool pack) { this.pack = pack; }
-}
-//alias structalign_t = uint;
-
-// magic value means "match whatever the underlying C compiler does"
-// other values are all powers of 2
-//enum STRUCTALIGN_DEFAULT = (cast(structalign_t)~0);
-
enum mars_ext = "d"; // for D source files
enum doc_ext = "html"; // for Ddoc generated files
enum ddoc_ext = "ddoc"; // for Ddoc macro include files
@@ -270,9 +252,7 @@ extern (C++) struct Global
Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path
private enum string _version = import("VERSION");
- private enum uint _versionNumber = parseVersionNumber(_version);
-
- const(char)[] vendor; /// Compiler backend name
+ CompileEnv compileEnv;
Param params; /// command line parameters
uint errors; /// number of errors reported so far
@@ -350,12 +330,12 @@ extern (C++) struct Global
extern (C++) void _init()
{
- global.errorSink = new ErrorSinkCompiler;
+ errorSink = new ErrorSinkCompiler;
this.fileManager = new FileManager();
version (MARS)
{
- vendor = "Digital Mars D";
+ compileEnv.vendor = "Digital Mars D";
// -color=auto is the default value
import dmd.console : detectTerminal;
@@ -363,8 +343,38 @@ extern (C++) struct Global
}
else version (IN_GCC)
{
- vendor = "GNU D";
+ compileEnv.vendor = "GNU D";
+ }
+ compileEnv.versionNumber = parseVersionNumber(_version);
+
+ /* Initialize date, time, and timestamp
+ */
+ import core.stdc.time;
+ import core.stdc.stdlib : getenv;
+
+ time_t ct;
+ // https://issues.dlang.org/show_bug.cgi?id=20444
+ if (auto p = getenv("SOURCE_DATE_EPOCH"))
+ {
+ if (!ct.parseDigits(p[0 .. strlen(p)]))
+ errorSink.error(Loc.initial, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
}
+ else
+ core.stdc.time.time(&ct);
+ const p = ctime(&ct);
+ assert(p);
+
+ __gshared char[11 + 1] date = 0; // put in BSS segment
+ __gshared char[8 + 1] time = 0;
+ __gshared char[24 + 1] timestamp = 0;
+
+ const dsz = snprintf(&date[0], date.length, "%.6s %.4s", p + 4, p + 20);
+ const tsz = snprintf(&time[0], time.length, "%.8s", p + 11);
+ const tssz = snprintf(&timestamp[0], timestamp.length, "%.24s", p);
+ assert(dsz > 0 && tsz > 0 && tssz > 0);
+ compileEnv.time = time[0 .. tsz];
+ compileEnv.date = date[0 .. dsz];
+ compileEnv.timestamp = timestamp[0 .. tssz];
}
/**
@@ -415,7 +425,7 @@ extern (C++) struct Global
*/
extern(C++) uint versionNumber()
{
- return _versionNumber;
+ return compileEnv.versionNumber;
}
/**
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 84fbec6..902cf83 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -151,7 +151,7 @@ struct Param
FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params
d_bool ehnogc; // use @nogc exception handling
d_bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
- d_bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
+ FeatureState fieldwise; // do struct equality testing field-wise rather than by memcmp()
d_bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes
FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters
// https://dconf.org/2019/talks/alexandrescu.html
@@ -212,6 +212,7 @@ struct Param
Strings runargs; // arguments for executable
Array<const char *> cppswitches; // preprocessor switches
+ const char *cpp; // if not null, then this specifies the C preprocessor
// Linker stuff
Array<const char *> objfiles;
@@ -252,6 +253,18 @@ const DString hdr_ext = "di"; // for D 'header' import files
const DString json_ext = "json"; // for JSON files
const DString map_ext = "map"; // for .map files
+struct CompileEnv
+{
+ uint32_t versionNumber;
+ DString date;
+ DString time;
+ DString vendor;
+ DString timestamp;
+ bool previewIn;
+ bool ddocOutput;
+ bool shortenedMethods;
+};
+
struct Global
{
DString inifilename;
@@ -261,7 +274,7 @@ struct Global
Array<const char *> *path; // Array of char*'s which form the import lookup path
Array<const char *> *filePath; // Array of char*'s which form the file import lookup path
- DString vendor; // Compiler backend name
+ CompileEnv compileEnv;
Param params;
unsigned errors; // number of errors reported so far
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index e0684e6..a159c2f 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -134,37 +134,19 @@ void moduleToBuffer2(Module m, OutBuffer* buf, HdrGenState* hgs)
private void statementToBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs)
{
- scope v = new StatementPrettyPrintVisitor(buf, hgs);
- s.accept(v);
-}
-
-private extern (C++) final class StatementPrettyPrintVisitor : Visitor
-{
- alias visit = Visitor.visit;
-public:
- OutBuffer* buf;
- HdrGenState* hgs;
-
- extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope
+ void visitDefaultCase(Statement s)
{
- this.buf = buf;
- this.hgs = hgs;
+ printf("Statement::toCBuffer() %d\n", s.stmt);
+ assert(0, "unrecognized statement in statementToBuffer()");
}
- override void visit(Statement s)
- {
- buf.writestring("Statement::toCBuffer()");
- buf.writenl();
- assert(0);
- }
-
- override void visit(ErrorStatement s)
+ void visitError(ErrorStatement s)
{
buf.writestring("__error__");
buf.writenl();
}
- override void visit(ExpStatement s)
+ void visitExp(ExpStatement s)
{
if (s.exp && s.exp.op == EXP.declaration &&
(cast(DeclarationExp)s.exp).declaration)
@@ -180,7 +162,12 @@ public:
buf.writenl();
}
- override void visit(CompileStatement s)
+ void visitDtorExp(DtorExpStatement s)
+ {
+ visitExp(s);
+ }
+
+ void visitMixin(MixinStatement s)
{
buf.writestring("mixin(");
argsToBuffer(s.exps, buf, hgs, null);
@@ -189,25 +176,29 @@ public:
buf.writenl();
}
- override void visit(CompoundStatement s)
+ void visitCompound(CompoundStatement s)
{
foreach (sx; *s.statements)
{
if (sx)
- sx.accept(this);
+ sx.statementToBuffer(buf, hgs);
}
}
- override void visit(CompoundDeclarationStatement s)
+ void visitCompoundAsm(CompoundAsmStatement s)
+ {
+ visitCompound(s);
+ }
+
+ void visitCompoundDeclaration(CompoundDeclarationStatement s)
{
bool anywritten = false;
foreach (sx; *s.statements)
{
auto ds = sx ? sx.isExpStatement() : null;
- if (ds && ds.exp.op == EXP.declaration)
+ if (ds && ds.exp.isDeclarationExp())
{
- auto d = (cast(DeclarationExp)ds.exp).declaration;
- assert(d.isDeclaration());
+ auto d = ds.exp.isDeclarationExp().declaration;
if (auto v = d.isVarDeclaration())
{
scope ppv = new DsymbolPrettyPrintVisitor(buf, hgs);
@@ -223,7 +214,7 @@ public:
buf.writenl();
}
- override void visit(UnrolledLoopStatement s)
+ void visitUnrolledLoop(UnrolledLoopStatement s)
{
buf.writestring("/*unrolled*/ {");
buf.writenl();
@@ -231,26 +222,26 @@ public:
foreach (sx; *s.statements)
{
if (sx)
- sx.accept(this);
+ sx.statementToBuffer(buf, hgs);
}
buf.level--;
buf.writeByte('}');
buf.writenl();
}
- override void visit(ScopeStatement s)
+ void visitScope(ScopeStatement s)
{
buf.writeByte('{');
buf.writenl();
buf.level++;
if (s.statement)
- s.statement.accept(this);
+ s.statement.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
buf.writenl();
}
- override void visit(WhileStatement s)
+ void visitWhile(WhileStatement s)
{
buf.writestring("while (");
if (auto p = s.param)
@@ -271,28 +262,28 @@ public:
buf.writeByte(')');
buf.writenl();
if (s._body)
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
}
- override void visit(DoStatement s)
+ void visitDo(DoStatement s)
{
buf.writestring("do");
buf.writenl();
if (s._body)
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
buf.writestring("while (");
s.condition.expressionToBuffer(buf, hgs);
buf.writestring(");");
buf.writenl();
}
- override void visit(ForStatement s)
+ void visitFor(ForStatement s)
{
buf.writestring("for (");
if (s._init)
{
hgs.forStmtInit++;
- s._init.accept(this);
+ s._init.statementToBuffer(buf, hgs);
hgs.forStmtInit--;
}
else
@@ -314,13 +305,13 @@ public:
buf.writenl();
buf.level++;
if (s._body)
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
buf.writenl();
}
- private void foreachWithoutBody(ForeachStatement s)
+ void foreachWithoutBody(ForeachStatement s)
{
buf.writestring(Token.toString(s.op));
buf.writestring(" (");
@@ -341,20 +332,20 @@ public:
buf.writenl();
}
- override void visit(ForeachStatement s)
+ void visitForeach(ForeachStatement s)
{
foreachWithoutBody(s);
buf.writeByte('{');
buf.writenl();
buf.level++;
if (s._body)
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
buf.writenl();
}
- private void foreachRangeWithoutBody(ForeachRangeStatement s)
+ void foreachRangeWithoutBody(ForeachRangeStatement s)
{
buf.writestring(Token.toString(s.op));
buf.writestring(" (");
@@ -370,39 +361,39 @@ public:
buf.writenl();
}
- override void visit(ForeachRangeStatement s)
+ void visitForeachRange(ForeachRangeStatement s)
{
foreachRangeWithoutBody(s);
buf.writeByte('{');
buf.writenl();
buf.level++;
if (s._body)
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
buf.writenl();
}
- override void visit(StaticForeachStatement s)
+ void visitStaticForeach(StaticForeachStatement s)
{
buf.writestring("static ");
if (s.sfe.aggrfe)
{
- visit(s.sfe.aggrfe);
+ visitForeach(s.sfe.aggrfe);
}
else
{
assert(s.sfe.rangefe);
- visit(s.sfe.rangefe);
+ visitForeachRange(s.sfe.rangefe);
}
}
- override void visit(ForwardingStatement s)
+ void visitForwarding(ForwardingStatement s)
{
- s.statement.accept(this);
+ s.statement.statementToBuffer(buf, hgs);
}
- override void visit(IfStatement s)
+ void visitIf(IfStatement s)
{
buf.writestring("if (");
if (Parameter p = s.prm)
@@ -423,12 +414,12 @@ public:
buf.writenl();
if (s.ifbody.isScopeStatement())
{
- s.ifbody.accept(this);
+ s.ifbody.statementToBuffer(buf, hgs);
}
else
{
buf.level++;
- s.ifbody.accept(this);
+ s.ifbody.statementToBuffer(buf, hgs);
buf.level--;
}
if (s.elsebody)
@@ -444,18 +435,18 @@ public:
}
if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement())
{
- s.elsebody.accept(this);
+ s.elsebody.statementToBuffer(buf, hgs);
}
else
{
buf.level++;
- s.elsebody.accept(this);
+ s.elsebody.statementToBuffer(buf, hgs);
buf.level--;
}
}
}
- override void visit(ConditionalStatement s)
+ void visitConditional(ConditionalStatement s)
{
s.condition.conditionToBuffer(buf, hgs);
buf.writenl();
@@ -463,7 +454,7 @@ public:
buf.writenl();
buf.level++;
if (s.ifbody)
- s.ifbody.accept(this);
+ s.ifbody.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
buf.writenl();
@@ -474,14 +465,14 @@ public:
buf.writeByte('{');
buf.level++;
buf.writenl();
- s.elsebody.accept(this);
+ s.elsebody.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
}
buf.writenl();
}
- override void visit(PragmaStatement s)
+ void visitPragma(PragmaStatement s)
{
buf.writestring("pragma (");
buf.writestring(s.ident.toString());
@@ -497,7 +488,7 @@ public:
buf.writeByte('{');
buf.writenl();
buf.level++;
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
buf.writenl();
@@ -509,12 +500,12 @@ public:
}
}
- override void visit(StaticAssertStatement s)
+ void visitStaticAssert(StaticAssertStatement s)
{
s.sa.dsymbolToBuffer(buf, hgs);
}
- override void visit(SwitchStatement s)
+ void visitSwitch(SwitchStatement s)
{
buf.writestring(s.isFinal ? "final switch (" : "switch (");
s.condition.expressionToBuffer(buf, hgs);
@@ -527,28 +518,28 @@ public:
buf.writeByte('{');
buf.writenl();
buf.level++;
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
buf.writenl();
}
else
{
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
}
}
}
- override void visit(CaseStatement s)
+ void visitCase(CaseStatement s)
{
buf.writestring("case ");
s.exp.expressionToBuffer(buf, hgs);
buf.writeByte(':');
buf.writenl();
- s.statement.accept(this);
+ s.statement.statementToBuffer(buf, hgs);
}
- override void visit(CaseRangeStatement s)
+ void visitCaseRange(CaseRangeStatement s)
{
buf.writestring("case ");
s.first.expressionToBuffer(buf, hgs);
@@ -556,23 +547,23 @@ public:
s.last.expressionToBuffer(buf, hgs);
buf.writeByte(':');
buf.writenl();
- s.statement.accept(this);
+ s.statement.statementToBuffer(buf, hgs);
}
- override void visit(DefaultStatement s)
+ void visitDefault(DefaultStatement s)
{
buf.writestring("default:");
buf.writenl();
- s.statement.accept(this);
+ s.statement.statementToBuffer(buf, hgs);
}
- override void visit(GotoDefaultStatement s)
+ void visitGotoDefault(GotoDefaultStatement s)
{
buf.writestring("goto default;");
buf.writenl();
}
- override void visit(GotoCaseStatement s)
+ void visitGotoCase(GotoCaseStatement s)
{
buf.writestring("goto case");
if (s.exp)
@@ -584,13 +575,13 @@ public:
buf.writenl();
}
- override void visit(SwitchErrorStatement s)
+ void visitSwitchError(SwitchErrorStatement s)
{
buf.writestring("SwitchErrorStatement::toCBuffer()");
buf.writenl();
}
- override void visit(ReturnStatement s)
+ void visitReturn(ReturnStatement s)
{
buf.writestring("return ");
if (s.exp)
@@ -599,7 +590,7 @@ public:
buf.writenl();
}
- override void visit(BreakStatement s)
+ void visitBreak(BreakStatement s)
{
buf.writestring("break");
if (s.ident)
@@ -611,7 +602,7 @@ public:
buf.writenl();
}
- override void visit(ContinueStatement s)
+ void visitContinue(ContinueStatement s)
{
buf.writestring("continue");
if (s.ident)
@@ -623,7 +614,7 @@ public:
buf.writenl();
}
- override void visit(SynchronizedStatement s)
+ void visitSynchronized(SynchronizedStatement s)
{
buf.writestring("synchronized");
if (s.exp)
@@ -635,21 +626,21 @@ public:
if (s._body)
{
buf.writeByte(' ');
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
}
}
- override void visit(WithStatement s)
+ void visitWith(WithStatement s)
{
buf.writestring("with (");
s.exp.expressionToBuffer(buf, hgs);
buf.writestring(")");
buf.writenl();
if (s._body)
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
}
- override void visit(TryCatchStatement s)
+ void visitTryCatch(TryCatchStatement s)
{
buf.writestring("try");
buf.writenl();
@@ -657,29 +648,44 @@ public:
{
if (s._body.isScopeStatement())
{
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
}
else
{
buf.level++;
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
buf.level--;
}
}
foreach (c; *s.catches)
{
- visit(c);
+ buf.writestring("catch");
+ if (c.type)
+ {
+ buf.writeByte('(');
+ typeToBuffer(c.type, c.ident, buf, hgs);
+ buf.writeByte(')');
+ }
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ if (c.handler)
+ c.handler.statementToBuffer(buf, hgs);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
}
}
- override void visit(TryFinallyStatement s)
+ void visitTryFinally(TryFinallyStatement s)
{
buf.writestring("try");
buf.writenl();
buf.writeByte('{');
buf.writenl();
buf.level++;
- s._body.accept(this);
+ s._body.statementToBuffer(buf, hgs);
buf.level--;
buf.writeByte('}');
buf.writenl();
@@ -687,25 +693,25 @@ public:
buf.writenl();
if (s.finalbody.isScopeStatement())
{
- s.finalbody.accept(this);
+ s.finalbody.statementToBuffer(buf, hgs);
}
else
{
buf.level++;
- s.finalbody.accept(this);
+ s.finalbody.statementToBuffer(buf, hgs);
buf.level--;
}
}
- override void visit(ScopeGuardStatement s)
+ void visitScopeGuard(ScopeGuardStatement s)
{
buf.writestring(Token.toString(s.tok));
buf.writeByte(' ');
if (s.statement)
- s.statement.accept(this);
+ s.statement.statementToBuffer(buf, hgs);
}
- override void visit(ThrowStatement s)
+ void visitThrow(ThrowStatement s)
{
buf.writestring("throw ");
s.exp.expressionToBuffer(buf, hgs);
@@ -713,15 +719,15 @@ public:
buf.writenl();
}
- override void visit(DebugStatement s)
+ void visitDebug(DebugStatement s)
{
if (s.statement)
{
- s.statement.accept(this);
+ s.statement.statementToBuffer(buf, hgs);
}
}
- override void visit(GotoStatement s)
+ void visitGoto(GotoStatement s)
{
buf.writestring("goto ");
buf.writestring(s.ident.toString());
@@ -729,16 +735,16 @@ public:
buf.writenl();
}
- override void visit(LabelStatement s)
+ void visitLabel(LabelStatement s)
{
buf.writestring(s.ident.toString());
buf.writeByte(':');
buf.writenl();
if (s.statement)
- s.statement.accept(this);
+ s.statement.statementToBuffer(buf, hgs);
}
- override void visit(AsmStatement s)
+ void visitAsm(AsmStatement s)
{
buf.writestring("asm { ");
Token* t = s.tokens;
@@ -764,33 +770,26 @@ public:
buf.writenl();
}
- override void visit(ImportStatement s)
+ void visitInlineAsm(InlineAsmStatement s)
{
- foreach (imp; *s.imports)
- {
- imp.dsymbolToBuffer(buf, hgs);
- }
+ visitAsm(s);
}
- void visit(Catch c)
+ void visitGccAsm(GccAsmStatement s)
{
- buf.writestring("catch");
- if (c.type)
+ visitAsm(s);
+ }
+
+ void visitImport(ImportStatement s)
+ {
+ foreach (imp; *s.imports)
{
- buf.writeByte('(');
- typeToBuffer(c.type, c.ident, buf, hgs);
- buf.writeByte(')');
+ imp.dsymbolToBuffer(buf, hgs);
}
- buf.writenl();
- buf.writeByte('{');
- buf.writenl();
- buf.level++;
- if (c.handler)
- c.handler.accept(this);
- buf.level--;
- buf.writeByte('}');
- buf.writenl();
}
+
+ mixin VisitStatement!void visit;
+ visit.VisitStatement(s);
}
private void dsymbolToBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs)
@@ -1160,7 +1159,7 @@ public:
}
- override void visit(CompileDeclaration d)
+ override void visit(MixinDeclaration d)
{
buf.writestring("mixin(");
argsToBuffer(d.exps, buf, hgs, null);
@@ -2321,6 +2320,16 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
+ void visitLoweredAssignExp(LoweredAssignExp e)
+ {
+ if (global.params.vcg_ast)
+ {
+ expressionToBuffer(e.lowering, buf, hgs);
+ return;
+ }
+
+ visit(cast(BinExp)e);
+ }
void visitBin(BinExp e)
{
expToBuffer(e.e1, precedence[e.op], buf, hgs);
@@ -2694,6 +2703,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg
case EXP.remove: return visitRemove(e.isRemoveExp());
case EXP.question: return visitCond(e.isCondExp());
case EXP.classReference: return visitClassReference(e.isClassReferenceExp());
+ case EXP.loweredAssignExp: return visitLoweredAssignExp(e.isLoweredAssignExp());
}
}
@@ -2882,8 +2892,7 @@ public:
void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs)
{
- scope v = new StatementPrettyPrintVisitor(buf, hgs);
- (cast() s).accept(v);
+ (cast()s).statementToBuffer(buf, hgs);
}
void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs)
@@ -3223,6 +3232,7 @@ private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* h
final switch (pl.varargs)
{
case VarArg.none:
+ case VarArg.KRvariadic:
break;
case VarArg.variadic:
@@ -3817,15 +3827,8 @@ private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* h
buf.writeByte('}');
}
- final switch (inx.kind)
- {
- case InitKind.error: return visitError (inx.isErrorInitializer ());
- case InitKind.void_: return visitVoid (inx.isVoidInitializer ());
- case InitKind.struct_: return visitStruct(inx.isStructInitializer());
- case InitKind.array: return visitArray (inx.isArrayInitializer ());
- case InitKind.exp: return visitExp (inx.isExpInitializer ());
- case InitKind.C_: return visitC (inx.isCInitializer ());
- }
+ mixin VisitInitializer!void visit;
+ visit.VisitInitializer(inx);
}
@@ -4101,7 +4104,6 @@ string EXPtoString(EXP op)
EXP.error : "error",
EXP.objcClassReference : "class",
- EXP.typeof_ : "typeof",
EXP.mixin_ : "mixin",
EXP.import_ : "import",
@@ -4141,7 +4143,6 @@ string EXPtoString(EXP op)
EXP.remove : "remove",
EXP.tuple : "tuple",
EXP.traits : "__traits",
- EXP.default_ : "default",
EXP.overloadSet : "__overloadset",
EXP.void_ : "void",
EXP.vectorArray : "vectorarray",
@@ -4232,6 +4233,7 @@ string EXPtoString(EXP op)
EXP.declaration : "declaration",
EXP.interval : "interval",
+ EXP.loweredAssignExp : "="
];
const p = strings[op];
if (!p)
diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d
index 4d780b3..66829da 100644
--- a/gcc/d/dmd/iasm.d
+++ b/gcc/d/dmd/iasm.d
@@ -13,9 +13,15 @@
module dmd.iasm;
+import core.stdc.stdio;
+
import dmd.dscope;
+import dmd.expression;
import dmd.func;
+import dmd.mtype;
+import dmd.tokens;
import dmd.statement;
+import dmd.statementsem;
version (MARS)
{
@@ -43,6 +49,19 @@ extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc)
version (MARS)
{
+ /* If it starts with a string literal, it's gcc inline asm
+ */
+ if (s.tokens.value == TOK.string_)
+ {
+ /* Replace the asm statement with an assert(0, msg) that trips at runtime.
+ */
+ const loc = s.loc;
+ auto e = new IntegerExp(loc, 0, Type.tint32);
+ auto msg = new StringExp(loc, "Gnu Asm not supported - compile this function with gcc or clang");
+ auto ae = new AssertExp(loc, e, msg);
+ auto se = new ExpStatement(loc, ae);
+ return statementSemantic(se, sc);
+ }
auto ias = new InlineAsmStatement(s.loc, s.tokens);
return inlineAsmSemantic(ias, sc);
}
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
index f8c88ab..1d4dea4 100644
--- a/gcc/d/dmd/iasmgcc.d
+++ b/gcc/d/dmd/iasmgcc.d
@@ -302,7 +302,8 @@ Ldone:
extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
{
//printf("GccAsmStatement.semantic()\n");
- scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink);
+ const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
+ scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink, &global.compileEnv, doUnittests);
// Make a safe copy of the token list before parsing.
Token *toklist = null;
@@ -410,7 +411,8 @@ unittest
{
const errors = global.errors;
scope gas = new GccAsmStatement(Loc.initial, tokens);
- scope p = new Parser!ASTCodegen(null, ";", false, global.errorSink);
+ const bool doUnittests = false;
+ scope p = new Parser!ASTCodegen(null, ";", false, global.errorSink, &global.compileEnv, doUnittests);
p.token = *tokens;
p.parseGccAsm(gas);
return global.errors - errors;
@@ -420,7 +422,8 @@ unittest
static void parseAsm(string input, bool expectError)
{
// Generate tokens from input test.
- scope p = new Parser!ASTCodegen(null, input, false, global.errorSink);
+ const bool doUnittests = false;
+ scope p = new Parser!ASTCodegen(null, input, false, global.errorSink, &global.compileEnv, doUnittests);
p.nextToken();
Token* toklist = null;
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index ec5cb25..a2271d5 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -361,6 +361,8 @@ immutable Msgtable[] msgtable =
{ "_d_arrayappendcTXImpl" },
{ "_d_arrayappendcTX" },
{ "_d_arrayappendcTXTrace" },
+ { "_d_arraycatnTX" },
+ { "_d_arraycatnTXTrace" },
// varargs implementation
{ "stdc" },
@@ -370,6 +372,10 @@ immutable Msgtable[] msgtable =
// Builtin functions
{ "std" },
{ "core" },
+ { "config" },
+ { "c_complex_float" },
+ { "c_complex_double" },
+ { "c_complex_real" },
{ "etc" },
{ "attribute" },
{ "atomic" },
@@ -519,9 +525,17 @@ immutable Msgtable[] msgtable =
{ "__tag" },
{ "dllimport" },
{ "dllexport" },
+ { "naked" },
+ { "thread" },
{ "vector_size" },
{ "__func__" },
+ { "always_inline" },
+ { "noinline" },
{ "noreturn" },
+ { "_nothrow", "nothrow" },
+ { "_deprecated", "deprecated" },
+ { "_align", "align" },
+ { "aligned" },
{ "__pragma", "pragma" },
{ "builtins", "__builtins" },
{ "builtin_va_list", "__builtin_va_list" },
@@ -532,6 +546,7 @@ immutable Msgtable[] msgtable =
{ "show" },
{ "push" },
{ "pop" },
+ { "_pure", "pure" },
{ "define" },
{ "undef" },
];
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index f646d03..6f20a3c 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -269,7 +269,22 @@ extern (C++) final class CInitializer : Initializer
*/
Initializer syntaxCopy(Initializer inx)
{
- static Initializer copyStruct(StructInitializer vi)
+ static Initializer visitVoid(VoidInitializer vi)
+ {
+ return new VoidInitializer(vi.loc);
+ }
+
+ static Initializer visitError(ErrorInitializer vi)
+ {
+ return vi;
+ }
+
+ static Initializer visitExp(ExpInitializer vi)
+ {
+ return new ExpInitializer(vi.loc, vi.exp.syntaxCopy());
+ }
+
+ static Initializer visitStruct(StructInitializer vi)
{
auto si = new StructInitializer(vi.loc);
assert(vi.field.length == vi.value.length);
@@ -283,7 +298,7 @@ Initializer syntaxCopy(Initializer inx)
return si;
}
- static Initializer copyArray(ArrayInitializer vi)
+ static Initializer visitArray(ArrayInitializer vi)
{
auto ai = new ArrayInitializer(vi.loc);
assert(vi.index.length == vi.value.length);
@@ -297,7 +312,7 @@ Initializer syntaxCopy(Initializer inx)
return ai;
}
- static Initializer copyC(CInitializer vi)
+ static Initializer visitC(CInitializer vi)
{
auto ci = new CInitializer(vi.loc);
ci.initializerList.setDim(vi.initializerList.length);
@@ -322,13 +337,62 @@ Initializer syntaxCopy(Initializer inx)
return ci;
}
- final switch (inx.kind)
+ mixin VisitInitializer!Initializer visit;
+ return visit.VisitInitializer(inx);
+}
+
+/***********************************************************
+ * Visit each Initializer in init. Call a function visit%s(init) for
+ * each node, where %s is the op of the node. Otherwise call visitDefault(init)
+ * for that node. If the visit function returns R.init, continue
+ * visiting each node, otherwise return the value of R.
+ * Params:
+ * Result = return type
+ * init = Initializer tree to traverse
+ * Returns:
+ * Result.init for continue, value of type Result for early exit
+ */
+
+mixin template VisitInitializer(Result)
+{
+ Result VisitInitializer(Initializer init)
+ {
+ final switch (init.kind)
+ {
+ case InitKind.void_: mixin(visitCase("Void")); break;
+ case InitKind.error: mixin(visitCase("Error")); break;
+ case InitKind.struct_: mixin(visitCase("Struct")); break;
+ case InitKind.array: mixin(visitCase("Array")); break;
+ case InitKind.exp: mixin(visitCase("Exp")); break;
+ case InitKind.C_: mixin(visitCase("C")); break;
+ }
+ static if (is(Result == void)) { } else
+ return Result.init;
+ }
+}
+
+/****************************************
+ * CTFE-only helper function for VisitInitializer.
+ * Params:
+ * handler = string for the name of the visit handler
+ * Returns: boilerplate code for a case
+ */
+pure string visitCase(string handler)
+{
+ if (__ctfe)
{
- case InitKind.void_: return new VoidInitializer(inx.loc);
- case InitKind.error: return inx;
- case InitKind.struct_: return copyStruct(cast(StructInitializer)inx);
- case InitKind.array: return copyArray(cast(ArrayInitializer)inx);
- case InitKind.exp: return new ExpInitializer(inx.loc, (cast(ExpInitializer)inx).exp.syntaxCopy());
- case InitKind.C_: return copyC(cast(CInitializer)inx);
+ return
+ "
+ auto ix = init.is"~handler~"Initializer();
+ static if (is(Result == void))
+ visit"~handler~"(ix);
+ else
+ {
+ Result r = visit"~handler~"(ix);
+ if (r !is Result.init)
+ return r;
+ }
+ ";
}
+ assert(0);
}
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 18b10b4..893d2a6 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -958,15 +958,9 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
}
}
- final switch (init.kind)
- {
- case InitKind.void_: return visitVoid (init.isVoidInitializer());
- case InitKind.error: return visitError (init.isErrorInitializer());
- case InitKind.struct_: return visitStruct(init.isStructInitializer());
- case InitKind.array: return visitArray (init.isArrayInitializer());
- case InitKind.exp: return visitExp (init.isExpInitializer());
- case InitKind.C_: return visitC (init.isCInitializer());
- }
+ mixin VisitInitializer!Initializer visit;
+ auto result = visit.VisitInitializer(init);
+ return (result !is null) ? result : new ErrorInitializer();
}
/***********************
@@ -1120,15 +1114,9 @@ Initializer inferType(Initializer init, Scope* sc)
return new ErrorInitializer();
}
- final switch (init.kind)
- {
- case InitKind.void_: return visitVoid (init.isVoidInitializer());
- case InitKind.error: return visitError (init.isErrorInitializer());
- case InitKind.struct_: return visitStruct(init.isStructInitializer());
- case InitKind.array: return visitArray (init.isArrayInitializer());
- case InitKind.exp: return visitExp (init.isExpInitializer());
- case InitKind.C_: return visitC (init.isCInitializer());
- }
+ mixin VisitInitializer!Initializer visit;
+ auto result = visit.VisitInitializer(init);
+ return (result !is null) ? result : new ErrorInitializer();
}
/***********************
@@ -1333,15 +1321,8 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
return null;
}
- final switch (init.kind)
- {
- case InitKind.void_: return visitVoid (init.isVoidInitializer());
- case InitKind.error: return visitError (init.isErrorInitializer());
- case InitKind.struct_: return visitStruct(init.isStructInitializer());
- case InitKind.array: return visitArray (init.isArrayInitializer());
- case InitKind.exp: return visitExp (init.isExpInitializer());
- case InitKind.C_: return visitC (init.isCInitializer());
- }
+ mixin VisitInitializer!Expression visit;
+ return visit.VisitInitializer(init);
}
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
index 2af7fae..dcf53b8 100644
--- a/gcc/d/dmd/json.d
+++ b/gcc/d/dmd/json.d
@@ -833,7 +833,7 @@ public:
{
import dmd.target : target;
objectStart();
- requiredProperty("vendor", global.vendor);
+ requiredProperty("vendor", global.compileEnv.vendor);
requiredProperty("version", global.versionString());
property("__VERSION__", global.versionNumber());
requiredProperty("interface", determineCompilerInterface());
@@ -1070,13 +1070,13 @@ Determines and returns the compiler interface which is one of `dmd`, `ldc`,
*/
private extern(D) string determineCompilerInterface()
{
- if (global.vendor == "Digital Mars D")
+ if (global.compileEnv.vendor == "Digital Mars D")
return "dmd";
- if (global.vendor == "LDC")
+ if (global.compileEnv.vendor == "LDC")
return "ldc";
- if (global.vendor == "GNU D")
+ if (global.compileEnv.vendor == "GNU D")
return "gdc";
- if (global.vendor == "SDC")
+ if (global.compileEnv.vendor == "SDC")
return "sdc";
return null;
}
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index f0f7872..0ec468b 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -14,12 +14,8 @@
module dmd.lexer;
import core.stdc.ctype;
-import core.stdc.errno;
-import core.stdc.stdarg;
import core.stdc.stdio;
-import core.stdc.stdlib : getenv;
import core.stdc.string;
-import core.stdc.time;
import dmd.entity;
import dmd.errorsink;
@@ -31,10 +27,8 @@ import dmd.root.ctfloat;
import dmd.common.outbuffer;
import dmd.root.port;
import dmd.root.rmem;
-import dmd.root.string;
import dmd.root.utf;
import dmd.tokens;
-import dmd.utils;
nothrow:
@@ -44,6 +38,22 @@ version (DMDLIB)
}
/***********************************************************
+ * Values to use for various magic identifiers
+ */
+struct CompileEnv
+{
+ uint versionNumber; /// __VERSION__
+ const(char)[] date; /// __DATE__
+ const(char)[] time; /// __TIME__
+ const(char)[] vendor; /// __VENDOR__
+ const(char)[] timestamp; /// __TIMESTAMP__
+
+ bool previewIn; /// `in` means `[ref] scope const`, accepts rvalues
+ bool ddocOutput; /// collect embedded documentation comments
+ bool shortenedMethods = true; /// allow => in normal function declarations
+}
+
+/***********************************************************
*/
class Lexer
{
@@ -69,6 +79,7 @@ class Lexer
ubyte wchar_tsize; /// size of C wchar_t, 2 or 4
ErrorSink eSink; /// send error messages through this interface
+ CompileEnv compileEnv; /// environment
private
{
@@ -87,8 +98,6 @@ class Lexer
int lastDocLine; // last line of previous doc comment
Token* tokenFreelist;
- uint versionNumber;
- const(char)[] vendor;
}
nothrow:
@@ -105,13 +114,12 @@ class Lexer
* doDocComment = handle documentation comments
* commentToken = comments become TOK.comment's
* errorSink = where error messages go, must not be null
- * vendor = name of the vendor
- * versionNumber = version of the caller
+ * compileEnv = version, vendor, date, time, etc.
*/
this(const(char)* filename, const(char)* base, size_t begoffset,
size_t endoffset, bool doDocComment, bool commentToken,
ErrorSink errorSink,
- const(char)[] vendor = "DLF", uint versionNumber = 1) pure scope
+ const CompileEnv* compileEnv) pure scope
{
scanloc = Loc(filename, 1, 1);
// debug printf("Lexer::Lexer(%p)\n", base);
@@ -128,8 +136,13 @@ class Lexer
this.lastDocLine = 0;
this.eSink = errorSink;
assert(errorSink);
- this.versionNumber = versionNumber;
- this.vendor = vendor;
+ if (compileEnv)
+ this.compileEnv = *compileEnv;
+ else
+ {
+ this.compileEnv.versionNumber = 1;
+ this.compileEnv.vendor = "DLF";
+ }
//initKeywords();
/* If first line starts with '#!', ignore the line
*/
@@ -169,10 +182,10 @@ class Lexer
*/
this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset,
bool doDocComment, bool commentToken, bool whitespaceToken,
- ErrorSink errorSink
+ ErrorSink errorSink, const CompileEnv* compileEnv = null
)
{
- this(filename, base, begoffset, endoffset, doDocComment, commentToken, errorSink);
+ this(filename, base, begoffset, endoffset, doDocComment, commentToken, errorSink, compileEnv);
this.whitespaceToken = whitespaceToken;
}
@@ -380,6 +393,15 @@ class Lexer
}
}
continue; // skip white space
+
+ case '\\':
+ if (Ccompile && (p[1] == '\r' || p[1] == '\n'))
+ {
+ ++p; // ignore \ followed by new line, like VC does
+ continue;
+ }
+ goto default;
+
case '0':
if (!isZeroSecond(p[1])) // if numeric literal does not continue
{
@@ -571,36 +593,26 @@ class Lexer
else if (*t.ptr == '_') // if special identifier token
{
- // Lazy initialization
- TimeStampInfo.initialize(t.loc, eSink);
-
- if (id == Id.DATE)
+ void toToken(const(char)[] s)
{
- t.ustring = TimeStampInfo.date.ptr;
- goto Lstr;
+ t.value = TOK.string_;
+ t.ustring = s.ptr;
+ t.len = cast(uint)s.length;
+ t.postfix = 0;
}
+
+ if (id == Id.DATE)
+ toToken(compileEnv.date);
else if (id == Id.TIME)
- {
- t.ustring = TimeStampInfo.time.ptr;
- goto Lstr;
- }
+ toToken(compileEnv.time);
else if (id == Id.VENDOR)
- {
- t.ustring = vendor.xarraydup.ptr;
- goto Lstr;
- }
+ toToken(compileEnv.vendor);
else if (id == Id.TIMESTAMP)
- {
- t.ustring = TimeStampInfo.timestamp.ptr;
- Lstr:
- t.value = TOK.string_;
- t.postfix = 0;
- t.len = cast(uint)strlen(t.ustring);
- }
+ toToken(compileEnv.timestamp);
else if (id == Id.VERSIONX)
{
t.value = TOK.int64Literal;
- t.unsvalue = versionNumber;
+ t.unsvalue = compileEnv.versionNumber;
}
else if (id == Id.EOFX)
{
@@ -2570,6 +2582,14 @@ class Lexer
TOK result;
bool isOutOfRange = false;
t.floatvalue = (isWellformedString ? CTFloat.parse(sbufptr, isOutOfRange) : CTFloat.zero);
+
+ bool imaginary = false;
+ if (*p == 'i' && Ccompile)
+ {
+ ++p;
+ imaginary = true;
+ }
+
switch (*p)
{
case 'F':
@@ -2595,11 +2615,17 @@ class Lexer
result = TOK.float80Literal;
break;
}
+
if ((*p == 'i' || *p == 'I') && !Ccompile)
{
if (*p == 'I')
error("use 'i' suffix instead of 'I'");
p++;
+ imaginary = true;
+ }
+
+ if (imaginary)
+ {
switch (result)
{
case TOK.float32Literal:
@@ -3033,7 +3059,10 @@ class Lexer
auto dc = (lineComment && anyToken) ? &t.lineComment : &t.blockComment;
// Combine with previous doc comment, if any
if (*dc)
- *dc = combineComments(*dc, buf[], newParagraph).toDString();
+ {
+ auto p = combineComments(*dc, buf[], newParagraph);
+ *dc = p ? p[0 .. strlen(p)] : null;
+ }
else
*dc = buf.extractSlice(true);
}
@@ -3081,42 +3110,6 @@ class Lexer
private:
-/// Support for `__DATE__`, `__TIME__`, and `__TIMESTAMP__`
-private struct TimeStampInfo
-{
- private __gshared bool initdone = false;
-
- // Note: Those properties need to be guarded by a call to `init`
- // The API isn't safe, and quite brittle, but it was left this way
- // over performance concerns.
- // This is currently only called once, from the lexer.
- __gshared char[11 + 1] date;
- __gshared char[8 + 1] time;
- __gshared char[24 + 1] timestamp;
-
- public static void initialize(const ref Loc loc, ErrorSink eSink) nothrow
- {
- if (initdone)
- return;
-
- initdone = true;
- time_t ct;
- // https://issues.dlang.org/show_bug.cgi?id=20444
- if (auto p = getenv("SOURCE_DATE_EPOCH"))
- {
- if (!ct.parseDigits(p.toDString()))
- eSink.error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
- }
- else
- .time(&ct);
- const p = ctime(&ct);
- assert(p);
- snprintf(&date[0], date.length, "%.6s %.4s", p + 4, p + 20);
- snprintf(&time[0], time.length, "%.8s", p + 11);
- snprintf(&timestamp[0], timestamp.length, "%.24s", p);
- }
-}
-
private enum LS = 0x2028; // UTF line separator
private enum PS = 0x2029; // UTF paragraph separator
@@ -3366,7 +3359,7 @@ unittest
*/
string text = "int"; // We rely on the implicit null-terminator
ErrorSink errorSink = new ErrorSinkStderr;
- scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, false, false, errorSink);
+ scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, false, false, errorSink, null);
TOK tok;
tok = lex1.nextToken();
//printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32);
@@ -3402,7 +3395,7 @@ unittest
foreach (testcase; testcases)
{
- scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, false, false, errorSink);
+ scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, false, false, errorSink, null);
TOK tok = lex2.nextToken();
size_t iterations = 1;
while ((tok != TOK.endOfFile) && (iterations++ < testcase.length))
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 5939db5..badc579 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -313,6 +313,7 @@ int mutabilityOfType(bool isref, Type t)
*/
enum DotExpFlag
{
+ none = 0,
gag = 1, // don't report "not a property" error and just return null
noDeref = 2, // the use of the expression will not attempt a dereference
noAliasThis = 4, // don't do 'alias this' resolution
@@ -2044,9 +2045,11 @@ extern (C++) abstract class Type : ASTNode
t = t.addMod(this.mod);
return t;
}
- if (auto fd = s.isFuncDeclaration())
+ Dsymbol callable = s.isFuncDeclaration();
+ callable = callable ? callable : s.isTemplateDeclaration();
+ if (callable)
{
- fd = resolveFuncCall(Loc.initial, null, fd, null, this, ArgumentList(), FuncResolveFlag.quiet);
+ auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet);
if (!fd || fd.errors || !fd.functionSemantic())
return Type.terror;
@@ -2065,24 +2068,17 @@ extern (C++) abstract class Type : ASTNode
{
return ed.type;
}
- if (auto td = s.isTemplateDeclaration())
- {
- assert(td._scope);
- auto fd = resolveFuncCall(Loc.initial, null, td, null, this, ArgumentList(), FuncResolveFlag.quiet);
- if (!fd || fd.errors || !fd.functionSemantic())
- return Type.terror;
-
- auto t = fd.type.nextOf();
- if (!t)
- return Type.terror;
- t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod);
- return t;
- }
//printf("%s\n", s.kind());
return null;
}
+ /**
+ * Check whether this type has endless `alias this` recursion.
+ * Returns:
+ * `true` if this type has an `alias this` that can be implicitly
+ * converted back to this type itself.
+ */
extern (D) final bool checkAliasThisRec()
{
Type tb = toBasetype();
@@ -2645,6 +2641,8 @@ extern (C++) abstract class Type : ASTNode
if (t.isimaginary() || t.iscomplex())
{
+ if (sc.flags & SCOPE.Cfile)
+ return true; // complex/imaginary not deprecated in C code
Type rt;
switch (t.ty)
{
@@ -4270,7 +4268,7 @@ extern (C++) final class TypeFunction : TypeNext
super(Tfunction, treturn);
//if (!treturn) *(char*)0=0;
// assert(treturn);
- assert(VarArg.none <= pl.varargs && pl.varargs <= VarArg.typesafe);
+ assert(VarArg.none <= pl.varargs && pl.varargs <= VarArg.max);
this.parameterList = pl;
this.linkage = linkage;
@@ -6513,6 +6511,7 @@ extern (C++) final class TypeTag : Type
{
Loc loc; /// location of declaration
TOK tok; /// TOK.struct_, TOK.union_, TOK.enum_
+ structalign_t packalign; /// alignment of struct/union fields
Identifier id; /// tag name identifier
Type base; /// base type for enums otherwise null
Dsymbols* members; /// members of struct, null if none
@@ -6522,13 +6521,14 @@ extern (C++) final class TypeTag : Type
/// struct S { int a; } s1, *s2;
MOD mod; /// modifiers to apply after type is resolved (only MODFlags.const_ at the moment)
- extern (D) this(const ref Loc loc, TOK tok, Identifier id, Type base, Dsymbols* members)
+ extern (D) this(const ref Loc loc, TOK tok, Identifier id, structalign_t packalign, Type base, Dsymbols* members)
{
//printf("TypeTag ctor %s %p\n", id ? id.toChars() : "null".ptr, this);
super(Ttag);
this.loc = loc;
this.tok = tok;
this.id = id;
+ this.packalign = packalign;
this.base = base;
this.members = members;
this.mod = 0;
@@ -7252,7 +7252,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
s ~= "pure ";
if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
s ~= "@safe ";
- if (!f.isNogc && sc.func.setGC())
+ if (!f.isNogc && sc.func.setGC(arg.loc, null))
s ~= "nogc ";
if (s)
{
@@ -7579,3 +7579,113 @@ TypeVector toBooleanVector(TypeVector tv)
return new TypeVector(new TypeSArray(telem, tsa.dim));
}
+
+/*************************************************
+ * Dispatch to function based on static type of Type.
+ */
+mixin template VisitType(Result)
+{
+ Result VisitType(Type t)
+ {
+ final switch (t.ty)
+ {
+ case TY.Tvoid:
+ case TY.Tint8:
+ case TY.Tuns8:
+ case TY.Tint16:
+ case TY.Tuns16:
+ case TY.Tint32:
+ case TY.Tuns32:
+ case TY.Tint64:
+ case TY.Tuns64:
+ case TY.Tfloat32:
+ case TY.Tfloat64:
+ case TY.Tfloat80:
+ case TY.Timaginary32:
+ case TY.Timaginary64:
+ case TY.Timaginary80:
+ case TY.Tcomplex32:
+ case TY.Tcomplex64:
+ case TY.Tcomplex80:
+ case TY.Tbool:
+ case TY.Tchar:
+ case TY.Twchar:
+ case TY.Tdchar:
+ case TY.Tint128:
+ case TY.Tuns128: mixin(visitTYCase("Basic"));
+ case TY.Tarray: mixin(visitTYCase("DArray"));
+ case TY.Tsarray: mixin(visitTYCase("SArray"));
+ case TY.Taarray: mixin(visitTYCase("AArray"));
+ case TY.Tpointer: mixin(visitTYCase("Pointer"));
+ case TY.Treference: mixin(visitTYCase("Reference"));
+ case TY.Tfunction: mixin(visitTYCase("Function"));
+ case TY.Tident: mixin(visitTYCase("Identifier"));
+ case TY.Tclass: mixin(visitTYCase("Class"));
+ case TY.Tstruct: mixin(visitTYCase("Struct"));
+ case TY.Tenum: mixin(visitTYCase("Enum"));
+ case TY.Tdelegate: mixin(visitTYCase("Delegate"));
+ case TY.Terror: mixin(visitTYCase("Error"));
+ case TY.Tinstance: mixin(visitTYCase("Instance"));
+ case TY.Ttypeof: mixin(visitTYCase("Typeof"));
+ case TY.Ttuple: mixin(visitTYCase("Tuple"));
+ case TY.Tslice: mixin(visitTYCase("Slice"));
+ case TY.Treturn: mixin(visitTYCase("Return"));
+ case TY.Tnull: mixin(visitTYCase("Null"));
+ case TY.Tvector: mixin(visitTYCase("Vector"));
+ case TY.Ttraits: mixin(visitTYCase("Traits"));
+ case TY.Tmixin: mixin(visitTYCase("Mixin"));
+ case TY.Tnoreturn: mixin(visitTYCase("Noreturn"));
+ case TY.Ttag: mixin(visitTYCase("Tag"));
+ case TY.Tnone: assert(0);
+ }
+ }
+}
+
+/****************************************
+ * CTFE-only helper function for VisitInitializer.
+ * Params:
+ * handler = string for the name of the visit handler
+ * Returns: boilerplate code for a case
+ */
+pure string visitTYCase(string handler)
+{
+ if (__ctfe)
+ {
+ return
+ "
+ enum isVoid = is(Result == void);
+ auto tx = t.isType"~handler~"();
+ static if (__traits(compiles, visit"~handler~"(tx)))
+ {
+ static if (isVoid)
+ {
+ visit"~handler~"(tx);
+ return;
+ }
+ else
+ {
+ if (Result r = visit"~handler~"(tx))
+ return r;
+ return Result.init;
+ }
+ }
+ else static if (__traits(compiles, visitDefaultCase(t)))
+ {
+ static if (isVoid)
+ {
+ visitDefaultCase(tx);
+ return;
+ }
+ else
+ {
+ if (Result r = visitDefaultCase(t))
+ return r;
+ return Result.init;
+ }
+ }
+ else
+ static assert(0, "~handler~");
+ ";
+ }
+ assert(0);
+}
diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d
index 201f168..a0f3e60 100644
--- a/gcc/d/dmd/nogc.d
+++ b/gcc/d/dmd/nogc.d
@@ -83,7 +83,7 @@ public:
err = true;
return true;
}
- if (f.setGC())
+ if (f.setGC(e.loc, format))
{
e.error(format, f.kind(), f.toPrettyChars());
err = true;
@@ -135,7 +135,7 @@ public:
override void visit(NewExp e)
{
- if (e.member && !e.member.isNogc() && f.setGC())
+ if (e.member && !e.member.isNogc() && f.setGC(e.loc, null))
{
// @nogc-ness is already checked in NewExp::semantic
return;
@@ -195,7 +195,7 @@ public:
err = true;
return;
}
- if (f.setGC())
+ if (f.setGC(e.loc, null))
{
err = true;
return;
diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d
index 9cff76b..89728b6 100644
--- a/gcc/d/dmd/ob.d
+++ b/gcc/d/dmd/ob.d
@@ -844,7 +844,7 @@ void toObNodes(ref ObNodes obnodes, Statement s)
case STMT.Conditional:
case STMT.While:
case STMT.Forwarding:
- case STMT.Compile:
+ case STMT.Mixin:
case STMT.Peel:
case STMT.Synchronized:
debug printf("s: %s\n", s.toChars());
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index 3c80e5e..d7b90d7 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -293,6 +293,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
{
ie = (*ae.arguments)[0].isIntervalExp();
}
+ Type att = null; // first cyclic `alias this` type
while (true)
{
if (ae.e1.op == EXP.error)
@@ -354,7 +355,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
return result;
}
// Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
+ if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
{
/* Rewrite op(a[arguments]) as:
* op(a.aliasthis[arguments])
@@ -370,13 +371,18 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
}
e.e1 = e.e1.expressionSemantic(sc);
e.e1 = resolveProperties(sc, e.e1);
- if (e.e1.op == EXP.error)
- {
- return e.e1;
- }
- AggregateDeclaration ad = isAggregate(e.e1.type);
- if (ad)
+ Type att = null; // first cyclic `alias this` type
+ while (1)
{
+ if (e.e1.op == EXP.error)
+ {
+ return e.e1;
+ }
+
+ AggregateDeclaration ad = isAggregate(e.e1.type);
+ if (!ad)
+ break;
+
Dsymbol fd = null;
/* Rewrite as:
* e1.opUnary!(op)()
@@ -404,18 +410,18 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
}
}
// Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type))
+ if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type))
{
/* Rewrite op(e1) as:
* op(e1.aliasthis)
*/
//printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars());
- Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident);
- UnaExp ue = cast(UnaExp)e.copy();
- ue.e1 = e1;
- result = ue.trySemantic(sc);
- return result;
+ e.e1 = resolveAliasThis(sc, e.e1, true);
+ if (e.e1)
+ continue;
+ break;
}
+ break;
}
return result;
}
@@ -433,6 +439,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
ie = (*ae.arguments)[0].isIntervalExp();
}
Expression result;
+ Type att = null; // first cyclic `alias this` type
while (true)
{
if (ae.e1.op == EXP.error)
@@ -526,7 +533,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
return result;
}
// Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
+ if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
{
//printf("att arr e1 = %s\n", this.e1.type.toChars());
/* Rewrite op(a[arguments]) as:
@@ -547,7 +554,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
* This is mostly the same as UnaryExp::op_overload(), but has
* a different rewrite.
*/
- Expression visitCast(CastExp e)
+ Expression visitCast(CastExp e, Type att = null)
{
//printf("CastExp::op_overload() (%s)\n", e.toChars());
Expression result;
@@ -578,7 +585,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
return result;
}
// Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type))
+ if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type))
{
/* Rewrite op(e1) as:
* op(e1.aliasthis)
@@ -587,7 +594,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
{
result = e.copy();
(cast(UnaExp)result).e1 = e1;
- result = result.op_overload(sc);
+ result = visitCast(result.isCastExp(), att);
return result;
}
}
@@ -997,7 +1004,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
return null;
import dmd.clone : needOpEquals;
- if (!global.params.fieldwise && !needOpEquals(sd))
+ if (global.params.fieldwise != FeatureState.enabled && !needOpEquals(sd))
{
// Use bitwise equality.
auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
@@ -1016,12 +1023,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
* also compare the parent class's equality. Otherwise, compares
* the identity of parent context through void*.
*/
- if (e.att1 && t1.equivalent(e.att1)) return null;
- if (e.att2 && t2.equivalent(e.att2)) return null;
-
e = e.copy().isEqualExp();
- if (!e.att1) e.att1 = t1;
- if (!e.att2) e.att2 = t2;
e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof);
e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof);
@@ -1029,18 +1031,6 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
sc2.flags |= SCOPE.noaccesscheck;
Expression r = e.expressionSemantic(sc2);
sc2.pop();
-
- /* https://issues.dlang.org/show_bug.cgi?id=15292
- * if the rewrite result is same with the original,
- * the equality is unresolvable because it has recursive definition.
- */
- if (r.op == e.op &&
- r.isEqualExp().e1.type.toBasetype() == t1)
- {
- e.error("cannot compare `%s` because its auto generated member-wise equality has recursive definition",
- t1.toChars());
- return ErrorExp.get();
- }
return r;
}
@@ -1071,8 +1061,6 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
auto ex1 = (*tup1.exps)[i];
auto ex2 = (*tup2.exps)[i];
auto eeq = new EqualExp(e.op, e.loc, ex1, ex2);
- eeq.att1 = e.att1;
- eeq.att2 = e.att2;
if (!result)
result = eeq;
@@ -1114,6 +1102,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
{
ie = (*ae.arguments)[0].isIntervalExp();
}
+ Type att = null; // first cyclic `alias this` type
while (true)
{
if (ae.e1.op == EXP.error)
@@ -1185,7 +1174,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
return result;
}
// Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
+ if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
{
/* Rewrite (a[arguments] op= e2) as:
* a.aliasthis[arguments] op= e2
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index b5d32b2..61c385f 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -371,7 +371,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
{
if (e.stageflags & stageOptimize)
return;
- int old = e.stageflags;
+ const old = e.stageflags;
e.stageflags |= stageOptimize;
if (e.elements)
{
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 36a76f5..68a2506 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -15,14 +15,13 @@ module dmd.parse;
import core.stdc.stdio;
import core.stdc.string;
+
import dmd.astenums;
import dmd.errorsink;
-import dmd.globals;
import dmd.id;
import dmd.identifier;
import dmd.lexer;
import dmd.location;
-import dmd.errors;
import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.root.rmem;
@@ -30,6 +29,8 @@ import dmd.root.rootobject;
import dmd.root.string;
import dmd.tokens;
+alias CompileEnv = dmd.lexer.CompileEnv;
+
/***********************************************************
*/
class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
@@ -45,49 +46,38 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
Loc endloc; // set to location of last right curly
int inBrackets; // inside [] of array index or slice
Loc lookingForElse; // location of lonely if looking for an else
+ bool doUnittests; // parse unittest blocks
}
+ bool transitionIn = false; /// `-transition=in` is active, `in` parameters are listed
+
/*********************
* Use this constructor for string mixins.
* Input:
- * loc location in source file of mixin
+ * loc = location in source file of mixin
*/
extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment,
- ErrorSink errorSink) scope
+ ErrorSink errorSink, const CompileEnv* compileEnv, const bool doUnittests) scope
{
- super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false,
- errorSink,
- global.vendor, global.versionNumber());
-
- //printf("Parser::Parser()\n");
+ //printf("Parser::Parser()1 %d\n", doUnittests);
+ this(_module, input, doDocComment, errorSink, compileEnv, doUnittests);
scanloc = loc;
-
- if (!writeMixin(input, scanloc) && loc.filename)
- {
- /* Create a pseudo-filename for the mixin string, as it may not even exist
- * in the source file.
- */
- auto len = strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1;
- char* filename = cast(char*)mem.xmalloc(len);
- snprintf(filename, len, "%s-mixin-%d", loc.filename, cast(int)loc.linnum);
- scanloc.filename = filename;
- }
-
- mod = _module;
- linkage = LINK.d;
- //nextToken(); // start up the scanner
}
- extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink) scope
+ /**************************************************
+ * Main Parser constructor.
+ */
+ extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink,
+ const CompileEnv* compileEnv, const bool doUnittests) scope
{
super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false,
errorSink,
- global.vendor, global.versionNumber());
+ compileEnv);
- //printf("Parser::Parser()\n");
- mod = _module;
- linkage = LINK.d;
- //nextToken(); // start up the scanner
+ //printf("Parser::Parser()2 %d\n", doUnittests);
+ this.mod = _module;
+ this.linkage = LINK.d;
+ this.doUnittests = doUnittests;
}
/++
@@ -335,6 +325,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
linkage = linksave;
Loc startloc;
+ Loc scdLoc;
switch (token.value)
{
@@ -381,7 +372,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
auto exps = parseArguments();
check(TOK.semicolon);
- s = new AST.CompileDeclaration(loc, exps);
+ s = new AST.MixinDeclaration(loc, exps);
break;
}
case TOK.template_:
@@ -497,7 +488,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* template instantiations in these unittests as candidates for
* further codegen culling.
*/
- if (mod.isRoot() && (global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput))
+ // The isRoot check is here because it can change after parsing begins (see dmodule.d)
+ if (doUnittests && mod.isRoot())
{
linkage = LINK.d; // unittests have D linkage
s = parseUnitTest(pAttrs);
@@ -696,6 +688,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
Lstc:
pAttrs.storageClass = appendStorageClass(pAttrs.storageClass, stc);
+ scdLoc = token.loc;
nextToken();
Lautodecl:
@@ -748,7 +741,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
auto stc2 = getStorageClass!AST(pAttrs);
if (stc2 != STC.undefined_)
{
- s = new AST.StorageClassDeclaration(stc2, a);
+ s = new AST.StorageClassDeclaration(scdLoc, stc2, a);
}
if (pAttrs.udas)
{
@@ -1219,19 +1212,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return orig | added;
}
- const Redundant = (STC.const_ | STC.scope_ |
- (global.params.previewIn ? STC.ref_ : 0));
+ const Redundant = (STC.const_ | STC.scope_ | STC.ref_);
orig |= added;
if ((orig & STC.in_) && (added & Redundant))
{
if (added & STC.const_)
error("attribute `const` is redundant with previously-applied `in`");
- else if (global.params.previewIn)
+ else if (compileEnv.previewIn)
{
error("attribute `%s` is redundant with previously-applied `in`",
(orig & STC.scope_) ? "scope".ptr : "ref".ptr);
}
+ else if (added & STC.ref_)
+ deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead");
else
error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
return orig;
@@ -1241,13 +1235,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
if (orig & STC.const_)
error("attribute `in` cannot be added after `const`: remove `const`");
- else if (global.params.previewIn)
+ else if (compileEnv.previewIn)
{
// Windows `printf` does not support `%1$s`
const(char*) stc_str = (orig & STC.scope_) ? "scope".ptr : "ref".ptr;
error(token.loc, "attribute `in` cannot be added after `%s`: remove `%s`",
stc_str, stc_str);
}
+ else if (orig & STC.ref_)
+ deprecation("using `ref in` is deprecated, use `-preview=in` and `in` instead");
else
error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
return orig;
@@ -1302,12 +1298,38 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return 0;
}
+ AST.Expression templateArgToExp(RootObject o, const ref Loc loc)
+ {
+ switch (o.dyncast)
+ {
+ case DYNCAST.expression:
+ return cast(AST.Expression) o;
+ case DYNCAST.type:
+ return new AST.TypeExp(loc, cast(AST.Type)o);
+ default:
+ assert(0);
+ }
+ }
+
if (token.value == TOK.leftParenthesis)
{
// Multi-UDAs ( `@( ArgumentList )`) form, concatenate with existing
if (peekNext() == TOK.rightParenthesis)
error("empty attribute list is not allowed");
- udas = AST.UserAttributeDeclaration.concat(udas, parseArguments());
+
+ if (udas is null)
+ udas = new AST.Expressions();
+ auto args = parseTemplateArgumentList();
+ foreach (arg; *args)
+ udas.push(templateArgToExp(arg, token.loc));
+ return 0;
+ }
+
+ if (auto o = parseTemplateSingleArgument())
+ {
+ if (udas is null)
+ udas = new AST.Expressions();
+ udas.push(templateArgToExp(o, token.loc));
return 0;
}
@@ -1764,7 +1786,16 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
else
{
// ident!template_argument
- tiargs = parseTemplateSingleArgument();
+ RootObject o = parseTemplateSingleArgument();
+ if (!o)
+ {
+ error("template argument expected following `!`");
+ }
+ else
+ {
+ tiargs = new AST.Objects();
+ tiargs.push(o);
+ }
}
if (token.value == TOK.not)
{
@@ -1830,11 +1861,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* foo!arg
* Input:
* current token is the arg
+ * Returns: An AST.Type, AST.Expression, or `null` on error
*/
- private AST.Objects* parseTemplateSingleArgument()
+ private RootObject parseTemplateSingleArgument()
{
//printf("parseTemplateSingleArgument()\n");
- auto tiargs = new AST.Objects();
AST.Type ta;
switch (token.value)
{
@@ -1942,9 +1973,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
ta = AST.Type.tdchar;
goto LabelX;
LabelX:
- tiargs.push(ta);
nextToken();
- break;
+ return ta;
case TOK.int32Literal:
case TOK.uns32Literal:
@@ -1974,15 +2004,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.this_:
{
// Template argument is an expression
- AST.Expression ea = parsePrimaryExp();
- tiargs.push(ea);
- break;
+ return parsePrimaryExp();
}
default:
- error("template argument expected following `!`");
- break;
+ return null;
}
- return tiargs;
}
/**********************************
@@ -2694,7 +2720,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
/** Extract unittest body as a string. Must be done eagerly since memory
will be released by the lexer before doc gen. */
char* docline = null;
- if (global.params.ddoc.doOutput && endPtr > begPtr)
+ if (compileEnv.ddocOutput && endPtr > begPtr)
{
/* Remove trailing whitespaces */
for (const(char)* p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
@@ -2849,8 +2875,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
// Don't call nextToken again.
}
case TOK.in_:
- if (global.params.vin)
- message(scanloc, "Usage of 'in' on parameter");
+ if (transitionIn)
+ eSink.message(scanloc, "Usage of 'in' on parameter");
stc = STC.in_;
goto L2;
@@ -4610,8 +4636,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.Dsymbol s;
if (width)
{
- if (!global.params.bitfields)
- error("use -preview=bitfields for bitfield support");
if (_init)
error("initializer not allowed for bit-field declaration");
if (storage_class)
@@ -5144,7 +5168,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.goesTo:
if (requireDo)
error("missing `do { ... }` after `in` or `out`");
- if (!global.params.shortenedMethods)
+ if (!compileEnv.shortenedMethods)
error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`");
const returnloc = token.loc;
nextToken();
@@ -5156,7 +5180,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.leftCurly:
if (requireDo)
error("missing `do { ... }` after `in` or `out`");
- f.fbody = parseStatement(ParseStatementFlags.semi);
+ f.fbody = parseStatement(0);
f.endloc = endloc;
break;
@@ -5801,7 +5825,11 @@ LagainStc:
if (token.value != TOK.semicolon && peek(&token).value == TOK.semicolon)
error("found `%s` when expecting `;` following statement", token.toChars());
else
- check(TOK.semicolon, "statement");
+ {
+ if (token.value != TOK.semicolon)
+ error("found `%s` when expecting `;` following statement `%s` on line %s", token.toChars(), exp.toChars(), exp.loc.toChars());
+ nextToken();
+ }
}
s = new AST.ExpStatement(loc, exp);
break;
@@ -5959,7 +5987,7 @@ LagainStc:
if (e.op == EXP.mixin_)
{
AST.MixinExp cpe = cast(AST.MixinExp)e;
- s = new AST.CompileStatement(loc, cpe.exps);
+ s = new AST.MixinStatement(loc, cpe.exps);
}
else
{
@@ -5992,7 +6020,7 @@ LagainStc:
auto statements = new AST.Statements();
while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
{
- statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+ statements.push(parseStatement(ParseStatementFlags.curlyScope));
}
if (endPtr)
*endPtr = token.ptr;
@@ -6025,10 +6053,7 @@ LagainStc:
case TOK.semicolon:
if (!(flags & ParseStatementFlags.semiOk))
{
- if (flags & ParseStatementFlags.semi)
- deprecation("use `{ }` for an empty statement, not `;`");
- else
- error("use `{ }` for an empty statement, not `;`");
+ error("use `{ }` for an empty statement, not `;`");
}
nextToken();
s = new AST.ExpStatement(loc, cast(AST.Expression)null);
@@ -6245,7 +6270,7 @@ LagainStc:
_body = null;
}
else
- _body = parseStatement(ParseStatementFlags.semi);
+ _body = parseStatement(0);
s = new AST.PragmaStatement(loc, ident, args, _body);
break;
}
@@ -6298,7 +6323,7 @@ LagainStc:
auto statements = new AST.Statements();
while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
{
- auto cur = parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
+ auto cur = parseStatement(ParseStatementFlags.curlyScope);
statements.push(cur);
// https://issues.dlang.org/show_bug.cgi?id=21739
@@ -6313,7 +6338,7 @@ LagainStc:
}
else
{
- s = parseStatement(ParseStatementFlags.semi);
+ s = parseStatement(0);
}
s = new AST.ScopeStatement(loc, s, token.loc);
@@ -6342,12 +6367,12 @@ LagainStc:
auto statements = new AST.Statements();
while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
{
- statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+ statements.push(parseStatement(ParseStatementFlags.curlyScope));
}
s = new AST.CompoundStatement(loc, statements);
}
else
- s = parseStatement(ParseStatementFlags.semi);
+ s = parseStatement(0);
s = new AST.ScopeStatement(loc, s, token.loc);
s = new AST.DefaultStatement(loc, s);
break;
@@ -6891,6 +6916,15 @@ LagainStc:
/********************
* Parse inline assembler block.
+ * Enters with token on the `asm`.
+ * https://dlang.org/spec/iasm.html
+ *
+ * AsmStatement:
+ * asm FunctionAttributes(opt) { AsmInstructionListopt }
+ * AsmInstructionList:
+ * AsmInstruction ;
+ * AsmInstruction ; AsmInstruction
+ *
* Returns:
* inline assembler block as a Statement
*/
@@ -6905,7 +6939,7 @@ LagainStc:
Loc labelloc;
nextToken();
- StorageClass stc = parsePostfix(STC.undefined_, null);
+ StorageClass stc = parsePostfix(STC.undefined_, null); // optional FunctionAttributes
if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild))
error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks");
@@ -9181,7 +9215,7 @@ LagainStc:
void checkRequiredParens()
{
if (e.op == EXP.question && !e.parens)
- dmd.errors.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
+ eSink.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
e.toChars(), Token.toChars(token.value));
}
@@ -9498,7 +9532,6 @@ immutable PREC[EXP.max + 1] precedence =
EXP.error : PREC.expr,
EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
- EXP.typeof_ : PREC.primary,
EXP.mixin_ : PREC.primary,
EXP.import_ : PREC.primary,
@@ -9538,7 +9571,6 @@ immutable PREC[EXP.max + 1] precedence =
EXP.remove : PREC.primary,
EXP.tuple : PREC.primary,
EXP.traits : PREC.primary,
- EXP.default_ : PREC.primary,
EXP.overloadSet : PREC.primary,
EXP.void_ : PREC.primary,
EXP.vectorArray : PREC.primary,
@@ -9637,7 +9669,6 @@ immutable PREC[EXP.max + 1] precedence =
enum ParseStatementFlags : int
{
- semi = 1, // empty ';' statements are allowed, but deprecated
scope_ = 2, // start a new scope
curly = 4, // { } statement is required
curlyScope = 8, // { } starts a new scope
@@ -9708,52 +9739,3 @@ private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
}
return stc;
}
-
-/**************************************
- * dump mixin expansion to file for better debugging
- */
-private bool writeMixin(const(char)[] s, ref Loc loc)
-{
- if (!global.params.mixinOut.doOutput)
- return false;
-
- OutBuffer* ob = global.params.mixinOut.buffer;
-
- ob.writestring("// expansion at ");
- ob.writestring(loc.toChars());
- ob.writenl();
-
- global.params.mixinOut.bufferLines++;
-
- loc = Loc(global.params.mixinOut.name.ptr, global.params.mixinOut.bufferLines + 1, loc.charnum);
-
- // write by line to create consistent line endings
- size_t lastpos = 0;
- for (size_t i = 0; i < s.length; ++i)
- {
- // detect LF and CRLF
- const c = s[i];
- if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n'))
- {
- ob.writestring(s[lastpos .. i]);
- ob.writenl();
- global.params.mixinOut.bufferLines++;
- if (c == '\r')
- ++i;
- lastpos = i + 1;
- }
- }
-
- if(lastpos < s.length)
- ob.writestring(s[lastpos .. $]);
-
- if (s.length == 0 || s[$-1] != '\n')
- {
- ob.writenl(); // ensure empty line after expansion
- global.params.mixinOut.bufferLines++;
- }
- ob.writenl();
- global.params.mixinOut.bufferLines++;
-
- return true;
-}
diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d
index 387b28c..a4a9434 100644
--- a/gcc/d/dmd/parsetimevisitor.d
+++ b/gcc/d/dmd/parsetimevisitor.d
@@ -66,7 +66,7 @@ public:
void visit(AST.SharedStaticDtorDeclaration s) { visit(cast(AST.StaticDtorDeclaration)s); }
// AttribDeclarations
- void visit(AST.CompileDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.MixinDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
void visit(AST.UserAttributeDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
void visit(AST.LinkDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
void visit(AST.AnonDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
@@ -99,7 +99,7 @@ public:
void visit(AST.ReturnStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.LabelStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.StaticAssertStatement s) { visit(cast(AST.Statement)s); }
- void visit(AST.CompileStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.MixinStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.WhileStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.ForStatement s) { visit(cast(AST.Statement)s); }
void visit(AST.DoStatement s) { visit(cast(AST.Statement)s); }
diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d
index d85105d..8c01095 100644
--- a/gcc/d/dmd/printast.d
+++ b/gcc/d/dmd/printast.d
@@ -219,6 +219,25 @@ extern (C++) final class PrintASTVisitor : Visitor
printAST(e.value, indent + 2);
}
+ override void visit(ArrayLiteralExp e)
+ {
+ visit(cast(Expression)e);
+ printIndent(indent + 2);
+ printf(".basis : %s\n", e.basis ? e.basis.toChars() : "");
+ if (e.elements)
+ {
+ printIndent(indent + 2);
+ printf("[");
+ foreach (i, element; (*e.elements)[])
+ {
+ if (i)
+ printf(", ");
+ printf("%s", element.toChars());
+ }
+ printf("]\n");
+ }
+ }
+
static void printIndent(int indent)
{
foreach (i; 0 .. indent)
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index a912e76..33c2f02 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -467,7 +467,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
/* Generate identifier for un-named parameter,
* because we need it later on.
*/
- fparam.ident = id = Identifier.generateId("_param_", i);
+ fparam.ident = id = Identifier.generateId("__param_", i);
stc |= STC.temp;
}
Type vtype = fparam.type;
diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d
index 60a74cc..3f3e7e6 100644
--- a/gcc/d/dmd/sideeffect.d
+++ b/gcc/d/dmd/sideeffect.d
@@ -185,6 +185,7 @@ private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false)
case EXP.delete_:
case EXP.new_:
case EXP.newAnonymousClass:
+ case EXP.loweredAssignExp:
return true;
case EXP.call:
{
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index 90728fb..3ccf228 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -373,6 +373,7 @@ extern (C++) abstract class Statement : ASTNode
* the downcast statement if it can be downcasted, otherwise `null`
*/
inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; }
+ inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; }
inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; }
inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; }
inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; }
@@ -388,7 +389,7 @@ extern (C++) abstract class Statement : ASTNode
inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; }
inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; }
inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; }
- inout(CompileStatement) isCompileStatement() { return stmt == STMT.Compile ? cast(typeof(return))this : null; }
+ inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; }
inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; }
inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; }
inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; }
@@ -406,6 +407,15 @@ extern (C++) abstract class Statement : ASTNode
inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
+ inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; }
+ inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; }
+ inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; }
+ inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; }
+ inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; }
+ inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; }
+ inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; }
+ inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; }
+ inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; }
}
/***********************************************************
@@ -518,7 +528,8 @@ extern (C++) final class DtorExpStatement : ExpStatement
/***********************************************************
* https://dlang.org/spec/statement.html#mixin-statement
*/
-extern (C++) final class CompileStatement : Statement
+// Note: was called CompileStatement
+extern (C++) final class MixinStatement : Statement
{
Expressions* exps;
@@ -531,13 +542,13 @@ extern (C++) final class CompileStatement : Statement
extern (D) this(const ref Loc loc, Expressions* exps)
{
- super(loc, STMT.Compile);
+ super(loc, STMT.Mixin);
this.exps = exps;
}
- override CompileStatement syntaxCopy()
+ override MixinStatement syntaxCopy()
{
- return new CompileStatement(loc, Expression.arraySyntaxCopy(exps));
+ return new MixinStatement(loc, Expression.arraySyntaxCopy(exps));
}
override void accept(Visitor v)
@@ -2084,3 +2095,107 @@ extern (C++) final class ImportStatement : Statement
v.visit(this);
}
}
+
+
+mixin template VisitStatement(Result)
+{
+ Result VisitStatement(Statement s)
+ {
+ final switch (s.stmt)
+ {
+ case STMT.Error: mixin(visitStmtCase("Error"));
+ case STMT.Scope: mixin(visitStmtCase("Scope"));
+ case STMT.Exp: mixin(visitStmtCase("Exp"));
+ case STMT.Compound: mixin(visitStmtCase("Compound"));
+ case STMT.Return: mixin(visitStmtCase("Return"));
+ case STMT.If: mixin(visitStmtCase("If"));
+ case STMT.Conditional: mixin(visitStmtCase("Conditional"));
+ case STMT.StaticForeach: mixin(visitStmtCase("StaticForeach"));
+ case STMT.Case: mixin(visitStmtCase("Case"));
+ case STMT.Default: mixin(visitStmtCase("Default"));
+ case STMT.Label: mixin(visitStmtCase("Label"));
+ case STMT.Goto: mixin(visitStmtCase("Goto"));
+ case STMT.GotoDefault: mixin(visitStmtCase("GotoDefault"));
+ case STMT.GotoCase: mixin(visitStmtCase("GotoCase"));
+ case STMT.Break: mixin(visitStmtCase("Break"));
+ case STMT.DtorExp: mixin(visitStmtCase("DtorExp"));
+ case STMT.Mixin: mixin(visitStmtCase("Mixin"));
+ case STMT.Forwarding: mixin(visitStmtCase("Forwarding"));
+ case STMT.Do: mixin(visitStmtCase("Do"));
+ case STMT.While: mixin(visitStmtCase("While"));
+ case STMT.For: mixin(visitStmtCase("For"));
+ case STMT.Foreach: mixin(visitStmtCase("Foreach"));
+ case STMT.Switch: mixin(visitStmtCase("Switch"));
+ case STMT.Continue: mixin(visitStmtCase("Continue"));
+ case STMT.With: mixin(visitStmtCase("With"));
+ case STMT.TryCatch: mixin(visitStmtCase("TryCatch"));
+ case STMT.Throw: mixin(visitStmtCase("Throw"));
+ case STMT.Debug: mixin(visitStmtCase("Debug"));
+ case STMT.TryFinally: mixin(visitStmtCase("TryFinally"));
+ case STMT.ScopeGuard: mixin(visitStmtCase("ScopeGuard"));
+ case STMT.SwitchError: mixin(visitStmtCase("SwitchError"));
+ case STMT.UnrolledLoop: mixin(visitStmtCase("UnrolledLoop"));
+ case STMT.ForeachRange: mixin(visitStmtCase("ForeachRange"));
+ case STMT.CompoundDeclaration: mixin(visitStmtCase("CompoundDeclaration"));
+ case STMT.Peel: mixin(visitStmtCase("Peel"));
+ case STMT.CompoundAsm: mixin(visitStmtCase("CompoundAsm"));
+ case STMT.Pragma: mixin(visitStmtCase("Pragma"));
+ case STMT.StaticAssert: mixin(visitStmtCase("StaticAssert"));
+ case STMT.CaseRange: mixin(visitStmtCase("CaseRange"));
+ case STMT.Synchronized: mixin(visitStmtCase("Synchronized"));
+ case STMT.Asm: mixin(visitStmtCase("Asm"));
+ case STMT.InlineAsm: mixin(visitStmtCase("InlineAsm"));
+ case STMT.GccAsm: mixin(visitStmtCase("GccAsm"));
+ case STMT.Import: mixin(visitStmtCase("Import"));
+ }
+ }
+}
+
+/****************************************
+ * CTFE-only helper function for VisitInitializer.
+ * Params:
+ * handler = string for the name of the visit handler
+ * Returns: boilerplate code for a case
+ */
+pure string visitStmtCase(string handler)
+{
+ if (__ctfe)
+ {
+ return
+ "
+ enum isVoid = is(Result == void);
+ auto sx = s.is"~handler~"Statement();
+ static if (__traits(compiles, visit"~handler~"(sx)))
+ {
+ static if (isVoid)
+ {
+ visit"~handler~"(sx);
+ return;
+ }
+ else
+ {
+ if (Result r = visit"~handler~"(sx))
+ return r;
+ return Result.init;
+ }
+ }
+ else static if (__traits(compiles, visitDefaultCase(s)))
+ {
+ static if (isVoid)
+ {
+ visitDefaultCase(sx);
+ return;
+ }
+ else
+ {
+ if (Result r = visitDefaultCase(s))
+ return r;
+ return Result.init;
+ }
+ }
+ else
+ static assert(0, "~handler~");
+ ";
+ }
+ assert(0);
+}
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index 6d1f85b3..b7403b5 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -65,7 +65,7 @@ enum
STMTerror,
STMTpeel,
STMTexp, STMTdtorExp,
- STMTcompile,
+ STMTmixin,
STMTcompound, STMTcompoundDeclaration, STMTcompoundAsm,
STMTunrolledLoop,
STMTscope,
@@ -143,7 +143,7 @@ public:
GotoCaseStatement *isGotoCaseStatement() { return stmt == STMTgotoCase ? (GotoCaseStatement*)this : NULL; }
BreakStatement *isBreakStatement() { return stmt == STMTbreak ? (BreakStatement*)this : NULL; }
DtorExpStatement *isDtorExpStatement() { return stmt == STMTdtorExp ? (DtorExpStatement*)this : NULL; }
- CompileStatement *isCompileStatement() { return stmt == STMTcompile ? (CompileStatement*)this : NULL; }
+ MixinStatement *isMixinStatement() { return stmt == STMTmixin ? (MixinStatement*)this : NULL; }
ForwardingStatement *isForwardingStatement() { return stmt == STMTforwarding ? (ForwardingStatement*)this : NULL; }
DoStatement *isDoStatement() { return stmt == STMTdo ? (DoStatement*)this : NULL; }
ForStatement *isForStatement() { return stmt == STMTfor ? (ForStatement*)this : NULL; }
@@ -206,12 +206,12 @@ public:
void accept(Visitor *v) override { v->visit(this); }
};
-class CompileStatement final : public Statement
+class MixinStatement final : public Statement
{
public:
Expressions *exps;
- CompileStatement *syntaxCopy() override;
+ MixinStatement *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 694db28..f849ce1 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -145,43 +145,35 @@ extern(C++) Statement statementSemantic(Statement s, Scope* sc)
version (CallbackAPI)
Compiler.onStatementSemanticStart(s, sc);
- scope v = new StatementSemanticVisitor(sc);
- s.accept(v);
+ Statement result = statementSemanticVisit(s, sc);
version (CallbackAPI)
Compiler.onStatementSemanticDone(s, sc);
- return v.result;
+ return result;
}
-package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
+package (dmd)
+Statement statementSemanticVisit(Statement s, Scope* sc)
{
- alias visit = Visitor.visit;
-
Statement result;
- Scope* sc;
-
- this(Scope* sc) scope
- {
- this.sc = sc;
- }
- private void setError()
+ void setError()
{
result = new ErrorStatement();
}
- override void visit(Statement s)
+ void visitDefaultCase(Statement s)
{
result = s;
}
- override void visit(ErrorStatement s)
+ void visitError(ErrorStatement s)
{
result = s;
}
- override void visit(PeelStatement s)
+ void visitPeel(PeelStatement s)
{
/* "peel" off this wrapper, and don't run semantic()
* on the result.
@@ -189,7 +181,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = s.s;
}
- override void visit(ExpStatement s)
+ void visitExp(ExpStatement s)
{
/* https://dlang.org/spec/statement.html#expression-statement
*/
@@ -226,12 +218,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = s;
}
- override void visit(CompileStatement cs)
+ void visitDtorExp(DtorExpStatement s)
+ {
+ visitExp(s);
+ }
+
+ void visitMixin(MixinStatement cs)
{
/* https://dlang.org/spec/statement.html#mixin-statement
*/
- //printf("CompileStatement::semantic() %s\n", exp.toChars());
+ //printf("MixinStatement::semantic() %s\n", exp.toChars());
Statements* a = cs.flatten(sc);
if (!a)
return;
@@ -239,7 +236,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = s.statementSemantic(sc);
}
- override void visit(CompoundStatement cs)
+ void visitCompound(CompoundStatement cs)
{
//printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc);
version (none)
@@ -431,7 +428,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = cs;
}
- override void visit(UnrolledLoopStatement uls)
+ void visitUnrolledLoop(UnrolledLoopStatement uls)
{
//printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc);
Scope* scd = sc.push();
@@ -454,7 +451,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = serror ? serror : uls;
}
- override void visit(ScopeStatement ss)
+ void visitScope(ScopeStatement ss)
{
//printf("ScopeStatement::semantic(sc = %p)\n", sc);
if (!ss.statement)
@@ -501,7 +498,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ss;
}
- override void visit(ForwardingStatement ss)
+ void visitForwarding(ForwardingStatement ss)
{
assert(ss.sym);
for (Scope* csc = sc; !ss.sym.parent; csc = csc.enclosing)
@@ -517,7 +514,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ss.statement;
}
- override void visit(WhileStatement ws)
+ void visitWhile(WhileStatement ws)
{
/* Rewrite as a for(;condition;) loop
* https://dlang.org/spec/statement.html#while-statement
@@ -544,7 +541,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = s;
}
- override void visit(DoStatement ds)
+ void visitDo(DoStatement ds)
{
/* https://dlang.org/spec/statement.html#do-statement
*/
@@ -580,7 +577,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ds;
}
- override void visit(ForStatement fs)
+ void visitFor(ForStatement fs)
{
/* https://dlang.org/spec/statement.html#for-statement
*/
@@ -674,7 +671,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = fs;
}
- override void visit(ForeachStatement fs)
+ void visitForeach(ForeachStatement fs)
{
/* https://dlang.org/spec/statement.html#foreach-statement
*/
@@ -1349,7 +1346,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
auto exp = (*exps)[i];
version (none)
{
- printf("[%d] p = %s %s, exp = %s %s\n", i,
+ printf("[%lu] p = %s %s, exp = %s %s\n", i,
p.type ? p.type.toChars() : "?", p.ident.toChars(),
exp.type.toChars(), exp.toChars());
}
@@ -1360,7 +1357,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
if (ignoreRef) sc &= ~STC.ref_;
p.type = p.type.addStorageClass(sc).typeSemantic(loc, sc2);
if (!exp.implicitConvTo(p.type))
- return rangeError();
+ {
+ fs.error("cannot implicilty convert range element of type `%s` to variable `%s` of type `%s`",
+ exp.type.toChars(), p.toChars(), p.type.toChars());
+ return retError();
+ }
auto var = new VarDeclaration(loc, p.type, p.ident, new ExpInitializer(loc, exp));
var.storage_class |= STC.ctfe | STC.ref_ | STC.foreach_;
@@ -1395,312 +1396,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
}
- private static extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde,
- Type tab, Scope* sc2, Dsymbol sapply)
- {
- version (none)
- {
- if (global.params.useDIP1000 == FeatureState.enabled)
- {
- message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`");
- }
- (cast(FuncExp)flde).fd.tookAddressOf = 1;
- }
- else
- {
- if (global.params.useDIP1000 == FeatureState.enabled)
- ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope'
- }
- assert(tab.ty == Tstruct || tab.ty == Tclass);
- assert(sapply);
- /* Call:
- * aggr.apply(flde)
- */
- Expression ec;
- 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)
- return null;
- if (ec.type != Type.tint32)
- {
- fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars());
- return null;
- }
- return ec;
- }
-
- private static extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde,
- Type tab, Scope* sc2)
- {
- Expression ec;
- /* Call:
- * aggr(flde)
- */
- if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() &&
- !(cast(DelegateExp)fs.aggr).func.needThis())
- {
- // https://issues.dlang.org/show_bug.cgi?id=3560
- fs.aggr = (cast(DelegateExp)fs.aggr).e1;
- }
- ec = new CallExp(fs.loc, fs.aggr, flde);
- ec = ec.expressionSemantic(sc2);
- if (ec.op == EXP.error)
- return null;
- if (ec.type != Type.tint32)
- {
- fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars());
- return null;
- }
- return ec;
- }
-
- private static extern(D) Expression applyArray(ForeachStatement fs, Expression flde,
- Type tab, Scope* sc2, Type tn, Type tnv)
- {
- Expression ec;
- const dim = fs.parameters.length;
- const loc = fs.loc;
- /* Call:
- * _aApply(aggr, flde)
- */
- static immutable fntab =
- [
- "cc", "cw", "cd",
- "wc", "cc", "wd",
- "dc", "dw", "dd"
- ];
-
- const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1;
- char[BUFFER_LEN] fdname;
- int flag;
-
- switch (tn.ty)
- {
- case Tchar: flag = 0; break;
- case Twchar: flag = 3; break;
- case Tdchar: flag = 6; break;
- default:
- assert(0);
- }
- switch (tnv.ty)
- {
- case Tchar: flag += 0; break;
- case Twchar: flag += 1; break;
- case Tdchar: flag += 2; break;
- default:
- assert(0);
- }
- const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : "";
- int j = snprintf(fdname.ptr, BUFFER_LEN, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim);
- assert(j < BUFFER_LEN);
-
- FuncDeclaration fdapply;
- TypeDelegate dgty;
- auto params = new Parameters();
- params.push(new Parameter(STC.in_, tn.arrayOf(), null, null, null));
- auto dgparams = new Parameters();
- dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
- if (dim == 2)
- dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
- dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d));
- params.push(new Parameter(0, dgty, null, null, null));
- fdapply = FuncDeclaration.genCfunc(params, Type.tint32, fdname.ptr);
-
- if (tab.isTypeSArray())
- fs.aggr = fs.aggr.castTo(sc2, tn.arrayOf());
- // paint delegate argument to the type runtime expects
- Expression fexp = flde;
- if (!dgty.equals(flde.type))
- {
- fexp = new CastExp(loc, flde, flde.type);
- fexp.type = dgty;
- }
- ec = new VarExp(Loc.initial, fdapply, false);
- ec = new CallExp(loc, ec, fs.aggr, fexp);
- ec.type = Type.tint32; // don't run semantic() on ec
- return ec;
- }
-
- private static extern(D) Expression applyAssocArray(ForeachStatement fs, Expression flde, Type tab)
- {
- auto taa = tab.isTypeAArray();
- Expression ec;
- const dim = fs.parameters.length;
- // Check types
- Parameter p = (*fs.parameters)[0];
- bool isRef = (p.storageClass & STC.ref_) != 0;
- Type ta = p.type;
- if (dim == 2)
- {
- Type ti = (isRef ? taa.index.addMod(MODFlags.const_) : taa.index);
- if (isRef ? !ti.constConv(ta) : !ti.implicitConvTo(ta))
- {
- fs.error("`foreach`: index must be type `%s`, not `%s`",
- ti.toChars(), ta.toChars());
- return null;
- }
- p = (*fs.parameters)[1];
- isRef = (p.storageClass & STC.ref_) != 0;
- ta = p.type;
- }
- Type taav = taa.nextOf();
- if (isRef ? !taav.constConv(ta) : !taav.implicitConvTo(ta))
- {
- fs.error("`foreach`: value must be type `%s`, not `%s`",
- taav.toChars(), ta.toChars());
- return null;
- }
-
- /* Call:
- * extern(C) int _aaApply(void*, in size_t, int delegate(void*))
- * _aaApply(aggr, keysize, flde)
- *
- * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
- * _aaApply2(aggr, keysize, flde)
- */
- __gshared FuncDeclaration* fdapply = [null, null];
- __gshared TypeDelegate* fldeTy = [null, null];
- ubyte i = (dim == 2 ? 1 : 0);
- if (!fdapply[i])
- {
- auto params = new Parameters();
- params.push(new Parameter(0, Type.tvoid.pointerTo(), null, null, null));
- params.push(new Parameter(STC.const_, Type.tsize_t, null, null, null));
- auto dgparams = new Parameters();
- dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
- if (dim == 2)
- dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
- fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d));
- params.push(new Parameter(0, fldeTy[i], null, null, null));
- fdapply[i] = FuncDeclaration.genCfunc(params, Type.tint32, i ? Id._aaApply2 : Id._aaApply);
- }
-
- auto exps = new Expressions();
- exps.push(fs.aggr);
- auto keysize = taa.index.size();
- if (keysize == SIZE_INVALID)
- return null;
- assert(keysize < keysize.max - target.ptrsize);
- keysize = (keysize + (target.ptrsize - 1)) & ~(target.ptrsize - 1);
- // paint delegate argument to the type runtime expects
- Expression fexp = flde;
- if (!fldeTy[i].equals(flde.type))
- {
- fexp = new CastExp(fs.loc, flde, flde.type);
- fexp.type = fldeTy[i];
- }
- exps.push(new IntegerExp(Loc.initial, keysize, Type.tsize_t));
- exps.push(fexp);
- ec = new VarExp(Loc.initial, fdapply[i], false);
- ec = new CallExp(fs.loc, ec, exps);
- ec.type = Type.tint32; // don't run semantic() on ec
- return ec;
- }
-
- private static extern(D) Statement loopReturn(Expression e, Statements* cases, const ref Loc loc)
- {
- if (!cases.length)
- {
- // Easy case, a clean exit from the loop
- e = new CastExp(loc, e, Type.tvoid); // https://issues.dlang.org/show_bug.cgi?id=13899
- return new ExpStatement(loc, e);
- }
- // Construct a switch statement around the return value
- // of the apply function.
- Statement s;
- auto a = new Statements();
-
- // default: break; takes care of cases 0 and 1
- s = new BreakStatement(Loc.initial, null);
- s = new DefaultStatement(Loc.initial, s);
- a.push(s);
-
- // cases 2...
- foreach (i, c; *cases)
- {
- s = new CaseStatement(Loc.initial, new IntegerExp(i + 2), c);
- a.push(s);
- }
-
- s = new CompoundStatement(loc, a);
- return new SwitchStatement(loc, e, s, false);
- }
- /*************************************
- * Turn foreach body into the function literal:
- * int delegate(ref T param) { body }
- * Params:
- * sc = context
- * fs = ForeachStatement
- * tfld = type of function literal to be created (type of opApply() function if any), can be null
- * Returns:
- * Function literal created, as an expression
- * null if error.
- */
- static FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFunction tfld)
- {
- auto params = new Parameters();
- foreach (i, p; *fs.parameters)
- {
- StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_);
- Identifier id;
-
- p.type = p.type.typeSemantic(fs.loc, sc);
- p.type = p.type.addStorageClass(p.storageClass);
- if (tfld)
- {
- Parameter prm = tfld.parameterList[i];
- //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars());
- stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_);
- if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_))
- {
- if (!(prm.storageClass & STC.ref_))
- {
- fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars());
- return null;
- }
- goto LcopyArg;
- }
- id = p.ident; // argument copy is not need.
- }
- else if (p.storageClass & STC.ref_)
- {
- // default delegate parameters are marked as ref, then
- // argument copy is not need.
- id = p.ident;
- }
- else
- {
- // Make a copy of the ref argument so it isn't
- // a reference.
- LcopyArg:
- id = Identifier.generateId("__applyArg", cast(int)i);
-
- Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id));
- auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie);
- v.storage_class |= STC.temp | (stc & STC.scope_);
- Statement s = new ExpStatement(fs.loc, v);
- fs._body = new CompoundStatement(fs.loc, s, fs._body);
- }
- params.push(new Parameter(stc, p.type, id, null, null));
- }
- // https://issues.dlang.org/show_bug.cgi?id=13840
- // Throwable nested function inside nothrow function is acceptable.
- StorageClass stc = mergeFuncAttrs(STC.safe | STC.pure_ | STC.nogc, fs.func);
- auto tf = new TypeFunction(ParameterList(params), Type.tint32, LINK.d, stc);
- fs.cases = new Statements();
- fs.gotos = new ScopeStatements();
- auto fld = new FuncLiteralDeclaration(fs.loc, fs.endloc, tf, TOK.delegate_, fs);
- fld.fbody = fs._body;
- Expression flde = new FuncExp(fs.loc, fld);
- flde = flde.expressionSemantic(sc);
- fld.tookAddressOf = 0;
- if (flde.op == EXP.error)
- return null;
- return cast(FuncExp)flde;
- }
-
- override void visit(ForeachRangeStatement fs)
+ void visitForeachRange(ForeachRangeStatement fs)
{
/* https://dlang.org/spec/statement.html#foreach-range-statement
*/
@@ -1886,7 +1582,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = s.statementSemantic(sc);
}
- override void visit(IfStatement ifs)
+ void visitIf(IfStatement ifs)
{
/* https://dlang.org/spec/statement.html#IfStatement
*/
@@ -1959,6 +1655,20 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
// Save 'root' of two branches (then and else) at the point where it forks
CtorFlow ctorflow_root = scd.ctorflow.clone();
+ /* Rewrite `if (!__ctfe) A else B` as `if (__ctfe) B else A`
+ */
+ NotExp notExp;
+ if (ifs.elsebody &&
+ (notExp = ifs.condition.isNotExp()) !is null &&
+ notExp.e1.isVarExp() &&
+ notExp.e1.isVarExp().var.ident == Id.ctfe)
+ {
+ ifs.condition = notExp.e1;
+ auto sbody = ifs.ifbody;
+ ifs.ifbody = ifs.elsebody;
+ ifs.elsebody = sbody;
+ }
+
/* Detect `if (__ctfe)`
*/
if (ifs.isIfCtfeBlock())
@@ -1991,7 +1701,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ifs;
}
- override void visit(ConditionalStatement cs)
+ void visitConditional(ConditionalStatement cs)
{
//printf("ConditionalStatement::semantic()\n");
@@ -2020,7 +1730,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
}
- override void visit(PragmaStatement ps)
+ void visitPragma(PragmaStatement ps)
{
/* https://dlang.org/spec/statement.html#pragma-statement
*/
@@ -2104,14 +1814,14 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ps._body;
}
- override void visit(StaticAssertStatement s)
+ void visitStaticAssert(StaticAssertStatement s)
{
s.sa.semantic2(sc);
if (s.sa.errors)
return setError();
}
- override void visit(SwitchStatement ss)
+ void visitSwitch(SwitchStatement ss)
{
/* https://dlang.org/spec/statement.html#switch-statement
*/
@@ -2288,6 +1998,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
{
s = new BreakStatement(ss.loc, null); // default for C is `default: break;`
}
+ else if (!sc.needsCodegen())
+ {
+ // something for the interpreter to deal with
+ s = new ExpStatement(ss.loc, new AssertExp(ss.loc, IntegerExp.literal!0));
+ }
else if (global.params.useSwitchError == CHECKENABLE.on &&
global.params.checkAction != CHECKACTION.halt)
{
@@ -2337,7 +2052,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
- if (!ss.condition.type.isString())
+ if (!(ss.condition.type.isString() && sc.needsCodegen()))
{
sc.pop();
result = ss;
@@ -2420,7 +2135,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ss;
}
- override void visit(CaseStatement cs)
+ void visitCase(CaseStatement cs)
{
SwitchStatement sw = sc.sw;
bool errors = false;
@@ -2566,7 +2281,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = cs;
}
- override void visit(CaseRangeStatement crs)
+ void visitCaseRange(CaseRangeStatement crs)
{
SwitchStatement sw = sc.sw;
if (sw is null)
@@ -2649,7 +2364,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = s;
}
- override void visit(DefaultStatement ds)
+ void visitDefault(DefaultStatement ds)
{
//printf("DefaultStatement::semantic()\n");
bool errors = false;
@@ -2693,7 +2408,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ds;
}
- override void visit(GotoDefaultStatement gds)
+ void visitGotoDefault(GotoDefaultStatement gds)
{
/* https://dlang.org/spec/statement.html#goto-statement
*/
@@ -2712,7 +2427,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = gds;
}
- override void visit(GotoCaseStatement gcs)
+ void visitGotoCase(GotoCaseStatement gcs)
{
/* https://dlang.org/spec/statement.html#goto-statement
*/
@@ -2736,7 +2451,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = gcs;
}
- override void visit(ReturnStatement rs)
+ void visitReturn(ReturnStatement rs)
{
/* https://dlang.org/spec/statement.html#return-statement
*/
@@ -3129,7 +2844,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = rs;
}
- override void visit(BreakStatement bs)
+ void visitBreak(BreakStatement bs)
{
/* https://dlang.org/spec/statement.html#break-statement
*/
@@ -3207,7 +2922,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = bs;
}
- override void visit(ContinueStatement cs)
+ void visitContinue(ContinueStatement cs)
{
/* https://dlang.org/spec/statement.html#continue-statement
*/
@@ -3294,7 +3009,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = cs;
}
- override void visit(SynchronizedStatement ss)
+ void visitSynchronized(SynchronizedStatement ss)
{
/* https://dlang.org/spec/statement.html#synchronized-statement
*/
@@ -3416,7 +3131,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
}
- override void visit(WithStatement ws)
+ void visitWith(WithStatement ws)
{
/* https://dlang.org/spec/statement.html#with-statement
*/
@@ -3451,14 +3166,16 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
else
{
- Type t = ws.exp.type.toBasetype();
+ Type texp = ws.exp.type;
+ Type t = texp.toBasetype();
Expression olde = ws.exp;
if (t.ty == Tpointer)
{
ws.exp = new PtrExp(ws.loc, ws.exp);
ws.exp = ws.exp.expressionSemantic(sc);
- t = ws.exp.type.toBasetype();
+ texp = ws.exp.type;
+ t = texp.toBasetype();
}
assert(t);
@@ -3506,9 +3223,16 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
sym.parent = sc.scopesym;
sym.endlinnum = ws.endloc.linnum;
}
+ else if (auto tenum = texp.isTypeEnum())
+ {
+ ws.exp = new TypeExp(ws.exp.loc, tenum);
+ sym = new WithScopeSymbol(ws);
+ sym.parent = sc.scopesym;
+ sym.endlinnum = ws.endloc.linnum;
+ }
else
{
- ws.error("`with` expressions must be aggregate types or pointers to them, not `%s`", olde.type.toChars());
+ ws.error("`with` expression types must be enums or aggregates or pointers to them, not `%s`", olde.type.toChars());
return setError();
}
}
@@ -3531,7 +3255,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
// https://dlang.org/spec/statement.html#TryStatement
- override void visit(TryCatchStatement tcs)
+ void visitTryCatch(TryCatchStatement tcs)
{
//printf("TryCatchStatement.semantic()\n");
@@ -3635,7 +3359,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = tcs;
}
- override void visit(TryFinallyStatement tfs)
+ void visitTryFinally(TryFinallyStatement tfs)
{
//printf("TryFinallyStatement::semantic()\n");
tfs.tryBody = sc.tryBody; // chain on in-flight tryBody
@@ -3675,7 +3399,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = tfs;
}
- override void visit(ScopeGuardStatement oss)
+ void visitScopeGuard(ScopeGuardStatement oss)
{
/* https://dlang.org/spec/statement.html#scope-guard-statement
*/
@@ -3725,7 +3449,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = oss;
}
- override void visit(ThrowStatement ts)
+ void visitThrow(ThrowStatement ts)
{
/* https://dlang.org/spec/statement.html#throw-statement
*/
@@ -3738,57 +3462,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
- /**
- * Run semantic on `throw <exp>`.
- *
- * Params:
- * loc = location of the `throw`
- * exp = value to be thrown
- * sc = enclosing scope
- *
- * Returns: true if the `throw` is valid, or false if an error was found
- */
- extern(D) static bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
- {
- if (!global.params.useExceptions)
- {
- loc.error("cannot use `throw` statements with -betterC");
- return false;
- }
-
- if (!ClassDeclaration.throwable)
- {
- loc.error("cannot use `throw` statements because `object.Throwable` was not declared");
- return false;
- }
-
- if (FuncDeclaration fd = sc.parent.isFuncDeclaration())
- fd.hasReturnExp |= 2;
-
- if (exp.op == EXP.new_)
- {
- 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)
- return false;
-
- checkThrowEscape(sc, exp, false);
-
- ClassDeclaration cd = exp.type.toBasetype().isClassHandle();
- if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null)))
- {
- loc.error("can only throw class objects derived from `Throwable`, not type `%s`", exp.type.toChars());
- return false;
- }
- return true;
- }
-
- override void visit(DebugStatement ds)
+ void visitDebug(DebugStatement ds)
{
if (ds.statement)
{
@@ -3800,7 +3474,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ds.statement;
}
- override void visit(GotoStatement gs)
+ void visitGoto(GotoStatement gs)
{
/* https://dlang.org/spec/statement.html#goto-statement
*/
@@ -3844,7 +3518,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = gs;
}
- override void visit(LabelStatement ls)
+ void visitLabel(LabelStatement ls)
{
//printf("LabelStatement::semantic()\n");
FuncDeclaration fd = sc.parent.isFuncDeclaration();
@@ -3878,7 +3552,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = ls;
}
- override void visit(AsmStatement s)
+ void visitAsm(AsmStatement s)
{
/* https://dlang.org/spec/statement.html#asm
*/
@@ -3887,7 +3561,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = asmSemantic(s, sc);
}
- override void visit(CompoundAsmStatement cas)
+ void visitCompoundAsm(CompoundAsmStatement cas)
{
//printf("CompoundAsmStatement()::semantic()\n");
// Apply postfix attributes of the asm block to each statement.
@@ -3915,9 +3589,9 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
assert(sc.func);
- if (!(cas.stc & STC.pure_) && sc.func.setImpure())
+ if (!(cas.stc & STC.pure_) && sc.func.setImpure(cas.loc, "`asm` statement is assumed to be impure - mark it with `pure` if it is not"))
cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not");
- if (!(cas.stc & STC.nogc) && sc.func.setGC())
+ if (!(cas.stc & STC.nogc) && sc.func.setGC(cas.loc, "`asm` statement in %s `%s` is assumed to use the GC - mark it with `@nogc` if it does not"))
cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
if (!(cas.stc & (STC.trusted | STC.safe)))
{
@@ -3928,7 +3602,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
result = cas;
}
- override void visit(ImportStatement imps)
+ void visitImport(ImportStatement imps)
{
/* https://dlang.org/spec/module.html#ImportDeclaration
*/
@@ -3967,8 +3641,375 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
result = imps;
}
+
+ mixin VisitStatement!void visit;
+ visit.VisitStatement(s);
+ return result;
}
+/**
+ * Run semantic on `throw <exp>`.
+ *
+ * Params:
+ * loc = location of the `throw`
+ * exp = value to be thrown
+ * sc = enclosing scope
+ *
+ * Returns: true if the `throw` is valid, or false if an error was found
+ */
+public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
+{
+ if (!global.params.useExceptions)
+ {
+ loc.error("cannot use `throw` statements with -betterC");
+ return false;
+ }
+
+ if (!ClassDeclaration.throwable)
+ {
+ loc.error("cannot use `throw` statements because `object.Throwable` was not declared");
+ return false;
+ }
+
+ if (FuncDeclaration fd = sc.parent.isFuncDeclaration())
+ fd.hasReturnExp |= 2;
+
+ if (exp.op == EXP.new_)
+ {
+ 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)
+ return false;
+ if (!exp.type.isNaked())
+ {
+ // @@@DEPRECATED_2.112@@@
+ // Deprecated in 2.102, change into an error & return false in 2.112
+ exp.loc.deprecation("cannot throw object of qualified type `%s`", exp.type.toChars());
+ //return false;
+ }
+ checkThrowEscape(sc, exp, false);
+
+ ClassDeclaration cd = exp.type.toBasetype().isClassHandle();
+ if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null)))
+ {
+ loc.error("can only throw class objects derived from `Throwable`, not type `%s`", exp.type.toChars());
+ return false;
+ }
+ return true;
+}
+
+private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde,
+ Type tab, Scope* sc2, Dsymbol sapply)
+{
+ version (none)
+ {
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`");
+ }
+ (cast(FuncExp)flde).fd.tookAddressOf = 1;
+ }
+ else
+ {
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope'
+ }
+ assert(tab.ty == Tstruct || tab.ty == Tclass);
+ assert(sapply);
+ /* Call:
+ * aggr.apply(flde)
+ */
+ Expression ec;
+ 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)
+ return null;
+ if (ec.type != Type.tint32)
+ {
+ fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars());
+ return null;
+ }
+ return ec;
+}
+
+private extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde,
+ Type tab, Scope* sc2)
+{
+ Expression ec;
+ /* Call:
+ * aggr(flde)
+ */
+ if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() &&
+ !(cast(DelegateExp)fs.aggr).func.needThis())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=3560
+ fs.aggr = (cast(DelegateExp)fs.aggr).e1;
+ }
+ ec = new CallExp(fs.loc, fs.aggr, flde);
+ ec = ec.expressionSemantic(sc2);
+ if (ec.op == EXP.error)
+ return null;
+ if (ec.type != Type.tint32)
+ {
+ fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars());
+ return null;
+ }
+ return ec;
+}
+
+private extern(D) Expression applyArray(ForeachStatement fs, Expression flde,
+ Type tab, Scope* sc2, Type tn, Type tnv)
+{
+ Expression ec;
+ const dim = fs.parameters.length;
+ const loc = fs.loc;
+ /* Call:
+ * _aApply(aggr, flde)
+ */
+ static immutable fntab =
+ [
+ "cc", "cw", "cd",
+ "wc", "cc", "wd",
+ "dc", "dw", "dd"
+ ];
+
+ const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1;
+ char[BUFFER_LEN] fdname;
+ int flag;
+
+ switch (tn.ty)
+ {
+ case Tchar: flag = 0; break;
+ case Twchar: flag = 3; break;
+ case Tdchar: flag = 6; break;
+ default:
+ assert(0);
+ }
+ switch (tnv.ty)
+ {
+ case Tchar: flag += 0; break;
+ case Twchar: flag += 1; break;
+ case Tdchar: flag += 2; break;
+ default:
+ assert(0);
+ }
+ const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : "";
+ int j = snprintf(fdname.ptr, BUFFER_LEN, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim);
+ assert(j < BUFFER_LEN);
+
+ FuncDeclaration fdapply;
+ TypeDelegate dgty;
+ auto params = new Parameters();
+ params.push(new Parameter(STC.in_, tn.arrayOf(), null, null, null));
+ auto dgparams = new Parameters();
+ dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
+ if (dim == 2)
+ dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
+ dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d));
+ params.push(new Parameter(0, dgty, null, null, null));
+ fdapply = FuncDeclaration.genCfunc(params, Type.tint32, fdname.ptr);
+
+ if (tab.isTypeSArray())
+ fs.aggr = fs.aggr.castTo(sc2, tn.arrayOf());
+ // paint delegate argument to the type runtime expects
+ Expression fexp = flde;
+ if (!dgty.equals(flde.type))
+ {
+ fexp = new CastExp(loc, flde, flde.type);
+ fexp.type = dgty;
+ }
+ ec = new VarExp(Loc.initial, fdapply, false);
+ ec = new CallExp(loc, ec, fs.aggr, fexp);
+ ec.type = Type.tint32; // don't run semantic() on ec
+ return ec;
+}
+
+private extern(D) Expression applyAssocArray(ForeachStatement fs, Expression flde, Type tab)
+{
+ auto taa = tab.isTypeAArray();
+ Expression ec;
+ const dim = fs.parameters.length;
+ // Check types
+ Parameter p = (*fs.parameters)[0];
+ bool isRef = (p.storageClass & STC.ref_) != 0;
+ Type ta = p.type;
+ if (dim == 2)
+ {
+ Type ti = (isRef ? taa.index.addMod(MODFlags.const_) : taa.index);
+ if (isRef ? !ti.constConv(ta) : !ti.implicitConvTo(ta))
+ {
+ fs.error("`foreach`: index must be type `%s`, not `%s`",
+ ti.toChars(), ta.toChars());
+ return null;
+ }
+ p = (*fs.parameters)[1];
+ isRef = (p.storageClass & STC.ref_) != 0;
+ ta = p.type;
+ }
+ Type taav = taa.nextOf();
+ if (isRef ? !taav.constConv(ta) : !taav.implicitConvTo(ta))
+ {
+ fs.error("`foreach`: value must be type `%s`, not `%s`",
+ taav.toChars(), ta.toChars());
+ return null;
+ }
+
+ /* Call:
+ * extern(C) int _aaApply(void*, in size_t, int delegate(void*))
+ * _aaApply(aggr, keysize, flde)
+ *
+ * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
+ * _aaApply2(aggr, keysize, flde)
+ */
+ __gshared FuncDeclaration* fdapply = [null, null];
+ __gshared TypeDelegate* fldeTy = [null, null];
+ ubyte i = (dim == 2 ? 1 : 0);
+ if (!fdapply[i])
+ {
+ auto params = new Parameters();
+ params.push(new Parameter(0, Type.tvoid.pointerTo(), null, null, null));
+ params.push(new Parameter(STC.const_, Type.tsize_t, null, null, null));
+ auto dgparams = new Parameters();
+ dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
+ if (dim == 2)
+ dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
+ fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d));
+ params.push(new Parameter(0, fldeTy[i], null, null, null));
+ fdapply[i] = FuncDeclaration.genCfunc(params, Type.tint32, i ? Id._aaApply2 : Id._aaApply);
+ }
+
+ auto exps = new Expressions();
+ exps.push(fs.aggr);
+ auto keysize = taa.index.size();
+ if (keysize == SIZE_INVALID)
+ return null;
+ assert(keysize < keysize.max - target.ptrsize);
+ keysize = (keysize + (target.ptrsize - 1)) & ~(target.ptrsize - 1);
+ // paint delegate argument to the type runtime expects
+ Expression fexp = flde;
+ if (!fldeTy[i].equals(flde.type))
+ {
+ fexp = new CastExp(fs.loc, flde, flde.type);
+ fexp.type = fldeTy[i];
+ }
+ exps.push(new IntegerExp(Loc.initial, keysize, Type.tsize_t));
+ exps.push(fexp);
+ ec = new VarExp(Loc.initial, fdapply[i], false);
+ ec = new CallExp(fs.loc, ec, exps);
+ ec.type = Type.tint32; // don't run semantic() on ec
+ return ec;
+}
+
+private extern(D) Statement loopReturn(Expression e, Statements* cases, const ref Loc loc)
+{
+ if (!cases.length)
+ {
+ // Easy case, a clean exit from the loop
+ e = new CastExp(loc, e, Type.tvoid); // https://issues.dlang.org/show_bug.cgi?id=13899
+ return new ExpStatement(loc, e);
+ }
+ // Construct a switch statement around the return value
+ // of the apply function.
+ Statement s;
+ auto a = new Statements();
+
+ // default: break; takes care of cases 0 and 1
+ s = new BreakStatement(Loc.initial, null);
+ s = new DefaultStatement(Loc.initial, s);
+ a.push(s);
+
+ // cases 2...
+ foreach (i, c; *cases)
+ {
+ s = new CaseStatement(Loc.initial, new IntegerExp(i + 2), c);
+ a.push(s);
+ }
+
+ s = new CompoundStatement(loc, a);
+ return new SwitchStatement(loc, e, s, false);
+}
+
+/*************************************
+ * Turn foreach body into the function literal:
+ * int delegate(ref T param) { body }
+ * Params:
+ * sc = context
+ * fs = ForeachStatement
+ * tfld = type of function literal to be created (type of opApply() function if any), can be null
+ * Returns:
+ * Function literal created, as an expression
+ * null if error.
+ */
+private FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFunction tfld)
+{
+ auto params = new Parameters();
+ foreach (i, p; *fs.parameters)
+ {
+ StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_);
+ Identifier id;
+
+ p.type = p.type.typeSemantic(fs.loc, sc);
+ p.type = p.type.addStorageClass(p.storageClass);
+ if (tfld)
+ {
+ Parameter prm = tfld.parameterList[i];
+ //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars());
+ stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_);
+ if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_))
+ {
+ if (!(prm.storageClass & STC.ref_))
+ {
+ fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars());
+ return null;
+ }
+ goto LcopyArg;
+ }
+ id = p.ident; // argument copy is not need.
+ }
+ else if (p.storageClass & STC.ref_)
+ {
+ // default delegate parameters are marked as ref, then
+ // argument copy is not need.
+ id = p.ident;
+ }
+ else
+ {
+ // Make a copy of the ref argument so it isn't
+ // a reference.
+ LcopyArg:
+ id = Identifier.generateId("__applyArg", cast(int)i);
+
+ Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id));
+ auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie);
+ v.storage_class |= STC.temp | (stc & STC.scope_);
+ Statement s = new ExpStatement(fs.loc, v);
+ fs._body = new CompoundStatement(fs.loc, s, fs._body);
+ }
+ params.push(new Parameter(stc, p.type, id, null, null));
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=13840
+ // Throwable nested function inside nothrow function is acceptable.
+ StorageClass stc = mergeFuncAttrs(STC.safe | STC.pure_ | STC.nogc, fs.func);
+ auto tf = new TypeFunction(ParameterList(params), Type.tint32, LINK.d, stc);
+ fs.cases = new Statements();
+ fs.gotos = new ScopeStatements();
+ auto fld = new FuncLiteralDeclaration(fs.loc, fs.endloc, tf, TOK.delegate_, fs);
+ fld.fbody = fs._body;
+ Expression flde = new FuncExp(fs.loc, fld);
+ flde = flde.expressionSemantic(sc);
+ fld.tookAddressOf = 0;
+ if (flde.op == EXP.error)
+ return null;
+ return cast(FuncExp)flde;
+}
+
+
void catchSemantic(Catch c, Scope* sc)
{
//printf("Catch::semantic(%s)\n", ident.toChars());
@@ -4735,8 +4776,8 @@ private Statements* flatten(Statement statement, Scope* sc)
(*a)[0] = ls;
return a;
- case STMT.Compile:
- auto cs = statement.isCompileStatement();
+ case STMT.Mixin:
+ auto cs = statement.isMixinStatement();
OutBuffer buf;
@@ -4747,13 +4788,16 @@ private Statements* flatten(Statement statement, Scope* sc)
const len = buf.length;
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
- scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false, global.errorSink);
+ const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
+ 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.vin;
p.nextToken();
auto a = new Statements();
while (p.token.value != TOK.endOfFile)
{
- Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
+ Statement s = p.parseStatement(ParseStatementFlags.curlyScope);
if (!s || global.errors != errors)
return errorStatements();
a.push(s);
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
index aec3a77..352c89e 100644
--- a/gcc/d/dmd/tokens.d
+++ b/gcc/d/dmd/tokens.d
@@ -274,6 +274,7 @@ enum TOK : ubyte
__cdecl,
__declspec,
__stdcall,
+ __thread,
__pragma,
__int128,
__attribute__,
@@ -289,8 +290,6 @@ enum EXP : ubyte
cast_,
null_,
assert_,
- true_,
- false_,
array,
call,
address,
@@ -307,13 +306,10 @@ enum EXP : ubyte
dotType,
slice,
arrayLength,
- version_,
dollar,
template_,
dotTemplateDeclaration,
declaration,
- typeof_,
- pragma_,
dSymbol,
typeid_,
uadd,
@@ -394,13 +390,11 @@ enum EXP : ubyte
int64,
float64,
complex80,
- char_,
import_,
delegate_,
function_,
mixin_,
in_,
- default_,
break_,
continue_,
goto_,
@@ -414,7 +408,6 @@ enum EXP : ubyte
moduleString, // __MODULE__
functionString, // __FUNCTION__
prettyFunction, // __PRETTY_FUNCTION__
- shared_,
pow,
powAssign,
vector,
@@ -424,10 +417,11 @@ enum EXP : ubyte
showCtfeContext,
objcClassReference,
vectorArray,
- arrow, // ->
compoundLiteral, // ( type-name ) { initializer-list }
_Generic,
interval,
+
+ loweredAssignExp,
}
enum FirstCKeyword = TOK.inline;
@@ -586,6 +580,7 @@ private immutable TOK[] keywords =
TOK.__cdecl,
TOK.__declspec,
TOK.__stdcall,
+ TOK.__thread,
TOK.__pragma,
TOK.__int128,
TOK.__attribute__,
@@ -617,7 +612,7 @@ static immutable TOK[TOK.max + 1] Ckeywords =
union_, unsigned, void_, volatile, while_, asm_, typeof_,
_Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
_Static_assert, _Thread_local,
- _import, __cdecl, __declspec, __stdcall, __pragma, __int128, __attribute__,
+ _import, __cdecl, __declspec, __stdcall, __thread, __pragma, __int128, __attribute__,
_assert ];
foreach (kw; Ckwds)
@@ -889,6 +884,7 @@ extern (C++) struct Token
TOK.__cdecl : "__cdecl",
TOK.__declspec : "__declspec",
TOK.__stdcall : "__stdcall",
+ TOK.__thread : "__thread",
TOK.__pragma : "__pragma",
TOK.__int128 : "__int128",
TOK.__attribute__ : "__attribute__",
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
index 87361f32..6c1b979 100644
--- a/gcc/d/dmd/tokens.h
+++ b/gcc/d/dmd/tokens.h
@@ -283,6 +283,7 @@ enum class TOK : unsigned char
cdecl_,
declspec,
stdcall,
+ thread,
pragma,
int128_,
attribute__,
@@ -299,8 +300,6 @@ enum class EXP : unsigned char
cast_,
null_,
assert_,
- true_,
- false_,
array,
call,
address,
@@ -317,13 +316,10 @@ enum class EXP : unsigned char
dotType,
slice,
arrayLength,
- version_,
dollar,
template_,
dotTemplateDeclaration,
declaration,
- typeof_,
- pragma_,
dSymbol,
typeid_,
uadd,
@@ -404,13 +400,11 @@ enum class EXP : unsigned char
int64,
float64,
complex80,
- char_,
import_,
delegate_,
function_,
mixin_,
in_,
- default_,
break_,
continue_,
goto_,
@@ -424,7 +418,6 @@ enum class EXP : unsigned char
moduleString, // __MODULE__
functionString, // __FUNCTION__
prettyFunction, // __PRETTY_FUNCTION__
- shared_,
pow,
powAssign,
vector,
@@ -434,7 +427,6 @@ enum class EXP : unsigned char
showCtfeContext,
objcClassReference,
vectorArray,
- arrow, // ->
compoundLiteral, // ( type-name ) { initializer-list }
_Generic_,
interval,
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index de0129b..0f36353 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -118,55 +118,40 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
data.setDim(cast(size_t)cntdata);
data.zero();
- extern (C++) final class PointerBitmapVisitor : Visitor
- {
- alias visit = Visitor.visit;
- public:
- extern (D) this(Array!(ulong)* _data, ulong _sz_size_t) scope
- {
- this.data = _data;
- this.sz_size_t = _sz_size_t;
- }
+ ulong offset;
+ bool error;
+ 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));
}
- override void visit(Type t)
+ void visitType(Type t)
{
Type tb = t.toBasetype();
if (tb != t)
- tb.accept(this);
+ visit(tb);
}
- override void visit(TypeError t)
+ void visitError(TypeError t)
{
- visit(cast(Type)t);
+ visitType(t);
}
- override void visit(TypeNext t)
- {
- assert(0);
- }
-
- override void visit(TypeBasic t)
+ void visitBasic(TypeBasic t)
{
if (t.ty == Tvoid)
setpointer(offset);
}
- override void visit(TypeVector t)
- {
- }
-
- override void visit(TypeArray t)
+ void visitVector(TypeVector t)
{
- assert(0);
}
- override void visit(TypeSArray t)
+ void visitSArray(TypeSArray t)
{
ulong arrayoff = offset;
ulong nextsize = t.next.size();
@@ -176,95 +161,67 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
for (ulong i = 0; i < dim; i++)
{
offset = arrayoff + i * nextsize;
- t.next.accept(this);
+ visit(t.next);
}
offset = arrayoff;
}
- override void visit(TypeDArray t)
+ void visitDArray(TypeDArray t)
{
setpointer(offset + sz_size_t);
}
// dynamic array is {length,ptr}
- override void visit(TypeAArray t)
+ void visitAArray(TypeAArray t)
{
setpointer(offset);
}
- override void visit(TypePointer t)
+ void visitPointer(TypePointer t)
{
if (t.nextOf().ty != Tfunction) // don't mark function pointers
setpointer(offset);
}
- override void visit(TypeReference t)
+ void visitReference(TypeReference t)
{
setpointer(offset);
}
- override void visit(TypeClass t)
+ void visitClass(TypeClass t)
{
setpointer(offset);
}
- override void visit(TypeFunction t)
+ void visitFunction(TypeFunction t)
{
}
- override void visit(TypeDelegate t)
+ void visitDelegate(TypeDelegate t)
{
setpointer(offset);
}
- // delegate is {context, function}
- override void visit(TypeQualified t)
+ void visitEnum(TypeEnum t)
{
- assert(0);
+ visitType(t);
}
- // assume resolved
- override void visit(TypeIdentifier t)
+ void visitTuple(TypeTuple t)
{
- assert(0);
+ visitType(t);
}
- override void visit(TypeInstance t)
+ void visitNull(TypeNull t)
{
- assert(0);
- }
-
- override void visit(TypeTypeof t)
- {
- assert(0);
- }
-
- override void visit(TypeReturn t)
- {
- assert(0);
- }
-
- override void visit(TypeEnum t)
- {
- visit(cast(Type)t);
- }
-
- override void visit(TypeTuple t)
- {
- visit(cast(Type)t);
+ // always a null pointer
}
- override void visit(TypeSlice t)
+ void visitNoreturn(TypeNoreturn t)
{
- assert(0);
}
- override void visit(TypeNull t)
- {
- // always a null pointer
- }
-
- override void visit(TypeStruct t)
+ void visitStruct(TypeStruct t)
{
ulong structoff = offset;
foreach (v; t.sym.fields)
@@ -273,38 +230,43 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
if (v.type.ty == Tclass)
setpointer(offset);
else
- v.type.accept(this);
+ visit(v.type);
}
offset = structoff;
}
+ void visitDefaultCase(Type t)
+ {
+ //printf("ty = %d\n", t.ty);
+ assert(0);
+ }
+
+ mixin VisitType!void visit;
+ visit.VisitType(t);
+ }
+
+ if (auto tc = t.isTypeClass())
+ {
// a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
- void visitClass(TypeClass t)
+ void visitTopLevelClass(TypeClass t)
{
ulong classoff = offset;
// skip vtable-ptr and monitor
if (t.sym.baseClass)
- visitClass(cast(TypeClass)t.sym.baseClass.type);
+ visitTopLevelClass(t.sym.baseClass.type.isTypeClass());
foreach (v; t.sym.fields)
{
offset = classoff + v.offset;
- v.type.accept(this);
+ visit(v.type);
}
offset = classoff;
}
- Array!(ulong)* data;
- ulong offset;
- ulong sz_size_t;
- bool error;
+ visitTopLevelClass(tc);
}
-
- scope PointerBitmapVisitor pbv = new PointerBitmapVisitor(data, sz_size_t);
- if (t.ty == Tclass)
- pbv.visitClass(cast(TypeClass)t);
else
- t.accept(pbv);
- return pbv.error ? ulong.max : sz;
+ visit(t);
+ return error ? ulong.max : sz;
}
/**
@@ -1314,6 +1276,19 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
return ErrorExp.get();
}
+ // https://issues.dlang.org/show_bug.cgi?id=19706
+ // When getting the attributes of the instance of a
+ // templated member function semantic tiargs does
+ // not perform semantic3 on the instance.
+ // For more information see FuncDeclaration.functionSemantic.
+ // For getFunctionAttributes it is mandatory to do
+ // attribute inference.
+ if (fd && fd.parent && fd.parent.isTemplateInstance)
+ {
+ fd.functionSemantic3();
+ tf = cast(TypeFunction)fd.type;
+ }
+
auto mods = new Expressions();
void addToMods(string str)
@@ -1354,6 +1329,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
* "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
* "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
* "typesafe" void typesafe(T[] ...)
+ * "KR" old K+R style
*/
// get symbol linkage as a string
if (dim != 1)
@@ -1388,6 +1364,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
case VarArg.variadic: style = (link == LINK.d)
? "argptr"
: "stdarg"; break;
+ case VarArg.KRvariadic: style = "KR"; break;
case VarArg.typesafe: style = "typesafe"; break;
}
auto se = new StringExp(e.loc, style);
@@ -2246,65 +2223,65 @@ private void traitNotFound(TraitsExp e)
// All possible traits
__gshared Identifier*[59] idents =
[
+ &Id.allMembers,
+ &Id.child,
+ &Id.classInstanceAlignment,
+ &Id.classInstanceSize,
+ &Id.compiles,
+ &Id.derivedMembers,
+ &Id.fullyQualifiedName,
+ &Id.getAliasThis,
+ &Id.getAttributes,
+ &Id.getFunctionAttributes,
+ &Id.getFunctionVariadicStyle,
+ &Id.getLinkage,
+ &Id.getLocation,
+ &Id.getMember,
+ &Id.getOverloads,
+ &Id.getParameterStorageClasses,
+ &Id.getPointerBitmap,
+ &Id.getProtection,
+ &Id.getTargetInfo,
+ &Id.getUnitTests,
+ &Id.getVirtualFunctions,
+ &Id.getVirtualIndex,
+ &Id.getVirtualMethods,
+ &Id.getVisibility,
+ &Id.hasCopyConstructor,
+ &Id.hasMember,
+ &Id.hasPostblit,
+ &Id.identifier,
&Id.isAbstractClass,
+ &Id.isAbstractFunction,
&Id.isArithmetic,
&Id.isAssociativeArray,
- &Id.isDisabled,
+ &Id.isCopyable,
&Id.isDeprecated,
- &Id.isFuture,
+ &Id.isDisabled,
&Id.isFinalClass,
- &Id.isPOD,
- &Id.isNested,
+ &Id.isFinalFunction,
&Id.isFloating,
+ &Id.isFuture,
&Id.isIntegral,
- &Id.isScalar,
- &Id.isStaticArray,
- &Id.isUnsigned,
- &Id.isVirtualFunction,
- &Id.isVirtualMethod,
- &Id.isAbstractFunction,
- &Id.isFinalFunction,
- &Id.isOverrideFunction,
- &Id.isStaticFunction,
+ &Id.isLazy,
&Id.isModule,
+ &Id.isNested,
+ &Id.isOut,
+ &Id.isOverrideFunction,
&Id.isPackage,
+ &Id.isPOD,
&Id.isRef,
- &Id.isOut,
- &Id.isLazy,
&Id.isReturnOnStack,
- &Id.hasMember,
- &Id.identifier,
- &Id.fullyQualifiedName,
- &Id.getProtection,
- &Id.getVisibility,
- &Id.parent,
- &Id.child,
- &Id.getLinkage,
- &Id.getMember,
- &Id.getOverloads,
- &Id.getVirtualFunctions,
- &Id.getVirtualMethods,
- &Id.classInstanceSize,
- &Id.classInstanceAlignment,
- &Id.allMembers,
- &Id.derivedMembers,
&Id.isSame,
- &Id.compiles,
- &Id.getAliasThis,
- &Id.getAttributes,
- &Id.getFunctionAttributes,
- &Id.getFunctionVariadicStyle,
- &Id.getParameterStorageClasses,
- &Id.getUnitTests,
- &Id.getVirtualIndex,
- &Id.getPointerBitmap,
+ &Id.isScalar,
+ &Id.isStaticArray,
+ &Id.isStaticFunction,
+ &Id.isUnsigned,
+ &Id.isVirtualFunction,
+ &Id.isVirtualMethod,
&Id.isZeroInit,
- &Id.getTargetInfo,
- &Id.getLocation,
- &Id.hasPostblit,
- &Id.hasCopyConstructor,
- &Id.isCopyable,
&Id.parameters,
+ &Id.parent,
];
StringTable!(bool)* stringTable = cast(StringTable!(bool)*) &traitsStringTable;
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
index 5844911..c588270 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -44,9 +44,9 @@ package mixin template ParseVisitMethods(AST)
}
}
- override void visit(AST.CompileStatement s)
+ override void visit(AST.MixinStatement s)
{
- //printf("Visiting CompileStatement\n");
+ //printf("Visiting MixinStatement\n");
visitArgs(s.exps.peekSlice());
}
@@ -579,7 +579,7 @@ package mixin template ParseVisitMethods(AST)
de.accept(this);
}
- override void visit(AST.CompileDeclaration d)
+ override void visit(AST.MixinDeclaration d)
{
//printf("Visiting compileDeclaration\n");
visitArgs(d.exps.peekSlice());
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index c668199..f0decf2 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -290,6 +290,8 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
if (!sm)
return helper3();
+ if (sm.isAliasDeclaration)
+ sm.checkDeprecated(loc, sc);
s = sm.toAlias();
}
@@ -456,6 +458,17 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
return t.merge();
}
+ Type visitComplex(TypeBasic t)
+ {
+ if (!(sc.flags & SCOPE.Cfile))
+ return visitType(t);
+
+ auto tc = getComplexLibraryType(loc, sc, t.ty);
+ if (tc.ty == Terror)
+ return tc;
+ return tc.addMod(t.mod).merge();
+ }
+
Type visitVector(TypeVector mtype)
{
const errors = global.errors;
@@ -1185,19 +1198,31 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
// -preview=in: Always add `ref` when used with `extern(C++)` functions
// Done here to allow passing opaque types with `in`
- if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
+ if ((fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
{
switch (tf.linkage)
{
case LINK.cpp:
- fparam.storageClass |= STC.ref_;
+ if (global.params.previewIn)
+ fparam.storageClass |= STC.ref_;
break;
case LINK.default_, LINK.d:
break;
default:
- .error(loc, "cannot use `in` parameters with `extern(%s)` functions",
- linkageToChars(tf.linkage));
- .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
+ if (global.params.previewIn)
+ {
+ .error(loc, "cannot use `in` parameters with `extern(%s)` functions",
+ linkageToChars(tf.linkage));
+ .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
+ }
+ else
+ {
+ // Note that this deprecation will not trigger on `in ref` / `ref in`
+ // parameters, however the parser will trigger a deprecation on them.
+ .deprecation(loc, "using `in` parameters with `extern(%s)` functions is deprecated",
+ linkageToChars(tf.linkage));
+ .deprecationSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars());
+ }
break;
}
}
@@ -1292,28 +1317,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
// error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
}
- /* Scope attribute is not necessary if the parameter type does not have pointers
- */
- const sr = buildScopeRef(fparam.storageClass);
- switch (sr)
- {
- case ScopeRef.Scope:
- case ScopeRef.RefScope:
- case ScopeRef.ReturnRef_Scope:
- if (!fparam.type.hasPointers())
- fparam.storageClass &= ~STC.scope_;
- break;
-
- case ScopeRef.ReturnScope:
- case ScopeRef.Ref_ReturnScope:
- if (!fparam.type.hasPointers())
- fparam.storageClass &= ~(STC.return_ | STC.scope_ | STC.returnScope);
- break;
-
- default:
- break;
- }
-
// Remove redundant storage classes for type, they are already applied
fparam.storageClass &= ~(STC.TYPECTOR);
@@ -1786,12 +1789,14 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
case TOK.struct_:
auto sd = new StructDeclaration(mtype.loc, mtype.id, false);
+ sd.alignment = mtype.packalign;
declare(sd);
mtype.resolved = visitStruct(new TypeStruct(sd));
break;
case TOK.union_:
auto ud = new UnionDeclaration(mtype.loc, mtype.id);
+ ud.alignment = mtype.packalign;
declare(ud);
mtype.resolved = visitStruct(new TypeStruct(ud));
break;
@@ -1928,6 +1933,9 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
switch (type.ty)
{
default: return visitType(type);
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80: return visitComplex(type.isTypeBasic());
case Tvector: return visitVector(type.isTypeVector());
case Tsarray: return visitSArray(type.isTypeSArray());
case Tarray: return visitDArray(type.isTypeDArray());
@@ -2697,7 +2705,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
{
void semanticOnMixin(Dsymbol member)
{
- if (auto compileDecl = member.isCompileDeclaration())
+ if (auto compileDecl = member.isMixinDeclaration())
compileDecl.dsymbolSemantic(sc);
else if (auto mixinTempl = member.isTemplateMixin())
mixinTempl.dsymbolSemantic(sc);
@@ -2796,8 +2804,10 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
}
mt.exp = exp2;
- if (mt.exp.op == EXP.type ||
- mt.exp.op == EXP.scope_)
+ if ((mt.exp.op == EXP.type || mt.exp.op == EXP.scope_) &&
+ // https://issues.dlang.org/show_bug.cgi?id=23863
+ // compile time sequences are valid types
+ !mt.exp.type.isTypeTuple())
{
if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof
mt.exp.checkType())
@@ -3126,7 +3136,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
* Returns:
* resulting expression with e.ident resolved
*/
-Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
+Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag)
{
Expression visitType(Type mt)
{
@@ -3624,7 +3634,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
* template opDispatch(name) if (isValid!name) { ... }
*/
uint errors = gagError ? global.startGagging() : 0;
- e = dti.dotTemplateSemanticProp(sc, 0);
+ e = dti.dotTemplateSemanticProp(sc, DotExpFlag.none);
if (gagError && global.endGagging(errors))
e = null;
return returnExp(e);
@@ -3730,6 +3740,9 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
{
return noMember(mt, sc, e, ident, flag);
}
+ // check before alias resolution; the alias itself might be deprecated!
+ if (s.isAliasDeclaration)
+ e.checkDeprecated(sc, s);
s = s.toAlias();
if (auto em = s.isEnumMember())
@@ -3917,7 +3930,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
return mt.getProperty(sc, e.loc, ident, flag & 1);
}
- Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, 1);
+ Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, DotExpFlag.gag);
if (!(flag & 1) && !res)
{
if (auto ns = mt.sym.search_correct(ident))
@@ -4599,6 +4612,74 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
}
}
+
+/**********************************************
+ * Extract complex type from core.stdc.config
+ * Params:
+ * loc = for error messages
+ * sc = context
+ * ty = a complex or imaginary type
+ * Returns:
+ * Complex!float, Complex!double, Complex!real or null for error
+ */
+
+Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
+{
+ // singleton
+ __gshared Type complex_float;
+ __gshared Type complex_double;
+ __gshared Type complex_real;
+
+ Type* pt;
+ Identifier id;
+ switch (ty)
+ {
+ case Timaginary32:
+ case Tcomplex32: id = Id.c_complex_float; pt = &complex_float; break;
+ case Timaginary64:
+ case Tcomplex64: id = Id.c_complex_double; pt = &complex_double; break;
+ case Timaginary80:
+ case Tcomplex80: id = Id.c_complex_real; pt = &complex_real; break;
+ default:
+ return Type.terror;
+ }
+
+ if (*pt)
+ return *pt;
+ *pt = Type.terror;
+
+ Module mConfig = Module.loadCoreStdcConfig();
+ if (!mConfig)
+ {
+ error(loc, "`core.stdc.config` is required for complex numbers");
+ return *pt;
+ }
+
+ Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports);
+ if (!s)
+ {
+ error(loc, "`%s` not found in core.stdc.config", id.toChars());
+ return *pt;
+ }
+ s = s.toAlias();
+ if (auto t = s.getType())
+ {
+ if (auto ts = t.toBasetype().isTypeStruct())
+ {
+ *pt = ts;
+ return ts;
+ }
+ }
+ if (auto sd = s.isStructDeclaration())
+ {
+ *pt = sd.type;
+ return sd.type;
+ }
+
+ error(loc, "`%s` must be an alias for a complex struct", s.toChars());
+ return *pt;
+}
+
/******************************* Private *****************************************/
private:
@@ -4909,7 +4990,7 @@ Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
* Return:
* null if error, else RootObject AST as parsed
*/
-RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
+RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
{
OutBuffer buf;
if (expressionsToString(buf, sc, tm.exps))
@@ -4919,7 +5000,10 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
const len = buf.length;
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
- scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink);
+ const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
+ 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.vin;
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index 38a39b4..4f87d92 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -47,6 +47,7 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope
{
if (!global.params.useTypeInfo)
{
+ global.gag = 0;
if (e)
.error(loc, "expression `%s` uses the GC and cannot be used with switch `-betterC`", e.toChars());
else
diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d
index 8990ce4..7b059a0 100644
--- a/gcc/d/dmd/visitor.d
+++ b/gcc/d/dmd/visitor.d
@@ -89,6 +89,7 @@ public:
void visit(ASTCodegen.ClassReferenceExp e) { visit(cast(ASTCodegen.Expression)e); }
void visit(ASTCodegen.VoidInitExp e) { visit(cast(ASTCodegen.Expression)e); }
void visit(ASTCodegen.ThrownExceptionExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.LoweredAssignExp e) { visit(cast(ASTCodegen.AssignExp)e); }
}
/**
@@ -152,7 +153,7 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor
// need to avoid infinite recursion.
if (!(e.stageflags & stageToCBuffer))
{
- int old = e.stageflags;
+ const old = e.stageflags;
e.stageflags |= stageToCBuffer;
foreach (el; *e.elements)
if (el)
@@ -240,6 +241,12 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor
e.e1.accept(this);
e.e2.accept(this);
}
+
+ override void visit(ASTCodegen.LoweredAssignExp e)
+ {
+ e.lowering.accept(this);
+ visit(cast(AssignExp)e);
+ }
}
extern (C++) class StoppableVisitor : Visitor
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index ed9f9ce..3d8c3e6 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -17,7 +17,7 @@ class ErrorStatement;
class PeelStatement;
class ExpStatement;
class DtorExpStatement;
-class CompileStatement;
+class MixinStatement;
class CompoundStatement;
class CompoundDeclarationStatement;
class UnrolledLoopStatement;
@@ -110,7 +110,7 @@ class AnonDeclaration;
class PragmaDeclaration;
class ConditionalDeclaration;
class StaticIfDeclaration;
-class CompileDeclaration;
+class MixinDeclaration;
class StaticForeachDeclaration;
class UserAttributeDeclaration;
class ForwardingAttribDeclaration;
@@ -268,6 +268,7 @@ class UshrAssignExp;
class CatAssignExp;
class CatElemAssignExp;
class CatDcharAssignExp;
+class LoweredAssignExp;
class AddExp;
class MinExp;
class CatExp;
@@ -365,7 +366,7 @@ public:
virtual void visit(SharedStaticDtorDeclaration *s) { visit((StaticDtorDeclaration *)s); }
// AttribDeclarations
- virtual void visit(CompileDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(MixinDeclaration *s) { visit((AttribDeclaration *)s); }
virtual void visit(UserAttributeDeclaration *s) { visit((AttribDeclaration *)s); }
virtual void visit(LinkDeclaration *s) { visit((AttribDeclaration *)s); }
virtual void visit(AnonDeclaration *s) { visit((AttribDeclaration *)s); }
@@ -396,7 +397,7 @@ public:
virtual void visit(ReturnStatement *s) { visit((Statement *)s); }
virtual void visit(LabelStatement *s) { visit((Statement *)s); }
virtual void visit(StaticAssertStatement *s) { visit((Statement *)s); }
- virtual void visit(CompileStatement *s) { visit((Statement *)s); }
+ virtual void visit(MixinStatement *s) { visit((Statement *)s); }
virtual void visit(WhileStatement *s) { visit((Statement *)s); }
virtual void visit(ForStatement *s) { visit((Statement *)s); }
virtual void visit(DoStatement *s) { visit((Statement *)s); }
@@ -659,6 +660,7 @@ public:
virtual void visit(ClassReferenceExp *e) { visit((Expression *)e); }
virtual void visit(VoidInitExp *e) { visit((Expression *)e); }
virtual void visit(ThrownExceptionExp *e) { visit((Expression *)e); }
+ virtual void visit(LoweredAssignExp *e) { visit((AssignExp *)e); }
};
class StoppableVisitor : public Visitor
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index aeafe43..23f2f0b 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -693,78 +693,22 @@ public:
void visit (CatExp *e) final override
{
- Type *tb1 = e->e1->type->toBasetype ();
- Type *tb2 = e->e2->type->toBasetype ();
- Type *etype;
-
- if (tb1->ty == TY::Tarray || tb1->ty == TY::Tsarray)
- etype = tb1->nextOf ();
- else
- etype = tb2->nextOf ();
-
- tree result;
-
- if (e->e1->op == EXP::concatenate)
+ /* This error is only emitted during the code generation pass because
+ concatentation is allowed in CTFE. */
+ if (global.params.betterC)
{
- /* Flatten multiple concatenations to an array.
- So the expression ((a ~ b) ~ c) becomes [a, b, c] */
- int ndims = 2;
-
- for (Expression *ex = e->e1; ex->op == EXP::concatenate;)
- {
- if (ex->op == EXP::concatenate)
- {
- ex = ex->isCatExp ()->e1;
- ndims++;
- }
- }
-
- /* Store all concatenation args to a temporary byte[][ndims] array. */
- Type *targselem = Type::tint8->arrayOf ();
- tree var = build_local_temp (make_array_type (targselem, ndims));
-
- /* Loop through each concatenation from right to left. */
- vec <constructor_elt, va_gc> *elms = NULL;
- CatExp *ce = e;
- int dim = ndims - 1;
-
- for (Expression *oe = ce->e2; oe != NULL;
- (ce->e1->op != EXP::concatenate
- ? (oe = ce->e1)
- : (ce = ce->e1->isCatExp (), oe = ce->e2)))
- {
- tree arg = d_array_convert (etype, oe);
- tree index = size_int (dim);
- CONSTRUCTOR_APPEND_ELT (elms, index, d_save_expr (arg));
-
- /* Finished pushing all arrays. */
- if (oe == ce->e1)
- break;
-
- dim -= 1;
- }
-
- /* Check there is no logic bug in constructing byte[][] of arrays. */
- gcc_assert (dim == 0);
- tree init = build_constructor (TREE_TYPE (var), elms);
- var = compound_expr (modify_expr (var, init), var);
-
- tree arrs = d_array_value (build_ctype (targselem->arrayOf ()),
- size_int (ndims), build_address (var));
-
- result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2,
- build_typeinfo (e, e->type), arrs);
- }
- else
- {
- /* Handle single concatenation (a ~ b). */
- result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3,
- build_typeinfo (e, e->type),
- d_array_convert (etype, e->e1),
- d_array_convert (etype, e->e2));
+ error_at (make_location_t (e->loc),
+ "array concatenation of expression %qs requires the GC and "
+ "cannot be used with %<-fno-druntime%>", e->toChars ());
+ this->result_ = error_mark_node;
+ return;
}
- this->result_ = result;
+ /* All concat expressions should have been rewritten to `_d_arraycatnTX` in
+ the semantic phase. */
+ gcc_assert (e->lowering);
+
+ this->result_ = build_expr (e->lowering);
}
/* Build an assignment operator expression. The right operand is implicitly
@@ -1150,6 +1094,13 @@ public:
this->result_ = build_assign (modifycode, t1, t2);
}
+ /* Build an assignment expression that has been lowered in the front-end. */
+
+ void visit (LoweredAssignExp *e) final override
+ {
+ this->result_ = build_expr (e->lowering);
+ }
+
/* Build a throw expression. */
void visit (ThrowExp *e) final override
@@ -2828,7 +2779,7 @@ public:
/* Building sinit trees are delayed until after frontend semantic
processing has complete. Build the static initializer now. */
- if (e->useStaticInit && !this->constp_)
+ if (e->useStaticInit && !this->constp_ && !e->sd->isCsymbol ())
{
tree init = aggregate_initializer_decl (e->sd);
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
index 23f8b64..fd83cc9 100644
--- a/gcc/d/runtime.def
+++ b/gcc/d/runtime.def
@@ -112,13 +112,6 @@ DEF_D_RUNTIME (ALLOCMEMORY, "_d_allocmemory", RT(VOIDPTR), P1(SIZE_T),
DEF_D_RUNTIME (ARRAYCOPY, "_d_arraycopy", RT(ARRAY_VOID),
P3(SIZE_T, ARRAY_VOID, ARRAY_VOID), 0)
-/* Used for concatenating two or more arrays together. Then `n' variant is
- for when there is more than two arrays to handle. */
-DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE),
- P3(CONST_TYPEINFO, ARRAY_BYTE, ARRAY_BYTE), 0)
-DEF_D_RUNTIME (ARRAYCATNTX, "_d_arraycatnTX", RT(ARRAY_VOID),
- P2(CONST_TYPEINFO, ARRAYARRAY_BYTE), 0)
-
/* Used for appending a single element to an array. */
DEF_D_RUNTIME (ARRAYAPPENDCTX, "_d_arrayappendcTX", RT(ARRAY_BYTE),
P3(CONST_TYPEINFO, ARRAYPTR_BYTE, SIZE_T), 0)
diff --git a/gcc/testsuite/gdc.dg/nogc1.d b/gcc/testsuite/gdc.dg/nogc1.d
new file mode 100644
index 0000000..2894ef0
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/nogc1.d
@@ -0,0 +1,8 @@
+// { dg-do compile }
+// { dg-options "-fno-druntime" }
+// { dg-shouldfail "expressions depend on GC" }
+
+string testConcat(string a, string b)
+{
+ return a ~ b; // { dg-error "requires the GC and cannot be used with .-fno-druntime." }
+}
diff --git a/gcc/testsuite/gdc.dg/rtti1.d b/gcc/testsuite/gdc.dg/rtti1.d
index ed5f344..29b8265 100644
--- a/gcc/testsuite/gdc.dg/rtti1.d
+++ b/gcc/testsuite/gdc.dg/rtti1.d
@@ -11,8 +11,3 @@ bool testAAEqual(int[string] aa1, int[string] aa2)
{
return aa1 == aa2; // { dg-error "requires .object.TypeInfo. and cannot be used with .-fno-rtti." }
}
-
-string testConcat(string a, string b)
-{
- return a ~ b; // { dg-error "requires .object.TypeInfo. and cannot be used with .-fno-rtti." }
-}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d
index 870387c..0436371 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d
@@ -48,7 +48,7 @@ namespace nameSpace
extern void fn2();
}
- extern double identity(double _param_0);
+ extern double identity(double __param_0_);
}
---
@@ -63,5 +63,5 @@ extern(C++, "nameSpace")
void fn2() {}
}
- double identity(double) { return _param_0; }
+ double identity(double) { return __param_0; }
}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_functions.d b/gcc/testsuite/gdc.test/compilable/dtoh_functions.d
index 1feff40..38607f6 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_functions.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_functions.d
@@ -159,7 +159,7 @@ extern int32_t(*f)(int32_t );
extern void special(int32_t a = ptr->i, int32_t b = ptr->get(1, 2), int32_t j = (*f)(1));
-extern void variadic(int32_t _param_0, ...);
+extern void variadic(int32_t __param_0_, ...);
---
+/
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d
index b8e8d05..a8f5b99 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d
@@ -110,7 +110,7 @@ struct InvalidNames final
}
};
-extern void useInvalid(InvalidNames<int32_t > _param_0);
+extern void useInvalid(InvalidNames<int32_t > __param_0_);
extern size_t offsetof();
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d b/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d
index 37b4507..ee86a5e 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d
@@ -40,25 +40,25 @@ struct _d_dynamicArray final
#endif
enum class __c_not_special;
-extern "C" void fn_long(long _param_0);
+extern "C" void fn_long(long __param_0_);
-extern "C" void fn_ulong(unsigned long _param_0);
+extern "C" void fn_ulong(unsigned long __param_0_);
-extern "C" void fn_longlong(long long _param_0);
+extern "C" void fn_longlong(long long __param_0_);
-extern "C" void fn_ulonglong(unsigned long long _param_0);
+extern "C" void fn_ulonglong(unsigned long long __param_0_);
-extern "C" void fn_long_double(long double _param_0);
+extern "C" void fn_long_double(long double __param_0_);
-extern "C" void fn_wchar_t(wchar_t _param_0);
+extern "C" void fn_wchar_t(wchar_t __param_0_);
-extern "C" void fn_complex_float(_Complex float _param_0);
+extern "C" void fn_complex_float(_Complex float __param_0_);
-extern "C" void fn_complex_double(_Complex double _param_0);
+extern "C" void fn_complex_double(_Complex double __param_0_);
-extern "C" void fn_complex_real(_Complex long double _param_0);
+extern "C" void fn_complex_real(_Complex long double __param_0_);
-extern "C" void fn_not_special(__c_not_special _param_0);
+extern "C" void fn_not_special(__c_not_special __param_0_);
---
+/
diff --git a/gcc/testsuite/gdc.test/compilable/imports/c23789.i b/gcc/testsuite/gdc.test/compilable/imports/c23789.i
new file mode 100644
index 0000000..74d7e80
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/c23789.i
@@ -0,0 +1,31 @@
+// https://issues.dlang.org/show_bug.cgi?id=23789
+
+struct __declspec(align(64)) M128A {
+ char c;
+};
+
+typedef struct __declspec(align(32)) _M128B {
+ int x;
+} M128B, *PM128A;
+
+
+void testpl(p)
+struct __declspec(align(2)) S *p;
+{
+}
+
+/////
+
+struct __attribute__((aligned(64))) N128A {
+ char c;
+};
+
+typedef struct __attribute__((aligned(32))) _N128B {
+ int x;
+} N128B, *PN128A;
+
+
+void testpl2(p)
+struct __attribute__((aligned(2))) S *p;
+{
+}
diff --git a/gcc/testsuite/gdc.test/compilable/interpret3.d b/gcc/testsuite/gdc.test/compilable/interpret3.d
index 2c9a84e..1414263 100644
--- a/gcc/testsuite/gdc.test/compilable/interpret3.d
+++ b/gcc/testsuite/gdc.test/compilable/interpret3.d
@@ -7208,7 +7208,7 @@ struct S13630(T)
{
T[3] arr;
- this(A...)(auto ref in A args)
+ this(A...)(const auto ref A args)
{
auto p = arr.ptr;
@@ -7238,7 +7238,7 @@ struct Matrix13827(T, uint N)
T[N] flat;
}
- this(A...)(auto ref in A args)
+ this(A...)(const auto ref A args)
{
uint k;
diff --git a/gcc/testsuite/gdc.test/compilable/test18493.d b/gcc/testsuite/gdc.test/compilable/test18493.d
new file mode 100644
index 0000000..558bf44
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18493.d
@@ -0,0 +1,19 @@
+// https://issues.dlang.org/show_bug.cgi?id=18493
+// REQUIRED_ARGS: -betterC
+
+struct S
+{
+ this(this)
+ {
+ }
+
+ ~this()
+ {
+ }
+}
+
+struct C
+{
+ S s1;
+ S s2;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19688.d b/gcc/testsuite/gdc.test/compilable/test19688.d
index 9cc4dd7..9cc4dd7 100644
--- a/gcc/testsuite/gdc.test/runnable/test19688.d
+++ b/gcc/testsuite/gdc.test/compilable/test19688.d
diff --git a/gcc/testsuite/gdc.test/compilable/test21667.d b/gcc/testsuite/gdc.test/compilable/test21667.d
new file mode 100644
index 0000000..6d83dc0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21667.d
@@ -0,0 +1,19 @@
+// Issue 21667 - scope parameter causes 'no size because of forward references'
+// https://issues.dlang.org/show_bug.cgi?id=21667
+@safe:
+
+struct Foo
+{
+ void delegate(scope Foo) dg;
+}
+
+struct M
+{
+ F.Type f;
+}
+
+struct F
+{
+ enum Type {a}
+ void foo(scope M m) {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test23789.d b/gcc/testsuite/gdc.test/compilable/test23789.d
new file mode 100644
index 0000000..ddf7351
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test23789.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=23789
+// EXTRA_FILES: imports/c23789.i
+
+import imports.c23789;
+
+static assert(M128A.alignof == 64);
+static assert(_M128B.alignof == 32);
+static assert(M128B.alignof == 32);
+
+static assert(N128A.alignof == 64);
+static assert(_N128B.alignof == 32);
+static assert(N128B.alignof == 32);
diff --git a/gcc/testsuite/gdc.test/compilable/test23862.d b/gcc/testsuite/gdc.test/compilable/test23862.d
new file mode 100644
index 0000000..c5b063b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test23862.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=23862
+
+enum E { A, B }
+
+void test(E e)
+{
+ with (e)
+ switch (e)
+ {
+ case A:
+ case B:
+ default:
+ break;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test23863.d b/gcc/testsuite/gdc.test/compilable/test23863.d
new file mode 100644
index 0000000..c3941ce
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test23863.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=23863
+
+alias AliasSeq(T...) = T;
+
+struct S
+{
+}
+alias Empty = S.tupleof;
+Empty x; // accepts valid
+
+static assert(is(typeof(x)));
+static assert(is(typeof(Empty)));
+static assert(is(typeof(AliasSeq!(int))));
+static assert(is(typeof(Empty) == AliasSeq!()));
+static assert(is(typeof(AliasSeq!()) == AliasSeq!()));
diff --git a/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d b/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d
index 1f25b26..f4defb4 100644
--- a/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d
+++ b/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d
@@ -1,9 +1,10 @@
module traits_getFunctionAttributes;
+alias tuple(T...) = T;
+
void test_getFunctionAttributes()
{
- alias tuple(T...) = T;
struct S
{
@@ -118,3 +119,14 @@ void test_getFunctionAttributes()
static assert(__traits(getFunctionAttributes, systemDel) == tuple!("pure", "nothrow", "@nogc", "@system"));
static assert(__traits(getFunctionAttributes, typeof(systemDel)) == tuple!("pure", "nothrow", "@nogc", "@system"));
}
+
+void bug19706()
+{
+ struct S
+ {
+ static int fImpl(Ret)() { return Ret.init; }
+
+ // tells us: `fImpl!int` is @system
+ static assert(__traits(getFunctionAttributes, fImpl!int) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/user_defined_attributes.d b/gcc/testsuite/gdc.test/compilable/user_defined_attributes.d
new file mode 100644
index 0000000..169ca49
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/user_defined_attributes.d
@@ -0,0 +1,22 @@
+
+enum Test;
+
+@true @null @byte int x;
+@(int) int y;
+@"test" @`test2` @30 @'a' @__LINE__ void f();
+
+@Test void h();
+
+static assert( __traits(getAttributes, x)[0] == true);
+static assert( __traits(getAttributes, x)[1] == null);
+static assert(is(__traits(getAttributes, x)[2] == byte));
+
+static assert(is(__traits(getAttributes, y)[0] == int));
+
+static assert( __traits(getAttributes, f)[0] == "test");
+static assert( __traits(getAttributes, f)[1] == "test2");
+static assert( __traits(getAttributes, f)[2] == 30);
+static assert( __traits(getAttributes, f)[3] == 'a');
+static assert( __traits(getAttributes, f)[4] == 6);
+
+static assert(is(__traits(getAttributes, h)[0] == enum));
diff --git a/gcc/testsuite/gdc.test/compilable/warn3882.d b/gcc/testsuite/gdc.test/compilable/warn3882.d
index f02a87b..0474315 100644
--- a/gcc/testsuite/gdc.test/compilable/warn3882.d
+++ b/gcc/testsuite/gdc.test/compilable/warn3882.d
@@ -12,7 +12,7 @@ void test3882()
/******************************************/
// https://issues.dlang.org/show_bug.cgi?id=12619
-extern (C) @system nothrow pure void* memcpy(void* s1, in void* s2, size_t n);
+extern (C) @system nothrow pure void* memcpy(void* s1, const void* s2, size_t n);
// -> weakly pure
void test12619() pure
@@ -64,7 +64,7 @@ void test12909()
const struct Foo13899
{
- int opApply(immutable int delegate(in ref int) pure nothrow dg) pure nothrow
+ int opApply(immutable int delegate(const ref int) pure nothrow dg) pure nothrow
{
return 1;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d
index 8360e1a..523a183 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d
@@ -4,15 +4,15 @@ TEST_OUTPUT:
fail_compilation/attributediagnostic.d(24): Error: `@safe` function `attributediagnostic.layer2` cannot call `@system` function `attributediagnostic.layer1`
fail_compilation/attributediagnostic.d(26): which calls `attributediagnostic.layer0`
fail_compilation/attributediagnostic.d(28): which calls `attributediagnostic.system`
-fail_compilation/attributediagnostic.d(30): which was inferred `@system` because of:
+fail_compilation/attributediagnostic.d(30): which wasn't inferred `@safe` because of:
fail_compilation/attributediagnostic.d(30): `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not
fail_compilation/attributediagnostic.d(25): `attributediagnostic.layer1` is declared here
fail_compilation/attributediagnostic.d(46): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system1`
-fail_compilation/attributediagnostic.d(35): which was inferred `@system` because of:
+fail_compilation/attributediagnostic.d(35): which wasn't inferred `@safe` because of:
fail_compilation/attributediagnostic.d(35): cast from `uint` to `int*` not allowed in safe code
fail_compilation/attributediagnostic.d(33): `attributediagnostic.system1` is declared here
fail_compilation/attributediagnostic.d(47): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system2`
-fail_compilation/attributediagnostic.d(41): which was inferred `@system` because of:
+fail_compilation/attributediagnostic.d(41): which wasn't inferred `@safe` because of:
fail_compilation/attributediagnostic.d(41): `@safe` function `system2` cannot call `@system` `fsys`
fail_compilation/attributediagnostic.d(39): `attributediagnostic.system2` is declared here
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nogc.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nogc.d
new file mode 100644
index 0000000..e3dbee8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nogc.d
@@ -0,0 +1,56 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/attributediagnostic_nogc.d(21): Error: `@nogc` function `attributediagnostic_nogc.layer2` cannot call non-@nogc function `attributediagnostic_nogc.layer1`
+fail_compilation/attributediagnostic_nogc.d(22): which calls `attributediagnostic_nogc.layer0`
+fail_compilation/attributediagnostic_nogc.d(23): which calls `attributediagnostic_nogc.gc`
+fail_compilation/attributediagnostic_nogc.d(27): which wasn't inferred `@nogc` because of:
+fail_compilation/attributediagnostic_nogc.d(27): `asm` statement in function `attributediagnostic_nogc.gc` is assumed to use the GC - mark it with `@nogc` if it does not
+fail_compilation/attributediagnostic_nogc.d(43): Error: `@nogc` function `D main` cannot call non-@nogc function `attributediagnostic_nogc.gc1`
+fail_compilation/attributediagnostic_nogc.d(32): which wasn't inferred `@nogc` because of:
+fail_compilation/attributediagnostic_nogc.d(32): cannot use `new` in `@nogc` function `attributediagnostic_nogc.gc1`
+fail_compilation/attributediagnostic_nogc.d(44): Error: `@nogc` function `D main` cannot call non-@nogc function `attributediagnostic_nogc.gc2`
+fail_compilation/attributediagnostic_nogc.d(38): which wasn't inferred `@nogc` because of:
+fail_compilation/attributediagnostic_nogc.d(38): `@nogc` function `attributediagnostic_nogc.gc2` cannot call non-@nogc `fgc`
+fail_compilation/attributediagnostic_nogc.d(45): Error: `@nogc` function `D main` cannot call non-@nogc function `attributediagnostic_nogc.gcClosure`
+fail_compilation/attributediagnostic_nogc.d(48): which wasn't inferred `@nogc` because of:
+fail_compilation/attributediagnostic_nogc.d(48): function `attributediagnostic_nogc.gcClosure` is `@nogc` yet allocates closure for `gcClosure()` with the GC
+---
+*/
+#line 18
+// Issue 17374 - Improve inferred attribute error message
+// https://issues.dlang.org/show_bug.cgi?id=17374
+
+auto layer2() @nogc { layer1(); }
+auto layer1() { layer0(); }
+auto layer0() { gc(); }
+
+auto gc()
+{
+ asm {}
+}
+
+auto gc1()
+{
+ int* x = new int;
+}
+
+auto fgc = function void() {new int[10];};
+auto gc2()
+{
+ fgc();
+}
+
+void main() @nogc
+{
+ gc1();
+ gc2();
+ gcClosure();
+}
+
+auto gcClosure()
+{
+ int x;
+ int bar() { return x; }
+ return &bar;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nothrow.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nothrow.d
new file mode 100644
index 0000000..7fea322
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nothrow.d
@@ -0,0 +1,45 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/attributediagnostic_nothrow.d(21): Error: function `attributediagnostic_nothrow.layer1` is not `nothrow`
+fail_compilation/attributediagnostic_nothrow.d(22): which calls `attributediagnostic_nothrow.layer0`
+fail_compilation/attributediagnostic_nothrow.d(23): which calls `attributediagnostic_nothrow.gc`
+fail_compilation/attributediagnostic_nothrow.d(27): which wasn't inferred `nothrow` because of:
+fail_compilation/attributediagnostic_nothrow.d(27): `asm` statement is assumed to throw - mark it with `nothrow` if it does not
+fail_compilation/attributediagnostic_nothrow.d(21): Error: function `attributediagnostic_nothrow.layer2` may throw but is marked as `nothrow`
+fail_compilation/attributediagnostic_nothrow.d(43): Error: function `attributediagnostic_nothrow.gc1` is not `nothrow`
+fail_compilation/attributediagnostic_nothrow.d(32): which wasn't inferred `nothrow` because of:
+fail_compilation/attributediagnostic_nothrow.d(32): `object.Exception` is thrown but not caught
+fail_compilation/attributediagnostic_nothrow.d(44): Error: function `attributediagnostic_nothrow.gc2` is not `nothrow`
+fail_compilation/attributediagnostic_nothrow.d(41): Error: function `D main` may throw but is marked as `nothrow`
+---
+*/
+
+// Issue 17374 - Improve inferred attribute error message
+// https://issues.dlang.org/show_bug.cgi?id=17374
+
+auto layer2() nothrow { layer1(); }
+auto layer1() { layer0(); }
+auto layer0() { gc(); }
+
+auto gc()
+{
+ asm {}
+}
+
+auto gc1()
+{
+ throw new Exception("msg");
+}
+
+auto fgc = function void() {throw new Exception("msg");};
+auto gc2()
+{
+ fgc();
+}
+
+void main() nothrow
+{
+ gc1();
+ gc2();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_pure.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_pure.d
new file mode 100644
index 0000000..a120dab
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_pure.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/attributediagnostic_pure.d(20): Error: `pure` function `D main` cannot call impure function `attributediagnostic_pure.gc`
+fail_compilation/attributediagnostic_pure.d(15): which wasn't inferred `pure` because of:
+fail_compilation/attributediagnostic_pure.d(15): `asm` statement is assumed to be impure - mark it with `pure` if it is not
+---
+*/
+
+// Issue 17374 - Improve inferred attribute error message
+// https://issues.dlang.org/show_bug.cgi?id=17374
+
+auto gc()
+{
+ asm {}
+}
+
+void main() pure
+{
+ gc();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
index c980d76..802d1c2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
@@ -66,8 +66,8 @@ fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is n
fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s`
fail_compilation/bug9631.d(80): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)`
fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s`
-fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S _param_0)` is not callable using argument types `(S)`
-fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S _param_0`
+fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)`
+fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0`
---
*/
void arg()
@@ -89,8 +89,8 @@ void arg()
/*
TEST_OUTPUT:
---
-fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S _param_0)` is not callable using argument types `(S)`
-fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S _param_0`
+fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S __param_0)` is not callable using argument types `(S)`
+fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0`
fail_compilation/bug9631.d(107): Error: none of the overloads of template `bug9631.targ.ft` are callable using argument types `!()(S)`
fail_compilation/bug9631.d(105): Candidate is: `ft()(tem!().S)`
fail_compilation/bug9631.d(109): Error: none of the overloads of template `bug9631.targ.ft2` are callable using argument types `!()(S, int)`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d b/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d
index 2d8bf7a..9c90103 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d
@@ -19,7 +19,7 @@ struct T { }
{
L1:
new T();
- a = 3;
+ a = 3;
}
goto L1;
}
@@ -31,3 +31,14 @@ L1:
new T();
}
}
+
+@nogc void test3()
+{
+ if (!__ctfe)
+ {
+ }
+ else
+ {
+ int* p = new int;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecatedinref.d b/gcc/testsuite/gdc.test/fail_compilation/deprecatedinref.d
new file mode 100644
index 0000000..20c3666
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecatedinref.d
@@ -0,0 +1,10 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/deprecatedinref.d(9): Deprecation: using `in ref` is deprecated, use `-preview=in` and `in` instead
+fail_compilation/deprecatedinref.d(10): Deprecation: using `ref in` is deprecated, use `-preview=in` and `in` instead
+---
+*/
+void foo(in ref int);
+void foor(ref in int);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecations_preview_in.d b/gcc/testsuite/gdc.test/fail_compilation/deprecations_preview_in.d
new file mode 100644
index 0000000..33cc904
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecations_preview_in.d
@@ -0,0 +1,11 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/deprecations_preview_in.d(1): Deprecation: using `in` parameters with `extern(C)` functions is deprecated
+fail_compilation/deprecations_preview_in.d(1): parameter `__anonymous_param` declared as `in` here
+---
+*/
+
+#line 1
+extern(C) void fun1(in char*);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
index 7b2eca7..efc818f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
@@ -1,17 +1,21 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10319.d(29): Error: `pure` function `D main` cannot call impure function `diag10319.foo`
-fail_compilation/diag10319.d(29): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo`
-fail_compilation/diag10319.d(18): `diag10319.foo` is declared here
-fail_compilation/diag10319.d(30): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar`
-fail_compilation/diag10319.d(30): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar`
-fail_compilation/diag10319.d(23): which was inferred `@system` because of:
-fail_compilation/diag10319.d(23): cannot take address of local `x` in `@safe` function `bar`
-fail_compilation/diag10319.d(20): `diag10319.bar!int.bar` is declared here
-fail_compilation/diag10319.d(29): Error: function `diag10319.foo` is not `nothrow`
-fail_compilation/diag10319.d(30): Error: function `diag10319.bar!int.bar` is not `nothrow`
-fail_compilation/diag10319.d(27): Error: function `D main` may throw but is marked as `nothrow`
+fail_compilation/diag10319.d(33): Error: `pure` function `D main` cannot call impure function `diag10319.foo`
+fail_compilation/diag10319.d(33): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo`
+fail_compilation/diag10319.d(22): `diag10319.foo` is declared here
+fail_compilation/diag10319.d(34): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar`
+fail_compilation/diag10319.d(26): which wasn't inferred `pure` because of:
+fail_compilation/diag10319.d(26): `pure` function `diag10319.bar!int.bar` cannot access mutable static data `g`
+fail_compilation/diag10319.d(34): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar`
+fail_compilation/diag10319.d(27): which wasn't inferred `@safe` because of:
+fail_compilation/diag10319.d(27): cannot take address of local `x` in `@safe` function `bar`
+fail_compilation/diag10319.d(24): `diag10319.bar!int.bar` is declared here
+fail_compilation/diag10319.d(33): Error: function `diag10319.foo` is not `nothrow`
+fail_compilation/diag10319.d(34): Error: function `diag10319.bar!int.bar` is not `nothrow`
+fail_compilation/diag10319.d(28): which wasn't inferred `nothrow` because of:
+fail_compilation/diag10319.d(28): `object.Exception` is thrown but not caught
+fail_compilation/diag10319.d(31): Error: function `D main` may throw but is marked as `nothrow`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
index 1fde171..207f6a4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
@@ -3,7 +3,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(18): `diag10415.C.x(int _param_0)`
+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/gcc/testsuite/gdc.test/fail_compilation/diag11769.d b/gcc/testsuite/gdc.test/fail_compilation/diag11769.d
index 2717de4..75047f5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag11769.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag11769.d
@@ -2,9 +2,9 @@
TEST_OUTPUT:
---
fail_compilation/diag11769.d(18): Error: `diag11769.foo!string.bar` called with argument types `(string)` matches both:
-fail_compilation/diag11769.d(13): `diag11769.foo!string.bar(wstring _param_0)`
+fail_compilation/diag11769.d(13): `diag11769.foo!string.bar(wstring __param_0)`
and:
-fail_compilation/diag11769.d(14): `diag11769.foo!string.bar(dstring _param_0)`
+fail_compilation/diag11769.d(14): `diag11769.foo!string.bar(dstring __param_0)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14818.d b/gcc/testsuite/gdc.test/fail_compilation/diag14818.d
index f9b535a..6147f32 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag14818.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14818.d
@@ -2,8 +2,8 @@
TEST_OUTPUT:
---
fail_compilation/diag14818.d(40): Error: none of the overloads of `func` are callable using argument types `(string)`
-fail_compilation/diag14818.d(18): Candidates are: `diag14818.foo(int _param_0)`
-fail_compilation/diag14818.d(19): `diag14818.bar(double _param_0)`
+fail_compilation/diag14818.d(18): Candidates are: `diag14818.foo(int __param_0)`
+fail_compilation/diag14818.d(19): `diag14818.bar(double __param_0)`
fail_compilation/diag14818.d(41): Error: template instance `diag14818.X!string` does not match any template declaration
fail_compilation/diag14818.d(41): Candidates are:
fail_compilation/diag14818.d(24): Foo(T) if (is(T == int))
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d
new file mode 100644
index 0000000..a314561
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=20268
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag20268.d(12): Error: none of the overloads of template `diag20268.__lambda4` are callable using argument types `!()(int)`
+fail_compilation/diag20268.d(11): Candidate is: `__lambda4(__T1, __T2)(x, y)`
+---
+*/
+
+alias f = (x,y) => true;
+auto x = f(1);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
index bc0ee9d..a55ef73 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
@@ -2,13 +2,13 @@
TEST_OUTPUT:
---
fail_compilation/diag8101b.d(28): Error: none of the overloads of `foo` are callable using argument types `(double)`
-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(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(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(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(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(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
fail_compilation/diag8101b.d(22): Consider adding `const` or `inout` here
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9312.d b/gcc/testsuite/gdc.test/fail_compilation/diag9312.d
index 94e3d3f..9830813 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9312.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9312.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9312.d(10): Error: `with` expressions must be aggregate types or pointers to them, not `int`
+fail_compilation/diag9312.d(10): Error: `with` expression types must be enums or aggregates or pointers to them, not `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9620.d b/gcc/testsuite/gdc.test/fail_compilation/diag9620.d
index d99290c..4af87df 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9620.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9620.d
@@ -1,8 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9620.d(18): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo1`
-fail_compilation/diag9620.d(19): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo2!().foo2`
+fail_compilation/diag9620.d(20): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo1`
+fail_compilation/diag9620.d(21): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo2!().foo2`
+fail_compilation/diag9620.d(14): which wasn't inferred `pure` because of:
+fail_compilation/diag9620.d(14): `pure` function `diag9620.foo2!().foo2` cannot access mutable static data `x`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
index b990ced..c93a06a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9831.d(13): Error: function `diag9831.main.__lambda3` cannot access variable `c` in frame of function `D main`
+fail_compilation/diag9831.d(13): Error: function `diag9831.main.__lambda3(__T1)(x)` cannot access variable `c` in frame of function `D main`
fail_compilation/diag9831.d(11): `c` declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
index bf51363..6117439 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
@@ -3,11 +3,11 @@ REQUIRED_ARGS: -de
TEST_OUTPUT:
---
fail_compilation/dip1000_deprecation.d(20): Deprecation: `@safe` function `main` calling `inferred`
-fail_compilation/dip1000_deprecation.d(28): which would be `@system` because of:
+fail_compilation/dip1000_deprecation.d(28): which wouldn't be `@safe` because of:
fail_compilation/dip1000_deprecation.d(28): scope variable `x0` may not be returned
fail_compilation/dip1000_deprecation.d(22): Deprecation: `@safe` function `main` calling `inferredC`
fail_compilation/dip1000_deprecation.d(39): which calls `dip1000_deprecation.inferred`
-fail_compilation/dip1000_deprecation.d(28): which would be `@system` because of:
+fail_compilation/dip1000_deprecation.d(28): which wouldn't be `@safe` because of:
fail_compilation/dip1000_deprecation.d(28): scope variable `x0` may not be returned
fail_compilation/dip1000_deprecation.d(54): Deprecation: escaping reference to stack allocated value returned by `S(null)`
fail_compilation/dip1000_deprecation.d(55): Deprecation: escaping reference to stack allocated value returned by `createS()`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d
index ce81d6b..21a12ed 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d
@@ -8,8 +8,6 @@ fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is impu
fail_compilation/dtor_attributes.d(111): - HasDtor member
fail_compilation/dtor_attributes.d(103): impure `HasDtor.~this` is declared here
fail_compilation/dtor_attributes.d(118): Error: `@safe` function `dtor_attributes.test1` cannot call `@system` destructor `dtor_attributes.Strict.~this`
-fail_compilation/dtor_attributes.d(113): which calls `dtor_attributes.Strict.~this`
-fail_compilation/dtor_attributes.d(103): which calls `dtor_attributes.HasDtor.~this`
fail_compilation/dtor_attributes.d(113): `dtor_attributes.Strict.~this` is declared here
fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is @system because of the following field's destructors:
fail_compilation/dtor_attributes.d(111): - HasDtor member
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d
index 45b23ce..f6cab89 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d
@@ -9,7 +9,6 @@ fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` i
fail_compilation/dtorfields_attributes.d(115): - HasDtor member
fail_compilation/dtorfields_attributes.d(103): impure `HasDtor.~this` is declared here
fail_compilation/dtorfields_attributes.d(117): Error: `@safe` constructor `dtorfields_attributes.Strict.this` cannot call `@system` destructor `dtorfields_attributes.Strict.~this`
-fail_compilation/dtorfields_attributes.d(103): which calls `dtorfields_attributes.HasDtor.~this`
fail_compilation/dtorfields_attributes.d(119): `dtorfields_attributes.Strict.~this` is declared here
fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` is @system because of the following field's destructors:
fail_compilation/dtorfields_attributes.d(115): - HasDtor member
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d
index cfda8f4..a436197 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d
@@ -8,10 +8,14 @@ fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot
fail_compilation/fail10968.d(44): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here
fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.arrayassign._d_arraysetassign!(SA[], SA)._d_arraysetassign`
+$p:druntime/import/core/internal/array/arrayassign.d$($n$): which calls `core.lifetime.copyEmplace!(SA, SA).copyEmplace`
+$p:druntime/import/core/lifetime.d$($n$): which calls `fail10968.SA.__postblit`
fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(45): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here
fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.arrayassign._d_arrayassign_l!(SA[], SA)._d_arrayassign_l`
+$p:druntime/import/core/internal/array/arrayassign.d$-mixin-$n$($n$): which calls `core.lifetime.copyEmplace!(SA, SA).copyEmplace`
+$p:druntime/import/core/lifetime.d$($n$): which calls `fail10968.SA.__postblit`
fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(48): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here
@@ -19,13 +23,18 @@ fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot
fail_compilation/fail10968.d(49): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here
fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor`
+$p:druntime/import/core/internal/array/construction.d$($n$): which calls `core.lifetime.copyEmplace!(SA, SA).copyEmplace`
+$p:druntime/import/core/lifetime.d$($n$): which calls `fail10968.SA.__postblit`
fail_compilation/fail10968.d(50): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(50): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here
fail_compilation/fail10968.d(50): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor`
+$p:druntime/import/core/internal/array/construction.d$($n$): which calls `core.lifetime.copyEmplace!(SA, SA).copyEmplace`
+$p:druntime/import/core/lifetime.d$($n$): which calls `fail10968.SA.__postblit`
---
*/
+#line 29
struct SA
{
this(this)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
index 7592a5a..cabf87a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
@@ -1,8 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11375.d(17): Error: constructor `fail11375.D!().D.this` is not `nothrow`
-fail_compilation/fail11375.d(15): Error: function `D main` may throw but is marked as `nothrow`
+fail_compilation/fail11375.d(18): Error: constructor `fail11375.D!().D.this` is not `nothrow`
+ which calls `fail11375.B.this`
+fail_compilation/fail11375.d(16): Error: function `D main` may throw but is marked as `nothrow`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
index 738864c..824f5e4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
@@ -7,7 +7,7 @@ fail_compilation/fail12236.d(21): Error: forward reference to inferred return ty
fail_compilation/fail12236.d(21): while evaluating `pragma(msg, f2(T)(T).mangleof)`
fail_compilation/fail12236.d(27): Error: template instance `fail12236.f2!int` error instantiating
fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function `__lambda1`
-fail_compilation/fail12236.d(31): while evaluating `pragma(msg, __lambda1.mangleof)`
+fail_compilation/fail12236.d(31): while evaluating `pragma(msg, __lambda1(__T1)(a).mangleof)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
index f1cf340..6a1335e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
@@ -17,13 +17,13 @@ void g1(char[] s) pure @nogc
TEST_OUTPUT:
---
fail_compilation/fail13120.d(35): Error: `pure` function `fail13120.h2` cannot call impure function `fail13120.g2!().g2`
+fail_compilation/fail13120.d(30): which calls `fail13120.f2`
fail_compilation/fail13120.d(35): Error: `@safe` function `fail13120.h2` cannot call `@system` function `fail13120.g2!().g2`
fail_compilation/fail13120.d(27): `fail13120.g2!().g2` is declared here
fail_compilation/fail13120.d(35): Error: `@nogc` function `fail13120.h2` cannot call non-@nogc function `fail13120.g2!().g2`
---
*/
void f2() {}
-
void g2()(char[] s)
{
foreach (dchar dc; s)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13577.d b/gcc/testsuite/gdc.test/fail_compilation/fail13577.d
new file mode 100644
index 0000000..79f9068
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13577.d
@@ -0,0 +1,28 @@
+// https://issues.dlang.org/show_bug.cgi?id=13577
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail13577.d(27): Error: cannot implicilty convert range element of type `int[]` to variable `x` of type `immutable(int[])`
+---
+*/
+
+struct Tuple(Types...)
+{
+ Types items;
+ alias items this;
+}
+
+struct Range(T)
+{
+ T[] arr;
+ alias ElemType = Tuple!(int, T);
+ ElemType front() { return typeof(return)(0, arr[0]); }
+ bool empty() { return false; }
+ void popFront() {}
+}
+
+void main()
+{
+ foreach (immutable i, immutable x; Range!(int[])()) {} // Error
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16600.d b/gcc/testsuite/gdc.test/fail_compilation/fail16600.d
index eb341c6..3bd600e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail16600.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail16600.d
@@ -1,9 +1,9 @@
/* TEST_OUTPUT:
---
fail_compilation/fail16600.d(22): Error: `fail16600.S.__ctor` called with argument types `(string) const` matches both:
-fail_compilation/fail16600.d(16): `fail16600.S.this(string _param_0)`
+fail_compilation/fail16600.d(16): `fail16600.S.this(string __param_0)`
and:
-fail_compilation/fail16600.d(17): `fail16600.S.this(string _param_0) immutable`
+fail_compilation/fail16600.d(17): `fail16600.S.this(string __param_0) immutable`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17518.d b/gcc/testsuite/gdc.test/fail_compilation/fail17518.d
index 385483c..cf2648d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17518.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17518.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail17518.d(21): Error: constructor `fail17518.S.this(inout(Correct) _param_0) inout` is not callable using argument types `(Wrong)`
-fail_compilation/fail17518.d(21): cannot pass argument `Wrong()` of type `Wrong` to parameter `inout(Correct) _param_0`
+fail_compilation/fail17518.d(21): Error: constructor `fail17518.S.this(inout(Correct) __param_0) inout` is not callable using argument types `(Wrong)`
+fail_compilation/fail17518.d(21): cannot pass argument `Wrong()` of type `Wrong` to parameter `inout(Correct) __param_0`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17955.d b/gcc/testsuite/gdc.test/fail_compilation/fail17955.d
index 95eb5cc..0832919 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17955.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17955.d
@@ -11,7 +11,7 @@ fail_compilation/fail17955.d(49): instantiated from here: `toRedis!(SysTi
fail_compilation/fail17955.d(40): ... (2 instantiations, -v to show) ...
fail_compilation/fail17955.d(32): instantiated from here: `indicesOf!(isRedisType, resetCodeExpireTime)`
fail_compilation/fail17955.d(67): instantiated from here: `RedisStripped!(User, true)`
-fail_compilation/fail17955.d(93): Error: need `this` for `fromISOExtString` of type `pure nothrow @nogc @safe immutable(SimpleTimeZone)(dstring _param_0)`
+fail_compilation/fail17955.d(93): Error: need `this` for `fromISOExtString` of type `pure nothrow @nogc @safe immutable(SimpleTimeZone)(dstring __param_0)`
fail_compilation/fail17955.d(95): Error: undefined identifier `DateTimeException`
fail_compilation/fail17955.d(25): Error: variable `fail17955.isISOExtStringSerializable!(SysTime).isISOExtStringSerializable` - type `void` is inferred from initializer `fromISOExtString("")`, and variables cannot be of type `void`
fail_compilation/fail17955.d(54): Error: function `fail17955.toRedis!(SysTime).toRedis` has no `return` statement, but is expected to return a value of type `string`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail196.d b/gcc/testsuite/gdc.test/fail_compilation/fail196.d
index 2c7d93f..53505f4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail196.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail196.d
@@ -6,15 +6,15 @@ fail_compilation/fail196.d(27): Error: implicit string concatenation is error-pr
fail_compilation/fail196.d(27): Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\n assert(s == "
fail_compilation/fail196.d(28): Error: semicolon needed to end declaration of `s`, instead of `foo`
fail_compilation/fail196.d(27): `s` declared here
-fail_compilation/fail196.d(28): Error: found `");\n\n s = q"` when expecting `;` following statement
-fail_compilation/fail196.d(30): Error: found `";\n assert(s == "` when expecting `;` following statement
-fail_compilation/fail196.d(31): Error: found `");\n\n s = q"` when expecting `;` following statement
-fail_compilation/fail196.d(33): Error: found `{` when expecting `;` following statement
-fail_compilation/fail196.d(33): Error: found `}` when expecting `;` following statement
-fail_compilation/fail196.d(34): Error: found `foo` when expecting `;` following statement
-fail_compilation/fail196.d(34): Error: found `}` when expecting `;` following statement
-fail_compilation/fail196.d(36): Error: found `<` when expecting `;` following statement
-fail_compilation/fail196.d(37): Error: found `foo` when expecting `;` following statement
+fail_compilation/fail196.d(28): Error: found `");\n\n s = q"` when expecting `;` following statement `foo(xxx)` on line fail_compilation/fail196.d(28)
+fail_compilation/fail196.d(30): Error: found `";\n assert(s == "` when expecting `;` following statement `[foo[xxx]]` on line fail_compilation/fail196.d(30)
+fail_compilation/fail196.d(31): Error: found `");\n\n s = q"` when expecting `;` following statement `foo[xxx]` on line fail_compilation/fail196.d(31)
+fail_compilation/fail196.d(33): Error: found `{` when expecting `;` following statement `foo` on line fail_compilation/fail196.d(33)
+fail_compilation/fail196.d(33): Error: found `}` when expecting `;` following statement `xxx` on line fail_compilation/fail196.d(33)
+fail_compilation/fail196.d(34): Error: found `foo` when expecting `;` following statement `";\n assert(s == "` on line fail_compilation/fail196.d(33)
+fail_compilation/fail196.d(34): Error: found `}` when expecting `;` following statement `xxx` on line fail_compilation/fail196.d(34)
+fail_compilation/fail196.d(36): Error: found `<` when expecting `;` following statement `");\n\n s = q" < foo` on line fail_compilation/fail196.d(34)
+fail_compilation/fail196.d(37): Error: found `foo` when expecting `;` following statement `xxx >> ";\n assert(s == "` on line fail_compilation/fail196.d(36)
fail_compilation/fail196.d(37): Error: found `<` instead of statement
fail_compilation/fail196.d(43): Error: unterminated string constant starting at fail_compilation/fail196.d(43)
fail_compilation/fail196.d(45): Error: found `End of File` when expecting `}` following compound statement
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d
index e8a9e77..ae67443 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d
@@ -1,5 +1,5 @@
// https://issues.dlang.org/show_bug.cgi?id=19948
-
+// DISABLED: win32
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20609.d b/gcc/testsuite/gdc.test/fail_compilation/fail20609.d
index 05b7c85..80a5d46 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail20609.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20609.d
@@ -4,7 +4,7 @@
fail_compilation/fail20609.d(26): Error: none of the overloads of `this` are callable using argument types `(int)`
fail_compilation/fail20609.d(23): Candidate is: `fail20609.Foo.this(string[] args)`
fail_compilation/fail20609.d(27): Error: none of the overloads of `this` are callable using argument types `(int)`
-fail_compilation/fail20609.d(22): Candidates are: `fail20609.Foo.this(Object _param_0)`
+fail_compilation/fail20609.d(22): Candidates are: `fail20609.Foo.this(Object __param_0)`
fail_compilation/fail20609.d(23): `fail20609.Foo.this(string[] args)`
fail_compilation/fail20609.d(37): Error: none of the overloads of `this` are callable using argument types `(int)`
fail_compilation/fail20609.d(37): All possible candidates are marked as `deprecated` or `@disable`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d
index 167d362..d865fd9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d
@@ -3,7 +3,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy _param_0)` is not callable using argument types `(SystemCopy)`
+fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy __param_0)` is not callable using argument types `(SystemCopy)`
fail_compilation/fail22202.d(21): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23773.d b/gcc/testsuite/gdc.test/fail_compilation/fail23773.d
new file mode 100644
index 0000000..e6cdc3e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail23773.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=23773
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail23773.d(14): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+---
+*/
+
+void main()
+{
+ int i;
+ int[] arr;
+ assert(arr.length = i);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23822.d b/gcc/testsuite/gdc.test/fail_compilation/fail23822.d
new file mode 100644
index 0000000..5cdd1fe
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail23822.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=23822
+
+// REQUIRED_ARGS: -de
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail23822.d(21): Deprecation: alias `fail23822.S.value` is deprecated
+---
+*/
+
+alias Alias(alias A) = A;
+
+struct S
+{
+ deprecated alias value = Alias!5;
+}
+
+void main()
+{
+ auto a = S.value;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23826.d b/gcc/testsuite/gdc.test/fail_compilation/fail23826.d
new file mode 100644
index 0000000..3db243a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail23826.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=23826
+
+// REQUIRED_ARGS: -de
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail23826.d(23): Deprecation: alias `fail23826.S.value` is deprecated
+---
+*/
+
+alias Alias(alias A) = A;
+
+class S
+{
+ deprecated alias value = Alias!5;
+}
+
+enum identity(alias A) = A;
+
+void main()
+{
+ auto a = identity!(S.value);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23861.d b/gcc/testsuite/gdc.test/fail_compilation/fail23861.d
new file mode 100644
index 0000000..23c5407
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail23861.d
@@ -0,0 +1,25 @@
+// https://issues.dlang.org/show_bug.cgi?id=23861
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail23861.d(24): Error: cannot implicitly convert expression `3` of type `int` to `Foo`
+---
+*/
+
+Foo global;
+
+struct Foo
+{
+ ref Foo get()
+ {
+ return global;
+ }
+ alias get this;
+}
+
+void main()
+{
+ Foo g;
+ g = 3;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d
index 91f8046..77e8cd8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail332.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail332.d(22): Error: function `fail332.foo(int _param_0, ...)` is not callable using argument types `()`
-fail_compilation/fail332.d(22): missing argument for parameter #1: `int _param_0`
-fail_compilation/fail332.d(23): Error: function `fail332.foo(int _param_0, ...)` is not callable using argument types `(typeof(null))`
-fail_compilation/fail332.d(23): cannot pass argument `null` of type `typeof(null)` to parameter `int _param_0`
-fail_compilation/fail332.d(25): Error: function `fail332.baz(int[] _param_0...)` is not callable using argument types `(string)`
-fail_compilation/fail332.d(25): cannot pass argument `""` of type `string` to parameter `int[] _param_0...`
-fail_compilation/fail332.d(26): Error: function `fail332.baz(int[] _param_0...)` is not callable using argument types `(int, typeof(null))`
-fail_compilation/fail332.d(26): cannot pass argument `null` of type `typeof(null)` to parameter `int[] _param_0...`
+fail_compilation/fail332.d(22): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `()`
+fail_compilation/fail332.d(22): missing argument for parameter #1: `int __param_0`
+fail_compilation/fail332.d(23): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `(typeof(null))`
+fail_compilation/fail332.d(23): cannot pass argument `null` of type `typeof(null)` to parameter `int __param_0`
+fail_compilation/fail332.d(25): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(string)`
+fail_compilation/fail332.d(25): cannot pass argument `""` of type `string` to parameter `int[] __param_0...`
+fail_compilation/fail332.d(26): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(int, typeof(null))`
+fail_compilation/fail332.d(26): cannot pass argument `null` of type `typeof(null)` to parameter `int[] __param_0...`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d
index b02fbb1..f57e746 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d
@@ -4,7 +4,7 @@
TEST_OUTPUT:
---
fail_compilation/fail4375q.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375q.d(13)
-fail_compilation/fail4375q.d(14): Error: `with` expressions must be aggregate types or pointers to them, not `int`
+fail_compilation/fail4375q.d(14): Error: `with` expression types must be enums or aggregates or pointers to them, not `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4559.d b/gcc/testsuite/gdc.test/fail_compilation/fail4559.d
index 0101ae9..657c184 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4559.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4559.d
@@ -1,10 +1,10 @@
/*
-REQUIRED_ARGS: -o- -de
+REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/fail4559.d(13): Deprecation: use `{ }` for an empty statement, not `;`
-fail_compilation/fail4559.d(19): Deprecation: use `{ }` for an empty statement, not `;`
-fail_compilation/fail4559.d(21): Deprecation: use `{ }` for an empty statement, not `;`
+fail_compilation/fail4559.d(13): Error: use `{ }` for an empty statement, not `;`
+fail_compilation/fail4559.d(19): Error: use `{ }` for an empty statement, not `;`
+fail_compilation/fail4559.d(21): Error: use `{ }` for an empty statement, not `;`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d b/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d
index 392cebd..a3b4d1a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d
@@ -1,17 +1,14 @@
/* TEST_OUTPUT:
---
-fail_compilation/fail_typeof.d(18): Error: undefined identifier `this`
-fail_compilation/fail_typeof.d(23): Error: `this` is not in a class or struct scope
-fail_compilation/fail_typeof.d(23): Error: `this` is only defined in non-static member functions, not `fail_typeof`
-fail_compilation/fail_typeof.d(28): Error: undefined identifier `super`
-fail_compilation/fail_typeof.d(33): Error: `super` is not in a class scope
-fail_compilation/fail_typeof.d(33): Error: `super` is only allowed in non-static class member functions
-fail_compilation/fail_typeof.d(40): Error: undefined identifier `this`, did you mean `typeof(this)`?
-fail_compilation/fail_typeof.d(50): Error: undefined identifier `super`
-fail_compilation/fail_typeof.d(55): Error: `super` is not in a class scope
-fail_compilation/fail_typeof.d(55): Error: `super` is only allowed in non-static class member functions
-fail_compilation/fail_typeof.d(63): Error: undefined identifier `this`, did you mean `typeof(this)`?
-fail_compilation/fail_typeof.d(73): Error: undefined identifier `super`, did you mean `typeof(super)`?
+fail_compilation/fail_typeof.d(15): Error: undefined identifier `this`
+fail_compilation/fail_typeof.d(20): Error: `this` is not in a class or struct scope
+fail_compilation/fail_typeof.d(25): Error: undefined identifier `super`
+fail_compilation/fail_typeof.d(30): Error: `super` is not in a class scope
+fail_compilation/fail_typeof.d(37): Error: undefined identifier `this`, did you mean `typeof(this)`?
+fail_compilation/fail_typeof.d(47): Error: undefined identifier `super`
+fail_compilation/fail_typeof.d(52): Error: `super` is not in a class scope
+fail_compilation/fail_typeof.d(60): Error: undefined identifier `this`, did you mean `typeof(this)`?
+fail_compilation/fail_typeof.d(70): Error: undefined identifier `super`, did you mean `typeof(super)`?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10651.d b/gcc/testsuite/gdc.test/fail_compilation/ice10651.d
index 1f87955..8b6c720 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10651.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10651.d
@@ -1,7 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10651.d(11): Error: can only throw class objects derived from `Throwable`, not type `int*`
+fail_compilation/ice10651.d(13): Error: can only throw class objects derived from `Throwable`, not type `int*`
+fail_compilation/ice10651.d(19): Deprecation: cannot throw object of qualified type `immutable(Exception)`
+fail_compilation/ice10651.d(20): Deprecation: cannot throw object of qualified type `const(Dummy)`
---
*/
@@ -10,3 +12,20 @@ void main()
alias T = int;
throw new T(); // ICE
}
+
+void f()
+{
+ immutable c = new Exception("");
+ if (c) throw c;
+ throw new const Dummy([]);
+}
+
+class Dummy: Exception
+{
+ int[] data;
+ @safe pure nothrow this(immutable int[] data) immutable
+ {
+ super("Dummy");
+ this.data = data;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11626.d b/gcc/testsuite/gdc.test/fail_compilation/ice11626.d
index 5dc5d5c..6d347bc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11626.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11626.d
@@ -5,4 +5,4 @@ fail_compilation/ice11626.d(8): Error: undefined identifier `Bar`
---
*/
-void foo(in ref Bar) {}
+void foo(const ref Bar) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11982.d b/gcc/testsuite/gdc.test/fail_compilation/ice11982.d
index ff5fae4..0f2ce41 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11982.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11982.d
@@ -1,16 +1,19 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11982.d(16): Error: basic type expected, not `scope`
-fail_compilation/ice11982.d(16): Error: found `scope` when expecting `;` following statement
-fail_compilation/ice11982.d(16): Error: basic type expected, not `}`
-fail_compilation/ice11982.d(16): Error: missing `{ ... }` for function literal
-fail_compilation/ice11982.d(16): Error: C style cast illegal, use `cast(funk)function _error_()
+fail_compilation/ice11982.d(19): Error: basic type expected, not `scope`
+fail_compilation/ice11982.d(19): Error: found `scope` when expecting `;` following statement `new _error_` on line fail_compilation/ice11982.d(19)
+fail_compilation/ice11982.d(19): Error: basic type expected, not `}`
+fail_compilation/ice11982.d(19): Error: missing `{ ... }` for function literal
+fail_compilation/ice11982.d(19): Error: C style cast illegal, use `cast(funk)function _error_()
{
}
`
-fail_compilation/ice11982.d(16): Error: found `}` when expecting `;` following statement
-fail_compilation/ice11982.d(17): Error: found `End of File` when expecting `}` following compound statement
+fail_compilation/ice11982.d(19): Error: found `}` when expecting `;` following statement `cast(funk)function _error_()
+{
+}
+` on line fail_compilation/ice11982.d(19)
+fail_compilation/ice11982.d(20): Error: found `End of File` when expecting `}` following compound statement
---
*/
void main() { new scope ( funk ) function }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13225.d b/gcc/testsuite/gdc.test/fail_compilation/ice13225.d
index 6988cd7..abc30ea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13225.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13225.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13225.d(12): Error: mixin `ice13225.S.M!(function (S _param_0) pure nothrow @nogc @safe => 0)` does not match template declaration `M(T)`
+fail_compilation/ice13225.d(12): Error: mixin `ice13225.S.M!(function (S __param_0) pure nothrow @nogc @safe => 0)` does not match template declaration `M(T)`
fail_compilation/ice13225.d(16): Error: undefined identifier `undefined`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d
index 4fd1f61..90cf03f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d
@@ -3,7 +3,7 @@ TEST_OUTPUT:
---
fail_compilation/ice23097.d(12): Error: undefined identifier `ICE`
fail_compilation/ice23097.d(27): Error: template instance `ice23097.ice23097!(S23097)` error instantiating
-fail_compilation/ice23097.d(27): Error: function `ice23097.ice23097!(S23097).ice23097(S23097 _param_0)` is not callable using argument types `(S23097)`
+fail_compilation/ice23097.d(27): Error: function `ice23097.ice23097!(S23097).ice23097(S23097 __param_0)` is not callable using argument types `(S23097)`
fail_compilation/ice23097.d(27): generating a copy constructor for `struct S23097` failed, therefore instances of it are uncopyable
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d
index 5276e83..456d3e12 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int _param_0)` is not callable using argument types `()`
+fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int __param_0)` is not callable using argument types `()`
fail_compilation/ice9540.d(35): too few arguments, expected 1, got 0
fail_compilation/ice9540.d(26): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d
index 11fddf0..d136144 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d
@@ -23,7 +23,7 @@ fail_compilation/misc_parser_err_cov1.d(40): Error: semicolon expected following
fail_compilation/misc_parser_err_cov1.d(40): Error: identifier or `new` expected following `.`, not `+`
fail_compilation/misc_parser_err_cov1.d(41): Error: identifier or new keyword expected following `(...)`.
fail_compilation/misc_parser_err_cov1.d(41): Error: expression expected, not `;`
-fail_compilation/misc_parser_err_cov1.d(42): Error: found `}` when expecting `;` following statement
+fail_compilation/misc_parser_err_cov1.d(42): Error: found `}` when expecting `;` following statement `(__error) + 0` on line fail_compilation/misc_parser_err_cov1.d(41)
fail_compilation/misc_parser_err_cov1.d(43): Error: found `End of File` when expecting `}` following compound statement
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d
index 19e230e..096c499 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d
@@ -1,13 +1,13 @@
/**
TEST_OUTPUT:
---
-fail_compilation/named_arguments_parse.d(10): Error: named arguments not allowed here
fail_compilation/named_arguments_parse.d(13): Error: named arguments not allowed here
fail_compilation/named_arguments_parse.d(14): Error: named arguments not allowed here
---
*/
-@(attribute: 3)
+
+// @(attribute: 3) Currently gives an ugly parse error, will be better when named template arguments are implemented
void main()
{
mixin(thecode: "{}");
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc.d
index c9c4288..d13006d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/parseStc.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc.d
@@ -3,7 +3,7 @@ TEST_OUTPUT:
---
fail_compilation/parseStc.d(12): Error: missing closing `)` after `if (x`
fail_compilation/parseStc.d(12): Error: use `{ }` for an empty statement, not `;`
-fail_compilation/parseStc.d(12): Error: found `)` when expecting `;` following statement
+fail_compilation/parseStc.d(12): Error: found `)` when expecting `;` following statement `1` on line fail_compilation/parseStc.d(12)
fail_compilation/parseStc.d(13): Error: redundant attribute `const`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/previewin.d b/gcc/testsuite/gdc.test/fail_compilation/previewin.d
index ca54093..d0e97c8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/previewin.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/previewin.d
@@ -4,10 +4,10 @@ TEST_OUTPUT:
---
fail_compilation/previewin.d(4): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)`
fail_compilation/previewin.d(4): cannot pass argument `__lambda1` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
-fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(const(real) x) pure nothrow @nogc @safe)`
-fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
-fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref const(real) x) pure nothrow @nogc @safe)`
-fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
+fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)`
+fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
+fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)`
+fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to global variable `myGlobal`
fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to global variable `myGlobal`
fail_compilation/previewin.d(17): Error: scope parameter `arg` may not be returned
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d
index 829fb6a..2e7940f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d
@@ -86,8 +86,8 @@ fail_compilation/retscope2.d(504): Error: scope variable `c` may not be returned
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(604): Error: scope variable `_param_0` assigned to non-scope anonymous parameter calling `foo600`
-fail_compilation/retscope2.d(604): Error: scope variable `_param_1` assigned to non-scope anonymous parameter calling `foo600`
+fail_compilation/retscope2.d(604): Error: scope variable `__param_0` assigned to non-scope anonymous parameter calling `foo600`
+fail_compilation/retscope2.d(604): Error: scope variable `__param_1` assigned to non-scope anonymous parameter calling `foo600`
fail_compilation/retscope2.d(614): Error: template instance `retscope2.test600!(int*, int*)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
index 5c581d1..ddeae81 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
@@ -25,7 +25,7 @@ int* test() @safe
---
fail_compilation/retscope6.d(7034): Error: address of variable `i` assigned to `s` with longer lifetime
fail_compilation/retscope6.d(7035): Error: address of variable `i` assigned to `s` with longer lifetime
-fail_compilation/retscope6.d(7025): Error: scope variable `_param_2` assigned to `ref` variable `t` with longer lifetime
+fail_compilation/retscope6.d(7025): Error: scope variable `__param_2` assigned to `ref` variable `t` with longer lifetime
fail_compilation/retscope6.d(7037): Error: template instance `retscope6.S.emplace4!(int*)` error instantiating
fail_compilation/retscope6.d(7037): Error: address of variable `i` assigned to `s` with longer lifetime
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d b/gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d
index 75dbe2d..b511535 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d
@@ -4,7 +4,7 @@ TEST_OUTPUT:
---
fail_compilation/systemvariables_deprecation.d(16): Deprecation: `@safe` function `main` calling `middle`
fail_compilation/systemvariables_deprecation.d(21): which calls `systemvariables_deprecation.inferred`
-fail_compilation/systemvariables_deprecation.d(27): which would be `@system` because of:
+fail_compilation/systemvariables_deprecation.d(27): which wouldn't be `@safe` because of:
fail_compilation/systemvariables_deprecation.d(27): cannot access `@system` variable `x0` in @safe code
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testInference.d b/gcc/testsuite/gdc.test/fail_compilation/testInference.d
index c0d5a05..145fc9e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/testInference.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/testInference.d
@@ -138,8 +138,13 @@ immutable(void)* g10063(inout int* p) pure
TEST_OUTPUT:
---
fail_compilation/testInference.d(154): Error: `pure` function `testInference.bar14049` cannot call impure function `testInference.foo14049!int.foo14049`
+fail_compilation/testInference.d(149): which calls `testInference.foo14049!int.foo14049.__lambda2`
+fail_compilation/testInference.d(148): which calls `testInference.impure14049`
+fail_compilation/testInference.d(143): which wasn't inferred `pure` because of:
+fail_compilation/testInference.d(143): `pure` function `testInference.impure14049` cannot access mutable static data `i`
---
*/
+#line 143
auto impure14049() { static int i = 1; return i; }
void foo14049(T)(T val)
@@ -170,8 +175,10 @@ int* f14160() pure
TEST_OUTPUT:
---
fail_compilation/testInference.d(180): Error: `pure` function `testInference.test12422` cannot call impure function `testInference.test12422.bar12422!().bar12422`
+fail_compilation/testInference.d(179): which calls `testInference.foo12422`
---
*/
+#line 175
int g12422;
void foo12422() { ++g12422; }
void test12422() pure
@@ -184,9 +191,15 @@ void test12422() pure
TEST_OUTPUT:
---
fail_compilation/testInference.d(198): Error: `pure` function `testInference.test13729a` cannot call impure function `testInference.test13729a.foo`
+fail_compilation/testInference.d(196): which wasn't inferred `pure` because of:
+fail_compilation/testInference.d(196): `pure` function `testInference.test13729a.foo` cannot access mutable static data `g13729`
fail_compilation/testInference.d(206): Error: `pure` function `testInference.test13729b` cannot call impure function `testInference.test13729b.foo!().foo`
+fail_compilation/testInference.d(204): which wasn't inferred `pure` because of:
+fail_compilation/testInference.d(204): `pure` function `testInference.test13729b.foo!().foo` cannot access mutable static data `g13729`
---
*/
+
+#line 190
int g13729;
void test13729a() pure
@@ -229,8 +242,10 @@ void test17086_call ()
TEST_OUTPUT:
---
fail_compilation/testInference.d(238): Error: `pure` function `testInference.test20047_pure_function` cannot call impure function `testInference.test20047_pure_function.bug`
+fail_compilation/testInference.d(237): which calls `testInference.test20047_impure_function`
---
*/
+#line 234
void test20047_impure_function() {}
void test20047_pure_function() pure
{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d
index 96511f5..50cebab 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d
@@ -6,7 +6,7 @@ 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(18): Candidates are: `testrvaluecpctor.Foo!int.Foo.this(ref Foo!int rhs)`
+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)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d b/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d
new file mode 100644
index 0000000..8609d29
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d
@@ -0,0 +1,35 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/var_func_attr.d(19): Error: cannot implicitly convert expression `__lambda8` of type `void function() nothrow @nogc @safe` to `void function() pure`
+---
+*/
+
+// Test the effect of function attributes on variables
+// See:
+// https://issues.dlang.org/show_bug.cgi?id=7432
+// https://github.com/dlang/dmd/pull/14199
+// Usually it's a no-op, but the attribute can apply to the function/delegate type of the variable
+// The current behavior is weird, so this is a test of the current behavior, not necessarily the desired behavior
+
+// No-op
+pure int x;
+
+// Applies to function type (existing code in dmd and Phobos relies on this)
+pure void function() pf = () {
+ static int g;
+ g++;
+};
+
+// Function attributes currently don't apply to inferred types (somewhat surprisingly)
+nothrow nf = () {
+ throw new Exception("");
+};
+
+// Neither do they apply to indirections
+alias F = void function();
+
+pure F pf2 = () {
+ static int g;
+ g++;
+};
diff --git a/gcc/testsuite/gdc.test/runnable/eh2.d b/gcc/testsuite/gdc.test/runnable/eh2.d
index dc285a5..2b469d2 100644
--- a/gcc/testsuite/gdc.test/runnable/eh2.d
+++ b/gcc/testsuite/gdc.test/runnable/eh2.d
@@ -24,7 +24,7 @@ class Abc : Throwable
{
printf("foo 1\n");
x |= 4;
- throw this;
+ throw cast() this;
printf("foo 2\n");
x |= 8;
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/link11069z.d b/gcc/testsuite/gdc.test/runnable/imports/link11069z.d
index 5987cb4..02301b9 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/link11069z.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/link11069z.d
@@ -1,7 +1,7 @@
module imports.link11069z;
struct Matrix(T, uint _M)
{
- int opCmp()(auto ref in Matrix b) const
+ int opCmp()(const auto ref Matrix b) const
{
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/link13415a.d b/gcc/testsuite/gdc.test/runnable/imports/link13415a.d
index de3bbe2..077671b 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/link13415a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/link13415a.d
@@ -7,7 +7,7 @@ struct S(alias func)
}
}
-extern(C) int printf(in char*, ...);
+extern(C) int printf(const char*, ...);
void f(int i = 77)
{
diff --git a/gcc/testsuite/gdc.test/runnable/imports/mainx23837.c b/gcc/testsuite/gdc.test/runnable/imports/mainx23837.c
new file mode 100644
index 0000000..0c446ab
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/mainx23837.c
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug?id=23837
+
+struct stbrp_context
+{
+ int width;
+ int height;
+ int align;
+ int init_mode;
+ int heuristic;
+};
diff --git a/gcc/testsuite/gdc.test/runnable/mangle.d b/gcc/testsuite/gdc.test/runnable/mangle.d
index 7599e0e..6e8f2b2 100644
--- a/gcc/testsuite/gdc.test/runnable/mangle.d
+++ b/gcc/testsuite/gdc.test/runnable/mangle.d
@@ -571,12 +571,6 @@ void test12231()
/***************************************************/
-int test2a(scope int a) { return a; }
-
-static assert(test2a.mangleof == "_D6mangle6test2aFiZi");
-
-/***************************************************/
-
class CC
{
int* p;
diff --git a/gcc/testsuite/gdc.test/runnable/test23837.d b/gcc/testsuite/gdc.test/runnable/test23837.d
new file mode 100644
index 0000000..4e155b6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test23837.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=23837
+// EXTRA_FILES: imports/mainx23837.c
+
+import imports.mainx23837;
+
+struct TexturePacker
+{
+ stbrp_context _context;
+}
+
+int main()
+{
+ auto res = TexturePacker();
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test42.d b/gcc/testsuite/gdc.test/runnable/test42.d
index 57045ba..436f707 100644
--- a/gcc/testsuite/gdc.test/runnable/test42.d
+++ b/gcc/testsuite/gdc.test/runnable/test42.d
@@ -2113,7 +2113,7 @@ void test12725()
struct Matrix12728(T, uint m, uint n = m, ubyte f = 0)
{
- void foo(uint r)(auto ref in Matrix12728!(T, n, r) b)
+ void foo(uint r)(const auto ref Matrix12728!(T, n, r) b)
{
}
}
diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d
index e57f52f..5017a76 100644
--- a/gcc/testsuite/gdc.test/runnable/xtest46.d
+++ b/gcc/testsuite/gdc.test/runnable/xtest46.d
@@ -5016,18 +5016,18 @@ void test6763()
{
int n;
- f6763(0); //With D2: Error: function main.f ((ref const const(int) _param_0)) is not callable using argument types (int)
+ f6763(0); //With D2: Error: function main.f ((ref const const(int) __param_0)) is not callable using argument types (int)
c6763(0);
r6763(n); static assert(__traits(compiles, r6763(0)));
i6763(0);
o6763(n); static assert(!__traits(compiles, o6763(0)));
// https://issues.dlang.org/show_bug.cgi?id=6755
- static assert(typeof(f6763).stringof == "void(int _param_0)");
- static assert(typeof(c6763).stringof == "void(const(int) _param_0)");
- static assert(typeof(r6763).stringof == "void(ref int _param_0)");
- static assert(typeof(i6763).stringof == "void(in int _param_0)");
- static assert(typeof(o6763).stringof == "void(out int _param_0)");
+ static assert(typeof(f6763).stringof == "void(int __param_0)");
+ static assert(typeof(c6763).stringof == "void(const(int) __param_0)");
+ static assert(typeof(r6763).stringof == "void(ref int __param_0)");
+ static assert(typeof(i6763).stringof == "void(in int __param_0)");
+ static assert(typeof(o6763).stringof == "void(out int __param_0)");
}
/***************************************************/
@@ -5997,7 +5997,7 @@ void test7618(const int x = 1)
{
int func(ref int x) { return 1; }
static assert(!__traits(compiles, func(x)));
- // Error: function test.foo.func (ref int _param_0) is not callable using argument types (const(int))
+ // Error: function test.foo.func (ref int __param_0) is not callable using argument types (const(int))
int delegate(ref int) dg = (ref int x) => 1;
static assert(!__traits(compiles, dg(x)));
@@ -6170,14 +6170,6 @@ static assert(!__traits(compiles, foo8220(typeof(0)))); // fail
/***************************************************/
-void func8105(in ref int x) { }
-
-void test8105()
-{
-}
-
-/***************************************************/
-
template ParameterTypeTuple159(alias foo)
{
static if (is(typeof(foo) P == __parameters))
@@ -8300,7 +8292,6 @@ int main()
test12503();
test8004();
test8064();
- test8105();
test159();
test12824();
test8283();