aboutsummaryrefslogtreecommitdiff
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
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.
-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
-rw-r--r--libphobos/libdruntime/MERGE2
-rw-r--r--libphobos/libdruntime/core/atomic.d55
-rw-r--r--libphobos/libdruntime/core/demangle.d478
-rw-r--r--libphobos/libdruntime/core/internal/array/concatenation.d187
-rw-r--r--libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d4
-rw-r--r--libphobos/libdruntime/core/internal/string.d62
-rw-r--r--libphobos/libdruntime/core/stdc/config.d344
-rw-r--r--libphobos/libdruntime/core/sync/condition.d19
-rw-r--r--libphobos/libdruntime/core/thread/package.d39
-rw-r--r--libphobos/libdruntime/core/thread/types.d5
-rw-r--r--libphobos/libdruntime/core/time.d223
-rw-r--r--libphobos/libdruntime/gcc/sections/elf.d6
-rw-r--r--libphobos/libdruntime/object.d5
-rw-r--r--libphobos/libdruntime/rt/aApply.d24
-rw-r--r--libphobos/libdruntime/rt/aApplyR.d24
-rw-r--r--libphobos/libdruntime/rt/lifetime.d148
-rw-r--r--libphobos/libdruntime/rt/profilegc.d11
-rw-r--r--libphobos/src/MERGE2
-rw-r--r--libphobos/src/std/algorithm/comparison.d23
-rw-r--r--libphobos/src/std/algorithm/iteration.d28
-rw-r--r--libphobos/src/std/algorithm/searching.d68
-rw-r--r--libphobos/src/std/array.d187
-rw-r--r--libphobos/src/std/concurrency.d4
-rw-r--r--libphobos/src/std/container/dlist.d36
-rw-r--r--libphobos/src/std/experimental/allocator/building_blocks/region.d20
-rw-r--r--libphobos/src/std/file.d4
-rw-r--r--libphobos/src/std/json.d44
-rw-r--r--libphobos/src/std/net/curl.d35
-rw-r--r--libphobos/src/std/path.d3
-rw-r--r--libphobos/src/std/random.d10
-rw-r--r--libphobos/src/std/range/package.d619
-rw-r--r--libphobos/src/std/range/primitives.d3
-rw-r--r--libphobos/src/std/regex/internal/backtracking.d7
-rw-r--r--libphobos/src/std/regex/internal/thompson.d7
-rw-r--r--libphobos/src/std/stdio.d50
-rw-r--r--libphobos/src/std/traits.d71
-rw-r--r--libphobos/src/std/typecons.d340
190 files changed, 6538 insertions, 3215 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..8ffbef3c 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 7cd8df19..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..33cc904e
--- /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();
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 1205cd9..95ea67d 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/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/libphobos/libdruntime/core/atomic.d b/libphobos/libdruntime/core/atomic.d
index 4af3fdf..1fba06c 100644
--- a/libphobos/libdruntime/core/atomic.d
+++ b/libphobos/libdruntime/core/atomic.d
@@ -2,6 +2,9 @@
* The atomic module provides basic support for lock-free
* concurrent programming.
*
+ * $(NOTE Use the `-preview=nosharedaccess` compiler flag to detect
+ * unsafe individual read or write operations on shared data.)
+ *
* Copyright: Copyright Sean Kelly 2005 - 2016.
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Authors: Sean Kelly, Alex Rønne Petersen, Manu Evans
@@ -10,6 +13,22 @@
module core.atomic;
+///
+@safe unittest
+{
+ int y = 2;
+ shared int x = y; // OK
+
+ //x++; // read modify write error
+ x.atomicOp!"+="(1); // OK
+ //y = x; // read error with preview flag
+ y = x.atomicLoad(); // OK
+ assert(y == 3);
+ //x = 5; // write error with preview flag
+ x.atomicStore(5); // OK
+ assert(x.atomicLoad() == 5);
+}
+
import core.internal.atomic;
import core.internal.attributes : betterC;
import core.internal.traits : hasUnsharedIndirections;
@@ -1089,42 +1108,6 @@ version (CoreUnittest)
assert(ptr is null);
}
- unittest
- {
- import core.thread;
-
- // Use heap memory to ensure an optimizing
- // compiler doesn't put things in registers.
- uint* x = new uint();
- bool* f = new bool();
- uint* r = new uint();
-
- auto thr = new Thread(()
- {
- while (!*f)
- {
- }
-
- atomicFence();
-
- *r = *x;
- });
-
- thr.start();
-
- *x = 42;
-
- atomicFence();
-
- *f = true;
-
- atomicFence();
-
- thr.join();
-
- assert(*r == 42);
- }
-
// === atomicFetchAdd and atomicFetchSub operations ====
@betterC pure nothrow @nogc @safe unittest
{
diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d
index 3fcb266..f08e1f8 100644
--- a/libphobos/libdruntime/core/demangle.d
+++ b/libphobos/libdruntime/core/demangle.d
@@ -69,62 +69,17 @@ pure @safe:
{
buf = buf_;
addType = addType_;
- dst = dst_;
+ dst.dst = dst_;
}
-
- enum size_t minBufSize = 4000;
-
-
const(char)[] buf = null;
- char[] dst = null;
+ Buffer dst;
size_t pos = 0;
- size_t len = 0;
size_t brp = 0; // current back reference pos
AddType addType = AddType.yes;
bool mute = false;
Hooks hooks;
- static class ParseException : Exception
- {
- this(string msg) @safe pure nothrow
- {
- super( msg );
- }
- }
-
-
- static class OverflowException : Exception
- {
- this(string msg) @safe pure nothrow
- {
- super( msg );
- }
- }
-
-
- static noreturn error( string msg = "Invalid symbol" ) @trusted /* exception only used in module */
- {
- pragma(inline, false); // tame dmd inliner
-
- //throw new ParseException( msg );
- debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
- throw __ctfe ? new ParseException(msg)
- : cast(ParseException) __traits(initSymbol, ParseException).ptr;
-
- }
-
-
- static noreturn overflow( string msg = "Buffer overflow" ) @trusted /* exception only used in module */
- {
- pragma(inline, false); // tame dmd inliner
-
- //throw new OverflowException( msg );
- debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
- throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr;
- }
-
-
//////////////////////////////////////////////////////////////////////////
// Type Testing and Conversion
//////////////////////////////////////////////////////////////////////////
@@ -163,91 +118,11 @@ pure @safe:
error();
}
-
- //////////////////////////////////////////////////////////////////////////
- // Data Output
- //////////////////////////////////////////////////////////////////////////
-
-
- static bool contains( const(char)[] a, const(char)[] b ) @trusted
- {
- if (a.length && b.length)
- {
- auto bend = b.ptr + b.length;
- auto aend = a.ptr + a.length;
- return a.ptr <= b.ptr && bend <= aend;
- }
- return false;
- }
-
-
- // move val to the end of the dst buffer
- char[] shift( const(char)[] val )
- {
- pragma(inline, false); // tame dmd inliner
-
- if ( val.length && !mute )
- {
- assert( contains( dst[0 .. len], val ) );
- debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr );
-
- if (len + val.length > dst.length)
- overflow();
- size_t v = &val[0] - &dst[0];
- dst[len .. len + val.length] = val[];
- for (size_t p = v; p < len; p++)
- dst[p] = dst[p + val.length];
-
- return dst[len - val.length .. len];
- }
- return null;
- }
-
- // remove val from dst buffer
- void remove( const(char)[] val )
+ char[] shift(scope const(char)[] val) return scope
{
- pragma(inline, false); // tame dmd inliner
-
- if ( val.length )
- {
- assert( contains( dst[0 .. len], val ) );
- debug(info) printf( "removing (%.*s)\n", cast(int) val.length, val.ptr );
- size_t v = &val[0] - &dst[0];
- assert( len >= val.length && len <= dst.length );
- len -= val.length;
- for (size_t p = v; p < len; p++)
- dst[p] = dst[p + val.length];
- }
- }
-
- char[] append( const(char)[] val ) return scope
- {
- pragma(inline, false); // tame dmd inliner
-
- if ( val.length && !mute )
- {
- if ( !dst.length )
- dst.length = minBufSize;
- assert( !contains( dst[0 .. len], val ) );
- debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr );
-
- if ( dst.length - len >= val.length && &dst[len] == &val[0] )
- {
- // data is already in place
- auto t = dst[len .. len + val.length];
- len += val.length;
- return t;
- }
- if ( dst.length - len >= val.length )
- {
- dst[len .. len + val.length] = val[];
- auto t = dst[len .. len + val.length];
- len += val.length;
- return t;
- }
- overflow();
- }
- return null;
+ if (mute)
+ return null;
+ return dst.shift(val);
}
void putComma(size_t n)
@@ -265,14 +140,9 @@ pure @safe:
void put(scope const(char)[] val) return scope
{
- pragma(inline, false); // tame dmd inliner
-
- if (!val.length) return;
-
- if (!contains(dst[0 .. len], val))
- append(val);
- else
- shift(val);
+ if (mute)
+ return;
+ dst.append(val);
}
@@ -297,7 +167,7 @@ pure @safe:
{
if ( val.length )
{
- append( " " );
+ put(" ");
put( val );
}
}
@@ -307,7 +177,7 @@ pure @safe:
{
debug(trace) printf( "silent+\n" );
debug(trace) scope(success) printf( "silent-\n" );
- auto n = len; dg(); len = n;
+ auto n = dst.length; dg(); dst.len = n;
}
@@ -835,7 +705,7 @@ pure @safe:
debug(trace) printf( "parseType+\n" );
debug(trace) scope(success) printf( "parseType-\n" );
- auto beg = len;
+ auto beg = dst.length;
auto t = front;
char[] parseBackrefType(scope char[] delegate() pure @safe parseDg) pure @safe
@@ -867,19 +737,19 @@ pure @safe:
put( "shared(" );
parseType();
put( ')' );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'x': // Const (x Type)
popFront();
put( "const(" );
parseType();
put( ')' );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'y': // Immutable (y Type)
popFront();
put( "immutable(" );
parseType();
put( ')' );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'N':
popFront();
switch ( front )
@@ -887,29 +757,28 @@ pure @safe:
case 'n': // Noreturn
popFront();
put("noreturn");
- return dst[beg .. len];
+ return dst[beg .. $];
case 'g': // Wild (Ng Type)
popFront();
// TODO: Anything needed here?
put( "inout(" );
parseType();
put( ')' );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'h': // TypeVector (Nh Type)
popFront();
put( "__vector(" );
parseType();
put( ')' );
- return dst[beg .. len];
+ return dst[beg .. $];
default:
error();
- assert( 0 );
}
case 'A': // TypeArray (A Type)
popFront();
parseType();
put( "[]" );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'G': // TypeStaticArray (G Number Type)
popFront();
auto num = sliceNumber();
@@ -917,21 +786,21 @@ pure @safe:
put( '[' );
put( num );
put( ']' );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'H': // TypeAssocArray (H Type Type)
popFront();
// skip t1
auto tx = parseType();
parseType();
put( '[' );
- put( tx );
+ shift(tx);
put( ']' );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'P': // TypePointer (P Type)
popFront();
parseType();
put( '*' );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction
return parseTypeFunction();
case 'C': // TypeClass (C LName)
@@ -940,7 +809,7 @@ pure @safe:
case 'T': // TypeTypedef (T LName)
popFront();
parseQualifiedName();
- return dst[beg .. len];
+ return dst[beg .. $];
case 'D': // TypeDelegate (D TypeFunction)
popFront();
auto modifiers = parseModifier();
@@ -957,15 +826,15 @@ pure @safe:
put(str);
}
}
- return dst[beg .. len];
+ return dst[beg .. $];
case 'n': // TypeNone (n)
popFront();
// TODO: Anything needed here?
- return dst[beg .. len];
+ return dst[beg .. $];
case 'B': // TypeTuple (B Number Arguments)
popFront();
// TODO: Handle this.
- return dst[beg .. len];
+ return dst[beg .. $];
case 'Z': // Internal symbol
// This 'type' is used for untyped internal symbols, i.e.:
// __array
@@ -975,13 +844,13 @@ pure @safe:
// __Interface
// __ModuleInfo
popFront();
- return dst[beg .. len];
+ return dst[beg .. $];
default:
if (t >= 'a' && t <= 'w')
{
popFront();
put( primitives[cast(size_t)(t - 'a')] );
- return dst[beg .. len];
+ return dst[beg .. $];
}
else if (t == 'z')
{
@@ -991,14 +860,13 @@ pure @safe:
case 'i':
popFront();
put( "cent" );
- return dst[beg .. len];
+ return dst[beg .. $];
case 'k':
popFront();
put( "ucent" );
- return dst[beg .. len];
+ return dst[beg .. $];
default:
error();
- assert( 0 );
}
}
error();
@@ -1351,12 +1219,13 @@ pure @safe:
{
debug(trace) printf( "parseTypeFunction+\n" );
debug(trace) scope(success) printf( "parseTypeFunction-\n" );
- auto beg = len;
+ auto beg = dst.length;
parseCallConvention();
auto attributes = parseFuncAttr();
- auto argbeg = len;
+ auto argbeg = dst.length;
+ put(IsDelegate.yes == isdg ? "delegate" : "function");
put( '(' );
parseFuncArguments();
put( ')' );
@@ -1369,17 +1238,18 @@ pure @safe:
put(str);
}
}
- auto retbeg = len;
- parseType();
- put( ' ' );
- // append delegate/function
- if (IsDelegate.yes == isdg)
- put( "delegate" );
- else
- put( "function" );
- // move arguments and attributes behind name
- shift( dst[argbeg .. retbeg] );
- return dst[beg..len];
+
+ // A function / delegate return type is located at the end of its mangling
+ // Write it in order, then shift it back to 'code order'
+ // e.g. `delegate(int) @safedouble ' => 'double delegate(int) @safe'
+ {
+ auto retbeg = dst.length;
+ parseType();
+ put(' ');
+ shift(dst[argbeg .. retbeg]);
+ }
+
+ return dst[beg .. $];
}
static bool isCallConvention( char ch )
@@ -1701,7 +1571,7 @@ pure @safe:
if ( mayBeMangledNameArg() )
{
- auto l = len;
+ auto l = dst.length;
auto p = pos;
auto b = brp;
try
@@ -1712,7 +1582,7 @@ pure @safe:
}
catch ( ParseException e )
{
- len = l;
+ dst.len = l;
pos = p;
brp = b;
debug(trace) printf( "not a mangled name arg\n" );
@@ -1724,7 +1594,7 @@ pure @safe:
// try all possible pairs of numbers
auto qlen = decodeNumber() / 10; // last digit needed for QualifiedName
pos--;
- auto l = len;
+ auto l = dst.length;
auto p = pos;
auto b = brp;
while ( qlen > 0 )
@@ -1740,7 +1610,7 @@ pure @safe:
}
qlen /= 10; // retry with one digit less
pos = --p;
- len = l;
+ dst.len = l;
brp = b;
}
}
@@ -1860,7 +1730,7 @@ pure @safe:
case '0': .. case '9':
if ( mayBeTemplateInstanceName() )
{
- auto t = len;
+ auto t = dst.length;
try
{
@@ -1871,7 +1741,7 @@ pure @safe:
catch ( ParseException e )
{
debug(trace) printf( "not a template instance name\n" );
- len = t;
+ dst.len = t;
}
}
goto case;
@@ -1889,10 +1759,9 @@ pure @safe:
{
// try to demangle a function, in case we are pointing to some function local
auto prevpos = pos;
- auto prevlen = len;
+ auto prevlen = dst.length;
auto prevbrp = brp;
- char[] attr;
try
{
if ( 'M' == front )
@@ -1908,6 +1777,7 @@ pure @safe:
}
if ( isCallConvention( front ) )
{
+ char[] attr;
// we don't want calling convention and attributes in the qualified name
parseCallConvention();
auto attributes = parseFuncAttr();
@@ -1917,23 +1787,23 @@ pure @safe:
put(str);
put(' ');
}
- attr = dst[prevlen .. len];
+ attr = dst[prevlen .. $];
}
put( '(' );
parseFuncArguments();
put( ')' );
+ return attr;
}
}
catch ( ParseException )
{
// not part of a qualified name, so back up
pos = prevpos;
- len = prevlen;
+ dst.len = prevlen;
brp = prevbrp;
- attr = null;
}
- return attr;
+ return null;
}
/*
@@ -1945,7 +1815,7 @@ pure @safe:
{
debug(trace) printf( "parseQualifiedName+\n" );
debug(trace) scope(success) printf( "parseQualifiedName-\n" );
- size_t beg = len;
+ size_t beg = dst.length;
size_t n = 0;
do
@@ -1956,7 +1826,7 @@ pure @safe:
parseFunctionTypeNoReturn();
} while ( isSymbolNameFront() );
- return dst[beg .. len];
+ return dst[beg .. $];
}
@@ -1977,17 +1847,17 @@ pure @safe:
match( 'D' );
do
{
- size_t beg = len;
- size_t nameEnd = len;
+ size_t beg = dst.length;
+ size_t nameEnd = dst.length;
char[] attr;
do
{
if ( attr )
- remove( attr ); // dump attributes of parent symbols
- if ( beg != len )
+ dst.remove(attr); // dump attributes of parent symbols
+ if (beg != dst.length)
put( '.' );
parseSymbolName();
- nameEnd = len;
+ nameEnd = dst.length;
attr = parseFunctionTypeNoReturn( displayType );
} while ( isSymbolNameFront() );
@@ -1995,7 +1865,7 @@ pure @safe:
if ( displayType )
{
attr = shift( attr );
- nameEnd = len - attr.length; // name includes function arguments
+ nameEnd = dst.length - attr.length; // name includes function arguments
}
name = dst[beg .. nameEnd];
@@ -2003,7 +1873,7 @@ pure @safe:
if ( 'M' == front )
popFront(); // has 'this' pointer
- auto lastlen = len;
+ auto lastlen = dst.length;
auto type = parseType();
if ( displayType )
{
@@ -2016,7 +1886,7 @@ pure @safe:
{
// remove type
assert( attr.length == 0 );
- len = lastlen;
+ dst.len = lastlen;
}
if ( pos >= buf.length || (n != 0 && pos >= end) )
return;
@@ -2040,15 +1910,6 @@ pure @safe:
parseMangledName( AddType.yes == addType );
}
- char[] copyInput() return scope
- {
- if (dst.length < buf.length)
- dst.length = buf.length;
- char[] r = dst[0 .. buf.length];
- r[] = buf[];
- return r;
- }
-
char[] doDemangle(alias FUNC)() return scope
{
while ( true )
@@ -2057,17 +1918,17 @@ pure @safe:
{
debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr );
FUNC();
- return dst[0 .. len];
+ return dst[0 .. $];
}
catch ( OverflowException e )
{
debug(trace) printf( "overflow... restarting\n" );
- auto a = minBufSize;
- auto b = 2 * dst.length;
+ auto a = Buffer.minSize;
+ auto b = 2 * dst.dst.length;
auto newsz = a < b ? b : a;
debug(info) printf( "growing dst to %lu bytes\n", newsz );
- dst.length = newsz;
- pos = len = brp = 0;
+ dst.dst.length = newsz;
+ pos = dst.len = brp = 0;
continue;
}
catch ( ParseException e )
@@ -2077,7 +1938,7 @@ pure @safe:
auto msg = e.toString();
printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
}
- return copyInput();
+ return dst.copyInput(buf);
}
catch ( Exception e )
{
@@ -2119,7 +1980,7 @@ char[] demangle(return scope const(char)[] buf, return scope char[] dst = null,
// fast path (avoiding throwing & catching exception) for obvious
// non-D mangled names
if (buf.length < 2 || !(buf[0] == 'D' || buf[0..2] == "_D"))
- return d.copyInput();
+ return d.dst.copyInput(buf);
return d.demangleName();
}
@@ -2212,7 +2073,7 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
d.popFront();
size_t n = d.decodeBackref();
if (!n || n > refpos)
- d.error("invalid back reference");
+ error("invalid back reference");
auto savepos = d.pos;
scope(exit) d.pos = savepos;
@@ -2220,11 +2081,11 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
auto idlen = d.decodeNumber();
if (d.pos + idlen > d.buf.length)
- d.error("invalid back reference");
+ error("invalid back reference");
auto id = d.buf[d.pos .. d.pos + idlen];
auto pid = id in idpos;
if (!pid)
- d.error("invalid back reference");
+ error("invalid back reference");
npos = positionInResult(*pid);
}
encodeBackref(reslen - npos);
@@ -2235,7 +2096,7 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
{
auto n = d.decodeNumber();
if (!n || n > d.buf.length || n > d.buf.length - d.pos)
- d.error("LName too shot or too long");
+ error("LName too shot or too long");
auto id = d.buf[d.pos .. d.pos + n];
d.pos += n;
if (auto pid = id in idpos)
@@ -2267,7 +2128,7 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
d.popFront();
auto n = d.decodeBackref();
if (n == 0 || n > refPos)
- d.error("invalid back reference");
+ error("invalid back reference");
size_t npos = positionInResult(refPos - n);
size_t reslen = result.length;
@@ -2903,6 +2764,7 @@ private shared CXX_DEMANGLER __cxa_demangle;
CXX_DEMANGLER getCXXDemangler() nothrow @trusted
{
+ import core.atomic : atomicLoad, atomicStore;
if (__cxa_demangle is null)
version (Posix)
{
@@ -2916,17 +2778,21 @@ CXX_DEMANGLER getCXXDemangler() nothrow @trusted
version (Solaris) import core.sys.solaris.dlfcn : RTLD_DEFAULT;
if (auto found = cast(CXX_DEMANGLER) dlsym(RTLD_DEFAULT, "__cxa_demangle"))
- __cxa_demangle = found;
+ atomicStore(__cxa_demangle, found);
}
if (__cxa_demangle is null)
- __cxa_demangle = (const char* mangled_name, char* output_buffer,
- size_t* length, int* status) nothrow pure @trusted {
- *status = -1;
- return null;
- };
+ {
+ static extern(C) char* _(const char* mangled_name, char* output_buffer,
+ size_t* length, int* status) nothrow pure @trusted
+ {
+ *status = -1;
+ return null;
+ }
+ atomicStore(__cxa_demangle, &_);
+ }
- return __cxa_demangle;
+ return atomicLoad(__cxa_demangle);
}
/**
@@ -2967,3 +2833,163 @@ private char[] demangleCXX(return scope const(char)[] buf, CXX_DEMANGLER __cxa_d
dst[] = buf[];
return dst;
}
+
+/**
+ * Error handling through Exceptions
+ *
+ * The following types / functions are only used in this module,
+ * hence why the functions are `@trusted`.
+ * To make things `@nogc`, default-initialized instances are thrown.
+ */
+private class ParseException : Exception
+{
+ public this(string msg) @safe pure nothrow
+ {
+ super(msg);
+ }
+}
+
+/// Ditto
+private class OverflowException : Exception
+{
+ public this(string msg) @safe pure nothrow
+ {
+ super(msg);
+ }
+}
+
+/// Ditto
+private noreturn error(string msg = "Invalid symbol") @trusted pure
+{
+ pragma(inline, false); // tame dmd inliner
+
+ //throw new ParseException( msg );
+ debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
+ throw __ctfe ? new ParseException(msg)
+ : cast(ParseException) __traits(initSymbol, ParseException).ptr;
+}
+
+/// Ditto
+private noreturn overflow(string msg = "Buffer overflow") @trusted pure
+{
+ pragma(inline, false); // tame dmd inliner
+
+ //throw new OverflowException( msg );
+ debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
+ throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr;
+}
+
+private struct Buffer
+{
+ enum size_t minSize = 4000;
+
+ @safe pure:
+
+ private char[] dst;
+ private size_t len;
+
+ public alias opDollar = len;
+
+ public size_t length () const scope @safe pure nothrow @nogc
+ {
+ return this.len;
+ }
+
+ public inout(char)[] opSlice (size_t from, size_t to)
+ inout return scope @safe pure nothrow @nogc
+ {
+ assert(from <= to);
+ assert(to <= len);
+ return this.dst[from .. to];
+ }
+
+ static bool contains(scope const(char)[] a, scope const(char)[] b) @trusted
+ {
+ if (a.length && b.length)
+ {
+ auto bend = b.ptr + b.length;
+ auto aend = a.ptr + a.length;
+ return a.ptr <= b.ptr && bend <= aend;
+ }
+ return false;
+ }
+
+ char[] copyInput(scope const(char)[] buf)
+ return scope nothrow
+ {
+ if (dst.length < buf.length)
+ dst.length = buf.length;
+ char[] r = dst[0 .. buf.length];
+ r[] = buf[];
+ return r;
+ }
+
+ // move val to the end of the dst buffer
+ char[] shift(scope const(char)[] val) return scope
+ {
+ pragma(inline, false); // tame dmd inliner
+
+ if (val.length)
+ {
+ assert( contains( dst[0 .. len], val ) );
+ debug(info) printf( "shifting (%.*s)\n", cast(int) val.length, val.ptr );
+
+ if (len + val.length > dst.length)
+ overflow();
+ size_t v = &val[0] - &dst[0];
+ dst[len .. len + val.length] = val[];
+ for (size_t p = v; p < len; p++)
+ dst[p] = dst[p + val.length];
+
+ return dst[len - val.length .. len];
+ }
+ return null;
+ }
+
+ // remove val from dst buffer
+ void remove(scope const(char)[] val) scope
+ {
+ pragma(inline, false); // tame dmd inliner
+
+ if ( val.length )
+ {
+ assert( contains( dst[0 .. len], val ) );
+ debug(info) printf( "removing (%.*s)\n", cast(int) val.length, val.ptr );
+ size_t v = &val[0] - &dst[0];
+ assert( len >= val.length && len <= dst.length );
+ len -= val.length;
+ for (size_t p = v; p < len; p++)
+ dst[p] = dst[p + val.length];
+ }
+ }
+
+ char[] append(scope const(char)[] val) return scope
+ {
+ pragma(inline, false); // tame dmd inliner
+
+ if (val.length)
+ {
+ if ( !dst.length )
+ dst.length = minSize;
+ assert( !contains( dst[0 .. len], val ) );
+ debug(info) printf( "appending (%.*s)\n", cast(int) val.length, val.ptr );
+
+ if ( dst.length - len >= val.length && &dst[len] == &val[0] )
+ {
+ // data is already in place
+ auto t = dst[len .. len + val.length];
+ len += val.length;
+ return t;
+ }
+ if ( dst.length - len >= val.length )
+ {
+ dst[len .. len + val.length] = val[];
+ auto t = dst[len .. len + val.length];
+ len += val.length;
+ return t;
+ }
+ overflow();
+ }
+ return null;
+ }
+}
diff --git a/libphobos/libdruntime/core/internal/array/concatenation.d b/libphobos/libdruntime/core/internal/array/concatenation.d
index 99f33da..ff777a6 100644
--- a/libphobos/libdruntime/core/internal/array/concatenation.d
+++ b/libphobos/libdruntime/core/internal/array/concatenation.d
@@ -8,71 +8,172 @@
*/
module core.internal.array.concatenation;
-/// See $(REF _d_arraycatnTX, rt,lifetime)
-private extern (C) void[] _d_arraycatnTX(const TypeInfo ti, scope byte[][] arrs) pure nothrow;
-
-/// Implementation of `_d_arraycatnTX` and `_d_arraycatnTXTrace`
-template _d_arraycatnTXImpl(Tarr : ResultArrT[], ResultArrT : T[], T)
+/**
+ * Concatenate the arrays inside of `froms`.
+ * `_d_arraycatnTX(a, b, c)` means `a ~ b ~ c`.
+ *
+ * Params:
+ * froms = Arrays to be concatenated.
+ * Returns:
+ * A newly allocated array that contains all the elements from `froms`.
+ */
+Tret _d_arraycatnTX(Tret, Tarr...)(auto ref Tarr froms) @trusted
{
- private enum errorMessage = "Cannot concatenate arrays if compiling without support for runtime type information!";
+ import core.internal.traits : hasElaborateCopyConstructor, Unqual;
+ import core.lifetime : copyEmplace;
+ import core.stdc.string : memcpy;
- /**
- * Concatenating the arrays inside of `arrs`.
- * `_d_arraycatnTX([a, b, c])` means `a ~ b ~ c`.
- * Params:
- * arrs = Array containing arrays that will be concatenated.
- * Returns:
- * A newly allocated array that contains all the elements from all the arrays in `arrs`.
- * Bugs:
- * This function template was ported from a much older runtime hook that bypassed safety,
- * purity, and throwabilty checks. To prevent breaking existing code, this function template
- * is temporarily declared `@trusted pure nothrow` until the implementation can be brought up to modern D expectations.
- */
- ResultArrT _d_arraycatnTX(scope const Tarr arrs) @trusted pure nothrow
+ Tret res;
+ size_t totalLen;
+
+ alias T = typeof(res[0]);
+ enum elemSize = T.sizeof;
+ enum hasPostblit = __traits(hasPostblit, T);
+
+ static foreach (from; froms)
+ static if (is (typeof(from) : T))
+ totalLen++;
+ else
+ totalLen += from.length;
+
+ if (totalLen == 0)
+ return res;
+ res.length = totalLen;
+
+ /* Currently, if both a postblit and a cpctor are defined, the postblit is
+ * used. If this changes, the condition below will have to be adapted.
+ */
+ static if (hasElaborateCopyConstructor!T && !hasPostblit)
{
- pragma(inline, false);
- version (D_TypeInfo)
- {
- auto ti = typeid(ResultArrT);
+ size_t i = 0;
+ foreach (ref from; froms)
+ static if (is (typeof(from) : T))
+ copyEmplace(cast(T) from, res[i++]);
+ else
+ {
+ if (from.length)
+ foreach (ref elem; from)
+ copyEmplace(cast(T) elem, res[i++]);
+ }
+ }
+ else
+ {
+ auto resptr = cast(Unqual!T *) res;
+ foreach (ref from; froms)
+ static if (is (typeof(from) : T))
+ memcpy(resptr++, cast(Unqual!T *) &from, elemSize);
+ else
+ {
+ const len = from.length;
+ if (len)
+ {
+ memcpy(resptr, cast(Unqual!T *) from, len * elemSize);
+ resptr += len;
+ }
+ }
+
+ static if (hasPostblit)
+ foreach (ref elem; res)
+ (cast() elem).__xpostblit();
+ }
+
+ return res;
+}
- byte[][] arrs2 = (cast(byte[]*)arrs.ptr)[0 .. arrs.length];
- void[] result = ._d_arraycatnTX(ti, arrs2);
- return (cast(T*)result.ptr)[0 .. result.length];
+// postblit
+@safe unittest
+{
+ int counter;
+ struct S
+ {
+ int val;
+ this(this)
+ {
+ counter++;
}
- else
- assert(0, errorMessage);
}
- version (D_ProfileGC)
+ S[] arr1 = [S(0), S(1), S(2)];
+ S[] arr2 = [];
+ S[] arr3 = [S(6), S(7), S(8)];
+ S elem = S(9);
+ S[] result = _d_arraycatnTX!(S[])(arr1, arr2, arr3, elem);
+
+ assert(counter == 7);
+ assert(result == [S(0), S(1), S(2), S(6), S(7), S(8), S(9)]);
+}
+
+// copy constructor
+@safe unittest
+{
+ int counter;
+ struct S
{
- import core.internal.array.utils : _d_HookTraceImpl;
-
- /**
- * TraceGC wrapper around $(REF _d_arraycatnTX, core,internal,array,concat).
- * Bugs:
- * This function template was ported from a much older runtime hook that bypassed safety,
- * purity, and throwabilty checks. To prevent breaking existing code, this function template
- * is temporarily declared `@trusted pure nothrow` until the implementation can be brought up to modern D expectations.
- */
- alias _d_arraycatnTXTrace = _d_HookTraceImpl!(ResultArrT, _d_arraycatnTX, errorMessage);
+ int val;
+ this(ref return scope S rhs)
+ {
+ val = rhs.val;
+ counter++;
+ }
}
+
+ S[] arr1 = [S(0), S(1), S(2)];
+ S[] arr2 = [S(3), S(4), S(5)];
+ S[] arr3 = [S(6), S(7), S(8)];
+ S elem = S(9);
+ S[] result = _d_arraycatnTX!(S[])(arr1, elem, arr2, arr3);
+
+ assert(counter == 10);
+ assert(result == [S(0), S(1), S(2), S(9), S(3), S(4), S(5), S(6), S(7), S(8)]);
}
+// throwing
@safe unittest
{
int counter;
+ bool didThrow;
struct S
{
int val;
this(this)
{
counter++;
+ if (counter == 4)
+ throw new Exception("");
}
}
- S[][] arr = [[S(0), S(1), S(2), S(3)], [S(4), S(5), S(6), S(7)]];
- S[] result = _d_arraycatnTXImpl!(typeof(arr))._d_arraycatnTX(arr);
+ try
+ {
+ S[] arr1 = [S(0), S(1), S(2)];
+ S[] arr2 = [S(3), S(4), S(5)];
+ _d_arraycatnTX!(S[])(arr1, arr2);
+ }
+ catch (Exception)
+ {
+ didThrow = true;
+ }
+
+ assert(counter == 4);
+ assert(didThrow);
+}
+
+version (D_ProfileGC)
+{
+ /**
+ * TraceGC wrapper around $(REF _d_arraycatnTX, core,internal,array,concatenation).
+ */
+ Tret _d_arraycatnTXTrace(Tret, Tarr...)(string file, int line, string funcname, scope auto ref Tarr froms) @trusted
+ {
+ version (D_TypeInfo)
+ {
+ import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
+ mixin(TraceHook!(Tarr.stringof, "_d_arraycatnTX"));
- assert(counter == 8);
- assert(result == [S(0), S(1), S(2), S(3), S(4), S(5), S(6), S(7)]);
+ import core.lifetime: forward;
+ return _d_arraycatnTX!Tret(forward!froms);
+ }
+ else
+ assert(0, "Cannot concatenate arrays if compiling without support for runtime type information!");
+ }
}
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index 6d19247..62ce941 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -1509,7 +1509,7 @@ struct Gcx
List*[Bins.B_NUMSMALL] bucket; // free list for each small size
// run a collection when reaching those thresholds (number of used pages)
- float smallCollectThreshold, largeCollectThreshold;
+ float smallCollectThreshold = 0.0f, largeCollectThreshold = 0.0f;
uint usedSmallPages, usedLargePages;
// total number of mapped pages
uint mappedPages;
@@ -3529,7 +3529,7 @@ struct Pool
Small = 4,
Large = 12
}
- ShiftBy shiftBy; // shift count for the divisor used for determining bit indices.
+ ShiftBy shiftBy = void; // shift count for the divisor used for determining bit indices.
// This tracks how far back we have to go to find the nearest B_PAGE at
// a smaller address than a B_PAGEPLUS. To save space, we use a uint.
diff --git a/libphobos/libdruntime/core/internal/string.d b/libphobos/libdruntime/core/internal/string.d
index 64a9cc9..e09bba4 100644
--- a/libphobos/libdruntime/core/internal/string.d
+++ b/libphobos/libdruntime/core/internal/string.d
@@ -12,26 +12,57 @@ module core.internal.string;
pure:
nothrow:
@nogc:
+@safe:
-alias UnsignedStringBuf = char[20];
+alias UnsignedStringBuf = char[64];
/**
Converts an unsigned integer value to a string of characters.
-This implementation is a template so it can be used when compiling with -betterC.
+Can be used when compiling with -betterC. Does not allocate memory.
Params:
+ T = char, wchar or dchar
value = the unsigned integer value to convert
buf = the pre-allocated buffer used to store the result
- radix = the numeric base to use in the conversion (defaults to 10)
+ radix = the numeric base to use in the conversion 2 through 36 (defaults to 10)
+ upperCase = use upper case letters for radices 11 - 36
Returns:
The unsigned integer value as a string of characters
*/
-char[] unsignedToTempString(uint radix = 10)(ulong value, return scope char[] buf) @safe
-if (radix >= 2 && radix <= 16)
+T[] unsignedToTempString(uint radix = 10, bool upperCase = false, T)(ulong value, return scope T[] buf)
+if (radix >= 2 && radix <= 36 &&
+ (is(T == char) || is(T == wchar) || is(T == dchar)))
{
+ enum baseChar = upperCase ? 'A' : 'a';
size_t i = buf.length;
+
+ static if (size_t.sizeof == 4) // 32 bit CPU
+ {
+ if (value <= uint.max)
+ {
+ // use faster 32 bit arithmetic
+ uint val = cast(uint) value;
+ do
+ {
+ uint x = void;
+ if (val < radix)
+ {
+ x = cast(uint)val;
+ val = 0;
+ }
+ else
+ {
+ x = cast(uint)(val % radix);
+ val /= radix;
+ }
+ buf[--i] = cast(char)((radix <= 10 || x < 10) ? x + '0' : x - 10 + baseChar);
+ } while (val);
+ return buf[i .. $];
+ }
+ }
+
do
{
uint x = void;
@@ -45,7 +76,7 @@ if (radix >= 2 && radix <= 16)
x = cast(uint)(value % radix);
value /= radix;
}
- buf[--i] = cast(char)((radix <= 10 || x < 10) ? x + '0' : x - 10 + 'a');
+ buf[--i] = cast(char)((radix <= 10 || x < 10) ? x + '0' : x - 10 + baseChar);
} while (value);
return buf[i .. $];
}
@@ -73,7 +104,7 @@ Params:
Returns:
The unsigned integer value as a string of characters
*/
-auto unsignedToTempString(uint radix = 10)(ulong value) @safe
+auto unsignedToTempString(uint radix = 10)(ulong value)
{
// Need a buffer of 65 bytes for radix of 2 with room for
// signedToTempString to possibly add a negative sign.
@@ -85,11 +116,12 @@ auto unsignedToTempString(uint radix = 10)(ulong value) @safe
unittest
{
- UnsignedStringBuf buf;
+ UnsignedStringBuf buf = void;
assert(0.unsignedToTempString(buf) == "0");
assert(1.unsignedToTempString(buf) == "1");
assert(12.unsignedToTempString(buf) == "12");
assert(0x12ABCF .unsignedToTempString!16(buf) == "12abcf");
+ assert(0x12ABCF .unsignedToTempString!(16, true)(buf) == "12ABCF");
assert(long.sizeof.unsignedToTempString(buf) == "8");
assert(uint.max.unsignedToTempString(buf) == "4294967295");
assert(ulong.max.unsignedToTempString(buf) == "18446744073709551615");
@@ -106,16 +138,17 @@ unittest
// test bad radices
assert(!is(typeof(100.unsignedToTempString!1(buf))));
assert(!is(typeof(100.unsignedToTempString!0(buf) == "")));
+ assert(!is(typeof(100.unsignedToTempString!37(buf) == "")));
}
-alias SignedStringBuf = char[20];
+alias SignedStringBuf = char[65];
-char[] signedToTempString(uint radix = 10)(long value, return scope char[] buf) @safe
+T[] signedToTempString(uint radix = 10, bool upperCase = false, T)(long value, return scope T[] buf)
{
bool neg = value < 0;
if (neg)
value = cast(ulong)-value;
- auto r = unsignedToTempString!radix(value, buf);
+ auto r = unsignedToTempString!(radix, upperCase)(value, buf);
if (neg)
{
// about to do a slice without a bounds check
@@ -126,7 +159,7 @@ char[] signedToTempString(uint radix = 10)(long value, return scope char[] buf)
return r;
}
-auto signedToTempString(uint radix = 10)(long value) @safe
+auto signedToTempString(uint radix = 10)(long value)
{
bool neg = value < 0;
if (neg)
@@ -142,7 +175,7 @@ auto signedToTempString(uint radix = 10)(long value) @safe
unittest
{
- SignedStringBuf buf;
+ SignedStringBuf buf = void;
assert(0.signedToTempString(buf) == "0");
assert(1.signedToTempString(buf) == "1");
assert((-1).signedToTempString(buf) == "-1");
@@ -150,6 +183,7 @@ unittest
assert((-12).signedToTempString(buf) == "-12");
assert(0x12ABCF .signedToTempString!16(buf) == "12abcf");
assert((-0x12ABCF) .signedToTempString!16(buf) == "-12abcf");
+ assert((-0x12ABCF) .signedToTempString!(16, true)(buf) == "-12ABCF");
assert(long.sizeof.signedToTempString(buf) == "8");
assert(int.max.signedToTempString(buf) == "2147483647");
assert(int.min.signedToTempString(buf) == "-2147483648");
@@ -183,7 +217,7 @@ unittest
* Returns:
* number of digits
*/
-int numDigits(uint radix = 10)(ulong value) @safe if (radix >= 2 && radix <= 36)
+int numDigits(uint radix = 10)(ulong value) if (radix >= 2 && radix <= 36)
{
int n = 1;
while (1)
diff --git a/libphobos/libdruntime/core/stdc/config.d b/libphobos/libdruntime/core/stdc/config.d
index c85682e..ca833ea 100644
--- a/libphobos/libdruntime/core/stdc/config.d
+++ b/libphobos/libdruntime/core/stdc/config.d
@@ -281,11 +281,185 @@ else
alias cpp_ptrdiff_t = ptrdiff_t;
}
-// ABI layout of native complex types.
-private struct _Complex(T)
+/** ABI layout of native complex types.
+ */
+struct _Complex(T)
+ if (is(T == float) || is(T == double) || is(T == c_long_double))
{
- T re;
- T im;
+ T re = 0;
+ T im = 0;
+
+ // Construction
+/+ https://issues.dlang.org/show_bug.cgi?id=23788 dmd codegen problem with constructors and _Complex!float
+ this(_Complex!float c) { re = c.re; im = c.im; }
+ this(_Complex!double c) { re = c.re; im = c.im; }
+ this(_Complex!c_long_double c) { re = c.re; im = c.im; }
+
+ this(T re, T im) { this.re = re; this.im = im; }
+
+ this(T re) { this.re = re; this.im = 0; }
++/
+ // Cast
+ R opCast(R)()
+ if (is(R == _Complex!float) || is(R == _Complex!double) || is(R == _Complex!c_long_double))
+ {
+ return R(this.re, this.im);
+ }
+
+ // Assignment
+
+ ref _Complex opAssign(_Complex!float c) { re = c.re; im = c.im; return this; }
+ ref _Complex opAssign(_Complex!double c) { re = c.re; im = c.im; return this; }
+ ref _Complex opAssign(_Complex!c_long_double c) { re = c.re; im = c.im; return this; }
+
+ ref _Complex opAssign(T t) { re = t; im = 0; return this; }
+
+ // Equals
+
+ bool opEquals(_Complex!float c) { return re == c.re && im == c.im; }
+ bool opEquals(_Complex!double c) { return re == c.re && im == c.im; }
+ bool opEquals(_Complex!c_long_double c) { return re == c.re && im == c.im; }
+
+ bool opEquals(T t) { return re == t && im == 0; }
+
+ // Unary operators
+
+ // +complex
+ _Complex opUnary(string op)()
+ if (op == "+")
+ {
+ return this;
+ }
+
+ // -complex
+ _Complex opUnary(string op)()
+ if (op == "-")
+ {
+ return _Complex(-re, -im);
+ }
+
+ // BINARY OPERATORS
+
+ // complex op complex
+ _Complex!(CommonType!(T,R)) opBinary(string op, R)(_Complex!R z)
+ {
+ alias C = typeof(return);
+ auto w = C(this.re, this.im);
+ return w.opOpAssign!(op)(z);
+ }
+
+ // complex op numeric
+ _Complex!(CommonType!(T,R)) opBinary(string op, R)(R r)
+ if (is(R : c_long_double))
+ {
+ alias C = typeof(return);
+ auto w = C(this.re, this.im);
+ return w.opOpAssign!(op)(r);
+ }
+
+ // numeric + complex, numeric * complex
+ _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r)
+ if ((op == "+" || op == "*") && is(R : c_long_double))
+ {
+ return opBinary!(op)(r);
+ }
+
+ // numeric - complex
+ _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r)
+ if (op == "-" && is(R : c_long_double))
+ {
+ return _Complex(r - re, -im);
+ }
+
+ // numeric / complex
+ _Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(R r)
+ if (op == "/" && is(R : c_long_double))
+ {
+ import core.math : fabs;
+ typeof(return) w = void;
+ if (fabs(re) < fabs(im))
+ {
+ immutable ratio = re/im;
+ immutable rdivd = r/(re*ratio + im);
+
+ w.re = rdivd*ratio;
+ w.im = -rdivd;
+ }
+ else
+ {
+ immutable ratio = im/re;
+ immutable rdivd = r/(re + im*ratio);
+
+ w.re = rdivd;
+ w.im = -rdivd*ratio;
+ }
+
+ return w;
+ }
+
+ // OP-ASSIGN OPERATORS
+
+ // complex += complex, complex -= complex
+ ref _Complex opOpAssign(string op, C)(C z)
+ if ((op == "+" || op == "-") && is(C R == _Complex!R))
+ {
+ mixin ("re "~op~"= z.re;");
+ mixin ("im "~op~"= z.im;");
+ return this;
+ }
+
+ // complex *= complex
+ ref _Complex opOpAssign(string op, C)(C z)
+ if (op == "*" && is(C R == _Complex!R))
+ {
+ auto temp = re*z.re - im*z.im;
+ im = im*z.re + re*z.im;
+ re = temp;
+ return this;
+ }
+
+ // complex /= complex
+ ref _Complex opOpAssign(string op, C)(C z)
+ if (op == "/" && is(C R == _Complex!R))
+ {
+ import core.math : fabs;
+ if (fabs(z.re) < fabs(z.im))
+ {
+ immutable ratio = z.re/z.im;
+ immutable denom = z.re*ratio + z.im;
+
+ immutable temp = (re*ratio + im)/denom;
+ im = (im*ratio - re)/denom;
+ re = temp;
+ }
+ else
+ {
+ immutable ratio = z.im/z.re;
+ immutable denom = z.re + z.im*ratio;
+
+ immutable temp = (re + im*ratio)/denom;
+ im = (im - re*ratio)/denom;
+ re = temp;
+ }
+ return this;
+ }
+
+ // complex += numeric, complex -= numeric
+ ref _Complex opOpAssign(string op, U : T)(U a)
+ if (op == "+" || op == "-")
+ {
+ mixin ("re "~op~"= a;");
+ return this;
+ }
+
+ // complex *= numeric, complex /= numeric
+ ref _Complex opOpAssign(string op, U : T)(U a)
+ if (op == "*" || op == "/")
+ {
+ mixin ("re "~op~"= a;");
+ mixin ("im "~op~"= a;");
+ return this;
+ }
// Helper properties.
pragma(inline, true)
@@ -311,6 +485,168 @@ enum __c_complex_real : _Complex!c_long_double;
alias c_complex_float = __c_complex_float;
alias c_complex_double = __c_complex_double;
alias c_complex_real = __c_complex_real;
+
+private template CommonType(T, R)
+{
+ // Special kludge for Microsoft c_long_double
+ static if (is(T == c_long_double))
+ alias CommonType = T;
+ else static if (is(R == c_long_double))
+ alias CommonType = R;
+ else
+ alias CommonType = typeof(true ? T.init : R.init);
+}
+
+/************ unittests ****************/
+
+version (unittest)
+{
+ private:
+
+ alias _cfloat = _Complex!float;
+ alias _cdouble = _Complex!double;
+ alias _creal = _Complex!c_long_double;
+
+ T abs(T)(T t) => t < 0 ? -t : t;
+}
+
+@safe pure nothrow unittest
+{
+ auto c1 = _cdouble(1.0, 1.0);
+
+ // Check unary operations.
+ auto c2 = _cdouble(0.5, 2.0);
+
+ assert(c2 == +c2);
+
+ assert((-c2).re == -(c2.re));
+ assert((-c2).im == -(c2.im));
+ assert(c2 == -(-c2));
+
+ // Check complex-complex operations.
+ auto cpc = c1 + c2;
+ assert(cpc.re == c1.re + c2.re);
+ assert(cpc.im == c1.im + c2.im);
+
+ auto cmc = c1 - c2;
+ assert(cmc.re == c1.re - c2.re);
+ assert(cmc.im == c1.im - c2.im);
+
+ auto ctc = c1 * c2;
+ assert(ctc == _cdouble(-1.5, 2.5));
+
+ auto cdc = c1 / c2;
+ assert(abs(cdc.re - 0.5882352941177) < 1e-12);
+ assert(abs(cdc.im - -0.3529411764706) < 1e-12);
+
+ // Check complex-real operations.
+ double a = 123.456;
+
+ auto cpr = c1 + a;
+ assert(cpr.re == c1.re + a);
+ assert(cpr.im == c1.im);
+
+ auto cmr = c1 - a;
+ assert(cmr.re == c1.re - a);
+ assert(cmr.im == c1.im);
+
+ auto ctr = c1 * a;
+ assert(ctr.re == c1.re*a);
+ assert(ctr.im == c1.im*a);
+
+ auto cdr = c1 / a;
+ assert(abs(cdr.re - 0.00810005184033) < 1e-12);
+ assert(abs(cdr.im - 0.00810005184033) < 1e-12);
+
+ auto rpc = a + c1;
+ assert(rpc == cpr);
+
+ auto rmc = a - c1;
+ assert(rmc.re == a-c1.re);
+ assert(rmc.im == -c1.im);
+
+ auto rtc = a * c1;
+ assert(rtc == ctr);
+
+ auto rdc = a / c1;
+ assert(abs(rdc.re - 61.728) < 1e-12);
+ assert(abs(rdc.im - -61.728) < 1e-12);
+
+ rdc = a / c2;
+ assert(abs(rdc.re - 14.5242352941) < 1e-10);
+ assert(abs(rdc.im - -58.0969411765) < 1e-10);
+
+ // Check operations between different complex types.
+ auto cf = _cfloat(1.0, 1.0);
+ auto cr = _creal(1.0, 1.0);
+ auto c1pcf = c1 + cf;
+ auto c1pcr = c1 + cr;
+ static assert(is(typeof(c1pcf) == _cdouble));
+ static assert(is(typeof(c1pcr) == _creal));
+ assert(c1pcf.re == c1pcr.re);
+ assert(c1pcf.im == c1pcr.im);
+
+ auto c1c = c1;
+ auto c2c = c2;
+
+ c1c /= c1;
+ assert(abs(c1c.re - 1.0) < 1e-10);
+ assert(abs(c1c.im - 0.0) < 1e-10);
+
+ c1c = c1;
+ c1c /= c2;
+ assert(abs(c1c.re - 0.5882352941177) < 1e-12);
+ assert(abs(c1c.im - -0.3529411764706) < 1e-12);
+
+ c2c /= c1;
+ assert(abs(c2c.re - 1.25) < 1e-11);
+ assert(abs(c2c.im - 0.75) < 1e-12);
+
+ c2c = c2;
+ c2c /= c2;
+ assert(abs(c2c.re - 1.0) < 1e-11);
+ assert(abs(c2c.im - 0.0) < 1e-12);
+}
+
+@safe pure nothrow unittest
+{
+ // Initialization
+ _cdouble a = _cdouble(1, 0);
+ assert(a.re == 1 && a.im == 0);
+ _cdouble b = _cdouble(1.0, 0);
+ assert(b.re == 1.0 && b.im == 0);
+// _cdouble c = _creal(1.0, 2);
+// assert(c.re == 1.0 && c.im == 2);
+}
+
+@safe pure nothrow unittest
+{
+ // Assignments and comparisons
+ _cdouble z;
+
+ z = 1;
+ assert(z == 1);
+ assert(z.re == 1.0 && z.im == 0.0);
+
+ z = 2.0;
+ assert(z == 2.0);
+ assert(z.re == 2.0 && z.im == 0.0);
+
+ z = 1.0L;
+ assert(z == 1.0L);
+ assert(z.re == 1.0 && z.im == 0.0);
+
+ auto w = _creal(1.0, 1.0);
+ z = w;
+ assert(z == w);
+ assert(z.re == 1.0 && z.im == 1.0);
+
+ auto c = _cfloat(2.0, 2.0);
+ z = c;
+ assert(z == c);
+ assert(z.re == 2.0 && z.im == 2.0);
+}
+
}
diff --git a/libphobos/libdruntime/core/sync/condition.d b/libphobos/libdruntime/core/sync/condition.d
index ddd04ae..afcfd74 100644
--- a/libphobos/libdruntime/core/sync/condition.d
+++ b/libphobos/libdruntime/core/sync/condition.d
@@ -84,7 +84,8 @@ class Condition
/// ditto
this( shared Mutex m ) shared nothrow @safe @nogc
{
- this(m, true);
+ import core.atomic : atomicLoad;
+ this(atomicLoad(m), true);
}
//
@@ -117,7 +118,15 @@ class Condition
}
else version (Posix)
{
- m_assocMutex = m;
+ static if (is(Q == shared))
+ {
+ import core.atomic : atomicLoad;
+ m_assocMutex = atomicLoad(m);
+ }
+ else
+ {
+ m_assocMutex = m;
+ }
static if ( is( typeof( pthread_condattr_setclock ) ) )
{
() @trusted
@@ -183,7 +192,8 @@ class Condition
/// ditto
@property shared(Mutex) mutex() shared
{
- return m_assocMutex;
+ import core.atomic : atomicLoad;
+ return atomicLoad(m_assocMutex);
}
// undocumented function for internal use
@@ -195,7 +205,8 @@ class Condition
// ditto
final @property shared(Mutex) mutex_nothrow() shared pure nothrow @safe @nogc
{
- return m_assocMutex;
+ import core.atomic : atomicLoad;
+ return atomicLoad(m_assocMutex);
}
////////////////////////////////////////////////////////////////////////////
diff --git a/libphobos/libdruntime/core/thread/package.d b/libphobos/libdruntime/core/thread/package.d
index 71b0237..d81ebbd 100644
--- a/libphobos/libdruntime/core/thread/package.d
+++ b/libphobos/libdruntime/core/thread/package.d
@@ -18,3 +18,42 @@ public import core.thread.threadbase;
public import core.thread.threadgroup;
public import core.thread.types;
public import core.thread.context;
+
+
+// this test is here to avoid a cyclic dependency between
+// core.thread and core.atomic
+unittest
+{
+ import core.atomic;
+
+ // Use heap memory to ensure an optimizing
+ // compiler doesn't put things in registers.
+ uint* x = new uint();
+ bool* f = new bool();
+ uint* r = new uint();
+
+ auto thr = new Thread(()
+ {
+ while (!*f)
+ {
+ }
+
+ atomicFence();
+
+ *r = *x;
+ });
+
+ thr.start();
+
+ *x = 42;
+
+ atomicFence();
+
+ *f = true;
+
+ atomicFence();
+
+ thr.join();
+
+ assert(*r == 42);
+}
diff --git a/libphobos/libdruntime/core/thread/types.d b/libphobos/libdruntime/core/thread/types.d
index eb84ad7..998f610 100644
--- a/libphobos/libdruntime/core/thread/types.d
+++ b/libphobos/libdruntime/core/thread/types.d
@@ -41,8 +41,9 @@ version (GNU)
}
else
{
- // this should be true for most architectures
- enum isStackGrowingDown = true;
+ version (X86) enum isStackGrowingDown = true;
+ else version (X86_64) enum isStackGrowingDown = true;
+ else static assert(0, "It is undefined how the stack grows on this architecture.");
}
package
diff --git a/libphobos/libdruntime/core/time.d b/libphobos/libdruntime/core/time.d
index 8d50875..be941e2a 100644
--- a/libphobos/libdruntime/core/time.d
+++ b/libphobos/libdruntime/core/time.d
@@ -18,7 +18,7 @@
$(LEADINGROW Types)
$(TR $(TDNW $(LREF Duration)) $(TD Represents a duration of time of weeks
or less (kept internally as hnsecs). (e.g. 22 days or 700 seconds).))
- $(TR $(TDNW $(LREF TickDuration)) $(TD Represents a duration of time in
+ $(TR $(TDNW $(LREF TickDuration)) $(TD $(RED DEPRECATED) Represents a duration of time in
system clock ticks, using the highest precision that the system provides.))
$(TR $(TDNW $(LREF MonoTime)) $(TD Represents a monotonic timestamp in
system clock ticks, using the highest precision that the system provides.))
@@ -682,21 +682,21 @@ public:
$(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration))
$(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration))
$(TR $(TD Duration) $(TD %) $(TD Duration) $(TD -->) $(TD Duration))
- $(TR $(TD Duration) $(TD +) $(TD TickDuration) $(TD -->) $(TD Duration))
- $(TR $(TD Duration) $(TD -) $(TD TickDuration) $(TD -->) $(TD Duration))
)
Params:
rhs = The duration to add to or subtract from this $(D Duration).
+/
- Duration opBinary(string op, D)(D rhs) const nothrow @nogc
- if (((op == "+" || op == "-" || op == "%") && is(immutable D == immutable Duration)) ||
- ((op == "+" || op == "-") && is(immutable D == immutable TickDuration)))
+ Duration opBinary(string op)(const Duration rhs) const nothrow @nogc
+ if (op == "+" || op == "-" || op == "%")
{
- static if (is(immutable D == immutable Duration))
- return Duration(mixin("_hnsecs " ~ op ~ " rhs._hnsecs"));
- else
- return Duration(mixin("_hnsecs " ~ op ~ " rhs.hnsecs"));
+ return Duration(mixin("_hnsecs " ~ op ~ " rhs._hnsecs"));
+ }
+
+ deprecated Duration opBinary(string op)(const TickDuration rhs) const nothrow @nogc
+ if (op == "+" || op == "-")
+ {
+ return Duration(mixin("_hnsecs " ~ op ~ " rhs.hnsecs"));
}
version (CoreUnittest) unittest
@@ -733,7 +733,13 @@ public:
assert((cast(D)Duration(-7)) - (cast(E)Duration(-5)) == Duration(-2));
assert((cast(D)Duration(-7)) % (cast(E)Duration(5)) == Duration(-2));
}
+ }
+ }
+ version (CoreUnittest) deprecated unittest
+ {
+ foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
+ {
foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
{
assertApprox((cast(D)Duration(5)) + cast(T)TickDuration.from!"usecs"(7), Duration(70), Duration(80));
@@ -761,6 +767,8 @@ public:
/++
+ $(RED TickDuration is Deprecated)
+
Adds or subtracts two durations.
The legal types of arithmetic for $(D Duration) using this operator are
@@ -774,14 +782,14 @@ public:
lhs = The $(D TickDuration) to add to this $(D Duration) or to
subtract this $(D Duration) from.
+/
- Duration opBinaryRight(string op, D)(D lhs) const nothrow @nogc
+ deprecated Duration opBinaryRight(string op, D)(D lhs) const nothrow @nogc
if ((op == "+" || op == "-") &&
is(immutable D == immutable TickDuration))
{
return Duration(mixin("lhs.hnsecs " ~ op ~ " _hnsecs"));
}
- version (CoreUnittest) unittest
+ version (CoreUnittest) deprecated unittest
{
foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
{
@@ -821,21 +829,22 @@ public:
$(TR $(TD Duration) $(TD +) $(TD Duration) $(TD -->) $(TD Duration))
$(TR $(TD Duration) $(TD -) $(TD Duration) $(TD -->) $(TD Duration))
$(TR $(TD Duration) $(TD %) $(TD Duration) $(TD -->) $(TD Duration))
- $(TR $(TD Duration) $(TD +) $(TD TickDuration) $(TD -->) $(TD Duration))
- $(TR $(TD Duration) $(TD -) $(TD TickDuration) $(TD -->) $(TD Duration))
)
Params:
rhs = The duration to add to or subtract from this $(D Duration).
+/
- ref Duration opOpAssign(string op, D)(const scope D rhs) nothrow @nogc
- if (((op == "+" || op == "-" || op == "%") && is(immutable D == immutable Duration)) ||
- ((op == "+" || op == "-") && is(immutable D == immutable TickDuration)))
+ ref Duration opOpAssign(string op)(const Duration rhs) nothrow @nogc
+ if (op == "+" || op == "-" || op == "%")
{
- static if (is(immutable D == immutable Duration))
- mixin("_hnsecs " ~ op ~ "= rhs._hnsecs;");
- else
- mixin("_hnsecs " ~ op ~ "= rhs.hnsecs;");
+ mixin("_hnsecs " ~ op ~ "= rhs._hnsecs;");
+ return this;
+ }
+
+ deprecated ref Duration opOpAssign(string op)(const TickDuration rhs) nothrow @nogc
+ if (op == "+" || op == "-")
+ {
+ mixin("_hnsecs " ~ op ~ "= rhs.hnsecs;");
return this;
}
@@ -850,13 +859,6 @@ public:
throw new AssertError("op assign failed", __FILE__, line);
}
- static void test2(string op, E)
- (Duration actual, in E rhs, Duration lower, Duration upper, size_t line = __LINE__)
- {
- assertApprox(mixin("actual " ~ op ~ " rhs"), lower, upper, "op failed", line);
- assertApprox(actual, lower, upper, "op assign failed", line);
- }
-
foreach (E; AliasSeq!(Duration, const Duration, immutable Duration))
{
test1!"+="(Duration(5), (cast(E)Duration(7)), Duration(12));
@@ -888,6 +890,26 @@ public:
test1!"%="(Duration(-7), (cast(E)Duration(-5)), Duration(-2));
}
+ foreach (D; AliasSeq!(const Duration, immutable Duration))
+ {
+ foreach (E; AliasSeq!(Duration, const Duration, immutable Duration))
+ {
+ D lhs = D(120);
+ E rhs = E(120);
+ static assert(!__traits(compiles, lhs += rhs), D.stringof ~ " " ~ E.stringof);
+ }
+ }
+ }
+
+ version (CoreUnittest) deprecated unittest
+ {
+ static void test2(string op, E)
+ (Duration actual, in E rhs, Duration lower, Duration upper, size_t line = __LINE__)
+ {
+ assertApprox(mixin("actual " ~ op ~ " rhs"), lower, upper, "op failed", line);
+ assertApprox(actual, lower, upper, "op assign failed", line);
+ }
+
foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
{
test2!"+="(Duration(5), cast(T)TickDuration.from!"usecs"(7), Duration(70), Duration(80));
@@ -913,8 +935,7 @@ public:
foreach (D; AliasSeq!(const Duration, immutable Duration))
{
- foreach (E; AliasSeq!(Duration, const Duration, immutable Duration,
- TickDuration, const TickDuration, immutable TickDuration))
+ foreach (E; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
{
D lhs = D(120);
E rhs = E(120);
@@ -1170,19 +1191,21 @@ public:
/++
+ $(RED TickDuration is Deprecated)
+
Returns a $(LREF TickDuration) with the same number of hnsecs as this
$(D Duration).
Note that the conventional way to convert between $(D Duration) and
$(D TickDuration) is using $(REF to, std,conv), e.g.:
$(D duration.to!TickDuration())
+/
- TickDuration opCast(T)() const nothrow @nogc
+ deprecated TickDuration opCast(T)() const nothrow @nogc
if (is(immutable T == immutable TickDuration))
{
return TickDuration.from!"hnsecs"(_hnsecs);
}
- version (CoreUnittest) unittest
+ version (CoreUnittest) deprecated unittest
{
foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
{
@@ -1762,6 +1785,8 @@ version (CoreUnittest) @safe pure nothrow @nogc unittest
}
/++
+ $(RED TickDuration is DEPRECATED)
+
Converts a $(D TickDuration) to the given units as either an integral
value or a floating point value.
@@ -1773,6 +1798,7 @@ version (CoreUnittest) @safe pure nothrow @nogc unittest
td = The TickDuration to convert
+/
+deprecated("TickDuration has been deprecated, please use Duration or MonoTime instead")
T to(string units, T, D)(D td) @safe pure nothrow @nogc
if (is(immutable D == immutable TickDuration) &&
(units == "seconds" ||
@@ -1804,7 +1830,7 @@ T to(string units, T, D)(D td) @safe pure nothrow @nogc
}
///
-unittest
+deprecated unittest
{
auto t = TickDuration.from!"seconds"(1000);
@@ -1816,7 +1842,7 @@ unittest
assert(fabs(td - 1000) < 0.001);
}
-unittest
+deprecated unittest
{
void testFun(string U)() {
auto t1v = 1000;
@@ -2756,22 +2782,24 @@ unittest
/++
- $(RED Warning: TickDuration will be deprecated in the near future (once all
- uses of it in Phobos have been deprecated). Please use
+ $(RED Warning: TickDuration is deprecated. Please use
$(LREF MonoTime) for the cases where a monotonic timestamp is needed
and $(LREF Duration) when a duration is needed, rather than using
- TickDuration. It has been decided that TickDuration is too confusing
- (e.g. it conflates a monotonic timestamp and a duration in monotonic
- clock ticks) and that having multiple duration types is too awkward
- and confusing.)
+ TickDuration.)
Represents a duration of time in system clock ticks.
The system clock ticks are the ticks of the system clock at the highest
precision that the system provides.
+/
+deprecated("TickDuration has been deprecated, please use Duration or MonoTime instead")
struct TickDuration
{
+deprecated:
+ private static TickDuration TDRvalueOf(TickDuration td)
+ {
+ return td;
+ }
/++
The number of ticks that the system clock has in one second.
@@ -2811,14 +2839,14 @@ struct TickDuration
version (CoreUnittest) unittest
{
- assert(zero == TickDuration(0));
- assert(TickDuration.max == TickDuration(long.max));
- assert(TickDuration.min == TickDuration(long.min));
- assert(TickDuration.min < TickDuration.zero);
- assert(TickDuration.zero < TickDuration.max);
- assert(TickDuration.min < TickDuration.max);
- assert(TickDuration.min - TickDuration(1) == TickDuration.max);
- assert(TickDuration.max + TickDuration(1) == TickDuration.min);
+ assert((zero == TickDuration(0)) == true);
+ assert((TickDuration.max == TickDuration(long.max)) == true);
+ assert((TickDuration.min == TickDuration(long.min)) == true);
+ assert((TickDuration.min < TickDuration.zero) == true);
+ assert((TickDuration.zero < TickDuration.max) == true);
+ assert((TickDuration.min < TickDuration.max) == true);
+ assert((TickDuration.min - TickDuration(1) == TickDuration.max) == true);
+ assert((TickDuration.max + TickDuration(1) == TickDuration.min) == true);
}
@@ -3040,12 +3068,12 @@ struct TickDuration
{
auto a = TickDuration.currSystemTick;
auto result = a += cast(T)TickDuration.currSystemTick;
- assert(a == result);
+ assert((a == result) == true);
assert(a.to!("seconds", real)() >= 0);
auto b = TickDuration.currSystemTick;
result = b -= cast(T)TickDuration.currSystemTick;
- assert(b == result);
+ assert((b == result) == true);
assert(b.to!("seconds", real)() <= 0);
foreach (U; AliasSeq!(const TickDuration, immutable TickDuration))
@@ -3104,11 +3132,11 @@ struct TickDuration
{
foreach (T; AliasSeq!(TickDuration, const TickDuration, immutable TickDuration))
{
- assert(-(cast(T)TickDuration(7)) == TickDuration(-7));
- assert(-(cast(T)TickDuration(5)) == TickDuration(-5));
- assert(-(cast(T)TickDuration(-7)) == TickDuration(7));
- assert(-(cast(T)TickDuration(-5)) == TickDuration(5));
- assert(-(cast(T)TickDuration(0)) == TickDuration(0));
+ assert((-(cast(T)TickDuration(7)) == TickDuration(-7)) == true);
+ assert((-(cast(T)TickDuration(5)) == TickDuration(-5)) == true);
+ assert((-(cast(T)TickDuration(-7)) == TickDuration(7)) == true);
+ assert((-(cast(T)TickDuration(-5)) == TickDuration(5)) == true);
+ assert((-(cast(T)TickDuration(0)) == TickDuration(0)) == true);
}
}
@@ -3130,9 +3158,9 @@ struct TickDuration
{
T t = TickDuration.currSystemTick;
U u = t;
- assert(t == u);
- assert(rvalueOf(t) == u);
- assert(t == rvalueOf(u));
+ assert((t == u) == true);
+ assert((TDRvalueOf(t) == u) == true);
+ assert((t == TDRvalueOf(u)) == true);
}
}
@@ -3142,20 +3170,20 @@ struct TickDuration
{
T t = TickDuration.currSystemTick;
U u = t + t;
- assert(t < u);
- assert(t <= t);
- assert(u > t);
- assert(u >= u);
-
- assert(rvalueOf(t) < u);
- assert(rvalueOf(t) <= t);
- assert(rvalueOf(u) > t);
- assert(rvalueOf(u) >= u);
-
- assert(t < rvalueOf(u));
- assert(t <= rvalueOf(t));
- assert(u > rvalueOf(t));
- assert(u >= rvalueOf(u));
+ assert((t < u) == true);
+ assert((t <= t) == true);
+ assert((u > t) == true);
+ assert((u >= u) == true);
+
+ assert((TDRvalueOf(t) < u) == true);
+ assert((TDRvalueOf(t) <= t) == true);
+ assert((TDRvalueOf(u) > t) == true);
+ assert((TDRvalueOf(u) >= u) == true);
+
+ assert((t < TDRvalueOf(u)) == true);
+ assert((t <= TDRvalueOf(t)) == true);
+ assert((u > TDRvalueOf(t)) == true);
+ assert((u >= TDRvalueOf(u)) == true);
}
}
}
@@ -3186,7 +3214,7 @@ struct TickDuration
TickDuration t1 = curr;
immutable t2 = curr + curr;
t1 *= 2;
- assert(t1 == t2);
+ assert((t1 == t2) == true);
t1 = curr;
t1 *= 2.0;
@@ -3195,7 +3223,7 @@ struct TickDuration
t1 = curr;
t1 *= 2.1;
- assert(t1 > t2);
+ assert((t1 > t2) == true);
foreach (T; AliasSeq!(const TickDuration, immutable TickDuration))
{
@@ -3237,7 +3265,7 @@ struct TickDuration
immutable t1 = curr;
TickDuration t2 = curr + curr;
t2 /= 2;
- assert(t1 == t2);
+ assert((t1 == t2) == true);
t2 = curr + curr;
t2 /= 2.0;
@@ -3246,7 +3274,7 @@ struct TickDuration
t2 = curr + curr;
t2 /= 2.1;
- assert(t1 > t2);
+ assert((t1 > t2) == true);
_assertThrown!TimeException(t2 /= 0);
@@ -3284,10 +3312,10 @@ struct TickDuration
{
T t1 = TickDuration.currSystemTick;
T t2 = t1 + t1;
- assert(t1 * 2 == t2);
+ assert((t1 * 2 == t2) == true);
immutable tol = TickDuration(cast(long)(_abs(t1.length) * double.epsilon * 2.0));
assertApprox(t1 * 2.0, t2 - tol, t2 + tol);
- assert(t1 * 2.1 > t2);
+ assert((t1 * 2.1 > t2) == true);
}
}
@@ -3323,12 +3351,12 @@ struct TickDuration
{
T t1 = TickDuration.currSystemTick;
T t2 = t1 + t1;
- assert(t2 / 2 == t1);
+ assert((t2 / 2 == t1) == true);
immutable tol = TickDuration(cast(long)(_abs(t2.length) * double.epsilon / 2.0));
assertApprox(t2 / 2.0, t1 - tol, t1 + tol);
- assert(t2 / 2.1 < t1);
+ assert((t2 / 2.1 < t1) == true);
- _assertThrown!TimeException(t2 / 0);
+ _assertThrownDep!TimeException(t2 / 0);
}
}
@@ -3430,7 +3458,6 @@ struct TickDuration
}
}
-
/++
Generic way of converting between two time units. Conversions to smaller
units use truncating division. Years and months can be converted to each
@@ -3641,6 +3668,7 @@ Duration abs(Duration duration) @safe pure nothrow @nogc
}
/++ Ditto +/
+deprecated("TickDuration has been deprecated, please use Duration or MonoTime instead")
TickDuration abs(TickDuration duration) @safe pure nothrow @nogc
{
return TickDuration(_abs(duration.length));
@@ -3650,9 +3678,12 @@ unittest
{
assert(abs(dur!"msecs"(5)) == dur!"msecs"(5));
assert(abs(dur!"msecs"(-5)) == dur!"msecs"(5));
+}
- assert(abs(TickDuration(17)) == TickDuration(17));
- assert(abs(TickDuration(-17)) == TickDuration(17));
+deprecated unittest
+{
+ assert((abs(TickDuration(17)) == TickDuration(17)) == true);
+ assert((abs(TickDuration(-17)) == TickDuration(17)) == true);
}
@@ -3987,6 +4018,28 @@ unittest
}
}
+version (CoreUnittest) deprecated void _assertThrownDep(T : Throwable = Exception, E)
+ (lazy E expression,
+ string msg = null,
+ string file = __FILE__,
+ size_t line = __LINE__)
+{
+ bool thrown = false;
+
+ try
+ expression();
+ catch (T t)
+ thrown = true;
+
+ if (!thrown)
+ {
+ immutable tail = msg.length == 0 ? "." : ": " ~ msg;
+
+ throw new AssertError("assertThrown() failed: No " ~ T.stringof ~ " was thrown" ~ tail, file, line);
+ }
+}
+
+
version (CoreUnittest) void assertApprox(D, E)(D actual,
E lower,
@@ -4001,7 +4054,7 @@ version (CoreUnittest) void assertApprox(D, E)(D actual,
throw new AssertError(msg ~ ": upper: " ~ actual.toString(), __FILE__, line);
}
-version (CoreUnittest) void assertApprox(D, E)(D actual,
+version (CoreUnittest) deprecated void assertApprox(D, E)(D actual,
E lower,
E upper,
string msg = "unittest failure",
diff --git a/libphobos/libdruntime/gcc/sections/elf.d b/libphobos/libdruntime/gcc/sections/elf.d
index 0c7a771..5376957 100644
--- a/libphobos/libdruntime/gcc/sections/elf.d
+++ b/libphobos/libdruntime/gcc/sections/elf.d
@@ -737,7 +737,7 @@ version (Shared)
!pthread_mutex_unlock(&_handleToDSOMutex) || assert(0);
}
- void getDependencies(in ref dl_phdr_info info, ref Array!(DSO*) deps)
+ void getDependencies(const ref dl_phdr_info info, ref Array!(DSO*) deps)
{
// get the entries of the .dynamic section
ElfW!"Dyn"[] dyns;
@@ -833,7 +833,7 @@ version (Shared)
* Scan segments in Linux dl_phdr_info struct and store
* the TLS and writeable data segments in *pdso.
*/
-void scanSegments(in ref dl_phdr_info info, DSO* pdso) nothrow @nogc
+void scanSegments(const ref dl_phdr_info info, DSO* pdso) nothrow @nogc
{
foreach (ref phdr; info.dlpi_phdr[0 .. info.dlpi_phnum])
{
@@ -957,7 +957,7 @@ bool findDSOInfoForAddr(in void* addr, dl_phdr_info* result=null) nothrow @nogc
* Determine if 'addr' lies within shared object 'info'.
* If so, return true and fill in 'result' with the corresponding ELF program header.
*/
-bool findSegmentForAddr(in ref dl_phdr_info info, in void* addr, ElfW!"Phdr"* result=null) nothrow @nogc
+bool findSegmentForAddr(const ref dl_phdr_info info, in void* addr, ElfW!"Phdr"* result=null) nothrow @nogc
{
if (addr < cast(void*)info.dlpi_addr) // less than base address of object means quick reject
return false;
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index a77788b..610cb7a 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -4529,12 +4529,15 @@ public import core.internal.entrypoint : _d_cmain;
public import core.internal.array.appending : _d_arrayappendT;
version (D_ProfileGC)
+{
public import core.internal.array.appending : _d_arrayappendTTrace;
+ public import core.internal.array.concatenation : _d_arraycatnTXTrace;
+}
public import core.internal.array.appending : _d_arrayappendcTXImpl;
public import core.internal.array.comparison : __cmp;
public import core.internal.array.equality : __equals;
public import core.internal.array.casting: __ArrayCast;
-public import core.internal.array.concatenation : _d_arraycatnTXImpl;
+public import core.internal.array.concatenation : _d_arraycatnTX;
public import core.internal.array.construction : _d_arrayctor;
public import core.internal.array.construction : _d_arraysetctor;
public import core.internal.array.arrayassign : _d_arrayassign_l;
diff --git a/libphobos/libdruntime/rt/aApply.d b/libphobos/libdruntime/rt/aApply.d
index 5d5ddb3..c59d9dc 100644
--- a/libphobos/libdruntime/rt/aApply.d
+++ b/libphobos/libdruntime/rt/aApply.d
@@ -71,7 +71,7 @@ Params:
Returns:
non-zero when the loop was exited through a `break`
*/
-extern (C) int _aApplycd1(in char[] aa, dg_t dg)
+extern (C) int _aApplycd1(scope const(char)[] aa, dg_t dg)
{
int result;
size_t len = aa.length;
@@ -132,7 +132,7 @@ unittest
}
/// ditto
-extern (C) int _aApplywd1(in wchar[] aa, dg_t dg)
+extern (C) int _aApplywd1(scope const(wchar)[] aa, dg_t dg)
{
int result;
size_t len = aa.length;
@@ -193,7 +193,7 @@ unittest
}
/// ditto
-extern (C) int _aApplycw1(in char[] aa, dg_t dg)
+extern (C) int _aApplycw1(scope const(char)[] aa, dg_t dg)
{
int result;
size_t len = aa.length;
@@ -267,7 +267,7 @@ unittest
}
/// ditto
-extern (C) int _aApplywc1(in wchar[] aa, dg_t dg)
+extern (C) int _aApplywc1(scope const(wchar)[] aa, dg_t dg)
{
int result;
size_t len = aa.length;
@@ -347,7 +347,7 @@ unittest
}
/// ditto
-extern (C) int _aApplydc1(in dchar[] aa, dg_t dg)
+extern (C) int _aApplydc1(scope const(dchar)[] aa, dg_t dg)
{
int result;
@@ -423,7 +423,7 @@ unittest
}
/// ditto
-extern (C) int _aApplydw1(in dchar[] aa, dg_t dg)
+extern (C) int _aApplydw1(scope const(dchar)[] aa, dg_t dg)
{
int result;
@@ -508,7 +508,7 @@ extern (D) alias dg2_t = int delegate(void* i, void* c);
/**
Variants of _aApplyXXX that include a loop index.
*/
-extern (C) int _aApplycd2(in char[] aa, dg2_t dg)
+extern (C) int _aApplycd2(scope const(char)[] aa, dg2_t dg)
{
int result;
size_t len = aa.length;
@@ -576,7 +576,7 @@ unittest
}
/// ditto
-extern (C) int _aApplywd2(in wchar[] aa, dg2_t dg)
+extern (C) int _aApplywd2(scope const(wchar)[] aa, dg2_t dg)
{
int result;
size_t len = aa.length;
@@ -644,7 +644,7 @@ unittest
}
/// ditto
-extern (C) int _aApplycw2(in char[] aa, dg2_t dg)
+extern (C) int _aApplycw2(scope const(char)[] aa, dg2_t dg)
{
int result;
size_t len = aa.length;
@@ -723,7 +723,7 @@ unittest
}
/// ditto
-extern (C) int _aApplywc2(in wchar[] aa, dg2_t dg)
+extern (C) int _aApplywc2(scope const(wchar)[] aa, dg2_t dg)
{
int result;
size_t len = aa.length;
@@ -808,7 +808,7 @@ unittest
}
/// ditto
-extern (C) int _aApplydc2(in dchar[] aa, dg2_t dg)
+extern (C) int _aApplydc2(scope const(dchar)[] aa, dg2_t dg)
{
int result;
size_t len = aa.length;
@@ -888,7 +888,7 @@ unittest
}
/// ditto
-extern (C) int _aApplydw2(in dchar[] aa, dg2_t dg)
+extern (C) int _aApplydw2(scope const(dchar)[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
diff --git a/libphobos/libdruntime/rt/aApplyR.d b/libphobos/libdruntime/rt/aApplyR.d
index ce3bb9e..560025c 100644
--- a/libphobos/libdruntime/rt/aApplyR.d
+++ b/libphobos/libdruntime/rt/aApplyR.d
@@ -34,7 +34,7 @@ Params:
Returns:
non-zero when the loop was exited through a `break`
*/
-extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
+extern (C) int _aApplyRcd1(scope const(char)[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
@@ -107,7 +107,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
+extern (C) int _aApplyRwd1(scope const(wchar)[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
@@ -170,7 +170,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
+extern (C) int _aApplyRcw1(scope const(char)[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
@@ -256,7 +256,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
+extern (C) int _aApplyRwc1(scope const(wchar)[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
@@ -340,7 +340,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
+extern (C) int _aApplyRdc1(scope const(dchar)[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
@@ -418,7 +418,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
+extern (C) int _aApplyRdw1(scope const(dchar)[] aa, dg_t dg)
{ int result;
debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
@@ -502,7 +502,7 @@ extern (D) alias dg2_t = int delegate(void* i, void* c);
/**
Variants of _aApplyRXXX that include a loop index.
*/
-extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
+extern (C) int _aApplyRcd2(scope const(char)[] aa, dg2_t dg)
{ int result;
size_t i;
size_t len = aa.length;
@@ -578,7 +578,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
+extern (C) int _aApplyRwd2(scope const(wchar)[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
@@ -643,7 +643,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
+extern (C) int _aApplyRcw2(scope const(char)[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
@@ -731,7 +731,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
+extern (C) int _aApplyRwc2(scope const(wchar)[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
@@ -817,7 +817,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
+extern (C) int _aApplyRdc2(scope const(dchar)[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
@@ -896,7 +896,7 @@ unittest
}
/// ditto
-extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
+extern (C) int _aApplyRdw2(scope const(dchar)[] aa, dg2_t dg)
{ int result;
debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index f2515c3..a37541b 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -1197,7 +1197,7 @@ extern (C) void* _d_newitemU(scope const TypeInfo _ti) pure nothrow @weak
}
/// ditto
-extern (C) void* _d_newitemT(in TypeInfo _ti) pure nothrow @weak
+extern (C) void* _d_newitemT(const TypeInfo _ti) pure nothrow @weak
{
import core.stdc.string;
auto p = _d_newitemU(_ti);
@@ -1206,7 +1206,7 @@ extern (C) void* _d_newitemT(in TypeInfo _ti) pure nothrow @weak
}
/// Same as above, for item with non-zero initializer.
-extern (C) void* _d_newitemiT(in TypeInfo _ti) pure nothrow @weak
+extern (C) void* _d_newitemiT(const TypeInfo _ti) pure nothrow @weak
{
import core.stdc.string;
auto p = _d_newitemU(_ti);
@@ -1286,7 +1286,7 @@ extern (C) CollectHandler rt_getCollectHandler()
/**
*
*/
-extern (C) int rt_hasFinalizerInSegment(void* p, size_t size, uint attr, in void[] segment) nothrow
+extern (C) int rt_hasFinalizerInSegment(void* p, size_t size, uint attr, scope const(void)[] segment) nothrow
{
if (attr & BlkAttr.STRUCTFINAL)
{
@@ -2231,148 +2231,6 @@ extern (C) void[] _d_arrayappendwd(ref byte[] x, dchar c) @weak
return x;
}
-
-/**
-Concatenate two arrays into a new array
-
----
-void main()
-{
- int[] x = [10, 20, 30];
- int[] y = [40, 50];
- int[] c = x ~ y; // _d_arraycatT(typeid(int[]), (cast(byte*) x)[0..x.length], (cast(byte*) y)[0..y.length]);
-}
----
-
-Params:
- ti = type that the two arrays share
- x = left hand side array casted to `byte[]`. Despite this cast, its `.length` is original element length, not byte length
- y = right hand side array casted to `byte[]`. Despite this cast, its `.length` is original element length, not byte length
-Returns:
- resulting concatenated array, with `.length` equal to new element length despite `byte` type
-*/
-extern (C) byte[] _d_arraycatT(const TypeInfo ti, byte[] x, byte[] y) @weak
-out (result)
-{
- auto tinext = unqualify(ti.next);
- auto sizeelem = tinext.tsize; // array element size
- debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr);
- assert(result.length == x.length + y.length);
-
- // If a postblit is involved, the contents of result might rightly differ
- // from the bitwise concatenation of x and y.
- if (!hasPostblit(tinext))
- {
- for (size_t i = 0; i < x.length * sizeelem; i++)
- assert((cast(byte*)result)[i] == (cast(byte*)x)[i]);
- for (size_t i = 0; i < y.length * sizeelem; i++)
- assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]);
- }
-
- size_t cap = GC.sizeOf(result.ptr);
- assert(!cap || cap > result.length * sizeelem);
-}
-do
-{
- import core.stdc.string;
- version (none)
- {
- /* Cannot use this optimization because:
- * char[] a, b;
- * char c = 'a';
- * b = a ~ c;
- * c = 'b';
- * will change the contents of b.
- */
- if (!y.length)
- return x;
- if (!x.length)
- return y;
- }
-
- auto tinext = unqualify(ti.next);
- auto sizeelem = tinext.tsize; // array element size
- debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem);
- size_t xlen = x.length * sizeelem;
- size_t ylen = y.length * sizeelem;
- size_t len = xlen + ylen;
-
- if (!len)
- return null;
-
- auto info = __arrayAlloc(len, ti, tinext);
- byte* p = cast(byte*)__arrayStart(info);
- p[len] = 0; // guessing this is to optimize for null-terminated arrays?
- memcpy(p, x.ptr, xlen);
- memcpy(p + xlen, y.ptr, ylen);
- // do postblit processing
- __doPostblit(p, xlen + ylen, tinext);
-
- auto isshared = typeid(ti) is typeid(TypeInfo_Shared);
- __setArrayAllocLength(info, len, isshared, tinext);
- return p[0 .. x.length + y.length];
-}
-
-
-/**
-Concatenate multiple arrays at once
-
-This is more efficient than repeatedly concatenating pairs of arrays because the total size is known in advance.
-
-```
-void main()
-{
- int[] a, b, c;
- int[] res = a ~ b ~ c;
- // _d_arraycatnTX(typeid(int[]),
- // [(cast(byte*)a.ptr)[0..a.length], (cast(byte*)b.ptr)[0..b.length], (cast(byte*)c.ptr)[0..c.length]]);
-}
-```
-
-Params:
- ti = type of arrays to concatenate and resulting array
- arrs = array of arrays to concatenate, cast to `byte[]` while keeping `.length` the same
-
-Returns:
- newly created concatenated array, `.length` equal to the total element length despite `void` type
-*/
-extern (C) void[] _d_arraycatnTX(const TypeInfo ti, scope byte[][] arrs) @weak
-{
- import core.stdc.string;
-
- size_t length;
- auto tinext = unqualify(ti.next);
- auto size = tinext.tsize; // array element size
-
- foreach (b; arrs)
- length += b.length;
-
- if (!length)
- return null;
-
- auto allocsize = length * size;
- auto info = __arrayAlloc(allocsize, ti, tinext);
- auto isshared = typeid(ti) is typeid(TypeInfo_Shared);
- __setArrayAllocLength(info, allocsize, isshared, tinext);
- void *a = __arrayStart (info);
-
- size_t j = 0;
- foreach (b; arrs)
- {
- if (b.length)
- {
- memcpy(a + j, b.ptr, b.length * size);
- j += b.length * size;
- }
- }
-
- // do postblit processing
- __doPostblit(a, j, tinext);
-
- return a[0..length];
-}
-
-
/**
Allocate an array literal
diff --git a/libphobos/libdruntime/rt/profilegc.d b/libphobos/libdruntime/rt/profilegc.d
index 45e0d51..b97a5c5 100644
--- a/libphobos/libdruntime/rt/profilegc.d
+++ b/libphobos/libdruntime/rt/profilegc.d
@@ -15,6 +15,7 @@ module rt.profilegc;
private:
+import core.stdc.errno;
import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;
@@ -151,7 +152,7 @@ shared static ~this()
{
qsort(counts.ptr, counts.length, Result.sizeof, &Result.qsort_cmp);
- FILE* fp = logfilename.length == 0 ? stdout : fopen((logfilename).ptr, "w");
+ FILE* fp = logfilename == "\0" ? stdout : fopen((logfilename).ptr, "w");
if (fp)
{
fprintf(fp, "bytes allocated, allocations, type, function, file:line\n");
@@ -165,6 +166,12 @@ shared static ~this()
fclose(fp);
}
else
- fprintf(stderr, "cannot write profilegc log file '%.*s'", cast(int) logfilename.length, logfilename.ptr);
+ {
+ const err = errno;
+ fprintf(stderr, "cannot write profilegc log file '%.*s' (errno=%d)",
+ cast(int) logfilename.length,
+ logfilename.ptr,
+ cast(int) err);
+ }
}
}
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 2b6bc3e..c6e61f7 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-106038f2eaa70045bf25b29bb1c789304a6065f7
+8ab95ded5265379e74d507fdc252ff3d2305fc26
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/algorithm/comparison.d b/libphobos/src/std/algorithm/comparison.d
index 5ecb4f6..5c70960 100644
--- a/libphobos/src/std/algorithm/comparison.d
+++ b/libphobos/src/std/algorithm/comparison.d
@@ -577,19 +577,20 @@ Returns:
and `T3` are different.
*/
T1 clamp(T1, T2, T3)(T1 val, T2 lower, T3 upper)
-if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val))
- && (is(T2 : T1) && is(T3 : T1)))
-// cannot use :
-// `if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val) : T1))
-// because of https://issues.dlang.org/show_bug.cgi?id=16235.
-// Once that is fixed, we can simply use the ternary in both the template constraint
-// and the template body
-in
{
+ static assert(is(T2 : T1), "T2 of type '", T2.stringof
+ , "' must be implicitly convertible to type of T1 '"
+ , T1.stringof, "'");
+ static assert(is(T3 : T1), "T3 of type '", T3.stringof
+ , "' must be implicitly convertible to type of T1 '"
+ , T1.stringof, "'");
+
assert(!lower.greaterThan(upper), "Lower can't be greater than upper.");
-}
-do
-{
+
+ // `if (is(typeof(val.lessThan(lower) ? lower : val.greaterThan(upper) ? upper : val) : T1))
+ // because of https://issues.dlang.org/show_bug.cgi?id=16235.
+ // Once that is fixed, we can simply use the ternary in both the template constraint
+ // and the template body
if (val.lessThan(lower))
return lower;
else if (val.greaterThan(upper))
diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d
index 8236076..9f5a6ac 100644
--- a/libphobos/src/std/algorithm/iteration.d
+++ b/libphobos/src/std/algorithm/iteration.d
@@ -3632,18 +3632,18 @@ auto joiner(RoR, Separator)(RoR r, Separator sep)
/// Ditto
auto joiner(RoR)(RoR r)
-if (isInputRange!RoR && isInputRange!(ElementType!RoR))
+if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)))
{
static struct Result
{
private:
RoR _items;
- ElementType!RoR _current;
+ Unqual!(ElementType!RoR) _current;
enum isBidirectional = isForwardRange!RoR && isForwardRange!(ElementType!RoR) &&
isBidirectionalRange!RoR && isBidirectionalRange!(ElementType!RoR);
static if (isBidirectional)
{
- ElementType!RoR _currentBack;
+ Unqual!(ElementType!RoR) _currentBack;
bool reachedFinalElement;
}
@@ -4293,6 +4293,28 @@ if (isInputRange!RoR && isInputRange!(ElementType!RoR))
assert([only(S(null))].joiner.front == S(null));
}
+// https://issues.dlang.org/show_bug.cgi?id=22785
+@safe unittest
+{
+
+ import std.algorithm.iteration : joiner, map;
+ import std.array : array;
+
+ static immutable struct S
+ {
+ int value;
+ }
+
+ static immutable struct T
+ {
+ S[] arr;
+ }
+
+ auto range = [T([S(3)]), T([S(4), S(5)])];
+
+ assert(range.map!"a.arr".joiner.array == [S(3), S(4), S(5)]);
+}
+
/++
Implements the homonym function (also known as `accumulate`, $(D
compress), `inject`, or `foldl`) present in various programming
diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d
index 15f7ca9..ee318c8 100644
--- a/libphobos/src/std/algorithm/searching.d
+++ b/libphobos/src/std/algorithm/searching.d
@@ -119,12 +119,9 @@ template all(alias pred = "a")
Performs (at most) $(BIGOH range.length) evaluations of `pred`.
+/
bool all(Range)(Range range)
- if (isInputRange!Range)
+ if (isInputRange!Range &&
+ (__traits(isTemplate, pred) || is(typeof(unaryFun!pred(range.front)))))
{
- static assert(is(typeof(unaryFun!pred(range.front))),
- "`" ~ (isSomeString!(typeof(pred))
- ? pred.stringof[1..$-1] : pred.stringof)
- ~ "` isn't a unary predicate function for range.front");
import std.functional : not;
return find!(not!(unaryFun!pred))(range).empty;
@@ -172,7 +169,8 @@ template any(alias pred = "a")
Performs (at most) $(BIGOH range.length) evaluations of `pred`.
+/
bool any(Range)(Range range)
- if (isInputRange!Range && is(typeof(unaryFun!pred(range.front))))
+ if (isInputRange!Range &&
+ (__traits(isTemplate, pred) || is(typeof(unaryFun!pred(range.front)))))
{
return !find!pred(range).empty;
}
@@ -1294,17 +1292,6 @@ if (isInputRange!R &&
private enum bool hasConstEmptyMember(T) = is(typeof(((const T* a) => (*a).empty)(null)) : bool);
-// Rebindable doesn't work with structs
-// see: https://github.com/dlang/phobos/pull/6136
-private template RebindableOrUnqual(T)
-{
- import std.typecons : Rebindable;
- static if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
- alias RebindableOrUnqual = Rebindable!T;
- else
- alias RebindableOrUnqual = Unqual!T;
-}
-
/**
Iterates the passed range and selects the extreme element with `less`.
If the extreme element occurs multiple time, the first occurrence will be
@@ -1313,8 +1300,8 @@ returned.
Params:
map = custom accessor for the comparison key
selector = custom mapping for the extrema selection
- seed = custom seed to use as initial element
r = Range from which the extreme value will be selected
+ seedElement = custom seed to use as initial element
Returns:
The extreme value according to `map` and `selector` of the passed-in values.
@@ -1328,10 +1315,19 @@ in
}
do
{
+ import std.typecons : Rebindable;
+
alias Element = ElementType!Range;
- RebindableOrUnqual!Element seed = r.front;
+ Rebindable!Element seed = r.front;
r.popFront();
- return extremum!(map, selector)(r, seed);
+ static if (is(Rebindable!Element == T[], T))
+ {
+ return extremum!(map, selector)(r, seed);
+ }
+ else
+ {
+ return extremum!(map, selector)(r, seed.get);
+ }
}
private auto extremum(alias map, alias selector = "a < b", Range,
@@ -1341,13 +1337,14 @@ if (isInputRange!Range && !isInfinite!Range &&
!is(CommonType!(ElementType!Range, RangeElementType) == void) &&
is(typeof(unaryFun!map(ElementType!(Range).init))))
{
+ import std.typecons : Rebindable;
+
alias mapFun = unaryFun!map;
alias selectorFun = binaryFun!selector;
alias Element = ElementType!Range;
alias CommonElement = CommonType!(Element, RangeElementType);
- RebindableOrUnqual!CommonElement extremeElement = seedElement;
-
+ Rebindable!CommonElement extremeElement = seedElement;
// if we only have one statement in the loop, it can be optimized a lot better
static if (__traits(isSame, map, a => a))
@@ -1408,7 +1405,15 @@ if (isInputRange!Range && !isInfinite!Range &&
}
}
}
- return extremeElement;
+ // Rebindable is an alias to T for arrays
+ static if (is(typeof(extremeElement) == T[], T))
+ {
+ return extremeElement;
+ }
+ else
+ {
+ return extremeElement.get;
+ }
}
private auto extremum(alias selector = "a < b", Range)(Range r)
@@ -1493,6 +1498,10 @@ if (isInputRange!Range && !isInfinite!Range &&
assert(d.extremum!`a > b` == 10);
assert(d.extremum!(a => a, `a > b`) == 10);
}
+
+ // compiletime
+ enum ctExtremum = iota(1, 5).extremum;
+ assert(ctExtremum == 1);
}
@nogc @safe nothrow pure unittest
@@ -1524,6 +1533,17 @@ if (isInputRange!Range && !isInfinite!Range &&
assert(arr.extremum!"a.val".val == 0);
}
+// https://issues.dlang.org/show_bug.cgi?id=22786
+@nogc @safe nothrow pure unittest
+{
+ struct S
+ {
+ immutable int value;
+ }
+
+ assert([S(5), S(6)].extremum!"a.value" == S(5));
+}
+
// find
/**
Finds an individual element in an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
@@ -1552,7 +1572,7 @@ Complexity:
`find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
There are specializations that improve performance by taking
advantage of $(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives)
- or $(REF_ALTTEXT random access, isRandomAccess, std,range,primitives)
+ or $(REF_ALTTEXT random access, isRandomAccessRange, std,range,primitives)
ranges (where possible).
Params:
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index 4584dcc..2652803 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -2565,33 +2565,8 @@ E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to)
if ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
is(Unqual!E : Unqual!R1))
{
- import std.algorithm.searching : find;
- import std.range : dropOne;
-
- static if (isInputRange!R1)
- {
- if (from.empty) return subject;
- alias rSave = a => a.save;
- }
- else
- {
- alias rSave = a => a;
- }
-
- auto balance = find(subject, rSave(from));
- if (balance.empty)
- return subject;
-
- auto app = appender!(E[])();
- app.put(subject[0 .. subject.length - balance.length]);
- app.put(rSave(to));
- // replacing an element in an array is different to a range replacement
- static if (is(Unqual!E : Unqual!R1))
- replaceInto(app, balance.dropOne, from, to);
- else
- replaceInto(app, balance[from.length .. $], from, to);
-
- return app.data;
+ size_t changed = 0;
+ return replace(subject, from, to, changed);
}
///
@@ -2645,55 +2620,87 @@ if ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)
}
/++
- Replace occurrences of `from` with `to` in `subject` and output the result into
- `sink`.
+ Replace occurrences of `from` with `to` in `subject` in a new array.
+ `changed` counts how many replacements took place.
Params:
- sink = an $(REF_ALTTEXT output range, isOutputRange, std,range,primitives)
subject = the array to scan
from = the item to replace
to = the item to replace all instances of `from` with
+ changed = the number of replacements
- See_Also:
- $(REF substitute, std,algorithm,iteration) for a lazy replace.
+ Returns:
+ A new array without changing the contents of `subject`, or the original
+ array if no match is found.
+/
-void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to)
-if (isOutputRange!(Sink, E) &&
- ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
- is(Unqual!E : Unqual!R1)))
+E[] replace(E, R1, R2)(E[] subject, R1 from, R2 to, ref size_t changed)
+if ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
+ is(Unqual!E : Unqual!R1))
{
import std.algorithm.searching : find;
import std.range : dropOne;
static if (isInputRange!R1)
{
- if (from.empty)
- {
- sink.put(subject);
- return;
- }
+ if (from.empty) return subject;
alias rSave = a => a.save;
}
else
{
alias rSave = a => a;
}
- for (;;)
- {
- auto balance = find(subject, rSave(from));
- if (balance.empty)
- {
- sink.put(subject);
- break;
- }
- sink.put(subject[0 .. subject.length - balance.length]);
- sink.put(rSave(to));
- // replacing an element in an array is different to a range replacement
- static if (is(Unqual!E : Unqual!R1))
- subject = balance.dropOne;
- else
- subject = balance[from.length .. $];
- }
+
+ auto balance = find(subject, rSave(from));
+ if (balance.empty)
+ return subject;
+
+ auto app = appender!(E[])();
+ app.put(subject[0 .. subject.length - balance.length]);
+ app.put(rSave(to));
+ ++changed;
+ // replacing an element in an array is different to a range replacement
+ static if (is(Unqual!E : Unqual!R1))
+ replaceInto(app, balance.dropOne, from, to, changed);
+ else
+ replaceInto(app, balance[from.length .. $], from, to, changed);
+
+ return app.data;
+}
+
+///
+@safe unittest
+{
+ size_t changed = 0;
+ assert("Hello Wörld".replace("o Wö", "o Wo", changed) == "Hello World");
+ assert(changed == 1);
+
+ changed = 0;
+ assert("Hello Wörld".replace("l", "h", changed) == "Hehho Wörhd");
+ import std.stdio : writeln;
+ writeln(changed);
+ assert(changed == 3);
+}
+
+/++
+ Replace occurrences of `from` with `to` in `subject` and output the result into
+ `sink`.
+
+ Params:
+ sink = an $(REF_ALTTEXT output range, isOutputRange, std,range,primitives)
+ subject = the array to scan
+ from = the item to replace
+ to = the item to replace all instances of `from` with
+
+ See_Also:
+ $(REF substitute, std,algorithm,iteration) for a lazy replace.
+ +/
+void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to)
+if (isOutputRange!(Sink, E) &&
+ ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
+ is(Unqual!E : Unqual!R1)))
+{
+ size_t changed = 0;
+ replaceInto(sink, subject, from, to, changed);
}
///
@@ -2784,6 +2791,72 @@ if (isOutputRange!(Sink, E) &&
}
/++
+ Replace occurrences of `from` with `to` in `subject` and output the result into
+ `sink`. `changed` counts how many replacements took place.
+
+ Params:
+ sink = an $(REF_ALTTEXT output range, isOutputRange, std,range,primitives)
+ subject = the array to scan
+ from = the item to replace
+ to = the item to replace all instances of `from` with
+ changed = the number of replacements
+ +/
+void replaceInto(E, Sink, R1, R2)(Sink sink, E[] subject, R1 from, R2 to, ref size_t changed)
+if (isOutputRange!(Sink, E) &&
+ ((isForwardRange!R1 && isForwardRange!R2 && (hasLength!R2 || isSomeString!R2)) ||
+ is(Unqual!E : Unqual!R1)))
+{
+ import std.algorithm.searching : find;
+ import std.range : dropOne;
+
+ static if (isInputRange!R1)
+ {
+ if (from.empty)
+ {
+ sink.put(subject);
+ return;
+ }
+ alias rSave = a => a.save;
+ }
+ else
+ {
+ alias rSave = a => a;
+ }
+ for (;;)
+ {
+ auto balance = find(subject, rSave(from));
+ if (balance.empty)
+ {
+ sink.put(subject);
+ break;
+ }
+ sink.put(subject[0 .. subject.length - balance.length]);
+ sink.put(rSave(to));
+ ++changed;
+ // replacing an element in an array is different to a range replacement
+ static if (is(Unqual!E : Unqual!R1))
+ subject = balance.dropOne;
+ else
+ subject = balance[from.length .. $];
+ }
+}
+
+///
+@safe unittest
+{
+ auto arr = [1, 2, 3, 4, 5];
+ auto from = [2, 3];
+ auto to = [4, 6];
+ auto sink = appender!(int[])();
+
+ size_t changed = 0;
+ replaceInto(sink, arr, from, to, changed);
+
+ assert(sink.data == [1, 4, 6, 4, 5]);
+ assert(changed == 1);
+}
+
+/++
Replaces elements from `array` with indices ranging from `from`
(inclusive) to `to` (exclusive) with the range `stuff`.
diff --git a/libphobos/src/std/concurrency.d b/libphobos/src/std/concurrency.d
index 7fe52ba..267f682 100644
--- a/libphobos/src/std/concurrency.d
+++ b/libphobos/src/std/concurrency.d
@@ -2270,7 +2270,9 @@ private
if (range.front.convertsTo!(Throwable))
throw range.front.get!(Throwable);
else if (range.front.convertsTo!(shared(Throwable)))
- throw range.front.get!(shared(Throwable));
+ /* Note: a shared type can be caught without the shared qualifier
+ * so throwing shared will be an error */
+ throw cast() range.front.get!(shared(Throwable));
else
throw new PriorityMessageException(range.front.data);
}
diff --git a/libphobos/src/std/container/dlist.d b/libphobos/src/std/container/dlist.d
index 11e3883..4fdf13d 100644
--- a/libphobos/src/std/container/dlist.d
+++ b/libphobos/src/std/container/dlist.d
@@ -198,8 +198,10 @@ struct DList(T)
this (BaseNode _base, T _payload)
{
+ import std.algorithm.mutation : move;
+
this._base = _base;
- this._payload = _payload;
+ this._payload = move(_payload);
}
inout(BaseNode)* asBaseNode() inout @trusted
@@ -216,7 +218,9 @@ struct DList(T)
//Construct as new PayNode, and returns it as a BaseNode.
static BaseNode* createNode(Stuff)(auto ref Stuff arg, BaseNode* prev = null, BaseNode* next = null)
{
- return (new PayNode(BaseNode(prev, next), arg)).asBaseNode();
+ import std.algorithm.mutation : move;
+
+ return (new PayNode(BaseNode(prev, next), move(arg))).asBaseNode();
}
void initialize() nothrow @safe pure
@@ -721,7 +725,9 @@ Complexity: $(BIGOH n)
*/
bool linearRemoveElement(T value)
{
- auto n1 = findNodeByValue(_root, value);
+ import std.algorithm.mutation : move;
+
+ auto n1 = findNodeByValue(_root, move(value));
if (n1)
{
auto n2 = n1._next._next;
@@ -1118,3 +1124,27 @@ private:
a.insertFront(iota(0, 5)); // can insert range with non-ref front
assert(a.front == 0 && a.back == 4);
}
+
+// https://issues.dlang.org/show_bug.cgi?id=22147
+@safe unittest
+{
+ import std.algorithm.mutation : move;
+
+ static struct Item
+ {
+ @disable this(this);
+
+ int x;
+ }
+
+ auto list = DList!Item();
+ list.insertFront(Item(1));
+ assert(list[].walkLength == 1);
+ assert(list.front.x == 1);
+ auto item = list.moveFront;
+ item.x = 2;
+ list.front = move(item);
+ assert(list.front.x == 2);
+ list.removeFront();
+ assert(list[].walkLength == 0);
+}
diff --git a/libphobos/src/std/experimental/allocator/building_blocks/region.d b/libphobos/src/std/experimental/allocator/building_blocks/region.d
index 8c39784..a23746a 100644
--- a/libphobos/src/std/experimental/allocator/building_blocks/region.d
+++ b/libphobos/src/std/experimental/allocator/building_blocks/region.d
@@ -695,25 +695,15 @@ struct InSituRegion(size_t size, size_t minAlign = platformAlignment)
import std.conv : to;
import std.traits : hasMember;
import std.typecons : Ternary;
+ import core.thread.types : isStackGrowingDown;
static assert(minAlign.isGoodStaticAlignment);
static assert(size >= minAlign);
- version (X86) enum growDownwards = Yes.growDownwards;
- else version (X86_64) enum growDownwards = Yes.growDownwards;
- else version (ARM) enum growDownwards = Yes.growDownwards;
- else version (AArch64) enum growDownwards = Yes.growDownwards;
- else version (HPPA) enum growDownwards = No.growDownwards;
- else version (PPC) enum growDownwards = Yes.growDownwards;
- else version (PPC64) enum growDownwards = Yes.growDownwards;
- else version (RISCV32) enum growDownwards = Yes.growDownwards;
- else version (RISCV64) enum growDownwards = Yes.growDownwards;
- else version (MIPS32) enum growDownwards = Yes.growDownwards;
- else version (MIPS64) enum growDownwards = Yes.growDownwards;
- else version (SPARC) enum growDownwards = Yes.growDownwards;
- else version (SPARC64) enum growDownwards = Yes.growDownwards;
- else version (SystemZ) enum growDownwards = Yes.growDownwards;
- else static assert(0, "Dunno how the stack grows on this architecture.");
+ static if (isStackGrowingDown)
+ enum growDownwards = Yes.growDownwards;
+ else
+ enum growDownwards = No.growDownwards;
@disable this(this);
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index b7bd3fc..5b8925d 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -310,6 +310,8 @@ Params:
Returns: Untyped array of bytes _read.
Throws: $(LREF FileException) on error.
+
+See_Also: $(REF readText, std,file) for reading and validating a text file.
*/
void[] read(R)(R name, size_t upTo = size_t.max)
@@ -497,6 +499,8 @@ version (linux) @safe unittest
Throws: $(LREF FileException) if there is an error reading the file,
$(REF UTFException, std, utf) on UTF decoding error.
+
+ See_Also: $(REF read, std,file) for reading a binary file.
+/
S readText(S = string, R)(auto ref R name)
if (isSomeString!S && (isSomeFiniteCharInputRange!R || is(StringTypeOf!R)))
diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d
index 088e77f..219af71 100644
--- a/libphobos/src/std/json.d
+++ b/libphobos/src/std/json.d
@@ -1,7 +1,10 @@
// Written in the D programming language.
/**
-JavaScript Object Notation
+Implements functionality to read and write JavaScript Object Notation values.
+
+JavaScript Object Notation is a lightweight data interchange format commonly used in web services and configuration files.
+It's easy for humans to read and write, and it's easy for machines to parse and generate.
Copyright: Copyright Jeremie Pelletier 2008 - 2009.
License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
@@ -602,6 +605,45 @@ struct JSONValue
assert(j.type == JSONType.object);
}
+ /**
+ * An enum value that can be used to obtain a `JSONValue` representing
+ * an empty JSON object.
+ */
+ enum emptyObject = JSONValue(string[string].init);
+ ///
+ @system unittest
+ {
+ JSONValue obj1 = JSONValue.emptyObject;
+ assert(obj1.type == JSONType.object);
+ obj1.object["a"] = JSONValue(1);
+ assert(obj1.object["a"] == JSONValue(1));
+
+ JSONValue obj2 = JSONValue.emptyObject;
+ assert("a" !in obj2.object);
+ obj2.object["b"] = JSONValue(5);
+ assert(obj1 != obj2);
+ }
+
+ /**
+ * An enum value that can be used to obtain a `JSONValue` representing
+ * an empty JSON array.
+ */
+ enum emptyArray = JSONValue(JSONValue[].init);
+ ///
+ @system unittest
+ {
+ JSONValue arr1 = JSONValue.emptyArray;
+ assert(arr1.type == JSONType.array);
+ assert(arr1.array.length == 0);
+ arr1.array ~= JSONValue("Hello");
+ assert(arr1.array.length == 1);
+ assert(arr1.array[0] == JSONValue("Hello"));
+
+ JSONValue arr2 = JSONValue.emptyArray;
+ assert(arr2.array.length == 0);
+ assert(arr1 != arr2);
+ }
+
void opAssign(T)(T arg) if (!isStaticArray!T && !is(T : JSONValue))
{
assign(arg);
diff --git a/libphobos/src/std/net/curl.d b/libphobos/src/std/net/curl.d
index 42a34b9..2fcbf94 100644
--- a/libphobos/src/std/net/curl.d
+++ b/libphobos/src/std/net/curl.d
@@ -23,7 +23,7 @@ SMTP) )
)
Note:
-You may need to link to the $(B curl) library, e.g. by adding $(D "libs": ["curl"])
+You may need to link with the $(B curl) library, e.g. by adding $(D "libs": ["curl"])
to your $(B dub.json) file if you are using $(LINK2 http://code.dlang.org, DUB).
Windows x86 note:
@@ -32,20 +32,19 @@ $(LINK2 https://downloads.dlang.org/other/index.html, download archive page).
This module is not available for iOS, tvOS or watchOS.
-Compared to using libcurl directly this module allows simpler client code for
+Compared to using libcurl directly, this module allows simpler client code for
common uses, requires no unsafe operations, and integrates better with the rest
-of the language. Futhermore it provides $(MREF_ALTTEXT range, std,range)
+of the language. Furthermore it provides $(MREF_ALTTEXT range, std,range)
access to protocols supported by libcurl both synchronously and asynchronously.
A high level and a low level API are available. The high level API is built
entirely on top of the low level one.
The high level API is for commonly used functionality such as HTTP/FTP get. The
-$(LREF byLineAsync) and $(LREF byChunkAsync) provides asynchronous
-$(MREF_ALTTEXT range, std,range) that performs the request in another
-thread while handling a line/chunk in the current thread.
+$(LREF byLineAsync) and $(LREF byChunkAsync) functions asynchronously
+perform the request given, outputting the fetched content into a $(MREF_ALTTEXT range, std,range).
-The low level API allows for streaming and other advanced features.
+The low level API allows for streaming, setting request headers and cookies, and other advanced features.
$(BOOKTABLE Cheat Sheet,
$(TR $(TH Function Name) $(TH Description)
@@ -79,18 +78,18 @@ byChunk("dlang.org", 10)) returns a range of ubyte[10] containing the
dlang.org web page.)
)
$(TR $(TDNW $(LREF byLineAsync)) $(TD $(D
-byLineAsync("dlang.org")) returns a range of char[] containing the dlang.org web
- page asynchronously.)
+byLineAsync("dlang.org")) asynchronously returns a range of char[] containing the dlang.org web
+ page.)
)
$(TR $(TDNW $(LREF byChunkAsync)) $(TD $(D
-byChunkAsync("dlang.org", 10)) returns a range of ubyte[10] containing the
-dlang.org web page asynchronously.)
+byChunkAsync("dlang.org", 10)) asynchronously returns a range of ubyte[10] containing the
+dlang.org web page.)
)
$(LEADINGROW Low level
)
-$(TR $(TDNW $(LREF HTTP)) $(TD `HTTP` struct for advanced usage))
-$(TR $(TDNW $(LREF FTP)) $(TD `FTP` struct for advanced usage))
-$(TR $(TDNW $(LREF SMTP)) $(TD `SMTP` struct for advanced usage))
+$(TR $(TDNW $(LREF HTTP)) $(TD Struct for advanced HTTP usage))
+$(TR $(TDNW $(LREF FTP)) $(TD Struct for advanced FTP usage))
+$(TR $(TDNW $(LREF SMTP)) $(TD Struct for advanced SMTP usage))
)
@@ -135,10 +134,10 @@ http.perform();
First, an instance of the reference-counted HTTP struct is created. Then the
custom delegates are set. These will be called whenever the HTTP instance
receives a header and a data buffer, respectively. In this simple example, the
-headers are written to stdout and the data is ignored. If the request should be
+headers are written to stdout and the data is ignored. If the request is
stopped before it has finished then return something less than data.length from
the onReceive callback. See $(LREF onReceiveHeader)/$(LREF onReceive) for more
-information. Finally the HTTP request is effected by calling perform(), which is
+information. Finally, the HTTP request is performed by calling perform(), which is
synchronous.
Source: $(PHOBOSSRC std/net/curl.d)
@@ -147,8 +146,8 @@ Copyright: Copyright Jonas Drewsen 2011-2012
License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: Jonas Drewsen. Some of the SMTP code contributed by Jimmy Cao.
-Credits: The functionally is based on $(HTTP curl.haxx.se/libcurl, libcurl).
- LibCurl is licensed under an MIT/X derivative license.
+Credits: The functionality is based on $(HTTP curl.haxx.se/libcurl, libcurl).
+ libcurl is licensed under an MIT/X derivative license.
*/
/*
Copyright Jonas Drewsen 2011 - 2012.
diff --git a/libphobos/src/std/path.d b/libphobos/src/std/path.d
index 4b5a7ef..63d60d1 100644
--- a/libphobos/src/std/path.d
+++ b/libphobos/src/std/path.d
@@ -1758,7 +1758,6 @@ immutable(C)[] buildNormalizedPath(C)(const(C[])[] paths...)
if (isSomeChar!C)
{
import std.array : array;
- import std.exception : assumeUnique;
const(C)[] chained;
foreach (path; paths)
@@ -1770,7 +1769,7 @@ if (isSomeChar!C)
}
auto result = asNormalizedPath(chained);
// .array returns a copy, so it is unique
- return () @trusted { return assumeUnique(result.array); } ();
+ return result.array;
}
///
diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d
index 93be764..066ed17 100644
--- a/libphobos/src/std/random.d
+++ b/libphobos/src/std/random.d
@@ -812,7 +812,7 @@ Parameters for the generator.
// Bitmasks used in the 'twist' part of the algorithm
private enum UIntType lowerMask = (cast(UIntType) 1u << r) - 1,
- upperMask = (~lowerMask) & this.max;
+ upperMask = (~lowerMask) & max;
/*
Collection of all state variables
@@ -905,17 +905,17 @@ Parameters for the generator.
private static void seedImpl(UIntType value, ref State mtState) @nogc
{
mtState.data[$ - 1] = value;
- static if (this.max != UIntType.max)
+ static if (max != UIntType.max)
{
- mtState.data[$ - 1] &= this.max;
+ mtState.data[$ - 1] &= max;
}
foreach_reverse (size_t i, ref e; mtState.data[0 .. $ - 1])
{
e = f * (mtState.data[i + 1] ^ (mtState.data[i + 1] >> (w - 2))) + cast(UIntType)(n - (i + 1));
- static if (this.max != UIntType.max)
+ static if (max != UIntType.max)
{
- e &= this.max;
+ e &= max;
}
}
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index 888ac1a..7a724b0 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -235,7 +235,7 @@ public import std.range.primitives;
public import std.typecons : Flag, Yes, No;
import std.internal.attributes : betterC;
-import std.meta : allSatisfy, anySatisfy, staticMap;
+import std.meta : aliasSeqOf, allSatisfy, anySatisfy, staticMap;
import std.traits : CommonType, isCallable, isFloatingPoint, isIntegral,
isPointer, isSomeFunction, isStaticArray, Unqual, isInstanceOf;
@@ -313,12 +313,16 @@ if (isBidirectionalRange!(Unqual!Range))
{
@property void front(ElementType!R val)
{
- source.back = val;
+ import std.algorithm.mutation : move;
+
+ source.back = move(val);
}
@property void back(ElementType!R val)
{
- source.front = val;
+ import std.algorithm.mutation : move;
+
+ source.front = move(val);
}
}
@@ -330,7 +334,9 @@ if (isBidirectionalRange!(Unqual!Range))
{
void opIndexAssign(ElementType!R val, size_t n)
{
- source[retroIndex(n)] = val;
+ import std.algorithm.mutation : move;
+
+ source[retroIndex(n)] = move(val);
}
}
@@ -474,6 +480,19 @@ pure @safe nothrow @nogc unittest
foreach (x; data.retro) {}
}
+pure @safe nothrow unittest
+{
+ import std.algorithm.comparison : equal;
+
+ static struct S {
+ int v;
+ @disable this(this);
+ }
+
+ immutable foo = [S(1), S(2), S(3)];
+ auto r = retro(foo);
+ assert(equal(r, [S(3), S(2), S(1)]));
+}
/**
Iterates range `r` with stride `n`. If the range is a
@@ -585,7 +604,9 @@ do
{
@property void front(ElementType!R val)
{
- source.front = val;
+ import std.algorithm.mutation : move;
+
+ source.front = move(val);
}
}
@@ -864,6 +885,20 @@ pure @safe nothrow unittest
assert(equal(s, [1L, 4L, 7L]));
}
+pure @safe nothrow unittest
+{
+ import std.algorithm.comparison : equal;
+
+ static struct S {
+ int v;
+ @disable this(this);
+ }
+
+ immutable foo = [S(1), S(2), S(3), S(4), S(5)];
+ auto r = stride(foo, 3);
+ assert(equal(r, [S(1), S(4)]));
+}
+
/**
Spans multiple ranges in sequence. The function `chain` takes any
number of ranges and returns a $(D Chain!(R1, R2,...)) object. The
@@ -872,6 +907,11 @@ result is a range that offers the `front`, `popFront`, and $(D
empty) primitives. If all input ranges offer random access and $(D
length), `Chain` offers them as well.
+Note that repeated random access of the resulting range is likely
+to perform somewhat badly since lengths of the ranges in the chain have to be
+added up for each random access operation. Random access to elements of
+the first remaining range is still efficient.
+
If only one range is offered to `Chain` or `chain`, the $(D
Chain) type exits the picture by aliasing itself directly to that
range's type.
@@ -907,7 +947,12 @@ if (Ranges.length > 0 &&
enum sameET = is(.ElementType!A == RvalueElementType);
}
- enum bool allSameType = allSatisfy!(sameET, R);
+ enum bool allSameType = allSatisfy!(sameET, R),
+ bidirectional = allSatisfy!(isBidirectionalRange, R),
+ mobileElements = allSatisfy!(hasMobileElements, R),
+ assignableElements = allSameType
+ && allSatisfy!(hasAssignableElements, R);
+
alias ElementType = RvalueElementType;
static if (allSameType && allSatisfy!(hasLvalueElements, R))
@@ -925,17 +970,44 @@ if (Ranges.length > 0 &&
}
}
- // This is the entire state
R source;
- // TODO: use a vtable (or more) instead of linear iteration
+ size_t frontIndex;
+ // Always points to index one past the last non-empty range,
+ // because otherwise decrementing while pointing to first range
+ // would overflow to size_t.max.
+ static if (bidirectional) size_t backIndex;
+ else enum backIndex = source.length;
public:
this(R input)
{
- // Must be static foreach because of https://issues.dlang.org/show_bug.cgi?id=21209
- static foreach (i, v; input)
+ frontIndex = source.length;
+ static if (bidirectional) backIndex = 0;
+
+ foreach (i, ref v; input) source[i] = v;
+
+ // We do this separately to avoid invoking `empty` needlessly.
+ // While not recommended, a range may depend on side effects of
+ // `empty` call.
+ foreach (i, ref v; input) if (!v.empty)
{
- source[i] = v;
+ frontIndex = i;
+ static if (bidirectional) backIndex = i+1;
+ break;
+ }
+
+ // backIndex is already set in the first loop to
+ // as frontIndex+1, so we'll use that if we don't find a
+ // non-empty range here.
+ static if (bidirectional)
+ static foreach_reverse (i; 1 .. R.length + 1)
+ {
+ if (i <= frontIndex + 1) return;
+ if (!input[i-1].empty)
+ {
+ backIndex = i;
+ return;
+ }
}
}
@@ -948,120 +1020,209 @@ if (Ranges.length > 0 &&
}
else
{
- @property bool empty()
+ @property bool empty() => frontIndex >= backIndex;
+ }
+
+ static if (allSatisfy!(isForwardRange, R))
+ {
+ @property auto save()
{
- foreach (i, Unused; R)
+ auto saveI(size_t i)() => source[i].save;
+
+ // TODO: this has the constructor needlessly refind
+ // frontIndex and backIndex. It'd be better to just copy
+ // those from `.this`.
+ auto saveResult =
+ Result(staticMap!(saveI, aliasSeqOf!(R.length.iota)));
+
+ return saveResult;
+ }
+ }
+
+ void popFront()
+ {
+ sw1: switch (frontIndex)
+ {
+ static foreach (i; 0 .. R.length)
{
- if (!source[i].empty) return false;
+ case i:
+ source[i].popFront();
+ break sw1;
}
- return true;
+
+ case R.length:
+ assert(0, "Attempt to `popFront` of empty `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- }
- static if (allSatisfy!(isForwardRange, R))
- @property auto save()
+ sw2: switch (frontIndex)
{
- auto saveSource(size_t len)()
+ static foreach (i; 0 .. R.length)
{
- import std.typecons : tuple;
- static assert(len > 0);
- static if (len == 1)
- {
- return tuple(source[0].save);
- }
- else
+ case i:
+ if (source[i].empty)
{
- return saveSource!(len - 1)() ~
- tuple(source[len - 1].save);
+ frontIndex++;
+ goto case;
}
+ else break sw2;
}
- return Result(saveSource!(R.length).expand);
- }
- void popFront()
- {
- foreach (i, Unused; R)
- {
- if (source[i].empty) continue;
- source[i].popFront();
- return;
+ // Only possible to reach from goto of previous case.
+ case R.length:
+ break;
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to `popFront` of empty `chain` range");
}
@property auto ref front()
{
- foreach (i, Unused; R)
+ switch (frontIndex)
{
- if (source[i].empty) continue;
- return fixRef(source[i].front);
+ static foreach (i; 0 .. R.length)
+ {
+ case i:
+ return fixRef(source[i].front);
+ }
+
+ case R.length:
+ assert(0, "Attempt to get `front` of empty `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to get `front` of empty `chain` range");
}
- static if (allSameType && allSatisfy!(hasAssignableElements, R))
+ static if (assignableElements)
{
// @@@BUG@@@
//@property void front(T)(T v) if (is(T : RvalueElementType))
@property void front(RvalueElementType v)
{
- foreach (i, Unused; R)
+ import std.algorithm.mutation : move;
+
+ sw: switch (frontIndex)
{
- if (source[i].empty) continue;
- source[i].front = v;
- return;
+ static foreach (i; 0 .. R.length)
+ {
+ case i:
+ source[i].front = move(v);
+ break sw;
+ }
+
+ case R.length:
+ assert(0, "Attempt to set `front` of empty `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to set `front` of empty `chain` range");
}
}
- static if (allSatisfy!(hasMobileElements, R))
+ static if (mobileElements)
{
RvalueElementType moveFront()
{
- foreach (i, Unused; R)
+ switch (frontIndex)
{
- if (source[i].empty) continue;
- return source[i].moveFront();
+ static foreach (i; 0 .. R.length)
+ {
+ case i:
+ return source[i].moveFront();
+ }
+
+ case R.length:
+ assert(0, "Attempt to `moveFront` of empty `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to `moveFront` of empty `chain` range");
}
}
- static if (allSatisfy!(isBidirectionalRange, R))
+ static if (bidirectional)
{
@property auto ref back()
{
- foreach_reverse (i, Unused; R)
+ switch (backIndex)
{
- if (source[i].empty) continue;
- return fixRef(source[i].back);
+ static foreach_reverse (i; 1 .. R.length + 1)
+ {
+ case i:
+ return fixRef(source[i-1].back);
+ }
+
+ case 0:
+ assert(0, "Attempt to get `back` of empty `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to get `back` of empty `chain` range");
}
void popBack()
{
- foreach_reverse (i, Unused; R)
+ sw1: switch (backIndex)
{
- if (source[i].empty) continue;
- source[i].popBack();
- return;
+ static foreach_reverse (i; 1 .. R.length + 1)
+ {
+ case i:
+ source[i-1].popBack();
+ break sw1;
+ }
+
+ case 0:
+ assert(0, "Attempt to `popFront` of empty `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
+ }
+
+ sw2: switch (backIndex)
+ {
+ static foreach_reverse (i; 1 .. R.length + 1)
+ {
+ case i:
+ if (source[i-1].empty)
+ {
+ backIndex--;
+ goto case;
+ }
+ else break sw2;
+ }
+
+ // Only possible to reach from goto of previous case.
+ case 0:
+ break;
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to `popBack` of empty `chain` range");
}
- static if (allSatisfy!(hasMobileElements, R))
+ static if (mobileElements)
{
RvalueElementType moveBack()
{
- foreach_reverse (i, Unused; R)
+ switch (backIndex)
{
- if (source[i].empty) continue;
- return source[i].moveBack();
+ static foreach_reverse (i; 1 .. R.length + 1)
+ {
+ case i:
+ return source[i-1].moveBack();
+ }
+
+ case 0:
+ assert(0, "Attempt to `moveBack` of empty `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to `moveBack` of empty `chain` range");
}
}
@@ -1069,13 +1230,23 @@ if (Ranges.length > 0 &&
{
@property void back(RvalueElementType v)
{
- foreach_reverse (i, Unused; R)
+ import std.algorithm.mutation : move;
+
+ sw: switch (backIndex)
{
- if (source[i].empty) continue;
- source[i].back = v;
- return;
+ static foreach_reverse (i; 1 .. R.length + 1)
+ {
+ case i:
+ source[i-1].back = move(v);
+ break sw;
+ }
+
+ case 0:
+ assert(0, "Attempt to set `back` of empty `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to set `back` of empty `chain` range");
}
}
}
@@ -1084,11 +1255,24 @@ if (Ranges.length > 0 &&
{
@property size_t length()
{
- size_t result;
- foreach (i, Unused; R)
+ size_t result = 0;
+ sw: switch (frontIndex)
{
- result += source[i].length;
+ static foreach (i; 0 .. R.length)
+ {
+ case i:
+ result += source[i].length;
+ if (backIndex == i+1) break sw;
+ else goto case;
+ }
+
+ case R.length:
+ break;
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
+
return result;
}
@@ -1099,64 +1283,93 @@ if (Ranges.length > 0 &&
{
auto ref opIndex(size_t index)
{
- foreach (i, Range; R)
+ switch (frontIndex)
{
- static if (isInfinite!(Range))
- {
- return source[i][index];
- }
- else
+ static foreach (i; 0 .. R.length)
{
- immutable length = source[i].length;
- if (index < length) return fixRef(source[i][index]);
- index -= length;
+ case i:
+ static if (!isInfinite!(R[i]))
+ {
+ immutable length = source[i].length;
+ if (index >= length)
+ {
+ index -= length;
+ goto case;
+ }
+ }
+
+ return fixRef(source[i][index]);
}
+
+ case R.length:
+ assert(0, "Attempt to access out-of-bounds index of `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to access out-of-bounds index of `chain` range");
}
- static if (allSatisfy!(hasMobileElements, R))
+ static if (mobileElements)
{
RvalueElementType moveAt(size_t index)
{
- foreach (i, Range; R)
+ switch (frontIndex)
{
- static if (isInfinite!(Range))
+ static foreach (i; 0 .. R.length)
{
+ case i:
+ static if (!isInfinite!(R[i]))
+ {
+ immutable length = source[i].length;
+ if (index >= length)
+ {
+ index -= length;
+ goto case;
+ }
+ }
+
return source[i].moveAt(index);
}
- else
- {
- immutable length = source[i].length;
- if (index < length) return source[i].moveAt(index);
- index -= length;
- }
+
+ case R.length:
+ assert(0, "Attempt to move out-of-bounds index of `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to move out-of-bounds index of `chain` range");
}
}
static if (allSameType && allSatisfy!(hasAssignableElements, R))
void opIndexAssign(ElementType v, size_t index)
{
- foreach (i, Range; R)
+ import std.algorithm.mutation : move;
+
+ sw: switch (frontIndex)
{
- static if (isInfinite!(Range))
+ static foreach (i; 0 .. R.length)
{
- source[i][index] = v;
- }
- else
- {
- immutable length = source[i].length;
- if (index < length)
+ case i:
+ static if (!isInfinite!(R[i]))
{
- source[i][index] = v;
- return;
+ immutable length = source[i].length;
+ if (index >= length)
+ {
+ index -= length;
+ goto case;
+ }
}
- index -= length;
+
+ source[i][index] = move(v);
+ break sw;
}
+
+ case R.length:
+ assert(0, "Attempt to write out-of-bounds index of `chain` range");
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- assert(false, "Attempt to write out-of-bounds index of `chain` range");
}
}
@@ -1164,40 +1377,74 @@ if (Ranges.length > 0 &&
auto opSlice(size_t begin, size_t end) return scope
{
auto result = this;
- foreach (i, Unused; R)
+
+ sw: switch (frontIndex)
{
- immutable len = result.source[i].length;
- if (len < begin)
- {
- result.source[i] = result.source[i]
- [len .. len];
- begin -= len;
- }
- else
+ static foreach (i; 0 .. R.length)
{
- result.source[i] = result.source[i]
- [begin .. len];
- break;
+ case i:
+ immutable len = result.source[i].length;
+ if (len <= begin)
+ {
+ result.source[i] = result.source[i]
+ [len .. len];
+ begin -= len;
+ result.frontIndex++;
+ goto case;
+ }
+ else
+ {
+ result.source[i] = result.source[i]
+ [begin .. len];
+ break sw;
+ }
}
+
+ case R.length:
+ assert(begin == 0,
+ "Attempt to access out-of-bounds slice of `chain` range");
+ break;
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
- auto cut = length;
- cut = cut <= end ? 0 : cut - end;
- foreach_reverse (i, Unused; R)
+
+ // Overflow intentional if end index too big.
+ // This will trigger the bounds check failure below.
+ auto cut = length - end;
+
+ sw2: switch (backIndex)
{
- immutable len = result.source[i].length;
- if (cut > len)
+ static foreach_reverse (i; 1 .. R.length + 1)
{
- result.source[i] = result.source[i]
- [0 .. 0];
- cut -= len;
- }
- else
- {
- result.source[i] = result.source[i]
- [0 .. len - cut];
- break;
+ case i:
+ immutable len = result.source[i-1].length;
+ if (len <= cut)
+ {
+ result.source[i-1] = result.source[i-1]
+ [0 .. 0];
+ cut -= len;
+ result.backIndex--;
+ goto case;
+ }
+ else
+ {
+ result.source[i-1] = result.source[i-1]
+ [0 .. len - cut];
+ break sw2;
+ }
}
+
+ case 0:
+ assert(cut == 0, end > length?
+ "Attempt to access out-of-bounds slice of `chain` range":
+ "Attempt to access negative length slice of `chain` range");
+ break sw2;
+
+ default:
+ assert(0, "Internal library error. Please report it.");
}
+
return result;
}
}
@@ -1293,6 +1540,10 @@ pure @safe nothrow unittest
auto s = chain(arr1, arr2, arr3);
assert(s[5] == 6);
assert(equal(s, witness));
+ assert(s[4 .. 6].equal(arr2));
+ assert(s[2 .. 5].equal([3, 4, 5]));
+ assert(s[0 .. 0].empty);
+ assert(s[7 .. $].empty);
assert(s[5] == 6);
}
{
@@ -1392,6 +1643,28 @@ pure @safe unittest
assert(equal(r, "foobar"));
}
+pure @safe nothrow @nogc unittest
+{
+ // support non-copyable items
+
+ static struct S {
+ int v;
+ @disable this(this);
+ }
+
+ S[2] s0, s1;
+ foreach (ref el; chain(s0[], s1[]))
+ {
+ int n = el.v;
+ }
+
+ S[] s2, s3;
+ foreach (ref el; chain(s2, s3))
+ {
+ int n = el.v;
+ }
+}
+
/**
Choose one of two ranges at runtime depending on a Boolean condition.
@@ -1825,6 +2098,23 @@ pure @safe unittest
auto chosen2 = chosen.save;
}
+pure @safe nothrow unittest
+{
+ static struct S {
+ int v;
+ @disable this(this);
+ }
+
+ auto a = [S(1), S(2), S(3)];
+ auto b = [S(4), S(5), S(6)];
+
+ auto chosen = choose(true, a, b);
+ assert(chosen.front.v == 1);
+
+ auto chosen2 = choose(false, a, b);
+ assert(chosen2.front.v == 4);
+}
+
/**
Choose one of multiple ranges at runtime.
@@ -2122,6 +2412,20 @@ pure @safe unittest
assert(equal(r.save, "fboaor"));
assert(equal(r.save, "fboaor"));
}
+pure @safe nothrow unittest
+{
+ import std.algorithm.comparison : equal;
+
+ static struct S {
+ int v;
+ @disable this(this);
+ }
+
+ S[] a = [ S(1), S(2) ];
+ S[] b = [ S(10), S(20) ];
+ auto r = roundRobin(a, b);
+ assert(equal(r, [ S(1), S(10), S(2), S(20) ]));
+}
/**
Iterates a random-access range starting from a given point and
@@ -2313,12 +2617,12 @@ if (isInputRange!(Unqual!Range) &&
/// ditto
@property void front(ElementType!R v)
{
+ import std.algorithm.mutation : move;
+
assert(!empty,
"Attempting to assign to the front of an empty "
~ Take.stringof);
- // This has to return auto instead of void because of
- // https://issues.dlang.org/show_bug.cgi?id=4706
- source.front = v;
+ source.front = move(v);
}
static if (hasMobileElements!R)
@@ -2694,10 +2998,12 @@ if (isInputRange!R)
{
@property auto ref front(ElementType!R v)
{
+ import std.algorithm.mutation : move;
+
assert(!empty,
"Attempting to assign to the front of an empty "
~ typeof(this).stringof);
- return _input.front = v;
+ return _input.front = move(v);
}
}
}
@@ -3929,7 +4235,9 @@ if (isForwardRange!R && !isInfinite!R)
/// ditto
@property void front(ElementType!R val)
{
- _original[_index] = val;
+ import std.algorithm.mutation : move;
+
+ _original[_index] = move(val);
}
}
@@ -4039,7 +4347,9 @@ if (isForwardRange!R && !isInfinite!R)
/// ditto
@property auto front(ElementType!R val)
{
- return _current.front = val;
+ import std.algorithm.mutation : move;
+
+ return _current.front = move(val);
}
}
@@ -7053,7 +7363,9 @@ struct FrontTransversal(Ror,
{
@property void front(ElementType val)
{
- _input.front.front = val;
+ import std.algorithm.mutation : move;
+
+ _input.front.front = move(val);
}
}
@@ -7110,7 +7422,9 @@ struct FrontTransversal(Ror,
{
@property void back(ElementType val)
{
- _input.back.front = val;
+ import std.algorithm.mutation : move;
+
+ _input.back.front = move(val);
}
}
}
@@ -7143,7 +7457,9 @@ struct FrontTransversal(Ror,
{
void opIndexAssign(ElementType val, size_t n)
{
- _input[n].front = val;
+ import std.algorithm.mutation : move;
+
+ _input[n].front = move(val);
}
}
mixin ImplementLength!_input;
@@ -8785,7 +9101,8 @@ public:
{
// `nextSource` is used to "look one step into the future" and check for the end
// this means `nextSource` is advanced by `stepSize` on every `popFront`
- nextSource = source.save.drop(windowSize);
+ nextSource = source.save;
+ auto poppedElems = nextSource.popFrontN(windowSize);
}
if (source.empty)
@@ -8798,7 +9115,7 @@ public:
{
static if (needsEndTracker)
{
- if (nextSource.empty)
+ if (poppedElems < windowSize)
hasShownPartialBefore = true;
}
else
@@ -8806,14 +9123,13 @@ public:
if (source.length <= windowSize)
hasShownPartialBefore = true;
}
-
}
else
{
// empty source range is needed, s.t. length, slicing etc. works properly
static if (needsEndTracker)
{
- if (nextSource.empty)
+ if (poppedElems < windowSize)
_empty = true;
}
else
@@ -9770,6 +10086,15 @@ public:
assert([1].map!(x => x).slide(2).equal!equal([[1]]));
}
+// https://issues.dlang.org/show_bug.cgi?id=19642
+@safe unittest
+{
+ import std.algorithm.comparison : equal;
+ import std.algorithm.iteration : splitter;
+
+ assert("ab cd".splitter(' ').slide!(No.withPartial)(2).equal!equal([["ab", "cd"]]));
+}
+
private struct OnlyResult(Values...)
if (Values.length > 1)
{
diff --git a/libphobos/src/std/range/primitives.d b/libphobos/src/std/range/primitives.d
index 748fde3..e581409 100644
--- a/libphobos/src/std/range/primitives.d
+++ b/libphobos/src/std/range/primitives.d
@@ -1041,7 +1041,8 @@ See_Also:
*/
enum bool isBidirectionalRange(R) = isForwardRange!R
&& is(typeof((R r) => r.popBack))
- && is(typeof((R r) { return r.back; } (R.init)) == ElementType!R);
+ && (is(typeof((return ref R r) => r.back)) || is(typeof(ref (return ref R r) => r.back)))
+ && is(typeof(R.init.back.init) == ElementType!R);
///
@safe unittest
diff --git a/libphobos/src/std/regex/internal/backtracking.d b/libphobos/src/std/regex/internal/backtracking.d
index 21766fc..ac73f70 100644
--- a/libphobos/src/std/regex/internal/backtracking.d
+++ b/libphobos/src/std/regex/internal/backtracking.d
@@ -73,12 +73,7 @@ final:
override @property ref size_t refCount() { return _refCount; }
override @property ref const(RegEx) pattern(){ return re; }
- static if (__traits(hasMember,Stream, "search"))
- {
- enum kicked = true;
- }
- else
- enum kicked = false;
+ enum kicked = __traits(hasMember, Stream, "search");
static size_t initialMemory(const ref RegEx re)
{
diff --git a/libphobos/src/std/regex/internal/thompson.d b/libphobos/src/std/regex/internal/thompson.d
index ab28d37..f4643ae 100644
--- a/libphobos/src/std/regex/internal/thompson.d
+++ b/libphobos/src/std/regex/internal/thompson.d
@@ -759,12 +759,7 @@ final:
}
- static if (__traits(hasMember,Stream, "search"))
- {
- enum kicked = true;
- }
- else
- enum kicked = false;
+ enum kicked = __traits(hasMember, Stream, "search");
static size_t getThreadSize(const ref Regex!Char re)
{
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index 92e4906..5ed685f 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -43,6 +43,8 @@ License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
Authors: $(HTTP digitalmars.com, Walter Bright),
$(HTTP erdani.org, Andrei Alexandrescu),
Alex Rønne Petersen
+Macros:
+CSTDIO=$(HTTP cplusplus.com/reference/cstdio/$1/, $1)
*/
module std.stdio;
@@ -534,8 +536,7 @@ Params:
name = range or string representing the file _name
stdioOpenmode = range or string represting the open mode
(with the same semantics as in the C standard library
- $(HTTP cplusplus.com/reference/clibrary/cstdio/fopen.html, fopen)
- function)
+ $(CSTDIO fopen) function)
Throws: `ErrnoException` if the file could not be opened.
*/
@@ -618,8 +619,7 @@ file.
/**
Detaches from the current file (throwing on failure), and then attempts to
_open file `name` with mode `stdioOpenmode`. The mode has the
-same semantics as in the C standard library $(HTTP
-cplusplus.com/reference/clibrary/cstdio/fopen.html, fopen) function.
+same semantics as in the C standard library $(CSTDIO fopen) function.
Throws: `ErrnoException` in case of error.
*/
@@ -735,8 +735,7 @@ Reuses the `File` object to either open a different file, or change
the file mode. If `name` is `null`, the mode of the currently open
file is changed; otherwise, a new file is opened, reusing the C
`FILE*`. The function has the same semantics as in the C standard
-library $(HTTP cplusplus.com/reference/cstdio/freopen/, freopen)
-function.
+library $(CSTDIO freopen) function.
Note: Calling `reopen` with a `null` `name` is not implemented
in all C runtimes.
@@ -832,8 +831,8 @@ Throws: `ErrnoException` in case of error.
Params:
fd = File descriptor to associate with this `File`.
stdioOpenmode = Mode to associate with this File. The mode has the same semantics
- semantics as in the C standard library
- $(HTTP cplusplus.com/reference/cstdio/fopen/, fdopen) function, and must be compatible with `fd`.
+ semantics as in the C standard library $(CSTDIO fdopen) function,
+ and must be compatible with `fd`.
*/
void fdopen(int fd, scope const(char)[] stdioOpenmode = "rb") @safe
{
@@ -932,8 +931,7 @@ Throws: `ErrnoException` in case of error.
}
/**
-Returns `true` if the file is at end (see $(HTTP
-cplusplus.com/reference/clibrary/cstdio/feof.html, feof)).
+Returns `true` if the file is at end (see $(CSTDIO feof)).
Throws: `Exception` if the file is not opened.
*/
@@ -961,8 +959,7 @@ Throws: `Exception` if the file is not opened.
/**
If the file is closed or not yet opened, returns `true`. Otherwise, returns
-$(HTTP cplusplus.com/reference/clibrary/cstdio/ferror.html, ferror) for
-the file handle.
+$(CSTDIO ferror) for the file handle.
*/
@property bool error() const @trusted pure nothrow
{
@@ -1017,8 +1014,7 @@ Throws: `ErrnoException` on failure if closing the file.
/**
If the file was closed or not yet opened, succeeds vacuously. Otherwise
-closes the file (by calling $(HTTP
-cplusplus.com/reference/clibrary/cstdio/fclose.html, fclose)),
+closes the file (by calling $(CSTDIO fclose)),
throwing on error. Even if an exception is thrown, afterwards the $(D
File) object is empty. This is different from `detach` in that it
always closes the file; consequently, all other `File` objects
@@ -1046,8 +1042,7 @@ Throws: `ErrnoException` on error.
/**
If the file is closed or not yet opened, succeeds vacuously. Otherwise, returns
-$(HTTP cplusplus.com/reference/clibrary/cstdio/_clearerr.html,
-_clearerr) for the file handle.
+$(CSTDIO clearerr) for the file handle.
*/
void clearerr() @safe pure nothrow
{
@@ -1058,8 +1053,7 @@ _clearerr) for the file handle.
/**
Flushes the C `FILE` buffers.
-Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/_fflush.html, _fflush)
-for the file handle.
+Calls $(CSTDIO fflush) for the file handle.
Throws: `Exception` if the file is not opened or if the call to `fflush` fails.
*/
@@ -1125,7 +1119,7 @@ Throws: `Exception` if the file is not opened or if the OS call fails.
}
/**
-Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/fread.html, fread) for the
+Calls $(CSTDIO fread) for the
file handle. The number of items to read and the size of
each item is inferred from the size and type of the input array, respectively.
@@ -1220,7 +1214,7 @@ Throws: `ErrnoException` if the file is not opened or the call to `fread` fails.
}
/**
-Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/fwrite.html, fwrite) for the file
+Calls $(CSTDIO fwrite) for the file
handle. The number of items to write and the size of each
item is inferred from the size and type of the input array, respectively. An
error is thrown if the buffer could not be written in its entirety.
@@ -1290,7 +1284,7 @@ Throws: `ErrnoException` if the file is not opened or if the call to `fwrite` fa
}
/**
-Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/fseek.html, fseek)
+Calls $(CSTDIO fseek)
for the file handle to move its position indicator.
Params:
@@ -1374,7 +1368,7 @@ Throws: `Exception` if the file is not opened.
}
/**
-Calls $(HTTP cplusplus.com/reference/cstdio/ftell.html, ftell)
+Calls $(CSTDIO ftell)
for the managed file handle, which returns the current value of
the position indicator of the file handle.
@@ -1420,8 +1414,7 @@ Throws: `Exception` if the file is not opened.
}
/**
-Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/_rewind.html, _rewind)
-for the file handle.
+Calls $(CSTDIO rewind) for the file handle.
Throws: `Exception` if the file is not opened.
*/
@@ -1434,8 +1427,7 @@ Throws: `Exception` if the file is not opened.
}
/**
-Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/_setvbuf.html, _setvbuf) for
-the file handle.
+Calls $(CSTDIO setvbuf) for the file handle.
Throws: `Exception` if the file is not opened.
`ErrnoException` if the call to `setvbuf` fails.
@@ -1450,8 +1442,7 @@ Throws: `Exception` if the file is not opened.
}
/**
-Calls $(HTTP cplusplus.com/reference/clibrary/cstdio/_setvbuf.html,
-_setvbuf) for the file handle.
+Calls $(CSTDIO setvbuf) for the file handle.
Throws: `Exception` if the file is not opened.
`ErrnoException` if the call to `setvbuf` fails.
@@ -2252,8 +2243,7 @@ $(CONSOLE
}
/**
- Returns a temporary file by calling
- $(HTTP cplusplus.com/reference/clibrary/cstdio/_tmpfile.html, _tmpfile).
+ Returns a temporary file by calling $(CSTDIO tmpfile).
Note that the created file has no $(LREF name).*/
static File tmpfile() @safe
{
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index f4d011bb..689f0ae 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -1198,7 +1198,7 @@ if (isCallable!func)
}
/**
-Convert the result of `__traits(getParameterStorageClasses)`
+Convert the result of $(DDSUBLINK spec/traits, getParameterStorageClasses, `__traits(getParameterStorageClasses)`)
to $(LREF ParameterStorageClass) `enum`s.
Params:
@@ -2184,7 +2184,7 @@ if (isCallable!func)
void func() {}
static assert(variadicFunctionStyle!func == Variadic.no);
- extern(C) int printf(in char*, ...);
+ extern(C) int printf(const char*, ...);
static assert(variadicFunctionStyle!printf == Variadic.c);
}
@@ -2572,6 +2572,8 @@ if (is(T == class))
/**
Determines whether `T` has its own context pointer.
`T` must be either `class`, `struct`, or `union`.
+
+See also: $(DDSUBLINK spec/traits, isNested, `__traits(isNested, T)`)
*/
template isNested(T)
if (is(T == class) || is(T == struct) || is(T == union))
@@ -3857,6 +3859,8 @@ package alias Identity(alias A) = A;
/**
Yields `true` if and only if `T` is an aggregate that defines
a symbol called `name`.
+
+ See also: $(DDSUBLINK spec/traits, hasMember, `__traits(hasMember, T, name)`)
*/
enum hasMember(T, string name) = __traits(hasMember, T, name);
@@ -4839,6 +4843,8 @@ package enum maxAlignment(U...) =
/**
Returns class instance alignment.
+
+See also: $(DDSUBLINK spec/traits, classInstanceAlignment, `__traits(classInstanceAlignment, T)`)
*/
template classInstanceAlignment(T)
if (is(T == class))
@@ -5313,7 +5319,7 @@ enum isLvalueAssignable(Lhs, Rhs = Lhs) = __traits(compiles, { lvalueOf!Lhs = lv
}
else
{
- mixin(q{ struct S6 { void opAssign(in ref S5); } });
+ mixin(q{ struct S6 { void opAssign(scope const ref S5); } });
static assert(!isRvalueAssignable!(S6, S5));
static assert( isLvalueAssignable!(S6, S5));
@@ -5680,7 +5686,7 @@ private struct __InoutWorkaroundStruct{}
/**
Creates an lvalue or rvalue of type `T` for `typeof(...)` and
-`__traits(compiles, ...)` purposes. No actual value is returned.
+$(DDSUBLINK spec/traits, compiles, `__traits(compiles, ...)`) purposes. No actual value is returned.
Params:
T = The type to transform
@@ -6166,7 +6172,7 @@ template BuiltinTypeOf(T)
//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
/**
- * Detect whether `T` is a built-in boolean type.
+ * Detect whether `T` is a built-in boolean type or enum of boolean base type.
*/
enum bool isBoolean(T) = __traits(isUnsigned, T) && is(T : bool);
@@ -6196,8 +6202,15 @@ enum bool isBoolean(T) = __traits(isUnsigned, T) && is(T : bool);
}
/**
- * Detect whether `T` is a built-in integral type. Types `bool`,
- * `char`, `wchar`, and `dchar` are not considered integral.
+ * Detect whether `T` is a built-in integral type.
+ * Integral types are `byte`, `ubyte`, `short`, `ushort`, `int`, `uint`, `long`, `ulong`, `cent`, `ucent`,
+ * and enums with an integral type as its base type.
+ * Params:
+ * T = type to test
+ * Returns:
+ * `true` if `T` is an integral type
+ * Note:
+ * this is not the same as $(LINK2 https://dlang.org/spec/traits.html#isIntegral, `__traits(isIntegral)`)
*/
template isIntegral(T)
{
@@ -6260,7 +6273,10 @@ template isIntegral(T)
/**
* Detect whether `T` is a built-in floating point type.
+ *
+ * See also: $(DDSUBLINK spec/traits, isFloating, `__traits(isFloating, T)`)
*/
+// is(T : real) to discount complex types
enum bool isFloatingPoint(T) = __traits(isFloating, T) && is(T : real);
///
@@ -6398,7 +6414,10 @@ template isNumeric(T)
/**
* Detect whether `T` is a scalar type (a built-in numeric, character or
* boolean type).
+ *
+ * See also: $(DDSUBLINK spec/traits, isScalar, `__traits(isScalar, T)`)
*/
+// is(T : real) to discount complex types
enum bool isScalarType(T) = __traits(isScalar, T) && is(T : real);
///
@@ -6927,6 +6946,8 @@ template isAutodecodableString(T)
/**
* Detect whether type `T` is a static array.
+ *
+ * See also: $(DDSUBLINK spec/traits, isStaticArray, `__traits(isStaticArray, T)`)
*/
enum bool isStaticArray(T) = __traits(isStaticArray, T);
@@ -7056,6 +7077,8 @@ enum bool isArray(T) = isStaticArray!T || isDynamicArray!T;
/**
* Detect whether `T` is an associative array type
+ *
+ * See also: $(DDSUBLINK spec/traits, isAssociativeArray, `__traits(isAssociativeArray, T)`)
*/
enum bool isAssociativeArray(T) = __traits(isAssociativeArray, T);
@@ -7542,14 +7565,12 @@ template isCallable(alias callable)
else static if (is(typeof(&callable.opCall) V : V*) && is(V == function))
// T is a type which has a static member function opCall().
enum bool isCallable = true;
- else static if (is(typeof(&callable.opCall!())))
+ else static if (is(typeof(&callable.opCall!()) TemplateInstanceType))
{
- alias TemplateInstanceType = typeof(&callable.opCall!());
enum bool isCallable = isCallable!TemplateInstanceType;
}
- else static if (is(typeof(&callable!())))
+ else static if (is(typeof(&callable!()) TemplateInstanceType))
{
- alias TemplateInstanceType = typeof(&callable!());
enum bool isCallable = isCallable!TemplateInstanceType;
}
else
@@ -7613,14 +7634,15 @@ template isCallable(alias callable)
/**
-Detect whether `T` is an abstract function.
+Detect whether `S` is an abstract function.
+See also: $(DDSUBLINK spec/traits, isAbstractFunction, `__traits(isAbstractFunction, S)`)
Params:
- T = The type to check
+ S = The symbol to check
Returns:
A `bool`
*/
-enum isAbstractFunction(alias T) = __traits(isAbstractFunction, T);
+enum isAbstractFunction(alias S) = __traits(isAbstractFunction, S);
///
@safe unittest
@@ -7635,9 +7657,11 @@ enum isAbstractFunction(alias T) = __traits(isAbstractFunction, T);
}
/**
- * Detect whether `T` is a final function.
+ * Detect whether `S` is a final function.
+ *
+ * See also: $(DDSUBLINK spec/traits, isFinalFunction, `__traits(isFinalFunction, S)`)
*/
-enum isFinalFunction(alias T) = __traits(isFinalFunction, T);
+enum isFinalFunction(alias S) = __traits(isFinalFunction, S);
///
@safe unittest
@@ -7703,9 +7727,11 @@ template isNestedFunction(alias f)
}
/**
- * Detect whether `T` is an abstract class.
+ * Detect whether `S` is an abstract class.
+ *
+ * See also: $(DDSUBLINK spec/traits, isAbstractClass, `__traits(isAbstractClass, S)`)
*/
-enum isAbstractClass(alias T) = __traits(isAbstractClass, T);
+enum isAbstractClass(alias S) = __traits(isAbstractClass, S);
///
@safe unittest
@@ -7723,9 +7749,11 @@ enum isAbstractClass(alias T) = __traits(isAbstractClass, T);
}
/**
- * Detect whether `T` is a final class.
+ * Detect whether `S` is a final class.
+ *
+ * See also: $(DDSUBLINK spec/traits, isFinalClass, `__traits(isFinalClass, S)`)
*/
-enum isFinalClass(alias T) = __traits(isFinalClass, T);
+enum isFinalClass(alias S) = __traits(isFinalClass, S);
///
@safe unittest
@@ -9092,12 +9120,13 @@ template isFinal(alias X)
+ If a type cannot be copied, then code such as `MyStruct x; auto y = x;` will fail to compile.
+ Copying for structs can be disabled by using `@disable this(this)`.
+
+ + See also: $(DDSUBLINK spec/traits, isCopyable, `__traits(isCopyable, S)`)
+ Params:
+ S = The type to check.
+
+ Returns:
+ `true` if `S` can be copied. `false` otherwise.
- + ++/
+ +/
enum isCopyable(S) = __traits(isCopyable, S);
///
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index bde8439..d267e71 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -2332,7 +2332,7 @@ break the soundness of D's type system and does not incur any of the
risks usually associated with `cast`.
Params:
- T = An object, interface, array slice type, or associative array type.
+ T = Any type.
*/
template Rebindable(T)
if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArray!T)
@@ -2395,15 +2395,155 @@ if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArr
static assert(!__traits(compiles, &r.get()));
}
+/// ditto
+struct Rebindable(T)
+if (!is(T == class) && !is(T == interface) && !isDynamicArray!T && !isAssociativeArray!T)
+{
+private:
+ static if (isAssignable!(typeof(cast() T.init)))
+ {
+ enum useQualifierCast = true;
+
+ typeof(cast() T.init) data;
+ }
+ else
+ {
+ enum useQualifierCast = false;
+
+ align(T.alignof)
+ static struct Payload
+ {
+ static if (hasIndirections!T)
+ {
+ void[T.sizeof] data;
+ }
+ else
+ {
+ ubyte[T.sizeof] data;
+ }
+ }
+
+ Payload data;
+ }
+
+public:
+
+ static if (!__traits(compiles, { T value; }))
+ {
+ @disable this();
+ }
+
+ /**
+ * Constructs a `Rebindable` from a given value.
+ */
+ this(T value) @trusted
+ {
+ static if (useQualifierCast)
+ {
+ this.data = cast() value;
+ }
+ else
+ {
+ set(value);
+ }
+ }
+
+ /**
+ * Overwrites the currently stored value with `value`.
+ */
+ void opAssign(this This)(T value) @trusted
+ {
+ clear;
+ set(value);
+ }
+
+ /**
+ * Returns the value currently stored in the `Rebindable`.
+ */
+ T get(this This)() @property @trusted
+ {
+ static if (useQualifierCast)
+ {
+ return cast(T) this.data;
+ }
+ else
+ {
+ return *cast(T*) &this.data;
+ }
+ }
+
+ static if (!useQualifierCast)
+ {
+ ~this() @trusted
+ {
+ clear;
+ }
+ }
+
+ ///
+ alias get this;
+
+private:
+
+ void set(this This)(T value)
+ {
+ static if (useQualifierCast)
+ {
+ this.data = cast() value;
+ }
+ else
+ {
+ // As we're escaping a copy of `value`, deliberately leak a copy:
+ static union DontCallDestructor
+ {
+ T value;
+ }
+ DontCallDestructor copy = DontCallDestructor(value);
+ this.data = *cast(Payload*) &copy;
+ }
+ }
+
+ void clear(this This)()
+ {
+ // work around reinterpreting cast being impossible in CTFE
+ if (__ctfe)
+ {
+ return;
+ }
+
+ // call possible struct destructors
+ .destroy!(No.initialize)(*cast(T*) &this.data);
+ }
+}
+
+/// Using Rebindable in a generic algorithm:
@safe unittest
{
- class CustomToHash
+ import std.range.primitives : front, popFront;
+
+ // simple version of std.algorithm.searching.maxElement
+ typeof(R.init.front) maxElement(R)(R r)
{
- override size_t toHash() const nothrow @trusted { return 42; }
+ auto max = rebindable(r.front);
+ r.popFront;
+ foreach (e; r)
+ if (e > max)
+ max = e; // Rebindable allows const-correct reassignment
+ return max;
}
- Rebindable!(immutable(CustomToHash)) a = new immutable CustomToHash();
- assert(a.toHash() == 42, "Rebindable!A should offer toHash()"
- ~ " by forwarding to A.toHash().");
+ struct S
+ {
+ char[] arr;
+ alias arr this; // for comparison
+ }
+ // can't convert to mutable
+ const S cs;
+ static assert(!__traits(compiles, { S s = cs; }));
+
+ alias CS = const S;
+ CS[] arr = [CS("harp"), CS("apple"), CS("pot")];
+ CS ms = maxElement(arr);
+ assert(ms.arr == "pot");
}
// https://issues.dlang.org/show_bug.cgi?id=18615
@@ -2453,6 +2593,34 @@ if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArr
~ " comparable against Object itself and use Object.opEquals.");
}
+///
+@system unittest
+{
+ static struct S
+ {
+ int* ptr;
+ }
+ S s = S(new int);
+
+ const cs = s;
+ // Can't assign s.ptr to cs.ptr
+ static assert(!__traits(compiles, {s = cs;}));
+
+ Rebindable!(const S) rs = s;
+ assert(rs.ptr is s.ptr);
+ // rs.ptr is const
+ static assert(!__traits(compiles, {rs.ptr = null;}));
+
+ // Can't assign s.ptr to rs.ptr
+ static assert(!__traits(compiles, {s = rs;}));
+
+ const S cs2 = rs;
+ // Rebind rs
+ rs = cs2;
+ rs = S();
+ assert(rs.ptr is null);
+}
+
// https://issues.dlang.org/show_bug.cgi?id=18755
@safe unittest
{
@@ -2473,13 +2641,145 @@ if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArr
}));
}
+@safe unittest
+{
+ class CustomToHash
+ {
+ override size_t toHash() const nothrow @trusted { return 42; }
+ }
+ Rebindable!(immutable(CustomToHash)) a = new immutable CustomToHash();
+ assert(a.toHash() == 42, "Rebindable!A should offer toHash()"
+ ~ " by forwarding to A.toHash().");
+}
+
+// Test Rebindable!immutable
+@safe unittest
+{
+ static struct S
+ {
+ int* ptr;
+ }
+ S s = S(new int);
+
+ Rebindable!(immutable S) ri = S(new int);
+ assert(ri.ptr !is null);
+ static assert(!__traits(compiles, {ri.ptr = null;}));
+
+ // ri is not compatible with mutable S
+ static assert(!__traits(compiles, {s = ri;}));
+ static assert(!__traits(compiles, {ri = s;}));
+
+ auto ri2 = ri;
+ assert(ri2.ptr == ri.ptr);
+
+ const S cs3 = ri;
+ static assert(!__traits(compiles, {ri = cs3;}));
+
+ immutable S si = ri;
+ // Rebind ri
+ ri = si;
+ ri = S();
+ assert(ri.ptr is null);
+
+ // Test RB!immutable -> RB!const
+ Rebindable!(const S) rc = ri;
+ assert(rc.ptr is null);
+ ri = S(new int);
+ rc = ri;
+ assert(rc.ptr !is null);
+
+ // test rebindable, opAssign
+ rc.destroy;
+ assert(rc.ptr is null);
+ rc = rebindable(cs3);
+ rc = rebindable(si);
+ assert(rc.ptr !is null);
+
+ ri.destroy;
+ assert(ri.ptr is null);
+ ri = rebindable(si);
+ assert(ri.ptr !is null);
+}
+
+// Test disabled default ctor
+@safe unittest
+{
+ static struct ND
+ {
+ int i;
+ @disable this();
+ this(int i) inout {this.i = i;}
+ }
+ static assert(!__traits(compiles, Rebindable!ND()));
+
+ Rebindable!(const ND) rb = const ND(1);
+ assert(rb.i == 1);
+ rb = immutable ND(2);
+ assert(rb.i == 2);
+ rb = rebindable(const ND(3));
+ assert(rb.i == 3);
+ static assert(!__traits(compiles, rb.i++));
+}
+
+// Test copying
+@safe unittest
+{
+ int del;
+ int post;
+ struct S
+ {
+ int* ptr;
+ int level;
+ this(this)
+ {
+ post++;
+ level++;
+ }
+ ~this()
+ {
+ del++;
+ }
+ }
+
+ // test ref count
+ {
+ Rebindable!S rc = S(new int);
+ }
+ assert(post == del - 1);
+}
+
+@safe unittest
+{
+ int del;
+ int post;
+ struct S
+ {
+ immutable int x;
+ int level;
+ this(this)
+ {
+ post++;
+ level++;
+ }
+ ~this()
+ {
+ del++;
+ }
+ }
+
+ // test ref count
+ {
+ Rebindable!S rc = S(0);
+ }
+ assert(post == del - 1);
+}
+
/**
Convenience function for creating a `Rebindable` using automatic type
inference.
Params:
- obj = A reference to an object, interface, associative array, or an array slice
- to initialize the `Rebindable` with.
+ obj = A reference to a value to initialize the `Rebindable` with.
Returns:
A newly constructed `Rebindable` initialized with the given reference.
@@ -2514,6 +2814,26 @@ if (is(T == class) || is(T == interface) || isDynamicArray!T || isAssociativeArr
assert(c3.payload == 2);
}
+/// ditto
+Rebindable!T rebindable(T)(T value)
+if (!is(T == class) && !is(T == interface) && !isDynamicArray!T && !isAssociativeArray!T
+ && !is(T : Rebindable!U, U))
+{
+ return Rebindable!T(value);
+}
+
+///
+@safe unittest
+{
+ immutable struct S
+ {
+ int[] array;
+ }
+ auto s1 = [3].idup.rebindable;
+ s1 = [4].idup.rebindable;
+ assert(s1 == [4]);
+}
+
/**
This function simply returns the `Rebindable` object passed in. It's useful
in generic programming cases when a given object may be either a regular
@@ -2626,10 +2946,6 @@ Rebindable!T rebindable(T)(Rebindable!T obj)
static assert(is(Rebindable!(T[]) == T[]));
}
- // https://issues.dlang.org/show_bug.cgi?id=12046
- static assert(!__traits(compiles, Rebindable!(int[1])));
- static assert(!__traits(compiles, Rebindable!(const int[1])));
-
// Pull request 3341
Rebindable!(immutable int[int]) pr3341 = [123:345];
assert(pr3341[123] == 345);