aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2021-12-05 17:11:12 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2021-12-09 00:58:58 +0100
commit0fb57034770aa20adced4d176f34ca611c2945bf (patch)
tree1f5735c8b4f25aa4a290e5ae8124713c24f98359 /gcc
parentc15aa46cca0649b68613d3292cf71c7cc57ef78f (diff)
downloadgcc-0fb57034770aa20adced4d176f34ca611c2945bf.zip
gcc-0fb57034770aa20adced4d176f34ca611c2945bf.tar.gz
gcc-0fb57034770aa20adced4d176f34ca611c2945bf.tar.bz2
d: Merge upstream dmd 568496d5b, druntime 178c44ff, phobos 574bf883b.
D front-end changes: - Import dmd v2.098.0 - New ImportC module for compiling preprocessed C11 code into D. - New -ftransition=in switch. - Improved handling of new 'noreturn' type. Druntime changes: - Import druntime v2.098.0 - Fix broken import in core.sys.linux.perf_event module (PR103558). Phobos changes: - Import phobos v2.098.0 - All sources are now compiled with -fpreview=fieldwise. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 568496d5b. * Make-lang.in (D_FRONTEND_OBJS): Add d/common-file.o, d/common-outbuffer.o, d/common-string.o, d/file_manager.o, d/importc.o. Remove d/root-outbuffer.o. (d/common-%.o): New recipe. * d-builtins.cc (build_frontend_type): Update for new front-end interface. (d_build_d_type_nodes): Set noreturn_type_node. * d-codegen.cc (d_build_call): Don't call function if one of the arguments is type 'noreturn'. (build_vthis_function): Propagate TYPE_QUAL_VOLATILE from original function type. * d-frontend.cc (eval_builtin): Update signature. (getTypeInfoType): Likewise. (toObjFile): New function. * d-gimplify.cc (d_gimplify_call_expr): Always evaluate arguments from left to right. * d-lang.cc (d_handle_option): Handle OPT_ftransition_in. (d_parse_file): Don't generate D main if it is declared in user code. * d-tree.h (CALL_EXPR_ARGS_ORDERED): Remove. (enum d_tree_index): Add DTI_BOTTOM_TYPE. (noreturn_type_node): New. * decl.cc (apply_pragma_crt): Remove. (DeclVisitor::visit): Update for new front-end interface. (DeclVisitor::visit (PragmaDeclaration *)): Don't handle crt_constructor and crt_destructor pragmas. (DeclVisitor::visit (VarDeclaration *)): Don't generate declarations of type 'noreturn'. (DeclVisitor::visit (FuncDeclaration *)): Stop adding parameters when 'noreturn' type has been encountered. (get_symbol_decl): Set DECL_STATIC_CONSTRUCTOR and DECL_STATIC_DESTRUCTOR on decl node if requested. (aggregate_initializer_decl): Update for new front-end interface. * expr.cc (ExprVisitor::visit (CallExp *)): Always use the 'this' object as the result of calling any constructor function. (ExprVisitor::visit): Update for new front-end interface. * gdc.texi (Runtime Options): Document -fmain and -ftransition=in. * lang.opt (ftransition=in): New option. * modules.cc (get_internal_fn): Update for new front-end interface. * types.cc (TypeVisitor::visit): Likewise. (TypeVisitor::visit (TypeNoreturn *)): Return noreturn_type_node. (TypeVisitor::visit (TypeFunction *)): Stop adding parameters when 'notreturn' type has been encountered. Qualify function types that return 'noreturn' as TYPE_QUAL_VOLATILE. libphobos/ChangeLog: PR d/103558 * libdruntime/MERGE: Merge upstream druntime 178c44ff. * libdruntime/Makefile.am (DRUNTIME_DSOURCES_LINUX): Add core/sys/linux/syscalls.d. (DRUNTIME_DSOURCES_OPENBSD): Add core/sys/openbsd/pthread_np.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 574bf883b. * src/Makefile.am (D_EXTRA_DFLAGS): Add -fpreview=fieldwise. * src/Makefile.in: Regenerate. * testsuite/libphobos.exceptions/assert_fail.d: Update test. * testsuite/libphobos.betterc/test22336.d: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/d/Make-lang.in10
-rw-r--r--gcc/d/d-builtins.cc7
-rw-r--r--gcc/d/d-codegen.cc36
-rw-r--r--gcc/d/d-frontend.cc11
-rw-r--r--gcc/d/d-gimplify.cc65
-rw-r--r--gcc/d/d-lang.cc16
-rw-r--r--gcc/d/d-tree.h9
-rw-r--r--gcc/d/decl.cc155
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/README.md18
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/aggregate.d81
-rw-r--r--gcc/d/dmd/aggregate.h17
-rw-r--r--gcc/d/dmd/aliasthis.d23
-rw-r--r--gcc/d/dmd/arrayop.d2
-rw-r--r--gcc/d/dmd/attrib.d22
-rw-r--r--gcc/d/dmd/blockexit.d4
-rw-r--r--gcc/d/dmd/builtin.d2
-rw-r--r--gcc/d/dmd/chkformat.d8
-rw-r--r--gcc/d/dmd/clone.d139
-rw-r--r--gcc/d/dmd/common/README.md7
-rw-r--r--gcc/d/dmd/common/file.d576
-rw-r--r--gcc/d/dmd/common/outbuffer.d (renamed from gcc/d/dmd/root/outbuffer.d)243
-rw-r--r--gcc/d/dmd/common/outbuffer.h (renamed from gcc/d/dmd/root/outbuffer.h)10
-rw-r--r--gcc/d/dmd/common/string.d209
-rw-r--r--gcc/d/dmd/cond.d3
-rw-r--r--gcc/d/dmd/cparse.d225
-rw-r--r--gcc/d/dmd/cppmangle.d15
-rw-r--r--gcc/d/dmd/ctfeexpr.d5
-rw-r--r--gcc/d/dmd/dcast.d136
-rw-r--r--gcc/d/dmd/dclass.d23
-rw-r--r--gcc/d/dmd/declaration.d161
-rw-r--r--gcc/d/dmd/declaration.h9
-rw-r--r--gcc/d/dmd/dinterpret.d46
-rw-r--r--gcc/d/dmd/dmacro.d2
-rw-r--r--gcc/d/dmd/dmangle.d53
-rw-r--r--gcc/d/dmd/dmodule.d142
-rw-r--r--gcc/d/dmd/doc.d28
-rw-r--r--gcc/d/dmd/dscope.d15
-rw-r--r--gcc/d/dmd/dstruct.d39
-rw-r--r--gcc/d/dmd/dsymbol.d110
-rw-r--r--gcc/d/dmd/dsymbol.h20
-rw-r--r--gcc/d/dmd/dsymbolsem.d167
-rw-r--r--gcc/d/dmd/dtemplate.d41
-rw-r--r--gcc/d/dmd/dtoh.d31
-rw-r--r--gcc/d/dmd/dversion.d2
-rw-r--r--gcc/d/dmd/expression.d104
-rw-r--r--gcc/d/dmd/expression.h55
-rw-r--r--gcc/d/dmd/expressionsem.d426
-rw-r--r--gcc/d/dmd/file_manager.d301
-rw-r--r--gcc/d/dmd/file_manager.h (renamed from gcc/d/dmd/root/root.h)17
-rw-r--r--gcc/d/dmd/func.d76
-rw-r--r--gcc/d/dmd/globals.d27
-rw-r--r--gcc/d/dmd/globals.h23
-rw-r--r--gcc/d/dmd/gluelayer.d1
-rw-r--r--gcc/d/dmd/hdrgen.d20
-rw-r--r--gcc/d/dmd/iasmgcc.d2
-rw-r--r--gcc/d/dmd/id.d11
-rw-r--r--gcc/d/dmd/identifier.d2
-rw-r--r--gcc/d/dmd/importc.d171
-rw-r--r--gcc/d/dmd/init.d2
-rw-r--r--gcc/d/dmd/initsem.d128
-rw-r--r--gcc/d/dmd/intrange.h177
-rw-r--r--gcc/d/dmd/json.d6
-rw-r--r--gcc/d/dmd/lambdacomp.d2
-rw-r--r--gcc/d/dmd/lexer.d237
-rw-r--r--gcc/d/dmd/lexer.h75
-rw-r--r--gcc/d/dmd/macro.h38
-rw-r--r--gcc/d/dmd/mars.h93
-rw-r--r--gcc/d/dmd/module.h2
-rw-r--r--gcc/d/dmd/mtype.d211
-rw-r--r--gcc/d/dmd/mtype.h4
-rw-r--r--gcc/d/dmd/ob.d2
-rw-r--r--gcc/d/dmd/objc.d2
-rw-r--r--gcc/d/dmd/opover.d43
-rw-r--r--gcc/d/dmd/optimize.d2
-rw-r--r--gcc/d/dmd/parse.d12
-rw-r--r--gcc/d/dmd/parse.h192
-rw-r--r--gcc/d/dmd/printast.d2
-rw-r--r--gcc/d/dmd/root/README.md1
-rw-r--r--gcc/d/dmd/root/aav.h22
-rw-r--r--gcc/d/dmd/root/checkedint.h30
-rw-r--r--gcc/d/dmd/root/file.d529
-rw-r--r--gcc/d/dmd/root/filename.d102
-rw-r--r--gcc/d/dmd/root/hash.h76
-rw-r--r--gcc/d/dmd/root/rootobject.d2
-rw-r--r--gcc/d/dmd/root/speller.h16
-rw-r--r--gcc/d/dmd/root/stringtable.h56
-rw-r--r--gcc/d/dmd/safe.d2
-rw-r--r--gcc/d/dmd/semantic2.d4
-rw-r--r--gcc/d/dmd/semantic3.d18
-rw-r--r--gcc/d/dmd/statement.d8
-rw-r--r--gcc/d/dmd/statement.h6
-rw-r--r--gcc/d/dmd/statement_rewrite_walker.h172
-rw-r--r--gcc/d/dmd/statementsem.d160
-rw-r--r--gcc/d/dmd/staticcond.d2
-rw-r--r--gcc/d/dmd/target.d3
-rw-r--r--gcc/d/dmd/target.h3
-rw-r--r--gcc/d/dmd/template.h10
-rw-r--r--gcc/d/dmd/tokens.d2
-rw-r--r--gcc/d/dmd/tokens.h1
-rw-r--r--gcc/d/dmd/traits.d33
-rw-r--r--gcc/d/dmd/typesem.d48
-rw-r--r--gcc/d/dmd/typinf.d238
-rw-r--r--gcc/d/dmd/utf.h117
-rw-r--r--gcc/d/dmd/utils.d2
-rw-r--r--gcc/d/expr.cc9
-rw-r--r--gcc/d/gdc.texi9
-rw-r--r--gcc/d/lang.opt4
-rw-r--r--gcc/d/modules.cc2
-rw-r--r--gcc/d/types.cc19
-rw-r--r--gcc/testsuite/gdc.test/compilable/b19294.d69
-rw-r--r--gcc/testsuite/gdc.test/compilable/cdcmp.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_22285.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_ignored.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/cstuff3.c6
-rw-r--r--gcc/testsuite/gdc.test/compilable/mixintype2.d49
-rw-r--r--gcc/testsuite/gdc.test/compilable/noreturn1.d49
-rw-r--r--gcc/testsuite/gdc.test/compilable/previewall.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/reinterpretctfe.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/sroa.d55
-rw-r--r--gcc/testsuite/gdc.test/compilable/stc_traits.d172
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15711.d31
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16492.d87
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19482.d68
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21438.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21794.d52
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21850.d35
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22214.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22224.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22228.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22292.d155
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22388.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22410.d59
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22420.d88
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22421.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test318.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test4090.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9766.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/testcstuff3.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/transition_in.d26
-rw-r--r--gcc/testsuite/gdc.test/compilable/zerosize.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10327.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag20059.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20618.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21091a.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21091b.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22084.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22151.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22366.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail225.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail287.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail318.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail318_b.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail7173.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/foreach.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/foreach2.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10212.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice22377.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice7782.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/imp22329.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/noreturn.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/noreturn2.d90
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/reserved_version.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17425.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17868b.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20998.d120
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21093.d56
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21380.d46
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21930.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test22329.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test22361.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/testOpApply.d161
-rw-r--r--gcc/testsuite/gdc.test/runnable/aliasthis.d36
-rw-r--r--gcc/testsuite/gdc.test/runnable/dhry.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/fix22372.d38
-rw-r--r--gcc/testsuite/gdc.test/runnable/interpret.d57
-rw-r--r--gcc/testsuite/gdc.test/runnable/noreturn1.d47
-rw-r--r--gcc/testsuite/gdc.test/runnable/noreturn2.d220
-rw-r--r--gcc/testsuite/gdc.test/runnable/sroa13220.d103
-rw-r--r--gcc/testsuite/gdc.test/runnable/test15624.d51
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21039.d27
-rw-r--r--gcc/testsuite/gdc.test/runnable/test22205.d17
-rw-r--r--gcc/testsuite/gdc.test/runnable/test22278.d24
-rw-r--r--gcc/testsuite/gdc.test/runnable/testOpApply.d142
-rw-r--r--gcc/testsuite/gdc.test/runnable/testmainb.d15
-rw-r--r--gcc/testsuite/gdc.test/runnable/uda.d48
-rw-r--r--gcc/testsuite/gdc.test/runnable/ufcs.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp22287.cpp337
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/test22287.d327
191 files changed, 7386 insertions, 3141 deletions
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 4ce11e3..d7f7147 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -89,6 +89,9 @@ D_FRONTEND_OBJS = \
d/canthrow.o \
d/chkformat.o \
d/clone.o \
+ d/common-file.o \
+ d/common-outbuffer.o \
+ d/common-string.o \
d/compiler.o \
d/complex.o \
d/cond.o \
@@ -120,6 +123,7 @@ D_FRONTEND_OBJS = \
d/escape.o \
d/expression.o \
d/expressionsem.o \
+ d/file_manager.o \
d/foreachvar.o \
d/func.o \
d/globals.o \
@@ -131,6 +135,7 @@ D_FRONTEND_OBJS = \
d/identifier.o \
d/impcnvtab.o \
d/imphint.o \
+ d/importc.o \
d/init.o \
d/initsem.o \
d/inline.o \
@@ -157,7 +162,6 @@ D_FRONTEND_OBJS = \
d/root-filename.o \
d/root-hash.o \
d/root-longdouble.o \
- d/root-outbuffer.o \
d/root-port.o \
d/root-region.o \
d/root-rmem.o \
@@ -393,6 +397,10 @@ d/%.o: d/dmd/%.d
$(DCOMPILE) $(D_INCLUDES) $<
$(DPOSTCOMPILE)
+d/common-%.o: d/dmd/common/%.d
+ $(DCOMPILE) $(D_INCLUDES) $<
+ $(DPOSTCOMPILE)
+
d/root-%.o: d/dmd/root/%.d
$(DCOMPILE) $(D_INCLUDES) $<
$(DPOSTCOMPILE)
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index ab3a950..ea8e1ed 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -236,7 +236,7 @@ build_frontend_type (tree type)
sdecl->parent = stubmod;
sdecl->structsize = int_size_in_bytes (type);
sdecl->alignsize = TYPE_ALIGN_UNIT (type);
- sdecl->alignment = STRUCTALIGN_DEFAULT;
+ sdecl->alignment.setDefault ();
sdecl->sizeok = Sizeok::done;
sdecl->type = (TypeStruct::create (sdecl))->addMod (mod);
sdecl->type->ctype = type;
@@ -275,7 +275,7 @@ build_frontend_type (tree type)
NULL);
vd->parent = sdecl;
vd->offset = tree_to_uhwi (byte_position (field));
- vd->semanticRun = PASSsemanticdone;
+ vd->semanticRun = PASS::semanticdone;
vd->csym = field;
sdecl->members->push (vd);
sdecl->fields.push (vd);
@@ -856,6 +856,9 @@ d_build_d_type_nodes (void)
ireal_type_node = build_distinct_type_copy (long_double_type_node);
TYPE_IMAGINARY_FLOAT (ireal_type_node) = 1;
+ /* Noreturn type. */
+ noreturn_type_node = build_distinct_type_copy (void_type_node);
+
/* Calling build_ctype() links the front-end Type to the GCC node,
and sets the TYPE_NAME to the D language type. */
for (unsigned ty = 0; ty < (unsigned) TY::TMAX; ty++)
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 403e3c7..c082ac5 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -2140,6 +2140,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
/* Build the argument list for the call. */
vec <tree, va_gc> *args = NULL;
tree saved_args = NULL_TREE;
+ bool noreturn_call = false;
/* If this is a delegate call or a nested function being called as
a delegate, the object should not be NULL. */
@@ -2165,9 +2166,9 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
}
}
- size_t nparams = tf->parameterList.length ();
+ const size_t nparams = tf->parameterList.length ();
/* if _arguments[] is the first argument. */
- size_t varargs = tf->isDstyleVariadic ();
+ const size_t varargs = tf->isDstyleVariadic ();
/* Assumes arguments->length <= formal_args->length if (!tf->varargs). */
for (size_t i = 0; i < arguments->length; ++i)
@@ -2206,6 +2207,11 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
build_address (targ));
}
+ /* Type `noreturn` is a terminator, as no other arguments can possibly
+ be evaluated after it. */
+ if (TREE_TYPE (targ) == noreturn_type_node)
+ noreturn_call = true;
+
vec_safe_push (args, targ);
}
}
@@ -2217,13 +2223,27 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
saved_args = compound_expr (callee, saved_args);
}
+ /* If we saw a `noreturn` parameter, any unreachable argument evaluations
+ after it are discarded, as well as the function call itself. */
+ if (noreturn_call)
+ {
+ if (TREE_SIDE_EFFECTS (callee))
+ saved_args = compound_expr (callee, saved_args);
+
+ tree arg;
+ unsigned int ix;
+
+ FOR_EACH_VEC_SAFE_ELT (args, ix, arg)
+ saved_args = compound_expr (saved_args, arg);
+
+ /* Add a stub result type for the expression. */
+ tree result = build_zero_cst (TREE_TYPE (ctype));
+ return compound_expr (saved_args, result);
+ }
+
tree result = build_call_vec (TREE_TYPE (ctype), callee, args);
SET_EXPR_LOCATION (result, input_location);
- /* Enforce left to right evaluation. */
- if (tf->linkage == LINK::d)
- CALL_EXPR_ARGS_ORDERED (result) = 1;
-
result = maybe_expand_intrinsic (result);
/* Return the value in a temporary slot so that it can be evaluated
@@ -2296,6 +2316,10 @@ build_vthis_function (tree basetype, tree type)
TYPE_ARG_TYPES (type));
tree fntype = build_function_type (TREE_TYPE (type), argtypes);
+ /* Copy volatile qualifiers from the original function type. */
+ if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
+ fntype = build_qualified_type (fntype, TYPE_QUAL_VOLATILE);
+
if (RECORD_OR_UNION_TYPE_P (basetype))
TYPE_METHOD_BASETYPE (fntype) = TYPE_MAIN_VARIANT (basetype);
else
diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
index 522095f..b2e52c0 100644
--- a/gcc/d/d-frontend.cc
+++ b/gcc/d/d-frontend.cc
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "d-tree.h"
+#include "d-frontend.h"
/* Implements back-end specific interfaces used by the frontend. */
@@ -51,7 +52,7 @@ isBuiltin (FuncDeclaration *fd)
Return result; NULL if cannot evaluate it. */
Expression *
-eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
+eval_builtin (const Loc &loc, FuncDeclaration *fd, Expressions *arguments)
{
if (fd->builtin == BUILTIN::unimp)
return NULL;
@@ -78,10 +79,16 @@ eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
/* Build and return typeinfo type for TYPE. */
Type *
-getTypeInfoType (Loc loc, Type *type, Scope *sc)
+getTypeInfoType (const Loc &loc, Type *type, Scope *sc)
{
gcc_assert (type->ty != TY::Terror);
check_typeinfo_type (loc, sc);
create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
return type->vtinfo->type;
}
+
+void
+toObjFile (Dsymbol *ds, bool)
+{
+ build_decl_tree (ds);
+}
diff --git a/gcc/d/d-gimplify.cc b/gcc/d/d-gimplify.cc
index 0fa7442..e366881 100644
--- a/gcc/d/d-gimplify.cc
+++ b/gcc/d/d-gimplify.cc
@@ -120,52 +120,47 @@ d_gimplify_addr_expr (tree *expr_p)
static gimplify_status
d_gimplify_call_expr (tree *expr_p, gimple_seq *pre_p)
{
- if (CALL_EXPR_ARGS_ORDERED (*expr_p))
- {
- /* Strictly evaluate all arguments from left to right. */
- int nargs = call_expr_nargs (*expr_p);
- location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
+ /* Strictly evaluate all arguments from left to right. */
+ int nargs = call_expr_nargs (*expr_p);
+ location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
- /* No need to enforce evaluation order if only one argument. */
- if (nargs < 2)
- return GS_UNHANDLED;
+ /* No need to enforce evaluation order if only one argument. */
+ if (nargs < 2)
+ return GS_UNHANDLED;
- /* Or if all arguments are already free of side-effects. */
- bool has_side_effects = false;
- for (int i = 0; i < nargs; i++)
+ /* Or if all arguments are already free of side-effects. */
+ bool has_side_effects = false;
+ for (int i = 0; i < nargs; i++)
+ {
+ if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i)))
{
- if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i)))
- {
- has_side_effects = true;
- break;
- }
+ has_side_effects = true;
+ break;
}
+ }
- if (!has_side_effects)
- return GS_UNHANDLED;
-
- /* Leave the last argument for gimplify_call_expr. */
- for (int i = 0; i < nargs - 1; i++)
- {
- tree new_arg = CALL_EXPR_ARG (*expr_p, i);
+ if (!has_side_effects)
+ return GS_UNHANDLED;
- /* If argument has a side-effect, gimplify_arg will handle it. */
- if (gimplify_arg (&new_arg, pre_p, loc) == GS_ERROR)
- return GS_ERROR;
+ /* Leave the last argument for gimplify_call_expr. */
+ for (int i = 0; i < nargs - 1; i++)
+ {
+ tree new_arg = CALL_EXPR_ARG (*expr_p, i);
- /* Even if an argument itself doesn't have any side-effects, it
- might be altered by another argument in the list. */
- if (new_arg == CALL_EXPR_ARG (*expr_p, i)
- && !really_constant_p (new_arg))
- new_arg = get_formal_tmp_var (new_arg, pre_p);
+ /* If argument has a side-effect, gimplify_arg will handle it. */
+ if (gimplify_arg (&new_arg, pre_p, loc) == GS_ERROR)
+ return GS_ERROR;
- CALL_EXPR_ARG (*expr_p, i) = new_arg;
- }
+ /* Even if an argument itself doesn't have any side-effects, it
+ might be altered by another argument in the list. */
+ if (new_arg == CALL_EXPR_ARG (*expr_p, i)
+ && !really_constant_p (new_arg))
+ new_arg = get_formal_tmp_var (new_arg, pre_p);
- return GS_OK;
+ CALL_EXPR_ARG (*expr_p, i) = new_arg;
}
- return GS_UNHANDLED;
+ return GS_OK;
}
/* Gimplify an UNSIGNED_RSHIFT_EXPR node. */
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index dbf7a8b..576eefc 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -674,6 +674,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
case OPT_ftransition_all:
global.params.vfield = value;
global.params.vgc = value;
+ global.params.vin = value;
global.params.vmarkdown= value;
global.params.vtls = value;
break;
@@ -682,6 +683,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.vfield = value;
break;
+ case OPT_ftransition_in:
+ global.params.vin = value;
+ break;
+
case OPT_ftransition_nogc:
global.params.vgc = value;
break;
@@ -1176,6 +1181,14 @@ d_parse_file (void)
{
Module *m = modules[i];
+ /* If this is the `__main` module, check that `D main` hasn't already
+ been declared in user code before running semantic on it. */
+ if (m == main_module && global.hasMainFunction)
+ {
+ modules.remove (i);
+ continue;
+ }
+
if (global.params.verbose)
message ("semantic %s", m->toChars ());
@@ -1357,6 +1370,9 @@ d_parse_file (void)
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
+
+ /* Skip generating code for header files, or when the module wasn't
+ specified by `-fonly=`. */
if ((m->isHdrFile && m != main_module)
|| (d_option.fonly && m != Module::rootModule))
continue;
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
index 328b6b8..a5970d8 100644
--- a/gcc/d/d-tree.h
+++ b/gcc/d/d-tree.h
@@ -47,7 +47,6 @@ typedef Array <Expression *> Expressions;
/* Usage of TREE_LANG_FLAG_?:
0: METHOD_CALL_EXPR
- 1: CALL_EXPR_ARGS_ORDERED (in CALL_EXPR).
Usage of TYPE_LANG_FLAG_?:
0: TYPE_SHARED
@@ -351,11 +350,6 @@ lang_tree_node
#define METHOD_CALL_EXPR(NODE) \
(TREE_LANG_FLAG_0 (NODE))
-/* True if all arguments in a call expression should be evaluated in the
- order they are given (left to right). */
-#define CALL_EXPR_ARGS_ORDERED(NODE) \
- (TREE_LANG_FLAG_1 (CALL_EXPR_CHECK (NODE)))
-
/* True if the type was declared 'shared'. */
#define TYPE_SHARED(NODE) \
(TYPE_LANG_FLAG_0 (NODE))
@@ -430,6 +424,7 @@ enum d_tree_index
DTI_ARRAY_TYPE,
DTI_NULL_ARRAY,
+ DTI_BOTTOM_TYPE,
DTI_MAX
};
@@ -465,6 +460,8 @@ extern GTY(()) tree d_global_trees[DTI_MAX];
#define array_type_node d_global_trees[DTI_ARRAY_TYPE]
/* Null initializer for dynamic arrays. */
#define null_array_node d_global_trees[DTI_NULL_ARRAY]
+/* The bottom type, referred to as `noreturn` in code. */
+#define noreturn_type_node d_global_trees[DTI_BOTTOM_TYPE]
/* A prefix for internal variables, which are not user-visible. */
#if !defined (NO_DOT_IN_LABEL)
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index e28a581..a4976b6 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -116,59 +116,6 @@ gcc_attribute_p (Dsymbol *decl)
return false;
}
-/* Subroutine of pragma declaration visitor for marking the function in the
- defined in SYM as a global constructor or destructor. If ISCTOR is true,
- then we're applying pragma(crt_constructor). */
-
-static int
-apply_pragma_crt (Dsymbol *sym, bool isctor)
-{
- AttribDeclaration *ad = sym->isAttribDeclaration ();
- if (ad != NULL)
- {
- int nested = 0;
-
- /* Walk all declarations of the attribute scope. */
- Dsymbols *ds = ad->include (NULL);
- if (ds)
- {
- for (size_t i = 0; i < ds->length; i++)
- nested += apply_pragma_crt ((*ds)[i], isctor);
- }
-
- return nested;
- }
-
- FuncDeclaration *fd = sym->isFuncDeclaration ();
- if (fd != NULL)
- {
- tree decl = get_decl_tree (fd);
-
- /* Apply flags to the function. */
- if (isctor)
- {
- DECL_STATIC_CONSTRUCTOR (decl) = 1;
- decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY);
- }
- else
- {
- DECL_STATIC_DESTRUCTOR (decl) = 1;
- decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
- }
-
- if (fd->linkage != LINK::c)
- {
- error_at (make_location_t (fd->loc),
- "must be %<extern(C)%> for %<pragma(%s)%>",
- isctor ? "crt_constructor" : "crt_destructor");
- }
-
- return 1;
- }
-
- return 0;
-}
-
/* Implements the visitor interface to lower all Declaration AST classes
emitted from the D Front-end to GCC trees.
All visit methods accept one parameter D, which holds the frontend AST
@@ -210,18 +157,18 @@ public:
void visit (Module *d)
{
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
build_module_tree (d);
- d->semanticRun = PASSobj;
+ d->semanticRun = PASS::obj;
}
/* Write the imported symbol to debug. */
void visit (Import *d)
{
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
/* Implements import declarations by telling the debug back-end we are
@@ -266,7 +213,7 @@ public:
false, false);
}
- d->semanticRun = PASSobj;
+ d->semanticRun = PASS::obj;
}
/* Expand any local variables found in tuples. */
@@ -312,18 +259,6 @@ public:
"pragma(%s) not implemented", d->ident->toChars ());
}
}
- else if (d->ident == Identifier::idPool ("crt_constructor")
- || d->ident == Identifier::idPool ("crt_destructor"))
- {
- /* Handle pragma(crt_constructor) and pragma(crt_destructor). Apply
- flag to indicate that the functions enclosed should run automatically
- at the beginning or end of execution. */
- bool isctor = (d->ident == Identifier::idPool ("crt_constructor"));
-
- if (apply_pragma_crt (d, isctor) > 1)
- error_at (make_location_t (d->loc),
- "can only apply to a single declaration");
- }
visit ((AttribDeclaration *) d);
}
@@ -422,7 +357,7 @@ public:
void visit (StructDeclaration *d)
{
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
if (d->type->ty == TY::Terror)
@@ -470,7 +405,7 @@ public:
if (d->xhash)
this->build_dsymbol (d->xhash);
- d->semanticRun = PASSobj;
+ d->semanticRun = PASS::obj;
}
/* Finish semantic analysis of functions in vtbl for class CD. */
@@ -537,7 +472,7 @@ public:
void visit (ClassDeclaration *d)
{
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
if (d->type->ty == TY::Terror)
@@ -603,7 +538,7 @@ public:
if (TYPE_NAME (ctype))
d_pushdecl (TYPE_NAME (ctype));
- d->semanticRun = PASSobj;
+ d->semanticRun = PASS::obj;
}
/* Write out compiler generated TypeInfo and vtables for the given interface
@@ -611,7 +546,7 @@ public:
void visit (InterfaceDeclaration *d)
{
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
if (d->type->ty == TY::Terror)
@@ -646,7 +581,7 @@ public:
if (TYPE_NAME (ctype))
d_pushdecl (TYPE_NAME (ctype));
- d->semanticRun = PASSobj;
+ d->semanticRun = PASS::obj;
}
/* Write out compiler generated TypeInfo and initializer for the given
@@ -654,7 +589,7 @@ public:
void visit (EnumDeclaration *d)
{
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
if (d->errors || d->type->ty == TY::Terror)
@@ -685,7 +620,7 @@ public:
if (TYPE_NAME (ctype))
d_pushdecl (TYPE_NAME (ctype));
- d->semanticRun = PASSobj;
+ d->semanticRun = PASS::obj;
}
/* Finish up a variable declaration and push it into the current scope.
@@ -693,7 +628,7 @@ public:
void visit (VarDeclaration *d)
{
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
if (d->type->ty == TY::Terror)
@@ -703,6 +638,21 @@ public:
return;
}
+ /* Variables of type `noreturn` are just placeholders, and evaluate to
+ `assert(0)` if ever read. */
+ if (d->type->isTypeNoreturn ())
+ {
+ if (!d->isDataseg () && !d->isMember ()
+ && d->_init && !d->_init->isVoidInitializer ())
+ {
+ Expression *e = d->type->defaultInitLiteral (d->loc);
+ tree exp = build_expr (e);
+ add_stmt (exp);
+ }
+
+ return;
+ }
+
if (d->aliassym)
{
this->build_dsymbol (d->toAlias ());
@@ -762,7 +712,7 @@ public:
/* Frontend should have already caught this. */
gcc_assert (!integer_zerop (size)
- || d->type->toBasetype ()->ty == TY::Tsarray);
+ || d->type->toBasetype ()->isTypeSArray ());
d_finish_decl (decl);
@@ -797,7 +747,7 @@ public:
}
}
- d->semanticRun = PASSobj;
+ d->semanticRun = PASS::obj;
}
/* Generate and compile a static TypeInfo declaration, but only if it is
@@ -805,7 +755,7 @@ public:
void visit (TypeInfoDeclaration *d)
{
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
if (speculative_type_p (d->tinfo))
@@ -814,7 +764,7 @@ public:
tree t = get_typeinfo_decl (d);
DECL_INITIAL (t) = layout_typeinfo (d);
d_finish_decl (t);
- d->semanticRun = PASSobj;
+ d->semanticRun = PASS::obj;
}
/* Finish up a function declaration and compile it all the way
@@ -823,7 +773,7 @@ public:
void visit (FuncDeclaration *d)
{
/* Already generated the function. */
- if (d->semanticRun >= PASSobj)
+ if (d->semanticRun >= PASS::obj)
return;
/* Don't emit any symbols from gcc.attribute module. */
@@ -861,7 +811,7 @@ public:
}
/* Ensure all semantic passes have run. */
- if (d->semanticRun < PASSsemantic3)
+ if (d->semanticRun < PASS::semantic3)
{
d->functionSemantic3 ();
Module::runDeferredSemantic3 ();
@@ -887,8 +837,8 @@ public:
message ("function %s", d->toPrettyChars ());
/* Start generating code for this function. */
- gcc_assert (d->semanticRun == PASSsemantic3done);
- d->semanticRun = PASSobj;
+ gcc_assert (d->semanticRun == PASS::semantic3done);
+ d->semanticRun = PASS::obj;
tree old_context = start_function (d);
@@ -927,12 +877,19 @@ public:
}
/* formal function parameters. */
- size_t n_parameters = d->parameters ? d->parameters->length : 0;
+ const size_t n_parameters = d->parameters ? d->parameters->length : 0;
for (size_t i = 0; i < n_parameters; i++)
{
VarDeclaration *param = (*d->parameters)[i];
+
parm_decl = get_symbol_decl (param);
+
+ /* Type `noreturn` is a terminator, as no other arguments can possibly
+ be evaluated after it. */
+ if (TREE_TYPE (parm_decl) == noreturn_type_node)
+ break;
+
/* Chain them in the correct order. */
param_list = chainon (param_list, parm_decl);
}
@@ -1136,9 +1093,9 @@ get_symbol_decl (Declaration *decl)
declaration_type (vd));
/* If any alignment was set on the declaration. */
- if (vd->alignment != STRUCTALIGN_DEFAULT)
+ if (!vd->alignment.isDefault ())
{
- SET_DECL_ALIGN (decl->csym, vd->alignment * BITS_PER_UNIT);
+ SET_DECL_ALIGN (decl->csym, vd->alignment.get () * BITS_PER_UNIT);
DECL_USER_ALIGN (decl->csym) = 1;
}
@@ -1321,6 +1278,20 @@ get_symbol_decl (Declaration *decl)
else if (fd->inlining == PINLINE::never)
DECL_UNINLINABLE (decl->csym) = 1;
+ /* In [pragma/crtctor], Annotates a function so it is run after the C
+ runtime library is initialized and before the D runtime library is
+ initialized. */
+ if (fd->isCrtCtorDtor == 1)
+ {
+ DECL_STATIC_CONSTRUCTOR (decl->csym) = 1;
+ decl_init_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
+ }
+ else if (fd->isCrtCtorDtor == 2)
+ {
+ DECL_STATIC_DESTRUCTOR (decl->csym) = 1;
+ decl_fini_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
+ }
+
/* Function was declared `naked'. */
if (fd->naked)
{
@@ -1342,7 +1313,7 @@ get_symbol_decl (Declaration *decl)
DECL_FINAL_P (decl->csym) = 1;
/* Function is of type `noreturn' or `typeof(*null)'. */
- if (fd->type->nextOf ()->ty == TY::Tnoreturn)
+ if (fd->type->nextOf ()->isTypeNoreturn ())
TREE_THIS_VOLATILE (decl->csym) = 1;
/* Check whether this function is expanded by the frontend. */
@@ -2246,9 +2217,9 @@ aggregate_initializer_decl (AggregateDeclaration *decl)
TREE_READONLY (sinit) = 1;
/* Honor struct alignment set by user. */
- if (sd && sd->alignment != STRUCTALIGN_DEFAULT)
+ if (sd && !sd->alignment.isDefault ())
{
- SET_DECL_ALIGN (sinit, sd->alignment * BITS_PER_UNIT);
+ SET_DECL_ALIGN (sinit, sd->alignment.get () * BITS_PER_UNIT);
DECL_USER_ALIGN (sinit) = true;
}
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 129050b..d23e1fe 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-b8384668f28741ad5884fc055a2bdb9c05fd95ec
+568496d5b6ed02d577dfa86f73c7bb4edee05813
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 720d256..3cb7e12 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -20,6 +20,7 @@ this license for that file.
|--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [dmd/](https://github.com/dlang/dmd/tree/master/src/dmd) | The dmd driver and front-end |
| [dmd/backend/](https://github.com/dlang/dmd/tree/master/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/common/](https://github.com/dlang/dmd/tree/master/src/dmd/common) | Code shared by the front-end and back-end |
| [dmd/root/](https://github.com/dlang/dmd/tree/master/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). |
DMD has a mostly flat directory structure, so this section aims to divide all source files into logical groups for easier navigation.
@@ -126,6 +127,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
| [optimize.d](https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d) | Do constant folding more generally |
| [dcast.d](https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d) | Implicit or explicit cast(), finding common types e.g. in `x ? a : b`, integral promotions |
| [impcnvtab.d](https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d) | Define an implicit conversion table for basic types |
+| [importc.d](https://github.com/dlang/dmd/blob/master/src/dmd/importc.d) | Helpers specific to ImportC |
| [sideeffect.d](https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings. |
**Compile Time Function Execution (CTFE)**
@@ -243,14 +245,14 @@ Note that these groups have no strict meaning, the category assignments are a bi
Note: many other utilities are in [dmd/root](https://github.com/dlang/dmd/tree/master/src/dmd/root).
-| File | Purpose |
-|-----------------------------------------------------------------------------|---------------------------------------------------|
-| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/env.d) | Modify environment variables |
-| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d) | Print error messages in color |
-| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/utf.d) | Encoding/decoding Unicode text |
-| [filecache.d](https://github.com/dlang/dmd/blob/master/src/dmd/filecache.d) | Keep file contents in memory |
-| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d) | Utility functions related to files and file paths |
-| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/complex.d) | A complex number type |
+| File | Purpose |
+|-----------------------------------------------------------------------------------|---------------------------------------------------|
+| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/env.d) | Modify environment variables |
+| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d) | Print error messages in color |
+| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/utf.d) | Encoding/decoding Unicode text |
+| [file_manager.d](https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d) | Keep file contents in memory |
+| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d) | Utility functions related to files and file paths |
+| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/complex.d) | A complex number type |
| File | Purpose |
|---------------------------------------------------------------------------------|---------------------------------------------------------------|
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 64ce79a..fa5940e 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.097.2
+v2.098.0
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index cff4b9f..1fe8e80 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -21,6 +21,7 @@ import dmd.aliasthis;
import dmd.apply;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.attrib;
import dmd.declaration;
import dmd.dscope;
import dmd.dstruct;
@@ -115,11 +116,12 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
AliasThis aliasthis; /// forward unresolved lookups to aliasthis
- DtorDeclarations dtors; /// Array of destructors
- DtorDeclaration dtor; /// aggregate destructor calling dtors and member constructors
- DtorDeclaration primaryDtor;/// non-deleting C++ destructor, same as dtor for D
+ DtorDeclarations userDtors; /// user-defined destructors (`~this()`) - mixins can yield multiple ones
+ DtorDeclaration aggrDtor; /// aggregate destructor calling userDtors and fieldDtor (and base class aggregate dtor for C++ classes)
+ DtorDeclaration dtor; /// the aggregate destructor exposed as `__xdtor` alias
+ /// (same as aggrDtor, except for C++ classes with virtual dtor on Windows)
DtorDeclaration tidtor; /// aggregate destructor used in TypeInfo (must have extern(D) ABI)
- FuncDeclaration fieldDtor; /// aggregate destructor for just the fields
+ DtorDeclaration fieldDtor; /// function destructing (non-inherited) fields
Expression getRTInfo; /// pointer to GC info generated by object.RTInfo(this)
@@ -177,7 +179,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
* Returns:
* false if failed to determine the size.
*/
- final bool determineSize(Loc loc)
+ final bool determineSize(const ref Loc loc)
{
//printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
@@ -331,7 +333,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
* false if any errors occur.
* Otherwise, returns true and the missing arguments will be pushed in elements[].
*/
- final bool fill(Loc loc, Expressions* elements, bool ctorinit)
+ final bool fill(const ref Loc loc, Expressions* elements, bool ctorinit)
{
//printf("AggregateDeclaration::fill() %s\n", toChars());
assert(sizeok == Sizeok.done);
@@ -482,45 +484,52 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
* Align sizes of 0, as we may not know array sizes yet.
* Params:
* alignment = struct alignment that is in effect
- * size = alignment requirement of field
+ * memalignsize = natural alignment of field
* poffset = pointer to offset to be aligned
*/
- extern (D) static void alignmember(structalign_t alignment, uint size, uint* poffset) pure nothrow @safe
+ extern (D) static void alignmember(structalign_t alignment, uint memalignsize, uint* poffset) pure nothrow @safe
{
- //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
- switch (alignment)
- {
- case cast(structalign_t)1:
- // No alignment
- break;
+ //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, *poffset);
+ uint alignvalue;
- case cast(structalign_t)STRUCTALIGN_DEFAULT:
+ if (alignment.isDefault())
+ {
// Alignment in Target::fieldalignsize must match what the
// corresponding C compiler's default alignment behavior is.
- assert(size > 0 && !(size & (size - 1)));
- *poffset = (*poffset + size - 1) & ~(size - 1);
- break;
-
- default:
+ alignvalue = memalignsize;
+ }
+ else if (alignment.isPack()) // #pragma pack semantics
+ {
+ alignvalue = alignment.get();
+ if (memalignsize < alignvalue)
+ alignvalue = memalignsize; // align to min(memalignsize, alignment)
+ }
+ else if (alignment.get() > 1)
+ {
// Align on alignment boundary, which must be a positive power of 2
- assert(alignment > 0 && !(alignment & (alignment - 1)));
- *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
- break;
+ alignvalue = alignment.get();
}
+ else
+ return;
+
+ assert(alignvalue > 0 && !(alignvalue & (alignvalue - 1)));
+ *poffset = (*poffset + alignvalue - 1) & ~(alignvalue - 1);
}
/****************************************
- * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
+ * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
+ * Params:
+ * nextoffset = location just past the end of the previous field in the aggregate.
+ * Updated to be just past the end of this field to be placed, i.e. the future nextoffset
+ * memsize = size of field
+ * memalignsize = natural alignment of field
+ * alignment = alignment in effect for this field
+ * paggsize = size of aggregate (updated)
+ * paggalignsize = alignment of aggregate (updated)
+ * isunion = the aggregate is a union
* Returns:
- * offset to place field at
+ * aligned offset to place field at
*
- * nextoffset: next location in aggregate
- * memsize: size of member
- * memalignsize: natural alignment of member
- * alignment: alignment in effect for this member
- * paggsize: size of aggregate (updated)
- * paggalignsize: alignment of aggregate (updated)
- * isunion: the aggregate is a union
*/
extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
@@ -528,7 +537,8 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
uint ofs = *nextoffset;
const uint actualAlignment =
- alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
+ alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get()
+ ? memalignsize : alignment.get();
// Ensure no overflow
bool overflow;
@@ -536,7 +546,10 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
addu(ofs, sz, overflow);
if (overflow) assert(0);
- alignmember(alignment, memalignsize, &ofs);
+ // Skip no-op for noreturn without custom aligment
+ if (memsize != 0 || !alignment.isDefault())
+ alignmember(alignment, memalignsize, &ofs);
+
uint memoffset = ofs;
ofs += memsize;
if (ofs > *paggsize)
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index f8d2f45..48e5f4a 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -105,11 +105,12 @@ public:
AliasThis *aliasthis; // forward unresolved lookups to aliasthis
- DtorDeclarations dtors; // Array of destructors
- DtorDeclaration *dtor; // aggregate destructor
- DtorDeclaration *primaryDtor; // non-deleting C++ destructor, same as dtor for D
+ DtorDeclarations userDtors; // user-defined destructors (`~this()`) - mixins can yield multiple ones
+ DtorDeclaration *aggrDtor; // aggregate destructor calling userDtors and fieldDtor (and base class aggregate dtor for C++ classes)
+ DtorDeclaration *dtor; // the aggregate destructor exposed as `__xdtor` alias
+ // (same as aggrDtor, except for C++ classes with virtual dtor on Windows)
DtorDeclaration *tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI)
- FuncDeclaration *fieldDtor; // aggregate destructor for just the fields
+ DtorDeclaration *fieldDtor; // function destructing (non-inherited) fields
Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this)
@@ -121,10 +122,10 @@ public:
virtual Scope *newScope(Scope *sc);
void setScope(Scope *sc);
size_t nonHiddenFields();
- bool determineSize(Loc loc);
+ bool determineSize(const Loc &loc);
virtual void finalizeSize() = 0;
d_uns64 size(const Loc &loc);
- bool fill(Loc loc, Expressions *elements, bool ctorinit);
+ bool fill(const Loc &loc, Expressions *elements, bool ctorinit);
Type *getType();
bool isDeprecated() const; // is aggregate deprecated?
void setDeprecated();
@@ -184,7 +185,7 @@ public:
// ABI-specific type(s) if the struct can be passed in registers
TypeTuple *argTypes;
- static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
+ static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject);
StructDeclaration *syntaxCopy(Dsymbol *s);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
const char *kind() const;
@@ -277,7 +278,7 @@ public:
ObjcClassDeclaration objc; // Data for a class declaration that is needed for the Objective-C integration
Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
- static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
+ static ClassDeclaration *create(const Loc &loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
const char *toPrettyChars(bool QualifyTypes = false);
ClassDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d
index 81e0d7e..e048cdc 100644
--- a/gcc/d/dmd/aliasthis.d
+++ b/gcc/d/dmd/aliasthis.d
@@ -72,17 +72,32 @@ extern (C++) final class AliasThis : Dsymbol
}
}
-Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false)
+/*************************************
+ * Find the `alias this` symbol of e's type.
+ * Params:
+ * sc = context
+ * e = expression forming the `this`
+ * gag = if true do not print errors, return null instead
+ * findOnly = don't do further processing like resolving properties,
+ * i.e. just return plain dotExp() result.
+ * Returns:
+ * Expression that is `e.aliasthis`
+ */
+Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
{
+ import dmd.typesem : dotExp;
for (AggregateDeclaration ad = isAggregate(e.type); ad;)
{
if (ad.aliasthis)
{
- uint olderrors = gag ? global.startGagging() : 0;
Loc loc = e.loc;
Type tthis = (e.op == TOK.type ? e.type : null);
- e = new DotIdExp(loc, e, ad.aliasthis.ident);
- e = e.expressionSemantic(sc);
+ const flags = DotExpFlag.noAliasThis | (gag ? DotExpFlag.gag : 0);
+ uint olderrors = gag ? global.startGagging() : 0;
+ e = dotExp(e.type, sc, e, ad.aliasthis.ident, flags);
+ if (!e || findOnly)
+ return gag && global.endGagging(olderrors) ? null : e;
+
if (tthis && ad.aliasthis.sym.needThis())
{
if (e.op == TOK.variable)
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index 66be73e..e2b3319 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -26,7 +26,7 @@ import dmd.globals;
import dmd.id;
import dmd.identifier;
import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.statement;
import dmd.tokens;
import dmd.visitor;
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index ae8f65b..0bf40ef 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -42,7 +42,7 @@ import dmd.id;
import dmd.identifier;
import dmd.mtype;
import dmd.objc; // for objc.addSymbols
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.target; // for target.systemLinkage
import dmd.tokens;
import dmd.visitor;
@@ -696,12 +696,9 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
{
Expressions* exps; /// Expression(s) yielding the desired alignment,
/// the largest value wins
- enum structalign_t UNKNOWN = 0; /// alignment not yet computed
- static assert(STRUCTALIGN_DEFAULT != UNKNOWN);
-
- /// the actual alignment, `UNKNOWN` until it's either set to the value of `ealign`
- /// or `STRUCTALIGN_DEFAULT` if `ealign` is null ( / an error ocurred)
- structalign_t salign = UNKNOWN;
+ /// the actual alignment is Unknown until it's either set to the value of `ealign`
+ /// or the default if `ealign` is null ( / an error ocurred)
+ structalign_t salign;
extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
@@ -709,8 +706,7 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
super(loc, null, decl);
if (exp)
{
- if (!exps)
- exps = new Expressions();
+ exps = new Expressions();
exps.push(exp);
}
}
@@ -721,6 +717,12 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
this.exps = exps;
}
+ extern (D) this(const ref Loc loc, structalign_t salign, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ this.salign = salign;
+ }
+
override AlignDeclaration syntaxCopy(Dsymbol s)
{
assert(!s);
@@ -1196,7 +1198,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
// expand static foreach
import dmd.statementsem: makeTupleForeach;
- Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion);
+ Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion).decl;
if (d) // process generated declarations
{
// Add members lazily.
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index 1fd9005..0ecd635 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -108,7 +108,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
return;
}
}
- if (s.exp.type.toBasetype().isTypeNoreturn())
+ if (s.exp.type && s.exp.type.toBasetype().isTypeNoreturn())
result = BE.halt;
if (canThrow(s.exp, func, mustNotThrow))
result |= BE.throw_;
@@ -146,7 +146,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
{
}
- else
+ else if (!func.getModule().isCFile)
{
const(char)* gototype = s.isCaseStatement() ? "case" : "default";
s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d
index b99f690..c4f84b1 100644
--- a/gcc/d/dmd/builtin.d
+++ b/gcc/d/dmd/builtin.d
@@ -30,4 +30,4 @@ public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd);
* Evaluate builtin function.
* Return result; NULL if cannot evaluate it.
*/
-public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments);
+public extern (C++) Expression eval_builtin(const ref Loc loc, FuncDeclaration fd, Expressions* arguments);
diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d
index 97adc5a..b168b4f 100644
--- a/gcc/d/dmd/chkformat.d
+++ b/gcc/d/dmd/chkformat.d
@@ -690,8 +690,8 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
return error();
while ('0' <= format[i] && format[i] <= '9')
{
- ++i;
- if (i == length)
+ ++i;
+ if (i == length)
return error();
}
}
@@ -720,8 +720,8 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
return error();
while ('0' <= format[i] && format[i] <= '9')
{
- ++i;
- if (i == length)
+ ++i;
+ if (i == length)
return error();
}
}
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index d300617..da66812 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -794,6 +794,19 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
if (!needToHash(sd))
return null;
+ /* The trouble is that the following code relies on .tupleof, but .tupleof
+ * is not allowed for C files. If we allow it for C files, then that turns on
+ * the other D properties, too, such as .dup which will then conflict with allowed
+ * field names.
+ * One way to fix it is to replace the following foreach and .tupleof with C
+ * statements and expressions.
+ * But, it's debatable whether C structs should even need toHash().
+ * Note that it would only be necessary if it has floating point fields.
+ * For now, we'll just not generate a toHash() for C files.
+ */
+ if (sc.flags & SCOPE.Cfile)
+ return null;
+
//printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars());
Loc declLoc; // loc is unnecessary so __xtoHash is never called directly
Loc loc; // internal code should have no loc to prevent coverage
@@ -831,31 +844,31 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
}
/*****************************************
- * Create inclusive destructor for struct/class by aggregating
- * all the destructors in dtors[] with the destructors for
+ * Create aggregate destructor for struct/class by aggregating
+ * all the destructors in userDtors[] with the destructors for
* all the members.
+ * Sets ad's fieldDtor, aggrDtor, dtor and tidtor fields.
* Params:
* ad = struct or class to build destructor for
* sc = context
- * Returns:
- * generated function, null if none needed
* Note:
* Close similarity with StructDeclaration::buildPostBlit(),
* and the ordering changes (runs backward instead of forwards).
*/
-DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
+void buildDtors(AggregateDeclaration ad, Scope* sc)
{
//printf("AggregateDeclaration::buildDtor() %s\n", ad.toChars());
if (ad.isUnionDeclaration())
- return null; // unions don't have destructors
+ return; // unions don't have destructors
StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
- Loc declLoc = ad.dtors.dim ? ad.dtors[0].loc : ad.loc;
+ Loc declLoc = ad.userDtors.dim ? ad.userDtors[0].loc : ad.loc;
Loc loc; // internal code should have no loc to prevent coverage
FuncDeclaration xdtor_fwd = null;
- // if the dtor is an extern(C++) prototype, then we expect it performs a full-destruction; we don't need to build a full-dtor
- const bool dtorIsCppPrototype = ad.dtors.dim == 1 && ad.dtors[0].linkage == LINK.cpp && !ad.dtors[0].fbody;
+ // Build the field destructor (`ad.fieldDtor`), if needed.
+ // If the user dtor is an extern(C++) prototype, then we expect it performs a full-destruction and skip building.
+ const bool dtorIsCppPrototype = ad.userDtors.dim && ad.userDtors[0].linkage == LINK.cpp && !ad.userDtors[0].fbody;
if (!dtorIsCppPrototype)
{
Expression e = null;
@@ -936,36 +949,6 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
e = Expression.combine(ex, e); // combine in reverse order
}
- /* extern(C++) destructors call into super to destruct the full hierarchy
- */
- ClassDeclaration cldec = ad.isClassDeclaration();
- if (cldec && cldec.classKind == ClassKind.cpp && cldec.baseClass && cldec.baseClass.primaryDtor)
- {
- // WAIT BUT: do I need to run `cldec.baseClass.dtor` semantic? would it have been run before?
- cldec.baseClass.dtor.functionSemantic();
-
- stc = mergeFuncAttrs(stc, cldec.baseClass.primaryDtor);
- if (!(stc & STC.disable))
- {
- // super.__xdtor()
-
- Expression ex = new SuperExp(loc);
-
- // This is a hack so we can call destructors on const/immutable objects.
- // Do it as a type 'paint'.
- ex = new CastExp(loc, ex, cldec.baseClass.type.mutableOf());
- if (stc & STC.safe)
- stc = (stc & ~STC.safe) | STC.trusted;
-
- ex = new DotVarExp(loc, ex, cldec.baseClass.primaryDtor, false);
- ex = new CallExp(loc, ex);
-
- e = Expression.combine(e, ex); // super dtor last
- }
- }
-
- /* Build our own "destructor" which executes e
- */
if (e || (stc & STC.disable))
{
//printf("Building __fieldDtor(), %s\n", e.toChars());
@@ -973,29 +956,45 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
dd.generated = true;
dd.storage_class |= STC.inference;
dd.fbody = new ExpStatement(loc, e);
- ad.dtors.shift(dd);
ad.members.push(dd);
dd.dsymbolSemantic(sc);
ad.fieldDtor = dd;
}
}
- DtorDeclaration xdtor = null;
- switch (ad.dtors.dim)
+ // Generate list of dtors to call in that order
+ DtorDeclarations dtors;
+ foreach_reverse (userDtor; ad.userDtors[])
+ dtors.push(userDtor);
+ if (ad.fieldDtor)
+ dtors.push(ad.fieldDtor);
+ if (!dtorIsCppPrototype)
+ {
+ // extern(C++) destructors call into super to destruct the full hierarchy
+ ClassDeclaration cldec = ad.isClassDeclaration();
+ if (cldec && cldec.classKind == ClassKind.cpp && cldec.baseClass && cldec.baseClass.aggrDtor)
+ dtors.push(cldec.baseClass.aggrDtor);
+ }
+
+ // Set/build `ad.aggrDtor`
+ switch (dtors.dim)
{
case 0:
break;
case 1:
- xdtor = ad.dtors[0];
+ // Use the single existing dtor directly as aggregate dtor.
+ // Note that this might be `cldec.baseClass.aggrDtor`.
+ ad.aggrDtor = dtors[0];
break;
default:
+ // Build the aggregate destructor, calling all dtors in order.
assert(!dtorIsCppPrototype);
Expression e = null;
e = null;
stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
- foreach (FuncDeclaration fd; ad.dtors)
+ foreach (FuncDeclaration fd; dtors)
{
stc = mergeFuncAttrs(stc, fd);
if (stc & STC.disable)
@@ -1005,8 +1004,9 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
}
Expression ex = new ThisExp(loc);
ex = new DotVarExp(loc, ex, fd, false);
- ex = new CallExp(loc, ex);
- e = Expression.combine(ex, e);
+ CallExp ce = new CallExp(loc, ex);
+ ce.directcall = true;
+ e = Expression.combine(e, ce);
}
auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor);
dd.generated = true;
@@ -1014,19 +1014,20 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
dd.fbody = new ExpStatement(loc, e);
ad.members.push(dd);
dd.dsymbolSemantic(sc);
- xdtor = dd;
+ ad.aggrDtor = dd;
break;
}
- ad.primaryDtor = xdtor;
-
- if (xdtor && xdtor.linkage == LINK.cpp && !target.cpp.twoDtorInVtable)
- xdtor = buildWindowsCppDtor(ad, xdtor, sc);
+ // Set/build `ad.dtor`.
+ // On Windows, the dtor in the vtable is a shim with different signature.
+ ad.dtor = (ad.aggrDtor && ad.aggrDtor.linkage == LINK.cpp && !target.cpp.twoDtorInVtable)
+ ? buildWindowsCppDtor(ad, ad.aggrDtor, sc)
+ : ad.aggrDtor;
- // Add an __xdtor alias to make the inclusive dtor accessible
- if (xdtor)
+ // Add an __xdtor alias to make `ad.dtor` accessible
+ if (ad.dtor)
{
- auto _alias = new AliasDeclaration(Loc.initial, Id.__xdtor, xdtor);
+ auto _alias = new AliasDeclaration(Loc.initial, Id.__xdtor, ad.dtor);
_alias.dsymbolSemantic(sc);
ad.members.push(_alias);
if (xdtor_fwd)
@@ -1035,7 +1036,8 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
_alias.addMember(sc, ad); // add to symbol table
}
- return xdtor;
+ // Set/build `ad.tidtor`
+ ad.tidtor = buildExternDDtor(ad, sc);
}
/**
@@ -1069,17 +1071,16 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, dtor.storage_class);
auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.cppdtor);
func.type = ftype;
- if (dtor.fbody)
- {
- const loc = dtor.loc;
- auto stmts = new Statements;
- auto call = new CallExp(loc, dtor, null);
- call.directcall = true;
- stmts.push(new ExpStatement(loc, call));
- stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
- func.fbody = new CompoundStatement(loc, stmts);
- func.generated = true;
- }
+
+ // Always generate the function with body, because it is not exported from DLLs.
+ const loc = dtor.loc;
+ auto stmts = new Statements;
+ auto call = new CallExp(loc, dtor, null);
+ call.directcall = true;
+ stmts.push(new ExpStatement(loc, call));
+ stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
+ func.fbody = new CompoundStatement(loc, stmts);
+ func.generated = true;
auto sc2 = sc.push();
sc2.stc &= ~STC.static_; // not a static destructor
@@ -1094,7 +1095,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
}
/**
- * build a shim function around the compound dtor that translates
+ * build a shim function around the aggregate dtor that translates
* a C++ destructor to a destructor with extern(D) calling convention
*
* Params:
@@ -1104,9 +1105,9 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
* Returns:
* the shim destructor, semantically analyzed and added to the class as a member
*/
-DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
+private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
{
- auto dtor = ad.primaryDtor;
+ auto dtor = ad.aggrDtor;
if (!dtor)
return null;
diff --git a/gcc/d/dmd/common/README.md b/gcc/d/dmd/common/README.md
new file mode 100644
index 0000000..a9b65c3
--- /dev/null
+++ b/gcc/d/dmd/common/README.md
@@ -0,0 +1,7 @@
+# Table of contents
+
+| File | Purpose |
+|------------------------------------------------------------------------------------|-----------------------------------------------------------------|
+| [file.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d) | Functions and objects dedicated to file I/O and management |
+| [outbuffer.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data |
+| [string.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d) | Common string functions including filename manipulation |
diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d
new file mode 100644
index 0000000..b8cde37
--- /dev/null
+++ b/gcc/d/dmd/common/file.d
@@ -0,0 +1,576 @@
+/**
+ * File utilities.
+ *
+ * Functions and objects dedicated to file I/O and management. TODO: Move here artifacts
+ * from places such as root/ so both the frontend and the backend have access to them.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d, common/_file.d)
+ * Documentation: https://dlang.org/phobos/dmd_common_file.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/file.d
+ */
+
+module dmd.common.file;
+
+import core.stdc.errno : errno;
+import core.stdc.stdio : fprintf, remove, rename, stderr;
+import core.stdc.stdlib : exit;
+import core.stdc.string : strerror;
+import core.sys.windows.winbase;
+import core.sys.windows.winnt;
+import core.sys.posix.fcntl;
+import core.sys.posix.unistd;
+
+import dmd.common.string;
+
+/**
+Encapsulated management of a memory-mapped file.
+
+Params:
+Datum = the mapped data type: Use a POD of size 1 for read/write mapping
+and a `const` version thereof for read-only mapping. Other primitive types
+should work, but have not been yet tested.
+*/
+struct FileMapping(Datum)
+{
+ static assert(__traits(isPOD, Datum) && Datum.sizeof == 1,
+ "Not tested with other data types yet. Add new types with care.");
+
+ version(Posix) enum invalidHandle = -1;
+ else version(Windows) enum invalidHandle = INVALID_HANDLE_VALUE;
+
+ // state {
+ /// Handle of underlying file
+ private auto handle = invalidHandle;
+ /// File mapping object needed on Windows
+ version(Windows) private HANDLE fileMappingObject = invalidHandle;
+ /// Memory-mapped array
+ private Datum[] data;
+ /// Name of underlying file, zero-terminated
+ private const(char)* name;
+ // state }
+
+ /**
+ Open `filename` and map it in memory. If `Datum` is `const`, opens for
+ read-only and maps the content in memory; no error is issued if the file
+ does not exist. This makes it easy to treat a non-existing file as empty.
+
+ If `Datum` is mutable, opens for read/write (creates file if it does not
+ exist) and fails fatally on any error.
+
+ Due to quirks in `mmap`, if the file is empty, `handle` is valid but `data`
+ is `null`. This state is valid and accounted for.
+
+ Params:
+ filename = the name of the file to be mapped in memory
+ */
+ this(const char* filename)
+ {
+ version (Posix)
+ {
+ import core.sys.posix.sys.mman;
+ import core.sys.posix.fcntl : open, O_CREAT, O_RDONLY, O_RDWR, S_IRGRP, S_IROTH, S_IRUSR, S_IWUSR;
+
+ handle = open(filename, is(Datum == const) ? O_RDONLY : (O_CREAT | O_RDWR),
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (handle == invalidHandle)
+ {
+ static if (is(Datum == const))
+ {
+ // No error, nonexisting file in read mode behaves like an empty file.
+ return;
+ }
+ else
+ {
+ fprintf(stderr, "open(\"%s\") failed: %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ }
+
+ const size = fileSize(handle);
+
+ if (size > 0 && size != ulong.max && size <= size_t.max)
+ {
+ auto p = mmap(null, cast(size_t) size, is(Datum == const) ? PROT_READ : PROT_WRITE, MAP_SHARED, handle, 0);
+ if (p == MAP_FAILED)
+ {
+ fprintf(stderr, "mmap(null, %zu) for \"%s\" failed: %s\n", cast(size_t) size, filename, strerror(errno));
+ exit(1);
+ }
+ // The cast below will always work because it's gated by the `size <= size_t.max` condition.
+ data = cast(Datum[]) p[0 .. cast(size_t) size];
+ }
+ }
+ else version(Windows)
+ {
+ static if (is(Datum == const))
+ {
+ enum createFileMode = GENERIC_READ;
+ enum openFlags = OPEN_EXISTING;
+ }
+ else
+ {
+ enum createFileMode = GENERIC_READ | GENERIC_WRITE;
+ enum openFlags = CREATE_ALWAYS;
+ }
+
+ handle = filename.asDString.extendedPathThen!(p => CreateFileW(p.ptr, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null));
+ if (handle == invalidHandle)
+ {
+ static if (is(Datum == const))
+ {
+ return;
+ }
+ else
+ {
+ fprintf(stderr, "CreateFileW() failed for \"%s\": %d\n", filename, GetLastError());
+ exit(1);
+ }
+ }
+ createMapping(filename, fileSize(handle));
+ }
+ else static assert(0);
+
+ // Save the name for later. Technically there's no need: on Linux one can use readlink on /proc/self/fd/NNN.
+ // On BSD and OSX one can use fcntl with F_GETPATH. On Windows one can use GetFileInformationByHandleEx.
+ // But just saving the name is simplest, fastest, and most portable...
+ import core.stdc.string : strlen;
+ import core.stdc.stdlib : malloc;
+ import core.stdc.string : memcpy;
+ auto totalNameLength = filename.strlen() + 1;
+ name = cast(char*) memcpy(malloc(totalNameLength), filename, totalNameLength);
+ name || assert(0, "FileMapping: Out of memory.");
+ }
+
+ /**
+ Common code factored opportunistically. Windows only. Assumes `handle` is
+ already pointing to an opened file. Initializes the `fileMappingObject`
+ and `data` members.
+
+ Params:
+ filename = the file to be mapped
+ size = the size of the file in bytes
+ */
+ version(Windows) private void createMapping(const char* filename, ulong size)
+ {
+ assert(size <= size_t.max || size == ulong.max);
+ assert(handle != invalidHandle);
+ assert(data is null);
+ assert(fileMappingObject == invalidHandle);
+
+ if (size == 0 || size == ulong.max)
+ return;
+
+ static if (is(Datum == const))
+ {
+ enum fileMappingFlags = PAGE_READONLY;
+ enum mapViewFlags = FILE_MAP_READ;
+ }
+ else
+ {
+ enum fileMappingFlags = PAGE_READWRITE;
+ enum mapViewFlags = FILE_MAP_WRITE;
+ }
+
+ fileMappingObject = CreateFileMappingW(handle, null, fileMappingFlags, 0, 0, null);
+ if (!fileMappingObject)
+ {
+ fprintf(stderr, "CreateFileMappingW(%p) failed for %llu bytes of \"%s\": %d\n",
+ handle, size, filename, GetLastError());
+ fileMappingObject = invalidHandle; // by convention always use invalidHandle, not null
+ exit(1);
+ }
+ auto p = MapViewOfFile(fileMappingObject, mapViewFlags, 0, 0, 0);
+ if (!p)
+ {
+ fprintf(stderr, "MapViewOfFile() failed for \"%s\": %d\n", filename, GetLastError());
+ exit(1);
+ }
+ data = cast(Datum[]) p[0 .. cast(size_t) size];
+ }
+
+ // Not copyable or assignable (for now).
+ @disable this(const FileMapping!Datum rhs);
+ @disable void opAssign(const ref FileMapping!Datum rhs);
+
+ /**
+ Frees resources associated with this mapping. However, it does not deallocate the name.
+ */
+ ~this() pure nothrow
+ {
+ if (!active)
+ return;
+ fakePure({
+ version (Posix)
+ {
+ import core.sys.posix.sys.mman : munmap;
+ import core.sys.posix.unistd : close;
+
+ // Cannot call fprintf from inside a destructor, so exiting silently.
+
+ if (data.ptr && munmap(cast(void*) data.ptr, data.length) != 0)
+ {
+ exit(1);
+ }
+ data = null;
+ if (handle != invalidHandle && close(handle) != 0)
+ {
+ exit(1);
+ }
+ handle = invalidHandle;
+ }
+ else version(Windows)
+ {
+ if (data.ptr !is null && UnmapViewOfFile(cast(void*) data.ptr) == 0)
+ {
+ exit(1);
+ }
+ data = null;
+ if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
+ {
+ exit(1);
+ }
+ fileMappingObject = invalidHandle;
+ if (handle != invalidHandle && CloseHandle(handle) == 0)
+ {
+ exit(1);
+ }
+ handle = invalidHandle;
+ }
+ else static assert(0);
+ });
+ }
+
+ /**
+ Returns the zero-terminated file name associated with the mapping. Can NOT
+ be saved beyond the lifetime of `this`.
+ */
+ private const(char)* filename() const pure @nogc @safe nothrow { return name; }
+
+ /**
+ Frees resources associated with this mapping. However, it does not deallocate the name.
+ Reinitializes `this` as a fresh object that can be reused.
+ */
+ void close()
+ {
+ __dtor();
+ handle = invalidHandle;
+ version(Windows) fileMappingObject = invalidHandle;
+ data = null;
+ name = null;
+ }
+
+ /**
+ Deletes the underlying file and frees all resources associated.
+ Reinitializes `this` as a fresh object that can be reused.
+
+ This function does not abort if the file cannot be deleted, but does print
+ a message on `stderr` and returns `false` to the caller. The underlying
+ rationale is to give the caller the option to continue execution if
+ deleting the file is not important.
+
+ Returns: `true` iff the file was successfully deleted. If the file was not
+ deleted, prints a message to `stderr` and returns `false`.
+ */
+ static if (!is(Datum == const))
+ bool discard()
+ {
+ // Truncate file to zero so unflushed buffers are not flushed unnecessarily.
+ resize(0);
+ auto deleteme = name;
+ close();
+ // In-memory resource freed, now get rid of the underlying temp file.
+ version(Posix)
+ {
+ import core.sys.posix.unistd : unlink;
+ if (unlink(deleteme) != 0)
+ {
+ fprintf(stderr, "unlink(\"%s\") failed: %s\n", filename, strerror(errno));
+ return false;
+ }
+ }
+ else version(Windows)
+ {
+ import core.sys.windows.winbase;
+ if (deleteme.asDString.extendedPathThen!(p => DeleteFileW(p.ptr)) == 0)
+ {
+ fprintf(stderr, "DeleteFileW error %d\n", GetLastError());
+ return false;
+ }
+ }
+ else static assert(0);
+ return true;
+ }
+
+ /**
+ Queries whether `this` is currently associated with a file.
+
+ Returns: `true` iff there is an active mapping.
+ */
+ bool active() const pure @nogc nothrow
+ {
+ return handle !is invalidHandle;
+ }
+
+ /**
+ Queries the length of the file associated with this mapping. If not
+ active, returns 0.
+
+ Returns: the length of the file, or 0 if no file associated.
+ */
+ size_t length() const pure @nogc @safe nothrow { return data.length; }
+
+ /**
+ Get a slice to the contents of the entire file.
+
+ Returns: the contents of the file. If not active, returns the `null` slice.
+ */
+ auto opSlice() pure @nogc @safe nothrow { return data; }
+
+ /**
+ Resizes the file and mapping to the specified `size`.
+
+ Params:
+ size = new length requested
+ */
+ static if (!is(Datum == const))
+ void resize(size_t size) pure
+ {
+ assert(handle != invalidHandle);
+ fakePure({
+ version(Posix)
+ {
+ import core.sys.posix.unistd : ftruncate;
+ import core.sys.posix.sys.mman;
+
+ if (data.length)
+ {
+ assert(data.ptr, "Corrupt memory mapping");
+ // assert(0) here because it would indicate an internal error
+ munmap(cast(void*) data.ptr, data.length) == 0 || assert(0);
+ data = null;
+ }
+ if (ftruncate(handle, size) != 0)
+ {
+ fprintf(stderr, "ftruncate() failed for \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ if (size > 0)
+ {
+ auto p = mmap(null, size, PROT_WRITE, MAP_SHARED, handle, 0);
+ if (cast(ssize_t) p == -1)
+ {
+ fprintf(stderr, "mmap() failed for \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ data = cast(Datum[]) p[0 .. size];
+ }
+ }
+ else version(Windows)
+ {
+ // Per documentation, must unmap first.
+ if (data.length > 0 && UnmapViewOfFile(cast(void*) data.ptr) == 0)
+ {
+ fprintf(stderr, "UnmapViewOfFile(%p) failed for memory mapping of \"%s\": %d\n",
+ data.ptr, filename, GetLastError());
+ exit(1);
+ }
+ data = null;
+ if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
+ {
+ fprintf(stderr, "CloseHandle() failed for memory mapping of \"%s\": %d\n", filename, GetLastError());
+ exit(1);
+ }
+ fileMappingObject = invalidHandle;
+ LARGE_INTEGER biggie;
+ biggie.QuadPart = size;
+ if (SetFilePointerEx(handle, biggie, null, FILE_BEGIN) == 0 || SetEndOfFile(handle) == 0)
+ {
+ fprintf(stderr, "SetFilePointer() failed for \"%s\": %d\n", filename, GetLastError());
+ exit(1);
+ }
+ createMapping(name, size);
+ }
+ else static assert(0);
+ });
+ }
+
+ /**
+ Unconditionally and destructively moves the underlying file to `filename`.
+ If the operation succeeds, returns true. Upon failure, prints a message to
+ `stderr` and returns `false`. In all cases it closes the underlying file.
+
+ Params: filename = zero-terminated name of the file to move to.
+
+ Returns: `true` iff the operation was successful.
+ */
+ bool moveToFile(const char* filename)
+ {
+ assert(name !is null);
+
+ // Fetch the name and then set it to `null` so it doesn't get deallocated
+ auto oldname = name;
+ import core.stdc.stdlib;
+ scope(exit) free(cast(void*) oldname);
+ name = null;
+ close();
+
+ // Rename the underlying file to the target, no copy necessary.
+ version(Posix)
+ {
+ if (.rename(oldname, filename) != 0)
+ {
+ fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", oldname, filename, strerror(errno));
+ return false;
+ }
+ }
+ else version(Windows)
+ {
+ import core.sys.windows.winbase;
+ auto r = oldname.asDString.extendedPathThen!(
+ p1 => filename.asDString.extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING))
+ );
+ if (r == 0)
+ {
+ fprintf(stderr, "MoveFileExW(\"%s\", \"%s\") failed: %d\n", oldname, filename, GetLastError());
+ return false;
+ }
+ }
+ else static assert(0);
+ return true;
+ }
+}
+
+/// Write a file, returning `true` on success.
+extern(D) static bool writeFile(const(char)* name, const void[] data) nothrow
+{
+ version (Posix)
+ {
+ int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
+ if (fd == -1)
+ goto err;
+ if (.write(fd, data.ptr, data.length) != data.length)
+ goto err2;
+ if (close(fd) == -1)
+ goto err;
+ return true;
+ err2:
+ close(fd);
+ .remove(name);
+ err:
+ return false;
+ }
+ else version (Windows)
+ {
+ DWORD numwritten; // here because of the gotos
+ const nameStr = name.asDString;
+ // work around Windows file path length limitation
+ // (see documentation for extendedPathThen).
+ HANDLE h = nameStr.extendedPathThen!
+ (p => CreateFileW(p.ptr,
+ GENERIC_WRITE,
+ 0,
+ null,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ null));
+ if (h == INVALID_HANDLE_VALUE)
+ goto err;
+
+ if (WriteFile(h, data.ptr, cast(DWORD)data.length, &numwritten, null) != TRUE)
+ goto err2;
+ if (numwritten != data.length)
+ goto err2;
+ if (!CloseHandle(h))
+ goto err;
+ return true;
+ err2:
+ CloseHandle(h);
+ nameStr.extendedPathThen!(p => DeleteFileW(p.ptr));
+ err:
+ return false;
+ }
+ else
+ {
+ static assert(0);
+ }
+}
+
+/// Touch a file to current date
+bool touchFile(const char* namez)
+{
+ version (Windows)
+ {
+ FILETIME ft = void;
+ SYSTEMTIME st = void;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+
+ import core.stdc.string : strlen;
+
+ // get handle to file
+ HANDLE h = namez[0 .. namez.strlen()].extendedPathThen!(p => CreateFile(p.ptr,
+ FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ null, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, null));
+ if (h == INVALID_HANDLE_VALUE)
+ return false;
+
+ const f = SetFileTime(h, null, null, &ft); // set last write time
+
+ if (!CloseHandle(h))
+ return false;
+
+ return f != 0;
+ }
+ else version (Posix)
+ {
+ import core.sys.posix.utime;
+ return utime(namez, null) == 0;
+ }
+ else
+ static assert(0);
+}
+
+// Feel free to make these public if used elsewhere.
+/**
+Size of a file in bytes.
+Params: fd = file handle
+Returns: file size in bytes, or `ulong.max` on any error.
+*/
+version (Posix)
+private ulong fileSize(int fd)
+{
+ import core.sys.posix.sys.stat;
+ stat_t buf;
+ if (fstat(fd, &buf) == 0)
+ return buf.st_size;
+ return ulong.max;
+}
+
+/// Ditto
+version (Windows)
+private ulong fileSize(HANDLE fd)
+{
+ ulong result;
+ if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
+ return result;
+ return ulong.max;
+}
+
+/**
+Runs a non-pure function or delegate as pure code. Use with caution.
+
+Params:
+fun = the delegate to run, usually inlined: `fakePure({ ... });`
+
+Returns: whatever `fun` returns.
+*/
+private auto ref fakePure(F)(scope F fun) pure
+{
+ mixin("alias PureFun = " ~ F.stringof ~ " pure;");
+ return (cast(PureFun) fun)();
+}
diff --git a/gcc/d/dmd/root/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
index e756917..c5a8437 100644
--- a/gcc/d/dmd/root/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -9,14 +9,21 @@
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/outbuffer.d
*/
-module dmd.root.outbuffer;
+module dmd.common.outbuffer;
import core.stdc.stdarg;
import core.stdc.stdio;
import core.stdc.string;
-import dmd.root.rmem;
-import dmd.root.rootobject;
-import dmd.root.string;
+import core.stdc.stdlib;
+
+// In theory these functions should also restore errno, but we don't care because
+// we abort application on error anyway.
+extern (C) private pure @system @nogc nothrow
+{
+ pragma(mangle, "malloc") void* pureMalloc(size_t);
+ pragma(mangle, "realloc") void* pureRealloc(void* ptr, size_t size);
+ pragma(mangle, "free") void pureFree(void* ptr);
+}
debug
{
@@ -29,7 +36,7 @@ a contiguous array or a memory-mapped file.
*/
struct OutBuffer
{
- import dmd.root.file : FileMapping;
+ import dmd.common.file : FileMapping, touchFile, writeFile;
// IMPORTANT: PLEASE KEEP STATE AND DESTRUCTOR IN SYNC WITH DEFINITION IN ./outbuffer.h.
// state {
@@ -48,6 +55,14 @@ struct OutBuffer
// state }
/**
+ Construct given size.
+ */
+ this(size_t initialSize) nothrow
+ {
+ reserve(initialSize);
+ }
+
+ /**
Construct from filename. Will map the file into memory (or create it anew
if necessary) and start writing at the beginning of it.
@@ -56,14 +71,36 @@ struct OutBuffer
*/
@trusted this(const(char)* filename)
{
- fileMapping = new FileMapping!ubyte(filename);
+ FileMapping!ubyte model;
+ fileMapping = cast(FileMapping!ubyte*) malloc(model.sizeof);
+ memcpy(fileMapping, &model, model.sizeof);
+ fileMapping.__ctor(filename);
+ //fileMapping = new FileMapping!ubyte(filename);
data = (*fileMapping)[];
}
/**
+ Frees resources associated.
+ */
+ extern (C++) void dtor() nothrow @trusted
+ {
+ if (fileMapping)
+ {
+ if (fileMapping.active)
+ fileMapping.close();
+ fileMapping = null;
+ }
+ else
+ {
+ debug (stomp) memset(data.ptr, 0xFF, data.length);
+ free(data.ptr);
+ }
+ }
+
+ /**
Frees resources associated automatically.
*/
- extern (C++) ~this() pure nothrow
+ extern (C++) ~this() pure nothrow @trusted
{
if (fileMapping)
{
@@ -74,10 +111,23 @@ struct OutBuffer
else
{
debug (stomp) memset(data.ptr, 0xFF, data.length);
- mem.xfree(data.ptr);
+ pureFree(data.ptr);
}
}
+ /// For porting with ease from dmd.backend.outbuf.Outbuffer
+ ubyte* buf() nothrow {
+ return data.ptr;
+ }
+
+ /// For porting with ease from dmd.backend.outbuf.Outbuffer
+ ubyte** bufptr() nothrow {
+ static struct Array { size_t length; ubyte* ptr; }
+ auto a = cast(Array*) &data;
+ assert(a.length == data.length && a.ptr == data.ptr);
+ return &a.ptr;
+ }
+
extern (C++) size_t length() const pure @nogc @safe nothrow { return offset; }
/**********************
@@ -109,7 +159,7 @@ struct OutBuffer
else
{
debug (stomp) memset(data.ptr, 0xFF, data.length);
- mem.xfree(extractData());
+ pureFree(extractData());
}
}
@@ -141,17 +191,18 @@ struct OutBuffer
{
debug (stomp)
{
- auto p = cast(ubyte*)mem.xmalloc(size);
+ auto p = cast(ubyte*) pureMalloc(size);
+ p || assert(0, "OutBuffer: out of memory.");
memcpy(p, data.ptr, offset);
memset(data.ptr, 0xFF, data.length); // stomp old location
- mem.xfree(data.ptr);
+ pureFree(data.ptr);
memset(p + offset, 0xff, size - offset); // stomp unused data
}
else
{
- auto p = cast(ubyte*)mem.xrealloc(data.ptr, size);
- if (mem.isGCEnabled) // clear currently unused data to avoid false pointers
- memset(p + offset + nbytes, 0xff, size - offset - nbytes);
+ auto p = cast(ubyte*) pureRealloc(data.ptr, size);
+ p || assert(0, "OutBuffer: out of memory.");
+ memset(p + offset + nbytes, 0xff, size - offset - nbytes);
}
data = p[0 .. size];
}
@@ -164,7 +215,7 @@ struct OutBuffer
*/
extern (C++) void setsize(size_t size) pure nothrow @nogc @safe
{
- assert(size <= offset);
+ assert(size <= data.length);
offset = size;
}
@@ -185,6 +236,14 @@ struct OutBuffer
notlinehead = true;
}
+ // Write an array to the buffer, no reserve check
+ @trusted nothrow
+ void writen(const void *b, size_t len)
+ {
+ memcpy(data.ptr + offset, b, len);
+ offset += len;
+ }
+
extern (C++) void write(const(void)* data, size_t nbytes) pure nothrow
{
write(data[0 .. nbytes]);
@@ -199,27 +258,90 @@ struct OutBuffer
offset += buf.length;
}
- extern (C++) void writestring(const(char)* string) pure nothrow
+ /**
+ * Writes a 16 bit value, no reserve check.
+ */
+ @trusted nothrow
+ void write16n(int v)
{
- write(string.toDString);
+ auto x = cast(ushort) v;
+ data[offset] = x & 0x00FF;
+ data[offset + 1] = x >> 8u;
+ offset += 2;
}
+ /**
+ * Writes a 16 bit value.
+ */
+ void write16(int v) nothrow
+ {
+ auto u = cast(ushort) v;
+ write(&u, u.sizeof);
+ }
+
+ /**
+ * Writes a 32 bit int.
+ */
+ void write32(int v) nothrow @trusted
+ {
+ write(&v, v.sizeof);
+ }
+
+ /**
+ * Writes a 64 bit int.
+ */
+ @trusted void write64(long v) nothrow
+ {
+ write(&v, v.sizeof);
+ }
+
+ /// NOT zero-terminated
+ extern (C++) void writestring(const(char)* s) pure nothrow
+ {
+ if (!s)
+ return;
+ import core.stdc.string : strlen;
+ write(s[0 .. strlen(s)]);
+ }
+
+ /// ditto
void writestring(const(char)[] s) pure nothrow
{
write(s);
}
+ /// ditto
void writestring(string s) pure nothrow
{
write(s);
}
+ /// NOT zero-terminated, followed by newline
void writestringln(const(char)[] s) pure nothrow
{
writestring(s);
writenl();
}
+ // Zero-terminated
+ void writeString(const(char)* s) pure nothrow @trusted
+ {
+ write(s[0 .. strlen(s)+1]);
+ }
+
+ /// ditto
+ void writeString(const(char)[] s) pure nothrow
+ {
+ write(s);
+ writeByte(0);
+ }
+
+ /// ditto
+ void writeString(string s) pure nothrow
+ {
+ writeString(cast(const(char)[])(s));
+ }
+
extern (C++) void prependstring(const(char)* string) pure nothrow
{
size_t len = strlen(string);
@@ -244,6 +366,38 @@ struct OutBuffer
notlinehead = false;
}
+ // Write n zeros; return pointer to start of zeros
+ @trusted
+ void *writezeros(size_t n) nothrow
+ {
+ reserve(n);
+ auto result = memset(data.ptr + offset, 0, n);
+ offset += n;
+ return result;
+ }
+
+ // Position buffer to accept the specified number of bytes at offset
+ @trusted
+ void position(size_t where, size_t nbytes) nothrow
+ {
+ if (where + nbytes > data.length)
+ {
+ reserve(where + nbytes - offset);
+ }
+ offset = where;
+
+ debug assert(offset + nbytes <= data.length);
+ }
+
+ /**
+ * Writes an 8 bit byte, no reserve check.
+ */
+ extern (C++) @trusted nothrow
+ void writeByten(int b)
+ {
+ this.data[offset++] = cast(ubyte) b;
+ }
+
extern (C++) void writeByte(uint b) pure nothrow
{
if (doindent && !notlinehead && b != '\n')
@@ -369,14 +523,6 @@ struct OutBuffer
}
}
- extern (C++) void write(RootObject obj) /*nothrow*/
- {
- if (obj)
- {
- writestring(obj.toChars());
- }
- }
-
extern (C++) void fill0(size_t nbytes) pure nothrow
{
reserve(nbytes);
@@ -428,8 +574,8 @@ struct OutBuffer
break;
}
offset += count;
- if (mem.isGCEnabled)
- memset(data.ptr + offset, 0xff, psize - count);
+ // if (mem.isGCEnabled)
+ memset(data.ptr + offset, 0xff, psize - count);
}
static if (__VERSION__ < 2092)
@@ -460,7 +606,6 @@ struct OutBuffer
*/
extern (C++) void print(ulong u) pure nothrow
{
- //import core.internal.string; // not available
UnsignedStringBuf buf = void;
writestring(unsignedToTempString(u, buf));
}
@@ -558,6 +703,11 @@ struct OutBuffer
return extractData()[0 .. length];
}
+ extern (D) byte[] extractUbyteSlice(bool nullTerminate = false) pure nothrow
+ {
+ return cast(byte[]) extractSlice(nullTerminate);
+ }
+
// Append terminating null if necessary and get view of internal buffer
extern (C++) char* peekChars() pure nothrow
{
@@ -577,6 +727,36 @@ struct OutBuffer
return extractData();
}
+ void writesLEB128(int value) pure nothrow
+ {
+ while (1)
+ {
+ ubyte b = value & 0x7F;
+
+ value >>= 7; // arithmetic right shift
+ if ((value == 0 && !(b & 0x40)) ||
+ (value == -1 && (b & 0x40)))
+ {
+ writeByte(b);
+ break;
+ }
+ writeByte(b | 0x80);
+ }
+ }
+
+ void writeuLEB128(uint value) pure nothrow
+ {
+ do
+ {
+ ubyte b = value & 0x7F;
+
+ value >>= 7;
+ if (value)
+ b |= 0x80;
+ writeByte(b);
+ } while (value);
+ }
+
/**
Destructively saves the contents of `this` to `filename`. As an
optimization, if the file already has identical contents with the buffer,
@@ -591,7 +771,6 @@ struct OutBuffer
*/
extern(D) bool moveToFile(const char* filename)
{
- import dmd.root.file;
bool result = true;
const bool identical = this[] == FileMapping!(const ubyte)(filename)[];
@@ -615,12 +794,12 @@ struct OutBuffer
else
{
if (!identical)
- File.write(filename, this[]);
+ writeFile(filename, this[]);
destroy();
}
return identical
- ? result && File.touch(filename)
+ ? result && touchFile(filename)
: result;
}
}
@@ -645,7 +824,7 @@ char[] unsignedToTempString(ulong value, char[] buf, uint radix = 10) @safe pure
else
{
ubyte x = cast(ubyte)(value % radix);
- value = value / radix;
+ value /= radix;
buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a');
}
} while (value);
diff --git a/gcc/d/dmd/root/outbuffer.h b/gcc/d/dmd/common/outbuffer.h
index b635373..a5e3f9c 100644
--- a/gcc/d/dmd/root/outbuffer.h
+++ b/gcc/d/dmd/common/outbuffer.h
@@ -4,14 +4,14 @@
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/common/outbuffer.h
*/
#pragma once
-#include "dsystem.h"
-#include "dcompat.h"
-#include "rmem.h"
+#include "../root/dsystem.h"
+#include "../root/dcompat.h"
+#include "../root/rmem.h"
class RootObject;
@@ -22,7 +22,7 @@ private:
DArray<unsigned char> data;
d_size_t offset;
bool notlinehead;
- void* fileMapping; // pointer to a file mapping object not used on the C++ side
+ void *fileMapping; // pointer to a file mapping object not used on the C++ side
public:
bool doindent;
bool spaces;
diff --git a/gcc/d/dmd/common/string.d b/gcc/d/dmd/common/string.d
new file mode 100644
index 0000000..026374a
--- /dev/null
+++ b/gcc/d/dmd/common/string.d
@@ -0,0 +1,209 @@
+/**
+ * Common string functions including filename manipulation.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d, common/_string.d)
+ * Documentation: https://dlang.org/phobos/dmd_common_string.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/string.d
+ */
+module dmd.common.string;
+
+/**
+Defines a temporary array 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.
+
+This type is meant to use exclusively as an automatic variable. It is not
+default constructible or copyable.
+*/
+struct SmallBuffer(T)
+{
+ import core.stdc.stdlib : malloc, free;
+
+ private T[] _extent;
+ private bool needsFree;
+
+ @disable this(); // no default ctor
+ @disable this(ref const SmallBuffer!T); // noncopyable, nonassignable
+
+ this(size_t len, T[] buffer)
+ {
+ if (len <= buffer.length)
+ {
+ _extent = buffer[0 .. len];
+ }
+ else
+ {
+ _extent = (cast(typeof(_extent.ptr)) malloc(len * _extent[0].sizeof))[0 .. len];
+ _extent.ptr || assert(0, "Out of memory.");
+ needsFree = true;
+ }
+ assert(this.length == len);
+ }
+
+ ~this()
+ {
+ if (needsFree)
+ free(_extent.ptr);
+ }
+
+ void create(size_t len)
+ {
+ if (len <= _extent.length)
+ {
+ _extent = _extent[0 .. len];
+ }
+ else
+ {
+ __dtor();
+ _extent = (cast(typeof(_extent.ptr)) malloc(len * _extent[0].sizeof))[0 .. len];
+ _extent.ptr || assert(0, "Out of memory.");
+ needsFree = true;
+ }
+ assert(this.length == len);
+ }
+
+ // Force accesses to extent to be scoped.
+ scope inout extent()
+ {
+ return _extent;
+ }
+
+ alias extent this;
+}
+
+/// ditto
+unittest
+{
+ char[230] buf = void;
+ auto a = SmallBuffer!char(10, buf);
+ assert(a[] is buf[0 .. 10]);
+ auto b = SmallBuffer!char(1000, buf);
+ assert(b[] !is buf[]);
+ b.create(1000);
+ assert(b.length == 1000);
+ assert(b[] !is buf[]);
+}
+
+/**
+Converts a zero-terminated C string to a D slice. Takes linear time and allocates no memory.
+
+Params:
+stringz = the C string to be converted
+
+Returns:
+a slice comprehending the string. The terminating 0 is not part of the slice.
+*/
+auto asDString(C)(C* stringz) pure @nogc nothrow
+{
+ import core.stdc.string : strlen;
+ return stringz[0 .. strlen(stringz)];
+}
+
+///
+unittest
+{
+ const char* p = "123".ptr;
+ assert(p.asDString == "123");
+}
+
+/**
+(Windows only) Converts a narrow string to a wide string using `buffer` as strorage. Returns a slice managed by
+`buffer` containing the converted string. The terminating zero is not part of the returned slice,
+but is guaranteed to follow it.
+*/
+version(Windows) wchar[] toWStringz(const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow
+{
+ import core.sys.windows.winnls : CP_ACP, MultiByteToWideChar;
+ // assume filenames encoded in system default Windows ANSI code page
+ enum CodePage = CP_ACP;
+
+ if (narrow is null)
+ return null;
+
+ const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
+ if (requiredLength < cast(int) buffer.length)
+ {
+ buffer[requiredLength] = 0;
+ return buffer[0 .. requiredLength];
+ }
+
+ buffer.create(requiredLength + 1);
+ const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, requiredLength);
+ assert(length == requiredLength);
+ buffer[length] = 0;
+ return buffer[0 .. length];
+}
+
+/**************************************
+* Converts a path to one suitable to be passed to Win32 API
+* functions that can deal with paths longer than 248
+* characters then calls the supplied function on it.
+*
+* Params:
+* path = The Path to call F on.
+*
+* Returns:
+* The result of calling F on path.
+*
+* References:
+* https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+*/
+version(Windows) auto extendedPathThen(alias F)(const(char)[] path)
+{
+ import core.sys.windows.winbase;
+ import core.sys.windows.winnt;
+
+ if (!path.length)
+ return F((wchar[]).init);
+
+ wchar[1024] buf = void;
+ auto store = SmallBuffer!wchar(buf.length, buf);
+ auto wpath = toWStringz(path, store);
+
+ // GetFullPathNameW expects a sized buffer to store the result in. Since we don't
+ // know how large it has to be, we pass in null and get the needed buffer length
+ // as the return code.
+ const pathLength = GetFullPathNameW(&wpath[0],
+ 0 /*length8*/,
+ null /*output buffer*/,
+ null /*filePartBuffer*/);
+ if (pathLength == 0)
+ {
+ return F((wchar[]).init);
+ }
+
+ // wpath is the UTF16 version of path, but to be able to use
+ // extended paths, we need to prefix with `\\?\` and the absolute
+ // path.
+ static immutable prefix = `\\?\`w;
+
+ // prefix only needed for long names and non-UNC names
+ const needsPrefix = pathLength >= MAX_PATH && (wpath[0] != '\\' || wpath[1] != '\\');
+ const prefixLength = needsPrefix ? prefix.length : 0;
+
+ // +1 for the null terminator
+ const bufferLength = pathLength + prefixLength + 1;
+
+ wchar[1024] absBuf = void;
+ auto absPath = SmallBuffer!wchar(bufferLength, absBuf);
+
+ absPath[0 .. prefixLength] = prefix[0 .. prefixLength];
+
+ const absPathRet = GetFullPathNameW(&wpath[0],
+ cast(uint)(absPath.length - prefixLength - 1),
+ &absPath[prefixLength],
+ null /*filePartBuffer*/);
+
+ if (absPathRet == 0 || absPathRet > absPath.length - prefixLength)
+ {
+ return F((wchar[]).init);
+ }
+
+ absPath[$ - 1] = '\0';
+ // Strip null terminator from the slice
+ return F(absPath[0 .. $ - 1]);
+}
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index d4a8b13..05bd4bd 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -28,7 +28,7 @@ import dmd.globals;
import dmd.identifier;
import dmd.mtype;
import dmd.typesem;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.root.string;
import dmd.tokens;
@@ -452,7 +452,6 @@ extern (C++) final class StaticForeach : RootObject
sc = sc.startCTFE();
aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
sc = sc.endCTFE();
- aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
}
if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror)
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index bb40649..7d8ab67 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -23,7 +23,7 @@ import dmd.lexer;
import dmd.parse;
import dmd.errors;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.rootobject;
import dmd.root.string;
@@ -72,6 +72,7 @@ final class CParser(AST) : Parser!AST
{
//printf("cparseTranslationUnit()\n");
symbols = new AST.Dsymbols();
+ addBuiltinDeclarations();
while (1)
{
if (token.value == TOK.endOfFile)
@@ -756,7 +757,6 @@ final class CParser(AST) : Parser!AST
switch (token.value)
{
case TOK.dot:
- case TOK.arrow:
nextToken();
if (token.value == TOK.identifier)
{
@@ -767,6 +767,19 @@ final class CParser(AST) : Parser!AST
error("identifier expected following `.`, not `%s`", token.toChars());
break;
+ case TOK.arrow:
+ nextToken();
+ if (token.value == TOK.identifier)
+ {
+ Identifier id = token.ident;
+ auto die = new AST.DotIdExp(loc, e, id);
+ die.arrow = true;
+ e = die;
+ break;
+ }
+ error("identifier expected following `->`, not `%s`", token.toChars());
+ break;
+
case TOK.plusPlus:
e = new AST.PostExp(TOK.plusPlus, loc, e);
break;
@@ -949,6 +962,7 @@ final class CParser(AST) : Parser!AST
nextToken();
auto t = cparseTypeName();
check(TOK.rightParenthesis);
+ pt = &token;
if (token.value == TOK.leftCurly)
{
@@ -957,6 +971,17 @@ final class CParser(AST) : Parser!AST
auto ce = new AST.CompoundLiteralExp(loc, t, ci);
return cparsePostfixOperators(ce);
}
+ else if (t.isTypeIdentifier() &&
+ token.value == TOK.leftParenthesis &&
+ !isCastExpression(pt))
+ {
+ /* this might actually be a function
+ * call that looks like `(a)(b)` or even `(a)(b,c)`
+ */
+ auto ie = new AST.IdentifierExp(loc, t.isTypeIdentifier().ident);
+ ie.parens = true; // disambiguate it from being a declaration
+ return new AST.CallExp(loc, ie, cparseArguments());
+ }
else
{
// ( type-name ) cast-expression
@@ -1451,6 +1476,7 @@ final class CParser(AST) : Parser!AST
auto symbolsSave = symbols;
Specifier specifier;
+ specifier.packalign = this.packalign;
auto tspec = cparseDeclarationSpecifiers(level, specifier);
/* If a declarator does not follow, it is unnamed
@@ -1459,7 +1485,8 @@ final class CParser(AST) : Parser!AST
{
nextToken();
auto tt = tspec.isTypeTag();
- if (!tt || !tt.id)
+ if (!tt ||
+ !tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_))
return; // legal but meaningless empty declaration, ignore it
/* `struct tag;` and `struct tag { ... };`
@@ -1493,7 +1520,7 @@ final class CParser(AST) : Parser!AST
{
Identifier id;
AST.Expression asmname;
- auto dt = cparseDeclarator(DTR.xdirect, tspec, id);
+ auto dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
if (!dt)
{
panic();
@@ -1674,6 +1701,8 @@ final class CParser(AST) : Parser!AST
return;
case TOK.comma:
+ if (!symbolsSave)
+ symbolsSave = symbols;
nextToken();
break;
@@ -1720,8 +1749,9 @@ final class CParser(AST) : Parser!AST
*/
auto pl = ft.parameterList;
pl.hasIdentifierList = true; // semantic needs to know to adjust parameter types
- if (pl.varargs != AST.VarArg.none)
+ 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
auto plLength = pl.length;
if (symbols.length != plLength)
error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
@@ -1756,7 +1786,10 @@ final class CParser(AST) : Parser!AST
}
}
if (!p.type)
+ {
error("no declaration for identifier `%s`", p.ident.toChars());
+ p.type = AST.Type.terror;
+ }
}
}
@@ -2240,14 +2273,14 @@ final class CParser(AST) : Parser!AST
* declarator = declarator kind
* t = base type to start with
* pident = set to Identifier if there is one, null if not
- * storageClass = any storage classes seen so far that apply to a function
+ * specifier = specifiers in and out
* Returns:
* type declared. If a TypeFunction is returned, this.symbols is the
* symbol table for the parameter-type-list, which will contain any
* declared struct, union or enum tags.
*/
private AST.Type cparseDeclarator(DTR declarator, AST.Type t,
- out Identifier pident, StorageClass storageClass = 0)
+ out Identifier pident, ref Specifier specifier)
{
//printf("cparseDeclarator(%d)\n", declarator);
AST.Types constTypes; // all the Types that will need `const` applied to them
@@ -2285,6 +2318,8 @@ final class CParser(AST) : Parser!AST
const mod = cparseTypeQualifierList();
if (mod & MOD.xconst)
constTypes.push(t);
+ if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
continue;
default:
@@ -2352,8 +2387,9 @@ final class CParser(AST) : Parser!AST
}
else
{
- // An array of unknown size, fake it with a DArray
- ta = new AST.TypeDArray(t); // []
+ /* C11 6.7.6.2-4 An [ ] array is an incomplete array type
+ */
+ ta = new AST.TypeSArray(t);
}
check(TOK.rightBracket);
@@ -2388,7 +2424,7 @@ final class CParser(AST) : Parser!AST
/* C11 6.7.6.2-1: the element type shall not be an incomplete or
* function type.
*/
- if (ta.isTypeDArray() && !isVLA)
+ if (ta.isTypeSArray() && ta.isTypeSArray().isIncomplete() && !isVLA)
error("array type has incomplete element type `%s`", ta.toChars());
}
@@ -2489,9 +2525,10 @@ final class CParser(AST) : Parser!AST
AST.Type cparseTypeName()
{
Specifier specifier;
+ specifier.packalign.setDefault();
auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
Identifier id;
- return cparseDeclarator(DTR.xabstract, tspec, id);
+ return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
}
/***********************************
@@ -2525,13 +2562,19 @@ final class CParser(AST) : Parser!AST
StorageClass varargsStc;
check(TOK.leftParenthesis);
- if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis)
+ if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis) // func(void)
{
nextToken();
nextToken();
return AST.ParameterList(parameters, varargs, varargsStc);
}
+ if (token.value == TOK.rightParenthesis) // func()
+ {
+ nextToken();
+ return AST.ParameterList(parameters, AST.VarArg.variadic, varargsStc);
+ }
+
/* The check for identifier-list comes later,
* when doing the trailing declaration-list (opt)
*/
@@ -2541,6 +2584,8 @@ final class CParser(AST) : Parser!AST
break;
if (token.value == TOK.dotDotDot)
{
+ if (parameters.length == 0) // func(...)
+ error("named parameter required before `...`");
varargs = AST.VarArg.variadic; // C-style variadics
nextToken();
check(TOK.rightParenthesis);
@@ -2548,10 +2593,16 @@ final class CParser(AST) : Parser!AST
}
Specifier specifier;
+ specifier.packalign.setDefault();
auto tspec = cparseDeclarationSpecifiers(LVL.prototype, specifier);
+ if (tspec && specifier.mod & MOD.xconst)
+ {
+ tspec = toConst(tspec);
+ specifier.mod = MOD.xnone; // 'used' it
+ }
Identifier id;
- auto t = cparseDeclarator(DTR.xparameter, tspec, id);
+ auto t = cparseDeclarator(DTR.xparameter, tspec, id, specifier);
if (specifier.mod & MOD.xconst)
t = toConst(t);
auto param = new AST.Parameter(STC.parameter, t, id, null, null);
@@ -2920,6 +2971,7 @@ final class CParser(AST) : Parser!AST
* enum gnu-attributes (opt) identifier
*/
Specifier specifier;
+ specifier.packalign.setDefault();
if (token.value == TOK.__attribute__)
cparseGnuAttributes(specifier);
@@ -2950,6 +3002,16 @@ final class CParser(AST) : Parser!AST
nextToken();
auto mloc = token.loc;
+ if (token.value == TOK.__attribute__)
+ {
+ /* gnu-attributes can appear here, but just scan and ignore them
+ * https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
+ */
+ Specifier specifierx;
+ specifierx.packalign.setDefault();
+ cparseGnuAttributes(specifierx);
+ }
+
AST.Expression value;
if (token.value == TOK.assign)
{
@@ -2958,6 +3020,16 @@ final class CParser(AST) : Parser!AST
// TODO C11 6.7.2.2-2 value must fit into an int
}
+ if (token.value == TOK.__attribute__)
+ {
+ /* gnu-attributes can appear here, but just scan and ignore them
+ * https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
+ */
+ Specifier specifierx;
+ specifierx.packalign.setDefault();
+ cparseGnuAttributes(specifierx);
+ }
+
auto em = new AST.EnumMember(mloc, ident, value, null, 0, null, null);
members.push(em);
@@ -3037,14 +3109,12 @@ final class CParser(AST) : Parser!AST
check(TOK.rightCurly);
if ((*members).length == 0) // C11 6.7.2.1-8
- /* TODO: not strict enough, should really be contains "no named members",
- * not just "no members".
- * I.e. an unnamed bit field, _Static_assert, etc, are not named members,
- * but will pass this check.
- * Be careful to detect named members that come anonymous structs.
- * Correctly doing this will likely mean moving it to typesem.d.
+ {
+ /* allow empty structs as an extension
+ * struct-declarator-list:
+ * struct-declarator (opt)
*/
- error("empty struct-declaration-list for `%s %s`", Token.toChars(structOrUnion), tag ? tag.toChars() : "Anonymous".ptr);
+ }
}
else if (!tag)
error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
@@ -3083,7 +3153,13 @@ final class CParser(AST) : Parser!AST
auto symbolsSave = symbols;
Specifier specifier;
+ specifier.packalign = this.packalign;
auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
+ if (tspec && specifier.mod & MOD.xconst)
+ {
+ tspec = toConst(tspec);
+ specifier.mod = MOD.xnone; // 'used' it
+ }
/* If a declarator does not follow, it is unnamed
*/
@@ -3139,12 +3215,14 @@ final class CParser(AST) : Parser!AST
dt = tspec;
}
else
- dt = cparseDeclarator(DTR.xdirect, tspec, id);
- if (!dt)
{
- panic();
- nextToken();
- break; // error recovery
+ dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
+ if (!dt)
+ {
+ panic();
+ nextToken();
+ break; // error recovery
+ }
}
AST.Expression width;
@@ -3155,9 +3233,6 @@ final class CParser(AST) : Parser!AST
width = cparseConstantExp();
}
- if (specifier.mod & MOD.xconst)
- dt = toConst(dt);
-
/* GNU Extensions
* struct-declarator:
* declarator gnu-attributes (opt)
@@ -3234,8 +3309,8 @@ final class CParser(AST) : Parser!AST
*/
private bool isCDeclaration(ref Token* pt)
{
- //printf("isCDeclaration()\n");
auto t = pt;
+ //printf("isCDeclaration() %s\n", t.toChars());
if (!isDeclarationSpecifiers(t))
return false;
@@ -3360,8 +3435,8 @@ final class CParser(AST) : Parser!AST
*/
private bool isAssignmentExpression(ref Token* pt)
{
- //printf("isAssignmentExpression()\n");
auto t = pt;
+ //printf("isAssignmentExpression() %s\n", t.toChars());
/* This doesn't actually check for grammar matching an
* assignment-expression. It just matches ( ) [ ] looking for
@@ -3384,6 +3459,15 @@ final class CParser(AST) : Parser!AST
case TOK.leftParenthesis:
if (!skipParens(t, &t))
return false;
+ /*
+ https://issues.dlang.org/show_bug.cgi?id=22267
+ Fix issue 22267: If the parser encounters the following
+ `identifier variableName = (expression);`
+ the initializer is not identified as such since the parentheses
+ cause the parser to keep walking indefinitely
+ (whereas `(1) + 1` would not be affected.).
+ */
+ any = true;
continue;
case TOK.leftBracket:
@@ -3391,6 +3475,11 @@ final class CParser(AST) : Parser!AST
return false;
continue;
+ case TOK.leftCurly:
+ if (!skipBraces(t))
+ return false;
+ continue;
+
default:
any = true; // assume token was part of an a-e
t = peek(t);
@@ -3427,6 +3516,7 @@ final class CParser(AST) : Parser!AST
auto t = pt;
+ bool seenType;
bool any;
while (1)
{
@@ -3445,9 +3535,19 @@ final class CParser(AST) : Parser!AST
case TOK._Bool:
//case TOK._Imaginary:
case TOK._Complex:
- case TOK.identifier: // typedef-name
t = peek(t);
+ seenType = true;
any = true;
+ continue;
+
+ case TOK.identifier: // typedef-name
+ if (!seenType)
+ {
+ t = peek(t);
+ seenType = true;
+ any = true;
+ continue;
+ }
break;
case TOK.struct_:
@@ -3878,6 +3978,10 @@ final class CParser(AST) : Parser!AST
t = tk;
break;
}
+
+ if (tk.value == TOK.leftParenthesis && peek(tk).value == TOK.rightParenthesis)
+ return false; // (type-name)() is not a cast (it might be a function call)
+
if (!isCastExpression(tk, true))
{
if (afterParenType) // could be ( type-name ) ( unary-expression )
@@ -4071,6 +4175,7 @@ final class CParser(AST) : Parser!AST
SCW scw; /// storage-class specifiers
MOD mod; /// type qualifiers
AST.Expressions* alignExps; /// alignment
+ structalign_t packalign; /// #pragma pack alignment value
}
/***********************
@@ -4089,19 +4194,19 @@ final class CParser(AST) : Parser!AST
if (level == LVL.global)
{
if (specifier.scw & SCW.xextern)
- stc = AST.STC.extern_;
+ stc = AST.STC.extern_;
}
else if (level == LVL.local)
{
if (specifier.scw & SCW.xextern)
- stc = AST.STC.extern_;
+ stc = AST.STC.extern_;
else if (specifier.scw & SCW.xstatic)
stc = AST.STC.static_;
}
else if (level == LVL.member)
{
if (specifier.scw & SCW.xextern)
- stc = AST.STC.extern_;
+ stc = AST.STC.extern_;
else if (specifier.scw & SCW.xstatic)
stc = AST.STC.static_;
}
@@ -4111,21 +4216,23 @@ final class CParser(AST) : Parser!AST
if (level == LVL.global)
{
if (specifier.scw & SCW.xextern)
- stc = AST.STC.extern_ | AST.STC.gshared;
+ stc = AST.STC.extern_ | AST.STC.gshared;
+ else if (specifier.scw & SCW.xstatic)
+ stc = AST.STC.gshared | AST.STC.static_;
else
stc = AST.STC.gshared;
}
else if (level == LVL.local)
{
if (specifier.scw & SCW.xextern)
- stc = AST.STC.extern_ | AST.STC.gshared;
+ stc = AST.STC.extern_ | AST.STC.gshared;
else if (specifier.scw & SCW.xstatic)
stc = AST.STC.gshared;
}
else if (level == LVL.member)
{
if (specifier.scw & SCW.xextern)
- stc = AST.STC.extern_ | AST.STC.gshared;
+ stc = AST.STC.extern_ | AST.STC.gshared;
else if (specifier.scw & SCW.xstatic)
stc = AST.STC.gshared;
}
@@ -4235,15 +4342,59 @@ final class CParser(AST) : Parser!AST
*/
private AST.Dsymbol applySpecifier(AST.Dsymbol s, ref Specifier specifier)
{
+ //printf("applySpecifier() %s\n", s.toChars());
if (specifier.alignExps)
{
+ //printf(" applying _Alignas %s, packalign %d\n", (*specifier.alignExps)[0].toChars(), cast(int)specifier.packalign);
// Wrap declaration in an AlignDeclaration
auto decls = new AST.Dsymbols(1);
(*decls)[0] = s;
s = new AST.AlignDeclaration(s.loc, specifier.alignExps, decls);
}
+ else if (!specifier.packalign.isDefault())
+ {
+ //printf(" applying packalign %d\n", cast(int)specifier.packalign);
+ // Wrap #pragma pack in an AlignDeclaration
+ auto decls = new AST.Dsymbols(1);
+ (*decls)[0] = s;
+ s = new AST.AlignDeclaration(s.loc, specifier.packalign, decls);
+ }
return s;
}
+ /***********************************
+ * Add global target-dependent builtin declarations.
+ */
+ private void addBuiltinDeclarations()
+ {
+ void genBuiltinFunc(Identifier id, AST.VarArg va)
+ {
+ auto tva_list = new AST.TypeIdentifier(Loc.initial, Id.builtin_va_list);
+ auto parameters = new AST.Parameters();
+ parameters.push(new AST.Parameter(STC.parameter | STC.ref_, tva_list, null, null, null));
+ auto pl = AST.ParameterList(parameters, va, 0);
+ auto tf = new AST.TypeFunction(pl, AST.Type.tvoid, LINK.c, 0);
+ auto s = new AST.FuncDeclaration(Loc.initial, Loc.initial, id, AST.STC.static_, tf, false);
+ symbols.push(s);
+ }
+
+ /* void __builtin_va_start(__builtin_va_list, ...);
+ * The second argument is supposed to be of any type, so fake it with the ...
+ */
+ genBuiltinFunc(Id.builtin_va_start, AST.VarArg.variadic);
+
+ /* void __builtin_va_end(__builtin_va_list);
+ */
+ genBuiltinFunc(Id.builtin_va_end, AST.VarArg.none);
+
+ /* struct __va_list_tag
+ * {
+ * uint, uint, void*, void*
+ * }
+ */
+ auto s = new AST.StructDeclaration(Loc.initial, Id.va_list_tag, false);
+ symbols.push(s);
+ }
+
//}
}
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 0381f9a..df742c0 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -41,7 +41,7 @@ import dmd.identifier;
import dmd.mtype;
import dmd.nspace;
import dmd.root.array;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.root.string;
import dmd.target;
@@ -98,21 +98,20 @@ extern(C++) const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
}
/******************************
- * Determine if sym is the 'primary' destructor, that is,
- * the most-aggregate destructor (the one that is defined as __xdtor)
+ * Determine if sym is a full aggregate destructor.
* Params:
* sym = Dsymbol
* Returns:
- * true if sym is the primary destructor for an aggregate
+ * true if sym is an aggregate destructor
*/
-bool isPrimaryDtor(const Dsymbol sym)
+bool isAggregateDtor(const Dsymbol sym)
{
const dtor = sym.isDtorDeclaration();
if (!dtor)
return false;
const ad = dtor.isMember();
assert(ad);
- return dtor == ad.primaryDtor;
+ return dtor == ad.aggrDtor;
}
/// Context used when processing pre-semantic AST
@@ -1069,7 +1068,7 @@ private final class CppMangleVisitor : Visitor
if (auto ctor = d.isCtorDeclaration())
buf.writestring(ctor.isCpCtor ? "C2" : "C1");
- else if (d.isPrimaryDtor())
+ else if (d.isAggregateDtor())
buf.writestring("D1");
else if (d.ident && d.ident == Id.assign)
buf.writestring("aS");
@@ -1184,7 +1183,7 @@ private final class CppMangleVisitor : Visitor
mangleFunctionParameters(tf.parameterList);
return;
}
- else if (d.isPrimaryDtor())
+ else if (d.isAggregateDtor())
{
buf.writestring("D1");
mangleFunctionParameters(tf.parameterList);
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 22633a8..7f76d75 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -685,6 +685,11 @@ bool isSafePointerCast(Type srcPointee, Type destPointee)
// It's OK if both are the same (modulo const)
if (srcPointee.constConv(destPointee))
return true;
+
+ // It's ok to cast from/to shared because CTFE is single threaded anyways
+ if (srcPointee.unSharedOf() == destPointee.unSharedOf())
+ return true;
+
// It's OK if function pointers differ only in safe/pure/nothrow
if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
return srcPointee.covariant(destPointee) == Covariant.yes ||
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 4c70565..87c3ada 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -31,12 +31,13 @@ import dmd.func;
import dmd.globals;
import dmd.impcnvtab;
import dmd.id;
+import dmd.importc;
import dmd.init;
import dmd.intrange;
import dmd.mtype;
import dmd.opover;
import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.tokens;
import dmd.typesem;
@@ -1445,6 +1446,29 @@ MATCH implicitConvTo(Expression e, Type t)
if (tb.ty == Tpointer && e.e1.op == TOK.string_)
e.e1.accept(this);
}
+
+ override void visit(TupleExp e)
+ {
+ result = e.type.implicitConvTo(t);
+ if (result != MATCH.nomatch)
+ return;
+
+ /* If target type is a tuple of same length, test conversion of
+ * each expression to the corresponding type in the tuple.
+ */
+ TypeTuple totuple = t.isTypeTuple();
+ if (totuple && e.exps.length == totuple.arguments.length)
+ {
+ result = MATCH.exact;
+ foreach (i, ex; *e.exps)
+ {
+ auto to = (*totuple.arguments)[i].type;
+ MATCH mi = ex.implicitConvTo(to);
+ if (mi < result)
+ result = mi;
+ }
+ }
+ }
}
scope ImplicitConvTo v = new ImplicitConvTo(t);
@@ -1476,12 +1500,8 @@ MATCH cimplicitConvTo(Expression e, Type t)
return MATCH.convert;
if (tb.isintegral() && typeb.ty == Tpointer) // C11 6.3.2.3-6
return MATCH.convert;
- if (tb.ty == Tpointer && typeb.ty == Tpointer)
- {
- if (tb.isTypePointer().next.ty == Tvoid ||
- typeb.isTypePointer().next.ty == Tvoid)
- return MATCH.convert; // convert to/from void* C11 6.3.2.3-1
- }
+ if (tb.ty == Tpointer && typeb.ty == Tpointer) // C11 6.3.2.3-7
+ return MATCH.convert;
return implicitConvTo(e, t);
}
@@ -2189,13 +2209,20 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
return;
}
+ /* If target type is a tuple of same length, cast each expression to
+ * the corresponding type in the tuple.
+ */
+ TypeTuple totuple;
+ if (auto tt = t.isTypeTuple())
+ totuple = e.exps.length == tt.arguments.length ? tt : null;
+
TupleExp te = e.copy().isTupleExp();
te.e0 = e.e0 ? e.e0.copy() : null;
te.exps = e.exps.copy();
for (size_t i = 0; i < te.exps.dim; i++)
{
Expression ex = (*te.exps)[i];
- ex = ex.castTo(sc, t);
+ ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t);
(*te.exps)[i] = ex;
}
result = te;
@@ -2821,6 +2848,13 @@ Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
Expression e1 = pe1;
Expression e2 = pe2;
+ // ImportC: do array/function conversions
+ if (sc)
+ {
+ e1 = e1.arrayFuncConv(sc);
+ e2 = e2.arrayFuncConv(sc);
+ }
+
Type Lret(Type result)
{
pe1 = e1;
@@ -2838,7 +2872,7 @@ Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
return result;
}
- /// Converts one of the expression too the other
+ /// Converts one of the expression to the other
Type convert(ref Expression from, Type to)
{
from = from.castTo(sc, to);
@@ -2856,6 +2890,22 @@ Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
Type t1b = e1.type.toBasetype();
Type t2b = e2.type.toBasetype();
+ if (sc && sc.flags & SCOPE.Cfile)
+ {
+ // Integral types can be implicitly converted to pointers
+ if ((t1b.ty == Tpointer) != (t2b.ty == Tpointer))
+ {
+ if (t1b.isintegral())
+ {
+ return convert(e1, t2b);
+ }
+ else if (t2b.isintegral())
+ {
+ return convert(e2, t1b);
+ }
+ }
+ }
+
if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
{
if (op == TOK.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar())
@@ -3132,6 +3182,14 @@ Lagain:
Lcc:
while (1)
{
+ MATCH i1woat = MATCH.exact;
+ MATCH i2woat = MATCH.exact;
+
+ if (auto t2c = t2.isTypeClass())
+ i1woat = t2c.implicitConvToWithoutAliasThis(t1);
+ if (auto t1c = t1.isTypeClass())
+ i2woat = t1c.implicitConvToWithoutAliasThis(t2);
+
MATCH i1 = e2.implicitConvTo(t1);
MATCH i2 = e1.implicitConvTo(t2);
@@ -3144,11 +3202,26 @@ Lagain:
i2 = MATCH.nomatch;
}
- if (i2)
+ // Match but without 'alias this' on classes
+ if (i2 && i2woat)
return coerce(t2);
- if (i1)
+ if (i1 && i1woat)
return coerce(t1);
+ // Here use implicitCastTo() instead of castTo() to try 'alias this' on classes
+ Type coerceImplicit(Type towards)
+ {
+ e1 = e1.implicitCastTo(sc, towards);
+ e2 = e2.implicitCastTo(sc, towards);
+ return Lret(towards);
+ }
+
+ // Implicit conversion with 'alias this'
+ if (i2)
+ return coerceImplicit(t2);
+ if (i1)
+ return coerceImplicit(t1);
+
if (t1.ty == Tclass && t2.ty == Tclass)
{
TypeClass tc1 = t1.isTypeClass();
@@ -3257,29 +3330,26 @@ Lagain:
}
}
- if (t1.ty == Tstruct || t2.ty == Tstruct)
+ if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
{
- if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
- {
- if (isRecursiveAliasThis(att1, e1.type))
- return null;
- //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
- e1 = resolveAliasThis(sc, e1);
- t1 = e1.type;
- t = t1;
- goto Lagain;
- }
- if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
- {
- if (isRecursiveAliasThis(att2, e2.type))
- return null;
- //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
- e2 = resolveAliasThis(sc, e2);
- t2 = e2.type;
- t = t2;
- goto Lagain;
- }
- return null;
+ if (isRecursiveAliasThis(att1, e1.type))
+ return null;
+ //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
+ e1 = resolveAliasThis(sc, e1);
+ t1 = e1.type;
+ t = t1;
+ goto Lagain;
+ }
+
+ if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
+ {
+ if (isRecursiveAliasThis(att2, e2.type))
+ return null;
+ //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
+ e2 = resolveAliasThis(sc, e2);
+ t2 = e2.type;
+ t = t2;
+ goto Lagain;
}
if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2))
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index b065251..34a236b 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -20,6 +20,7 @@ import dmd.aggregate;
import dmd.apply;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.attrib;
import dmd.gluelayer;
import dmd.declaration;
import dmd.dscope;
@@ -367,7 +368,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
baseok = Baseok.none;
}
- static ClassDeclaration create(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
+ static ClassDeclaration create(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
{
return new ClassDeclaration(loc, id, baseclasses, members, inObject);
}
@@ -607,7 +608,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
if (!b.sym.alignsize)
b.sym.alignsize = target.ptrsize;
- alignmember(b.sym.alignsize, b.sym.alignsize, &offset);
+ alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, &offset);
assert(bi < vtblInterfaces.dim);
BaseClass* bv = (*vtblInterfaces)[bi];
@@ -725,6 +726,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
void searchVtbl(ref Dsymbols vtbl)
{
+ bool seenInterfaceVirtual;
foreach (s; vtbl)
{
auto fd = s.isFuncDeclaration();
@@ -748,6 +750,23 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
if (fd == fdmatch)
continue;
+ /* Functions overriding interface functions for extern(C++) with VC++
+ * are not in the normal vtbl, but in vtblFinal. If the implementation
+ * is again overridden in a child class, both would be found here.
+ * The function in the child class should override the function
+ * in the base class, which is done here, because searchVtbl is first
+ * called for the child class. Checking seenInterfaceVirtual makes
+ * sure, that the compared functions are not in the same vtbl.
+ */
+ if (fd.interfaceVirtual &&
+ fd.interfaceVirtual is fdmatch.interfaceVirtual &&
+ !seenInterfaceVirtual &&
+ fdmatch.type.covariant(fd.type) == Covariant.yes)
+ {
+ seenInterfaceVirtual = true;
+ continue;
+ }
+
{
// Function type matching: exact > covariant
MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 0f40c11..e3f135a 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -16,6 +16,7 @@ import core.stdc.stdio;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.attrib;
import dmd.ctorflow;
import dmd.dclass;
import dmd.delegatize;
@@ -34,7 +35,7 @@ import dmd.init;
import dmd.initsem;
import dmd.intrange;
import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.target;
import dmd.tokens;
@@ -705,7 +706,7 @@ extern (C++) final class AliasDeclaration : Declaration
assert(s);
}
- static AliasDeclaration create(Loc loc, Identifier id, Type type)
+ static AliasDeclaration create(const ref Loc loc, Identifier id, Type type)
{
return new AliasDeclaration(loc, id, type);
}
@@ -1192,14 +1193,7 @@ extern (C++) class VarDeclaration : Declaration
/* If coming after a bit field in progress,
* advance past the field
*/
- if (fieldState.inFlight)
- {
- fieldState.inFlight = false;
- if (0 && target.os & Target.OS.Posix)
- fieldState.offset += (fieldState.bitOffset + 7) / 8;
- else if (0 &&target.os == Target.OS.Windows)
- fieldState.offset += fieldState.fieldSize;
- }
+ fieldState.inFlight = false;
const sz = t.size(loc);
assert(sz != SIZE_INVALID && sz < uint.max);
@@ -1743,13 +1737,23 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
- //printf("BitFieldDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
+ //printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
+ static void print(const ref FieldState fieldState)
+ {
+ printf("FieldState.offset = %d bytes\n", fieldState.offset);
+ printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset);
+ printf(" .bitOffset = %d bits\n", fieldState.bitOffset);
+ printf(" .fieldSize = %d bytes\n", fieldState.fieldSize);
+ printf(" .inFlight = %d\n\n", fieldState.inFlight);
+ }
+ //print(fieldState);
Type t = type.toBasetype();
+ const bool anon = isAnonymous();
// List in ad.fields. Even if the type is error, it's necessary to avoid
// pointless error diagnostic "more initializers than fields" on struct literal.
- if (!isAnonymous())
+ if (!anon)
ad.fields.push(this);
if (t.ty == Terror)
@@ -1760,17 +1764,36 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
- if (fieldWidth == 0 && !isAnonymous())
+ if (fieldWidth == 0 && !anon)
error(loc, "named bit fields cannot have 0 width");
if (fieldWidth > memsize * 8)
error(loc, "bit field width %d is larger than type", fieldWidth);
+ const style = target.c.bitFieldStyle;
+
void startNewField()
{
+ uint alignsize;
+ if (style == TargetC.BitFieldStyle.Gcc_Clang)
+ {
+ if (fieldWidth > 32)
+ alignsize = memalignsize;
+ else if (fieldWidth > 16)
+ alignsize = 4;
+ else if (fieldWidth > 8)
+ alignsize = 2;
+ else
+ alignsize = 1;
+ }
+ else
+ alignsize = memsize; // not memalignsize
+
+ uint dummy;
offset = AggregateDeclaration.placeField(
&fieldState.offset,
- memsize, memalignsize, alignment,
- &ad.structsize, &ad.alignsize,
+ memsize, alignsize, alignment,
+ &ad.structsize,
+ (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? &dummy : &ad.alignsize,
isunion);
fieldState.inFlight = true;
@@ -1779,19 +1802,92 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
fieldState.fieldSize = memsize;
}
- if (!fieldState.inFlight || fieldWidth == 0)
+ if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
- startNewField();
+ if (fieldWidth == 0)
+ {
+ if (!isunion)
+ {
+ // Use type of zero width field to align to next field
+ fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
+ ad.structsize = fieldState.offset;
+ }
+
+ fieldState.inFlight = false;
+ return;
+ }
+
+ if (ad.alignsize == 0)
+ ad.alignsize = 1;
+ if (!anon &&
+ ad.alignsize < memalignsize)
+ ad.alignsize = memalignsize;
+ }
+ else if (style == TargetC.BitFieldStyle.MS)
+ {
+ if (ad.alignsize == 0)
+ ad.alignsize = 1;
+ if (fieldWidth == 0)
+ {
+ if (fieldState.inFlight && !isunion)
+ {
+ // documentation says align to next int
+ //const alsz = cast(uint)Type.tint32.size();
+ const alsz = memsize; // but it really does this
+ fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+ ad.structsize = fieldState.offset;
+ }
+
+ fieldState.inFlight = false;
+ return;
+ }
+ }
+ else if (style == TargetC.BitFieldStyle.DM)
+ {
+ if (anon && fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
+ return; // this probably should be a bug in DMC
+ if (ad.alignsize == 0)
+ ad.alignsize = 1;
+ if (fieldWidth == 0)
+ {
+ if (fieldState.inFlight && !isunion)
+ {
+ const alsz = memsize;
+ fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+ ad.structsize = fieldState.offset;
+ }
+
+ fieldState.inFlight = false;
+ return;
+ }
}
- if (0 && target.os & Target.OS.Posix)
+ if (!fieldState.inFlight)
+ {
+ startNewField();
+ }
+ else if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
- if ((fieldState.offset%4 * 8) + fieldState.bitOffset + fieldWidth > int.sizeof * 8)
+ if (fieldState.bitOffset + fieldWidth > memsize * 8)
{
+ //printf("start1 fieldState.bitOffset:%u fieldWidth:%u memsize:%u\n", fieldState.bitOffset, fieldWidth, memsize);
startNewField();
}
+ else
+ {
+ // if alignment boundary is crossed
+ uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
+ uint end = start + fieldWidth;
+ //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
+ if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
+ {
+ //printf("alignment is crossed\n");
+ startNewField();
+ }
+ }
}
- else if (1 || target.os == Target.OS.Windows)
+ else if (style == TargetC.BitFieldStyle.DM ||
+ style == TargetC.BitFieldStyle.MS)
{
if (memsize != fieldState.fieldSize ||
fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
@@ -1799,22 +1895,29 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
startNewField();
}
}
+ else
+ assert(0);
offset = fieldState.fieldOffset;
bitOffset = fieldState.bitOffset;
- if (0 && target.os & Target.OS.Posix)
+
+ const pastField = bitOffset + fieldWidth;
+ if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
- while (bitOffset > memsize * 8)
- {
- bitOffset -= 8;
- offset += 1;
- }
+ auto size = (pastField + 7) / 8;
+ fieldState.fieldSize = size;
+ //printf(" offset: %d, size: %d\n", offset, size);
+ ad.structsize = offset + size;
}
+ else
+ fieldState.fieldSize = memsize;
+ //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
+ //print(fieldState);
- //fieldState.fieldSize = memsize;
if (!isunion)
{
- fieldState.bitOffset += fieldWidth;
+ fieldState.offset = offset + fieldState.fieldSize;
+ fieldState.bitOffset = pastField;
}
//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
@@ -1861,7 +1964,7 @@ extern (C++) class TypeInfoDeclaration : VarDeclaration
storage_class = STC.static_ | STC.gshared;
visibility = Visibility(Visibility.Kind.public_);
linkage = LINK.c;
- alignment = target.ptrsize;
+ alignment.set(target.ptrsize);
}
static TypeInfoDeclaration create(Type tinfo)
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 1c56def..4a4c353 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -188,7 +188,7 @@ public:
Dsymbol *overnext; // next in overload list
Dsymbol *_import; // !=NULL if unresolved internal alias for selective import
- static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
+ static AliasDeclaration *create(const Loc &loc, Identifier *id, Type *type);
AliasDeclaration *syntaxCopy(Dsymbol *);
bool overloadInsert(Dsymbol *s);
const char *kind() const;
@@ -511,7 +511,7 @@ enum class BUILTIN : unsigned char
toPrecReal
};
-Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments);
+Expression *eval_builtin(const Loc &loc, FuncDeclaration *fd, Expressions *arguments);
BUILTIN isBuiltin(FuncDeclaration *fd);
class FuncDeclaration : public Declaration
@@ -535,6 +535,8 @@ public:
VarDeclaration *vresult; // result variable for out contracts
LabelDsymbol *returnLabel; // where the return goes
+ void *isTypeIsolatedCache; // An AA on the D side to cache an expensive check result
+
// used to prevent symbols in different
// scopes from having the same name
DsymbolTable *localsymtab;
@@ -839,9 +841,6 @@ public:
class NewDeclaration : public FuncDeclaration
{
public:
- Parameters *parameters;
- VarArg varargs;
-
NewDeclaration *syntaxCopy(Dsymbol *);
const char *kind() const;
bool isVirtual() const;
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 541fac7..a1f36c0 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -42,6 +42,7 @@ import dmd.mtype;
import dmd.printast;
import dmd.root.rmem;
import dmd.root.array;
+import dmd.root.ctfloat;
import dmd.root.region;
import dmd.root.rootobject;
import dmd.statement;
@@ -75,6 +76,7 @@ public Expression ctfeInterpret(Expression e)
case TOK.template_: // non-eponymous template/instance
case TOK.scope_: // ditto
case TOK.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
+ case TOK.dotTemplateInstance: // ditto
case TOK.dot: // ditto
if (e.type.ty == Terror)
return ErrorExp.get();
@@ -2167,26 +2169,20 @@ public:
return;
}
- // Note: This is a workaround for
- // https://issues.dlang.org/show_bug.cgi?id=17351
- // The aforementioned bug triggers when passing manifest constant by `ref`.
- // If there was not a previous reference to them, they are
- // not cached and trigger a "cannot be read at compile time".
- // This fix is a crude solution to get it to work. A more proper
- // approach would be to resolve the forward reference, but that is
- // much more involved.
- if (goal == CTFEGoal.LValue && e.var.type.isMutable())
+ if (goal == CTFEGoal.LValue)
{
if (auto v = e.var.isVarDeclaration())
{
- if (!v.isDataseg() && !v.isCTFE() && !istate)
- {
- e.error("variable `%s` cannot be read at compile time", v.toChars());
- result = CTFEExp.cantexp;
- return;
- }
if (!hasValue(v))
{
+ // Compile-time known non-CTFE variable from an outer context
+ // e.g. global or from a ref argument
+ if (v.isConst() || v.isImmutable())
+ {
+ result = getVarExp(e.loc, istate, v, goal);
+ return;
+ }
+
if (!v.isCTFE() && v.isDataseg())
e.error("static variable `%s` cannot be read at compile time", v.toChars());
else // CTFE initiated from inside a function
@@ -2201,7 +2197,7 @@ public:
Expression ev = getValue(v);
if (ev.op == TOK.variable ||
ev.op == TOK.index ||
- ev.op == TOK.slice ||
+ (ev.op == TOK.slice && ev.type.toBasetype().ty == Tsarray) ||
ev.op == TOK.dotVariable)
{
result = interpret(pue, ev, istate, goal);
@@ -2836,8 +2832,7 @@ public:
auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
se.origin = se;
se.ownedByCtfe = OwnedBy.ctfe;
- emplaceExp!(ClassReferenceExp)(pue, e.loc, se, e.type);
- Expression eref = pue.exp();
+ Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
if (e.member)
{
// Call constructor
@@ -6024,12 +6019,23 @@ public:
}
if (e.to.ty == Tsarray)
e1 = resolveSlice(e1);
- if (e.to.toBasetype().ty == Tbool && e1.type.ty == Tpointer)
+
+ auto tobt = e.to.toBasetype();
+ if (tobt.ty == Tbool && e1.type.ty == Tpointer)
{
emplaceExp!(IntegerExp)(pue, e.loc, e1.op != TOK.null_, e.to);
result = pue.exp();
return;
}
+ else if (tobt.isTypeBasic() && e1.op == TOK.null_)
+ {
+ if (tobt.isintegral())
+ emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
+ else if (tobt.isreal())
+ emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
+ result = pue.exp();
+ return;
+ }
result = ctfeCast(pue, e.loc, e.type, e.to, e1);
}
@@ -6306,7 +6312,7 @@ public:
auto tsa = cast(TypeSArray)v.type;
auto len = cast(size_t)tsa.dim.toInteger();
UnionExp ue = void;
- result = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
+ result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
if (result == ue.exp())
result = ue.copy();
(*se.elements)[i] = result;
diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d
index ddfee2c..357f7bd 100644
--- a/gcc/d/dmd/dmacro.d
+++ b/gcc/d/dmd/dmacro.d
@@ -16,7 +16,7 @@ import core.stdc.string;
import dmd.doc;
import dmd.errors;
import dmd.globals;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
extern (C++) struct MacroTable
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index 71b8c7a..c417f93 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -139,7 +139,7 @@ import dmd.id;
import dmd.identifier;
import dmd.mtype;
import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.aav;
import dmd.root.string;
import dmd.root.stringtable;
@@ -1259,14 +1259,49 @@ public:
override void visit(Parameter p)
{
- if (p.storageClass & STC.scope_ && !(p.storageClass & STC.scopeinferred))
- buf.writeByte('M');
+ // https://dlang.org/spec/abi.html#Parameter
+
+ auto stc = p.storageClass;
+
+ // Inferred storage classes don't get mangled in
+ if (stc & STC.scopeinferred)
+ stc &= ~(STC.scope_ | STC.scopeinferred);
+ if (stc & STC.returninferred)
+ stc &= ~(STC.return_ | STC.returninferred);
// 'return inout ref' is the same as 'inout ref'
- if ((p.storageClass & (STC.return_ | STC.wild)) == STC.return_ &&
- !(p.storageClass & STC.returninferred))
- buf.writestring("Nk");
- switch (p.storageClass & (STC.IOR | STC.lazy_))
+ if ((stc & (STC.return_ | STC.wild)) == (STC.return_ | STC.wild))
+ stc &= ~STC.return_;
+
+ // much like hdrgen.stcToBuffer()
+ string rrs;
+ const isout = (stc & STC.out_) != 0;
+ final switch (buildScopeRef(stc))
+ {
+ case ScopeRef.None:
+ case ScopeRef.Scope:
+ case ScopeRef.Ref:
+ case ScopeRef.Return:
+ case ScopeRef.RefScope:
+ break;
+
+ case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope
+ case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref
+ case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref
+ case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref
+ L1:
+ buf.writestring(rrs);
+ stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
+ break;
+ }
+
+ if (stc & STC.scope_)
+ buf.writeByte('M'); // scope
+
+ if (stc & STC.return_)
+ buf.writestring("Nk"); // return
+
+ switch (stc & (STC.IOR | STC.lazy_))
{
case 0:
break;
@@ -1288,10 +1323,10 @@ public:
default:
debug
{
- printf("storageClass = x%llx\n", p.storageClass & (STC.IOR | STC.lazy_));
+ printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_));
}
assert(0);
}
- visitWithMask(p.type, (p.storageClass & STC.in_) ? MODFlags.const_ : 0);
+ visitWithMask(p.type, (stc & STC.in_) ? MODFlags.const_ : 0);
}
}
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 768eaa0..4e00713 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -31,6 +31,7 @@ import dmd.dsymbolsem;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
+import dmd.file_manager;
import dmd.globals;
import dmd.id;
import dmd.identifier;
@@ -39,7 +40,7 @@ import dmd.cparse;
import dmd.root.array;
import dmd.root.file;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.port;
import dmd.root.rmem;
import dmd.root.rootobject;
@@ -50,113 +51,6 @@ import dmd.target;
import dmd.utils;
import dmd.visitor;
-enum package_d = "package." ~ mars_ext;
-enum package_di = "package." ~ hdr_ext;
-
-/********************************************
- * Look for the source file if it's different from filename.
- * Look for .di, .d, directory, and along global.path.
- * Does not open the file.
- * Params:
- * filename = as supplied by the user
- * path = path to look for filename
- * Returns:
- * the found file name or
- * `null` if it is not different from filename.
- */
-private const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
-{
- //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
- /* Search along path[] for .di file, then .d file, then .i file, then .c file.
- */
- const sdi = FileName.forceExt(filename, hdr_ext);
- if (FileName.exists(sdi) == 1)
- return sdi;
- scope(exit) FileName.free(sdi.ptr);
-
- const sd = FileName.forceExt(filename, mars_ext);
- if (FileName.exists(sd) == 1)
- return sd;
- scope(exit) FileName.free(sd.ptr);
-
- const si = FileName.forceExt(filename, i_ext);
- if (FileName.exists(si) == 1)
- return si;
- scope(exit) FileName.free(si.ptr);
-
- const sc = FileName.forceExt(filename, c_ext);
- if (FileName.exists(sc) == 1)
- return sc;
- scope(exit) FileName.free(sc.ptr);
-
- if (FileName.exists(filename) == 2)
- {
- /* The filename exists and it's a directory.
- * Therefore, the result should be: filename/package.d
- * iff filename/package.d is a file
- */
- const ni = FileName.combine(filename, package_di);
- if (FileName.exists(ni) == 1)
- return ni;
- FileName.free(ni.ptr);
-
- const n = FileName.combine(filename, package_d);
- if (FileName.exists(n) == 1)
- return n;
- FileName.free(n.ptr);
- }
- if (FileName.absolute(filename))
- return null;
- if (!path.length)
- return null;
- foreach (entry; path)
- {
- const p = entry.toDString();
-
- const(char)[] n = FileName.combine(p, sdi);
- if (FileName.exists(n) == 1) {
- return n;
- }
- FileName.free(n.ptr);
-
- n = FileName.combine(p, sd);
- if (FileName.exists(n) == 1) {
- return n;
- }
- FileName.free(n.ptr);
-
- n = FileName.combine(p, si);
- if (FileName.exists(n) == 1) {
- return n;
- }
- FileName.free(n.ptr);
-
- n = FileName.combine(p, sc);
- if (FileName.exists(n) == 1) {
- return n;
- }
- FileName.free(n.ptr);
-
- const b = FileName.removeExt(filename);
- n = FileName.combine(p, b);
- FileName.free(b.ptr);
- if (FileName.exists(n) == 2)
- {
- const n2i = FileName.combine(n, package_di);
- if (FileName.exists(n2i) == 1)
- return n2i;
- FileName.free(n2i.ptr);
- const n2 = FileName.combine(n, package_d);
- if (FileName.exists(n2) == 1) {
- return n2;
- }
- FileName.free(n2.ptr);
- }
- FileName.free(n.ptr);
- }
- return null;
-}
-
// function used to call semantic3 on a module's dependencies
void semantic3OnDependencies(Module m)
{
@@ -414,8 +308,8 @@ extern (C++) class Package : ScopeDsymbol
packages ~= s.ident;
reverse(packages);
- if (lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null))
- Module.load(Loc(), packages, this.ident);
+ if (FileManager.lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null))
+ Module.load(Loc.initial, packages, this.ident);
else
isPkgMod = PKG.package_;
}
@@ -598,12 +492,12 @@ extern (C++) final class Module : Package
return new Module(Loc.initial, filename, ident, doDocComment, doHdrGen);
}
- extern (C++) static Module load(Loc loc, Identifiers* packages, Identifier ident)
+ extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident)
{
return load(loc, packages ? (*packages)[] : null, ident);
}
- extern (D) static Module load(Loc loc, Identifier[] packages, Identifier ident)
+ extern (D) static Module load(const ref Loc loc, Identifier[] packages, Identifier ident)
{
//printf("Module::load(ident = '%s')\n", ident.toChars());
// Build module filename by turning:
@@ -612,7 +506,7 @@ extern (C++) final class Module : Package
// foo\bar\baz
const(char)[] filename = getFilename(packages, ident);
// Look for the source file
- if (const result = lookForSourceFile(filename, global.path ? (*global.path)[] : null))
+ if (const result = FileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null))
filename = result; // leaks
auto m = new Module(loc, filename, ident, 0, 0);
@@ -737,7 +631,12 @@ extern (C++) final class Module : Package
if (isPackageMod)
.error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars());
else
- error(loc, "is in file '%s' which cannot be read", srcfile.toChars());
+ {
+ .error(loc, "unable to read module `%s`", toChars());
+ const pkgfile = FileName.combine(FileName.removeExt(srcfile.toString()), package_d);
+ .errorSupplemental(loc, "Expected '%s' or '%s' in one of the following import paths:",
+ srcfile.toChars(), pkgfile.ptr);
+ }
}
if (!global.gag)
{
@@ -776,14 +675,25 @@ extern (C++) final class Module : Package
return true; // already read
//printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
- auto readResult = File.read(srcfile.toChars());
if (global.params.emitMakeDeps)
{
global.params.makeDeps.push(srcfile.toChars());
}
- return loadSourceBuffer(loc, readResult);
+ if (auto readResult = FileManager.fileManager.lookup(srcfile))
+ {
+ srcBuffer = readResult;
+ return true;
+ }
+
+ auto readResult = File.read(srcfile.toChars());
+ if (loadSourceBuffer(loc, readResult))
+ {
+ FileManager.fileManager.add(srcfile, srcBuffer);
+ return true;
+ }
+ return false;
}
/// syntactic parse
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index 9b4329b..f9b765c 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -45,7 +45,7 @@ import dmd.mtype;
import dmd.root.array;
import dmd.root.file;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.port;
import dmd.root.rmem;
import dmd.root.string;
@@ -3995,8 +3995,8 @@ private size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const r
const iDelimiterRowEnd = parseTableDelimiterRow(buf, iEnd + 1, inQuote, columnAlignments);
if (iDelimiterRowEnd)
{
- const delta = replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, true);
- if (delta)
+ size_t delta;
+ if (replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, true, delta))
{
buf.remove(iEnd + delta, iDelimiterRowEnd - iEnd);
buf.insert(iEnd + delta, "$(TBODY ");
@@ -4023,12 +4023,15 @@ private size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const r
* headerRow = if `true` then the number of columns will be enforced to match
* `columnAlignments.length` and the row will be surrounded by a
* `THEAD` macro
- * Returns: the number of characters added by replacing the row, or `0` if unchanged
+ * delta = the number of characters added by replacing the row, or `0` if unchanged
+ * Returns: `true` if a table row was found and replaced
*/
-private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow)
+private bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow, out size_t delta)
{
+ delta = 0;
+
if (!columnAlignments.length || iStart == iEnd)
- return 0;
+ return false;
iStart = skipChars(buf, iStart, " \t");
int cellCount = 0;
@@ -4045,7 +4048,7 @@ private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, co
++cellCount;
if (headerRow && cellCount != columnAlignments.length)
- return 0;
+ return false;
if (headerRow && global.params.vmarkdown)
{
@@ -4053,8 +4056,6 @@ private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, co
message(loc, "Ddoc: formatting table '%.*s'", cast(int)s.length, s.ptr);
}
- size_t delta = 0;
-
void replaceTableCell(size_t iCellStart, size_t iCellEnd, int cellIndex, int di)
{
const eDelta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, di);
@@ -4146,7 +4147,7 @@ private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, co
delta += 9;
}
- return delta;
+ return true;
}
/****************************************************
@@ -4182,7 +4183,8 @@ private size_t endTable(ref OutBuffer buf, size_t i, ref TableColumnAlignment[]
*/
private size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments)
{
- size_t delta = replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, false);
+ size_t delta;
+ replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, false, delta);
delta += endTable(buf, iEnd + delta, columnAlignments);
return delta;
}
@@ -4263,8 +4265,8 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s
i += startTable(buf, iLineStart, i, loc, lineQuoted, inlineDelimiters, columnAlignments);
else if (columnAlignments.length)
{
- const delta = replaceTableRow(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments, false);
- if (delta)
+ size_t delta;
+ if (replaceTableRow(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments, false, delta))
i += delta;
else
i += endTable(buf, i, columnAlignments);
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 638fc7e..42c0d18 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -33,7 +33,7 @@ import dmd.func;
import dmd.globals;
import dmd.id;
import dmd.identifier;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.speller;
import dmd.statement;
@@ -730,12 +730,21 @@ struct Scope
}
}
+ /******************************
+ */
structalign_t alignment()
{
if (aligndecl)
- return aligndecl.getAlignment(&this);
+ {
+ auto ad = aligndecl.getAlignment(&this);
+ return ad.salign;
+ }
else
- return STRUCTALIGN_DEFAULT;
+ {
+ structalign_t sa;
+ sa.setDefault();
+ return sa;
+ }
}
/**********************************
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 80ecd36..0925e7c 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -16,6 +16,7 @@ module dmd.dstruct;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.attrib;
import dmd.declaration;
import dmd.dmodule;
import dmd.dscope;
@@ -127,7 +128,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t)
*/
if (!sd.members)
return; // opaque struct
- if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd))
+ if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.tidtor && !sd.xhash && !search_toString(sd))
return; // none of TypeInfo-specific members
// If the struct is in a non-root module, run semantic3 to get
@@ -232,7 +233,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
}
}
- static StructDeclaration create(Loc loc, Identifier id, bool inObject)
+ static StructDeclaration create(const ref Loc loc, Identifier id, bool inObject)
{
return new StructDeclaration(loc, id, inObject);
}
@@ -297,22 +298,46 @@ extern (C++) class StructDeclaration : AggregateDeclaration
return;
}
- // 0 sized struct's are set to 1 byte
if (structsize == 0)
{
hasNoFields = true;
alignsize = 1;
- if (classKind != classKind.c) // C gets a struct size of 0
- structsize = 1;
+
+ // A fine mess of what size a zero sized struct should be
+ final switch (classKind)
+ {
+ case ClassKind.d:
+ case ClassKind.cpp:
+ structsize = 1;
+ break;
+
+ case ClassKind.c:
+ case ClassKind.objc:
+ if (target.c.bitFieldStyle == TargetC.BitFieldStyle.MS)
+ {
+ /* Undocumented MS behavior for:
+ * struct S { int :0; };
+ */
+ structsize = 4;
+ }
+ else if (target.c.bitFieldStyle == TargetC.BitFieldStyle.DM)
+ {
+ structsize = 0;
+ alignsize = 0;
+ }
+ else
+ structsize = 0;
+ break;
+ }
}
// Round struct size up to next alignsize boundary.
// This will ensure that arrays of structs will get their internals
// aligned properly.
- if (alignment == STRUCTALIGN_DEFAULT)
+ if (alignment.isDefault() || alignment.isPack())
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
else
- structsize = (structsize + alignment - 1) & ~(alignment - 1);
+ structsize = (structsize + alignment.get() - 1) & ~(alignment.get() - 1);
sizeok = Sizeok.done;
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 3a6dff2..9aa435d 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -187,7 +187,7 @@ struct Visibility
}
}
-enum PASS : int
+enum PASS : ubyte
{
init, // initial state
semantic, // semantic() started
@@ -225,11 +225,13 @@ enum : int
*/
struct FieldState
{
- uint offset; /// offset for next field
+ uint offset; /// byte offset for next field
- uint fieldOffset; /// offset for the start of the bit field
+ uint fieldOffset; /// byte offset for the start of the bit field
+ uint fieldSize; /// byte size of field
+ uint fieldAlign; /// byte alignment of field
uint bitOffset; /// bit offset for field
- uint fieldSize; /// size of field in bytes
+
bool inFlight; /// bit field is in flight
}
@@ -793,10 +795,18 @@ extern (C++) class Dsymbol : ASTNode
Dsymbol s2 = sds.symtabLookup(this,ident);
// If using C tag/prototype/forward declaration rules
- if (sc.flags & SCOPE.Cfile &&
- handleTagSymbols(*sc, this, s2, sds))
+ if (sc.flags & SCOPE.Cfile)
+ {
+ if (handleTagSymbols(*sc, this, s2, sds))
+ return;
+ if (handleSymbolRedeclarations(*sc, this, s2, sds))
return;
+ sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading
+ errors = true;
+ return;
+ }
+
if (!s2.overloadInsert(this))
{
sds.multiplyDefined(Loc.initial, this, s2);
@@ -2384,3 +2394,91 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
}
+/**********************************************
+ * ImportC allows redeclarations of C variables, functions and typedefs.
+ * extern int x;
+ * int x = 3;
+ * and:
+ * extern void f();
+ * void f() { }
+ * Attempt to merge them.
+ * Params:
+ * sc = context
+ * s = symbol to add to symbol table
+ * s2 = existing declaration
+ * sds = symbol table
+ * Returns:
+ * if s and s2 are successfully put in symbol table then return the merged symbol,
+ * null if they conflict
+ */
+Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
+{
+ enum log = false;
+ if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
+
+ static Dsymbol collision()
+ {
+ if (log) printf(" collision\n");
+ return null;
+ }
+
+ auto vd = s.isVarDeclaration(); // new declaration
+ auto vd2 = s2.isVarDeclaration(); // existing declaration
+ if (vd && vd2)
+ {
+ // if one is `static` and the other isn't
+ if ((vd.storage_class ^ vd2.storage_class) & STC.static_)
+ return collision();
+
+ const i1 = vd._init && ! vd._init.isVoidInitializer();
+ const i2 = vd2._init && !vd2._init.isVoidInitializer();
+
+ if (i1 && i2)
+ return collision(); // can't both have initializers
+
+ if (i1)
+ return vd;
+
+ /* BUG: the types should match, which needs semantic() to be run on it
+ * extern int x;
+ * int x; // match
+ * typedef int INT;
+ * INT x; // match
+ * long x; // collision
+ * We incorrectly ignore these collisions
+ */
+ return vd2;
+ }
+
+ auto fd = s.isFuncDeclaration(); // new declaration
+ auto fd2 = s2.isFuncDeclaration(); // existing declaration
+ if (fd && fd2)
+ {
+ // if one is `static` and the other isn't
+ if ((fd.storage_class ^ fd2.storage_class) & STC.static_)
+ return collision();
+
+ if (fd.fbody && fd2.fbody)
+ return collision(); // can't both have bodies
+
+ if (fd.fbody)
+ return fd;
+
+ /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
+ * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
+ */
+ return fd2;
+ }
+
+ auto td = s.isAliasDeclaration(); // new declaration
+ auto td2 = s2.isAliasDeclaration(); // existing declaration
+ if (td && td2)
+ {
+ /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
+ * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
+ */
+ return td2;
+ }
+
+ return collision();
+}
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index f43bc83..02252fd 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -108,7 +108,21 @@ struct Visibility
/* State of symbol in winding its way through the passes of the compiler
*/
-enum PASS
+enum class PASS : uint8_t
+{
+ init, // initial state
+ semantic, // semantic() started
+ semanticdone, // semantic() done
+ semantic2, // semantic2() started
+ semantic2done, // semantic2() done
+ semantic3, // semantic3() started
+ semantic3done, // semantic3() done
+ inline_, // inline started
+ inlinedone, // inline done
+ obj // toObjFile() run
+};
+
+enum
{
PASSinit, // initial state
PASSsemantic, // semantic() started
@@ -145,8 +159,10 @@ struct FieldState
unsigned offset;
unsigned fieldOffset;
+ unsigned fieldSize;
+ unsigned fieldAlign;
unsigned bitOffset;
- unsigned fieldSice;
+
bool inFlight;
};
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index eac2095..047c1eb 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -56,7 +56,7 @@ import dmd.objc;
import dmd.opover;
import dmd.parse;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.rootobject;
import dmd.semantic2;
@@ -109,17 +109,18 @@ extern(C++) void dsymbolSemantic(Dsymbol dsym, Scope* sc)
* ad = AlignmentDeclaration
* sc = context
* Returns:
- * alignment as numerical value that is never 0.
- * STRUCTALIGN_DEFAULT is used instead.
- * STRUCTALIGN_DEFAULT is returned for errors
+ * ad with alignment value determined
*/
-structalign_t getAlignment(AlignDeclaration ad, Scope* sc)
+AlignDeclaration getAlignment(AlignDeclaration ad, Scope* sc)
{
- if (ad.salign != ad.UNKNOWN) // UNKNOWN is 0
- return ad.salign;
+ if (!ad.salign.isUnknown()) // UNKNOWN is 0
+ return ad;
if (!ad.exps)
- return ad.salign = STRUCTALIGN_DEFAULT;
+ {
+ ad.salign.setDefault();
+ return ad;
+ }
dinteger_t strictest = 0; // strictest alignment
bool errors;
@@ -140,7 +141,7 @@ structalign_t getAlignment(AlignDeclaration ad, Scope* sc)
if (sc.flags & SCOPE.Cfile && n == 0) // C11 6.7.5-6 allows 0 for alignment
continue;
- if (n < 1 || n & (n - 1) || structalign_t.max < n || !e.type.isintegral())
+ if (n < 1 || n & (n - 1) || ushort.max < n || !e.type.isintegral())
{
error(ad.loc, "alignment must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
errors = true;
@@ -150,10 +151,12 @@ structalign_t getAlignment(AlignDeclaration ad, Scope* sc)
}
}
- ad.salign = (errors || strictest == 0) // C11 6.7.5-6 says alignment of 0 means no effect
- ? STRUCTALIGN_DEFAULT
- : cast(structalign_t) strictest;
- return ad.salign;
+ if (errors || strictest == 0) // C11 6.7.5-6 says alignment of 0 means no effect
+ ad.salign.setDefault();
+ else
+ ad.salign.set(cast(uint) strictest);
+
+ return ad;
}
const(char)* getMessage(DeprecatedDeclaration dd)
@@ -365,16 +368,31 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
dsym.semanticRun = PASS.semantic;
- /* Pick up storage classes from context, but except synchronized,
- * override, abstract, and final.
- */
- dsym.storage_class |= (sc.stc & ~(STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_));
+ // 'static foreach' variables should not inherit scope properties
+ // https://issues.dlang.org/show_bug.cgi?id=19482
+ if ((dsym.storage_class & (STC.foreach_ | STC.local)) == (STC.foreach_ | STC.local))
+ {
+ dsym.linkage = LINK.d;
+ dsym.visibility = Visibility(Visibility.Kind.public_);
+ dsym.overlapped = false; // unset because it is modified early on this function
+ dsym.userAttribDecl = null; // unset because it is set by Dsymbol.setScope()
+ }
+ else
+ {
+ /* Pick up storage classes from context, but except synchronized,
+ * override, abstract, and final.
+ */
+ dsym.storage_class |= (sc.stc & ~(STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_));
+ dsym.userAttribDecl = sc.userAttribDecl;
+ dsym.cppnamespace = sc.namespace;
+ dsym.linkage = sc.linkage;
+ dsym.visibility = sc.visibility;
+ dsym.alignment = sc.alignment();
+ }
+
if (dsym.storage_class & STC.extern_ && dsym._init)
dsym.error("extern symbols cannot have initializers");
- dsym.userAttribDecl = sc.userAttribDecl;
- dsym.cppnamespace = sc.namespace;
-
AggregateDeclaration ad = dsym.isThis();
if (ad)
dsym.storage_class |= ad.storage_class & STC.TYPECTOR;
@@ -431,16 +449,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
dsym.errors = true;
dsym.type.checkDeprecated(dsym.loc, sc);
- dsym.linkage = sc.linkage;
dsym.parent = sc.parent;
//printf("this = %p, parent = %p, '%s'\n", dsym, dsym.parent, dsym.parent.toChars());
- dsym.visibility = sc.visibility;
/* If scope's alignment is the default, use the type's alignment,
* otherwise the scope overrrides.
*/
- dsym.alignment = sc.alignment();
- if (dsym.alignment == STRUCTALIGN_DEFAULT)
+ if (dsym.alignment.isDefault())
dsym.alignment = dsym.type.alignment(); // use type's alignment
//printf("sc.stc = %x\n", sc.stc);
@@ -935,6 +950,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc = sc.push();
sc.stc &= ~(STC.TYPECTOR | STC.pure_ | STC.nothrow_ | STC.nogc | STC.ref_ | STC.disable);
+ if (sc.flags & SCOPE.Cfile &&
+ dsym.type.isTypeSArray() &&
+ dsym.type.isTypeSArray().isIncomplete() &&
+ dsym._init.isVoidInitializer() &&
+ !(dsym.storage_class & STC.field))
+ {
+ dsym.error("incomplete array type must have initializer");
+ }
+
ExpInitializer ei = dsym._init.isExpInitializer();
if (ei) // https://issues.dlang.org/show_bug.cgi?id=13424
@@ -971,6 +995,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ei = new ExpInitializer(dsym._init.loc, e);
dsym._init = ei;
}
+ else if (sc.flags & SCOPE.Cfile && dsym.type.isTypeSArray() &&
+ dsym.type.isTypeSArray().isIncomplete())
+ {
+ // C11 6.7.9-22 determine the size of the incomplete array,
+ // or issue an error that the initializer is invalid.
+ dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret);
+ }
Expression exp = ei.exp;
Expression e1 = new VarExp(dsym.loc, dsym);
@@ -1056,18 +1087,29 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// could crash (inf. recursion) on a mod/pkg referencing itself
if (ei && (ei.exp.op != TOK.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage()))
{
- Expression exp = ei.exp.syntaxCopy();
-
- bool needctfe = dsym.isDataseg() || (dsym.storage_class & STC.manifest);
- if (needctfe)
- sc = sc.startCTFE();
- exp = exp.expressionSemantic(sc);
- exp = resolveProperties(sc, exp);
- if (needctfe)
- sc = sc.endCTFE();
+ if (ei.exp.type)
+ {
+ // If exp is already resolved we are done, our original init exp
+ // could have a type painting that we need to respect
+ // e.g. ['a'] typed as string, or [['z'], ""] as string[]
+ // See https://issues.dlang.org/show_bug.cgi?id=15711
+ }
+ else
+ {
+ Expression exp = ei.exp.syntaxCopy();
+
+ bool needctfe = dsym.isDataseg() || (dsym.storage_class & STC.manifest);
+ if (needctfe)
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ if (needctfe)
+ sc = sc.endCTFE();
+ ei.exp = exp;
+ }
Type tb2 = dsym.type.toBasetype();
- Type ti = exp.type.toBasetype();
+ Type ti = ei.exp.type.toBasetype();
/* The problem is the following code:
* struct CopyTest {
@@ -1091,11 +1133,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (sd.postblit && tb2.toDsymbol(null) == sd)
{
// The only allowable initializer is a (non-copy) constructor
- if (exp.isLvalue())
+ if (ei.exp.isLvalue())
dsym.error("of type struct `%s` uses `this(this)`, which is not allowed in static initialization", tb2.toChars());
}
}
- ei.exp = exp;
}
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret);
@@ -1708,6 +1749,36 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
if (pd.args && pd.args.dim != 0)
pd.error("takes no argument");
+ else
+ {
+ immutable isCtor = pd.ident == Id.crt_constructor;
+
+ static uint recurse(Dsymbol s, bool isCtor)
+ {
+ if (auto ad = s.isAttribDeclaration())
+ {
+ uint nestedCount;
+ auto decls = ad.include(null);
+ if (decls)
+ {
+ for (size_t i = 0; i < decls.dim; ++i)
+ nestedCount += recurse((*decls)[i], isCtor);
+ }
+ return nestedCount;
+ }
+ else if (auto f = s.isFuncDeclaration())
+ {
+ f.isCrtCtorDtor |= isCtor ? 1 : 2;
+ return 1;
+ }
+ else
+ return 0;
+ assert(0);
+ }
+
+ if (recurse(pd, isCtor) > 1)
+ pd.error("can only apply to a single declaration");
+ }
return declarations();
}
else if (pd.ident == Id.printf || pd.ident == Id.scanf)
@@ -2445,6 +2516,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
tempdecl.parent = sc.parent;
tempdecl.visibility = sc.visibility;
+ tempdecl.userAttribDecl = sc.userAttribDecl;
tempdecl.cppnamespace = sc.namespace;
tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_);
tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_);
@@ -2973,6 +3045,16 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (auto pragmadecl = sc.inlining)
funcdecl.inlining = pragmadecl.evalPragmaInline(sc);
+ // check pragma(crt_constructor)
+ if (funcdecl.isCrtCtorDtor)
+ {
+ if (funcdecl.linkage != LINK.c)
+ {
+ funcdecl.error("must be `extern(C)` for `pragma(%s)`",
+ funcdecl.isCrtCtorDtor == 1 ? "crt_constructor".ptr : "crt_destructor".ptr);
+ }
+ }
+
funcdecl.visibility = sc.visibility;
funcdecl.userAttribDecl = sc.userAttribDecl;
UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl.linkage);
@@ -3799,6 +3881,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
+ if (funcdecl.fbody && sc._module.isRoot() &&
+ (funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain()))
+ global.hasMainFunction = true;
+
if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot())
{
// check if `_d_cmain` is defined
@@ -3995,7 +4081,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
return;
}
if (dd.ident == Id.dtor && dd.semanticRun < PASS.semantic)
- ad.dtors.push(dd);
+ ad.userDtors.push(dd);
if (!dd.type)
{
dd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, dd.storage_class);
@@ -4417,8 +4503,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// Look for the constructor
sd.ctor = sd.searchCtor();
- sd.dtor = buildDtor(sd, sc2);
- sd.tidtor = buildExternDDtor(sd, sc2);
+ buildDtors(sd, sc2);
+
sd.hasCopyCtor = buildCopyCtor(sd, sc2);
sd.postblit = buildPostBlit(sd, sc2);
@@ -5057,8 +5143,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
- cldec.dtor = buildDtor(cldec, sc2);
- cldec.tidtor = buildExternDDtor(cldec, sc2);
+ buildDtors(cldec, sc2);
if (cldec.classKind == ClassKind.cpp && cldec.cppDtorVtblIndex != -1)
{
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index c3503bb..9d7957a 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -67,7 +67,7 @@ import dmd.initsem;
import dmd.mtype;
import dmd.opover;
import dmd.root.array;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.semantic2;
import dmd.semantic3;
@@ -985,9 +985,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
buf.writenl();
buf.writestring(" ");
}
- buf.write((*parameters)[i]);
+ write(buf, (*parameters)[i]);
buf.writestring(" = ");
- buf.write(tiargs[i]);
+ write(buf, tiargs[i]);
}
// write remaining variadic arguments on the last line
if (variadic)
@@ -998,16 +998,16 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
buf.writenl();
buf.writestring(" ");
}
- buf.write((*parameters)[end]);
+ write(buf, (*parameters)[end]);
buf.writestring(" = ");
buf.writeByte('(');
if (cast(int)tiargs.length - end > 0)
{
- buf.write(tiargs[end]);
+ write(buf, tiargs[end]);
foreach (j; parameters.length .. tiargs.length)
{
buf.writestring(", ");
- buf.write(tiargs[j]);
+ write(buf, tiargs[j]);
}
}
buf.writeByte(')');
@@ -1919,8 +1919,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
/* If a semantic error occurs while doing alias this,
* eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
* just regard it as not a match.
- */
- if (auto e = resolveAliasThis(sc, farg, true))
+ *
+ * We also save/restore sc.func.flags to avoid messing up
+ * attribute inference in the evaluation.
+ */
+ const oldflags = sc.func ? sc.func.flags : 0;
+ auto e = resolveAliasThis(sc, farg, true);
+ if (sc.func)
+ sc.func.flags = oldflags;
+ if (e)
{
farg = e;
goto Lretry;
@@ -5340,7 +5347,7 @@ extern (C++) class TemplateParameter : ASTNode
abstract RootObject specialization();
- abstract RootObject defaultArg(Loc instLoc, Scope* sc);
+ abstract RootObject defaultArg(const ref Loc instLoc, Scope* sc);
abstract bool hasDefaultArg();
@@ -5422,7 +5429,7 @@ extern (C++) class TemplateTypeParameter : TemplateParameter
return specType;
}
- override final RootObject defaultArg(Loc instLoc, Scope* sc)
+ override final RootObject defaultArg(const ref Loc instLoc, Scope* sc)
{
Type t = defaultType;
if (t)
@@ -5541,7 +5548,7 @@ extern (C++) final class TemplateValueParameter : TemplateParameter
return specValue;
}
- override RootObject defaultArg(Loc instLoc, Scope* sc)
+ override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
{
Expression e = defaultValue;
if (e)
@@ -5640,7 +5647,7 @@ extern (C++) final class TemplateAliasParameter : TemplateParameter
return specAlias;
}
- override RootObject defaultArg(Loc instLoc, Scope* sc)
+ override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
{
RootObject da = defaultAlias;
Type ta = isType(defaultAlias);
@@ -5741,7 +5748,7 @@ extern (C++) final class TemplateTupleParameter : TemplateParameter
return null;
}
- override RootObject defaultArg(Loc instLoc, Scope* sc)
+ override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
{
return null;
}
@@ -8413,3 +8420,11 @@ private struct MATCHpair
this.mfa = mfa;
}
}
+
+private void write(ref OutBuffer buf, RootObject obj)
+{
+ if (obj)
+ {
+ buf.writestring(obj.toChars());
+ }
+}
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 28054d0..e19adfc 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -17,6 +17,7 @@ import core.stdc.ctype;
import dmd.astcodegen;
import dmd.arraytypes;
+import dmd.attrib;
import dmd.dsymbol;
import dmd.errors;
import dmd.globals;
@@ -25,7 +26,7 @@ import dmd.root.filename;
import dmd.visitor;
import dmd.tokens;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.utils;
//debug = Debug_DtoH;
@@ -254,7 +255,7 @@ public:
Identifier ident;
/// Original type of the currently visited declaration
- AST.Type* origType;
+ AST.Type origType;
/// Last written visibility level applying to the current scope
AST.Visibility.Kind currentVisibility;
@@ -706,6 +707,10 @@ public:
// printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars());
visited[cast(void*)fd] = true;
+ // silently ignore non-user-defined destructors
+ if (fd.generated && fd.isDtorDeclaration())
+ return;
+
// Note that tf might be null for templated (member) functions
auto tf = cast(AST.TypeFunction)fd.type;
if ((tf && tf.linkage != LINK.c && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
@@ -841,12 +846,12 @@ public:
return;
if (vd.originalType && vd.type == AST.Type.tsize_t)
- origType = &vd.originalType;
+ origType = vd.originalType;
scope(exit) origType = null;
- if (vd.alignment != STRUCTALIGN_DEFAULT)
+ if (!vd.alignment.isDefault())
{
- buf.printf("// Ignoring var %s alignment %u", vd.toChars(), vd.alignment);
+ buf.printf("// Ignoring var %s alignment %d", vd.toChars(), vd.alignment.get());
buf.writenl();
}
@@ -1008,12 +1013,12 @@ public:
if (ad.originalType && ad.type.ty == AST.Tpointer &&
(cast(AST.TypePointer)t).nextOf.ty == AST.Tfunction)
{
- origType = &ad.originalType;
+ origType = ad.originalType;
}
scope(exit) origType = null;
buf.writestring("typedef ");
- typeToBuffer(origType ? *origType : t, ad);
+ typeToBuffer(origType !is null ? origType : t, ad);
writeDeclEnd();
return;
}
@@ -1346,7 +1351,7 @@ public:
/// Starts a custom alignment section using `#pragma pack` if
/// `alignment` specifies a custom alignment
- private void pushAlignToBuffer(uint alignment)
+ private void pushAlignToBuffer(structalign_t alignment)
{
// DMD ensures alignment is a power of two
//assert(alignment > 0 && ((alignment & (alignment - 1)) == 0),
@@ -1354,20 +1359,20 @@ public:
// When no alignment is specified, `uint.max` is the default
// FIXME: alignment is 0 for structs templated members
- if (alignment == STRUCTALIGN_DEFAULT || (tdparent && alignment == 0))
+ if (alignment.isDefault() || (tdparent && alignment.isUnknown()))
{
return;
}
- buf.printf("#pragma pack(push, %d)", alignment);
+ buf.printf("#pragma pack(push, %d)", alignment.get());
buf.writenl();
}
/// Ends a custom alignment section using `#pragma pack` if
/// `alignment` specifies a custom alignment
- private void popAlignToBuffer(uint alignment)
+ private void popAlignToBuffer(structalign_t alignment)
{
- if (alignment == STRUCTALIGN_DEFAULT || (tdparent && alignment == 0))
+ if (alignment.isDefault() || (tdparent && alignment.isUnknown()))
return;
buf.writestringln("#pragma pack(pop)");
@@ -1645,7 +1650,7 @@ public:
}
this.ident = s.ident;
- auto type = origType ? *origType : t;
+ auto type = origType !is null ? origType : t;
AST.Dsymbol customLength;
// Check for quirks that are usually resolved during semantic
diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d
index 0dff754..49ee4b3 100644
--- a/gcc/d/dmd/dversion.d
+++ b/gcc/d/dmd/dversion.d
@@ -22,7 +22,7 @@ import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.globals;
import dmd.identifier;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.visitor;
/***********************************************************
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 0d6fa1e..2a62332 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -59,7 +59,7 @@ import dmd.opover;
import dmd.optimize;
import dmd.root.ctfloat;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.rootobject;
import dmd.root.string;
@@ -1201,20 +1201,14 @@ extern (C++) abstract class Expression : ASTNode
// DtorDeclaration without parents should fail at an earlier stage
auto ad = cast(AggregateDeclaration) f.toParent2();
assert(ad);
- assert(ad.dtors.length);
- // Search for the user-defined destructor (if any)
- foreach(dtor; ad.dtors)
+ if (ad.userDtors.dim)
{
- if (dtor.generated)
- continue;
-
- if (!check(dtor)) // doesn't match check (e.g. is impure as well)
+ if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well)
return;
// Sanity check
- assert(!check(cast(DtorDeclaration) ad.fieldDtor));
- break;
+ assert(!check(ad.fieldDtor));
}
dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
@@ -1781,13 +1775,13 @@ extern (C++) final class IntegerExp : Expression
this.value = cast(d_int32)value;
}
- static IntegerExp create(Loc loc, dinteger_t value, Type type)
+ static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
{
return new IntegerExp(loc, value, type);
}
// Same as create, but doesn't allocate memory.
- static void emplace(UnionExp* pue, Loc loc, dinteger_t value, Type type)
+ static void emplace(UnionExp* pue, const ref Loc loc, dinteger_t value, Type type)
{
emplaceExp!(IntegerExp)(pue, loc, value, type);
}
@@ -2052,13 +2046,13 @@ extern (C++) final class RealExp : Expression
this.type = type;
}
- static RealExp create(Loc loc, real_t value, Type type)
+ static RealExp create(const ref Loc loc, real_t value, Type type)
{
return new RealExp(loc, value, type);
}
// Same as create, but doesn't allocate memory.
- static void emplace(UnionExp* pue, Loc loc, real_t value, Type type)
+ static void emplace(UnionExp* pue, const ref Loc loc, real_t value, Type type)
{
emplaceExp!(RealExp)(pue, loc, value, type);
}
@@ -2127,13 +2121,13 @@ extern (C++) final class ComplexExp : Expression
//printf("ComplexExp::ComplexExp(%s)\n", toChars());
}
- static ComplexExp create(Loc loc, complex_t value, Type type)
+ static ComplexExp create(const ref Loc loc, complex_t value, Type type)
{
return new ComplexExp(loc, value, type);
}
// Same as create, but doesn't allocate memory.
- static void emplace(UnionExp* pue, Loc loc, complex_t value, Type type)
+ static void emplace(UnionExp* pue, const ref Loc loc, complex_t value, Type type)
{
emplaceExp!(ComplexExp)(pue, loc, value, type);
}
@@ -2203,7 +2197,7 @@ extern (C++) class IdentifierExp : Expression
this.ident = ident;
}
- static IdentifierExp create(Loc loc, Identifier ident)
+ static IdentifierExp create(const ref Loc loc, Identifier ident)
{
return new IdentifierExp(loc, ident);
}
@@ -2421,28 +2415,28 @@ extern (C++) final class StringExp : Expression
this.postfix = postfix;
}
- static StringExp create(Loc loc, char* s)
+ static StringExp create(const ref Loc loc, const(char)* s)
{
return new StringExp(loc, s.toDString());
}
- static StringExp create(Loc loc, void* string, size_t len)
+ static StringExp create(const ref Loc loc, const(void)* string, size_t len)
{
return new StringExp(loc, string[0 .. len]);
}
// Same as create, but doesn't allocate memory.
- static void emplace(UnionExp* pue, Loc loc, char* s)
+ static void emplace(UnionExp* pue, const ref Loc loc, const(char)* s)
{
emplaceExp!(StringExp)(pue, loc, s.toDString());
}
- extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string)
+ extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string)
{
emplaceExp!(StringExp)(pue, loc, string);
}
- extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
+ extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
{
emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
}
@@ -2863,7 +2857,7 @@ extern (C++) final class TupleExp : Expression
}
}
- static TupleExp create(Loc loc, Expressions* exps)
+ static TupleExp create(const ref Loc loc, Expressions* exps)
{
return new TupleExp(loc, exps);
}
@@ -2946,13 +2940,13 @@ extern (C++) final class ArrayLiteralExp : Expression
this.elements = elements;
}
- static ArrayLiteralExp create(Loc loc, Expressions* elements)
+ static ArrayLiteralExp create(const ref Loc loc, Expressions* elements)
{
return new ArrayLiteralExp(loc, null, elements);
}
// Same as create, but doesn't allocate memory.
- static void emplace(UnionExp* pue, Loc loc, Expressions* elements)
+ static void emplace(UnionExp* pue, const ref Loc loc, Expressions* elements)
{
emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
}
@@ -3188,7 +3182,7 @@ extern (C++) final class StructLiteralExp : Expression
//printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
}
- static StructLiteralExp create(Loc loc, StructDeclaration sd, void* elements, Type stype = null)
+ static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
{
return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
}
@@ -3532,7 +3526,7 @@ extern (C++) final class NewExp : Expression
this.arguments = arguments;
}
- static NewExp create(Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
+ static NewExp create(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
{
return new NewExp(loc, thisexp, newargs, newtype, arguments);
}
@@ -3653,7 +3647,7 @@ extern (C++) final class VarExp : SymbolExp
this.type = var.type;
}
- static VarExp create(Loc loc, Declaration var, bool hasOverloads = true)
+ static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true)
{
return new VarExp(loc, var, hasOverloads);
}
@@ -3965,6 +3959,7 @@ extern (C++) final class FuncExp : Expression
auto tfy = new TypeFunction(tfx.parameterList, tof.next,
tfx.linkage, STC.undefined_);
tfy.mod = tfx.mod;
+ tfy.trust = tfx.trust;
tfy.isnothrow = tfx.isnothrow;
tfy.isnogc = tfx.isnogc;
tfy.purity = tfx.purity;
@@ -4688,6 +4683,7 @@ extern (C++) final class DotIdExp : UnaExp
Identifier ident;
bool noderef; // true if the result of the expression will never be dereferenced
bool wantsym; // do not replace Symbol with its initializer during semantic()
+ bool arrow; // ImportC: if -> instead of .
extern (D) this(const ref Loc loc, Expression e, Identifier ident)
{
@@ -4695,7 +4691,7 @@ extern (C++) final class DotIdExp : UnaExp
this.ident = ident;
}
- static DotIdExp create(Loc loc, Expression e, Identifier ident)
+ static DotIdExp create(const ref Loc loc, Expression e, Identifier ident)
{
return new DotIdExp(loc, e, ident);
}
@@ -4889,6 +4885,31 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
return ti.updateTempDecl(sc, s);
}
+ override bool checkType()
+ {
+ // Same logic as ScopeExp.checkType()
+ if (ti.tempdecl &&
+ ti.semantictiargsdone &&
+ ti.semanticRun == PASS.init)
+ {
+ error("partial %s `%s` has no type", ti.kind(), toChars());
+ return true;
+ }
+ return false;
+ }
+
+ override bool checkValue()
+ {
+ if (ti.tempdecl &&
+ ti.semantictiargsdone &&
+ ti.semanticRun == PASS.init)
+
+ error("partial %s `%s` has no value", ti.kind(), toChars());
+ else
+ error("%s `%s` has no value", ti.kind(), ti.toChars());
+ return true;
+ }
+
override void accept(Visitor v)
{
v.visit(this);
@@ -4987,17 +5008,17 @@ extern (C++) final class CallExp : UnaExp
this.f = fd;
}
- static CallExp create(Loc loc, Expression e, Expressions* exps)
+ static CallExp create(const ref Loc loc, Expression e, Expressions* exps)
{
return new CallExp(loc, e, exps);
}
- static CallExp create(Loc loc, Expression e)
+ static CallExp create(const ref Loc loc, Expression e)
{
return new CallExp(loc, e);
}
- static CallExp create(Loc loc, Expression e, Expression earg1)
+ static CallExp create(const ref Loc loc, Expression e, Expression earg1)
{
return new CallExp(loc, e, earg1);
}
@@ -5009,7 +5030,7 @@ extern (C++) final class CallExp : UnaExp
* fd = the declaration of the function to call
* earg1 = the function argument
*/
- static CallExp create(Loc loc, FuncDeclaration fd, Expression earg1)
+ static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
{
return new CallExp(loc, fd, earg1);
}
@@ -5167,6 +5188,19 @@ extern (C++) final class PtrExp : UnaExp
override Expression modifiableLvalue(Scope* sc, Expression e)
{
//printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
+ Declaration var;
+ if (auto se = e1.isSymOffExp())
+ var = se.var;
+ else if (auto ve = e1.isVarExp())
+ var = ve.var;
+ if (var && var.type.isFunction_Delegate_PtrToFunction())
+ {
+ if (var.type.isTypeFunction())
+ error("function `%s` is not an lvalue and cannot be modified", var.toChars());
+ else
+ error("function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
+ return ErrorExp.get();
+ }
return Expression.modifiableLvalue(sc, e);
}
@@ -5331,13 +5365,13 @@ extern (C++) final class VectorExp : UnaExp
to = cast(TypeVector)t;
}
- static VectorExp create(Loc loc, Expression e, Type t)
+ static VectorExp create(const ref Loc loc, Expression e, Type t)
{
return new VectorExp(loc, e, t);
}
// Same as create, but doesn't allocate memory.
- static void emplace(UnionExp* pue, Loc loc, Expression e, Type type)
+ static void emplace(UnionExp* pue, const ref Loc loc, Expression e, Type type)
{
emplaceExp!(VectorExp)(pue, loc, e, type);
}
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index dec3713..691364c 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -57,6 +57,9 @@ enum
OWNEDcache // constant value cached for CTFE
};
+#define WANTvalue 0 // default
+#define WANTexpand 1 // expand const/immutable variables if possible
+
/**
* Specifies how the checkModify deals with certain situations
*/
@@ -239,8 +242,8 @@ class IntegerExp : public Expression
public:
dinteger_t value;
- static IntegerExp *create(Loc loc, dinteger_t value, Type *type);
- static void emplace(UnionExp *pue, Loc loc, dinteger_t value, Type *type);
+ static IntegerExp *create(const Loc &loc, dinteger_t value, Type *type);
+ static void emplace(UnionExp *pue, const Loc &loc, dinteger_t value, Type *type);
bool equals(const RootObject *o) const;
dinteger_t toInteger();
real_t toReal();
@@ -269,8 +272,8 @@ class RealExp : public Expression
public:
real_t value;
- static RealExp *create(Loc loc, real_t value, Type *type);
- static void emplace(UnionExp *pue, Loc loc, real_t value, Type *type);
+ static RealExp *create(const Loc &loc, real_t value, Type *type);
+ static void emplace(UnionExp *pue, const Loc &loc, real_t value, Type *type);
bool equals(const RootObject *o) const;
dinteger_t toInteger();
uinteger_t toUInteger();
@@ -286,8 +289,8 @@ class ComplexExp : public Expression
public:
complex_t value;
- static ComplexExp *create(Loc loc, complex_t value, Type *type);
- static void emplace(UnionExp *pue, Loc loc, complex_t value, Type *type);
+ static ComplexExp *create(const Loc &loc, complex_t value, Type *type);
+ static void emplace(UnionExp *pue, const Loc &loc, complex_t value, Type *type);
bool equals(const RootObject *o) const;
dinteger_t toInteger();
uinteger_t toUInteger();
@@ -303,7 +306,7 @@ class IdentifierExp : public Expression
public:
Identifier *ident;
- static IdentifierExp *create(Loc loc, Identifier *ident);
+ static IdentifierExp *create(const Loc &loc, Identifier *ident);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
@@ -365,10 +368,9 @@ public:
utf8_t postfix; // 'c', 'w', 'd'
OwnedBy ownedByCtfe;
- static StringExp *create(Loc loc, char *s);
- static StringExp *create(Loc loc, void *s, size_t len);
- static void emplace(UnionExp *pue, Loc loc, char *s);
- static void emplace(UnionExp *pue, Loc loc, void *s, size_t len);
+ static StringExp *create(const Loc &loc, const char *s);
+ static StringExp *create(const Loc &loc, const void *s, size_t len);
+ static void emplace(UnionExp *pue, const Loc &loc, const char *s);
bool equals(const RootObject *o) const;
StringExp *toStringExp();
StringExp *toUTF8(Scope *sc);
@@ -397,7 +399,7 @@ public:
*/
Expressions *exps;
- static TupleExp *create(Loc loc, Expressions *exps);
+ static TupleExp *create(const Loc &loc, Expressions *exps);
TupleExp *toTupleExp();
TupleExp *syntaxCopy();
bool equals(const RootObject *o) const;
@@ -412,8 +414,8 @@ public:
Expressions *elements;
OwnedBy ownedByCtfe;
- static ArrayLiteralExp *create(Loc loc, Expressions *elements);
- static void emplace(UnionExp *pue, Loc loc, Expressions *elements);
+ static ArrayLiteralExp *create(const Loc &loc, Expressions *elements);
+ static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements);
ArrayLiteralExp *syntaxCopy();
bool equals(const RootObject *o) const;
Expression *getElement(d_size_t i); // use opIndex instead
@@ -468,7 +470,7 @@ public:
bool isOriginal; // used when moving instances to indicate `this is this.origin`
OwnedBy ownedByCtfe;
- static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
+ static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
bool equals(const RootObject *o) const;
StructLiteralExp *syntaxCopy();
Expression *getField(Type *type, unsigned offset);
@@ -528,7 +530,7 @@ public:
bool onstack; // allocate on stack
bool thrownew; // this NewExp is the expression of a ThrowStatement
- static NewExp *create(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
+ static NewExp *create(const Loc &loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
NewExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
@@ -576,7 +578,7 @@ class VarExp : public SymbolExp
{
public:
bool delegateWasExtracted;
- static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true);
+ static VarExp *create(const Loc &loc, Declaration *var, bool hasOverloads = true);
bool equals(const RootObject *o) const;
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
@@ -746,8 +748,9 @@ public:
Identifier *ident;
bool noderef; // true if the result of the expression will never be dereferenced
bool wantsym; // do not replace Symbol with its initializer during semantic()
+ bool arrow; // ImportC: if -> instead of .
- static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
+ static DotIdExp *create(const Loc &loc, Expression *e, Identifier *ident);
void accept(Visitor *v) { v->visit(this); }
};
@@ -780,6 +783,8 @@ public:
DotTemplateInstanceExp *syntaxCopy();
bool findTempDecl(Scope *sc);
+ bool checkType();
+ bool checkValue();
void accept(Visitor *v) { v->visit(this); }
};
@@ -812,10 +817,10 @@ public:
bool ignoreAttributes; // don't enforce attributes (e.g. call @gc function in @nogc code)
VarDeclaration *vthis2; // container for multi-context
- static CallExp *create(Loc loc, Expression *e, Expressions *exps);
- static CallExp *create(Loc loc, Expression *e);
- static CallExp *create(Loc loc, Expression *e, Expression *earg1);
- static CallExp *create(Loc loc, FuncDeclaration *fd, Expression *earg1);
+ static CallExp *create(const Loc &loc, Expression *e, Expressions *exps);
+ static CallExp *create(const Loc &loc, Expression *e);
+ static CallExp *create(const Loc &loc, Expression *e, Expression *earg1);
+ static CallExp *create(const Loc &loc, FuncDeclaration *fd, Expression *earg1);
CallExp *syntaxCopy();
bool isLvalue();
@@ -893,8 +898,8 @@ public:
unsigned dim; // number of elements in the vector
OwnedBy ownedByCtfe;
- static VectorExp *create(Loc loc, Expression *e, Type *t);
- static void emplace(UnionExp *pue, Loc loc, Expression *e, Type *t);
+ static VectorExp *create(const Loc &loc, Expression *e, Type *t);
+ static void emplace(UnionExp *pue, const Loc &loc, Expression *e, Type *t);
VectorExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -1272,7 +1277,7 @@ public:
class GenericExp : Expression
{
- Expression cntlExp;
+ Expression *cntlExp;
Types *types;
Expressions *exps;
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 3b604af..8e152d6 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -43,12 +43,14 @@ import dmd.dtemplate;
import dmd.errors;
import dmd.escape;
import dmd.expression;
+import dmd.file_manager;
import dmd.func;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.imphint;
+import dmd.importc;
import dmd.init;
import dmd.initsem;
import dmd.inline;
@@ -62,7 +64,7 @@ import dmd.printast;
import dmd.root.ctfloat;
import dmd.root.file;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.root.string;
import dmd.semantic2;
@@ -1239,6 +1241,10 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
tthis = dve.e1.type;
goto Lfd;
}
+ else if (sc && sc.flags & SCOPE.Cfile && e1.op == TOK.variable && !e2)
+ {
+ // ImportC: do not implicitly call function if no ( ) are present
+ }
else if (e1.op == TOK.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
{
s = (cast(VarExp)e1).var;
@@ -1388,7 +1394,6 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
Type t0 = null;
Expression e0 = null;
- size_t j0 = ~0;
bool foundType;
for (size_t i = 0; i < exps.dim; i++)
@@ -1441,17 +1446,16 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
{
// https://issues.dlang.org/show_bug.cgi?id=21285
// Functions and delegates don't convert correctly with castTo below
- exps[j0] = condexp.e1;
+ exps[i] = condexp.e1;
e = condexp.e2;
}
else
{
// Convert to common type
- exps[j0] = condexp.e1.castTo(sc, condexp.type);
+ exps[i] = condexp.e1.castTo(sc, condexp.type);
e = condexp.e2.castTo(sc, condexp.type);
}
}
- j0 = i;
e0 = e;
t0 = e.type;
if (e.op != TOK.error)
@@ -1599,6 +1603,7 @@ private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool repo
{
Expression arg = (*exps)[i];
arg = resolveProperties(sc, arg);
+ arg = arg.arrayFuncConv(sc);
if (arg.op == TOK.type)
{
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
@@ -4297,7 +4302,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* expr.foo!(tiargs)(funcargs)
*/
Ldotti:
- if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type)
+ if (exp.e1.op == TOK.dotTemplateInstance)
{
DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1;
TemplateInstance ti = se.ti;
@@ -4352,7 +4357,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* We handle such earlier, so go back.
* Note that in the rewrite, we carefully did not run semantic() on e1
*/
- if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type)
+ if (exp.e1.op == TOK.dotTemplateInstance)
{
goto Ldotti;
}
@@ -4419,6 +4424,26 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (exp.e1.op == TOK.type && (sc && sc.flags & SCOPE.Cfile))
{
+ const numArgs = exp.arguments ? exp.arguments.length : 0;
+ if (e1org.parens && numArgs >= 1)
+ {
+ /* Ambiguous cases arise from CParser where there is not enough
+ * information to determine if we have a function call or a cast.
+ * ( type-name ) ( identifier ) ;
+ * ( identifier ) ( identifier ) ;
+ * If exp.e1 is a type-name, then this is a cast.
+ */
+ Expression arg;
+ foreach (a; (*exp.arguments)[])
+ {
+ arg = arg ? new CommaExp(a.loc, arg, a) : a;
+ }
+ auto t = exp.e1.isTypeExp().type;
+ auto e = new CastExp(exp.loc, arg, t);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+
/* Ambiguous cases arise from CParser where there is not enough
* information to determine if we have a function call or declaration.
* type-name ( identifier ) ;
@@ -4426,7 +4451,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* If exp.e1 is a type-name, then this is a declaration. C11 does not
* have type construction syntax, so don't convert this to a cast().
*/
- if (exp.arguments && exp.arguments.dim == 1)
+ if (numArgs == 1)
{
Expression arg = (*exp.arguments)[0];
if (auto ie = (*exp.arguments)[0].isIdentifierExp())
@@ -4638,15 +4663,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
UnaExp ue = cast(UnaExp)exp.e1;
- Expression ue1 = ue.e1;
- Expression ue1old = ue1; // need for 'right this' check
- VarDeclaration v;
- if (ue1.op == TOK.variable && (v = (cast(VarExp)ue1).var.isVarDeclaration()) !is null && v.needThis())
- {
- ue.e1 = new TypeExp(ue1.loc, ue1.type);
- ue1 = null;
- }
-
+ Expression ue1old = ue.e1; // need for 'right this' check
DotVarExp dve;
DotTemplateExp dte;
Dsymbol s;
@@ -4665,7 +4682,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
// Do overload resolution
- exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue1 ? ue1.type : null, exp.arguments, FuncResolveFlag.standard);
+ exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.arguments, FuncResolveFlag.standard);
if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
return setError();
@@ -4677,7 +4694,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto ad2 = b.sym;
ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
ue.e1 = ue.e1.expressionSemantic(sc);
- ue1 = ue.e1;
auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.dim);
assert(vi >= 0);
exp.f = ad2.vtbl[vi].isFuncDeclaration();
@@ -6036,17 +6052,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
{
- auto readResult = File.read(name);
- if (!readResult.success)
+ auto fileName = FileName(name.toDString);
+ if (auto fmResult = FileManager.fileManager.lookup(fileName))
{
- e.error("cannot read file `%s`", name);
- return setError();
+ se = new StringExp(e.loc, fmResult.data);
}
else
{
- // take ownership of buffer (probably leaking)
- auto data = readResult.extractSlice();
- se = new StringExp(e.loc, data);
+ auto readResult = File.read(name);
+ if (!readResult.success)
+ {
+ e.error("cannot read file `%s`", name);
+ return setError();
+ }
+ else
+ {
+ // take ownership of buffer (probably leaking)
+ auto data = readResult.extractSlice();
+ se = new StringExp(e.loc, data);
+
+ FileBuffer* fileBuffer = FileBuffer.create();
+ fileBuffer.data = data;
+ FileManager.fileManager.add(fileName, fileBuffer);
+ }
}
}
result = se.expressionSemantic(sc);
@@ -6357,7 +6385,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
return;
}
- exp.type = Type.tnoreturn;
+
+ // Only override the type when it isn't already some flavour of noreturn,
+ // e.g. when this assert was generated by defaultInitLiteral
+ if (!exp.type || !exp.type.isTypeNoreturn())
+ exp.type = Type.tnoreturn;
}
else
exp.type = Type.tvoid;
@@ -6374,12 +6406,53 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
//printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op));
}
+ if (exp.arrow) // ImportC only
+ exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
+
+ if (sc.flags & SCOPE.Cfile)
+ {
+ if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
+ {
+ // C11 6.5.3 says _Alignof only applies to types
+ Expression e;
+ Type t;
+ Dsymbol s;
+ dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
+ if (e)
+ {
+ exp.e1.error("argument to `_Alignof` must be a type");
+ return setError();
+ }
+ else if (t)
+ {
+ result = new IntegerExp(exp.loc, t.alignsize, Type.tsize_t);
+ }
+ else if (s)
+ {
+ exp.e1.error("argument to `_Alignof` must be a type");
+ return setError();
+ }
+ else
+ assert(0);
+ return;
+ }
+ }
+
+ if (sc.flags & SCOPE.Cfile && exp.ident != Id.__sizeof)
+ {
+ result = fieldLookup(exp.e1, sc, exp.ident);
+ return;
+ }
+
Expression e = exp.semanticY(sc, 1);
+
if (e && isDotOpDispatch(e))
{
+ auto ode = e;
uint errors = global.startGagging();
e = resolvePropertiesX(sc, e);
- if (global.endGagging(errors))
+ // Any error or if 'e' is not resolved, go to UFCS
+ if (global.endGagging(errors) || e is ode)
e = null; /* fall down to UFCS */
else
{
@@ -6580,10 +6653,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
}
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
// Indicate we need to resolve by UFCS.
Expression e = exp.semanticY(sc, 1);
if (!e)
e = resolveUFCSProperties(sc, exp);
+ if (e is exp)
+ e.type = Type.tvoid; // Unresolved type, because it needs inference
result = e;
}
@@ -7908,6 +7988,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
dinteger_t length = el.toInteger();
auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
exp.upperIsInBounds = bounds.contains(uprRange);
+ if (exp.lwr.op == TOK.int64 && exp.upr.op == TOK.int64 && exp.lwr.toInteger() > exp.upr.toInteger())
+ {
+ exp.error("in slice `%s[%llu .. %llu]`, lower bound is greater than upper bound", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger());
+ return setError();
+ }
+ if (exp.upr.op == TOK.int64 && exp.upr.toInteger() > length)
+ {
+ exp.error("in slice `%s[%llu .. %llu]`, upper bound is greater than array length `%llu`", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger(), length);
+ return setError();
+ }
}
else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0)
{
@@ -7965,6 +8055,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("ArrayExp::semantic('%s')\n", exp.toChars());
}
assert(!exp.type);
+
+ result = exp.carraySemantic(sc); // C semantics
+ if (result)
+ return;
+
Expression e = exp.op_overload(sc);
if (e)
{
@@ -8019,6 +8114,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(CommaExp e)
{
+ //printf("Semantic.CommaExp() %s\n", e.toChars());
if (e.type)
{
result = e;
@@ -8042,10 +8138,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (checkNonAssignmentArrayOp(e.e1))
return setError();
+ // Comma expressions trigger this conversion
+ e.e2 = e.e2.arrayFuncConv(sc);
+
e.type = e.e2.type;
if (e.type is Type.tvoid)
discardValue(e.e1);
- else if (!e.allowCommaExp && !e.isGenerated)
+ else if (!e.allowCommaExp && !e.isGenerated && !(sc.flags & SCOPE.Cfile))
e.error("Using the result of a comma expression is not allowed");
result = e;
}
@@ -8143,7 +8242,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// operator overloading should be handled in ArrayExp already.
if (!exp.e1.type)
- exp.e1 = exp.e1.expressionSemantic(sc);
+ exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
assert(exp.e1.type); // semantic() should already be run on it
if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
{
@@ -8191,7 +8290,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
if (t1b.ty == Ttuple)
sc = sc.startCTFE();
- exp.e2 = exp.e2.expressionSemantic(sc);
+ exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
exp.e2 = resolveProperties(sc, exp.e2);
if (t1b.ty == Ttuple)
sc = sc.endCTFE();
@@ -8515,7 +8614,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (auto e2comma = exp.e2.isCommaExp())
{
- if (!e2comma.isGenerated)
+ if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
exp.error("Using the result of a comma expression is not allowed");
/* Rewrite to get rid of the comma from rvalue
@@ -8659,6 +8758,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e1x = e;
}
+ else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
+ {
+ auto die = e1x.isDotIdExp();
+ e1x = fieldLookup(die.e1, sc, die.ident);
+ }
else if (auto die = e1x.isDotIdExp())
{
Expression e = die.semanticY(sc, 1);
@@ -8672,10 +8776,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* In order to make sure that UFCS is tried with correct parameters, e2
* needs to have semantic ran on it.
*/
+ auto ode = e;
exp.e2 = exp.e2.expressionSemantic(sc);
uint errors = global.startGagging();
e = resolvePropertiesX(sc, e, exp.e2);
- if (global.endGagging(errors))
+ // Any error or if 'e' is not resolved, go to UFCS
+ if (global.endGagging(errors) || e is ode)
e = null; /* fall down to UFCS */
else
return setResult(e);
@@ -8717,12 +8823,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
Expression e2x = inferType(exp.e2, t1.baseElemOf());
e2x = e2x.expressionSemantic(sc);
+ if (!t1.isTypeSArray())
+ e2x = e2x.arrayFuncConv(sc);
e2x = resolveProperties(sc, e2x);
if (e2x.op == TOK.type)
e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
if (e2x.op == TOK.error)
return setResult(e2x);
- // We skip checking the value for structs/classes as these might have
+ // We delay checking the value for structs/classes as these might have
// an opAssign defined.
if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
e2x.checkSharedAccess(sc))
@@ -9208,6 +9316,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
assert(exp.op == TOK.blit);
+ if (e2x.checkValue())
+ return setError();
+
exp.e1 = e1x;
exp.e2 = e2x;
}
@@ -9223,6 +9334,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
}
+ if (exp.e2.checkValue())
+ return setError();
}
else if (t1.ty == Tsarray)
{
@@ -9672,7 +9785,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.type = exp.e1.type;
assert(exp.type);
auto res = exp.op == TOK.assign ? exp.reorderSettingAAElem(sc) : exp;
- checkAssignEscape(sc, res, false);
+ Expression tmp;
+ /* https://issues.dlang.org/show_bug.cgi?id=22366
+ *
+ * `reorderSettingAAElem` creates a tree of comma expressions, however,
+ * `checkAssignExp` expects only AssignExps.
+ */
+ checkAssignEscape(sc, Expression.extractLast(res, tmp), false);
return setResult(res);
}
@@ -9944,6 +10063,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
+ /* ImportC: convert arrays to pointers, functions to pointers to functions
+ */
+ exp.e1 = exp.e1.arrayFuncConv(sc);
+ exp.e2 = exp.e2.arrayFuncConv(sc);
+
Type tb1 = exp.e1.type.toBasetype();
Type tb2 = exp.e2.type.toBasetype();
@@ -10045,6 +10169,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
+ /* ImportC: convert arrays to pointers, functions to pointers to functions
+ */
+ exp.e1 = exp.e1.arrayFuncConv(sc);
+ exp.e2 = exp.e2.arrayFuncConv(sc);
+
Type t1 = exp.e1.type.toBasetype();
Type t2 = exp.e2.type.toBasetype();
@@ -11539,12 +11668,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
ec = ec.toBoolean(sc);
CtorFlow ctorflow_root = sc.ctorflow.clone();
- Expression e1x = exp.e1.expressionSemantic(sc);
+ Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
e1x = resolveProperties(sc, e1x);
CtorFlow ctorflow1 = sc.ctorflow;
sc.ctorflow = ctorflow_root;
- Expression e2x = exp.e2.expressionSemantic(sc);
+ Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
e2x = resolveProperties(sc, e2x);
sc.merge(exp.loc, ctorflow1);
@@ -11894,95 +12023,84 @@ Expression semanticX(DotIdExp exp, Scope* sc)
if (exp.ident == Id._mangleof)
{
// symbol.mangleof
- Dsymbol ds;
- switch (exp.e1.op)
+
+ // return mangleof as an Expression
+ static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
{
- case TOK.scope_:
- ds = (cast(ScopeExp)exp.e1).sds;
- goto L1;
- case TOK.variable:
- ds = (cast(VarExp)exp.e1).var;
- goto L1;
- case TOK.dotVariable:
- ds = (cast(DotVarExp)exp.e1).var;
- goto L1;
- case TOK.overloadSet:
- ds = (cast(OverExp)exp.e1).vars;
- goto L1;
- case TOK.template_:
- {
- TemplateExp te = cast(TemplateExp)exp.e1;
- ds = te.fd ? cast(Dsymbol)te.fd : te.td;
- }
- L1:
+ assert(ds);
+ if (auto f = ds.isFuncDeclaration())
{
- assert(ds);
- if (auto f = ds.isFuncDeclaration())
+ if (f.checkForwardRef(loc))
+ return ErrorExp.get();
+
+ if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess |
+ FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess))
{
- if (f.checkForwardRef(exp.loc))
- {
- return ErrorExp.get();
- }
- if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess |
- FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess))
- {
- f.error(exp.loc, "cannot retrieve its `.mangleof` while inferring attributes");
- return ErrorExp.get();
- }
+ f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes");
+ return ErrorExp.get();
}
- OutBuffer buf;
- mangleToBuffer(ds, &buf);
- Expression e = new StringExp(exp.loc, buf.extractSlice());
- e = e.expressionSemantic(sc);
- return e;
}
- default:
- break;
+ OutBuffer buf;
+ mangleToBuffer(ds, &buf);
+ Expression e = new StringExp(loc, buf.extractSlice());
+ return e.expressionSemantic(sc);
+ }
+
+ Dsymbol ds;
+ switch (exp.e1.op)
+ {
+ case TOK.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
+ case TOK.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
+ case TOK.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
+ case TOK.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
+ case TOK.template_:
+ {
+ TemplateExp te = exp.e1.isTemplateExp();
+ return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
+ }
+
+ default:
+ break;
}
}
- if (exp.e1.op == TOK.variable && exp.e1.type.toBasetype().ty == Tsarray && exp.ident == Id.length)
+ 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);
}
- if (exp.e1.op == TOK.dot)
- {
- }
- else
+ if (!exp.e1.isDotExp())
{
exp.e1 = resolvePropertiesX(sc, exp.e1);
}
- if (exp.e1.op == TOK.tuple && exp.ident == Id.offsetof)
+
+ if (auto te = exp.e1.isTupleExp())
{
- /* 'distribute' the .offsetof to each of the tuple elements.
- */
- TupleExp te = cast(TupleExp)exp.e1;
- auto exps = new Expressions(te.exps.dim);
- for (size_t i = 0; i < exps.dim; i++)
+ if (exp.ident == Id.offsetof)
{
- Expression e = (*te.exps)[i];
+ /* 'distribute' the .offsetof to each of the tuple elements.
+ */
+ auto exps = new Expressions(te.exps.dim);
+ foreach (i, e; (*te.exps)[])
+ {
+ (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
+ }
+ // Don't evaluate te.e0 in runtime
+ Expression e = new TupleExp(exp.loc, null, exps);
e = e.expressionSemantic(sc);
- e = new DotIdExp(e.loc, e, Id.offsetof);
- (*exps)[i] = e;
+ return e;
+ }
+ if (exp.ident == Id.length)
+ {
+ // Don't evaluate te.e0 in runtime
+ return new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t);
}
- // Don't evaluate te.e0 in runtime
- Expression e = new TupleExp(exp.loc, null, exps);
- e = e.expressionSemantic(sc);
- return e;
- }
- if (exp.e1.op == TOK.tuple && exp.ident == Id.length)
- {
- TupleExp te = cast(TupleExp)exp.e1;
- // Don't evaluate te.e0 in runtime
- Expression e = new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t);
- return e;
}
// https://issues.dlang.org/show_bug.cgi?id=14416
// Template has no built-in properties except for 'stringof'.
- if ((exp.e1.op == TOK.dotTemplateDeclaration || exp.e1.op == TOK.template_) && exp.ident != Id.stringof)
+ if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
{
exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
return ErrorExp.get();
@@ -11996,8 +12114,15 @@ Expression semanticX(DotIdExp exp, Scope* sc)
return exp;
}
-// Resolve e1.ident without seeing UFCS.
-// If flag == 1, stop "not a property" error and return NULL.
+/******************************
+ * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
+ * Params:
+ * exp = expression to resolve
+ * sc = context
+ * flag = if 1 then do not emit error messages, just return null
+ * Returns:
+ * resolved expression, null if error
+ */
Expression semanticY(DotIdExp exp, Scope* sc, int flag)
{
//printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
@@ -12008,32 +12133,35 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
* to be classtype.id and baseclasstype.id
* if we have no this pointer.
*/
- if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && !hasThis(sc))
+ if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
{
if (AggregateDeclaration ad = sc.getStructClassScope())
{
- if (exp.e1.op == TOK.this_)
+ if (exp.e1.isThisExp())
{
exp.e1 = new TypeExp(exp.e1.loc, ad.type);
}
else
{
- ClassDeclaration cd = ad.isClassDeclaration();
- if (cd && cd.baseClass)
- exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
+ if (auto cd = ad.isClassDeclaration())
+ {
+ if (cd.baseClass)
+ exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
+ }
}
}
}
- Expression e = semanticX(exp, sc);
- if (e != exp)
- return e;
+ {
+ Expression e = semanticX(exp, sc);
+ if (e != exp)
+ return e;
+ }
Expression eleft;
Expression eright;
- if (exp.e1.op == TOK.dot)
+ if (auto de = exp.e1.isDotExp())
{
- DotExp de = cast(DotExp)exp.e1;
eleft = de.e1;
eright = de.e2;
}
@@ -12045,11 +12173,9 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
Type t1b = exp.e1.type.toBasetype();
- if (eright.op == TOK.scope_) // also used for template alias's
+ if (auto ie = eright.isScopeExp()) // also used for template alias's
{
- ScopeExp ie = cast(ScopeExp)eright;
-
- int flags = SearchLocalsOnly;
+ auto flags = SearchLocalsOnly;
/* Disable access to another module's private imports.
* The check for 'is sds our current module' is because
* the current module should have access to its own imports.
@@ -12082,13 +12208,11 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
exp.checkDeprecated(sc, s);
exp.checkDisabled(sc, s);
- EnumMember em = s.isEnumMember();
- if (em)
+ if (auto em = s.isEnumMember())
{
return em.getVarExp(exp.loc, sc);
}
- VarDeclaration v = s.isVarDeclaration();
- if (v)
+ if (auto v = s.isVarDeclaration())
{
//printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
if (!v.type ||
@@ -12100,7 +12224,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
return ErrorExp.get();
}
- if (v.type.ty == Terror)
+ if (v.type.isTypeError())
return ErrorExp.get();
if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
@@ -12114,13 +12238,14 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
return ErrorExp.get();
}
- e = v.expandInitializer(exp.loc);
+ auto e = v.expandInitializer(exp.loc);
v.inuse++;
e = e.expressionSemantic(sc);
v.inuse--;
return e;
}
+ Expression e;
if (v.needThis())
{
if (!eleft)
@@ -12141,12 +12266,12 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
return e.expressionSemantic(sc);
}
- FuncDeclaration f = s.isFuncDeclaration();
- if (f)
+ if (auto f = s.isFuncDeclaration())
{
//printf("it's a function\n");
if (!f.functionSemantic())
return ErrorExp.get();
+ Expression e;
if (f.needThis())
{
if (!eleft)
@@ -12167,6 +12292,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
}
if (auto td = s.isTemplateDeclaration())
{
+ Expression e;
if (eleft)
e = new DotTemplateExp(exp.loc, eleft, td);
else
@@ -12176,7 +12302,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
}
if (OverDeclaration od = s.isOverDeclaration())
{
- e = new VarExp(exp.loc, od, true);
+ Expression e = new VarExp(exp.loc, od, true);
if (eleft)
{
e = new CommaExp(exp.loc, eleft, e);
@@ -12184,8 +12310,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
}
return e;
}
- OverloadSet o = s.isOverloadSet();
- if (o)
+ if (auto o = s.isOverloadSet())
{
//printf("'%s' is an overload set\n", o.toChars());
return new OverExp(exp.loc, o);
@@ -12196,36 +12321,33 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
}
- TupleDeclaration tup = s.isTupleDeclaration();
- if (tup)
+ if (auto tup = s.isTupleDeclaration())
{
if (eleft)
{
- e = new DotVarExp(exp.loc, eleft, tup);
+ Expression e = new DotVarExp(exp.loc, eleft, tup);
e = e.expressionSemantic(sc);
return e;
}
- e = new TupleExp(exp.loc, tup);
+ Expression e = new TupleExp(exp.loc, tup);
e = e.expressionSemantic(sc);
return e;
}
- ScopeDsymbol sds = s.isScopeDsymbol();
- if (sds)
+ if (auto sds = s.isScopeDsymbol())
{
//printf("it's a ScopeDsymbol %s\n", ident.toChars());
- e = new ScopeExp(exp.loc, sds);
+ Expression e = new ScopeExp(exp.loc, sds);
e = e.expressionSemantic(sc);
if (eleft)
e = new DotExp(exp.loc, eleft, e);
return e;
}
- Import imp = s.isImport();
- if (imp)
+ if (auto imp = s.isImport())
{
- ie = new ScopeExp(exp.loc, imp.pkg);
- return ie.expressionSemantic(sc);
+ Expression se = new ScopeExp(exp.loc, imp.pkg);
+ return se.expressionSemantic(sc);
}
// BUG: handle other cases like in IdentifierExp::semantic()
debug
@@ -12236,7 +12358,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
}
else if (exp.ident == Id.stringof)
{
- e = new StringExp(exp.loc, ie.toString());
+ Expression e = new StringExp(exp.loc, ie.toString());
e = e.expressionSemantic(sc);
return e;
}
@@ -12263,9 +12385,11 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
Type t1bn = t1b.nextOf();
if (flag)
{
- AggregateDeclaration ad = isAggregate(t1bn);
- if (ad && !ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
- return null;
+ if (AggregateDeclaration ad = isAggregate(t1bn))
+ {
+ if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
+ return null;
+ }
}
/* Rewrite:
@@ -12275,27 +12399,27 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
*/
if (flag && t1bn.ty == Tvoid)
return null;
- e = new PtrExp(exp.loc, exp.e1);
+ 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));
}
else if (exp.ident == Id.__xalignof &&
exp.e1.isVarExp() &&
exp.e1.isVarExp().var.isVarDeclaration() &&
- exp.e1.isVarExp().var.isVarDeclaration().alignment)
+ !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
{
// For `x.alignof` get the alignment of the variable, not the alignment of its type
const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
const naturalAlignment = exp.e1.type.alignsize();
- const actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment);
- e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
+ const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
+ Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
return e;
}
else
{
- if (exp.e1.op == TOK.type || exp.e1.op == TOK.template_)
+ if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
flag = 0;
- e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
+ Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
if (e)
e = e.expressionSemantic(sc);
return e;
@@ -12875,7 +12999,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
const hasPointers = tb.hasPointers();
if (hasPointers)
{
- if ((stype.alignment() < target.ptrsize ||
+ if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
(v.offset & (target.ptrsize - 1))) &&
(sc.func && sc.func.setUnsafe()))
{
diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d
new file mode 100644
index 0000000..05aeb7d
--- /dev/null
+++ b/gcc/d/dmd/file_manager.d
@@ -0,0 +1,301 @@
+/**
+ * Read a file from disk and store it in memory.
+ *
+ * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d, _file_manager.d)
+ * Documentation: https://dlang.org/phobos/dmd_file_manager.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/file_manager.d
+ */
+
+module dmd.file_manager;
+
+import dmd.root.stringtable : StringTable;
+import dmd.root.file : File, FileBuffer;
+import dmd.root.filename : FileName;
+import dmd.root.string : toDString;
+import dmd.globals;
+import dmd.identifier;
+
+enum package_d = "package." ~ mars_ext;
+enum package_di = "package." ~ hdr_ext;
+
+extern(C++) struct FileManager
+{
+ private StringTable!(FileBuffer*) files;
+ private __gshared bool initialized = false;
+
+nothrow:
+ extern(D) private FileBuffer* readToFileBuffer(const(char)[] filename)
+ {
+ if (!initialized)
+ FileManager._init();
+
+ auto readResult = File.read(filename);
+ if (readResult.success)
+ {
+ FileBuffer* fb;
+ if (auto val = files.lookup(filename))
+ fb = val.value;
+
+ if (!fb)
+ fb = FileBuffer.create();
+
+ fb.data = readResult.extractSlice();
+
+ return files.insert(filename, fb) == null ? null : fb;
+ }
+ else
+ {
+ return null;
+ }
+
+ }
+
+ /********************************************
+ * Look for the source file if it's different from filename.
+ * Look for .di, .d, directory, and along global.path.
+ * Does not open the file.
+ * Params:
+ * filename = as supplied by the user
+ * path = path to look for filename
+ * Returns:
+ * the found file name or
+ * `null` if it is not different from filename.
+ */
+ extern(D) static const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
+ {
+ //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
+ /* Search along path[] for .di file, then .d file, then .i file, then .c file.
+ */
+ const sdi = FileName.forceExt(filename, hdr_ext);
+ if (FileName.exists(sdi) == 1)
+ return sdi;
+ scope(exit) FileName.free(sdi.ptr);
+
+ const sd = FileName.forceExt(filename, mars_ext);
+ if (FileName.exists(sd) == 1)
+ return sd;
+ scope(exit) FileName.free(sd.ptr);
+
+ const si = FileName.forceExt(filename, i_ext);
+ if (FileName.exists(si) == 1)
+ return si;
+ scope(exit) FileName.free(si.ptr);
+
+ const sc = FileName.forceExt(filename, c_ext);
+ if (FileName.exists(sc) == 1)
+ return sc;
+ scope(exit) FileName.free(sc.ptr);
+
+ if (FileName.exists(filename) == 2)
+ {
+ /* The filename exists and it's a directory.
+ * Therefore, the result should be: filename/package.d
+ * iff filename/package.d is a file
+ */
+ const ni = FileName.combine(filename, package_di);
+ if (FileName.exists(ni) == 1)
+ return ni;
+ FileName.free(ni.ptr);
+
+ const n = FileName.combine(filename, package_d);
+ if (FileName.exists(n) == 1)
+ return n;
+ FileName.free(n.ptr);
+ }
+ if (FileName.absolute(filename))
+ return null;
+ if (!path.length)
+ return null;
+ foreach (entry; path)
+ {
+ const p = entry.toDString();
+
+ const(char)[] n = FileName.combine(p, sdi);
+ if (FileName.exists(n) == 1) {
+ return n;
+ }
+ FileName.free(n.ptr);
+
+ n = FileName.combine(p, sd);
+ if (FileName.exists(n) == 1) {
+ return n;
+ }
+ FileName.free(n.ptr);
+
+ n = FileName.combine(p, si);
+ if (FileName.exists(n) == 1) {
+ return n;
+ }
+ FileName.free(n.ptr);
+
+ n = FileName.combine(p, sc);
+ if (FileName.exists(n) == 1) {
+ return n;
+ }
+ FileName.free(n.ptr);
+
+ const b = FileName.removeExt(filename);
+ n = FileName.combine(p, b);
+ FileName.free(b.ptr);
+ if (FileName.exists(n) == 2)
+ {
+ const n2i = FileName.combine(n, package_di);
+ if (FileName.exists(n2i) == 1)
+ return n2i;
+ FileName.free(n2i.ptr);
+ const n2 = FileName.combine(n, package_d);
+ if (FileName.exists(n2) == 1) {
+ return n2;
+ }
+ FileName.free(n2.ptr);
+ }
+ FileName.free(n.ptr);
+ }
+ return null;
+ }
+
+ /**
+ * Looks up the given filename from the internal file buffer table.
+ * If the file does not already exist within the table, it will be read from the filesystem.
+ * If it has been read before,
+ *
+ * Returns: the loaded source file if it was found in memory,
+ * otherwise `null`
+ */
+ extern(D) FileBuffer* lookup(FileName filename)
+ {
+ if (!initialized)
+ FileManager._init();
+
+ if (auto val = files.lookup(filename.toString))
+ {
+ // There is a chance that the buffer could've been
+ // stolen by a reader with extractSlice, so we should
+ // try and do our reading logic if that happens.
+ if (val !is null && val.value.data !is null)
+ {
+ return val.value;
+ }
+ }
+
+ const name = filename.toString;
+ auto res = FileName.exists(name);
+ if (res == 1)
+ return readToFileBuffer(name);
+
+ const fullName = lookForSourceFile(name, global.path ? (*global.path)[] : null);
+ if (!fullName)
+ return null;
+
+ return readToFileBuffer(fullName);
+ }
+
+ extern(C++) FileBuffer* lookup(const(char)* filename)
+ {
+ return lookup(FileName(filename.toDString));
+ }
+
+ /**
+ * Looks up the given filename from the internal file buffer table, and returns the lines within the file.
+ * If the file does not already exist within the table, it will be read from the filesystem.
+ * If it has been read before,
+ *
+ * Returns: the loaded source file if it was found in memory,
+ * otherwise `null`
+ */
+ extern(D) const(char)[][] getLines(FileName file)
+ {
+ if (!initialized)
+ FileManager._init();
+
+ const(char)[][] lines;
+ if (FileBuffer* buffer = lookup(file))
+ {
+ ubyte[] slice = buffer.data[0 .. buffer.data.length];
+ size_t start, end;
+ ubyte c;
+ for (auto i = 0; i < slice.length; i++)
+ {
+ c = slice[i];
+ if (c == '\n' || c == '\r')
+ {
+ if (i != 0)
+ {
+ end = i;
+ lines ~= cast(const(char)[])slice[start .. end];
+ }
+ // Check for Windows-style CRLF newlines
+ if (c == '\r')
+ {
+ if (slice.length > i + 1 && slice[i + 1] == '\n')
+ {
+ // This is a CRLF sequence, skip over two characters
+ start = i + 2;
+ i++;
+ }
+ else
+ {
+ // Just a CR sequence
+ start = i + 1;
+ }
+ }
+ else
+ {
+ // The next line should start after the LF sequence
+ start = i + 1;
+ }
+ }
+ }
+
+ if (slice[$ - 1] != '\r' && slice[$ - 1] != '\n')
+ {
+ end = slice.length;
+ lines ~= cast(const(char)[])slice[start .. end];
+ }
+ }
+
+ return lines;
+ }
+
+ /**
+ * Adds a FileBuffer to the table.
+ *
+ * Returns: The FileBuffer added, or null
+ */
+ extern(D) FileBuffer* add(FileName filename, FileBuffer* filebuffer)
+ {
+ if (!initialized)
+ FileManager._init();
+
+ auto val = files.insert(filename.toString, filebuffer);
+ return val == null ? null : val.value;
+ }
+
+ extern(C++) FileBuffer* add(const(char)* filename, FileBuffer* filebuffer)
+ {
+ if (!initialized)
+ FileManager._init();
+
+ auto val = files.insert(filename.toDString, filebuffer);
+ return val == null ? null : val.value;
+ }
+
+ __gshared fileManager = FileManager();
+
+ // Initialize the global FileManager singleton
+ extern(C++) static __gshared void _init()
+ {
+ if (!initialized)
+ {
+ fileManager.initialize();
+ initialized = true;
+ }
+ }
+
+ void initialize()
+ {
+ files._init();
+ }
+}
diff --git a/gcc/d/dmd/root/root.h b/gcc/d/dmd/file_manager.h
index 667ce67..7488fab1 100644
--- a/gcc/d/dmd/root/root.h
+++ b/gcc/d/dmd/file_manager.h
@@ -4,17 +4,16 @@
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/dmd/root/root.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.h
*/
#pragma once
-#include "object.h"
+#include "root/file.h"
-#include "filename.h"
-
-#include "file.h"
-
-#include "outbuffer.h"
-
-#include "array.h"
+struct FileManager
+{
+ static void _init();
+ FileBuffer* lookup(const char* filename);
+ FileBuffer* add(const char* filename, FileBuffer* filebuffer);
+};
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 7f0b0bb..2d6a756 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -45,7 +45,8 @@ import dmd.identifier;
import dmd.init;
import dmd.mtype;
import dmd.objc;
-import dmd.root.outbuffer;
+import dmd.root.aav;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.root.string;
import dmd.root.stringtable;
@@ -261,6 +262,8 @@ extern (C++) class FuncDeclaration : Declaration
VarDeclaration vresult; /// result variable for out contracts
LabelDsymbol returnLabel; /// where the return goes
+ bool[size_t] isTypeIsolatedCache; /// cache for the potentially very expensive isTypeIsolated check
+
// used to prevent symbols in different
// scopes from having the same name
DsymbolTable localsymtab;
@@ -740,7 +743,7 @@ extern (C++) class FuncDeclaration : Declaration
*/
final BaseClass* overrideInterface()
{
- if (ClassDeclaration cd = toParent2().isClassDeclaration())
+ for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
{
foreach (b; cd.interfaces)
{
@@ -1529,8 +1532,23 @@ extern (C++) class FuncDeclaration : Declaration
extern (D) final bool isTypeIsolated(Type t)
{
StringTable!Type parentTypes;
- parentTypes._init();
- return isTypeIsolated(t, parentTypes);
+ const uniqueTypeID = t.getUniqueID();
+ if (uniqueTypeID)
+ {
+ const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
+ if (cacheResultPtr !is null)
+ return *cacheResultPtr;
+
+ parentTypes._init();
+ const isIsolated = isTypeIsolated(t, parentTypes);
+ isTypeIsolatedCache[uniqueTypeID] = isIsolated;
+ return isIsolated;
+ }
+ else
+ {
+ parentTypes._init();
+ return isTypeIsolated(t, parentTypes);
+ }
}
///ditto
@@ -2593,9 +2611,10 @@ extern (C++) class FuncDeclaration : Declaration
}
if (!tf.nextOf())
- error("must return `int` or `void`");
- else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid)
- error("must return `int` or `void`, not `%s`", tf.nextOf().toChars());
+ // auto main(), check after semantic
+ assert(this.inferRetType);
+ else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid && tf.nextOf().ty != Tnoreturn)
+ error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars());
else if (tf.parameterList.varargs || nparams >= 2 || argerr)
error("parameters must be `main()` or `main(string[] args)`");
}
@@ -3054,7 +3073,11 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
return null;
bool hasOverloads = fd.overnext !is null;
- auto tf = fd.type.toTypeFunction();
+ auto tf = fd.type.isTypeFunction();
+ // if type is an error, the original type should be there for better diagnostics
+ if (!tf)
+ tf = fd.originalType.toTypeFunction();
+
if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
{
OutBuffer thisBuf, funcBuf;
@@ -3253,17 +3276,7 @@ private bool traverseIndirections(Type ta, Type tb)
{
//printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
- /* Threaded list of aggregate types already examined,
- * used to break cycles.
- * Cycles in type graphs can only occur with aggregates.
- */
- static struct Ctxt
- {
- Ctxt* prev;
- Type type; // an aggregate type
- }
-
- static bool traverse(Type ta, Type tb, Ctxt* ctxt, bool reversePass)
+ static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
{
//printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
ta = ta.baseElemOf();
@@ -3293,28 +3306,27 @@ private bool traverseIndirections(Type ta, Type tb)
if (tb.ty == Tclass || tb.ty == Tstruct)
{
- for (Ctxt* c = ctxt; c; c = c.prev)
- if (tb == c.type)
- return true;
- Ctxt c;
- c.prev = ctxt;
- c.type = tb;
-
/* Traverse the type of each field of the aggregate
*/
+ bool* found = table.getLvalue(tb.deco);
+ if (*found == true)
+ return true; // We have already seen this symbol, break the cycle
+ else
+ *found = true;
+
AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
foreach (v; sym.fields)
{
Type tprmi = v.type.addMod(tb.mod);
//printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
- if (!traverse(ta, tprmi, &c, reversePass))
+ if (!traverse(ta, tprmi, table, reversePass))
return false;
}
}
else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
{
Type tind = tb.nextOf();
- if (!traverse(ta, tind, ctxt, reversePass))
+ if (!traverse(ta, tind, table, reversePass))
return false;
}
else if (tb.hasPointers())
@@ -3325,7 +3337,10 @@ private bool traverseIndirections(Type ta, Type tb)
// Still no match, so try breaking up ta if we have not done so yet.
if (!reversePass)
- return traverse(tb, ta, ctxt, true);
+ {
+ scope newTable = AssocArray!(const(char)*, bool)();
+ return traverse(tb, ta, newTable, true);
+ }
return true;
}
@@ -3333,7 +3348,8 @@ private bool traverseIndirections(Type ta, Type tb)
// To handle arbitrary levels of indirections in both parameters, we
// recursively descend into aggregate members/levels of indirection in both
// `ta` and `tb` while avoiding cycles. Start with the original types.
- const result = traverse(ta, tb, null, false);
+ scope table = AssocArray!(const(char)*, bool)();
+ const result = traverse(ta, tb, table, false);
//printf(" returns %d\n", result);
return result;
}
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index 9b65d02..747a113 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -14,7 +14,7 @@ module dmd.globals;
import core.stdc.stdint;
import dmd.root.array;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.identifier;
/// Defines a setting for how compiler warnings and deprecations are handled
@@ -118,6 +118,7 @@ extern (C++) struct Param
bool vgc; // identify gc usage
bool vfield; // identify non-mutable field variables
bool vcomplex = true; // identify complex/imaginary type usage
+ bool vin; // identify 'in' parameters
ubyte symdebug; // insert debug symbolic information
bool symdebugref; // insert debug information for all referenced types, too
bool optimize; // run optimizer
@@ -261,11 +262,29 @@ extern (C++) struct Param
const(char)[] mapfile;
}
-alias structalign_t = uint;
+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 STRUCTALIGN_DEFAULT = (cast(structalign_t)~0);
enum mars_ext = "d"; // for D source files
enum doc_ext = "html"; // for Ddoc generated files
@@ -307,6 +326,8 @@ extern (C++) struct Global
Array!Identifier* versionids; /// command line versions and predefined versions
Array!Identifier* debugids; /// command line debug versions and predefined versions
+ bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch)
+
enum recursionLimit = 500; /// number of recursive template expansions before abort
nothrow:
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 6e79474..2275ec5 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -12,7 +12,7 @@
#include "root/dcompat.h"
#include "root/ctfloat.h"
-#include "root/outbuffer.h"
+#include "common/outbuffer.h"
#include "root/filename.h"
#include "compiler.h"
@@ -107,6 +107,7 @@ struct Param
bool vgc; // identify gc usage
bool vfield; // identify non-mutable field variables
bool vcomplex; // identify complex/imaginary type usage
+ bool vin; // identify 'in' parameters
unsigned char symdebug; // insert debug symbolic information
bool symdebugref; // insert debug information for all referenced types, too
bool optimize; // run optimizer
@@ -238,10 +239,24 @@ struct Param
DString mapfile;
};
-typedef unsigned structalign_t;
+struct structalign_t
+{
+ unsigned short value;
+ bool pack;
+
+ bool isDefault() const;
+ void setDefault();
+ bool isUnknown() const;
+ void setUnknown();
+ void set(unsigned value);
+ unsigned get() const;
+ bool isPack() const;
+ void setPack(bool pack);
+};
+
// magic value means "match whatever the underlying C compiler does"
// other values are all powers of 2
-#define STRUCTALIGN_DEFAULT ((structalign_t) ~0)
+//#define STRUCTALIGN_DEFAULT ((structalign_t) ~0)
const DString mars_ext = "d";
const DString doc_ext = "html"; // for Ddoc generated files
@@ -274,6 +289,8 @@ struct Global
Array<class Identifier*>* versionids; // command line versions and predefined versions
Array<class Identifier*>* debugids; // command line debug versions and predefined versions
+ bool hasMainFunction;
+
/* Start gagging. Return the current number of gagged errors
*/
unsigned startGagging();
diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d
index debb9ca..4018126 100644
--- a/gcc/d/dmd/gluelayer.d
+++ b/gcc/d/dmd/gluelayer.d
@@ -78,6 +78,7 @@ else version (IN_GCC)
extern (C++)
{
Statement asmSemantic(AsmStatement s, Scope* sc);
+ void toObjFile(Dsymbol ds, bool multiobj);
}
// stubs
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 8c31590..4ff07b5 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -44,7 +44,7 @@ import dmd.mtype;
import dmd.nspace;
import dmd.parse;
import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.root.string;
import dmd.statement;
@@ -909,6 +909,12 @@ public:
override void visit(AttribDeclaration d)
{
+ bool hasSTC;
+ if (auto stcd = d.isStorageClassDeclaration)
+ {
+ hasSTC = stcToBuffer(buf, stcd.stc);
+ }
+
if (!d.decl)
{
buf.writeByte(';');
@@ -918,10 +924,12 @@ public:
if (d.decl.dim == 0 || (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration()))
{
// hack for bugzilla 8081
+ if (hasSTC) buf.writeByte(' ');
buf.writestring("{}");
}
else if (d.decl.dim == 1)
{
+ if (hasSTC) buf.writeByte(' ');
(*d.decl)[0].accept(this);
return;
}
@@ -941,8 +949,6 @@ public:
override void visit(StorageClassDeclaration d)
{
- if (stcToBuffer(buf, d.stc))
- buf.writeByte(' ');
visit(cast(AttribDeclaration)d);
}
@@ -1324,11 +1330,10 @@ public:
if (d.ident)
{
buf.writestring(d.ident.toString());
- buf.writeByte(' ');
}
if (d.memtype)
{
- buf.writestring(": ");
+ buf.writestring(" : ");
typeToBuffer(d.memtype, null, buf, hgs);
}
if (!d.members)
@@ -2362,7 +2367,10 @@ public:
override void visit(DotIdExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
- buf.writeByte('.');
+ if (e.arrow)
+ buf.writestring("->");
+ else
+ buf.writeByte('.');
buf.writestring(e.ident.toString());
}
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
index e61fb23..3ff0e89 100644
--- a/gcc/d/dmd/iasmgcc.d
+++ b/gcc/d/dmd/iasmgcc.d
@@ -300,7 +300,7 @@ Ldone:
* Returns:
* the completed gcc asm statement, or null if errors occurred
*/
-public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
+extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
{
//printf("GccAsmStatement.semantic()\n");
scope p = new Parser!ASTCodegen(sc._module, ";", false);
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index 1f04dcf..1ee5153 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -500,6 +500,17 @@ immutable Msgtable[] msgtable =
{ "vector_size" },
{ "__func__" },
{ "noreturn" },
+ { "__pragma", "pragma" },
+ { "builtin_va_list", "__builtin_va_list" },
+ { "builtin_va_start", "__builtin_va_start" },
+ { "builtin_va_arg", "__builtin_va_arg" },
+ { "builtin_va_copy", "__builtin_va_copy" },
+ { "builtin_va_end", "__builtin_va_end" },
+ { "va_list_tag", "__va_list_tag" },
+ { "pack" },
+ { "show" },
+ { "push" },
+ { "pop" },
];
diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d
index 43a1435..8add74a 100644
--- a/gcc/d/dmd/identifier.d
+++ b/gcc/d/dmd/identifier.d
@@ -16,7 +16,7 @@ import core.stdc.stdio;
import core.stdc.string;
import dmd.globals;
import dmd.id;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.root.string;
import dmd.root.stringtable;
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
new file mode 100644
index 0000000..0dad1a8
--- /dev/null
+++ b/gcc/d/dmd/importc.d
@@ -0,0 +1,171 @@
+/**
+ * Contains semantic routines specific to ImportC
+ *
+ * Specification: C11
+ *
+ * Copyright: Copyright (C) 2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/importc.d, _importc.d)
+ * Documentation: https://dlang.org/phobos/dmd_importc.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/importc.d
+ */
+
+module dmd.importc;
+
+import core.stdc.stdio;
+
+import dmd.dcast;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.identifier;
+import dmd.mtype;
+
+/**************************************
+ * C11 does not allow array or function parameters.
+ * Hence, adjust those types per C11 6.7.6.3 rules.
+ * Params:
+ * t = parameter type to adjust
+ * sc = context
+ * Returns:
+ * adjusted type
+ */
+Type cAdjustParamType(Type t, Scope* sc)
+{
+ if (!(sc.flags & SCOPE.Cfile))
+ return t;
+
+ Type tb = t.toBasetype();
+
+ /* C11 6.7.6.3-7 array of T is converted to pointer to T
+ */
+ if (auto ta = tb.isTypeDArray())
+ {
+ t = ta.next.pointerTo();
+ }
+ else if (auto ts = tb.isTypeSArray())
+ {
+ t = ts.next.pointerTo();
+ }
+ /* C11 6.7.6.3-8 function is converted to pointer to function
+ */
+ else if (tb.isTypeFunction())
+ {
+ t = tb.pointerTo();
+ }
+ return t;
+}
+
+/***********************************************
+ * C11 6.3.2.1-3 Convert expression that is an array of type to a pointer to type.
+ * C11 6.3.2.1-4 Convert expression that is a function to a pointer to a function.
+ * Params:
+ * e = ImportC expression to possibly convert
+ * sc = context
+ * Returns:
+ * converted expression
+ */
+Expression arrayFuncConv(Expression e, Scope* sc)
+{
+ //printf("arrayFuncConv() %s\n", e.toChars());
+ if (!(sc.flags & SCOPE.Cfile))
+ return e;
+
+ auto t = e.type.toBasetype();
+ if (auto ta = t.isTypeDArray())
+ {
+ e = e.castTo(sc, ta.next.pointerTo());
+ }
+ else if (auto ts = t.isTypeSArray())
+ {
+ e = e.castTo(sc, ts.next.pointerTo());
+ }
+ else if (t.isTypeFunction())
+ {
+ e = e.addressOf();
+ }
+ else
+ return e;
+ return e.expressionSemantic(sc);
+}
+
+/****************************************
+ * Run semantic on `e`.
+ * Expression `e` evaluates to an instance of a struct.
+ * Look up `ident` as a field of that struct.
+ * Params:
+ * e = evaluates to an instance of a struct
+ * sc = context
+ * id = identifier of a field in that struct
+ * Returns:
+ * if successful `e.ident`
+ * if not then `ErrorExp` and message is printed
+ */
+Expression fieldLookup(Expression e, Scope* sc, Identifier id)
+{
+ e = e.expressionSemantic(sc);
+ if (e.isErrorExp())
+ return e;
+
+ Dsymbol s;
+ auto t = e.type;
+ if (t.isTypePointer())
+ {
+ t = t.isTypePointer().next;
+ e = new PtrExp(e.loc, e);
+ }
+ if (auto ts = t.isTypeStruct())
+ s = ts.sym.search(e.loc, id, 0);
+ if (!s)
+ {
+ e.error("`%s` is not a member of `%s`", id.toChars(), t.toChars());
+ return ErrorExp.get();
+ }
+ Expression ef = new DotVarExp(e.loc, e, s.isDeclaration());
+ return ef.expressionSemantic(sc);
+}
+
+/****************************************
+ * C11 6.5.2.1-2
+ * Apply C semantics to `E[I]` expression.
+ * E1[E2] is lowered to *(E1 + E2)
+ * Params:
+ * ae = ArrayExp to run semantics on
+ * sc = context
+ * Returns:
+ * Expression if this was a C expression with completed semantic, null if not
+ */
+Expression carraySemantic(ArrayExp ae, Scope* sc)
+{
+ if (!(sc.flags & SCOPE.Cfile))
+ return null;
+
+ auto e1 = ae.e1.expressionSemantic(sc);
+
+ assert(ae.arguments.length == 1);
+ Expression e2 = (*ae.arguments)[0];
+
+ /* CTFE cannot do pointer arithmetic, but it can index arrays.
+ * So, rewrite as an IndexExp if we can.
+ */
+ auto t1 = e1.type.toBasetype();
+ if (t1.isTypeDArray() || t1.isTypeSArray())
+ {
+ e2 = e2.expressionSemantic(sc).arrayFuncConv(sc);
+ return new IndexExp(ae.loc, e1, e2).expressionSemantic(sc);
+ }
+
+ e1 = e1.arrayFuncConv(sc); // e1 might still be a function call
+ e2 = e2.expressionSemantic(sc);
+ auto t2 = e2.type.toBasetype();
+ if (t2.isTypeDArray() || t2.isTypeSArray())
+ {
+ return new IndexExp(ae.loc, e2, e1).expressionSemantic(sc); // swap operands
+ }
+
+ e2 = e2.arrayFuncConv(sc);
+ auto ep = new PtrExp(ae.loc, new AddExp(ae.loc, e1, e2));
+ return ep.expressionSemantic(sc);
+}
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index 45e101b..d036ee1 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -23,7 +23,7 @@ import dmd.globals;
import dmd.hdrgen;
import dmd.identifier;
import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.tokens;
import dmd.visitor;
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index ae8bde2..5828486 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -31,6 +31,7 @@ import dmd.func;
import dmd.globals;
import dmd.id;
import dmd.identifier;
+import dmd.importc;
import dmd.init;
import dmd.mtype;
import dmd.opover;
@@ -176,30 +177,35 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
break;
}
}
- else if (fieldi >= nfields)
+ if (j >= nfields)
{
- error(i.loc, "too many initializers for `%s`", sd.toChars());
+ error(i.value[j].loc, "too many initializers for `%s`", sd.toChars());
return err();
}
VarDeclaration vd = sd.fields[fieldi];
if (elems[fieldi])
{
- error(i.loc, "duplicate initializer for field `%s`", vd.toChars());
+ error(i.value[j].loc, "duplicate initializer for field `%s`", vd.toChars());
errors = true;
+ elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+ ++fieldi;
continue;
}
// Check for @safe violations
if (vd.type.hasPointers)
{
- if ((t.alignment() < target.ptrsize ||
+ if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize ||
(vd.offset & (target.ptrsize - 1))) &&
sc.func && sc.func.setUnsafe())
{
- error(i.loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
+ error(i.value[j].loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
sd.toChars(), vd.toChars());
errors = true;
+ elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+ ++fieldi;
+ continue;
}
}
@@ -208,7 +214,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
if (vd.isOverlappedWith(v2) && elems[k])
{
- error(i.loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+ error(elems[k].loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
errors = true;
continue;
}
@@ -222,6 +228,8 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
if (ex.op == TOK.error)
{
errors = true;
+ elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+ ++fieldi;
continue;
}
@@ -363,10 +371,10 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
if (length > i.dim)
i.dim = length;
}
- if (t.ty == Tsarray)
+ if (auto tsa = t.isTypeSArray())
{
- uinteger_t edim = (cast(TypeSArray)t).dim.toInteger();
- if (i.dim > edim)
+ uinteger_t edim = tsa.dim.toInteger();
+ if (i.dim > edim && !(tsa.isIncomplete() && (sc.flags & SCOPE.Cfile)))
{
error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim);
return err();
@@ -398,6 +406,13 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
if (i.exp.op == TOK.error)
return err();
uint olderrors = global.errors;
+
+ /* ImportC: convert arrays to pointers, functions to pointers to functions
+ */
+ Type tb = t.toBasetype();
+ if (tb.isTypePointer())
+ i.exp = i.exp.arrayFuncConv(sc);
+
/* Save the expression before ctfe
* Otherwise the error message would contain for example "&[0][0]" instead of "new int"
* Regression: https://issues.dlang.org/show_bug.cgi?id=21687
@@ -408,7 +423,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
// If the result will be implicitly cast, move the cast into CTFE
// to avoid premature truncation of polysemous types.
// eg real [] x = [1.1, 2.2]; should use real precision.
- if (i.exp.implicitConvTo(t))
+ if (i.exp.implicitConvTo(t) && !(sc.flags & SCOPE.Cfile))
{
i.exp = i.exp.implicitCastTo(sc, t);
}
@@ -416,6 +431,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
return i;
}
+ if (sc.flags & SCOPE.Cfile)
+ /* the interpreter turns (char*)"string" into &"string"[0] which then
+ * it cannot interpret. Resolve that case by doing optimize() first
+ */
+ i.exp = i.exp.optimize(WANTvalue);
i.exp = i.exp.ctfeInterpret();
if (i.exp.op == TOK.voidExpression)
error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
@@ -424,6 +444,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
i.exp = i.exp.optimize(WANTvalue);
}
+
if (!global.gag && olderrors != global.errors)
{
return i; // Failed, suppress duplicate error messages
@@ -445,7 +466,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
i.exp.error("cannot use non-constant CTFE pointer in an initializer `%s`", currExp.toChars());
return err();
}
- Type tb = t.toBasetype();
Type ti = i.exp.type.toBasetype();
if (i.exp.op == TOK.tuple && i.expandTuples && !i.exp.implicitConvTo(t))
{
@@ -470,13 +490,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
goto L1;
}
}
-
/* C11 6.7.9-14..15
* Initialize an array of unknown size with a string.
- * ImportC regards Tarray as an array of unknown size.
* Change to static array of known size
*/
- if (sc.flags & SCOPE.Cfile && i.exp.op == TOK.string_ && tb.ty == Tarray)
+ if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
+ tb.isTypeSArray() && tb.isTypeSArray().isIncomplete())
{
StringExp se = i.exp.isStringExp();
auto ts = new TypeSArray(tb.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t));
@@ -683,8 +702,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
}
auto tsa = t.isTypeSArray();
- auto ta = t.isTypeDArray();
- if (!(tsa || ta))
+ if (!tsa)
{
/* Not an array. See if it is `{ exp }` which can be
* converted to an ExpInitializer
@@ -722,19 +740,32 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
//printf(" type %s i %d dim %d dil.length = %d\n", t.toChars(), cast(int)i, cast(int)dim, cast(int)dil.length);
auto tn = t.nextOf().toBasetype();
- if (auto tna = tn.isTypeDArray())
+ auto tnsa = tn.isTypeSArray();
+ if (tnsa && tnsa.isIncomplete())
{
// C11 6.2.5-20 "element type shall be complete whenever the array type is specified"
- error(ci.loc, "incomplete element type `%s` not allowed", tna.toChars());
+ error(ci.loc, "incomplete element type `%s` not allowed", tnsa.toChars());
errors = true;
return 1;
}
if (i == dil.length)
return 0;
size_t n;
- auto tnsa = tn.isTypeSArray();
const nelems = tnsa ? cast(size_t)tnsa.dim.toInteger() : 0;
+ /* Run initializerSemantic on a single element.
+ */
+ Initializer elem(Initializer ie)
+ {
+ ++i;
+ auto tnx = tn; // in case initializerSemantic tries to change it
+ ie = ie.initializerSemantic(sc, tnx, needInterpret);
+ if (ie.isErrorInitializer())
+ errors = true;
+ assert(tnx == tn); // sub-types should not be modified
+ return ie;
+ }
+
foreach (j; 0 .. dim)
{
auto di = dil[i];
@@ -751,16 +782,17 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
}
else if (auto tns = tn.isTypeStruct())
{
- dil[n].initializer = structs(tns);
+ if (di.initializer.isExpInitializer())
+ {
+ // no braces enclosing struct initializer
+ dil[n].initializer = structs(tns);
+ }
+ else
+ dil[n].initializer = elem(di.initializer);
}
else
{
- ++i;
- auto tnx = tn; // in case initializerSemantic tries to change it
- di.initializer = di.initializer.initializerSemantic(sc, tnx, needInterpret);
- if (di.initializer.isErrorInitializer())
- errors = true;
- assert(tnx == tn); // sub-types should not be modified
+ di.initializer = elem(di.initializer);
}
++n;
if (i == dil.length)
@@ -770,16 +802,16 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
return n;
}
- size_t dim = ta ? dil.length : cast(size_t)tsa.dim.toInteger();
- auto n = array(t, dim);
+ size_t dim = tsa.isIncomplete() ? dil.length : cast(size_t)tsa.dim.toInteger();
+ auto newdim = array(t, dim);
if (errors)
return err();
- if (ta) // array of unknown length
+ if (tsa.isIncomplete()) // array of unknown length
{
// Change to array of known length
- tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, n, Type.tsize_t));
+ tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, newdim, Type.tsize_t));
tx = tsa; // rewrite caller's type
ci.type = tsa; // remember for later passes
}
@@ -799,6 +831,39 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
return err();
}
+ /* If an array of simple elements, replace with an ArrayInitializer
+ */
+ auto tnb = tn.toBasetype();
+ if (!(tnb.isTypeSArray() || tnb.isTypeStruct()))
+ {
+ auto ai = new ArrayInitializer(ci.loc);
+ ai.dim = cast(uint) dil.length;
+ ai.index.setDim(dil.length);
+ ai.value.setDim(dil.length);
+ foreach (const j; 0 .. dil.length)
+ {
+ ai.index[j] = null;
+ ai.value[j] = dil[j].initializer;
+ }
+ auto ty = tx;
+ return ai.initializerSemantic(sc, ty, needInterpret);
+ }
+
+ if (newdim < ci.initializerList.length && tnb.isTypeStruct())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=22375
+ // initializerList can be bigger than the number of actual elements
+ // to initialize for array of structs because it is not required
+ // for values to have proper bracing.
+ // i.e: These are all valid initializers for `struct{int a,b;}[3]`:
+ // {1,2,3,4}, {{1,2},3,4}, {1,2,{3,4}}, {{1,2},{3,4}}
+ // In all examples above, the new length of the initializer list
+ // has been shortened from four elements to two. This is important,
+ // because `dil` is written back to directly, making the lowered
+ // initializer `{{1,2},{3,4}}` and not `{{1,2},{3,4},3,4}`.
+ ci.initializerList.length = newdim;
+ }
+
return ci;
}
@@ -1263,6 +1328,3 @@ private bool hasNonConstPointers(Expression e)
}
return false;
}
-
-
-
diff --git a/gcc/d/dmd/intrange.h b/gcc/d/dmd/intrange.h
deleted file mode 100644
index fd61532..0000000
--- a/gcc/d/dmd/intrange.h
+++ /dev/null
@@ -1,177 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by KennyTM
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/intrange.h
- */
-
-#pragma once
-
-#include "globals.h" // for uinteger_t
-class Type;
-class Expression;
-
-/**
-This class represents a "sign-extended number", i.e. a 65-bit number, which can
-represent all built-in integer types in D. This class is mainly used for
-performing value-range propagation only, therefore all arithmetic are done with
-saturation, not wrapping as usual.
-*/
-struct SignExtendedNumber
-{
- /// The lower 64-bit of the number.
- uinteger_t value;
- /// The sign (i.e. the most significant bit) of the number.
- bool negative;
-
- /// Create an uninitialized sign-extended number.
- SignExtendedNumber() {}
-
- /// Create a sign-extended number from an unsigned 64-bit number.
- SignExtendedNumber(uinteger_t value_)
- : value(value_), negative(false) {}
- /// Create a sign-extended number from the lower 64-bit and the sign bit.
- SignExtendedNumber(uinteger_t value_, bool negative_)
- : value(value_), negative(negative_) {}
-
- /// Create a sign-extended number from a signed 64-bit number.
- static SignExtendedNumber fromInteger(uinteger_t value_);
-
- /// Get the minimum or maximum value of a sign-extended number.
- static SignExtendedNumber extreme(bool minimum);
-
- // These names probably shouldn't be used anyway, as they are common macros
-#undef max
-#undef min
- static SignExtendedNumber max();
- static SignExtendedNumber min() { return SignExtendedNumber(0, true); }
-
- /// Check if the sign-extended number is minimum or zero.
- bool isMinimum() const { return negative && value == 0; }
-
- /// Compare two sign-extended number.
- bool operator==(const SignExtendedNumber&) const;
- bool operator!=(const SignExtendedNumber& a) const { return !(*this == a); }
- bool operator<(const SignExtendedNumber&) const;
- bool operator>(const SignExtendedNumber& a) const { return a < *this; }
- bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); }
- bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); }
-
- /// Increase the sign-extended number by 1 (saturated).
- SignExtendedNumber& operator++();
- /// Compute the saturated complement of a sign-extended number.
- SignExtendedNumber operator~() const;
- /// Compute the saturated negation of a sign-extended number.
- SignExtendedNumber operator-() const;
-
- /// Compute the saturated binary and of two sign-extended number.
- SignExtendedNumber operator&(const SignExtendedNumber&) const;
- /// Compute the saturated binary or of two sign-extended number.
- SignExtendedNumber operator|(const SignExtendedNumber&) const;
- /// Compute the saturated binary xor of two sign-extended number.
- SignExtendedNumber operator^(const SignExtendedNumber&) const;
- /// Compute the saturated sum of two sign-extended number.
- SignExtendedNumber operator+(const SignExtendedNumber&) const;
- /// Compute the saturated difference of two sign-extended number.
- SignExtendedNumber operator-(const SignExtendedNumber&) const;
- /// Compute the saturated product of two sign-extended number.
- SignExtendedNumber operator*(const SignExtendedNumber&) const;
- /// Compute the saturated quotient of two sign-extended number.
- SignExtendedNumber operator/(const SignExtendedNumber&) const;
- /// Compute the saturated modulus of two sign-extended number.
- SignExtendedNumber operator%(const SignExtendedNumber&) const;
-
- /// Compute the saturated shifts of two sign-extended number.
- SignExtendedNumber operator<<(const SignExtendedNumber&) const;
- SignExtendedNumber operator>>(const SignExtendedNumber&) const;
-};
-
-/**
-This class represents a range of integers, denoted by its lower and upper bounds
-(inclusive).
-*/
-struct IntRange
-{
- SignExtendedNumber imin, imax;
-
- /// Create an uninitialized range.
- IntRange() {}
-
- /// Create a range consisting of a single number.
- IntRange(const SignExtendedNumber& a)
- : imin(a), imax(a) {}
- /// Create a range with the lower and upper bounds.
- IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper)
- : imin(lower), imax(upper) {}
-
- /// Create the tightest range containing all valid integers in the specified
- /// type.
- static IntRange fromType(Type *type);
- /// Create the tightest range containing all valid integers in the type with
- /// a forced signedness.
- static IntRange fromType(Type *type, bool isUnsigned);
-
-
- /// Create the tightest range containing all specified numbers.
- static IntRange fromNumbers2(const SignExtendedNumber numbers[2]);
- static IntRange fromNumbers4(const SignExtendedNumber numbers[4]);
-
- /// Create the widest range possible.
- static IntRange widest();
-
- /// Cast the integer range to a signed type with the given size mask.
- IntRange& castSigned(uinteger_t mask);
- /// Cast the integer range to an unsigned type with the given size mask.
- IntRange& castUnsigned(uinteger_t mask);
- /// Cast the integer range to the dchar type.
- IntRange& castDchar();
-
- /// Cast the integer range to a specific type.
- IntRange& cast(Type *type);
- /// Cast the integer range to a specific type, forcing it to be unsigned.
- IntRange& castUnsigned(Type *type);
-
- /// Check if this range contains another range.
- bool contains(const IntRange& a) const;
-
- /// Check if this range contains 0.
- bool containsZero() const;
-
- /// Compute the range of the negated absolute values of the original range.
- IntRange absNeg() const;
-
- /// Compute the union of two ranges.
- IntRange unionWith(const IntRange& other) const;
- void unionOrAssign(const IntRange& other, bool& union_);
-
- /// Dump the content of the integer range to the console.
- const IntRange& dump(const char* funcName, Expression *e) const;
-
- /// Split the range into two nonnegative- and negative-only subintervals.
- void splitBySign(IntRange& negRange, bool& hasNegRange,
- IntRange& nonNegRange, bool& hasNonNegRange) const;
-
- /// Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
- /// https://github.com/tgehr/d-compiler/blob/master/vrange.d
- static SignExtendedNumber maxOr(const IntRange&, const IntRange&);
- static SignExtendedNumber minOr(const IntRange&, const IntRange&);
- static SignExtendedNumber maxAnd(const IntRange&, const IntRange&);
- static SignExtendedNumber minAnd(const IntRange&, const IntRange&);
- static void swap(IntRange&, IntRange&);
-
- IntRange operator~() const;
- IntRange operator-() const;
- IntRange operator&(const IntRange&) const;
- IntRange operator|(const IntRange&) const;
- IntRange operator^(const IntRange&) const;
- IntRange operator+(const IntRange&) const;
- IntRange operator-(const IntRange&) const;
- IntRange operator*(const IntRange&) const;
- IntRange operator/(const IntRange&) const;
- IntRange operator%(const IntRange&) const;
- IntRange operator<<(const IntRange&) const;
- IntRange operator>>(const IntRange&) const;
-};
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
index bfd31bc..fef5150 100644
--- a/gcc/d/dmd/json.d
+++ b/gcc/d/dmd/json.d
@@ -33,7 +33,7 @@ import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.root.string;
import dmd.target;
@@ -794,8 +794,8 @@ public:
property("init", d._init.toString());
if (d.isField())
property("offset", d.offset);
- if (d.alignment && d.alignment != STRUCTALIGN_DEFAULT)
- property("align", d.alignment);
+ if (!d.alignment.isUnknown() && !d.alignment.isDefault())
+ property("align", d.alignment.get());
objectEnd();
}
diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d
index d29bdc1..44a6c06 100644
--- a/gcc/d/dmd/lambdacomp.d
+++ b/gcc/d/dmd/lambdacomp.d
@@ -27,7 +27,7 @@ import dmd.expression;
import dmd.func;
import dmd.dmangle;
import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.stringtable;
import dmd.dscope;
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index afffc2d..e2b4199 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -26,8 +26,9 @@ import dmd.errors;
import dmd.globals;
import dmd.id;
import dmd.identifier;
+import dmd.root.array;
import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.port;
import dmd.root.rmem;
import dmd.root.string;
@@ -229,6 +230,8 @@ class Lexer
ubyte long_doublesize; /// size of C long double, 8 or D real.sizeof
ubyte wchar_tsize; /// size of C wchar_t, 2 or 4
+ structalign_t packalign; /// current state of #pragma pack alignment (ImportC)
+
private
{
const(char)* base; // pointer to start of buffer
@@ -242,6 +245,10 @@ class Lexer
int lastDocLine; // last line of previous doc comment
Token* tokenFreelist;
+
+ // ImportC #pragma pack stack
+ Array!Identifier* records; // identifers (or null)
+ Array!structalign_t* packs; // parallel alignment values
}
nothrow:
@@ -273,6 +280,7 @@ class Lexer
this.commentToken = commentToken;
this.inTokenStringConstant = 0;
this.lastDocLine = 0;
+ this.packalign.setDefault();
//initKeywords();
/* If first line starts with '#!', ignore the line
*/
@@ -1146,6 +1154,11 @@ class Lexer
poundLine(n, false);
continue;
}
+ else if (n.ident == Id.__pragma && Ccompile)
+ {
+ pragmaDirective(scanloc);
+ continue;
+ }
else
{
const locx = loc();
@@ -2162,7 +2175,7 @@ class Lexer
case '.':
if (p[1] == '.')
goto Ldone; // if ".."
- if (base == 10 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
+ if (base <= 10 && n > 0 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
goto Ldone; // if ".identifier" or ".unicode"
if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80))
goto Ldone; // if ".identifier" or ".unicode"
@@ -2911,6 +2924,220 @@ class Lexer
error(loc, "#line integer [\"filespec\"]\\n expected");
}
+ /*********************************************
+ * C11 6.10.6 Pragma directive
+ * # pragma pp-tokens(opt) new-line
+ * The C preprocessor sometimes leaves pragma directives in
+ * the preprocessed output. Ignore them.
+ * Upon return, p is at start of next line.
+ */
+ private void pragmaDirective(const ref Loc loc)
+ {
+ Token n;
+ scan(&n);
+ if (n.value == TOK.identifier && n.ident == Id.pack)
+ return pragmaPack(loc);
+ skipToNextLine();
+ }
+
+ /*********
+ * ImportC
+ * # pragma pack
+ * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
+ * https://docs.microsoft.com/en-us/cpp/preprocessor/pack
+ * Scanner is on the `pack`
+ * Params:
+ * startloc = location to use for error messages
+ */
+ private void pragmaPack(const ref Loc startloc)
+ {
+ const loc = startloc;
+ Token n;
+ scan(&n);
+ if (n.value != TOK.leftParenthesis)
+ {
+ error(loc, "left parenthesis expected to follow `#pragma pack`");
+ skipToNextLine();
+ return;
+ }
+
+ void closingParen()
+ {
+ if (n.value != TOK.rightParenthesis)
+ {
+ error(loc, "right parenthesis expected to close `#pragma pack(`");
+ }
+ skipToNextLine();
+ }
+
+ void setPackAlign(ref const Token t)
+ {
+ const n = t.unsvalue;
+ if (n < 1 || n & (n - 1) || ushort.max < n)
+ error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
+ packalign.set(cast(uint)n);
+ packalign.setPack(true);
+ }
+
+ scan(&n);
+
+ if (!records)
+ {
+ records = new Array!Identifier;
+ packs = new Array!structalign_t;
+ }
+
+ /* # pragma pack ( show )
+ */
+ if (n.value == TOK.identifier && n.ident == Id.show)
+ {
+ if (packalign.isDefault())
+ warning(startloc, "current pack attribute is default");
+ else
+ warning(startloc, "current pack attribute is %d", packalign.get());
+ scan(&n);
+ return closingParen();
+ }
+ /* # pragma pack ( push )
+ * # pragma pack ( push , identifier )
+ * # pragma pack ( push , integer )
+ * # pragma pack ( push , identifier , integer )
+ */
+ if (n.value == TOK.identifier && n.ident == Id.push)
+ {
+ scan(&n);
+ Identifier record = null;
+ if (n.value == TOK.comma)
+ {
+ scan(&n);
+ if (n.value == TOK.identifier)
+ {
+ record = n.ident;
+ scan(&n);
+ if (n.value == TOK.comma)
+ {
+ scan(&n);
+ if (n.value == TOK.int32Literal)
+ {
+ setPackAlign(n);
+ scan(&n);
+ }
+ else
+ error(loc, "alignment value expected, not `%s`", n.toChars());
+ }
+ }
+ else if (n.value == TOK.int32Literal)
+ {
+ setPackAlign(n);
+ scan(&n);
+ }
+ else
+ error(loc, "alignment value expected, not `%s`", n.toChars());
+ }
+ this.records.push(record);
+ this.packs.push(packalign);
+ return closingParen();
+ }
+ /* # pragma pack ( pop )
+ * # pragma pack ( pop PopList )
+ * PopList :
+ * , IdentifierOrInteger
+ * , IdentifierOrInteger PopList
+ * IdentifierOrInteger:
+ * identifier
+ * integer
+ */
+ if (n.value == TOK.identifier && n.ident == Id.pop)
+ {
+ scan(&n);
+ while (n.value == TOK.comma)
+ {
+ scan(&n);
+ if (n.value == TOK.identifier)
+ {
+ for (size_t len = this.records.length; len; --len)
+ {
+ if ((*this.records)[len - 1] == n.ident)
+ {
+ packalign = (*this.packs)[len - 1];
+ this.records.setDim(len - 1);
+ this.packs.setDim(len - 1);
+ break;
+ }
+ }
+ scan(&n);
+ }
+ else if (n.value == TOK.int32Literal)
+ {
+ setPackAlign(n);
+ this.records.push(null);
+ this.packs.push(packalign);
+ scan(&n);
+ }
+ }
+ return closingParen();
+ }
+ /* # pragma pack ( integer )
+ */
+ if (n.value == TOK.int32Literal)
+ {
+ setPackAlign(n);
+ scan(&n);
+ return closingParen();
+ }
+ /* # pragma pack ( )
+ */
+ if (n.value == TOK.rightParenthesis)
+ {
+ packalign.setDefault();
+ return closingParen();
+ }
+
+ error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
+ skipToNextLine();
+ }
+
+ /***************************************
+ * Scan forward to start of next line.
+ */
+ private void skipToNextLine()
+ {
+ while (1)
+ {
+ switch (*p)
+ {
+ case 0:
+ case 0x1A:
+ return; // do not advance p
+
+ case '\n':
+ ++p;
+ break;
+
+ case '\r':
+ ++p;
+ if (p[0] == '\n')
+ ++p;
+ break;
+
+ default:
+ if (*p & 0x80)
+ {
+ const u = decodeUTF();
+ if (u == PS || u == LS)
+ {
+ ++p;
+ break;
+ }
+ }
+ ++p;
+ continue;
+ }
+ break;
+ }
+ endOfLine();
+ }
+
/********************************************
* Decode UTF character.
* Issue error messages for invalid sequences.
@@ -3106,8 +3333,10 @@ class Lexer
return p;
}
-private:
- void endOfLine() pure @nogc @safe
+ /**************************
+ * `p` should be at start of next line
+ */
+ private void endOfLine() pure @nogc @safe
{
scanloc.linnum++;
line = p;
diff --git a/gcc/d/dmd/lexer.h b/gcc/d/dmd/lexer.h
deleted file mode 100644
index b36e7f7..0000000
--- a/gcc/d/dmd/lexer.h
+++ /dev/null
@@ -1,75 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.h
- */
-
-#pragma once
-
-#include "root/root.h"
-#include "globals.h"
-#include "tokens.h"
-
-struct StringTable;
-class Identifier;
-
-class Lexer
-{
-public:
- static OutBuffer stringbuffer;
-
- Loc scanloc; // for error messages
-
- const utf8_t *base; // pointer to start of buffer
- const utf8_t *end; // past end of buffer
- const utf8_t *p; // current character
- const utf8_t *line; // start of current line
- Token token;
- bool doDocComment; // collect doc comment information
- bool anyToken; // !=0 means seen at least one token
- bool commentToken; // !=0 means comments are TOKcomment's
- bool errors; // errors occurred during lexing or parsing
-
- Lexer(const char *filename,
- const utf8_t *base, size_t begoffset, size_t endoffset,
- bool doDocComment, bool commentToken);
-
- TOK nextToken();
- TOK peekNext();
- TOK peekNext2();
- void scan(Token *t);
- Token *peek(Token *t);
- Token *peekPastParen(Token *t);
- unsigned escapeSequence();
- TOK wysiwygStringConstant(Token *t, int tc);
- TOK hexStringConstant(Token *t);
- TOK delimitedStringConstant(Token *t);
- TOK tokenStringConstant(Token *t);
- TOK escapeStringConstant(Token *t);
- TOK charConstant(Token *t);
- void stringPostfix(Token *t);
- TOK number(Token *t);
- TOK inreal(Token *t);
-
- Loc loc()
- {
- scanloc.charnum = (unsigned)(1 + p-line);
- return scanloc;
- }
-
- void error(const char *format, ...);
- void error(Loc loc, const char *format, ...);
- void deprecation(const char *format, ...);
- void poundLine();
- unsigned decodeUTF();
- void getDocComment(Token *t, unsigned lineComment);
-
- static const utf8_t *combineComments(const utf8_t *c1, const utf8_t *c2);
-
-private:
- void endOfLine();
-};
diff --git a/gcc/d/dmd/macro.h b/gcc/d/dmd/macro.h
deleted file mode 100644
index 80ec36e..0000000
--- a/gcc/d/dmd/macro.h
+++ /dev/null
@@ -1,38 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/macro.h
- */
-
-#pragma once
-
-#include "root/dsystem.h"
-#include "root/port.h"
-
-
-struct Macro
-{
- private:
- Macro *next; // next in list
-
- const utf8_t *name; // macro name
- size_t namelen; // length of macro name
-
- const utf8_t *text; // macro replacement text
- size_t textlen; // length of replacement text
-
- int inuse; // macro is in use (don't expand)
-
- Macro(const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen);
- Macro *search(const utf8_t *name, size_t namelen);
-
- public:
- static Macro *define(Macro **ptable, const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen);
-
- void expand(OutBuffer *buf, size_t start, size_t *pend,
- const utf8_t *arg, size_t arglen);
-};
diff --git a/gcc/d/dmd/mars.h b/gcc/d/dmd/mars.h
deleted file mode 100644
index 9b9c278..0000000
--- a/gcc/d/dmd/mars.h
+++ /dev/null
@@ -1,93 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/dmd/mars.h
- */
-
-#pragma once
-
-/*
-It is very important to use version control macros correctly - the
-idea is that host and target are independent. If these are done
-correctly, cross compilers can be built.
-The host compiler and host operating system are also different,
-and are predefined by the host compiler. The ones used in
-dmd are:
-
-Macros defined by the compiler, not the code:
-
- Compiler:
- __DMC__ Digital Mars compiler
- _MSC_VER Microsoft compiler
- __GNUC__ Gnu compiler
- __clang__ Clang compiler
-
- Host operating system:
- _WIN32 Microsoft NT, Windows 95, Windows 98, Win32s,
- Windows 2000, Win XP, Vista
- _WIN64 Windows for AMD64
- __linux__ Linux
- __APPLE__ Mac OSX
- __FreeBSD__ FreeBSD
- __OpenBSD__ OpenBSD
- __sun Solaris, OpenSolaris, SunOS, OpenIndiana, etc
-
-For the target systems, there are the target operating system and
-the target object file format:
-
- Target operating system:
- TARGET_WINDOS Covers 32 bit windows and 64 bit windows
- TARGET_LINUX Covers 32 and 64 bit linux
- TARGET_OSX Covers 32 and 64 bit Mac OSX
- TARGET_FREEBSD Covers 32 and 64 bit FreeBSD
- TARGET_OPENBSD Covers 32 and 64 bit OpenBSD
- TARGET_SOLARIS Covers 32 and 64 bit Solaris
-
- It is expected that the compiler for each platform will be able
- to generate 32 and 64 bit code from the same compiler binary.
-
- There are currently no macros for byte endianness order.
- */
-
-
-#include "root/dsystem.h"
-
-#ifdef __DMC__
-#ifdef DEBUG
-#undef assert
-#define assert(e) (static_cast<void>((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt())))
-#endif
-#endif
-
-void unittests();
-
-struct OutBuffer;
-
-#include "globals.h"
-
-#include "root/ctfloat.h"
-
-#include "complex_t.h"
-
-#include "errors.h"
-
-class Dsymbol;
-class Library;
-struct File;
-void obj_start(char *srcfile);
-void obj_end(Library *library, File *objfile);
-void obj_append(Dsymbol *s);
-void obj_write_deferred(Library *library);
-
-/// Utility functions used by both main and frontend.
-void readFile(Loc loc, File *f);
-void writeFile(Loc loc, File *f);
-void ensurePathToNameExists(Loc loc, const char *name);
-
-const char *importHint(const char *s);
-/// Little helper function for writing out deps.
-void escapePath(OutBuffer *buf, const char *fname);
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index 969290c..fe4c73a 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -119,7 +119,7 @@ public:
static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
- static Module *load(Loc loc, Identifiers *packages, Identifier *ident);
+ static Module *load(const Loc &loc, Identifiers *packages, Identifier *ident);
const char *kind() const;
bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise.
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 80e4791..a21924b 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -43,7 +43,7 @@ import dmd.identifier;
import dmd.init;
import dmd.opover;
import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.rootobject;
import dmd.root.stringtable;
@@ -237,6 +237,7 @@ enum DotExpFlag
{
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
}
/// Result of a check whether two types are covariant
@@ -426,6 +427,13 @@ extern (C++) abstract class Type : ASTNode
return DYNCAST.type;
}
+ /// Returns a non-zero unique ID for this Type, or returns 0 if the Type does not (yet) have a unique ID.
+ /// If `semantic()` has not been run, 0 is returned.
+ final size_t getUniqueID() const
+ {
+ return cast(size_t) deco;
+ }
+
extern (D)
final Mcache* getMcache()
{
@@ -2298,7 +2306,9 @@ extern (C++) abstract class Type : ASTNode
*/
structalign_t alignment()
{
- return STRUCTALIGN_DEFAULT;
+ structalign_t s;
+ s.setDefault();
+ return s;
}
/***************************************
@@ -3532,6 +3542,13 @@ extern (C++) final class TypeSArray : TypeArray
this.dim = dim;
}
+ extern (D) this(Type t) // for incomplete type
+ {
+ super(Tsarray, t);
+ //printf("TypeSArray()\n");
+ this.dim = new IntegerExp(0);
+ }
+
override const(char)* kind() const
{
return "sarray";
@@ -3546,6 +3563,15 @@ extern (C++) final class TypeSArray : TypeArray
return result;
}
+ /***
+ * C11 6.7.6.2-4 incomplete array type
+ * Returns: true if incomplete type
+ */
+ bool isIncomplete()
+ {
+ return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0;
+ }
+
override d_uns64 size(const ref Loc loc)
{
//printf("TypeSArray::size()\n");
@@ -3952,65 +3978,37 @@ extern (C++) final class TypePointer : TypeNext
if (equals(to))
return MATCH.exact;
- if (next.ty == Tfunction)
- {
- if (auto tp = to.isTypePointer())
- {
- if (tp.next.ty == Tfunction)
- {
- if (next.equals(tp.next))
- return MATCH.constant;
-
- if (next.covariant(tp.next) == Covariant.yes)
- {
- Type tret = this.next.nextOf();
- Type toret = tp.next.nextOf();
- if (tret.ty == Tclass && toret.ty == Tclass)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=10219
- * Check covariant interface return with offset tweaking.
- * interface I {}
- * class C : Object, I {}
- * I function() dg = function C() {} // should be error
- */
- int offset = 0;
- if (toret.isBaseOf(tret, &offset) && offset != 0)
- return MATCH.nomatch;
- }
- return MATCH.convert;
- }
- }
- else if (tp.next.ty == Tvoid)
- {
- // Allow conversions to void*
- return MATCH.convert;
- }
- }
+ // Only convert between pointers
+ auto tp = to.isTypePointer();
+ if (!tp)
return MATCH.nomatch;
- }
- else if (auto tp = to.isTypePointer())
+
+ assert(this.next);
+ assert(tp.next);
+
+ // Conversion to void*
+ if (tp.next.ty == Tvoid)
{
- assert(tp.next);
+ // Function pointer conversion doesn't check constness?
+ if (this.next.ty == Tfunction)
+ return MATCH.convert;
if (!MODimplicitConv(next.mod, tp.next.mod))
return MATCH.nomatch; // not const-compatible
- /* Alloc conversion to void*
- */
- if (next.ty != Tvoid && tp.next.ty == Tvoid)
- {
- return MATCH.convert;
- }
-
- MATCH m = next.constConv(tp.next);
- if (m > MATCH.nomatch)
- {
- if (m == MATCH.exact && mod != to.mod)
- m = MATCH.constant;
- return m;
- }
+ return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
}
- return MATCH.nomatch;
+
+ // Conversion between function pointers
+ if (auto thisTf = this.next.isTypeFunction())
+ return thisTf.implicitPointerConv(tp.next);
+
+ // Default, no implicit conversion between the pointer targets
+ MATCH m = next.constConv(tp.next);
+
+ if (m == MATCH.exact && mod != to.mod)
+ m = MATCH.constant;
+ return m;
}
override MATCH constConv(Type to)
@@ -4760,7 +4758,10 @@ extern (C++) final class TypeFunction : TypeNext
}
}
else
- m = arg.implicitConvTo(tprm);
+ {
+ import dmd.dcast : cimplicitConvTo;
+ m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
+ }
}
//printf("match %d\n", m);
}
@@ -4971,6 +4972,47 @@ extern (C++) final class TypeFunction : TypeNext
return MATCH.nomatch;
}
+ /+
+ + Checks whether this function type is convertible to ` to`
+ + when used in a function pointer / delegate.
+ +
+ + Params:
+ + to = target type
+ +
+ + Returns:
+ + MATCH.nomatch: `to` is not a covaraint function
+ + MATCH.convert: `to` is a covaraint function
+ + MATCH.exact: `to` is identical to this function
+ +/
+ private MATCH implicitPointerConv(Type to)
+ {
+ assert(to);
+
+ if (this == to)
+ return MATCH.constant;
+
+ if (this.covariant(to) == Covariant.yes)
+ {
+ Type tret = this.nextOf();
+ Type toret = to.nextOf();
+ if (tret.ty == Tclass && toret.ty == Tclass)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=10219
+ * Check covariant interface return with offset tweaking.
+ * interface I {}
+ * class C : Object, I {}
+ * I function() dg = function C() {} // should be error
+ */
+ int offset = 0;
+ if (toret.isBaseOf(tret, &offset) && offset != 0)
+ return MATCH.nomatch;
+ }
+ return MATCH.convert;
+ }
+
+ return MATCH.nomatch;
+ }
+
/** Extends TypeNext.constConv by also checking for matching attributes **/
override MATCH constConv(Type to)
{
@@ -5262,27 +5304,16 @@ extern (C++) final class TypeDelegate : TypeNext
if (this == to)
return MATCH.exact;
- version (all)
+ if (auto toDg = to.isTypeDelegate())
{
- // not allowing covariant conversions because it interferes with overriding
- if (to.ty == Tdelegate && this.nextOf().covariant(to.nextOf()) == Covariant.yes)
- {
- Type tret = this.next.nextOf();
- Type toret = (cast(TypeDelegate)to).next.nextOf();
- if (tret.ty == Tclass && toret.ty == Tclass)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=10219
- * Check covariant interface return with offset tweaking.
- * interface I {}
- * class C : Object, I {}
- * I delegate() dg = delegate C() {} // should be error
- */
- int offset = 0;
- if (toret.isBaseOf(tret, &offset) && offset != 0)
- return MATCH.nomatch;
- }
- return MATCH.convert;
- }
+ MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next);
+
+ // Retain the old behaviour for this refactoring
+ // Should probably be changed to constant to match function pointers
+ if (m > MATCH.convert)
+ m = MATCH.convert;
+
+ return m;
}
return MATCH.nomatch;
@@ -5516,6 +5547,11 @@ extern (C++) final class TypeIdentifier : TypeQualified
this.ident = ident;
}
+ static TypeIdentifier create(const ref Loc loc, Identifier ident)
+ {
+ return new TypeIdentifier(loc, ident);
+ }
+
override const(char)* kind() const
{
return "identifier";
@@ -5737,7 +5773,7 @@ extern (C++) final class TypeStruct : Type
override structalign_t alignment()
{
- if (sym.alignment == 0)
+ if (sym.alignment.isUnknown())
sym.size(sym.loc);
return sym.alignment;
}
@@ -6519,6 +6555,29 @@ extern (C++) final class TypeTuple : Type
return false;
}
+ override MATCH implicitConvTo(Type to)
+ {
+ if (this == to)
+ return MATCH.exact;
+ if (auto tt = to.isTypeTuple())
+ {
+ if (arguments.dim == tt.arguments.dim)
+ {
+ MATCH m = MATCH.exact;
+ for (size_t i = 0; i < tt.arguments.dim; i++)
+ {
+ Parameter arg1 = (*arguments)[i];
+ Parameter arg2 = (*tt.arguments)[i];
+ MATCH mi = arg1.type.implicitConvTo(arg2.type);
+ if (mi < m)
+ m = mi;
+ }
+ return m;
+ }
+ }
+ return MATCH.nomatch;
+ }
+
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index cdf221f..430b39b 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -224,6 +224,7 @@ public:
bool equivalent(Type *t);
// kludge for template.isType()
DYNCAST dyncast() const { return DYNCAST_TYPE; }
+ size_t getUniqueID() const;
Covariant covariant(Type *t, StorageClass *pstc = NULL);
const char *toChars() const;
char *toPrettyChars(bool QualifyTypes = false);
@@ -446,6 +447,7 @@ public:
const char *kind();
TypeSArray *syntaxCopy();
+ bool isIncomplete();
d_uns64 size(const Loc &loc);
unsigned alignsize();
bool isString();
@@ -582,6 +584,7 @@ struct ParameterList
Parameters* parameters;
StorageClass stc;
VarArg varargs;
+ bool hasIdentifierList; // true if C identifier-list style
size_t length();
Parameter *operator[](size_t i) { return Parameter::getNth(parameters, i); }
@@ -711,6 +714,7 @@ public:
Identifier *ident;
Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution
+ static TypeIdentifier *create(const Loc &loc, Identifier *ident);
const char *kind();
TypeIdentifier *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d
index 7719ccf..605e9f3 100644
--- a/gcc/d/dmd/ob.d
+++ b/gcc/d/dmd/ob.d
@@ -43,7 +43,7 @@ import dmd.tokens;
import dmd.visitor;
import dmd.root.bitarray;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
/**********************************
* Perform ownership/borrowing checks for funcdecl.
diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d
index 85e371e..eb4ba1d 100644
--- a/gcc/d/dmd/objc.d
+++ b/gcc/d/dmd/objc.d
@@ -38,7 +38,7 @@ import dmd.id;
import dmd.identifier;
import dmd.mtype;
import dmd.root.array;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.stringtable;
import dmd.target;
import dmd.tokens;
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index 4ef55f3..ff03a6e 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -213,9 +213,13 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE
if (isRecursiveAliasThis(e.att1, e.e1.type))
return null;
//printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
- Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
- be.e1 = e1;
+ // Resolve 'alias this' but in case of assigment don't resolve properties yet
+ // because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2'
+ bool findOnly = (e.op == TOK.assign);
+ be.e1 = resolveAliasThis(sc, e.e1, true, findOnly);
+ if (!be.e1)
+ return null;
Expression result;
if (be.op == TOK.concatenateAssign)
@@ -237,9 +241,10 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
if (isRecursiveAliasThis(e.att2, e.e2.type))
return null;
//printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
- Expression e2 = new DotIdExp(e.loc, e.e2, ad.aliasthis.ident);
BinExp be = cast(BinExp)e.copy();
- be.e2 = e2;
+ be.e2 = resolveAliasThis(sc, e.e2, true);
+ if (!be.e2)
+ return null;
Expression result;
if (be.op == TOK.concatenateAssign)
@@ -1744,11 +1749,31 @@ private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration f
else if (m == match && m > MATCH.nomatch)
{
assert(fd_best);
- /* Ignore covariant matches, as later on it can be redone
- * after the opApply delegate has its attributes inferred.
- */
- if (tf.covariant(fd_best.type) != Covariant.yes &&
- fd_best.type.covariant(tf) != Covariant.yes)
+ auto bestTf = fd_best.type.isTypeFunction();
+ assert(bestTf);
+
+ // Found another overload with different attributes?
+ // e.g. @system vs. @safe opApply
+ bool ambig = tf.attributesEqual(bestTf);
+
+ // opApplies with identical attributes could still accept
+ // different function bodies as delegate
+ // => different parameters or attributes
+ if (ambig)
+ {
+ // Fetch the delegates that receive the function body
+ auto tfBody = tf.parameterList[0].type.isTypeDelegate().next;
+ assert(tfBody);
+
+ auto bestBody = bestTf.parameterList[0].type.isTypeDelegate().next;
+ assert(bestBody);
+
+ // Ignore covariant matches, as later on it can be redone
+ // after the opApply delegate has its attributes inferred.
+ ambig = !(tfBody.covariant(bestBody) == Covariant.yes || bestBody.covariant(tfBody) == Covariant.yes);
+ }
+
+ if (ambig)
fd_ambig = f; // not covariant, so ambiguous
}
return 0; // continue
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 3ae3061..9f116fe 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -697,6 +697,8 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
// See if we can remove an unnecessary cast
ClassDeclaration cdfrom = e.e1.type.isClassHandle();
ClassDeclaration cdto = e.type.isClassHandle();
+ if (cdfrom.errors || cdto.errors)
+ return error();
if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
goto L1; // can always convert a class to Object
// Need to determine correct offset before optimizing away the cast.
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 21042dd..f00ceb6 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -22,7 +22,7 @@ import dmd.identifier;
import dmd.lexer;
import dmd.errors;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.rootobject;
import dmd.root.string;
@@ -556,6 +556,9 @@ class Parser(AST) : Lexer
{
case TOK.leftParenthesis:
{
+ // MixinType
+ if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
+ goto Ldeclaration;
// mixin(string)
nextToken();
auto exps = parseArguments();
@@ -2954,6 +2957,8 @@ class Parser(AST) : Lexer
// Don't call nextToken again.
}
case TOK.in_:
+ if (global.params.vin)
+ message(scanloc, "Usage of 'in' on parameter");
stc = STC.in_;
goto L2;
@@ -5408,6 +5413,11 @@ class Parser(AST) : Lexer
stc = STC.scope_;
goto Lagain;
+ case TOK.out_:
+ error("cannot declare `out` loop variable, use `ref` instead");
+ stc = STC.out_;
+ goto Lagain;
+
case TOK.enum_:
stc = STC.manifest;
goto Lagain;
diff --git a/gcc/d/dmd/parse.h b/gcc/d/dmd/parse.h
deleted file mode 100644
index a2ad478..0000000
--- a/gcc/d/dmd/parse.h
+++ /dev/null
@@ -1,192 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.h
- */
-
-#pragma once
-
-#include "arraytypes.h"
-#include "lexer.h"
-#include "enum.h"
-
-class Type;
-class TypeQualified;
-class Expression;
-class Declaration;
-class Statement;
-class Import;
-class Initializer;
-class FuncDeclaration;
-class CtorDeclaration;
-class PostBlitDeclaration;
-class DtorDeclaration;
-class StaticCtorDeclaration;
-class StaticDtorDeclaration;
-class SharedStaticCtorDeclaration;
-class SharedStaticDtorDeclaration;
-class ConditionalDeclaration;
-class InvariantDeclaration;
-class UnitTestDeclaration;
-class NewDeclaration;
-class DeleteDeclaration;
-class Condition;
-class Module;
-struct ModuleDeclaration;
-class TemplateDeclaration;
-class TemplateInstance;
-class StaticAssert;
-struct PrefixAttributes;
-
-/************************************
- * These control how parseStatement() works.
- */
-
-enum ParseStatementFlags
-{
- PSsemi = 1, // empty ';' statements are allowed, but deprecated
- PSscope = 2, // start a new scope
- PScurly = 4, // { } statement is required
- PScurlyscope = 8, // { } starts a new scope
- PSsemi_ok = 0x10 // empty ';' are really ok
-};
-
-
-class Parser : public Lexer
-{
-public:
- Module *mod;
- ModuleDeclaration *md;
- LINK linkage;
- CPPMANGLE cppmangle;
- 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
-
- Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment);
- Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment);
-
- Dsymbols *parseModule();
- Dsymbols *parseDeclDefs(int once, Dsymbol **pLastDecl = NULL, PrefixAttributes *pAttrs = NULL);
- Dsymbols *parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment);
- Dsymbols *parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs = NULL);
- StorageClass appendStorageClass(StorageClass storageClass, StorageClass stc, bool deprec = false);
- StorageClass parseAttribute(Expressions **pexps);
- StorageClass parsePostfix(StorageClass storageClass, Expressions **pudas);
- StorageClass parseTypeCtor();
- Expression *parseConstraint();
- TemplateDeclaration *parseTemplateDeclaration(bool ismixin = false);
- TemplateParameters *parseTemplateParameterList(int flag = 0);
- Dsymbol *parseMixin();
- Objects *parseTemplateArguments();
- RootObject *parseTypeOrAssignExp(TOK endtoken = TOKreserved);
- Objects *parseTemplateArgumentList();
- Objects *parseTemplateSingleArgument();
- StaticAssert *parseStaticAssert();
- TypeQualified *parseTypeof();
- Type *parseVector();
- LINK parseLinkage(Identifiers **, CPPMANGLE *, bool *);
- Identifiers *parseQualifiedIdentifier(const char *entity);
- Condition *parseDebugCondition();
- Condition *parseVersionCondition();
- Condition *parseStaticIfCondition();
- Dsymbol *parseCtor(PrefixAttributes *pAttrs);
- Dsymbol *parseDtor(PrefixAttributes *pAttrs);
- Dsymbol *parseStaticCtor(PrefixAttributes *pAttrs);
- Dsymbol *parseStaticDtor(PrefixAttributes *pAttrs);
- Dsymbol *parseSharedStaticCtor(PrefixAttributes *pAttrs);
- Dsymbol *parseSharedStaticDtor(PrefixAttributes *pAttrs);
- Dsymbol *parseInvariant(PrefixAttributes *pAttrs);
- Dsymbol *parseUnitTest(PrefixAttributes *pAttrs);
- Dsymbol *parseNew(PrefixAttributes *pAttrs);
- Dsymbol *parseDelete(PrefixAttributes *pAttrs);
- Parameters *parseParameters(VarArg *pvarargs, TemplateParameters **tpl = NULL);
- EnumDeclaration *parseEnum();
- Dsymbol *parseAggregate();
- BaseClasses *parseBaseClasses();
- Dsymbols *parseImport();
- Type *parseType(Identifier **pident = NULL, TemplateParameters **ptpl = NULL);
- Type *parseBasicType(bool dontLookDotIdents = false);
- Type *parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents);
- Type *parseBasicType2(Type *t);
- Type *parseDeclarator(Type *t, int *alt, Identifier **pident,
- TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int *pdisable = NULL, Expressions **pudas = NULL);
- void parseStorageClasses(StorageClass &storage_class, LINK &link, bool &setAlignment, Expression *&ealign, Expressions *&udas);
- Dsymbols *parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment);
- Dsymbol *parseFunctionLiteral();
- FuncDeclaration *parseContracts(FuncDeclaration *f);
- void checkDanglingElse(Loc elseloc);
- void checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident);
- Statement *parseForeach(Loc loc, bool *isRange, bool isDecl);
- Dsymbol *parseForeachStaticDecl(Loc loc, Dsymbol **pLastDecl);
- Statement *parseForeachStatic(Loc loc);
- /** endPtr used for documented unittests */
- Statement *parseStatement(int flags, const utf8_t** endPtr = NULL, Loc *pEndloc = NULL);
- Initializer *parseInitializer();
- Expression *parseDefaultInitExp();
- void check(Loc loc, TOK value);
- void check(TOK value);
- void check(TOK value, const char *string);
- void checkParens(TOK value, Expression *e);
- bool isDeclaration(Token *t, int needId, TOK endtok, Token **pt);
- bool isBasicType(Token **pt);
- bool isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, bool allowAltSyntax = true);
- bool isParameters(Token **pt);
- bool isExpression(Token **pt);
- bool skipParens(Token *t, Token **pt);
- bool skipParensIf(Token *t, Token **pt);
- bool skipAttributes(Token *t, Token **pt);
-
- Expression *parseExpression();
- Expression *parsePrimaryExp();
- Expression *parseUnaryExp();
- Expression *parsePostExp(Expression *e);
- Expression *parseMulExp();
- Expression *parseAddExp();
- Expression *parseShiftExp();
- Expression *parseCmpExp();
- Expression *parseAndExp();
- Expression *parseXorExp();
- Expression *parseOrExp();
- Expression *parseAndAndExp();
- Expression *parseOrOrExp();
- Expression *parseCondExp();
- Expression *parseAssignExp();
-
- Expressions *parseArguments();
-
- Expression *parseNewExp(Expression *thisexp);
-
- void addComment(Dsymbol *s, const utf8_t *blockComment);
-};
-
-// Operator precedence - greater values are higher precedence
-
-enum PREC
-{
- PREC_zero,
- PREC_expr,
- PREC_assign,
- PREC_cond,
- PREC_oror,
- PREC_andand,
- PREC_or,
- PREC_xor,
- PREC_and,
- PREC_equal,
- PREC_rel,
- PREC_shift,
- PREC_add,
- PREC_mul,
- PREC_pow,
- PREC_unary,
- PREC_primary
-};
-
-extern PREC precedence[TOKMAX];
-
-void initPrecedence();
diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d
index 3f12b17..414d6f6 100644
--- a/gcc/d/dmd/printast.d
+++ b/gcc/d/dmd/printast.d
@@ -59,7 +59,7 @@ extern (C++) final class PrintASTVisitor : Visitor
printIndent(indent);
import dmd.hdrgen : floatToBuffer;
- import dmd.root.outbuffer : OutBuffer;
+ import dmd.common.outbuffer : OutBuffer;
OutBuffer buf;
floatToBuffer(e.type, e.value, &buf, false);
printf("Real %s %s\n", buf.peekChars(), e.type ? e.type.toChars() : "");
diff --git a/gcc/d/dmd/root/README.md b/gcc/d/dmd/root/README.md
index 539b940..e062d93 100644
--- a/gcc/d/dmd/root/README.md
+++ b/gcc/d/dmd/root/README.md
@@ -11,7 +11,6 @@
| [hash.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d) | Calculate a hash for a byte array |
| [longdouble.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/longdouble.d) | 80-bit floating point number implementation in case they are not natively supported |
| [man.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/man.d) | Opens an online manual page |
-| [outbuffer.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d) | An expandable buffer in which you can write text or binary data. |
| [port.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d) | Portable routines for functions that have different implementations on different platforms |
| [region.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d) | A region allocator |
| [response.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/response.d) | Parse command line arguments from response files |
diff --git a/gcc/d/dmd/root/aav.h b/gcc/d/dmd/root/aav.h
deleted file mode 100644
index c65b674..0000000
--- a/gcc/d/dmd/root/aav.h
+++ /dev/null
@@ -1,22 +0,0 @@
-
-/* Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/aav.h
- */
-
-#pragma once
-
-#include "dsystem.h"
-
-typedef void* Value;
-typedef void* Key;
-
-struct AA;
-
-size_t dmd_aaLen(AA* aa);
-Value* dmd_aaGet(AA** aa, Key key);
-Value dmd_aaGetRvalue(AA* aa, Key key);
-void dmd_aaRehash(AA** paa);
-
diff --git a/gcc/d/dmd/root/checkedint.h b/gcc/d/dmd/root/checkedint.h
deleted file mode 100644
index 8a7d9c9..0000000
--- a/gcc/d/dmd/root/checkedint.h
+++ /dev/null
@@ -1,30 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 2003-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/checkedint.h
- */
-
-#include "dsystem.h"
-
-
-int adds(int x, int y, bool& overflow);
-int64_t adds(int64_t x, int64_t y, bool& overflow);
-unsigned addu(unsigned x, unsigned y, bool& overflow);
-uint64_t addu(uint64_t x, uint64_t y, bool& overflow);
-
-int subs(int x, int y, bool& overflow);
-int64_t subs(int64_t x, int64_t y, bool& overflow);
-unsigned subu(unsigned x, unsigned y, bool& overflow);
-uint64_t subu(uint64_t x, uint64_t y, bool& overflow);
-
-int negs(int x, bool& overflow);
-int64_t negs(int64_t x, bool& overflow);
-
-int muls(int x, int y, bool& overflow);
-int64_t muls(int64_t x, int64_t y, bool& overflow);
-unsigned mulu(unsigned x, unsigned y, bool& overflow);
-uint64_t mulu(uint64_t x, uint64_t y, bool& overflow);
diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d
index ef6056c..64e9571 100644
--- a/gcc/d/dmd/root/file.d
+++ b/gcc/d/dmd/root/file.d
@@ -23,410 +23,8 @@ import dmd.root.filename;
import dmd.root.rmem;
import dmd.root.string;
-/**
-Encapsulated management of a memory-mapped file.
-
-Params:
-Datum = the mapped data type: Use a POD of size 1 for read/write mapping
-and a `const` version thereof for read-only mapping. Other primitive types
-should work, but have not been yet tested.
-*/
-struct FileMapping(Datum)
-{
- static assert(__traits(isPOD, Datum) && Datum.sizeof == 1,
- "Not tested with other data types yet. Add new types with care.");
-
- version(Posix) enum invalidHandle = -1;
- else version(Windows) enum invalidHandle = INVALID_HANDLE_VALUE;
-
- // state {
- /// Handle of underlying file
- private auto handle = invalidHandle;
- /// File mapping object needed on Windows
- version(Windows) private HANDLE fileMappingObject = invalidHandle;
- /// Memory-mapped array
- private Datum[] data;
- /// Name of underlying file, zero-terminated
- private const(char)* name;
- // state }
-
- /**
- Open `filename` and map it in memory. If `Datum` is `const`, opens for
- read-only and maps the content in memory; no error is issued if the file
- does not exist. This makes it easy to treat a non-existing file as empty.
-
- If `Datum` is mutable, opens for read/write (creates file if it does not
- exist) and fails fatally on any error.
-
- Due to quirks in `mmap`, if the file is empty, `handle` is valid but `data`
- is `null`. This state is valid and accounted for.
-
- Params:
- filename = the name of the file to be mapped in memory
- */
- this(const char* filename)
- {
- version (Posix)
- {
- import core.sys.posix.sys.mman;
- import core.sys.posix.fcntl;
-
- handle = .open(filename, is(Datum == const) ? O_RDONLY : (O_CREAT | O_RDWR),
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
- if (handle == invalidHandle)
- {
- static if (is(Datum == const))
- {
- // No error, nonexisting file in read mode behaves like an empty file.
- return;
- }
- else
- {
- fprintf(stderr, "open(\"%s\") failed: %s\n", filename, strerror(errno));
- exit(1);
- }
- }
-
- const size = File.size(handle);
-
- if (size > 0 && size != ulong.max && size <= size_t.max)
- {
- auto p = mmap(null, cast(size_t) size, is(Datum == const) ? PROT_READ : PROT_WRITE, MAP_SHARED, handle, 0);
- if (p == MAP_FAILED)
- {
- fprintf(stderr, "mmap(null, %zu) for \"%s\" failed: %s\n", cast(size_t) size, filename, strerror(errno));
- exit(1);
- }
- // The cast below will always work because it's gated by the `size <= size_t.max` condition.
- data = cast(Datum[]) p[0 .. cast(size_t) size];
- }
- }
- else version(Windows)
- {
- static if (is(Datum == const))
- {
- enum createFileMode = GENERIC_READ;
- enum openFlags = OPEN_EXISTING;
- }
- else
- {
- enum createFileMode = GENERIC_READ | GENERIC_WRITE;
- enum openFlags = CREATE_ALWAYS;
- }
-
- handle = CreateFileA(filename, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null);
- if (handle == invalidHandle)
- {
- static if (is(Datum == const))
- {
- return;
- }
- else
- {
- fprintf(stderr, "CreateFileA() failed for \"%s\": %d\n", filename, GetLastError());
- exit(1);
- }
- }
- createMapping(filename, File.size(handle));
- }
- else static assert(0);
-
- // Save the name for later. Technically there's no need: on Linux one can use readlink on /proc/self/fd/NNN.
- // On BSD and OSX one can use fcntl with F_GETPATH. On Windows one can use GetFileInformationByHandleEx.
- // But just saving the name is simplest, fastest, and most portable...
- import core.stdc.string : strlen;
- name = filename[0 .. filename.strlen() + 1].idup.ptr;
- }
-
- /**
- Common code factored opportunistically. Windows only. Assumes `handle` is
- already pointing to an opened file. Initializes the `fileMappingObject`
- and `data` members.
-
- Params:
- filename = the file to be mapped
- size = the size of the file in bytes
- */
- version(Windows) private void createMapping(const char* filename, ulong size)
- {
- assert(size <= size_t.max || size == ulong.max);
- assert(handle != invalidHandle);
- assert(data is null);
- assert(fileMappingObject == invalidHandle);
-
- if (size == 0 || size == ulong.max)
- return;
-
- static if (is(Datum == const))
- {
- enum fileMappingFlags = PAGE_READONLY;
- enum mapViewFlags = FILE_MAP_READ;
- }
- else
- {
- enum fileMappingFlags = PAGE_READWRITE;
- enum mapViewFlags = FILE_MAP_WRITE;
- }
-
- fileMappingObject = CreateFileMappingA(handle, null, fileMappingFlags, 0, 0, null);
- if (!fileMappingObject)
- {
- fprintf(stderr, "CreateFileMappingA(%p) failed for %llu bytes of \"%s\": %d\n",
- handle, size, filename, GetLastError());
- fileMappingObject = invalidHandle; // by convention always use invalidHandle, not null
- exit(1);
- }
- auto p = MapViewOfFile(fileMappingObject, mapViewFlags, 0, 0, 0);
- if (!p)
- {
- fprintf(stderr, "MapViewOfFile() failed for \"%s\": %d\n", filename, GetLastError());
- exit(1);
- }
- data = cast(Datum[]) p[0 .. cast(size_t) size];
- }
-
- // Not copyable or assignable (for now).
- @disable this(const FileMapping!Datum rhs);
- @disable void opAssign(const ref FileMapping!Datum rhs);
-
- /**
- Frees resources associated with this mapping. However, it does not deallocate the name.
- */
- ~this() pure nothrow
- {
- if (!active)
- return;
- fakePure({
- version (Posix)
- {
- import core.sys.posix.sys.mman : munmap;
-
- // Cannot call fprintf from inside a destructor, so exiting silently.
-
- if (data.ptr && munmap(cast(void*) data.ptr, data.length) != 0)
- {
- exit(1);
- }
- data = null;
- if (handle != invalidHandle && .close(handle) != 0)
- {
- exit(1);
- }
- handle = invalidHandle;
- }
- else version(Windows)
- {
- if (data.ptr !is null && UnmapViewOfFile(cast(void*) data.ptr) == 0)
- {
- exit(1);
- }
- data = null;
- if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
- {
- exit(1);
- }
- fileMappingObject = invalidHandle;
- if (handle != invalidHandle && CloseHandle(handle) == 0)
- {
- exit(1);
- }
- handle = invalidHandle;
- }
- else static assert(0);
- });
- }
-
- /**
- Returns the zero-terminated file name associated with the mapping. Can
- be saved beyond the lifetime of `this`.
- */
- const(char)* filename() const pure @nogc @safe nothrow { return name; }
-
- /**
- Frees resources associated with this mapping. However, it does not deallocate the name.
- Reinitializes `this` as a fresh object that can be reused.
- */
- void close()
- {
- __dtor();
- handle = invalidHandle;
- version(Windows) fileMappingObject = invalidHandle;
- data = null;
- name = null;
- }
-
- /**
- Deletes the underlying file and frees all resources associated.
- Reinitializes `this` as a fresh object that can be reused.
-
- This function does not abort if the file cannot be deleted, but does print
- a message on `stderr` and returns `false` to the caller. The underlying
- rationale is to give the caller the option to continue execution if
- deleting the file is not important.
-
- Returns: `true` iff the file was successfully deleted. If the file was not
- deleted, prints a message to `stderr` and returns `false`.
- */
- static if (!is(Datum == const))
- bool discard()
- {
- // Truncate file to zero so unflushed buffers are not flushed unnecessarily.
- resize(0);
- auto deleteme = name;
- close();
- // In-memory resource freed, now get rid of the underlying temp file.
- version(Posix)
- {
- import core.sys.posix.unistd;
- if (unlink(deleteme) != 0)
- {
- fprintf(stderr, "unlink(\"%s\") failed: %s\n", filename, strerror(errno));
- return false;
- }
- }
- else version(Windows)
- {
- import core.sys.windows.winbase;
- if (DeleteFileA(deleteme) == 0)
- {
- fprintf(stderr, "DeleteFileA error %d\n", GetLastError());
- return false;
- }
- }
- else static assert(0);
- return true;
- }
-
- /**
- Queries whether `this` is currently associated with a file.
-
- Returns: `true` iff there is an active mapping.
- */
- bool active() const pure @nogc nothrow
- {
- return handle !is invalidHandle;
- }
-
- /**
- Queries the length of the file associated with this mapping. If not
- active, returns 0.
-
- Returns: the length of the file, or 0 if no file associated.
- */
- size_t length() const pure @nogc @safe nothrow { return data.length; }
-
- /**
- Get a slice to the contents of the entire file.
-
- Returns: the contents of the file. If not active, returns the `null` slice.
- */
- auto opSlice() pure @nogc @safe nothrow { return data; }
-
- /**
- Resizes the file and mapping to the specified `size`.
-
- Params:
- size = new length requested
- */
- static if (!is(Datum == const))
- void resize(size_t size) pure
- {
- assert(handle != invalidHandle);
- fakePure({
- version(Posix)
- {
- import core.sys.posix.unistd : ftruncate;
- import core.sys.posix.sys.mman;
-
- if (data.length)
- {
- assert(data.ptr, "Corrupt memory mapping");
- // assert(0) here because it would indicate an internal error
- munmap(cast(void*) data.ptr, data.length) == 0 || assert(0);
- data = null;
- }
- if (ftruncate(handle, size) != 0)
- {
- fprintf(stderr, "ftruncate() failed for \"%s\": %s\n", filename, strerror(errno));
- exit(1);
- }
- if (size > 0)
- {
- auto p = mmap(null, size, PROT_WRITE, MAP_SHARED, handle, 0);
- if (cast(ssize_t) p == -1)
- {
- fprintf(stderr, "mmap() failed for \"%s\": %s\n", filename, strerror(errno));
- exit(1);
- }
- data = cast(Datum[]) p[0 .. size];
- }
- }
- else version(Windows)
- {
- // Per documentation, must unmap first.
- if (data.length > 0 && UnmapViewOfFile(cast(void*) data.ptr) == 0)
- {
- fprintf(stderr, "UnmapViewOfFile(%p) failed for memory mapping of \"%s\": %d\n",
- data.ptr, filename, GetLastError());
- exit(1);
- }
- data = null;
- if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
- {
- fprintf(stderr, "CloseHandle() failed for memory mapping of \"%s\": %d\n", filename, GetLastError());
- exit(1);
- }
- fileMappingObject = invalidHandle;
- LARGE_INTEGER biggie;
- biggie.QuadPart = size;
- if (SetFilePointerEx(handle, biggie, null, FILE_BEGIN) == 0 || SetEndOfFile(handle) == 0)
- {
- fprintf(stderr, "SetFilePointer() failed for \"%s\": %d\n", filename, GetLastError());
- exit(1);
- }
- createMapping(name, size);
- }
- else static assert(0);
- });
- }
-
- /**
- Unconditionally and destructively moves the underlying file to `filename`.
- If the operation succeds, returns true. Upon failure, prints a message to
- `stderr` and returns `false`.
-
- Params: filename = zero-terminated name of the file to move to.
-
- Returns: `true` iff the operation was successful.
- */
- bool moveToFile(const char* filename)
- {
- auto oldname = name;
-
- close();
- // Rename the underlying file to the target, no copy necessary.
- version(Posix)
- {
- if (.rename(oldname, filename) != 0)
- {
- fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", oldname, filename, strerror(errno));
- return false;
- }
- }
- else version(Windows)
- {
- import core.sys.windows.winbase;
- if (MoveFileExA(oldname, filename, MOVEFILE_REPLACE_EXISTING) == 0)
- {
- fprintf(stderr, "MoveFileExA(\"%s\", \"%s\") failed: %d\n", oldname, filename, GetLastError());
- return false;
- }
- }
- else static assert(0);
- return true;
- }
-}
+import dmd.common.file;
+import dmd.common.string;
/// Owns a (rmem-managed) file buffer.
struct FileBuffer
@@ -585,58 +183,8 @@ nothrow:
/// Write a file, returning `true` on success.
extern (D) static bool write(const(char)* name, const void[] data)
{
- version (Posix)
- {
- ssize_t numwritten;
- int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
- if (fd == -1)
- goto err;
- numwritten = .write(fd, data.ptr, data.length);
- if (numwritten != data.length)
- goto err2;
- if (close(fd) == -1)
- goto err;
- return true;
- err2:
- close(fd);
- .remove(name);
- err:
- return false;
- }
- else version (Windows)
- {
- DWORD numwritten; // here because of the gotos
- const nameStr = name.toDString;
- // work around Windows file path length limitation
- // (see documentation for extendedPathThen).
- HANDLE h = nameStr.extendedPathThen!
- (p => CreateFileW(p.ptr,
- GENERIC_WRITE,
- 0,
- null,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
- null));
- if (h == INVALID_HANDLE_VALUE)
- goto err;
-
- if (WriteFile(h, data.ptr, cast(DWORD)data.length, &numwritten, null) != TRUE)
- goto err2;
- if (numwritten != data.length)
- goto err2;
- if (!CloseHandle(h))
- goto err;
- return true;
- err2:
- CloseHandle(h);
- nameStr.extendedPathThen!(p => DeleteFileW(p.ptr));
- err:
- return false;
- }
- else
- {
- static assert(0);
- }
+ import dmd.common.file : writeFile;
+ return writeFile(name, data);
}
///ditto
@@ -717,42 +265,6 @@ nothrow:
return update(name, data[0 .. size]);
}
- /// Touch a file to current date
- static bool touch(const char* namez)
- {
- version (Windows)
- {
- FILETIME ft = void;
- SYSTEMTIME st = void;
- GetSystemTime(&st);
- SystemTimeToFileTime(&st, &ft);
-
- import core.stdc.string : strlen;
-
- // get handle to file
- HANDLE h = namez[0 .. namez.strlen()].extendedPathThen!(p => CreateFile(p.ptr,
- FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE,
- null, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, null));
- if (h == INVALID_HANDLE_VALUE)
- return false;
-
- const f = SetFileTime(h, null, null, &ft); // set last write time
-
- if (!CloseHandle(h))
- return false;
-
- return f != 0;
- }
- else version (Posix)
- {
- import core.sys.posix.utime;
- return utime(namez, null) == 0;
- }
- else
- static assert(0);
- }
-
/// Size of a file in bytes.
/// Params: namez = null-terminated filename
/// Returns: `ulong.max` on any error, the length otherwise.
@@ -777,38 +289,5 @@ nothrow:
// Error cases go here.
return ulong.max;
}
-
- /// Ditto
- version (Posix)
- static ulong size(int fd)
- {
- stat_t buf;
- if (fstat(fd, &buf) == 0)
- return buf.st_size;
- return ulong.max;
- }
-
- /// Ditto
- version (Windows)
- static ulong size(HANDLE fd)
- {
- ulong result;
- if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
- return result;
- return ulong.max;
- }
}
-/**
-Runs a non-pure function or delegate as pure code. Use with caution.
-
-Params:
-fun = the delegate to run, usually inlined: `fakePure({ ... });`
-
-Returns: whatever `fun` returns.
-*/
-private auto ref fakePure(F)(scope F fun) pure
-{
- mixin("alias PureFun = " ~ F.stringof ~ " pure;");
- return (cast(PureFun) fun)();
-}
diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d
index 1e4ccb5..d1500c8 100644
--- a/gcc/d/dmd/root/filename.d
+++ b/gcc/d/dmd/root/filename.d
@@ -16,7 +16,8 @@ import core.stdc.errno;
import core.stdc.string;
import dmd.root.array;
import dmd.root.file;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
+import dmd.common.file;
import dmd.root.port;
import dmd.root.rmem;
import dmd.root.rootobject;
@@ -1123,78 +1124,13 @@ version(Windows)
*/
private int _mkdir(const(char)[] path) nothrow
{
+ import dmd.common.string : extendedPathThen;
const createRet = path.extendedPathThen!(
p => CreateDirectoryW(&p[0], null /*securityAttributes*/));
// different conventions for CreateDirectory and mkdir
return createRet == 0 ? 1 : 0;
}
- /**************************************
- * Converts a path to one suitable to be passed to Win32 API
- * functions that can deal with paths longer than 248
- * characters then calls the supplied function on it.
- *
- * Params:
- * path = The Path to call F on.
- *
- * Returns:
- * The result of calling F on path.
- *
- * References:
- * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
- */
- package auto extendedPathThen(alias F)(const(char)[] path)
- {
- if (!path.length)
- return F((wchar[]).init);
- return path.toWStringzThen!((wpath)
- {
- // GetFullPathNameW expects a sized buffer to store the result in. Since we don't
- // know how large it has to be, we pass in null and get the needed buffer length
- // as the return code.
- const pathLength = GetFullPathNameW(&wpath[0],
- 0 /*length8*/,
- null /*output buffer*/,
- null /*filePartBuffer*/);
- if (pathLength == 0)
- {
- return F((wchar[]).init);
- }
-
- // wpath is the UTF16 version of path, but to be able to use
- // extended paths, we need to prefix with `\\?\` and the absolute
- // path.
- static immutable prefix = `\\?\`w;
-
- // prefix only needed for long names and non-UNC names
- const needsPrefix = pathLength >= MAX_PATH && (wpath[0] != '\\' || wpath[1] != '\\');
- const prefixLength = needsPrefix ? prefix.length : 0;
-
- // +1 for the null terminator
- const bufferLength = pathLength + prefixLength + 1;
-
- wchar[1024] absBuf = void;
- wchar[] absPath = bufferLength > absBuf.length
- ? new wchar[bufferLength] : absBuf[0 .. bufferLength];
-
- absPath[0 .. prefixLength] = prefix[0 .. prefixLength];
-
- const absPathRet = GetFullPathNameW(&wpath[0],
- cast(uint)(absPath.length - prefixLength - 1),
- &absPath[prefixLength],
- null /*filePartBuffer*/);
-
- if (absPathRet == 0 || absPathRet > absPath.length - prefixLength)
- {
- return F((wchar[]).init);
- }
-
- absPath[$ - 1] = '\0';
- // Strip null terminator from the slice
- return F(absPath[0 .. $ - 1]);
- });
- }
-
/**********************************
* Converts a UTF-16 string to a (null-terminated) narrow string.
* Returns:
@@ -1223,33 +1159,6 @@ version(Windows)
}
/**********************************
- * Converts a narrow string to a (null-terminated) UTF-16 string.
- * Returns:
- * If `buffer` is specified and the result fits, a slice of that buffer,
- * otherwise a new buffer which can be released via `mem.xfree()`.
- * Nulls are propagated, i.e., if `narrow` is null, the returned slice is
- * null too.
- */
- wchar[] toWStringz(const(char)[] narrow, wchar[] buffer = null) nothrow
- {
- if (narrow is null)
- return null;
-
- const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
- if (requiredLength < buffer.length)
- {
- buffer[requiredLength] = 0;
- return buffer[0 .. requiredLength];
- }
-
- wchar* newBuffer = cast(wchar*) mem.xmalloc_noscan((requiredLength + 1) * wchar.sizeof);
- const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, newBuffer, requiredLength);
- assert(length == requiredLength);
- newBuffer[length] = 0;
- return newBuffer[0 .. length];
- }
-
- /**********************************
* Converts a slice of UTF-8 characters to an array of wchar that's null
* terminated so it can be passed to Win32 APIs then calls the supplied
* function on it.
@@ -1262,9 +1171,12 @@ version(Windows)
*/
private auto toWStringzThen(alias F)(const(char)[] str) nothrow
{
+ import dmd.common.string : SmallBuffer, toWStringz;
+
if (!str.length) return F(""w.ptr);
- wchar[1024] buf = void;
+ wchar[1024] support = void;
+ auto buf = SmallBuffer!wchar(support.length, support);
wchar[] wide = toWStringz(str, buf);
scope(exit) wide.ptr != buf.ptr && mem.xfree(wide.ptr);
diff --git a/gcc/d/dmd/root/hash.h b/gcc/d/dmd/root/hash.h
deleted file mode 100644
index 6a32200..0000000
--- a/gcc/d/dmd/root/hash.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Compiler implementation of the D programming language
- * http://dlang.org
- *
- * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * Authors: Martin Nowak, Walter Bright, http://www.digitalmars.com
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(DMDSRC root/_hash.h)
- */
-
-#pragma once
-
-#include "dsystem.h" // uint{8|16|32}_t
-
-// MurmurHash2 was written by Austin Appleby, and is placed in the public
-// domain. The author hereby disclaims copyright to this source code.
-// https://sites.google.com/site/murmurhash/
-static inline uint32_t calcHash(const uint8_t *data, size_t len)
-{
- // 'm' and 'r' are mixing constants generated offline.
- // They're not really 'magic', they just happen to work well.
-
- const uint32_t m = 0x5bd1e995;
- const int r = 24;
-
- // Initialize the hash to a 'random' value
-
- uint32_t h = (uint32_t)len;
-
- // Mix 4 bytes at a time into the hash
-
- while(len >= 4)
- {
- uint32_t k = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
-
- k *= m;
- k ^= k >> r;
- k *= m;
-
- h *= m;
- h ^= k;
-
- data += 4;
- len -= 4;
- }
-
- // Handle the last few bytes of the input array
-
- switch(len & 3)
- {
- case 3: h ^= data[2] << 16; /* fall through */
- case 2: h ^= data[1] << 8; /* fall through */
- case 1: h ^= data[0];
- h *= m;
- }
-
- // Do a few final mixes of the hash to ensure the last few
- // bytes are well-incorporated.
-
- h ^= h >> 13;
- h *= m;
- h ^= h >> 15;
-
- return h;
-}
-
-static inline uint32_t calcHash(const char *data, size_t len)
-{
- return calcHash((const uint8_t *)data, len);
-}
-
-// combine and mix two words (boost::hash_combine)
-static inline size_t mixHash(size_t h, size_t k)
-{
- return h ^ (k + 0x9e3779b9 + (h << 6) + (h >> 2));
-}
diff --git a/gcc/d/dmd/root/rootobject.d b/gcc/d/dmd/root/rootobject.d
index 854ec1a..64104b8 100644
--- a/gcc/d/dmd/root/rootobject.d
+++ b/gcc/d/dmd/root/rootobject.d
@@ -13,7 +13,7 @@ module dmd.root.rootobject;
import core.stdc.stdio;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
/***********************************************************
*/
diff --git a/gcc/d/dmd/root/speller.h b/gcc/d/dmd/root/speller.h
deleted file mode 100644
index bd53fc4..0000000
--- a/gcc/d/dmd/root/speller.h
+++ /dev/null
@@ -1,16 +0,0 @@
-
-/* Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/speller.h
- */
-
-#pragma once
-
-typedef void *(fp_speller_t)(void *, const char *, int*);
-
-extern const char idchars[];
-
-void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset);
-
diff --git a/gcc/d/dmd/root/stringtable.h b/gcc/d/dmd/root/stringtable.h
deleted file mode 100644
index 51304d3..0000000
--- a/gcc/d/dmd/root/stringtable.h
+++ /dev/null
@@ -1,56 +0,0 @@
-
-/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.h
- */
-
-#pragma once
-
-#include "root.h"
-
-struct StringEntry;
-
-// StringValue is a variable-length structure. It has neither proper c'tors nor a
-// factory method because the only thing which should be creating these is StringTable.
-struct StringValue
-{
- void *ptrvalue;
- size_t length;
- char *lstring() { return (char *)(this + 1); }
-
- size_t len() const { return length; }
- const char *toDchars() const { return (const char *)(this + 1); }
-
- StringValue(); // not constructible
-};
-
-struct StringTable
-{
-private:
- StringEntry *table;
- size_t tabledim;
-
- uint8_t **pools;
- size_t npools;
- size_t nfill;
-
- size_t count;
-
-public:
- void _init(size_t size = 0);
- void reset(size_t size = 0);
- ~StringTable();
-
- StringValue *lookup(const char *s, size_t len);
- StringValue *insert(const char *s, size_t len, void *ptrvalue);
- StringValue *update(const char *s, size_t len);
- int apply(int (*fp)(StringValue *));
-
-private:
- uint32_t allocValue(const char *p, size_t length, void *ptrvalue);
- StringValue *getValue(uint32_t validx);
- size_t findSlot(hash_t hash, const char *s, size_t len);
- void grow();
-};
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index 35734b2..8904959 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -89,7 +89,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
if (hasPointers && v.type.toBasetype().ty != Tstruct)
{
- if ((ad.type.alignment() < target.ptrsize ||
+ if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize ||
(v.offset & (target.ptrsize - 1))) &&
sc.func.setUnsafe())
{
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index 7b2fa5e..993db90 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -53,7 +53,7 @@ import dmd.objc;
import dmd.opover;
import dmd.parse;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.rootobject;
import dmd.sideeffect;
@@ -363,7 +363,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
assert(fd.semanticRun <= PASS.semantic2);
fd.semanticRun = PASS.semantic2;
- //printf("FuncDeclaration::semantic2 [%s] fd0 = %s %s\n", loc.toChars(), toChars(), type.toChars());
+ //printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr);
// Only check valid functions which have a body to avoid errors
// for multiple declarations, e.g.
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index ac2b239..3852d0b 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -55,7 +55,7 @@ import dmd.objc;
import dmd.opover;
import dmd.parse;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.rootobject;
import dmd.sideeffect;
@@ -407,7 +407,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc2.insert(_arguments);
_arguments.parent = funcdecl;
}
- if (f.linkage == LINK.d || f.parameterList.length)
+ if ((f.linkage == LINK.d || f.parameterList.length) &&
+ !(sc.flags & SCOPE.Cfile)) // don't want to require importing stdarg for C files
{
// Declare _argptr
Type t = target.va_listType(funcdecl.loc, sc);
@@ -598,7 +599,10 @@ private extern(C++) final class Semantic3Visitor : Visitor
f.next = Type.tvoid;
if (f.checkRetType(funcdecl.loc))
funcdecl.fbody = new ErrorStatement();
+ else if (funcdecl.isMain())
+ funcdecl.checkDmain(); // Check main() parameters and return type
}
+
if (global.params.vcomplex && f.next !is null)
f.next.checkComplexTransition(funcdecl.loc, sc);
@@ -777,8 +781,14 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
assert(!funcdecl.returnLabel);
}
- else if (f.next.ty == Tnoreturn)
+ else if (f.next.toBasetype().ty == Tnoreturn)
{
+ // Fallthrough despite being declared as noreturn? return is already rejected when evaluating the ReturnStatement
+ if (blockexit & BE.fallthru)
+ {
+ funcdecl.error("is typed as `%s` but does return", f.next.toChars());
+ funcdecl.loc.errorSupplemental("`noreturn` functions must either throw, abort or loop indefinitely");
+ }
}
else
{
@@ -1571,7 +1581,7 @@ private struct FuncDeclSem3
}
}
-private void semanticTypeInfoMembers(StructDeclaration sd)
+extern (C++) void semanticTypeInfoMembers(StructDeclaration sd)
{
if (sd.xeq &&
sd.xeq._scope &&
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index b49c903..91e3fe7 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -39,7 +39,7 @@ import dmd.id;
import dmd.identifier;
import dmd.dinterpret;
import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.sapply;
import dmd.sideeffect;
@@ -463,7 +463,7 @@ extern (C++) class ExpStatement : Statement
this.exp = new DeclarationExp(loc, declaration);
}
- static ExpStatement create(Loc loc, Expression exp)
+ static ExpStatement create(const ref Loc loc, Expression exp)
{
return new ExpStatement(loc, exp);
}
@@ -577,7 +577,7 @@ extern (C++) class CompoundStatement : Statement
statements.push(s);
}
- static CompoundStatement create(Loc loc, Statement s1, Statement s2)
+ static CompoundStatement create(const ref Loc loc, Statement s1, Statement s2)
{
return new CompoundStatement(loc, s1, s2);
}
@@ -1635,7 +1635,7 @@ extern (C++) final class TryFinallyStatement : Statement
this.bodyFallsThru = true; // assume true until statementSemantic()
}
- static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody)
+ static TryFinallyStatement create(const ref Loc loc, Statement _body, Statement finalbody)
{
return new TryFinallyStatement(loc, _body, finalbody);
}
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index 7825762..98b7bd3 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -186,7 +186,7 @@ class ExpStatement : public Statement
public:
Expression *exp;
- static ExpStatement *create(Loc loc, Expression *exp);
+ static ExpStatement *create(const Loc &loc, Expression *exp);
ExpStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
@@ -218,7 +218,7 @@ class CompoundStatement : public Statement
public:
Statements *statements;
- static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2);
+ static CompoundStatement *create(const Loc &loc, Statement *s1, Statement *s2);
CompoundStatement *syntaxCopy();
ReturnStatement *endsWithReturnStatement();
Statement *last();
@@ -615,7 +615,7 @@ public:
Statement *tryBody; // set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
bool bodyFallsThru; // true if _body falls through to finally
- static TryFinallyStatement *create(Loc loc, Statement *body, Statement *finalbody);
+ static TryFinallyStatement *create(const Loc &loc, Statement *body, Statement *finalbody);
TryFinallyStatement *syntaxCopy();
bool hasBreak() const;
bool hasContinue() const;
diff --git a/gcc/d/dmd/statement_rewrite_walker.h b/gcc/d/dmd/statement_rewrite_walker.h
deleted file mode 100644
index 28a930a..0000000
--- a/gcc/d/dmd/statement_rewrite_walker.h
+++ /dev/null
@@ -1,172 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "statement.h"
-#include "visitor.h"
-
-/* A visitor to walk entire statements and provides ability to replace any sub-statements.
- */
-class StatementRewriteWalker : public Visitor
-{
- /* Point the currently visited statement.
- * By using replaceCurrent() method, you can replace AST during walking.
- */
- Statement **ps;
-public:
- void visitStmt(Statement *&s) { ps = &s; s->accept(this); }
- void replaceCurrent(Statement *s) { *ps = s; }
-
- void visit(ErrorStatement *) { }
- void visit(PeelStatement *s)
- {
- if (s->s)
- visitStmt(s->s);
- }
- void visit(ExpStatement *) { }
- void visit(DtorExpStatement *) { }
- void visit(CompileStatement *) { }
- void visit(CompoundStatement *s)
- {
- if (s->statements && s->statements->length)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- {
- if ((*s->statements)[i])
- visitStmt((*s->statements)[i]);
- }
- }
- }
- void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
- void visit(UnrolledLoopStatement *s)
- {
- if (s->statements && s->statements->length)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- {
- if ((*s->statements)[i])
- visitStmt((*s->statements)[i]);
- }
- }
- }
- void visit(ScopeStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(WhileStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(DoStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(ForStatement *s)
- {
- if (s->_init)
- visitStmt(s->_init);
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(ForeachStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(ForeachRangeStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(IfStatement *s)
- {
- if (s->ifbody)
- visitStmt(s->ifbody);
- if (s->elsebody)
- visitStmt(s->elsebody);
- }
- void visit(ConditionalStatement *) { }
- void visit(PragmaStatement *) { }
- void visit(StaticAssertStatement *) { }
- void visit(SwitchStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(CaseStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(CaseRangeStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(DefaultStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(GotoDefaultStatement *) { }
- void visit(GotoCaseStatement *) { }
- void visit(SwitchErrorStatement *) { }
- void visit(ReturnStatement *) { }
- void visit(BreakStatement *) { }
- void visit(ContinueStatement *) { }
- void visit(SynchronizedStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(WithStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- }
- void visit(TryCatchStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- if (s->catches && s->catches->length)
- {
- for (size_t i = 0; i < s->catches->length; i++)
- {
- Catch *c = (*s->catches)[i];
- if (c && c->handler)
- visitStmt(c->handler);
- }
- }
- }
- void visit(TryFinallyStatement *s)
- {
- if (s->_body)
- visitStmt(s->_body);
- if (s->finalbody)
- visitStmt(s->finalbody);
- }
- void visit(ScopeGuardStatement *) { }
- void visit(ThrowStatement *) { }
- void visit(DebugStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(GotoStatement *) { }
- void visit(LabelStatement *s)
- {
- if (s->statement)
- visitStmt(s->statement);
- }
- void visit(AsmStatement *) { }
- void visit(ImportStatement *) { }
-};
-
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index f067c91..9eba2ff 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -54,7 +54,7 @@ import dmd.nogc;
import dmd.opover;
import dmd.parse;
import dmd.printast;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.string;
import dmd.semantic2;
import dmd.sideeffect;
@@ -659,20 +659,6 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
result = fs;
}
- /*******************
- * Determines the return type of makeTupleForeach.
- */
- private static template MakeTupleForeachRet(bool isDecl)
- {
- static if(isDecl)
- {
- alias MakeTupleForeachRet = Dsymbols*;
- }
- else
- {
- alias MakeTupleForeachRet = void;
- }
- }
/*******************
* Type check and unroll `foreach` over an expression tuple as well
@@ -696,29 +682,24 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
* expands the tuples into multiple `STC.local` `static foreach`
* variables.
*/
- MakeTupleForeachRet!isDecl makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, TupleForeachArgs!(isStatic, isDecl) args)
+ auto makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
{
- auto returnEarly()
- {
- static if (isDecl)
- {
- return null;
- }
- else
- {
- result = new ErrorStatement();
- return;
- }
- }
- static if(isDecl)
+ // Voldemort return type
+ union U
{
- static assert(isStatic);
- auto dbody = args[0];
+ Statement statement;
+ Dsymbols* decl;
}
- static if(isStatic)
+
+ U result;
+
+ auto returnEarly()
{
- auto needExpansion = args[$-1];
- assert(sc);
+ if (isDecl)
+ result.decl = null;
+ else
+ result.statement = new ErrorStatement();
+ return result;
}
auto loc = fs.loc;
@@ -827,7 +808,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
}
Initializer ie = new ExpInitializer(Loc.initial, new IntegerExp(k));
auto var = new VarDeclaration(loc, p.type, p.ident, ie);
- var.storage_class |= STC.manifest;
+ var.storage_class |= STC.foreach_ | STC.manifest;
static if(isStatic) var.storage_class |= STC.local;
static if(!isDecl)
{
@@ -919,8 +900,9 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
e = resolveProperties(sc, e);
Initializer ie = new ExpInitializer(Loc.initial, e);
auto v = new VarDeclaration(loc, type, ident, ie, storageClass);
+ v.storage_class |= STC.foreach_;
if (storageClass & STC.ref_)
- v.storage_class |= STC.ref_ | STC.foreach_;
+ v.storage_class |= STC.ref_;
if (isStatic || storageClass&STC.manifest || e.isConst() ||
e.op == TOK.string_ ||
e.op == TOK.structLiteral ||
@@ -1057,23 +1039,17 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
ls.gotoTarget = res;
if (te && te.e0)
res = new CompoundStatement(loc, new ExpStatement(te.e0.loc, te.e0), res);
+ result.statement = res;
}
else static if (!isDecl)
{
- Statement res = new CompoundStatement(loc, statements);
- }
- else
- {
- auto res = declarations;
- }
- static if (!isDecl)
- {
- result = res;
+ result.statement = new CompoundStatement(loc, statements);
}
else
{
- return res;
+ result.decl = declarations;
}
+ return result;
}
override void visit(ForeachStatement fs)
@@ -1202,10 +1178,10 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
if (tab.ty == Ttuple) // don't generate new scope for tuple loops
{
- makeTupleForeach!(false,false)(fs);
+ Statement s = makeTupleForeach!(false,false)(fs, null, false).statement;
if (vinit)
- result = new CompoundStatement(loc, new ExpStatement(loc, vinit), result);
- result = result.statementSemantic(sc);
+ s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s);
+ result = s.statementSemantic(sc);
return;
}
@@ -2727,7 +2703,8 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
needswitcherror = true;
}
- if (!sc.sw.sdefault && (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
+ if (!sc.sw.sdefault && !(sc.flags & SCOPE.Cfile) &&
+ (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
{
ss.hasNoDefault = 1;
@@ -3061,7 +3038,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
if (lval - fval > 256)
{
- crs.error("had %llu cases which is more than 256 cases in case range", lval - fval);
+ crs.error("had %llu cases which is more than 257 cases in case range", 1 + lval - fval);
errors = true;
lval = fval + 256;
}
@@ -3295,12 +3272,14 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
if (e0)
e0 = e0.optimize(WANTvalue);
- /* Void-return function can have void typed expression
+ /* Void-return function can have void / noreturn typed expression
* on return statement.
*/
- if (tbret && tbret.ty == Tvoid || rs.exp.type.ty == Tvoid)
+ const convToVoid = rs.exp.type.ty == Tvoid || rs.exp.type.ty == Tnoreturn;
+
+ if (tbret && tbret.ty == Tvoid || convToVoid)
{
- if (rs.exp.type.ty != Tvoid)
+ if (!convToVoid)
{
rs.error("cannot return non-void from `void` function");
errors = true;
@@ -3345,7 +3324,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
}
else if (rs.exp.op != TOK.error)
{
- rs.error("Expected return type of `%s`, not `%s`:",
+ rs.error("expected return type of `%s`, not `%s`:",
tret.toChars(),
rs.exp.type.toChars());
errorSupplemental((fd.returns) ? (*fd.returns)[0].loc : fd.loc,
@@ -3409,10 +3388,20 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
}
else
{
+ // Type of the returned expression (if any), might've been moved to e0
+ auto resType = e0 ? e0.type : Type.tvoid;
+
// infer return type
if (fd.inferRetType)
{
- if (tf.next && tf.next.ty != Tvoid)
+ // 1. First `return <noreturn exp>?`
+ // 2. Potentially found a returning branch, update accordingly
+ if (!tf.next || tf.next.toBasetype().isTypeNoreturn())
+ {
+ tf.next = resType; // infer void or noreturn
+ }
+ // Found an actual return value before
+ else if (tf.next.ty != Tvoid && !resType.toBasetype().isTypeNoreturn())
{
if (tf.next.ty != Terror)
{
@@ -3421,20 +3410,23 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
errors = true;
tf.next = Type.terror;
}
- else
- tf.next = Type.tvoid;
- tret = tf.next;
+ tret = tf.next;
tbret = tret.toBasetype();
}
if (inferRef) // deduce 'auto ref'
tf.isref = false;
- if (tbret.ty != Tvoid) // if non-void return
+ if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return
{
if (tbret.ty != Terror)
- rs.error("`return` expression expected");
+ {
+ if (e0)
+ rs.error("expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars());
+ else
+ rs.error("`return` expression expected");
+ }
errors = true;
}
else if (fd.isMain())
@@ -3522,7 +3514,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
}
else
{
- result = new CompoundStatement(rs.loc, new ExpStatement(rs.loc, e0), rs);
+ auto es = new ExpStatement(rs.loc, e0);
+ if (e0.type.isTypeNoreturn())
+ result = es; // Omit unreachable return;
+ else
+ result = new CompoundStatement(rs.loc, es, rs);
+
return;
}
}
@@ -4014,7 +4011,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
/* If catch exception type is derived from Exception
*/
if (c.type.toBasetype().implicitConvTo(ClassDeclaration.exception.type) &&
- (!c.handler || !c.handler.comeFrom()))
+ (!c.handler || !c.handler.comeFrom()) && !(sc.flags & SCOPE.debug_))
{
// Remove c from the array of catches
tcs.catches.remove(i);
@@ -4570,44 +4567,13 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St
/*******************
- * Determines additional argument types for makeTupleForeach.
- */
-static template TupleForeachArgs(bool isStatic, bool isDecl)
-{
- alias Seq(T...)=T;
- static if(isStatic) alias T = Seq!(bool);
- else alias T = Seq!();
- static if(!isDecl) alias TupleForeachArgs = T;
- else alias TupleForeachArgs = Seq!(Dsymbols*,T);
-}
-
-/*******************
- * Determines the return type of makeTupleForeach.
- */
-static template TupleForeachRet(bool isStatic, bool isDecl)
-{
- alias Seq(T...)=T;
- static if(!isDecl) alias TupleForeachRet = Statement;
- else alias TupleForeachRet = Dsymbols*;
-}
-
-
-/*******************
* See StatementSemanticVisitor.makeTupleForeach. This is a simple
* wrapper that returns the generated statements/declarations.
*/
-TupleForeachRet!(isStatic, isDecl) makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, TupleForeachArgs!(isStatic, isDecl) args)
+auto makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
{
scope v = new StatementSemanticVisitor(sc);
- static if(!isDecl)
- {
- v.makeTupleForeach!(isStatic, isDecl)(fs, args);
- return v.result;
- }
- else
- {
- return v.makeTupleForeach!(isStatic, isDecl)(fs, args);
- }
+ return v.makeTupleForeach!(isStatic, isDecl)(fs, dbody, needExpansion);
}
/*********************************
@@ -4731,7 +4697,7 @@ private Statements* flatten(Statement statement, Scope* sc)
sfs.sfe.prepare(sc);
if (sfs.sfe.ready())
{
- auto s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, sfs.sfe.needExpansion);
+ Statement s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, null, sfs.sfe.needExpansion).statement;
auto result = s.flatten(sc);
if (result)
{
diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d
index 2f27414..d1578ec 100644
--- a/gcc/d/dmd/staticcond.d
+++ b/gcc/d/dmd/staticcond.d
@@ -22,7 +22,7 @@ import dmd.globals;
import dmd.identifier;
import dmd.mtype;
import dmd.root.array;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.tokens;
diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d
index d5b3de2..16739ad 100644
--- a/gcc/d/dmd/target.d
+++ b/gcc/d/dmd/target.d
@@ -316,7 +316,8 @@ struct TargetC
enum BitFieldStyle : ubyte
{
Unspecified,
- Dm_Ms, /// Digital Mars and Microsoft C compilers
+ DM, /// Digital Mars 32 bit C compiler
+ MS, /// Microsoft 32 and 64 bit C compilers
/// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
/// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
Gcc_Clang, /// gcc and clang
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index 83281a6..6a75ccc 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -63,7 +63,8 @@ struct TargetC
enum class BitFieldStyle : unsigned char
{
Unspecified,
- Dm_Ms, // Digital Mars and Microsoft C compilers
+ DM, // Digital Mars 32 bit C compiler
+ MS, // Microsoft 32 and 64 bit C compilers
// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
Gcc_Clang, // gcc and clang
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 08ce9ac..69cc84f 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -131,7 +131,7 @@ public:
virtual bool declareParameter(Scope *sc) = 0;
virtual void print(RootObject *oarg, RootObject *oded) = 0;
virtual RootObject *specialization() = 0;
- virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0;
+ virtual RootObject *defaultArg(const Loc &instLoc, Scope *sc) = 0;
virtual bool hasDefaultArg() = 0;
/* Create dummy argument based on parameter.
@@ -154,7 +154,7 @@ public:
bool declareParameter(Scope *sc);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
- RootObject *defaultArg(Loc instLoc, Scope *sc);
+ RootObject *defaultArg(const Loc &instLoc, Scope *sc);
bool hasDefaultArg();
RootObject *dummyArg();
void accept(Visitor *v) { v->visit(this); }
@@ -186,7 +186,7 @@ public:
bool declareParameter(Scope *sc);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
- RootObject *defaultArg(Loc instLoc, Scope *sc);
+ RootObject *defaultArg(const Loc &instLoc, Scope *sc);
bool hasDefaultArg();
RootObject *dummyArg();
void accept(Visitor *v) { v->visit(this); }
@@ -207,7 +207,7 @@ public:
bool declareParameter(Scope *sc);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
- RootObject *defaultArg(Loc instLoc, Scope *sc);
+ RootObject *defaultArg(const Loc &instLoc, Scope *sc);
bool hasDefaultArg();
RootObject *dummyArg();
void accept(Visitor *v) { v->visit(this); }
@@ -224,7 +224,7 @@ public:
bool declareParameter(Scope *sc);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
- RootObject *defaultArg(Loc instLoc, Scope *sc);
+ RootObject *defaultArg(const Loc &instLoc, Scope *sc);
bool hasDefaultArg();
RootObject *dummyArg();
void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
index 7680fb8..1ea51a8 100644
--- a/gcc/d/dmd/tokens.d
+++ b/gcc/d/dmd/tokens.d
@@ -19,7 +19,7 @@ import core.stdc.string;
import dmd.globals;
import dmd.identifier;
import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.utf;
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
index 0fd6634..d14d0aa 100644
--- a/gcc/d/dmd/tokens.h
+++ b/gcc/d/dmd/tokens.h
@@ -187,6 +187,7 @@ enum
TOKarrow,
TOKcolonColon,
TOKwchar_tLiteral,
+ TOKcompoundLiteral,
TOKinline,
TOKregister,
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 8f968ed..cc1d2e3 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -49,7 +49,7 @@ import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
import dmd.root.rootobject;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.string;
enum LOGSEMANTIC = false;
@@ -1410,19 +1410,30 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
auto o = (*e.args)[0];
auto o1 = (*e.args)[1];
- FuncDeclaration fd;
- TypeFunction tf = toTypeFunction(o, fd);
-
ParameterList fparams;
- if (tf)
- fparams = tf.parameterList;
- else if (fd)
- fparams = fd.getParameterList();
+
+ CallExp ce;
+ if (auto exp = isExpression(o))
+ ce = exp.isCallExp();
+
+ if (ce)
+ {
+ fparams = ce.f.getParameterList();
+ }
else
{
- e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
- o.toChars(), o1.toChars());
- return ErrorExp.get();
+ FuncDeclaration fd;
+ auto tf = toTypeFunction(o, fd);
+ if (tf)
+ fparams = tf.parameterList;
+ else if (fd)
+ fparams = fd.getParameterList();
+ else
+ {
+ e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function or a function call",
+ o.toChars(), o1.toChars());
+ return ErrorExp.get();
+ }
}
// Avoid further analysis for invalid functions leading to misleading error messages
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index ace4e42..f75ae0e 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -44,6 +44,7 @@ import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.imphint;
+import dmd.importc;
import dmd.init;
import dmd.initsem;
import dmd.visitor;
@@ -53,7 +54,7 @@ import dmd.opover;
import dmd.parse;
import dmd.root.ctfloat;
import dmd.root.rmem;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.rootobject;
import dmd.root.string;
import dmd.root.stringtable;
@@ -1334,6 +1335,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
continue;
}
+ fparam.type = fparam.type.cAdjustParamType(sc); // adjust C array and function parameter types
+
Type t = fparam.type.toBasetype();
/* If fparam after semantic() turns out to be a tuple, the number of parameters may
@@ -1378,6 +1381,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
}
fparam.type = new TypeTuple(newparams);
+ fparam.type = fparam.type.typeSemantic(loc, argsc);
}
fparam.storageClass = STC.parameter;
@@ -1627,7 +1631,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
errors = true;
}
- if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0)
+ if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
+ !(sc.flags & SCOPE.Cfile))
{
.error(loc, "variadic functions with non-D linkage must have at least one parameter");
errors = true;
@@ -1750,10 +1755,10 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
{
// if there was an error evaluating the symbol, it might actually
// be a type. Avoid misleading error messages.
- .error(loc, "`%s` had previous errors", mtype.toChars());
+ .error(loc, "`%s` had previous errors", mtype.toChars());
}
else
- .error(loc, "`%s` is used as a type", mtype.toChars());
+ .error(loc, "`%s` is used as a type", mtype.toChars());
return error();
}
return t;
@@ -2133,6 +2138,15 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
* struct S { int a; } *s;
*/
sd.members = mtype.members;
+ if (sd.semanticRun == PASS.semanticdone)
+ {
+ /* The first semantic pass marked `sd` as an opaque struct.
+ * Re-run semantic so that all newly assigned members are
+ * picked up and added to the symtab.
+ */
+ sd.semanticRun = PASS.semantic;
+ sd.dsymbolSemantic(sc);
+ }
}
else
{
@@ -2264,7 +2278,7 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
* Returns:
* the type that was merged
*/
-Type merge(Type type)
+extern (C++) Type merge(Type type)
{
switch (type.ty)
{
@@ -2361,7 +2375,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
{
const explicitAlignment = mt.alignment();
const naturalAlignment = mt.alignsize();
- const actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment);
+ const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
}
else if (ident == Id._init)
@@ -3734,10 +3748,18 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
}
/***************************************
- * Figures out what to do with an undefined member reference
- * for classes and structs.
- *
- * If flag & 1, don't report "not a property" error and just return NULL.
+ * `ident` was not found as a member of `mt`.
+ * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
+ * If that fails, forward to visitType().
+ * Params:
+ * mt = class or struct
+ * sc = context
+ * e = `this` for `ident`
+ * ident = name of member
+ * flag = flag & 1, don't report "not a property" error and just return NULL.
+ * flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
+ * Returns:
+ * resolved expression if found, otherwise null
*/
Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
{
@@ -3828,7 +3850,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
/* See if we should forward to the alias this.
*/
- auto alias_e = resolveAliasThis(sc, e, gagError);
+ auto alias_e = flag & DotExpFlag.noAliasThis ? null
+ : resolveAliasThis(sc, e, gagError);
if (alias_e && alias_e != e)
{
/* Rewrite e.ident as:
@@ -4611,7 +4634,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
* Returns:
* The initialization expression for the type.
*/
-Expression defaultInit(Type mt, const ref Loc loc)
+extern (C++) Expression defaultInit(Type mt, const ref Loc loc)
{
Expression visitBasic(TypeBasic mt)
{
@@ -4744,6 +4767,7 @@ Expression defaultInit(Type mt, const ref Loc loc)
}
auto cond = IntegerExp.createBool(false);
auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
+ msg.type = Type.tstring;
auto ae = new AssertExp(loc, cond, msg);
ae.type = mt;
return ae;
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index d8160f0..d05af61 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -1,5 +1,5 @@
/**
- * Generate `TypeInfo` objects, which are needed for run-time introspection of classes.
+ * Generate `TypeInfo` objects, which are needed for run-time introspection of types.
*
* Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
@@ -11,9 +11,87 @@
module dmd.typinf;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dmodule;
import dmd.dscope;
+import dmd.dclass;
+import dmd.dstruct;
+import dmd.errors;
import dmd.globals;
+import dmd.gluelayer;
import dmd.mtype;
+import dmd.visitor;
+import core.stdc.stdio;
+
+/****************************************************
+ * Generates the `TypeInfo` object associated with `torig` if it
+ * hasn't already been generated
+ * Params:
+ * loc = the location for reporting line numbers in errors
+ * torig = the type to generate the `TypeInfo` object for
+ * sc = the scope
+ */
+extern (C++) void genTypeInfo(const ref Loc loc, Type torig, Scope* sc)
+{
+ // printf("genTypeInfo() %s\n", torig.toChars());
+
+ // Even when compiling without `useTypeInfo` (e.g. -betterC) we should
+ // still be able to evaluate `TypeInfo` at compile-time, just not at runtime.
+ // https://issues.dlang.org/show_bug.cgi?id=18472
+ if (!sc || !(sc.flags & SCOPE.ctfe))
+ {
+ if (!global.params.useTypeInfo)
+ {
+ .error(loc, "`TypeInfo` cannot be used with -betterC");
+ fatal();
+ }
+ }
+
+ if (!Type.dtypeinfo)
+ {
+ .error(loc, "`object.TypeInfo` could not be found, but is implicitly used");
+ fatal();
+ }
+
+ Type t = torig.merge2(); // do this since not all Type's are merge'd
+ if (!t.vtinfo)
+ {
+ if (t.isShared()) // does both 'shared' and 'shared const'
+ t.vtinfo = TypeInfoSharedDeclaration.create(t);
+ else if (t.isConst())
+ t.vtinfo = TypeInfoConstDeclaration.create(t);
+ else if (t.isImmutable())
+ t.vtinfo = TypeInfoInvariantDeclaration.create(t);
+ else if (t.isWild())
+ t.vtinfo = TypeInfoWildDeclaration.create(t);
+ else
+ t.vtinfo = getTypeInfoDeclaration(t);
+ assert(t.vtinfo);
+
+ // ClassInfos are generated as part of ClassDeclaration codegen
+ const isUnqualifiedClassInfo = (t.ty == Tclass && !t.mod);
+
+ // generate a COMDAT for other TypeInfos not available as builtins in
+ // druntime
+ if (!isUnqualifiedClassInfo && !builtinTypeInfo(t))
+ {
+ if (sc) // if in semantic() pass
+ {
+ // Find module that will go all the way to an object file
+ Module m = sc._module.importedFrom;
+ m.members.push(t.vtinfo);
+ }
+ else // if in obj generation pass
+ {
+ toObjFile(t.vtinfo, global.params.multiobj);
+ }
+ }
+ }
+ if (!torig.vtinfo)
+ torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
+ assert(torig.vtinfo);
+}
/****************************************************
* Gets the type of the `TypeInfo` object associated with `t`
@@ -24,5 +102,161 @@ import dmd.mtype;
* Returns:
* The type of the `TypeInfo` object associated with `t`
*/
-extern (C++) Type getTypeInfoType(Loc loc, Type t, Scope* sc);
+extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc);
+
+private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
+{
+ //printf("Type::getTypeInfoDeclaration() %s\n", t.toChars());
+ switch (t.ty)
+ {
+ case Tpointer:
+ return TypeInfoPointerDeclaration.create(t);
+ case Tarray:
+ return TypeInfoArrayDeclaration.create(t);
+ case Tsarray:
+ return TypeInfoStaticArrayDeclaration.create(t);
+ case Taarray:
+ return TypeInfoAssociativeArrayDeclaration.create(t);
+ case Tstruct:
+ return TypeInfoStructDeclaration.create(t);
+ case Tvector:
+ return TypeInfoVectorDeclaration.create(t);
+ case Tenum:
+ return TypeInfoEnumDeclaration.create(t);
+ case Tfunction:
+ return TypeInfoFunctionDeclaration.create(t);
+ case Tdelegate:
+ return TypeInfoDelegateDeclaration.create(t);
+ case Ttuple:
+ return TypeInfoTupleDeclaration.create(t);
+ case Tclass:
+ if ((cast(TypeClass)t).sym.isInterfaceDeclaration())
+ return TypeInfoInterfaceDeclaration.create(t);
+ else
+ return TypeInfoClassDeclaration.create(t);
+
+ default:
+ return TypeInfoDeclaration.create(t);
+ }
+}
+
+/**************************************************
+ * Returns:
+ * true if any part of type t is speculative.
+ * if t is null, returns false.
+ */
+bool isSpeculativeType(Type t)
+{
+ static bool visitVector(TypeVector t)
+ {
+ return isSpeculativeType(t.basetype);
+ }
+
+ static bool visitAArray(TypeAArray t)
+ {
+ return isSpeculativeType(t.index) ||
+ isSpeculativeType(t.next);
+ }
+
+ static bool visitStruct(TypeStruct t)
+ {
+ StructDeclaration sd = t.sym;
+ if (auto ti = sd.isInstantiated())
+ {
+ if (!ti.needsCodegen())
+ {
+ if (ti.minst || sd.requestTypeInfo)
+ return false;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=14425
+ * TypeInfo_Struct would refer the members of
+ * struct (e.g. opEquals via xopEquals field), so if it's instantiated
+ * in speculative context, TypeInfo creation should also be
+ * stopped to avoid 'unresolved symbol' linker errors.
+ */
+ /* When -debug/-unittest is specified, all of non-root instances are
+ * automatically changed to speculative, and here is always reached
+ * from those instantiated non-root structs.
+ * Therefore, if the TypeInfo is not auctually requested,
+ * we have to elide its codegen.
+ */
+ return true;
+ }
+ }
+ else
+ {
+ //assert(!sd.inNonRoot() || sd.requestTypeInfo); // valid?
+ }
+ return false;
+ }
+
+ static bool visitClass(TypeClass t)
+ {
+ ClassDeclaration sd = t.sym;
+ if (auto ti = sd.isInstantiated())
+ {
+ if (!ti.needsCodegen() && !ti.minst)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static bool visitTuple(TypeTuple t)
+ {
+ if (t.arguments)
+ {
+ foreach (arg; *t.arguments)
+ {
+ if (isSpeculativeType(arg.type))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ if (!t)
+ return false;
+ Type tb = t.toBasetype();
+ switch (tb.ty)
+ {
+ case Tvector: return visitVector(tb.isTypeVector());
+ case Taarray: return visitAArray(tb.isTypeAArray());
+ case Tstruct: return visitStruct(tb.isTypeStruct());
+ case Tclass: return visitClass(tb.isTypeClass());
+ case Ttuple: return visitTuple(tb.isTypeTuple());
+ case Tenum: return false;
+ default:
+ return isSpeculativeType(tb.nextOf());
+
+ /* For TypeFunction, TypeInfo_Function doesn't store parameter types,
+ * so only the .next (the return type) is checked here.
+ */
+ }
+}
+
+/* ========================================================================= */
+
+/* Indicates whether druntime already contains an appropriate TypeInfo instance
+ * for the specified type (in module rt.util.typeinfo).
+ */
+extern (C++) bool builtinTypeInfo(Type t)
+{
+ if (!t.mod) // unqualified types only
+ {
+ // unqualified basic types + typeof(null)
+ if (t.isTypeBasic() || t.ty == Tnull)
+ return true;
+ // some unqualified arrays
+ if (t.ty == Tarray)
+ {
+ Type next = t.nextOf();
+ return (next.isTypeBasic() && !next.mod) // of unqualified basic types
+ || (next.ty == Tchar && next.mod == MODFlags.immutable_) // string
+ || (next.ty == Tchar && next.mod == MODFlags.const_); // const(char)[]
+ }
+ }
+ return false;
+}
diff --git a/gcc/d/dmd/utf.h b/gcc/d/dmd/utf.h
deleted file mode 100644
index b3782af..0000000
--- a/gcc/d/dmd/utf.h
+++ /dev/null
@@ -1,117 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 2003-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/utf.h
- */
-
-#pragma once
-
-#include "root/dsystem.h"
-
-/// A UTF-8 code unit
-typedef unsigned char utf8_t;
-/// A UTF-16 code unit
-typedef unsigned short utf16_t;
-/// A UTF-32 code unit
-typedef unsigned int utf32_t;
-typedef utf32_t dchar_t;
-
-#define ALPHA_TABLE_LENGTH 245
-static utf16_t const ALPHA_TABLE[ALPHA_TABLE_LENGTH][2] =
-{
- { 0x00AA, 0x00AA }, { 0x00B5, 0x00B5 }, { 0x00B7, 0x00B7 }, { 0x00BA, 0x00BA },
- { 0x00C0, 0x00D6 }, { 0x00D8, 0x00F6 }, { 0x00F8, 0x01F5 }, { 0x01FA, 0x0217 },
- { 0x0250, 0x02A8 }, { 0x02B0, 0x02B8 }, { 0x02BB, 0x02BB }, { 0x02BD, 0x02C1 },
- { 0x02D0, 0x02D1 }, { 0x02E0, 0x02E4 }, { 0x037A, 0x037A }, { 0x0386, 0x0386 },
- { 0x0388, 0x038A }, { 0x038C, 0x038C }, { 0x038E, 0x03A1 }, { 0x03A3, 0x03CE },
- { 0x03D0, 0x03D6 }, { 0x03DA, 0x03DA }, { 0x03DC, 0x03DC }, { 0x03DE, 0x03DE },
- { 0x03E0, 0x03E0 }, { 0x03E2, 0x03F3 }, { 0x0401, 0x040C }, { 0x040E, 0x044F },
- { 0x0451, 0x045C }, { 0x045E, 0x0481 }, { 0x0490, 0x04C4 }, { 0x04C7, 0x04C8 },
- { 0x04CB, 0x04CC }, { 0x04D0, 0x04EB }, { 0x04EE, 0x04F5 }, { 0x04F8, 0x04F9 },
- { 0x0531, 0x0556 }, { 0x0559, 0x0559 }, { 0x0561, 0x0587 }, { 0x05B0, 0x05B9 },
- { 0x05BB, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, { 0x05D0, 0x05EA },
- { 0x05F0, 0x05F2 }, { 0x0621, 0x063A }, { 0x0640, 0x0652 }, { 0x0660, 0x0669 },
- { 0x0670, 0x06B7 }, { 0x06BA, 0x06BE }, { 0x06C0, 0x06CE }, { 0x06D0, 0x06DC },
- { 0x06E5, 0x06E8 }, { 0x06EA, 0x06ED }, { 0x06F0, 0x06F9 }, { 0x0901, 0x0903 },
- { 0x0905, 0x0939 }, { 0x093D, 0x094D }, { 0x0950, 0x0952 }, { 0x0958, 0x0963 },
- { 0x0966, 0x096F }, { 0x0981, 0x0983 }, { 0x0985, 0x098C }, { 0x098F, 0x0990 },
- { 0x0993, 0x09A8 }, { 0x09AA, 0x09B0 }, { 0x09B2, 0x09B2 }, { 0x09B6, 0x09B9 },
- { 0x09BE, 0x09C4 }, { 0x09C7, 0x09C8 }, { 0x09CB, 0x09CD }, { 0x09DC, 0x09DD },
- { 0x09DF, 0x09E3 }, { 0x09E6, 0x09F1 }, { 0x0A02, 0x0A02 }, { 0x0A05, 0x0A0A },
- { 0x0A0F, 0x0A10 }, { 0x0A13, 0x0A28 }, { 0x0A2A, 0x0A30 }, { 0x0A32, 0x0A33 },
- { 0x0A35, 0x0A36 }, { 0x0A38, 0x0A39 }, { 0x0A3E, 0x0A42 }, { 0x0A47, 0x0A48 },
- { 0x0A4B, 0x0A4D }, { 0x0A59, 0x0A5C }, { 0x0A5E, 0x0A5E }, { 0x0A66, 0x0A6F },
- { 0x0A74, 0x0A74 }, { 0x0A81, 0x0A83 }, { 0x0A85, 0x0A8B }, { 0x0A8D, 0x0A8D },
- { 0x0A8F, 0x0A91 }, { 0x0A93, 0x0AA8 }, { 0x0AAA, 0x0AB0 }, { 0x0AB2, 0x0AB3 },
- { 0x0AB5, 0x0AB9 }, { 0x0ABD, 0x0AC5 }, { 0x0AC7, 0x0AC9 }, { 0x0ACB, 0x0ACD },
- { 0x0AD0, 0x0AD0 }, { 0x0AE0, 0x0AE0 }, { 0x0AE6, 0x0AEF }, { 0x0B01, 0x0B03 },
- { 0x0B05, 0x0B0C }, { 0x0B0F, 0x0B10 }, { 0x0B13, 0x0B28 }, { 0x0B2A, 0x0B30 },
- { 0x0B32, 0x0B33 }, { 0x0B36, 0x0B39 }, { 0x0B3D, 0x0B43 }, { 0x0B47, 0x0B48 },
- { 0x0B4B, 0x0B4D }, { 0x0B5C, 0x0B5D }, { 0x0B5F, 0x0B61 }, { 0x0B66, 0x0B6F },
- { 0x0B82, 0x0B83 }, { 0x0B85, 0x0B8A }, { 0x0B8E, 0x0B90 }, { 0x0B92, 0x0B95 },
- { 0x0B99, 0x0B9A }, { 0x0B9C, 0x0B9C }, { 0x0B9E, 0x0B9F }, { 0x0BA3, 0x0BA4 },
- { 0x0BA8, 0x0BAA }, { 0x0BAE, 0x0BB5 }, { 0x0BB7, 0x0BB9 }, { 0x0BBE, 0x0BC2 },
- { 0x0BC6, 0x0BC8 }, { 0x0BCA, 0x0BCD }, { 0x0BE7, 0x0BEF }, { 0x0C01, 0x0C03 },
- { 0x0C05, 0x0C0C }, { 0x0C0E, 0x0C10 }, { 0x0C12, 0x0C28 }, { 0x0C2A, 0x0C33 },
- { 0x0C35, 0x0C39 }, { 0x0C3E, 0x0C44 }, { 0x0C46, 0x0C48 }, { 0x0C4A, 0x0C4D },
- { 0x0C60, 0x0C61 }, { 0x0C66, 0x0C6F }, { 0x0C82, 0x0C83 }, { 0x0C85, 0x0C8C },
- { 0x0C8E, 0x0C90 }, { 0x0C92, 0x0CA8 }, { 0x0CAA, 0x0CB3 }, { 0x0CB5, 0x0CB9 },
- { 0x0CBE, 0x0CC4 }, { 0x0CC6, 0x0CC8 }, { 0x0CCA, 0x0CCD }, { 0x0CDE, 0x0CDE },
- { 0x0CE0, 0x0CE1 }, { 0x0CE6, 0x0CEF }, { 0x0D02, 0x0D03 }, { 0x0D05, 0x0D0C },
- { 0x0D0E, 0x0D10 }, { 0x0D12, 0x0D28 }, { 0x0D2A, 0x0D39 }, { 0x0D3E, 0x0D43 },
- { 0x0D46, 0x0D48 }, { 0x0D4A, 0x0D4D }, { 0x0D60, 0x0D61 }, { 0x0D66, 0x0D6F },
- { 0x0E01, 0x0E3A }, { 0x0E40, 0x0E5B }, { 0x0E81, 0x0E82 },
- { 0x0E84, 0x0E84 }, { 0x0E87, 0x0E88 }, { 0x0E8A, 0x0E8A }, { 0x0E8D, 0x0E8D },
- { 0x0E94, 0x0E97 }, { 0x0E99, 0x0E9F }, { 0x0EA1, 0x0EA3 }, { 0x0EA5, 0x0EA5 },
- { 0x0EA7, 0x0EA7 }, { 0x0EAA, 0x0EAB }, { 0x0EAD, 0x0EAE }, { 0x0EB0, 0x0EB9 },
- { 0x0EBB, 0x0EBD }, { 0x0EC0, 0x0EC4 }, { 0x0EC6, 0x0EC6 }, { 0x0EC8, 0x0ECD },
- { 0x0ED0, 0x0ED9 }, { 0x0EDC, 0x0EDD }, { 0x0F00, 0x0F00 }, { 0x0F18, 0x0F19 },
- { 0x0F20, 0x0F33 }, { 0x0F35, 0x0F35 }, { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 },
- { 0x0F3E, 0x0F47 }, { 0x0F49, 0x0F69 }, { 0x0F71, 0x0F84 }, { 0x0F86, 0x0F8B },
- { 0x0F90, 0x0F95 }, { 0x0F97, 0x0F97 }, { 0x0F99, 0x0FAD }, { 0x0FB1, 0x0FB7 },
- { 0x0FB9, 0x0FB9 }, { 0x10A0, 0x10C5 }, { 0x10D0, 0x10F6 }, { 0x1E00, 0x1E9B },
- { 0x1EA0, 0x1EF9 }, { 0x1F00, 0x1F15 }, { 0x1F18, 0x1F1D }, { 0x1F20, 0x1F45 },
- { 0x1F48, 0x1F4D }, { 0x1F50, 0x1F57 }, { 0x1F59, 0x1F59 }, { 0x1F5B, 0x1F5B },
- { 0x1F5D, 0x1F5D }, { 0x1F5F, 0x1F7D }, { 0x1F80, 0x1FB4 }, { 0x1FB6, 0x1FBC },
- { 0x1FBE, 0x1FBE }, { 0x1FC2, 0x1FC4 }, { 0x1FC6, 0x1FCC }, { 0x1FD0, 0x1FD3 },
- { 0x1FD6, 0x1FDB }, { 0x1FE0, 0x1FEC }, { 0x1FF2, 0x1FF4 }, { 0x1FF6, 0x1FFC },
- { 0x203F, 0x2040 }, { 0x207F, 0x207F }, { 0x2102, 0x2102 }, { 0x2107, 0x2107 },
- { 0x210A, 0x2113 }, { 0x2115, 0x2115 }, { 0x2118, 0x211D }, { 0x2124, 0x2124 },
- { 0x2126, 0x2126 }, { 0x2128, 0x2128 }, { 0x212A, 0x2131 }, { 0x2133, 0x2138 },
- { 0x2160, 0x2182 }, { 0x3005, 0x3007 }, { 0x3021, 0x3029 }, { 0x3041, 0x3093 },
- { 0x309B, 0x309C }, { 0x30A1, 0x30F6 }, { 0x30FB, 0x30FC }, { 0x3105, 0x312C },
- { 0x4E00, 0x9FA5 }, { 0xAC00, 0xD7A3 },
-};
-
-char const *const UTF8_DECODE_OK = NULL;
-extern char const UTF8_DECODE_OUTSIDE_CODE_SPACE[];
-extern char const UTF8_DECODE_TRUNCATED_SEQUENCE[];
-extern char const UTF8_DECODE_OVERLONG[];
-extern char const UTF8_DECODE_INVALID_TRAILER[];
-extern char const UTF8_DECODE_INVALID_CODE_POINT[];
-
-char const *const UTF16_DECODE_OK = NULL;
-extern char const UTF16_DECODE_TRUNCATED_SEQUENCE[];
-extern char const UTF16_DECODE_INVALID_SURROGATE[];
-extern char const UTF16_DECODE_UNPAIRED_SURROGATE[];
-extern char const UTF16_DECODE_INVALID_CODE_POINT[];
-
-/// \return true if \a c is a valid, non-private UTF-32 code point
-bool utf_isValidDchar(dchar_t c);
-
-bool isUniAlpha(dchar_t c);
-
-int utf_codeLengthChar(dchar_t c);
-int utf_codeLengthWchar(dchar_t c);
-int utf_codeLength(int sz, dchar_t c);
-
-void utf_encodeChar(utf8_t *s, dchar_t c);
-void utf_encodeWchar(utf16_t *s, dchar_t c);
-void utf_encode(int sz, void *s, dchar_t c);
-
-const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult);
-const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult);
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
index 600521f..6cd5d20 100644
--- a/gcc/d/dmd/utils.d
+++ b/gcc/d/dmd/utils.d
@@ -16,7 +16,7 @@ import dmd.errors;
import dmd.globals;
import dmd.root.file;
import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
import dmd.root.string;
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 3168056..2831eef 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -1757,7 +1757,7 @@ public:
/* C++ constructors return void, even though front-end semantic
treats them as implicitly returning `this'. Set returnvalue
to override the result of this expression. */
- if (fd->isCtorDeclaration () && fd->linkage == LINK::cpp)
+ if (fd->isCtorDeclaration ())
{
thisexp = d_save_expr (thisexp);
returnvalue = thisexp;
@@ -1846,6 +1846,11 @@ public:
{
tree init = TARGET_EXPR_INITIAL (cleanup);
TARGET_EXPR_INITIAL (cleanup) = compound_expr (init, exp);
+
+ /* Keep the return value outside the TARGET_EXPR. */
+ if (returnvalue != NULL_TREE)
+ cleanup = compound_expr (cleanup, TREE_OPERAND (exp, 1));
+
exp = cleanup;
}
@@ -1856,7 +1861,7 @@ public:
void visit (DelegateExp *e)
{
- if (e->func->semanticRun == PASSsemantic3done)
+ if (e->func->semanticRun == PASS::semantic3done)
{
/* Add the function as nested function if it belongs to this module.
ie: it is a member of this module, or it is a template instance. */
diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi
index c98eb1f..d37d205 100644
--- a/gcc/d/gdc.texi
+++ b/gcc/d/gdc.texi
@@ -283,6 +283,13 @@ Sets @code{__traits(getTargetInfo "cppStd")} to @code{202002}.
@cindex @option{-fno-invariants}
Turns off code generation for class @code{invariant} contracts.
+@item -fmain
+@cindex @option{-fmain}
+Generates a default @code{main()} function when compiling. This is useful when
+unittesting a library, as it enables running the unittests in a library without
+having to manually define an entry-point function. This option does nothing
+when @code{main} is already defined in user code.
+
@item -fno-moduleinfo
@cindex @option{-fmoduleinfo}
@cindex @option{-fno-moduleinfo}
@@ -742,6 +749,8 @@ List information on all D language transitions.
List all usages of complex or imaginary types.
@item field
List all non-mutable fields which occupy an object instance.
+@item in
+List all usages of @code{in} on parameter.
@item nogc
List all hidden GC allocations.
@item templates
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index f7f90fb..d0a5e2f 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -436,6 +436,10 @@ ftransition=field
D RejectNegative
List all non-mutable fields which occupy an object instance.
+ftransition=in
+D RejectNegative
+List all usages of 'in' on parameter.
+
ftransition=nogc
D RejectNegative
List all hidden GC allocations.
diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc
index 06eb5ae..cb5c4a7 100644
--- a/gcc/d/modules.cc
+++ b/gcc/d/modules.cc
@@ -145,7 +145,7 @@ get_internal_fn (tree ident, const Visibility &visibility)
fd->loc = Loc (mod->srcfile.toChars (), 1, 0);
fd->parent = mod;
fd->visibility = visibility;
- fd->semanticRun = PASSsemantic3done;
+ fd->semanticRun = PASS::semantic3done;
return fd;
}
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index db500ee..b39b92e 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -610,7 +610,8 @@ public:
void visit (TypeNoreturn *t)
{
- t->ctype = void_type_node;
+ t->ctype = noreturn_type_node;
+ TYPE_NAME (t->ctype) = get_identifier (t->toChars ());
}
/* Basic Data Types. */
@@ -770,11 +771,17 @@ public:
fnparams = chainon (fnparams, build_tree_list (0, type));
}
- size_t n_args = t->parameterList.length ();
+ const size_t n_args = t->parameterList.length ();
for (size_t i = 0; i < n_args; i++)
{
tree type = parameter_type (t->parameterList[i]);
+
+ /* Type `noreturn` is a terminator, as no other arguments can possibly
+ be evaluated after it. */
+ if (type == noreturn_type_node)
+ break;
+
fnparams = chainon (fnparams, build_tree_list (0, type));
}
@@ -797,6 +804,10 @@ public:
TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
d_keep (t->ctype);
+ /* Qualify function types that have the type `noreturn` as volatile. */
+ if (fntype == noreturn_type_node)
+ t->ctype = build_qualified_type (t->ctype, TYPE_QUAL_VOLATILE);
+
/* Handle any special support for calling conventions. */
switch (t->linkage)
{
@@ -995,8 +1006,8 @@ public:
the context or laying out fields as those types may make
recursive references to this type. */
unsigned structsize = t->sym->structsize;
- unsigned alignsize = (t->sym->alignment != STRUCTALIGN_DEFAULT)
- ? t->sym->alignment : t->sym->alignsize;
+ unsigned alignsize = t->sym->alignment.isDefault ()
+ ? t->sym->alignsize : t->sym->alignment.get ();
TYPE_SIZE (t->ctype) = bitsize_int (structsize * BITS_PER_UNIT);
TYPE_SIZE_UNIT (t->ctype) = size_int (structsize);
diff --git a/gcc/testsuite/gdc.test/compilable/b19294.d b/gcc/testsuite/gdc.test/compilable/b19294.d
new file mode 100644
index 0000000..063a9df
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b19294.d
@@ -0,0 +1,69 @@
+alias MT = MyStruct!int;
+
+struct MyStruct(T)
+{
+ T x;
+
+ this(T y)
+ {
+ x = y;
+ }
+
+ MyStruct!T opBinary(string op)(MyStruct!T y) const
+ {
+ alias C = typeof(return);
+ auto w = C(this.x);
+ return w.opOpAssign!(op)(y);
+ }
+
+ MyStruct!T opBinaryRight(string op)(MyStruct!T y) const
+ {
+ return opBinary!(op)(y);
+ }
+
+ ref MyStruct opOpAssign(string op, T)(const MyStruct!T z)
+ {
+ mixin ("x "~op~"= z.x;");
+ return this;
+ }
+
+ MyStruct!T opBinary(string op)(T y) const
+ {
+ alias C = typeof(return);
+ auto w = C(this.x);
+ return w.opOpAssign!(op)(y);
+ }
+
+ MyStruct!T opBinaryRight(string op)(T y) const
+ {
+ return opBinary!(op)(y);
+ }
+
+ ref MyStruct opOpAssign(string op, T)(const T z)
+ {
+ mixin ("x "~op~"= z;");
+ return this;
+ }
+}
+
+void test()
+{
+ MT s = MyStruct!int(1);
+ MT[] arr = [s, 2 * s, 3 * s, 4 * s, 5 * s, 6 * s];
+ MT[] result = new MT[arr.length];
+
+ result[] = arr[] + s;
+ result[] = s + arr[];
+
+ result[] = arr[] - s;
+ result[] = s - arr[];
+
+ result[] = arr[] * s;
+ result[] = s * arr[];
+
+ result[] = arr[] / s;
+ result[] = s / arr[];
+
+ result[] = arr[] ^^ s;
+ result[] = s ^^ arr[];
+}
diff --git a/gcc/testsuite/gdc.test/compilable/cdcmp.d b/gcc/testsuite/gdc.test/compilable/cdcmp.d
index 614bdc8..4248818 100644
--- a/gcc/testsuite/gdc.test/compilable/cdcmp.d
+++ b/gcc/testsuite/gdc.test/compilable/cdcmp.d
@@ -2,7 +2,7 @@
// REQUIRED_ARGS: -O
// POST_SCRIPT: compilable/extra-files/objdump-postscript.sh
// only testing on SYSV-ABI, but backend code is identical across platforms
-// DISABLED: win32 win64 osx linux32 freebsd32 freebsd64
+// DISABLED: win32 win64 osx linux32 freebsd32 freebsd64 openbsd32 openbsd64
bool test_ltz(ubyte x) { return x < 0; }
bool test_lez(ubyte x) { return x <= 0; }
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_22285.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_22285.d
new file mode 100644
index 0000000..5e8836d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_22285.d
@@ -0,0 +1,15 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_tables_22285.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_tables_22285.html
+
+module test.compilable.ddoc_markdown_tables_22285;
+
+/**
+| A | B | C |
+|---|---|---|
+| a | 0 | |
+| b | 1 1 1 | |
+| c | 2 | |
+*/
+enum _ = 0;
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d b/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d
index 54bbc79..47c0172 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d
@@ -144,4 +144,7 @@ __gshared void function(ifloat) onVariableFunctionParam;
__gshared ifloat delegate() onVariableDelegate;
-noreturn myExit() {}
+noreturn myExit()
+{
+ assert(false);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/cstuff3.c b/gcc/testsuite/gdc.test/compilable/imports/cstuff3.c
deleted file mode 100644
index f6aaf3b..0000000
--- a/gcc/testsuite/gdc.test/compilable/imports/cstuff3.c
+++ /dev/null
@@ -1,6 +0,0 @@
-// check bugs in importing C files
-
-int squared(int a)
-{
- return a * a;
-}
diff --git a/gcc/testsuite/gdc.test/compilable/mixintype2.d b/gcc/testsuite/gdc.test/compilable/mixintype2.d
index 43803df..d160bd4 100644
--- a/gcc/testsuite/gdc.test/compilable/mixintype2.d
+++ b/gcc/testsuite/gdc.test/compilable/mixintype2.d
@@ -66,3 +66,52 @@ static assert(is(T8 == const(ubyte*)));
alias T8 = mixin(q{immutable(__traits(getMember, S, "T"))})*;
static assert(is(T8 == immutable(float*)*));
*/
+
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=22356
+
+mixin("void") func22356(int) { }
+static assert(is(typeof(&func22356) == void function(int)));
+
+static mixin("void") func22356_s(char) { }
+static assert(is(typeof(&func22356_s) == void function(char)));
+
+mixin("int")[2] func22356_2(int) { return [1, 2]; }
+static assert(is(typeof(&func22356_2) == int[2] function(int)));
+
+mixin("int") func22356tp(S, T)(S, T) { return 1; }
+static assert(is(typeof(&func22356tp!(char, float)) == int function(char, float) pure nothrow @nogc @safe));
+
+mixin("int") x22356;
+static assert(is(typeof(x22356) == int));
+
+mixin("int")** xpp22356;
+static assert(is(typeof(xpp22356) == int**));
+
+mixin("int") y22356, z22356;
+static assert(is(typeof(y22356) == int) && is(typeof(z22356) == int));
+
+// Already working but for completeness
+void test_statements_22356()
+{
+ mixin("void") func22356(int) { }
+ static assert(is(typeof(&func22356) == void delegate(int) pure nothrow @nogc @safe));
+
+ static mixin("void") func22356_s(char) { }
+ static assert(is(typeof(&func22356_s) == void function(char) pure nothrow @nogc @safe));
+
+ mixin("int")[2] func22356_2(int) { return [1, 2]; }
+ static assert(is(typeof(&func22356_2) == int[2] delegate(int) pure nothrow @nogc @safe));
+
+ mixin("int") func22356tp(S, T)(S, T) { return 1; }
+ static assert(is(typeof(&func22356tp!(char, float)) == int delegate(char, float) pure nothrow @nogc @safe));
+
+ mixin("int") x22356;
+ static assert(is(typeof(x22356) == int));
+
+ mixin("int")** xpp22356;
+ static assert(is(typeof(xpp22356) == int**));
+
+ mixin("int") y22356, z22356;
+ static assert(is(typeof(y22356) == int) && is(typeof(z22356) == int));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/noreturn1.d b/gcc/testsuite/gdc.test/compilable/noreturn1.d
index 7517bb2..b041e07 100644
--- a/gcc/testsuite/gdc.test/compilable/noreturn1.d
+++ b/gcc/testsuite/gdc.test/compilable/noreturn1.d
@@ -49,8 +49,17 @@ static assert(noreturn.alignof == 0);
static assert((noreturn*).sizeof == (int*).sizeof);
static assert((noreturn[]).sizeof == (int[]).sizeof);
+static assert(is(typeof(noreturn.init) == noreturn));
+static assert(is(typeof((const noreturn).init) == const noreturn));
+static assert(is(typeof((immutable noreturn).init) == immutable noreturn));
+static assert(is(typeof((shared noreturn).init) == shared noreturn));
+
version (DigitalMars)
- noreturn exits(int* p) { *p = 3; }
+ noreturn exits(int* p)
+ {
+ *p = 3;
+ assert(false); // *p could be valid
+ }
noreturn exit();
@@ -58,9 +67,47 @@ noreturn pureexits() @nogc nothrow pure @safe { assert(0); }
noreturn callpureexits() { pureexits(); }
+noreturn returnExits()
+{
+ return pureexits();
+}
+
+void alsoExits()
+{
+ return assert(0);
+}
+
+int thisAlsoExits()
+{
+ return assert(0);
+}
+
+void cast_()
+{
+ noreturn n;
+ int i = n;
+}
+
int test1(int i)
{
if (exit())
return i + 1;
return i - 1;
}
+
+noreturn tlsNoreturn;
+__gshared noreturn globalNoreturn;
+
+template CreateTLS(A)
+{
+ A a;
+}
+
+void* useTls()
+{
+ alias Tnr = CreateTLS!noreturn;
+ void* a1 = &Tnr.a;
+ void* a2 = &tlsNoreturn;
+ void* a3 = &globalNoreturn;
+ return a1 < a2 ? a2 : a3;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/previewall.d b/gcc/testsuite/gdc.test/compilable/previewall.d
deleted file mode 100644
index e5ed7a8..0000000
--- a/gcc/testsuite/gdc.test/compilable/previewall.d
+++ /dev/null
@@ -1,10 +0,0 @@
-// ARG_SETS: -preview=all
-// ARG_SETS: -transition=all
-// ARG_SETS: -revert=all
-import core.stdc.stdio;
-
-void main (string[] args)
-{
- if (args.length == 42)
- printf("Hello World\n");
-}
diff --git a/gcc/testsuite/gdc.test/compilable/reinterpretctfe.d b/gcc/testsuite/gdc.test/compilable/reinterpretctfe.d
index 1d6fd4f..9a4db35 100644
--- a/gcc/testsuite/gdc.test/compilable/reinterpretctfe.d
+++ b/gcc/testsuite/gdc.test/compilable/reinterpretctfe.d
@@ -1,5 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=21997
+struct Strukt
+{
+ int i;
+ string s;
+}
+
int nonPureFunc(int i)
{
return 2 * i;
@@ -28,6 +34,14 @@ int mainCtfe()
auto baseDel = cast(int delegate(int)) pureDel;
assert(baseDel(4) == 20);
*/
+
+ {
+ shared Strukt shStr;
+ Strukt str = *cast(Strukt*) &shStr;
+
+ shared(Strukt)* ptr = cast(shared(Strukt)*) &str;
+ }
+
return 0;
}
diff --git a/gcc/testsuite/gdc.test/compilable/sroa.d b/gcc/testsuite/gdc.test/compilable/sroa.d
new file mode 100644
index 0000000..8ea515c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/sroa.d
@@ -0,0 +1,55 @@
+/* REQUIRED_ARGS: -O -release -inline
+This compares two different ways to do a for loop. The range
+version should SROA the VecRange struct into two register variables.
+*/
+
+extern (C):
+
+nothrow:
+@nogc:
+@safe:
+
+alias vec_base_t = size_t; // base type of vector
+alias vec_t = vec_base_t*;
+
+@trusted
+pure
+size_t vec_index(size_t b, const vec_t vec);
+
+@trusted
+pure ref inout(vec_base_t) vec_numbits(inout vec_t v) { return v[-1]; }
+@trusted
+pure ref inout(vec_base_t) vec_dim(inout vec_t v) { return v[-2]; }
+
+struct VecRange
+{
+ size_t i;
+ const vec_t v;
+
+ @nogc @safe nothrow pure:
+ this(const vec_t v) { this.v = v; i = vec_index(0, v); }
+ bool empty() const { return i == vec_numbits(v); }
+ size_t front() const { return i; }
+ void popFront() { i = vec_index(i + 1, v); }
+}
+
+@safe
+pure
+uint vec_numBitsSet(const vec_t vec)
+{
+ uint n = 0;
+ size_t length = vec_numbits(vec);
+ for (size_t i = 0; (i = vec_index(i, vec)) < length; ++i)
+ ++n;
+ return n;
+}
+
+@safe
+pure
+uint vec_numBitsSet2(const vec_t vec)
+{
+ uint n = 0;
+ foreach (j; VecRange(vec))
+ ++n;
+ return n;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/stc_traits.d b/gcc/testsuite/gdc.test/compilable/stc_traits.d
new file mode 100644
index 0000000..c5c4e5f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/stc_traits.d
@@ -0,0 +1,172 @@
+// REQUIRED_ARGS: -preview=dip1000 -preview=in
+/*
+TEST_OUTPUT:
+---
+100 tuple()
+101 tuple("return", "ref")
+102 tuple("ref")
+103 tuple()
+104 tuple("ref")
+105 tuple()
+106 tuple()
+107 tuple("ref")
+108 tuple("ref")
+109 tuple("ref")
+110 tuple("ref")
+111 tuple()
+112 tuple("ref")
+113 tuple("ref")
+114 tuple("ref")
+115 tuple("ref")
+116 tuple()
+117 tuple("ref")
+118 tuple("ref")
+119 tuple()
+120 tuple("ref")
+121 tuple()
+122 tuple("ref")
+123 tuple("in")
+124 tuple("in")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("return", "ref")
+m-mixin tuple("return", "ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple()
+m-mixin tuple()
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("ref")
+m-mixin tuple("ref")
+m tuple("in")
+m-mixin tuple("in")
+---
+*/
+
+void func(int i) {}
+void func(return ref bool i) {}
+void func(ref float a, int b) {}
+void get(T : int)(ref T t) {}
+void get()(float t) {}
+void get(T)(ref T[] t) {}
+void funcautoi()(auto ref int i) {}
+void funcauto(T)(auto ref T a) {}
+void funcin(in int i) {}
+
+struct Foo {
+ void foo(int i) {}
+ void foo(ref bool i) {}
+ static void sfoo(ref int i) {}
+}
+
+struct FooT(T) {
+ void foo(ref T i) {}
+ static void sfoo(ref T i) {}
+}
+
+class Bar {
+ void bar(int i) {}
+ void bar(ref bool i) {}
+ static void sbar(ref int i) {}
+}
+
+class BarT(T) {
+ void bar(ref T i) {}
+ static void sbar(ref T i) {}
+}
+
+int i;
+
+template match(handlers...)
+{
+ static foreach(h; handlers)
+ {
+ // should give the same result
+ pragma(msg, "m ", __traits(getParameterStorageClasses, h(i), 0));
+ pragma(msg, "m-mixin ", __traits(getParameterStorageClasses, mixin("h(i)"), 0));
+ }
+
+ enum match = (){};
+}
+
+void funcT(T)(ref T t) {}
+
+void main() {
+ int i;
+ bool b;
+ float f;
+ int[] ia;
+ Foo foo;
+ FooT!int foot;
+ Bar bar = new Bar;
+ BarT!int bart = new BarT!int;
+
+ ref int _foo(return ref const int* p, scope int* a, out int b, lazy int c);
+
+ // From SPEC_RUNNABLE_EXAMPLE_COMPILE:
+ int* p, a;
+ int _b, c;
+
+ static assert(__traits(getParameterStorageClasses, _foo(p, a, _b, c), 1)[0] == "scope");
+ static assert(__traits(getParameterStorageClasses, _foo(p, a, _b, c), 2)[0] == "out");
+ static assert(__traits(getParameterStorageClasses, _foo(p, a, _b, c), 3)[0] == "lazy");
+
+#line 100
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, func(0), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, func(b), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, func(f, i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, func(f, i), 1));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, get(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, get(0.0), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, get(f), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, get(ia), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, mixin("get(i)"), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, Foo.sfoo(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, FooT!int.sfoo(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, foo.foo(0), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, foo.foo(b), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, foot.foo(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, Bar.sbar(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, BarT!int.sbar(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, bar.bar(0), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, bar.bar(b), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, bart.bar(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, funcautoi(10), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, funcautoi(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, funcauto(10), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, funcauto(i), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, funcin(1), 0));
+ pragma(msg, __LINE__, " ", __traits(getParameterStorageClasses, funcin(i), 0));
+
+ cast(void) match!(
+ function(ref int i) => true,
+ delegate(ref int i) => true,
+ (ref int i) => true,
+ (return ref int i) => &i,
+ get,
+ funcT,
+ (int i) => true,
+ FooT!int.sfoo,
+ Foo.sfoo,
+ BarT!int.sbar,
+ Bar.sbar,
+ funcautoi,
+ funcauto,
+ funcin,
+ );
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test15711.d b/gcc/testsuite/gdc.test/compilable/test15711.d
new file mode 100644
index 0000000..ba7a93d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test15711.d
@@ -0,0 +1,31 @@
+// https://issues.dlang.org/show_bug.cgi?id=15711
+
+struct Quu {
+ string val;
+}
+
+string[] result = foo!(0, [Quu(['z']), Quu("")]);
+
+template foo(size_t i, Quu[] data, string[] results = []) {
+ static if (i < data.length) {
+ enum def = data[i];
+ enum foo = foo!(i+1, data, results ~ def.val);
+ }
+ else {
+ enum foo = results;
+ }
+}
+
+// Run-time version already works
+
+string[] result_rt = foo_rt(0, [Quu(['z']), Quu("")]);
+
+string[] foo_rt(size_t i, Quu[] data, string[] results = []) {
+ if (i < data.length) {
+ auto def = data[i];
+ return foo_rt(i+1, data, results ~ def.val);
+ }
+ else {
+ return results;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16492.d b/gcc/testsuite/gdc.test/compilable/test16492.d
deleted file mode 100644
index 833be1d..0000000
--- a/gcc/testsuite/gdc.test/compilable/test16492.d
+++ /dev/null
@@ -1,87 +0,0 @@
-// ARG_SETS: -debug; -o-; -debug -preview=dip1000
-// https://issues.dlang.org/show_bug.cgi?id=16492
-
-void mayCallGC();
-
-void test() @nogc pure
-{
- debug new int(1);
- debug
- {
- mayCallGC();
- auto b = [1, 2, 3];
- b ~= 4;
- }
-}
-
-void debugSafe() @safe
-{
- debug unsafeSystem();
- debug unsafeTemplated();
-}
-
-void unsafeSystem() @system {}
-void unsafeTemplated()() {
- int[] arr;
- auto b = arr.ptr;
-}
-
-void debugSafe2() @safe
-{
- char[] arr1, arr2;
- debug unsafeDIP1000Lifetime(arr1, arr2);
-
- char* ptr;
- char[] arr;
- debug ptr = arr.ptr;
-}
-
-void unsafeDIP1000Lifetime()(ref char[] p, scope char[] s)
-{
- p = s;
-}
-
-
-void test2() nothrow
-{
- debug throw new Exception("");
-}
-
-void test3() nothrow
-{
- debug {
- foreach (_; 0 .. 10) {
- if (1) {
- throw new Exception("");
- }
- }
- }
-}
-
-void test4() nothrow
-{
- debug throwException();
-}
-
-void test5() nothrow
-{
- debug willThrowException();
-}
-
-void willThrowException()()
-{
- throwException();
-}
-
-void throwException()
-{
- throw new Exception("");
-}
-
-void test6() nothrow
-{
- debug
- {
- () {throw new Exception("");}();
- }
-}
diff --git a/gcc/testsuite/gdc.test/compilable/test19482.d b/gcc/testsuite/gdc.test/compilable/test19482.d
new file mode 100644
index 0000000..09485a3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19482.d
@@ -0,0 +1,68 @@
+// https://issues.dlang.org/show_bug.cgi?id=19482
+
+alias AliasSeq(T...) = T;
+
+extern (C++, "cppns")
+@("asd", 123)
+private
+deprecated
+immutable
+static foreach (i; 0 .. 1)
+{
+ static assert(is(typeof(i) == int));
+ static assert(__traits(getLinkage, i) == "D");
+ static assert(__traits(isDeprecated, i) == false);
+ static assert(__traits(getAttributes, i).length == 0);
+ static assert(__traits(getCppNamespaces, i).length == 0);
+ static assert(__traits(getVisibility, i) == "public");
+
+ extern int x;
+ static assert(is(typeof(x) == immutable int));
+ static assert(__traits(getLinkage, x) == "C++");
+ static assert(__traits(isDeprecated, x) == true);
+ static assert(__traits(getAttributes, x) == AliasSeq!("asd", 123));
+ static assert(__traits(getCppNamespaces, x) == AliasSeq!("cppns"));
+ static assert(__traits(getVisibility, x) == "private");
+}
+
+struct S
+{
+ @disable static foreach (j; 0 .. 1)
+ {
+ int y;
+ static assert(__traits(isDisabled, j) == false);
+ static assert(__traits(isDisabled, S.y) == true);
+ }
+}
+
+const
+static foreach (i, v; ['a'])
+{
+ static assert(is(typeof(i) == size_t));
+ static assert(is(typeof(v) == char));
+}
+
+const
+static foreach (i, s, f; Range())
+{
+ static assert(is(typeof(i) == int));
+ static assert(is(typeof(s) == string));
+ static assert(is(typeof(f) == float));
+}
+
+struct Range
+{
+ int i;
+ auto front()
+ {
+ return Tup!(int, string, float)(123, "asd", 3.14f);
+ }
+ bool empty() { return i > 0; }
+ void popFront() { ++i; }
+}
+
+struct Tup(T...)
+{
+ T fields;
+ alias fields this;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21438.d b/gcc/testsuite/gdc.test/compilable/test21438.d
new file mode 100644
index 0000000..02e2d8d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21438.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=21438
+
+int genGBPLookup() {
+ static struct Table {
+ int[1] entries;
+ }
+
+ auto table = new Table;
+ auto x = table.entries[0];
+
+ static assert(is(typeof(x) == int));
+ return 0;
+}
+
+enum x = genGBPLookup;
diff --git a/gcc/testsuite/gdc.test/compilable/test21794.d b/gcc/testsuite/gdc.test/compilable/test21794.d
new file mode 100644
index 0000000..68e504b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21794.d
@@ -0,0 +1,52 @@
+// https://issues.dlang.org/show_bug.cgi?id=21794
+/*
+TEST_OUTPUT:
+---
+0
+0u
+0L
+0LU
+0.0F
+0.0
+0.0L
+---
+*/
+
+bool fun(void* p) {
+ const x = cast(ulong)p;
+ return 1;
+}
+
+static assert(fun(null));
+
+T fun2(T)(void* p) {
+ const x = cast(T)p;
+ return x;
+}
+
+// These were an error before, they were returning a NullExp instead of IntegerExp/RealExp
+
+static assert(fun2!int(null) == 0);
+static assert(fun2!uint(null) == 0);
+static assert(fun2!long(null) == 0);
+static assert(fun2!ulong(null) == 0);
+static assert(fun2!float(null) == 0);
+static assert(fun2!double(null) == 0);
+static assert(fun2!real(null) == 0);
+
+// These were printing 'null' instead of the corresponding number
+
+const i = cast(int)null;
+const ui = cast(uint)null;
+const l = cast(long)null;
+const ul = cast(ulong)null;
+const f = cast(float)null;
+const d = cast(double)null;
+const r = cast(real)null;
+pragma(msg, i);
+pragma(msg, ui);
+pragma(msg, l);
+pragma(msg, ul);
+pragma(msg, f);
+pragma(msg, d);
+pragma(msg, r);
diff --git a/gcc/testsuite/gdc.test/compilable/test21850.d b/gcc/testsuite/gdc.test/compilable/test21850.d
new file mode 100644
index 0000000..e7fe2d4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21850.d
@@ -0,0 +1,35 @@
+// https://issues.dlang.org/show_bug.cgi?id=21850
+
+struct Strukt2 {
+ this(int* _block) { }
+}
+
+struct Strukt {
+ int* block;
+ Strukt2 foo() { return Strukt2(null); }
+ alias foo this;
+}
+
+bool wrapper(T)(ref T a, ref T b)
+{
+ return doesPointTo(a, b);
+}
+
+void johan() pure {
+ Strukt a;
+ Strukt b;
+ assert(wrapper(a, b)); // error wrapper is not pure
+ assert(doesPointTo(a, b)); // fine
+}
+
+bool doesPointTo(S, T)(S , T) {
+ return false;
+}
+
+bool doesPointTo(S)(shared S) {
+ return false;
+}
+
+bool mayPointTo(){
+ return false;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22214.d b/gcc/testsuite/gdc.test/compilable/test22214.d
new file mode 100644
index 0000000..d218125
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22214.d
@@ -0,0 +1,16 @@
+// https://issues.dlang.org/show_bug.cgi?id=22214
+
+struct S
+{
+ struct T
+ {
+ }
+}
+
+void main() {
+ const S s;
+ static if (__traits(compiles, { auto t = s.T; }))
+ {
+ auto t = s.T;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22224.d b/gcc/testsuite/gdc.test/compilable/test22224.d
new file mode 100644
index 0000000..d16b2f40
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22224.d
@@ -0,0 +1,4 @@
+// REQUIRED_ARGS: -profile -c
+
+import core.stdc.stdarg;
+void error(...) { }
diff --git a/gcc/testsuite/gdc.test/compilable/test22228.d b/gcc/testsuite/gdc.test/compilable/test22228.d
new file mode 100644
index 0000000..ef31b4b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22228.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=22228
+// Note: fixed by reverting pull #11545
+
+auto f()
+{ immutable int i;
+ auto p = (() => &i)();
+
+ return 0;
+}
+
+enum ctfeInvocation = f;
diff --git a/gcc/testsuite/gdc.test/compilable/test22292.d b/gcc/testsuite/gdc.test/compilable/test22292.d
new file mode 100644
index 0000000..945dffb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22292.d
@@ -0,0 +1,155 @@
+// https://issues.dlang.org/show_bug.cgi?id=22292
+
+// Original case
+
+class C1
+{
+ C1 c1;
+ this () pure
+ {
+ c1 = this;
+ }
+}
+immutable x = cast(immutable)r;
+
+auto r()
+{
+ C1 c1 = new C1;
+ return c1;
+}
+
+// Reference stored in another class
+
+template Test2()
+{
+ class C1
+ {
+ C2 c2;
+ this () pure
+ {
+ C1 a = this;
+ c2 = new C2(a);
+ }
+ }
+ class C2
+ {
+ C1 c1;
+ this (C1 c) pure
+ {
+ c1 = c;
+ }
+ }
+ immutable x = cast(immutable)r;
+
+ auto r()
+ {
+ C1 c1 = new C1();
+ return c1;
+ }
+}
+
+alias test2 = Test2!();
+
+// Ditto but using a struct in the middle
+
+template Test3()
+{
+ class C0
+ {
+ S1 s1;
+
+ this()
+ {
+ s1 = S1(this);
+ }
+ }
+ struct S1
+ {
+ C1 c1;
+ this (C0 c)
+ {
+ c1 = new C1(c);
+ }
+ }
+ class C1
+ {
+ C0 c0;
+ this(C0 c)
+ {
+ c0 = c;
+ }
+ }
+ immutable x = cast(immutable)r;
+
+ auto r()
+ {
+ C0 c0 = new C0();
+ return c0;
+ }
+}
+
+alias test3 = Test3!();
+
+// From https://issues.dlang.org/show_bug.cgi?id=22114
+
+template Test4()
+{
+ public class Test1(T)
+ {
+ private Test2!T val;
+
+ this()
+ {
+ val = new Test2!T(this);
+ }
+
+ private class Test2(T)
+ {
+ private Test1!(T) m_source;
+
+ this(Test1!T source)
+ {
+ m_source = source;
+ }
+ }
+ }
+
+ public class Demo
+ {
+ auto val = new Test1!int();
+ }
+}
+
+alias test4 = Test4!();
+
+// ditto
+
+template Test5()
+{
+ public @nogc class TestA(T)
+ {
+ private TestB!T valA;
+ private TestB!T valB;
+ this()
+ {
+ valB = valA = new TestB!T(this);
+ }
+
+ private @nogc class TestB(T)
+ {
+ private TestA!(T) m_source;
+
+ this(TestA!T source)
+ {
+ m_source = source;
+ }
+ }
+ }
+
+ public class Demo
+ {
+ auto val = new TestA!int();
+ }
+}
+
+alias test5 = Test5!();
diff --git a/gcc/testsuite/gdc.test/compilable/test22388.d b/gcc/testsuite/gdc.test/compilable/test22388.d
new file mode 100644
index 0000000..cf8c3fc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22388.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=22388
+
+void setTimer(void delegate()) @system;
+void setTimer(void delegate() @safe) @safe;
+
+void setTimer2(void delegate() @safe) @safe;
+void setTimer2(void delegate()) @system;
+
+void main() @safe
+{
+ setTimer(() => assert(false));
+
+ alias lambda = () => assert(false);
+ setTimer(lambda);
+
+ // Reversed order
+
+ setTimer2(() => assert(false));
+
+ alias lambda2 = () => assert(false);
+ setTimer2(lambda2);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22410.d b/gcc/testsuite/gdc.test/compilable/test22410.d
new file mode 100644
index 0000000..7e631b7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22410.d
@@ -0,0 +1,59 @@
+// https://issues.dlang.org/show_bug.cgi?id=22410
+
+alias A(T...) = T;
+
+void fun0(const A!(int, string) x = A!(1, "asdf"))
+{
+ static assert(is(typeof(x) == A!(const int, const string)));
+}
+
+void fun1(const A!(immutable int, string) x = A!(1, "asdf"))
+{
+ static assert(is(typeof(x) == A!(immutable int, const string)));
+}
+
+void fun2(shared A!(int, string) x = A!(1, "asdf"))
+{
+ static assert(is(typeof(x) == A!(shared int, shared string)));
+}
+
+void fun3(shared const A!(int, string) x = A!(1, "asdf"))
+{
+ static assert(is(typeof(x) == A!(shared const int, shared const string)));
+}
+
+void fun4(inout A!(int, const string) x = A!(1, "asdf"))
+{
+ static assert(is(typeof(x) == A!(inout int, inout const string)));
+}
+
+void fun5(ref const A!(int, string) x = A!(1, "asdf"))
+{
+ static assert(is(typeof(x) == A!(const int, const string)));
+ static assert(__traits(isRef, x[0]) && __traits(isRef, x[1]));
+}
+
+// Implicitly conversion is also fixed, for example:
+// from (ulong, double) to (int, float)
+
+// Integral narrowing here, ulong(uint.max + 1UL) would fail.
+void fun10(A!(uint, float) x = A!(ulong(uint.max), 3.14))
+{
+ static assert(is(typeof(x) == A!(uint, float)));
+}
+
+void fun11(A!(int, double) x = A!(byte(1), 2.5f))
+{
+ static assert(is(typeof(x) == A!(int, double)));
+}
+
+void fun12(A!(byte, float) x = A!(1, 'a'))
+{
+ static assert(is(typeof(x) == A!(byte, float)));
+}
+
+A!(const int, shared char) tup = A!(1, 'a');
+void fun13(A!(byte, float) x = tup)
+{
+ static assert(is(typeof(x) == A!(byte, float)));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22420.d b/gcc/testsuite/gdc.test/compilable/test22420.d
new file mode 100644
index 0000000..c18d0a9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22420.d
@@ -0,0 +1,88 @@
+// https://issues.dlang.org/show_bug.cgi?id=22420
+
+struct File
+{
+ ~this()
+ {
+ }
+ File impl()
+ {
+ return File.init;
+ }
+ alias impl this;
+}
+struct Variable
+{
+ this(File)(File) { }
+ this(File)(File[]) { }
+}
+Variable wrapFunctionReturn(alias handler)(Variable params)
+{
+ return Variable(handler(params));
+}
+void registerFile()
+{
+ wrapFunctionReturn!((Variable) {
+ return File.init;
+ })(Variable.init);
+}
+
+// Reduction from an 'automem' test
+
+struct Issue156 {}
+
+void test2()
+{
+ RefCounted!Issue156 s;
+ auto r1 = repeat(s);
+ zip(r1);
+}
+
+struct RefCounted(RefCountedType)
+{
+ ~this() {}
+ alias _impl this;
+
+ struct Impl {}
+ alias ImplType = Impl;
+
+ private ImplType* _impl;
+
+}
+template Tuple(Specs)
+{
+ struct Tuple
+ {
+ this(U)(U) {}
+ this()(int) {}
+ }
+}
+
+template ElementType(R)
+{
+ static if (is(typeof(R.init) T))
+ alias ElementType = T;
+}
+
+struct Repeat(T)
+{
+ inout(T) front() inout {assert(0);}
+}
+
+Repeat!T repeat(T)(T ) {assert(0);}
+
+auto zip(Ranges)(Ranges )
+{
+ return ZipShortest!Ranges();
+}
+
+struct ZipShortest(Ranges...)
+{
+ Ranges ranges;
+ alias ElementType = Tuple!(.ElementType!(Ranges[0]));
+
+ ElementType front()
+ {
+ return typeof(return)(ranges[0].front);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22421.d b/gcc/testsuite/gdc.test/compilable/test22421.d
new file mode 100644
index 0000000..902646d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22421.d
@@ -0,0 +1,19 @@
+// https://issues.dlang.org/show_bug.cgi?id=22421
+
+alias AliasSeq(T...) = T;
+
+template staticMap(alias fun, args...)
+{
+ alias staticMap = AliasSeq!();
+ static foreach(arg; args)
+ staticMap = AliasSeq!(staticMap, fun!arg);
+}
+
+template id(alias what)
+{
+ enum id = __traits(identifier, what);
+}
+
+enum A { a }
+
+static assert(staticMap!(id, A.a) == AliasSeq!("a"));
diff --git a/gcc/testsuite/gdc.test/compilable/test318.d b/gcc/testsuite/gdc.test/compilable/test318.d
new file mode 100644
index 0000000..fd3cabe
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test318.d
@@ -0,0 +1,19 @@
+// LINK:
+// PERMUTE_ARGS: -version=C_Main
+
+version (C_Main)
+{
+ // Fine, infers int
+ extern(C) auto main(int argc, const char** argv)
+ {
+ return argc;
+ }
+}
+else
+{
+ // Fine, infers void
+ auto main()
+ {
+
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test4090.d b/gcc/testsuite/gdc.test/compilable/test4090.d
index 8f8f7c9..0e785cf 100644
--- a/gcc/testsuite/gdc.test/compilable/test4090.d
+++ b/gcc/testsuite/gdc.test/compilable/test4090.d
@@ -12,9 +12,6 @@ void test4090a()
// inference + qualifier + ref
foreach ( ref x; arr) static assert(is(typeof(x) == int));
foreach ( const ref x; arr) static assert(is(typeof(x) == const int));
- static assert(!__traits(compiles, {
- foreach (immutable ref x; arr) {}
- }));
// with exact type + qualifier
foreach ( int x; arr) static assert(is(typeof(x) == int));
@@ -24,25 +21,11 @@ void test4090a()
// with exact type + qualifier + ref
foreach ( ref int x; arr) static assert(is(typeof(x) == int));
foreach ( const ref int x; arr) static assert(is(typeof(x) == const int));
- static assert(!__traits(compiles, {
- foreach (immutable ref int x; arr) {}
- }));
// convertible type + qualifier
foreach ( double x; arr) static assert(is(typeof(x) == double));
foreach ( const double x; arr) static assert(is(typeof(x) == const double));
foreach (immutable double x; arr) static assert(is(typeof(x) == immutable double));
-
- // convertible type + qualifier + ref
- static assert(!__traits(compiles, {
- foreach ( ref double x; arr) {}
- }));
- static assert(!__traits(compiles, {
- foreach ( const ref double x; arr) {}
- }));
- static assert(!__traits(compiles, {
- foreach (immutable ref double x; arr) {}
- }));
}
// for the immutable elements
{
diff --git a/gcc/testsuite/gdc.test/compilable/test9766.d b/gcc/testsuite/gdc.test/compilable/test9766.d
index 3cfc22f..aaceb7d 100644
--- a/gcc/testsuite/gdc.test/compilable/test9766.d
+++ b/gcc/testsuite/gdc.test/compilable/test9766.d
@@ -69,9 +69,9 @@ static assert(U9766.var4.offsetof == 40);
struct TestMaxAlign
{
-align(1u << 31):
+align(1u << 15):
ubyte a;
ubyte b;
}
-static assert(TestMaxAlign.b.offsetof == 2147483648u);
+static assert(TestMaxAlign.b.offsetof == (1 << 15));
diff --git a/gcc/testsuite/gdc.test/compilable/testcstuff3.d b/gcc/testsuite/gdc.test/compilable/testcstuff3.d
deleted file mode 100644
index 89228a9..0000000
--- a/gcc/testsuite/gdc.test/compilable/testcstuff3.d
+++ /dev/null
@@ -1,4 +0,0 @@
-// EXTRA_FILES: imports/cstuff3.c
-import imports.cstuff3;
-
-static assert(squared(4) == 16);
diff --git a/gcc/testsuite/gdc.test/compilable/transition_in.d b/gcc/testsuite/gdc.test/compilable/transition_in.d
new file mode 100644
index 0000000..cc492a7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/transition_in.d
@@ -0,0 +1,26 @@
+// REQUIRED_ARGS: -transition=in
+/*
+TRANSFORM_OUTPUT: remove_lines(druntime)
+TEST_OUTPUT:
+---
+compilable/transition_in.d(3): Usage of 'in' on parameter
+compilable/transition_in.d(3): Usage of 'in' on parameter
+compilable/transition_in.d(8): Usage of 'in' on parameter
+compilable/transition_in.d(13): Usage of 'in' on parameter
+---
+*/
+#line 1
+struct Foobar
+{
+ void bar (in int a, in Object c);
+}
+
+version (none)
+{
+ void barfoo (in string arg);
+}
+
+void main ()
+{
+ void nested (in char c) {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/zerosize.d b/gcc/testsuite/gdc.test/compilable/zerosize.d
index 3c0062e..6e26deb 100644
--- a/gcc/testsuite/gdc.test/compilable/zerosize.d
+++ b/gcc/testsuite/gdc.test/compilable/zerosize.d
@@ -1,12 +1,17 @@
extern (C) struct S { }
-static assert(S.sizeof == 0);
-static assert(S.alignof == 1);
+version (CRuntime_Microsoft)
+ static assert(S.sizeof == 4);
+else
+ static assert(S.sizeof == 0);
+
+version (CRuntime_DigitalMars)
+ static assert(S.alignof == 0);
+else
+ static assert(S.alignof == 1);
extern (C++) struct T { }
static assert(T.sizeof == 1);
static assert(T.alignof == 1);
-
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10327.d b/gcc/testsuite/gdc.test/fail_compilation/diag10327.d
index 38f9ccb..1366882 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10327.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10327.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10327.d(11): Error: module `test10327` is in file 'imports/test10327.d' which cannot be read
+fail_compilation/diag10327.d(12): Error: unable to read module `test10327`
+fail_compilation/diag10327.d(12): Expected 'imports/test10327.d' or 'imports/test10327/package.d' in one of the following import paths:
import path[0] = fail_compilation
import path[1] = $p:druntime/import$
import path[2] = $p:phobos$
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20059.d b/gcc/testsuite/gdc.test/fail_compilation/diag20059.d
index a7a5914..2c8063a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag20059.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag20059.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag20059.d(15): Error: Expected return type of `string`, not `string[]`:
+fail_compilation/diag20059.d(15): Error: expected return type of `string`, not `string[]`:
fail_compilation/diag20059.d(13): Return type of `string` inferred here.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20618.d b/gcc/testsuite/gdc.test/fail_compilation/fail20618.d
new file mode 100644
index 0000000..ac6b33a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20618.d
@@ -0,0 +1,16 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20618.d(13): Error: in slice `a[1 .. 12]`, upper bound is greater than array length `10`
+fail_compilation/fail20618.d(14): Error: in slice `a[4 .. 3]`, lower bound is greater than upper bound
+fail_compilation/fail20618.d(15): Error: in slice `a[0 .. 11]`, upper bound is greater than array length `10`
+---
+*/
+
+void main()
+{
+ int[10] a;
+ auto b = a[1..12];
+ auto c = a[4..3];
+ auto d = a[0..$ + 1];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21091a.d b/gcc/testsuite/gdc.test/fail_compilation/fail21091a.d
index 74f40c2..c2bbe4d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail21091a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21091a.d
@@ -3,7 +3,8 @@
/*
TEST_OUTPUT:
----
-fail_compilation/fail21091a.d(15): Error: module `Ternary` is in file 'Ternary.d' which cannot be read
+fail_compilation/fail21091a.d(16): Error: unable to read module `Ternary`
+fail_compilation/fail21091a.d(16): Expected 'Ternary.d' or 'Ternary/package.d' in one of the following import paths:
import path[0] = fail_compilation
import path[1] = $p:druntime/import$
import path[2] = $p:phobos$
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21091b.d b/gcc/testsuite/gdc.test/fail_compilation/fail21091b.d
index d9467aa..3d7d600 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail21091b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21091b.d
@@ -3,7 +3,8 @@
/*
TEST_OUTPUT:
----
-fail_compilation/fail21091b.d(15): Error: module `Tid` is in file 'Tid.d' which cannot be read
+fail_compilation/fail21091b.d(16): Error: unable to read module `Tid`
+fail_compilation/fail21091b.d(16): Expected 'Tid.d' or 'Tid/package.d' in one of the following import paths:
import path[0] = fail_compilation
import path[1] = $p:druntime/import$
import path[2] = $p:phobos$
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22084.d b/gcc/testsuite/gdc.test/fail_compilation/fail22084.d
index 02fff2f..bd11832 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail22084.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22084.d
@@ -18,6 +18,6 @@ struct Destructor
void test()
{
- auto a0 = Destructor;
+ auto a0 = Destructor();
testVariadic(1, a0);
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22151.d b/gcc/testsuite/gdc.test/fail_compilation/fail22151.d
new file mode 100644
index 0000000..c6c3b1b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22151.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=22151
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22151.d(14): Error: function `test` is not an lvalue and cannot be modified
+fail_compilation/fail22151.d(15): Error: function `test2` is not an lvalue and cannot be modified
+fail_compilation/fail22151.d(18): Error: function pointed to by `fp` is not an lvalue and cannot be modified
+fail_compilation/fail22151.d(21): Error: function pointed to by `ff` is not an lvalue and cannot be modified
+---
+*/
+
+void test()
+{
+ *&test = *&test;
+ *&test2 = *&test;
+
+ void function() fp;
+ *fp = *fp;
+
+ auto ff = &test2;
+ *ff = *&test2;
+}
+
+void test2();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22366.d b/gcc/testsuite/gdc.test/fail_compilation/fail22366.d
new file mode 100644
index 0000000..3a2469f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22366.d
@@ -0,0 +1,15 @@
+// REQUIRED_ARGS: -dip1000
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22366.d(13): Error: scope variable `__aaval2` assigned to non-scope `aa[0]`
+---
+*/
+
+int* fun(scope int* x) @safe
+{
+ int*[int] aa;
+ aa[0] = x; // should give an error
+ return aa[0];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail225.d b/gcc/testsuite/gdc.test/fail_compilation/fail225.d
deleted file mode 100644
index dee9a54..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail225.d
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail225.d(15): Error: cannot implicitly convert expression `1` of type `int` to `immutable(char*)`
-fail_compilation/fail225.d(15): Error: cannot implicitly convert expression `& ch` of type `char*` to `immutable(char*)`
----
-*/
-struct Struct {
- char* chptr;
-}
-
-void main()
-{
- char ch = 'd';
- immutable Struct iStruct = {1, &ch};
-}
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail287.d b/gcc/testsuite/gdc.test/fail_compilation/fail287.d
index 7ed8f13..e5b1a79 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail287.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail287.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail287.d(14): Error: had 299 cases which is more than 256 cases in case range
+fail_compilation/fail287.d(14): Error: had 300 cases which is more than 257 cases in case range
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail318.d b/gcc/testsuite/gdc.test/fail_compilation/fail318.d
deleted file mode 100644
index d99175e..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail318.d
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail318.d(8): Error: function `D main` must return `int` or `void`
----
-*/
-
-auto main() { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail318_b.d b/gcc/testsuite/gdc.test/fail_compilation/fail318_b.d
new file mode 100644
index 0000000..efbf45b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail318_b.d
@@ -0,0 +1,11 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail318_b.d(8): Error: function `D main` must return `int`, `void` or `noreturn`, not `string`
+---
+*/
+
+auto main()
+{
+ return "";
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7173.d b/gcc/testsuite/gdc.test/fail_compilation/fail7173.d
index 2a2e46b..05ba7f9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7173.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7173.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7173.d(23): Error: cannot implicitly convert expression `b1._a.opBinary(b2._a).fun()` of type `void` to `B`
+fail_compilation/fail7173.d(23): Error: expression `b1._a.opBinary(b2._a).fun()` is `void` and has no value
---
*/
struct A{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/foreach.d b/gcc/testsuite/gdc.test/fail_compilation/foreach.d
new file mode 100644
index 0000000..9a1c7c8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/foreach.d
@@ -0,0 +1,14 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/foreach.d(12): Error: cannot declare `out` loop variable, use `ref` instead
+fail_compilation/foreach.d(13): Error: cannot declare `out` loop variable, use `ref` instead
+fail_compilation/foreach.d(13): Error: cannot declare `out` loop variable, use `ref` instead
+---
+*/
+void main ()
+{
+ int[] array;
+ foreach (out val; array) {}
+ foreach (out idx, out val; array) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/foreach2.d b/gcc/testsuite/gdc.test/fail_compilation/foreach2.d
new file mode 100644
index 0000000..8bd4893
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/foreach2.d
@@ -0,0 +1,22 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/foreach2.d(15): Error: argument type mismatch, `int` to `ref immutable(int)`
+fail_compilation/foreach2.d(16): Error: argument type mismatch, `int` to `ref immutable(int)`
+fail_compilation/foreach2.d(19): Error: argument type mismatch, `int` to `ref double`
+fail_compilation/foreach2.d(20): Error: argument type mismatch, `int` to `ref const(double)`
+fail_compilation/foreach2.d(21): Error: argument type mismatch, `int` to `ref immutable(double)`
+---
+*/
+void test4090 ()
+{
+ // From https://issues.dlang.org/show_bug.cgi?id=4090
+ int[] arr = [1,2,3];
+ foreach (immutable ref x; arr) {}
+ foreach (immutable ref int x; arr) {}
+
+ // convertible type + qualifier + ref
+ foreach ( ref double x; arr) {}
+ foreach ( const ref double x; arr) {}
+ foreach (immutable ref double x; arr) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10212.d b/gcc/testsuite/gdc.test/fail_compilation/ice10212.d
index b9fe2aa..99fe1ed 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10212.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10212.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10212.d(13): Error: Expected return type of `int`, not `int function() pure nothrow @nogc @safe`:
+fail_compilation/ice10212.d(13): Error: expected return type of `int`, not `int function() pure nothrow @nogc @safe`:
fail_compilation/ice10212.d(13): Return type of `int` inferred here.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice22377.d b/gcc/testsuite/gdc.test/fail_compilation/ice22377.d
new file mode 100644
index 0000000..4616f99
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice22377.d
@@ -0,0 +1,8 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice22377.d(8): Error: Internal Compiler Error: type `string` cannot be mapped to C++
+---
+*/
+
+extern(C++) void foo(string a) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice7782.d b/gcc/testsuite/gdc.test/fail_compilation/ice7782.d
index d42011a..551933b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice7782.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice7782.d
@@ -2,7 +2,8 @@
EXTRA_FILES: imports/ice7782algorithm.d imports/ice7782range.d
TEST_OUTPUT:
----
-fail_compilation/ice7782.d(13): Error: module `ice7782math` is in file 'imports/ice7782range/imports/ice7782math.d' which cannot be read
+fail_compilation/ice7782.d(14): Error: unable to read module `ice7782math`
+fail_compilation/ice7782.d(14): Expected 'imports/ice7782range/imports/ice7782math.d' or 'imports/ice7782range/imports/ice7782math/package.d' in one of the following import paths:
import path[0] = fail_compilation
import path[1] = $p:druntime/import$
import path[2] = $p:phobos$
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp22329.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp22329.d
new file mode 100644
index 0000000..9dc3c8e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp22329.d
@@ -0,0 +1,4 @@
+void func(T)(T arg)
+{
+ auto a = arg + 1;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/noreturn.d b/gcc/testsuite/gdc.test/fail_compilation/noreturn.d
index 3b340e8..4a588b4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/noreturn.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/noreturn.d
@@ -72,7 +72,7 @@ noreturn casting(int i)
return cast() n;
}
}
-
+ assert(false);
}
enum forceCasting0 = casting(0);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/noreturn2.d b/gcc/testsuite/gdc.test/fail_compilation/noreturn2.d
new file mode 100644
index 0000000..e7d28dc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/noreturn2.d
@@ -0,0 +1,90 @@
+/*
+REQUIRED_ARGS: -w -o-
+
+TEST_OUTPUT:
+---
+fail_compilation/noreturn2.d(18): Error: expected return type of `noreturn`, not `void`
+---
+
+https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1034.md
+*/
+
+alias noreturn = typeof(*null);
+
+void doStuff();
+
+noreturn returnVoid()
+{
+ return doStuff();
+}
+
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/noreturn2.d(37): Error: expected return type of `int`, not `string`:
+fail_compilation/noreturn2.d(35): Return type of `int` inferred here.
+---
++/
+
+auto missmatch(int i)
+{
+ if (i < 0)
+ return assert(false);
+ if (i == 0)
+ return i;
+ if (i > 0)
+ return "";
+}
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/noreturn2.d(50): Error: function `noreturn2.returns` is typed as `NR` but does return
+fail_compilation/noreturn2.d(50): `noreturn` functions must either throw, abort or loop indefinitely
+---
++/
+
+enum NR : noreturn;
+
+NR returns()
+{
+ // Fallthrough despite noreturn
+}
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/noreturn2.d(64): Error: cannot implicitly convert expression `1` of type `int` to `noreturn`
+---
++/
+
+noreturn returnsValue()
+{
+ return 1;
+}
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/noreturn2.d(75): Error: expected return type of `int`, not `void`
+---
++/
+int returnVoid2()
+{
+ return doStuff();
+}
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/noreturn2.d(89): Error: mismatched function return type inference of `void` and `int`
+---
++/
+auto returnVoid3(int i)
+{
+ if (i > 0)
+ return i;
+ else
+ return doStuff();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
index 034fa54..43998b9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
@@ -113,6 +113,8 @@ fail_compilation/reserved_version.d(214): Error: version identifier `CppRuntime_
fail_compilation/reserved_version.d(215): Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
fail_compilation/reserved_version.d(216): Error: version identifier `D_PIE` is reserved and cannot be set
fail_compilation/reserved_version.d(217): Error: version identifier `AVR` is reserved and cannot be set
+fail_compilation/reserved_version.d(218): Error: version identifier `D_PreConditions` is reserved and cannot be set
+fail_compilation/reserved_version.d(219): Error: version identifier `D_PostConditions` is reserved and cannot be set
---
*/
@@ -232,6 +234,8 @@ version = CppRuntime_Microsoft;
version = CppRuntime_Sun;
version = D_PIE;
version = AVR;
+version = D_PreConditions;
+version = D_PostConditions;
// This should work though
debug = DigitalMars;
@@ -340,3 +344,5 @@ debug = none;
debug = D_P16;
debug = MSP430;
debug = AVR;
+debug = D_PreConditions;
+debug = D_PostConditions;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
index b8b6fa4..6333309 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
@@ -103,6 +103,8 @@
// REQUIRED_ARGS: -version=assert
// REQUIRED_ARGS: -version=all
// REQUIRED_ARGS: -version=none
+// REQUIRED_ARGS: -version=D_PreConditions
+// REQUIRED_ARGS: -version=D_PostConditions
// REQUIRED_ARGS: -debug=DigitalMars
// REQUIRED_ARGS: -debug=GNU
// REQUIRED_ARGS: -debug=LDC
@@ -203,6 +205,8 @@
// REQUIRED_ARGS: -debug=assert
// REQUIRED_ARGS: -debug=all
// REQUIRED_ARGS: -debug=none
+// REQUIRED_ARGS: -debug=D_PreConditions
+// REQUIRED_ARGS: -debug=D_PostConditions
/*
TEST_OUTPUT:
---
@@ -309,5 +313,7 @@ Error: version identifier `unittest` is reserved and cannot be set
Error: version identifier `assert` is reserved and cannot be set
Error: version identifier `all` is reserved and cannot be set
Error: version identifier `none` is reserved and cannot be set
+Error: version identifier `D_PreConditions` is reserved and cannot be set
+Error: version identifier `D_PostConditions` is reserved and cannot be set
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17425.d b/gcc/testsuite/gdc.test/fail_compilation/test17425.d
index f7628b8..77c4956 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test17425.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17425.d
@@ -1,7 +1,7 @@
/* TEST_OUTPUT:
---
fail_compilation/test17425.d(24): Error: parameter index must be in range 0..4 not 4
-fail_compilation/test17425.d(27): Error: first argument to `__traits(getParameterStorageClasses, i, 4)` is not a function
+fail_compilation/test17425.d(27): Error: first argument to `__traits(getParameterStorageClasses, i, 4)` is not a function or a function call
fail_compilation/test17425.d(29): Error: expression expected as second argument of `__traits(getParameterStorageClasses, foo, int)`
fail_compilation/test17425.d(31): Error: expected 2 arguments for `getParameterStorageClasses` but had 3
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17868b.d b/gcc/testsuite/gdc.test/fail_compilation/test17868b.d
index 5bfff5c..7833b61 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test17868b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17868b.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
----
+fail_compilation/test17868b.d(9): Error: pragma `crt_constructor` can only apply to a single declaration
fail_compilation/test17868b.d(10): Error: function `test17868b.foo` must be `extern(C)` for `pragma(crt_constructor)`
fail_compilation/test17868b.d(14): Error: function `test17868b.bar` must be `extern(C)` for `pragma(crt_constructor)`
-fail_compilation/test17868b.d(9): Error: pragma `crt_constructor` can only apply to a single declaration
----
*/
pragma(crt_constructor):
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20998.d b/gcc/testsuite/gdc.test/fail_compilation/test20998.d
new file mode 100644
index 0000000..16eb026
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20998.d
@@ -0,0 +1,120 @@
+// https://issues.dlang.org/show_bug.cgi?id=20998
+/*
+REQUIRED_ARGS: -verrors=context
+TEST_OUTPUT:
+---
+fail_compilation/test20998.d(76): Error: undefined identifier `invalid`
+X x = { invalid, 2, "asd" };
+ ^
+fail_compilation/test20998.d(76): Error: too many initializers for `X`
+X x = { invalid, 2, "asd" };
+ ^
+fail_compilation/test20998.d(83): Error: cannot implicitly convert expression `"a"` of type `string` to `int`
+X2 x2 = { ptr: null, "a", ptr: 2, 444 };
+ ^
+fail_compilation/test20998.d(83): Error: duplicate initializer for field `ptr`
+X2 x2 = { ptr: null, "a", ptr: 2, 444 };
+ ^
+fail_compilation/test20998.d(83): Error: too many initializers for `X2`
+X2 x2 = { ptr: null, "a", ptr: 2, 444 };
+ ^
+fail_compilation/test20998.d(90): Error: overlapping initialization for field `ptr` and `x`
+X3 x3 = { ptr: null, "a", ptr: 2, 444 };
+ ^
+fail_compilation/test20998.d(90): Error: cannot implicitly convert expression `"a"` of type `string` to `int`
+X3 x3 = { ptr: null, "a", ptr: 2, 444 };
+ ^
+fail_compilation/test20998.d(90): Error: duplicate initializer for field `ptr`
+X3 x3 = { ptr: null, "a", ptr: 2, 444 };
+ ^
+fail_compilation/test20998.d(90): Error: too many initializers for `X3`
+X3 x3 = { ptr: null, "a", ptr: 2, 444 };
+ ^
+fail_compilation/test20998.d(98): Error: field `X4.ptr` cannot assign to misaligned pointers in `@safe` code
+ X4 x4 = { ptr: null, "a", 444, ptr: 2, true };
+ ^
+fail_compilation/test20998.d(98): Error: cannot implicitly convert expression `"a"` of type `string` to `int`
+ X4 x4 = { ptr: null, "a", 444, ptr: 2, true };
+ ^
+fail_compilation/test20998.d(98): Error: too many initializers for `X4`
+ X4 x4 = { ptr: null, "a", 444, ptr: 2, true };
+ ^
+fail_compilation/test20998.d(102): called from here: `test()`
+auto e = test();
+ ^
+fail_compilation/test20998.d(104): Error: cannot implicitly convert expression `1` of type `int` to `void*`
+X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 };
+ ^
+fail_compilation/test20998.d(104): Error: duplicate initializer for field `ptr`
+X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 };
+ ^
+fail_compilation/test20998.d(104): Error: duplicate initializer for field `ptr`
+X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 };
+ ^
+fail_compilation/test20998.d(104): Error: too many initializers for `X2`
+X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 };
+ ^
+fail_compilation/test20998.d(107): Error: too many initializers for `X2`
+X2 c6 = { null, 2, true, null };
+ ^
+fail_compilation/test20998.d(116): Error: cannot implicitly convert expression `1` of type `int` to `immutable(char*)`
+ immutable Struct iStruct = {1, &ch};
+ ^
+fail_compilation/test20998.d(116): Error: too many initializers for `Struct`
+ immutable Struct iStruct = {1, &ch};
+ ^
+fail_compilation/test20998.d(120): called from here: `test2()`
+auto t = test2();
+ ^
+---
+*/
+
+struct X {
+ void* ptr;
+ int x;
+}
+X x = { invalid, 2, "asd" };
+
+struct X2 {
+ void* ptr;
+ int x;
+ bool y;
+}
+X2 x2 = { ptr: null, "a", ptr: 2, 444 };
+
+union X3 {
+ void* ptr;
+ int x;
+ bool y;
+}
+X3 x3 = { ptr: null, "a", ptr: 2, 444 };
+
+int test() @safe
+{
+ align (1) struct X4 {
+ void* ptr;
+ int x;
+ }
+ X4 x4 = { ptr: null, "a", 444, ptr: 2, true };
+ return 0;
+}
+
+auto e = test();
+
+X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 };
+X2 b5 = { ptr: null, y: true };
+X2 c5 = { x: 2, true, ptr: null };
+X2 c6 = { null, 2, true, null };
+
+struct Struct {
+ char* chptr;
+}
+
+int test2()
+{
+ char ch = 'd';
+ immutable Struct iStruct = {1, &ch};
+ return 0;
+}
+
+auto t = test2();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21093.d b/gcc/testsuite/gdc.test/fail_compilation/test21093.d
new file mode 100644
index 0000000..b85d0c3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21093.d
@@ -0,0 +1,56 @@
+// https://issues.dlang.org/show_bug.cgi?id=21093
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21093.d(24): Error: function `test21093.LocalTime.hasDST` does not override any function
+fail_compilation/test21093.d(32): Error: class `test21093.LocalTime2` cannot implicitly generate a default constructor when base class `test21093.TimeZone2` is missing a default constructor
+fail_compilation/test21093.d(44): Error: function `test21093.LocalTime3.string` does not override any function
+fail_compilation/test21093.d(55): Error: cannot implicitly override base class method `test21093.TimeZone4.hasDST` with `test21093.LocalTime4.hasDST`; add `override` attribute
+---
+*/
+
+void fromUnixTime(immutable TimeZone tz = LocalTime()) { }
+void fromUnixTime(immutable TimeZone2 tz = LocalTime2()) { }
+void fromUnixTime(immutable TimeZone3 tz = LocalTime3()) { }
+void fromUnixTime(immutable TimeZone4 tz = LocalTime4()) { }
+
+class TimeZone
+{
+}
+
+class LocalTime : TimeZone
+{
+ static immutable(LocalTime) opCall() { }
+ override hasDST() { }
+}
+
+class TimeZone2
+{
+ this(string) { }
+}
+
+class LocalTime2 : TimeZone2
+{
+ static immutable(LocalTime2) opCall() { }
+}
+
+class TimeZone3
+{
+}
+
+class LocalTime3 : TimeZone3
+{
+ static immutable(LocalTime3) opCall() { }
+ override string () { }
+}
+
+class TimeZone4
+{
+ bool hasDST();
+}
+
+class LocalTime4 : TimeZone4
+{
+ static immutable(LocalTime4) opCall() { }
+ bool hasDST() { }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21380.d b/gcc/testsuite/gdc.test/fail_compilation/test21380.d
new file mode 100644
index 0000000..6a2da1b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21380.d
@@ -0,0 +1,46 @@
+// https://issues.dlang.org/show_bug.cgi?id=21380
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21380.d(39): Error: partial template instance `MySerializer().serializeSinkType!int` has no value
+fail_compilation/test21380.d(44): Error: template instance `test21380.SupportSinkTypeSer!(MySerializer!int)` error instantiating
+---
+*/
+
+template isSomeFunction(T...)
+if (T.length == 1)
+{
+ static if (is(typeof(& T[0]) U : U*) && is(U == function) || is(typeof(& T[0]) U == delegate))
+ {
+ // T is a (nested) function symbol.
+ enum bool isSomeFunction = true;
+ }
+ else static if (is(T[0] W) || is(typeof(T[0]) W))
+ {
+ // T is an expression or a type. Take the type of it and examine.
+ static if (is(W F : F*) && is(F == function))
+ enum bool isSomeFunction = true; // function pointer
+ else
+ enum bool isSomeFunction = is(W == function) || is(W == delegate);
+ }
+ else
+ enum bool isSomeFunction = false;
+}
+
+struct MySerializer (T)
+{
+ void serializeSinkType(T2) (scope auto ref T2 record) {}
+}
+
+template SupportSinkTypeSer(SerT)
+{
+ /* Note: Partial template instance because it needs inference, in this case
+ it cannot infer 'auto ref' parameter */
+ enum SupportSinkTypeSer = isSomeFunction!(SerT.init.serializeSinkType!int);
+}
+
+int main()
+{
+ enum x = SupportSinkTypeSer!(MySerializer!int);
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21930.d b/gcc/testsuite/gdc.test/fail_compilation/test21930.d
new file mode 100644
index 0000000..6c93243
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21930.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=21930
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21930.d(21): Error: variable `string` is used as a type
+fail_compilation/test21930.d(15): variable `string` is declared here
+fail_compilation/test21930.d(26): Error: constructor `test21930.R.this(string)` is not callable using argument types `()`
+---
+*/
+
+alias AliasSeq(T...) = T;
+
+alias TP(alias name) = AliasSeq!name;
+
+int string; // 'string' declared as a variable
+
+alias a = TP!(main);
+
+class R
+{
+ this(string) { } // so constructor have errors
+}
+
+@system main()
+{
+ new R;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22329.d b/gcc/testsuite/gdc.test/fail_compilation/test22329.d
new file mode 100644
index 0000000..237f9c7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test22329.d
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=22329
+// EXTRA_FILES: imports/imp22329.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/imports/imp22329.d(3): Error: no property `values` for type `test22329.Foo`
+fail_compilation/imports/imp22329.d(3): Error: incompatible types for `(arg) + (1)`: `Foo` and `int`
+fail_compilation/test22329.d(20): Error: template instance `imp22329.func!(Foo)` error instantiating
+---
+*/
+
+public struct Foo {
+ private int values;
+ alias values this;
+}
+
+void main()
+{
+ import imports.imp22329 : func;
+ func(Foo());
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22361.d b/gcc/testsuite/gdc.test/fail_compilation/test22361.d
new file mode 100644
index 0000000..11255ff
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test22361.d
@@ -0,0 +1,11 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test22361.d(11): Error: unable to read module `this_module_does_not_exist`
+fail_compilation/test22361.d(11): Expected 'this_module_does_not_exist.d' or 'this_module_does_not_exist/package.d' in one of the following import paths:
+import path[0] = fail_compilation
+import path[1] = $p:druntime/import$
+import path[2] = $p:phobos$
+---
+*/
+import this_module_does_not_exist;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testOpApply.d b/gcc/testsuite/gdc.test/fail_compilation/testOpApply.d
new file mode 100644
index 0000000..9203685
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/testOpApply.d
@@ -0,0 +1,161 @@
+/+
+TEST_OUTPUT:
+---
+fail_compilation/testOpApply.d(27): Error: `testOpApply.SameAttr.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @safe)` matches both:
+fail_compilation/testOpApply.d(13): `testOpApply.SameAttr.opApply(int delegate(int) @system dg)`
+and:
+fail_compilation/testOpApply.d(18): `testOpApply.SameAttr.opApply(int delegate(int) @system dg)`
+---
++/
+
+struct SameAttr
+{
+ int opApply(int delegate(int) @system dg) @system
+ {
+ return 0;
+ }
+
+ int opApply(int delegate(int) @system dg) @safe
+ {
+ return 0;
+ }
+}
+
+void testSameAttr() @safe
+{
+ SameAttr sa;
+ foreach (int i; sa) {}
+}
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/testOpApply.d(104): Error: `testOpApply.SameAttr.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @system)` matches both:
+fail_compilation/testOpApply.d(13): `testOpApply.SameAttr.opApply(int delegate(int) @system dg)`
+and:
+fail_compilation/testOpApply.d(18): `testOpApply.SameAttr.opApply(int delegate(int) @system dg)`
+---
++/
+#line 100
+
+void testSameAttr() @system
+{
+ SameAttr sa;
+ foreach (int i; sa) {}
+}
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/testOpApply.d(217): Error: `sa.opApply` matches more than one declaration:
+`fail_compilation/testOpApply.d(203)`: `int(int delegate(int) dg)`
+and:
+`fail_compilation/testOpApply.d(208)`: `int(int delegate(string) dg)`
+fail_compilation/testOpApply.d(217): Error: cannot uniquely infer `foreach` argument types
+---
++/
+#line 200
+
+struct DifferentTypes
+{
+ int opApply(int delegate(int) dg)
+ {
+ return 0;
+ }
+
+ int opApply(int delegate(string) dg)
+ {
+ return 0;
+ }
+}
+
+void testDifferentTypes()
+{
+ DifferentTypes sa;
+ foreach (i; sa) {}
+}
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/testOpApply.d(317): Error: `sa.opApply` matches more than one declaration:
+`fail_compilation/testOpApply.d(303)`: `int(int delegate(int) dg)`
+and:
+`fail_compilation/testOpApply.d(308)`: `int(int delegate(long) dg)`
+fail_compilation/testOpApply.d(317): Error: cannot uniquely infer `foreach` argument types
+---
++/
+#line 300
+
+struct CovariantTypes
+{
+ int opApply(int delegate(int) dg)
+ {
+ return 0;
+ }
+
+ int opApply(int delegate(long) dg)
+ {
+ return 0;
+ }
+}
+
+void testCovariantTypes()
+{
+ CovariantTypes sa;
+ foreach (i; sa) {}
+}
+
+/+
+See https://issues.dlang.org/show_bug.cgi?id=21683
+
+TEST_OUTPUT:
+---
+fail_compilation/testOpApply.d(420): Error: `sa.opApply` matches more than one declaration:
+`fail_compilation/testOpApply.d(404)`: `int(int delegate(int) dg)`
+and:
+`fail_compilation/testOpApply.d(410)`: `int(int delegate(ref int) dg)`
+fail_compilation/testOpApply.d(420): Error: cannot uniquely infer `foreach` argument types
+---
++/
+#line 400
+
+struct DifferentQualifiers
+{
+ int x;
+ int opApply(int delegate(int) dg)
+ {
+ x = 1;
+ return 0;
+ }
+
+ int opApply(int delegate(ref int) dg)
+ {
+ x = 2;
+ return 0;
+ }
+}
+
+void testDifferentQualifiers()
+{
+ DifferentQualifiers sa;
+ foreach (i; sa) {}
+}
+
+/+
+TEST_OUTPUT:
+---
+fail_compilation/testOpApply.d(504): Error: `sa.opApply` matches more than one declaration:
+`fail_compilation/testOpApply.d(404)`: `int(int delegate(int) dg)`
+and:
+`fail_compilation/testOpApply.d(410)`: `int(int delegate(ref int) dg)`
+fail_compilation/testOpApply.d(504): Error: cannot uniquely infer `foreach` argument types
+---
++/
+#line 500
+
+void testDifferentQualifiersRef()
+{
+ DifferentQualifiers sa;
+ foreach (ref i; sa) {}
+}
diff --git a/gcc/testsuite/gdc.test/runnable/aliasthis.d b/gcc/testsuite/gdc.test/runnable/aliasthis.d
index cc12f55..db5913c 100644
--- a/gcc/testsuite/gdc.test/runnable/aliasthis.d
+++ b/gcc/testsuite/gdc.test/runnable/aliasthis.d
@@ -2102,6 +2102,42 @@ void test16633()
root.populate;
}
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13009
+
+struct RefCounted13009_2(T)
+{
+ ref T refCountedPayload()
+ {
+ assert(false);
+ }
+
+ ref inout(T) refCountedPayload() inout
+ {
+ assert(false);
+ }
+
+ alias refCountedPayload this;
+}
+
+struct S13009_2
+{
+ struct Payload
+ {
+ int[] data;
+ }
+
+ RefCounted13009_2!Payload payload;
+ alias X = typeof(payload.data[0]);
+
+ void foo()
+ {
+ payload.data[0] = 0;
+ }
+}
+
+/***************************************************/
+
int main()
{
test1();
diff --git a/gcc/testsuite/gdc.test/runnable/dhry.d b/gcc/testsuite/gdc.test/runnable/dhry.d
index f772d61..1eb463c 100644
--- a/gcc/testsuite/gdc.test/runnable/dhry.d
+++ b/gcc/testsuite/gdc.test/runnable/dhry.d
@@ -929,3 +929,19 @@ version (NetBSD)
return q;
}
}
+
+version (OpenBSD)
+{
+ import core.sys.posix.sys.time;
+
+ double dtime()
+ {
+ double q;
+ timeval tv;
+
+ gettimeofday(&tv,null);
+ q = cast(double)tv.tv_sec + cast(double)tv.tv_usec * 1.0e-6;
+
+ return q;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/fix22372.d b/gcc/testsuite/gdc.test/runnable/fix22372.d
new file mode 100644
index 0000000..55864a0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/fix22372.d
@@ -0,0 +1,38 @@
+/* PERMUTE_ARGS: -O
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=22104
+
+struct S { int a1, a2, a3; }
+
+version (none)
+void throws2ndCall(ref S x);
+else
+{
+void throws2ndCall(ref S x)
+{
+ __gshared bool b;
+ if (b)
+ throw new Exception("n == 1");
+ b = true;
+}
+}
+
+void main() { foo(); }
+
+void foo()
+{
+ S[] arr = [S(), S()];
+ size_t i;
+ try
+ {
+ for (i = 0; i < 2; i++)
+ throws2ndCall(arr[i]);
+ }
+ catch (Exception o)
+ {
+ //printf("Exception: i = %lu\n", i);
+ assert(i == 1); // this fails
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/runnable/interpret.d b/gcc/testsuite/gdc.test/runnable/interpret.d
index a626749..989fb2e 100644
--- a/gcc/testsuite/gdc.test/runnable/interpret.d
+++ b/gcc/testsuite/gdc.test/runnable/interpret.d
@@ -3605,6 +3605,62 @@ void test21878()
}
/************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20133
+
+void bar20133(ref string text)
+{
+ text = text[1 .. $];
+ assert(text.length < 3);
+ if (text.length == 2) assert(text == "oo");
+ if (text.length == 1) assert(text == "o");
+ if (text.length == 0) assert(text == "");
+ string tcopy = text;
+ if (tcopy.length > 0)
+ bar20133(tcopy);
+ assert(tcopy.length < 2);
+ if (tcopy.length == 1) assert(tcopy == "o");
+ if (tcopy.length == 0) assert(tcopy == "");
+}
+
+void bar20133_2(ref string text)
+{
+ auto ptext = &text;
+ *ptext = text[1 .. $];
+ assert(text.length < 3);
+ if (text.length == 2) assert(text == "oo");
+ if (text.length == 1) assert(text == "o");
+ if (text.length == 0) assert(text == "");
+ string tcopy = text;
+ if (tcopy.length > 0)
+ bar20133_2(tcopy);
+ assert(tcopy.length < 2);
+ if (tcopy.length == 1) assert(tcopy == "o");
+ if (tcopy.length == 0) assert(tcopy == "");
+}
+
+alias fun20133 = {
+ string input = "foo";
+ bar20133(input);
+ assert(input == "oo");
+ return input;
+};
+
+alias fun20133_2 = {
+ string input = "foo";
+ bar20133_2(input);
+ assert(input == "oo");
+ return input;
+};
+
+void test20133()
+{
+ enum ctest = fun20133();
+ enum ctest2 = fun20133_2();
+ auto rtest = fun20133();
+ auto rtest2 = fun20133_2();
+}
+
+/************************************************/
int main()
{
@@ -3732,6 +3788,7 @@ int main()
test20366();
test20400();
test21878();
+ test20133();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/noreturn1.d b/gcc/testsuite/gdc.test/runnable/noreturn1.d
index 447ea28..1da0479 100644
--- a/gcc/testsuite/gdc.test/runnable/noreturn1.d
+++ b/gcc/testsuite/gdc.test/runnable/noreturn1.d
@@ -66,9 +66,56 @@ void test2()
/*****************************************/
+struct BasicStruct
+{
+ int firstInt;
+ noreturn noRet;
+ long lastLong;
+}
+
+struct AlignedStruct
+{
+ int firstInt;
+ align(16) noreturn noRet;
+ long lastLong;
+}
+
+void takeBasic(BasicStruct bs)
+{
+ assert(bs.firstInt == 13);
+ assert(bs.lastLong == 42);
+
+ assert(&bs.noRet == (&bs.firstInt + 1));
+}
+
+void takeAligned(AlignedStruct as)
+{
+ assert(as.firstInt == 99);
+ assert(as.lastLong == 0xDEADBEEF);
+
+ assert(&as.noRet == &as.lastLong);
+}
+
+void test3()
+{
+ {
+ BasicStruct bs;
+ bs.firstInt = 13;
+ bs.lastLong = 42;
+ takeBasic(bs);
+ }
+ {
+ AlignedStruct as;
+ as.firstInt = 99;
+ as.lastLong = 0xDEADBEEF;
+ takeAligned(as);
+ }
+}
+
int main()
{
test1();
test2();
+ test3();
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/noreturn2.d b/gcc/testsuite/gdc.test/runnable/noreturn2.d
new file mode 100644
index 0000000..1d3d362
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/noreturn2.d
@@ -0,0 +1,220 @@
+/*
+PERMUTE_ARGS: -O -inline
+RUN_OUTPUT:
+---
+getAndPrintS
+---
+*/
+
+import core.stdc.stdio;
+import core.exception : AssertError;
+
+/*****************************************/
+
+// noreturn is inferred for functions that always throw
+// The code must not strip the destructor when calling a noreturn function
+
+struct WithDtor
+{
+ __gshared int destroyed;
+
+ int num;
+
+ int acceptNoreturn(int a, int b, int c)
+ {
+ puts("unreachable");
+ return num + a + b + c;
+ }
+
+ ~this()
+ {
+ destroyed += num;
+ }
+}
+
+noreturn doesThrow()
+{
+ WithDtor wd = WithDtor(1);
+ throw new Exception("");
+}
+
+noreturn callDoesThrow()
+{
+ WithDtor wd = WithDtor(2);
+ doesThrow();
+}
+
+
+void testDtors()
+{
+ try
+ {
+ callDoesThrow();
+ assert(0);
+ } catch (Exception e) {}
+
+ assert(WithDtor.destroyed == 3);
+}
+
+/*****************************************************************************/
+
+/// Verifies that `func` throws a `Throwable` with `message` at `line`
+void testAssertFailure(size_t expLine, string expMsg, void function() func, size_t callLine = __LINE__)
+{
+ void enforce(bool check, string error)
+ {
+ if (!check)
+ throw new AssertError(error, __FILE__, callLine);
+ }
+
+ bool caught;
+ try
+ {
+ func();
+ }
+ catch (Throwable t)
+ {
+ // Save members because t might be overwritten by an Assertion failure below
+ string actFile = t.file;
+ size_t actLine = t.line;
+ string actMsg = t.msg;
+ caught = true;
+
+ scope (failure)
+ {
+ printf("\nfile = \"%.*s\"\nline = %zu\nmsg = \"%.*s\"\n\n",
+ cast(int) actFile.length, actFile.ptr,
+ actLine,
+ cast(int) actMsg.length, actMsg.ptr
+ );
+ fflush(stdout);
+ }
+
+ enforce(actFile == __FILE__, "Wrong file");
+ enforce(actLine == expLine, "Wrong line");
+ enforce(actMsg == expMsg, "Wrong message");
+ }
+
+ enforce(caught, "No Throwable was thrown!");
+}
+
+void testAccess()
+{
+ enum msg = "Accessed expression of type `noreturn`";
+
+ // FIXME: Another assertion failure in the backend trying to generate noreturn.sizeof = 0 byte assignment
+ version (FIXME)
+ testAssertFailure(__LINE__ + 3, msg, function noreturn()
+ {
+ noreturn a;
+ noreturn b = a;
+ });
+
+ if (false) // read does not assert!
+ testAssertFailure(__LINE__ + 3, msg, function noreturn()
+ {
+ noreturn a;
+ int b = a;
+ assert(false, "Unreachable!"); // Statement above not detected as noreturn
+ });
+
+ testAssertFailure(__LINE__ + 2, msg, function noreturn()
+ {
+ cast(noreturn) 1;
+ });
+
+ version (FIXME)
+ testAssertFailure(__LINE__ + 3, msg, function noreturn()
+ {
+ noreturn a;
+ noreturn b = cast(noreturn) 1;
+ });
+
+ if (false) // Read does not assert
+ testAssertFailure(__LINE__ + 3, msg, function noreturn()
+ {
+ noreturn a;
+ return a;
+ });
+
+ if (false) // Read does not assert
+ testAssertFailure(__LINE__ + 4, msg, function noreturn()
+ {
+ static void foo(noreturn) {}
+ noreturn a;
+ foo(a);
+ assert(false, "Unreachable!"); // Ditto
+ });
+}
+
+/*****************************************/
+
+void testFuncCall()
+{
+ enum msg = "Called abort()";
+ enum line = __LINE__ + 1;
+ static noreturn abort() { assert(0, msg); }
+
+ // Canaries to check for side effects
+ __gshared int countLeft, countRight;
+
+ scope (failure) printf("countLeft = %d\ncountRight = %d\n", countLeft, countRight);
+
+
+ // D function arguments are evaluated left to right
+ testAssertFailure(line, msg, function()
+ {
+ static void acceptNoreturnD(int, int, int) { puts("unreachable"); }
+
+ acceptNoreturnD(countLeft++, abort(), countRight++);
+ });
+
+ assert(countLeft == 1);
+ assert(countRight == 0);
+
+// // C function arguments are still evaluated left to right
+// // Despite them being push in reverse order
+ testAssertFailure(line, msg, function()
+ {
+ static extern(C) void acceptNoreturnC(int, int, int) { puts("unreachable"); }
+
+ acceptNoreturnC(countLeft++, abort(), countRight++);
+
+ assert(false);
+ });
+
+ assert(countLeft == 2);
+ assert(countRight == 0);
+
+ WithDtor.destroyed = 0;
+
+ testAssertFailure(__LINE__ + 2, "Error", function()
+ {
+ static WithDtor getS() { assert(false, "Error"); }
+
+ getS().acceptNoreturn(countLeft++, abort(), countRight++);
+ });
+
+ assert(countLeft == 2); // No changes
+ assert(countRight == 0);
+ assert(WithDtor.destroyed == 0); // No temporary to destruct
+
+ testAssertFailure(line, msg, function()
+ {
+ static WithDtor getAndPrintS() { puts("getAndPrintS"); return WithDtor(1); }
+
+ getAndPrintS().acceptNoreturn(countLeft++, abort(), countRight++);
+ });
+
+ assert(countLeft == 3);
+ assert(countRight == 0);
+ assert(WithDtor.destroyed == 1);
+}
+
+int main()
+{
+ testDtors();
+ testAccess();
+ testFuncCall();
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/sroa13220.d b/gcc/testsuite/gdc.test/runnable/sroa13220.d
new file mode 100644
index 0000000..2cec666
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/sroa13220.d
@@ -0,0 +1,103 @@
+/* REQUIRED_ARGS: -O -inline -noboundscheck
+ */
+// https://github.com/dlang/pull/13220
+
+version (D_SIMD)
+{
+
+mixin template VectorOps(VectorType, ArrayType: BaseType[N], BaseType, size_t N)
+{
+ enum Count = N;
+ alias Base = BaseType;
+
+ BaseType* ptr() return pure nothrow @nogc
+ {
+ return array.ptr;
+ }
+
+ // Unary operators
+ VectorType opUnary(string op)() pure nothrow @safe @nogc
+ {
+ VectorType res = void;
+ mixin("res.array[] = " ~ op ~ "array[];");
+ return res;
+ }
+
+ // Binary operators
+ VectorType opBinary(string op)(VectorType other) pure const nothrow @safe @nogc
+ {
+ VectorType res = void;
+ mixin("res.array[] = array[] " ~ op ~ " other.array[];");
+ return res;
+ }
+
+ // Assigning a BaseType value
+ void opAssign(BaseType e) pure nothrow @safe @nogc
+ {
+ array[] = e;
+ }
+
+ // Assigning a static array
+ void opAssign(ArrayType v) pure nothrow @safe @nogc
+ {
+ array[] = v[];
+ }
+
+ void opOpAssign(string op)(VectorType other) pure nothrow @safe @nogc
+ {
+ mixin("array[] " ~ op ~ "= other.array[];");
+ }
+
+ // Assigning a dyn array
+ this(ArrayType v) pure nothrow @safe @nogc
+ {
+ array[] = v[];
+ }
+
+ // Broadcast constructor
+ this(BaseType x) pure nothrow @safe @nogc
+ {
+ array[] = x;
+ }
+
+ ref inout(BaseType) opIndex(size_t i) inout pure nothrow @safe @nogc
+ {
+ return array[i];
+ }
+}
+
+// Note: can't be @safe with this signature
+Vec loadUnaligned(Vec)(const(BaseType!Vec)* pvec) @trusted
+{
+ // Since this vector is emulated, it doesn't have alignement constraints
+ // and as such we can just cast it.
+ return *cast(Vec*)(pvec);
+}
+
+private template BaseType(V)
+{
+ alias typeof( ( { V v; return v; }()).array[0]) BaseType;
+}
+
+struct int4
+{
+ int[4] array;
+ mixin VectorOps!(int4, int[4]);
+}
+
+alias __m128i = int4;
+}
+
+int main()
+{
+ version (D_SIMD)
+ {
+ int4 A = [1, 2, 3, 4];
+ int4 ia = A;
+ ia.ptr[2] = 5;
+ int4 C = ia;
+ int[4] result = [1, 2, 5, 4];
+ assert(C.array == result);
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test15624.d b/gcc/testsuite/gdc.test/runnable/test15624.d
deleted file mode 100644
index 7927579..0000000
--- a/gcc/testsuite/gdc.test/runnable/test15624.d
+++ /dev/null
@@ -1,51 +0,0 @@
-/* PERMUTE_ARGS:
- */
-
-// https://issues.dlang.org/show_bug.cgi?id=15624
-
-struct Foo {
- int x;
- int opApply(int delegate(int, string, string) @safe dg) @safe {
- x = 1;
- return 0;
- }
- int opApply(int delegate(int, string, string) @system dg) @system {
- x = 2;
- return 0;
- }
-}
-
-void testSafe() @safe {
- Foo foo;
- foreach (i, k, v; foo) {
- }
- assert(foo.x == 1);
-}
-
-void testSystem() @system {
- Foo foo;
- foreach (i, k, v; foo) {
- }
- assert(foo.x == 2);
-}
-
-void test() @system
-{
- Foo f;
-
- int dgsafe (int x, string s, string t) @safe { return 1; }
- int dgsystem(int x, string s, string t) @system { return 1; }
-
- f.opApply(&dgsafe);
- assert(f.x == 1);
- f.opApply(&dgsystem);
- assert(f.x == 2);
-}
-
-int main()
-{
- testSafe();
- testSystem();
- test();
- return 0;
-}
diff --git a/gcc/testsuite/gdc.test/runnable/test21039.d b/gcc/testsuite/gdc.test/runnable/test21039.d
new file mode 100644
index 0000000..c58600f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21039.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=21039
+
+class Inner {}
+
+class Outer {
+ Inner inner;
+ alias inner this;
+ this(Inner i) { inner = i; }
+}
+
+void main() {
+ auto inner = new Inner;
+ auto outer = new Outer(new Inner);
+
+ // implicit cast goes through 'alias this'
+
+ Inner inner1 = outer; // Already does it
+ assert(inner1);
+
+ Inner[] inners = [inner, outer]; // Fixed
+
+ assert(inners[0], "first element is null");
+ assert(inners[1], "second element is null");
+
+ Inner inner2 = 1 ? outer : inner; // Fixed
+ assert(inner2);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test22205.d b/gcc/testsuite/gdc.test/runnable/test22205.d
new file mode 100644
index 0000000..78abf2f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test22205.d
@@ -0,0 +1,17 @@
+// REQUIRED_ARGS: -debug
+
+void main() nothrow
+{
+ debug
+ {
+ try
+ {
+ throw new Exception("2");
+ }
+ catch (Exception) {}
+ catch (Throwable)
+ {
+ assert(0);
+ }
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test22278.d b/gcc/testsuite/gdc.test/runnable/test22278.d
new file mode 100644
index 0000000..72332a4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test22278.d
@@ -0,0 +1,24 @@
+/*
+REQUIRED_ARGS: -release
+PERMUTE_ARGS: -check=in=on -check=out=on
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=22278
+
+bool resultIn;
+bool resultOut;
+
+void foo22278()
+ in { resultIn = true; }
+ out { resultOut = true; }
+do {}
+
+int main()
+{
+ foo22278();
+
+ version(D_PreConditions) assert(resultIn); else assert(!resultIn);
+ version(D_PostConditions) assert(resultOut); else assert(!resultOut);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testOpApply.d b/gcc/testsuite/gdc.test/runnable/testOpApply.d
new file mode 100644
index 0000000..7b884e5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testOpApply.d
@@ -0,0 +1,142 @@
+/* PERMUTE_ARGS:
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=15624
+
+struct Foo {
+ int x;
+ int opApply(int delegate(int, string, string) @safe dg) @safe {
+ x = 1;
+ return 0;
+ }
+ int opApply(int delegate(int, string, string) @system dg) @system {
+ x = 2;
+ return 0;
+ }
+}
+
+void testSafe() @safe {
+ Foo foo;
+ foreach (i, k, v; foo) {
+ }
+ assert(foo.x == 1);
+}
+
+void testSystem() @system {
+ Foo foo;
+ foreach (i, k, v; foo) {
+ }
+ assert(foo.x == 2);
+}
+
+void test() @system
+{
+ Foo f;
+
+ int dgsafe (int x, string s, string t) @safe { return 1; }
+ int dgsystem(int x, string s, string t) @system { return 1; }
+
+ f.opApply(&dgsafe);
+ assert(f.x == 1);
+ f.opApply(&dgsystem);
+ assert(f.x == 2);
+}
+
+int main()
+{
+ testSafe();
+ testSystem();
+ test();
+ testDifferentTypes();
+ testSameAttributes();
+ testInverseAttributes();
+ return 0;
+}
+
+void testDifferentTypes()
+{
+ static struct DifferentTypes
+ {
+ int x;
+ int opApply(int delegate(int) dg) @safe {
+ x = 1;
+ return 0;
+ }
+ int opApply(int delegate(long) dg) @safe {
+ x = 2;
+ return 0;
+ }
+ }
+
+ DifferentTypes dt;
+ foreach (int i; dt) {}
+ assert(dt.x == 1);
+
+ foreach (long i; dt) {}
+ assert(dt.x == 2);
+}
+
+void testSameAttributes()
+{
+ static struct SameAttributes
+ {
+ int x;
+ int opApply(int delegate(int) @system dg) @safe {
+ x = 1;
+ return 0;
+ }
+ int opApply(int delegate(int) @safe dg) @safe {
+ x = 2;
+ return 0;
+ }
+ }
+
+ static void safe() @safe
+ {
+ SameAttributes sa;
+ foreach (i; sa) {}
+ assert(sa.x == 2);
+ }
+ safe();
+
+ static void system() @system
+ {
+ SameAttributes sa;
+ foreach (i; sa) {}
+ assert(sa.x == 1);
+ }
+ system();
+}
+
+// Not useful but enabled by the associated patch
+void testInverseAttributes()
+{
+ static struct InverseAttributes
+ {
+ int x;
+ int opApply(int delegate(int) @system dg) @safe {
+ x = 1;
+ return 0;
+ }
+ int opApply(int delegate(int) @safe dg) @system {
+ x = 2;
+ return 0;
+ }
+ }
+
+ static void system() @system
+ {
+ InverseAttributes sa;
+ foreach (i; sa) {}
+ assert(sa.x == 1);
+ }
+ system();
+
+ static void safe() @safe
+ {
+ InverseAttributes sa;
+ (() @trusted { foreach (i; sa) {} })();
+ assert(sa.x == 2);
+ }
+ safe();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testmainb.d b/gcc/testsuite/gdc.test/runnable/testmainb.d
new file mode 100644
index 0000000..d6452ec
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testmainb.d
@@ -0,0 +1,15 @@
+/*
+Test that -main does nothing when main is already defined
+
+REQUIRED_ARGS: -main
+RUN_OUTPUT:
+---
+Success
+---
+*/
+extern(C) int printf(const char*, ...);
+
+void main()
+{
+ printf("Success\n");
+}
diff --git a/gcc/testsuite/gdc.test/runnable/uda.d b/gcc/testsuite/gdc.test/runnable/uda.d
index cdb9aa6..1d01098 100644
--- a/gcc/testsuite/gdc.test/runnable/uda.d
+++ b/gcc/testsuite/gdc.test/runnable/uda.d
@@ -697,6 +697,54 @@ static if(is(typeof(foo20831) Params20831 == __parameters))
/************************************************/
+/************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15804
+
+template test15804()
+{
+ alias AliasSeq(T...) = T;
+
+ @(42) struct Foo(D) {}
+ auto fooFac(T)()
+ {
+ static assert(__traits(getAttributes, Foo) == AliasSeq!42);
+ static assert(__traits(getAttributes, Foo!int) == AliasSeq!42);
+ return Foo!T();
+ }
+
+ auto booFac(T)()
+ {
+ @(43) struct Boo {}
+ static assert(__traits(getAttributes, Boo) == AliasSeq!43);
+ return Boo();
+ }
+
+ auto barFac(T)()
+ {
+ @(44) struct Bar(D) {}
+ static assert(__traits(getAttributes, Bar) == AliasSeq!44); // Fixed
+ static assert(__traits(getAttributes, Bar!int) == AliasSeq!44);
+ return Bar!T();
+ }
+
+ auto bazFac(T)()
+ {
+ @(45) static struct Baz(D) {}
+ static assert(__traits(getAttributes, Baz) == AliasSeq!45); // Fixed
+ static assert(__traits(getAttributes, Baz!int) == AliasSeq!45);
+ return Baz!T();
+ }
+
+ auto foo = fooFac!int;
+ auto boo = booFac!int;
+ auto bar = barFac!int;
+ auto baz = bazFac!int;
+}
+
+alias a15804 = test15804!();
+
+/************************************************/
+
int main()
{
test1();
diff --git a/gcc/testsuite/gdc.test/runnable/ufcs.d b/gcc/testsuite/gdc.test/runnable/ufcs.d
index 2d9bf15..8fd7bb2 100644
--- a/gcc/testsuite/gdc.test/runnable/ufcs.d
+++ b/gcc/testsuite/gdc.test/runnable/ufcs.d
@@ -196,6 +196,7 @@ void test5()
{
// f5_1 .. f5_5 are symbols which declared in module scope
assert(100.f5_1() == 1);
+ assert(001.f5_1() == 1); // https://issues.dlang.org/show_bug.cgi?id=8346
assert("s".f5_2() == 2);
assert(1.4.f5_3() == 3);
assert(100.f5_4() == 1);
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp22287.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp22287.cpp
new file mode 100644
index 0000000..ba7b25a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp22287.cpp
@@ -0,0 +1,337 @@
+#include <assert.h>
+
+class X
+{
+public:
+ virtual ~X();
+ int i;
+};
+
+X::~X()
+{
+}
+
+class Y : public X
+{
+};
+
+class A
+{
+public:
+ virtual ~A();
+ virtual int f1() const;
+
+ int i;
+};
+
+class I
+{
+public:
+ virtual int f2() const = 0;
+ virtual X *f4() = 0;
+};
+
+class B : public A, public I
+{
+public:
+ virtual int f1() const;
+ virtual int f2() const;
+ virtual int f3() const;
+ virtual X *f4();
+};
+
+class C : public B
+{
+public:
+ virtual int f1() const;
+ virtual int f2() const;
+ virtual int f3() const;
+ virtual Y *f4();
+};
+
+#ifdef _WIN32
+class D : public B
+{
+public:
+ virtual int f1() const;
+ virtual int f2() const;
+ virtual int f3() const;
+ virtual Y *f4();
+};
+
+class E : public B
+{
+public:
+ virtual int f1() const;
+ virtual int f2() const;
+ virtual int f3() const;
+ virtual Y *f4();
+};
+#endif
+
+A::~A()
+{
+}
+
+int A::f1() const
+{
+ return i + 11;
+}
+
+int B::f1() const
+{
+ return i + 21;
+}
+
+int B::f2() const
+{
+ return i + 22;
+}
+
+int B::f3() const
+{
+ return i + 23;
+}
+
+X *B::f4()
+{
+ X *r = new X;
+ r->i = i + 24;
+ return r;
+}
+
+int C::f1() const
+{
+ return i + 31;
+}
+
+int C::f2() const
+{
+ return i + 32;
+}
+
+int C::f3() const
+{
+ return i + 33;
+}
+
+Y *C::f4()
+{
+ Y *r = new Y;
+ r->i = i + 34;
+ return r;
+}
+
+I *createIFromCPP(char type, int i)
+{
+ switch (type)
+ {
+ case 'B':
+ {
+ B *b = new B();
+ b->i = i;
+ return b;
+ }
+ case 'C':
+ {
+ C *c = new C();
+ c->i = i;
+ return c;
+ }
+#ifdef _WIN32
+ case 'D':
+ {
+ D *d = new D();
+ d->i = i;
+ return d;
+ }
+ case 'E':
+ {
+ E *e = new E();
+ e->i = i;
+ return e;
+ }
+#endif
+ default:
+ return 0;
+ }
+}
+
+B *createBFromCPP(char type, int i)
+{
+ switch (type)
+ {
+ case 'B':
+ {
+ B *b = new B();
+ b->i = i;
+ return b;
+ }
+ case 'C':
+ {
+ C *c = new C();
+ c->i = i;
+ return c;
+ }
+#ifdef _WIN32
+ case 'D':
+ {
+ D *d = new D();
+ d->i = i;
+ return d;
+ }
+ case 'E':
+ {
+ E *e = new E();
+ e->i = i;
+ return e;
+ }
+#endif
+ default:
+ return 0;
+ }
+}
+
+C *createCFromCPP(int i)
+{
+ C *c = new C();
+ c->i = i;
+ return c;
+}
+
+#ifdef _WIN32
+D *createDFromCPP(int i)
+{
+ D *d = new D();
+ d->i = i;
+ return d;
+}
+
+E *createEFromCPP(int i)
+{
+ E *e = new E();
+ e->i = i;
+ return e;
+}
+#endif
+
+I *createIFromD(char type, int i);
+B *createBFromD(char type, int i);
+C *createCFromD(int i);
+#ifdef _WIN32
+D *createDFromD(int i);
+E *createEFromD(int i);
+#endif
+
+void runCPPTests()
+{
+ {
+ B *b = new B();
+ b->i = 100;
+ assert(b->f1() == 121);
+ assert(b->f2() == 122);
+ assert(b->f3() == 123);
+ assert(b->f4()->i == 124);
+ }
+ {
+ C *c = new C();
+ c->i = 100;
+ assert(c->f1() == 131);
+ assert(c->f2() == 132);
+ assert(c->f3() == 133);
+ assert(c->f4()->i == 134);
+ }
+#ifdef _WIN32
+ {
+ D *d = new D();
+ d->i = 100;
+ assert(d->f1() == 141);
+ assert(d->f2() == 142);
+ assert(d->f3() == 143);
+ assert(d->f4()->i == 144);
+ }
+ {
+ E *e = new E();
+ e->i = 100;
+ assert(e->f1() == 151);
+ assert(e->f2() == 152);
+ assert(e->f3() == 153);
+ assert(e->f4()->i == 154);
+ }
+#endif
+ {
+ I *i = createIFromD('B', 100);
+ assert(i->f2() == 122);
+ assert(i->f4()->i == 124);
+ }
+ {
+ I *i = createIFromD('C', 100);
+ assert(i->f2() == 132);
+ assert(i->f4()->i == 134);
+ }
+#ifdef _WIN32
+ {
+ I *i = createIFromD('D', 100);
+ assert(i->f2() == 142);
+ assert(i->f4()->i == 144);
+ }
+ {
+ I *i = createIFromD('E', 100);
+ assert(i->f2() == 152);
+ assert(i->f4()->i == 154);
+ }
+#endif
+ {
+ B *b = createBFromD('B', 100);
+ assert(b->f1() == 121);
+ assert(b->f2() == 122);
+ assert(b->f3() == 123);
+ assert(b->f4()->i == 124);
+ }
+ {
+ B *b = createBFromD('C', 100);
+ assert(b->f1() == 131);
+ assert(b->f2() == 132);
+ assert(b->f3() == 133);
+ assert(b->f4()->i == 134);
+ }
+#ifdef _WIN32
+ {
+ B *b = createBFromD('D', 100);
+ assert(b->f1() == 141);
+ assert(b->f2() == 142);
+ assert(b->f3() == 143);
+ assert(b->f4()->i == 144);
+ }
+ {
+ B *b = createBFromD('E', 100);
+ assert(b->f1() == 151);
+ assert(b->f2() == 152);
+ assert(b->f3() == 153);
+ assert(b->f4()->i == 154);
+ }
+#endif
+ {
+ C *c = createCFromD(100);
+ assert(c->f1() == 131);
+ assert(c->f2() == 132);
+ assert(c->f3() == 133);
+ assert(c->f4()->i == 134);
+ }
+#ifdef _WIN32
+ {
+ D *d = createDFromD(100);
+ assert(d->f1() == 141);
+ assert(d->f2() == 142);
+ assert(d->f3() == 143);
+ assert(d->f4()->i == 144);
+ }
+ {
+ E *e = createEFromD(100);
+ assert(e->f1() == 151);
+ assert(e->f2() == 152);
+ assert(e->f3() == 153);
+ assert(e->f4()->i == 154);
+ }
+#endif
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test22287.d b/gcc/testsuite/gdc.test/runnable_cxx/test22287.d
new file mode 100644
index 0000000..a0c7475
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test22287.d
@@ -0,0 +1,327 @@
+// EXTRA_CPP_SOURCES: cpp22287.cpp
+
+extern(C++):
+
+class X
+{
+public:
+ ~this();
+ int i;
+}
+
+class Y : X
+{
+}
+
+class A
+{
+ ~this();
+ int f1() const;
+
+ int i;
+}
+
+interface I
+{
+ int f2() const;
+ X f4();
+}
+
+class B : A, I
+{
+ override int f1() const;
+ override int f2() const;
+ int f3() const;
+ override X f4();
+}
+
+class C : B
+{
+ override int f1() const;
+ override int f2() const;
+ override int f3() const;
+ override Y f4();
+}
+
+version(Windows)
+{
+class D : B
+{
+ override int f1() const
+ {
+ return i + 41;
+ }
+
+ override int f2() const
+ {
+ return i + 42;
+ }
+
+ override int f3() const
+ {
+ return i + 43;
+ }
+
+ override Y f4()
+ {
+ Y r = new Y;
+ r.i = i + 44;
+ return r;
+ }
+}
+
+mixin template MixinE()
+{
+ override int f1() const
+ {
+ return i + 51;
+ }
+
+ override int f2() const
+ {
+ return i + 52;
+ }
+
+ override int f3() const
+ {
+ return i + 53;
+ }
+
+ override Y f4()
+ {
+ Y r = new Y;
+ r.i = i + 54;
+ return r;
+ }
+}
+
+class E : B
+{
+ mixin MixinE;
+}
+}
+
+I createIFromCPP(char type, int i);
+B createBFromCPP(char type, int i);
+C createCFromCPP(int i);
+version(Windows)
+{
+D createDFromCPP(int i);
+E createEFromCPP(int i);
+}
+
+I createIFromD(char type, int i)
+{
+ switch (type)
+ {
+ case 'B':
+ {
+ B b = new B();
+ b.i = i;
+ return b;
+ }
+ case 'C':
+ {
+ C c = new C();
+ c.i = i;
+ return c;
+ }
+ version(Windows)
+ {
+ case 'D':
+ {
+ D d = new D();
+ d.i = i;
+ return d;
+ }
+ case 'E':
+ {
+ E e = new E();
+ e.i = i;
+ return e;
+ }
+ }
+ default:
+ return null;
+ }
+}
+
+B createBFromD(char type, int i)
+{
+ switch (type)
+ {
+ case 'B':
+ {
+ B b = new B();
+ b.i = i;
+ return b;
+ }
+ case 'C':
+ {
+ C c = new C();
+ c.i = i;
+ return c;
+ }
+ version(Windows)
+ {
+ case 'D':
+ {
+ D d = new D();
+ d.i = i;
+ return d;
+ }
+ case 'E':
+ {
+ E e = new E();
+ e.i = i;
+ return e;
+ }
+ }
+ default:
+ return null;
+ }
+}
+
+C createCFromD(int i)
+{
+ C c = new C();
+ c.i = i;
+ return c;
+}
+
+version(Windows)
+{
+D createDFromD(int i)
+{
+ D d = new D();
+ d.i = i;
+ return d;
+}
+
+E createEFromD(int i)
+{
+ E e = new E();
+ e.i = i;
+ return e;
+}
+}
+
+void runCPPTests();
+
+extern(D) void main()
+{
+ {
+ B b = new B();
+ b.i = 100;
+ assert(b.f1() == 121);
+ assert(b.f2() == 122);
+ assert(b.f3() == 123);
+ assert(b.f4().i == 124);
+ }
+ {
+ C c = new C();
+ c.i = 100;
+ assert(c.f1() == 131);
+ assert(c.f2() == 132);
+ assert(c.f3() == 133);
+ assert(c.f4().i == 134);
+ }
+ version(Windows)
+ {
+ {
+ D d = new D();
+ d.i = 100;
+ assert(d.f1() == 141);
+ assert(d.f2() == 142);
+ assert(d.f3() == 143);
+ assert(d.f4().i == 144);
+ }
+ {
+ E e = new E();
+ e.i = 100;
+ assert(e.f1() == 151);
+ assert(e.f2() == 152);
+ assert(e.f3() == 153);
+ assert(e.f4().i == 154);
+ }
+ }
+ {
+ I i = createIFromCPP('B', 100);
+ assert(i.f2() == 122);
+ assert(i.f4().i == 124);
+ }
+ {
+ I i = createIFromCPP('C', 100);
+ assert(i.f2() == 132);
+ assert(i.f4().i == 134);
+ }
+ version(Windows)
+ {
+ {
+ I i = createIFromCPP('D', 100);
+ assert(i.f2() == 142);
+ assert(i.f4().i == 144);
+ }
+ {
+ I i = createIFromCPP('E', 100);
+ assert(i.f2() == 152);
+ assert(i.f4().i == 154);
+ }
+ }
+ {
+ B b = createBFromCPP('B', 100);
+ assert(b.f1() == 121);
+ assert(b.f2() == 122);
+ assert(b.f3() == 123);
+ assert(b.f4().i == 124);
+ }
+ {
+ B b = createBFromCPP('C', 100);
+ assert(b.f1() == 131);
+ assert(b.f2() == 132);
+ assert(b.f3() == 133);
+ assert(b.f4().i == 134);
+ }
+ version(Windows)
+ {
+ {
+ B b = createBFromCPP('D', 100);
+ assert(b.f1() == 141);
+ assert(b.f2() == 142);
+ assert(b.f3() == 143);
+ assert(b.f4().i == 144);
+ }
+ {
+ B b = createBFromCPP('E', 100);
+ assert(b.f1() == 151);
+ assert(b.f2() == 152);
+ assert(b.f3() == 153);
+ assert(b.f4().i == 154);
+ }
+ }
+ {
+ C c = createCFromCPP(100);
+ assert(c.f1() == 131);
+ assert(c.f2() == 132);
+ assert(c.f3() == 133);
+ assert(c.f4().i == 134);
+ }
+ version(Windows)
+ {
+ {
+ D d = createDFromCPP(100);
+ assert(d.f1() == 141);
+ assert(d.f2() == 142);
+ assert(d.f3() == 143);
+ assert(d.f4().i == 144);
+ }
+ {
+ E e = createEFromCPP(100);
+ assert(e.f1() == 151);
+ assert(e.f2() == 152);
+ assert(e.f3() == 153);
+ assert(e.f4().i == 154);
+ }
+ }
+ runCPPTests();
+}