diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-05-16 18:30:46 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-05-16 19:07:45 +0200 |
commit | 5eb9927aae076200bb7ba3f22c33b0a7c97c5643 (patch) | |
tree | f80210439a5d8995ebf189bce7f2e141fcb1caec /gcc | |
parent | 682e587f1021241758f7dfe0b22651008622a312 (diff) | |
download | gcc-5eb9927aae076200bb7ba3f22c33b0a7c97c5643.zip gcc-5eb9927aae076200bb7ba3f22c33b0a7c97c5643.tar.gz gcc-5eb9927aae076200bb7ba3f22c33b0a7c97c5643.tar.bz2 |
d: Merge upstream dmd 60bfa0ee7, druntime 94bd5bcb, phobos 3a1cd9a01.
D front-end changes:
- Import dmd v2.100.0.
- Add bit fields to D, enabled via the -fpreview=bitfields switch.
- Removed the -ftransition=markdown and -frevert=markdown switches.
- Added new trait `__traits(classInstanceAlignment)' to provide the
required data alignment for classes.
- The check for `pragma(crt_constructor)' and `pragma(crt_destructor)'
linkage has been relaxed to allow all `void()' signatures.
- ImportC parser now recognizes the `typeof(...)' operator.
D runtime changes:
- Import druntime v2.100.0.
Phobos changes:
- Import phobos v2.100.0.
- To comply with dip1000, `std.socket.Socket` methods now accept only
`scope' arrays.
- The `fill', `alignSize', `align2', and `align4' methods of
`std.outbuffer.OutBuffer' have been extended to allow specifying a custom
value when pre-filling or padding the buffer.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 60bfa0ee7.
* dmd/VERSION: Update version to v2.100.0.
* d-builtins.cc (d_init_versions): Update for new front-end interface.
* d-codegen.cc (d_decl_context): Use resolvedLinkage to get
declaration linkage.
(build_struct_literal): Track offset in bits.
* d-gimplify.cc (d_gimplify_modify_expr): Check both operands for a
bit-field reference.
* d-lang.cc (d_handle_option): Handle -fpreview=bitfields, remove
-frevert=markdown and -ftransition=vmarkdown.
(d_post_options): Set flag_rtti and flag_exceptions if -fno-druntime
was seen on command-line.
(d_parse_file): Update for new front-end interface.
(d_type_promotes_to): Use resolvedLinkage to get declaration linkage.
* decl.cc (make_thunk): Likewise.
* expr.cc (ExprVisitor::visit (CatAssignExp *)): Remove lowering for
appending of an element or array to another array.
* lang.opt (fpreview=bitfields): New option.
(frevert=markdown): Remove.
(ftransition=vmarkdown): Remove.
* types.cc (layout_aggregate_members): Ignore anonymous fields in
total count.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 94bd5bcb.
* libdruntime/Makefile.am (ALL_DRUNTIME_INSTALL_DSOURCES): Add
$(DRUNTIME_DSOURCES_ELF).
(ALL_DRUNTIME_SOURCES): Likewise.
(DRUNTIME_DSOURCES_ELF): New variable.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos 3a1cd9a01.
* testsuite/libphobos.init_fini/custom_gc.d: Update test.
Diffstat (limited to 'gcc')
186 files changed, 3516 insertions, 2145 deletions
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 7e7fb75..cd9748c 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -475,7 +475,7 @@ d_init_versions (void) if (flag_pie) VersionCondition::addPredefinedGlobalIdent ("D_PIE"); - if (global.params.doDocComments) + if (global.params.ddoc.doOutput) VersionCondition::addPredefinedGlobalIdent ("D_Ddoc"); if (global.params.useUnitTests) diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index bb96b2f..22090a8 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -76,7 +76,7 @@ d_decl_context (Dsymbol *dsym) but only for extern(D) symbols. */ if (parent->isModule ()) { - if ((decl != NULL && decl->linkage != LINK::d) + if ((decl != NULL && decl->resolvedLinkage () != LINK::d) || (ad != NULL && ad->classKind != ClassKind::d)) return NULL_TREE; @@ -1165,7 +1165,7 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init) } vec <constructor_elt, va_gc> *ve = NULL; - HOST_WIDE_INT offset = 0; + HOST_WIDE_INT bitoffset = 0; bool constant_p = true; bool finished = false; @@ -1210,11 +1210,11 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init) if (is_initialized) { - HOST_WIDE_INT fieldpos = int_byte_position (field); + HOST_WIDE_INT fieldpos = int_bit_position (field); gcc_assert (value != NULL_TREE); /* Must not initialize fields that overlap. */ - if (fieldpos < offset) + if (fieldpos < bitoffset) { /* Find the nearest user defined type and field. */ tree vtype = type; @@ -1243,12 +1243,9 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init) finished = true; } - /* Move offset to the next position in the struct. */ - if (TREE_CODE (type) == RECORD_TYPE) - { - offset = int_byte_position (field) - + int_size_in_bytes (TREE_TYPE (field)); - } + /* Move bit offset to the next position in the struct. */ + if (TREE_CODE (type) == RECORD_TYPE && DECL_SIZE (field)) + bitoffset = int_bit_position (field) + tree_to_shwi (DECL_SIZE (field)); /* If all initializers have been assigned, there's nothing else to do. */ if (vec_safe_is_empty (init)) diff --git a/gcc/d/d-gimplify.cc b/gcc/d/d-gimplify.cc index a98089b7..36b76da 100644 --- a/gcc/d/d-gimplify.cc +++ b/gcc/d/d-gimplify.cc @@ -109,7 +109,8 @@ d_gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) } /* Same as above, but for bit-field assignments. */ - if (bit_field_ref (op0) && TREE_TYPE (op0) != TREE_TYPE (op1)) + if ((bit_field_ref (op0) || bit_field_ref (op1)) + && TREE_TYPE (op0) != TREE_TYPE (op1)) { TREE_OPERAND (*expr_p, 1) = convert (TREE_TYPE (op0), op1); return GS_OK; diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 9adcabd..d1f4959 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -478,21 +478,21 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fdoc: - global.params.doDocComments = value; + global.params.ddoc.doOutput = value; break; case OPT_fdoc_dir_: - global.params.doDocComments = true; - global.params.docdir = arg; + global.params.ddoc.doOutput = true; + global.params.ddoc.dir = arg; break; case OPT_fdoc_file_: - global.params.doDocComments = true; - global.params.docname = arg; + global.params.ddoc.doOutput = true; + global.params.ddoc.name = arg; break; case OPT_fdoc_inc_: - global.params.ddocfiles.push (arg); + global.params.ddoc.files.push (arg); break; case OPT_fdruntime: @@ -500,13 +500,12 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fdump_c___spec_: - if (global.params.doCxxHdrGeneration == CxxHeaderMode::none) - global.params.doCxxHdrGeneration = CxxHeaderMode::silent; - global.params.cxxhdrname = arg; + global.params.cxxhdr.doOutput = true; + global.params.cxxhdr.name = arg; break; case OPT_fdump_c___spec_verbose: - global.params.doCxxHdrGeneration = CxxHeaderMode::verbose; + global.params.cxxhdr.fullOutput = true; break; case OPT_fdump_d_original: @@ -572,18 +571,22 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.useDIP25 = FeatureState::enabled; global.params.useDIP1000 = FeatureState::enabled; global.params.useDIP1021 = value; + global.params.bitfields = value; global.params.dtorFields = FeatureState::enabled; global.params.fieldwise = value; global.params.fixAliasThis = value; global.params.previewIn = value; global.params.fix16997 = value; - global.params.markdown = value; global.params.noSharedAccess = value; global.params.rvalueRefParam = FeatureState::enabled; global.params.inclusiveInContracts = value; global.params.shortenedMethods = value; break; + case OPT_fpreview_bitfields: + global.params.bitfields = value; + break; + case OPT_fpreview_dip1000: global.params.useDIP1000 = FeatureState::enabled; break; @@ -641,7 +644,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.useDIP25 = FeatureState::disabled; global.params.dtorFields = FeatureState::disabled; global.params.fix16997 = !value; - global.params.markdown = !value; break; case OPT_frevert_dip1000: @@ -660,17 +662,14 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.fix16997 = !value; break; - case OPT_frevert_markdown: - global.params.markdown = !value; - break; - case OPT_frtti: global.params.useTypeInfo = value; break; case OPT_fsave_mixins_: - global.params.mixinFile = arg; - global.params.mixinOut = d_gc_malloc<OutBuffer> (); + global.params.mixinOut.doOutput = true; + global.params.mixinOut.name = arg; + global.params.mixinOut.buffer = d_gc_malloc<OutBuffer> (); break; case OPT_fswitch_errors: @@ -681,7 +680,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.vfield = value; global.params.vgc = value; global.params.vin = value; - global.params.vmarkdown= value; global.params.vtls = value; break; @@ -697,10 +695,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.vgc = value; break; - case OPT_ftransition_vmarkdown: - global.params.vmarkdown = value; - break; - case OPT_ftransition_templates: global.params.vtemplates = value; break; @@ -736,17 +730,17 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_H: - global.params.doHdrGeneration = true; + global.params.dihdr.doOutput = true; break; case OPT_Hd: - global.params.doHdrGeneration = true; - global.params.hdrdir = arg; + global.params.dihdr.doOutput = true; + global.params.dihdr.dir = arg; break; case OPT_Hf: - global.params.doHdrGeneration = true; - global.params.hdrname = arg; + global.params.dihdr.doOutput = true; + global.params.dihdr.name = arg; break; case OPT_imultilib: @@ -827,11 +821,11 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_Xf: - global.params.jsonfilename = arg; + global.params.json.name = arg; /* Fall through. */ case OPT_X: - global.params.doJsonGeneration = true; + global.params.json.doOutput = true; break; default: @@ -904,16 +898,26 @@ d_post_options (const char ** fn) ? CHECKENABLEoff : CHECKENABLEon; } + /* When not linking against D runtime, turn off all code generation that + would otherwise reference it. */ if (global.params.betterC) { if (!OPTION_SET_P (flag_moduleinfo)) global.params.useModuleInfo = false; + /* Ensure that the front-end options are in sync with the `-frtti' and + `-fexceptions' flags. */ if (!OPTION_SET_P (flag_rtti)) - global.params.useTypeInfo = false; + { + global.params.useTypeInfo = false; + flag_rtti = false; + } if (!OPTION_SET_P (flag_exceptions)) - global.params.useExceptions = false; + { + global.params.useExceptions = false; + flag_exceptions = false; + } global.params.checkAction = CHECKACTION_C; } @@ -947,19 +951,15 @@ d_post_options (const char ** fn) if (flag_excess_precision == EXCESS_PRECISION_DEFAULT) flag_excess_precision = EXCESS_PRECISION_STANDARD; - global.params.symdebug = write_symbols != NO_DEBUG; global.params.useInline = flag_inline_functions; global.params.showColumns = flag_show_column; global.params.printErrorContext = flag_diagnostics_show_caret; if (global.params.useInline) - global.params.hdrStripPlainFunctions = false; + global.params.dihdr.fullOutput = true; global.params.obj = !flag_syntax_only; - /* Has no effect yet. */ - global.params.pic = flag_pic != 0; - /* Add in versions given on the command line. */ if (global.params.versionids) { @@ -1068,8 +1068,8 @@ d_parse_file (void) /* Handling stdin, generate a unique name for the module. */ Module *m = Module::create (in_fnames[i], Identifier::idPool ("__stdin"), - global.params.doDocComments, - global.params.doHdrGeneration); + global.params.ddoc.doOutput, + global.params.dihdr.doOutput); modules.push (m); /* Overwrite the source file for the module, the one created by @@ -1084,8 +1084,8 @@ d_parse_file (void) const char *name = FileName::removeExt (basename); Module *m = Module::create (in_fnames[i], Identifier::idPool (name), - global.params.doDocComments, - global.params.doHdrGeneration); + global.params.ddoc.doOutput, + global.params.dihdr.doOutput); modules.push (m); FileName::free (name); } @@ -1142,7 +1142,7 @@ d_parse_file (void) if (global.errors) goto had_errors; - if (global.params.doHdrGeneration) + if (global.params.dihdr.doOutput) { /* Generate 'header' import files. Since 'header' import files must be independent of command line switches and what else is imported, they @@ -1316,12 +1316,12 @@ d_parse_file (void) printTemplateStats (); /* Generate JSON files. */ - if (global.params.doJsonGeneration) + if (global.params.json.doOutput) { OutBuffer buf; json_generate (&buf, &modules); - const char *name = global.params.jsonfilename.ptr; + const char *name = global.params.json.name.ptr; FILE *json_stream; if (name && (name[0] != '-' || name[1] != '\0')) @@ -1346,7 +1346,7 @@ d_parse_file (void) } /* Generate Ddoc files. */ - if (global.params.doDocComments && !global.errors && !errorcount) + if (global.params.ddoc.doOutput && !global.errors && !errorcount) { for (size_t i = 0; i < modules.length; i++) { @@ -1370,7 +1370,7 @@ d_parse_file (void) } /* Generate C++ header files. */ - if (global.params.doCxxHdrGeneration != CxxHeaderMode::none) + if (global.params.cxxhdr.doOutput) genCppHdrFiles (modules); if (global.errors) @@ -1403,23 +1403,23 @@ d_parse_file (void) errorcount += (global.errors + global.warnings); /* We want to write the mixin expansion file also on error. */ - if (global.params.mixinOut) + if (global.params.mixinOut.doOutput) { - FILE *mixin_stream = fopen (global.params.mixinFile, "w"); + FILE *mixin_stream = fopen (global.params.mixinOut.name.ptr, "w"); if (mixin_stream) { - OutBuffer *buf = global.params.mixinOut; + OutBuffer *buf = global.params.mixinOut.buffer; fprintf (mixin_stream, "%s", buf->peekChars ()); if (ferror (mixin_stream) || fclose (mixin_stream)) fatal_error (input_location, "closing mixin file %s: %m", - global.params.mixinFile); + global.params.mixinOut.name.ptr); } else { fatal_error (input_location, "opening mixin file %s: %m", - global.params.mixinFile); + global.params.mixinOut.name.ptr); } } @@ -1558,7 +1558,7 @@ d_type_promotes_to (tree type) /* Promotions are only applied on unnamed function arguments for declarations with `extern(C)' or `extern(C++)' linkage. */ if (cfun && DECL_LANG_FRONTEND (cfun->decl) - && DECL_LANG_FRONTEND (cfun->decl)->linkage != LINK::d) + && DECL_LANG_FRONTEND (cfun->decl)->resolvedLinkage () != LINK::d) { /* In [type/integer-promotions], integer promotions are conversions of the following types: diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 86ea176..f5c2107 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -1845,7 +1845,7 @@ make_thunk (FuncDeclaration *decl, int offset) forcing a D local thunk to be emitted. */ const char *ident; - if (decl->linkage == LINK::cpp) + if (decl->resolvedLinkage () == LINK::cpp) ident = target.cpp.thunkMangle (decl, offset); else { @@ -1862,7 +1862,7 @@ make_thunk (FuncDeclaration *decl, int offset) d_keep (thunk); - if (decl->linkage != LINK::cpp) + if (decl->resolvedLinkage () != LINK::cpp) free (CONST_CAST (char *, ident)); if (!DECL_EXTERNAL (function)) diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index d181191..b4d42ec 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -313d28b3db7523e67880ae3baf8ef28ce9abe9bd +a6c5224b2d6b61fa3856aa8a3369581f7c949b68 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 b143103..50c5ac3 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -164,20 +164,21 @@ Note that these groups have no strict meaning, the category assignments are a bi **Other** -| File | Purpose | -|-------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| -| [aliasthis.d](https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d) | Resolve implicit conversions for `alias X this` | -| [traits.d](https://github.com/dlang/dmd/blob/master/src/dmd/traits.d) | `__traits()` | -| [lambdacomp.d](https://github.com/dlang/dmd/blob/master/src/dmd/lambdacomp.d) | `__traits(isSame, x => y, z => w)` | -| [cond.d](https://github.com/dlang/dmd/blob/master/src/dmd/cond.d) | Evaluate `static if`, `version` `debug ` | -| [staticcond.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d) | Lazily evaluate static conditions for `static if`, `static assert` and template constraints | -| [delegatize.d](https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d) | Converts expression to delegates for `lazy` parameters | -| [eh.d](https://github.com/dlang/dmd/blob/master/src/dmd/eh.d) | Generate tables for exception handling | -| [nspace.d](https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d) | Namespace for `extern (C++, Module)` | -| [intrange.d](https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d) | [Value range propagation](https://digitalmars.com/articles/b62.html) | -| [dimport.d](https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d) | Renamed imports (`import aliasSymbol = pkg1.pkg2.symbol`) | -| [arrayop.d](https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d) | Array operations (`a[] = b[] + c[]`) | -| [typinf.d](https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d) | Generate typeinfo for `typeid()` (as well as internals) | +| File | Purpose | +|--------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| [aliasthis.d](https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d) | Resolve implicit conversions for `alias X this` | +| [traits.d](https://github.com/dlang/dmd/blob/master/src/dmd/traits.d) | `__traits()` | +| [lambdacomp.d](https://github.com/dlang/dmd/blob/master/src/dmd/lambdacomp.d) | `__traits(isSame, x => y, z => w)` | +| [cond.d](https://github.com/dlang/dmd/blob/master/src/dmd/cond.d) | Evaluate `static if`, `version` `debug ` | +| [staticcond.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d) | Lazily evaluate static conditions for `static if`, `static assert` and template constraints | +| [delegatize.d](https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d) | Converts expression to delegates for `lazy` parameters | +| [eh.d](https://github.com/dlang/dmd/blob/master/src/dmd/eh.d) | Generate tables for exception handling | +| [nspace.d](https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d) | Namespace for `extern (C++, Module)` | +| [intrange.d](https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d) | [Value range propagation](https://digitalmars.com/articles/b62.html) | +| [dimport.d](https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d) | Renamed imports (`import aliasSymbol = pkg1.pkg2.symbol`) | +| [arrayop.d](https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d) | Array operations (`a[] = b[] + c[]`) | +| [cpreprocess.d](https://github.com/dlang/dmd/blob/master/src/dmd/cpreprocess.d)| Run the C preprocessor on C source files | +| [typinf.d](https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d) | Generate typeinfo for `typeid()` (as well as internals) | | File | Purpose | |-----------------------------------------------------------------------------|------------------------------------------------------------------------------------| diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 2450fd5..5ea2ba0 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.100.0-beta.1 +v2.100.0 diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 9c8c1c3..75a16bd 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -563,9 +563,12 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) e = new DotIdExp(sd.loc, e, Id.object); e = new DotIdExp(sd.loc, e, id); e = e.expressionSemantic(sc); - Dsymbol s = getDsymbol(e); - assert(s); - sd.xerreq = s.isFuncDeclaration(); + if (!e.isErrorExp()) + { + Dsymbol s = getDsymbol(e); + assert(s); + sd.xerreq = s.isFuncDeclaration(); + } } Loc declLoc; // loc is unnecessary so __xopEquals is never called directly Loc loc; // loc is unnecessary so errors are gagged @@ -684,9 +687,12 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) e = new DotIdExp(sd.loc, e, Id.object); e = new DotIdExp(sd.loc, e, id); e = e.expressionSemantic(sc); - Dsymbol s = getDsymbol(e); - assert(s); - sd.xerrcmp = s.isFuncDeclaration(); + if (!e.isErrorExp()) + { + Dsymbol s = getDsymbol(e); + assert(s); + sd.xerrcmp = s.isFuncDeclaration(); + } } Loc declLoc; // loc is unnecessary so __xopCmp is never called directly Loc loc; // loc is unnecessary so errors are gagged @@ -867,7 +873,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) // 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; + const bool dtorIsCppPrototype = ad.userDtors.dim && ad.userDtors[0]._linkage == LINK.cpp && !ad.userDtors[0].fbody; if (!dtorIsCppPrototype) { Expression e = null; @@ -1019,7 +1025,7 @@ void buildDtors(AggregateDeclaration ad, Scope* 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) + ad.dtor = (ad.aggrDtor && ad.aggrDtor._linkage == LINK.cpp && !target.cpp.twoDtorInVtable) ? buildWindowsCppDtor(ad, ad.aggrDtor, sc) : ad.aggrDtor; diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d index d17983d..cccaabd 100644 --- a/gcc/d/dmd/common/bitfields.d +++ b/gcc/d/dmd/common/bitfields.d @@ -30,7 +30,7 @@ if (__traits(isUnsigned, T)) enum mask = "(1 << "~i.stringof~")"; result ~= " /// set or get the corresponding "~structName~" member - bool "~mem~"() const { return !!(bitFields & "~mask~"); } + bool "~mem~"() const scope { return !!(bitFields & "~mask~"); } /// ditto bool "~mem~"(bool v) { diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index 7e46d29..9a5bd82 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -309,23 +309,24 @@ struct OutBuffer writenl(); } - // Zero-terminated - void writeString(const(char)* s) pure nothrow @trusted + /** Write string to buffer, ensure it is zero terminated + */ + void writeStringz(const(char)* s) pure nothrow @trusted { write(s[0 .. strlen(s)+1]); } /// ditto - void writeString(const(char)[] s) pure nothrow + void writeStringz(const(char)[] s) pure nothrow { write(s); writeByte(0); } /// ditto - void writeString(string s) pure nothrow + void writeStringz(string s) pure nothrow { - writeString(cast(const(char)[])(s)); + writeStringz(cast(const(char)[])(s)); } extern (C++) void prependstring(const(char)* string) pure nothrow diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index dee0a17..65085f5 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -370,7 +370,7 @@ extern (C++) final class StaticForeach : RootObject Type ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1))); auto aty = ety.arrayOf(); auto idres = Identifier.generateId("__res"); - auto vard = new VarDeclaration(aloc, aty, idres, null); + auto vard = new VarDeclaration(aloc, aty, idres, null, STC.temp); auto s2 = new Statements(); // Run 'typeof' gagged to avoid duplicate errors and if it fails just create @@ -984,9 +984,9 @@ bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure // Helper for printing dependency information private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[] depType) { - if (!global.params.moduleDeps || global.params.moduleDepsFile) + if (!global.params.moduleDeps.buffer || global.params.moduleDeps.name) return; - OutBuffer* ob = global.params.moduleDeps; + OutBuffer* ob = global.params.moduleDeps.buffer; Module imod = sc ? sc._module : condition.mod; if (!imod) return; diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index bf66408..d90542f 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1181,7 +1181,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) { if (type != Type.terror) { - // have to change to Internal Compiler Error + // have to change to internal compiler error // all invalid casts should be handled already in Expression::castTo(). error(loc, "cannot cast `%s` to `%s`", e1.type.toChars(), type.toChars()); } diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 2b2046f..fde0648 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -284,6 +284,7 @@ final class CParser(AST) : Parser!AST case TOK.struct_: case TOK.union_: case TOK.enum_: + case TOK.typeof_: // storage-class-specifiers case TOK.typedef_: @@ -1662,6 +1663,14 @@ final class CParser(AST) : Parser!AST return; } + if (!tspec) + { + error("no type for declarator before `%s`", token.toChars()); + panic(); + nextToken(); + return; + } + if (tspec && specifier.mod & MOD.xconst) { tspec = toConst(tspec); @@ -2287,6 +2296,52 @@ final class CParser(AST) : Parser!AST break; } + case TOK.typeof_: + { + nextToken(); + check(TOK.leftParenthesis); + + auto tk = &token; + AST.Expression e; + if (isTypeName(tk)) + e = new AST.TypeExp(loc, cparseTypeName()); + else + e = cparseExpression(); + t = new AST.TypeTypeof(loc, e); + + if(token.value == TOK.rightParenthesis) + nextToken(); + else + { + t = AST.Type.terror; + error("`typeof` operator expects an expression or type name in parentheses"); + + // skipParens et. al expect to be on the opening parenthesis + int parens; + loop: while(1) + { + switch(token.value) + { + case TOK.leftParenthesis: + parens++; + break; + case TOK.rightParenthesis: + parens--; + if(parens < 0) + goto case; + break; + case TOK.endOfFile: + break loop; + default: + } + nextToken(); + } + } + + tkwx = TKW.xtag; + break; + } + default: break Lwhile; } @@ -2498,7 +2553,7 @@ final class CParser(AST) : Parser!AST private AST.Type cparseDeclarator(DTR declarator, AST.Type t, out Identifier pident, ref Specifier specifier) { - //printf("cparseDeclarator(%d)\n", declarator); + //printf("cparseDeclarator(%d, %p)\n", declarator, t); AST.Types constTypes; // all the Types that will need `const` applied to them constTypes.setDim(0); @@ -4227,6 +4282,7 @@ final class CParser(AST) : Parser!AST // atomic-type-specifier case TOK._Atomic: + case TOK.typeof_: t = peek(t); if (t.value != TOK.leftParenthesis || !skipParens(t, &t)) diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 13ef34c..6235342a 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -471,7 +471,7 @@ private final class CppMangleVisitor : Visitor } else { - ti.error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv.valType.toChars()); + ti.error("internal compiler error: C++ `%s` template value parameter is not supported", tv.valType.toChars()); fatal(); } } @@ -506,13 +506,13 @@ private final class CppMangleVisitor : Visitor } else { - ti.error("Internal Compiler Error: C++ `%s` template alias parameter is not supported", o.toChars()); + ti.error("internal compiler error: C++ `%s` template alias parameter is not supported", o.toChars()); fatal(); } } else if (tp.isTemplateThisParameter()) { - ti.error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o.toChars()); + ti.error("internal compiler error: C++ `%s` template this parameter is not supported", o.toChars()); fatal(); } else @@ -995,7 +995,7 @@ private final class CppMangleVisitor : Visitor // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared))) { - d.error("Internal Compiler Error: C++ static non-`__gshared` non-`extern` variables not supported"); + d.error("internal compiler error: C++ static non-`__gshared` non-`extern` variables not supported"); fatal(); } Dsymbol p = d.toParent(); @@ -1330,7 +1330,7 @@ private final class CppMangleVisitor : Visitor if (t.ty == Tsarray) { // Static arrays in D are passed by value; no counterpart in C++ - .error(loc, "Internal Compiler Error: unable to pass static array `%s` to extern(C++) function, use pointer instead", + .error(loc, "internal compiler error: unable to pass static array `%s` to extern(C++) function, use pointer instead", t.toChars()); fatal(); } @@ -1369,7 +1369,7 @@ private final class CppMangleVisitor : Visitor p = "`shared` "; else p = ""; - .error(loc, "Internal Compiler Error: %stype `%s` cannot be mapped to C++\n", p, t.toChars()); + .error(loc, "internal compiler error: %stype `%s` cannot be mapped to C++\n", p, t.toChars()); fatal(); //Fatal, because this error should be handled in frontend } diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 8397839..c0a86f5 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1695,14 +1695,6 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { // T[n] sa; // cast(U[])sa; // ==> cast(U[])sa[]; - if (global.params.useDIP1000 == FeatureState.enabled) - { - if (auto v = expToVariable(e)) - { - if (e.type.hasPointers() && !checkAddressVar(sc, e, v)) - goto Lfail; - } - } const fsize = t1b.nextOf().size(); const tsize = tob.nextOf().size(); if (fsize == SIZE_INVALID || tsize == SIZE_INVALID) @@ -2236,7 +2228,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) ArrayLiteralExp ae = e; Type tb = t.toBasetype(); - if (tb.ty == Tarray && global.params.useDIP1000 == FeatureState.enabled) + if (tb.ty == Tarray) { if (checkArrayLiteralEscape(sc, ae, false)) { @@ -2782,9 +2774,8 @@ Expression scaleFactor(BinExp be, Scope* sc) if (eoff.op == EXP.int64 && eoff.toInteger() == 0) { } - else if (sc.func.setUnsafe()) + else if (sc.func.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions")) { - be.error("pointer arithmetic not allowed in @safe functions"); return ErrorExp.get(); } } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 15ac8d9..a4a2abf 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -984,7 +984,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_); var.addMember(null, this); var.isdataseg = 1; - var.linkage = LINK.d; + var._linkage = LINK.d; var.semanticRun = PASS.semanticdone; // no more semantic wanted vtblsym = var; } diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index a533d30..bb0feb6 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -221,7 +221,7 @@ extern (C++) abstract class Declaration : Dsymbol Type originalType; // before semantic analysis StorageClass storage_class = STC.undefined_; Visibility visibility; - LINK linkage = LINK.default_; + LINK _linkage = LINK.default_; // may be `LINK.system`; use `resolvedLinkage()` to resolve it short inuse; // used to detect cycles ubyte adFlags; // control re-assignment of AliasDeclaration (put here for packing reasons) @@ -336,7 +336,7 @@ extern (C++) abstract class Declaration : Dsymbol { if (ctor.isCpCtor && ctor.isGenerated()) { - .error(loc, "Generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars()); + .error(loc, "generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars()); return true; } } @@ -420,6 +420,12 @@ extern (C++) abstract class Declaration : Dsymbol return (storage_class & STC.static_) != 0; } + /// Returns the linkage, resolving the target-specific `System` one. + final LINK resolvedLinkage() const + { + return _linkage == LINK.system ? target.systemLinkage() : _linkage; + } + bool isDelete() { return false; @@ -1506,7 +1512,7 @@ extern (C++) class VarDeclaration : Declaration uint oldgag = global.gag; if (global.gag) { - Dsymbol sym = toParent().isAggregateDeclaration(); + Dsymbol sym = isMember(); if (sym && !sym.isSpeculative()) global.gag = 0; } @@ -1691,6 +1697,32 @@ extern (C++) class BitFieldDeclaration : VarDeclaration v.visit(this); } + /*********************************** + * Retrieve the .min or .max values. + * Only valid after semantic analysis. + * Params: + * id = Id.min or Id.max + * Returns: + * the min or max value + */ + final ulong getMinMax(Identifier id) + { + const width = fieldWidth; + const uns = type.isunsigned(); + const min = id == Id.min; + ulong v; + assert(width != 0); // should have been rejected in semantic pass + if (width == ulong.sizeof * 8) + v = uns ? (min ? ulong.min : ulong.max) + : (min ? long.min : long.max); + else + v = uns ? (min ? 0 + : (1L << width) - 1) + : (min ? -(1L << (width - 1)) + : (1L << (width - 1)) - 1); + return v; + } + override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) { //printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars()); @@ -1919,7 +1951,7 @@ extern (C++) class TypeInfoDeclaration : VarDeclaration this.tinfo = tinfo; storage_class = STC.static_ | STC.gshared; visibility = Visibility(Visibility.Kind.public_); - linkage = LINK.c; + _linkage = LINK.c; alignment.set(target.ptrsize); } diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 441a966..0bde33d 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -28,6 +28,7 @@ struct Ensure class FuncDeclaration; class StructDeclaration; struct IntRange; +struct AttributeViolation; //enum STC : ulong from astenums.d: @@ -115,7 +116,7 @@ public: Type *originalType; // before semantic analysis StorageClass storage_class; Visibility visibility; - LINK linkage; + LINK _linkage; // may be `LINK::system`; use `resolvedLinkage()` to resolve it short inuse; // used to detect cycles uint8_t adFlags; Symbol* isym; // import version of csym @@ -127,6 +128,7 @@ public: Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); bool isStatic() const { return (storage_class & STCstatic) != 0; } + LINK resolvedLinkage() const; // returns the linkage, resolving the target-specific `System` one virtual bool isDelete(); virtual bool isDataseg(); virtual bool isThreadlocal(); @@ -612,6 +614,10 @@ public: FuncDeclarations *inlinedNestedCallees; +private: + AttributeViolation* safetyViolation; +public: + unsigned flags; // FUNCFLAGxxxxx // Data for a function declaration that is needed for the Objective-C @@ -655,6 +661,7 @@ public: bool isNRVO() const; void isNRVO(bool v); bool isNaked() const; + void isNaked(bool v); bool isGenerated() const; void isGenerated(bool v); bool isIntroducing() const; @@ -664,7 +671,9 @@ public: bool hasDualContext() const; bool hasAlwaysInlines() const; bool isCrtCtor() const; + void isCrtCtor(bool v); bool isCrtDtor() const; + void isCrtDtor(bool v); virtual bool isNested() const; AggregateDeclaration *isThis(); diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 3cfc07a..5e7527d 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -674,8 +674,20 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta } } // If fell off the end of a void function, return void - if (!e && tf.next.ty == Tvoid) - e = CTFEExp.voidexp; + if (!e) + { + if (tf.next.ty == Tvoid) + e = CTFEExp.voidexp; + else + { + /* missing a return statement can happen with C functions + * https://issues.dlang.org/show_bug.cgi?id=23056 + */ + fd.error("no return value from function"); + e = CTFEExp.cantexp; + } + } + if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis) e = thisarg; if (tf.isref && fd.hasDualContext() && e.op == EXP.index) @@ -695,7 +707,6 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta } } } - assert(e !is null); // Leave the function --ctfeGlobals.callDepth; @@ -1038,6 +1049,21 @@ public: if (exceptionOrCant(e)) return; + /** + * Interpret `return a ~= b` (i.e. `return _d_arrayappendT{,Trace}(a, b)`) as: + * a ~= b; + * return a; + * This is needed because `a ~= b` has to be interpreted as an lvalue, in order to avoid + * assigning a larger array into a smaller one, such as: + * `a = [1, 2], a ~= [3]` => `[1, 2] ~= [3]` => `[1, 2] = [1, 2, 3]` + */ + if (isRuntimeHook(s.exp, Id._d_arrayappendT) || isRuntimeHook(s.exp, Id._d_arrayappendTTrace)) + { + auto rs = new ReturnStatement(s.loc, e); + rs.accept(this); + return; + } + // Disallow returning pointers to stack-allocated variables (bug 7876) if (!stopPointersEscaping(s.loc, e)) { @@ -4826,6 +4852,33 @@ public: result = interpret(ce, istate); return; } + else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendTTrace) + { + // In expressionsem.d `ea ~= eb` was lowered to `_d_arrayappendT{,Trace}({file, line, funcname}, ea, eb);`. + // The following code will rewrite it back to `ea ~= eb` and then interpret that expression. + Expression lhs, rhs; + + if (fd.ident == Id._d_arrayappendT) + { + assert(e.arguments.dim == 2); + lhs = (*e.arguments)[0]; + rhs = (*e.arguments)[1]; + } + else + { + assert(e.arguments.dim == 5); + lhs = (*e.arguments)[3]; + rhs = (*e.arguments)[4]; + } + + auto cae = new CatAssignExp(e.loc, lhs, rhs); + cae.type = e.type; + + result = interpretRegion(cae, istate, CTFEGoal.LValue); + return; + } + else if (fd.ident == Id._d_arrayappendcTX) + assert(0, "CTFE cannot interpret _d_arrayappendcTX!"); } else if (auto soe = ecall.isSymOffExp()) { @@ -4947,6 +5000,25 @@ public: printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars()); } + if (auto ce = isRuntimeHook(e.e1, Id._d_arrayappendcTX)) + { + // In expressionsem.d `arr ~= elem` was lowered to + // `_d_arrayappendcTX(arr, elem), arr[arr.length - 1] = elem, elem;`. + // The following code will rewrite it back to `arr ~= elem` + // and then interpret that expression. + assert(ce.arguments.dim == 2); + + auto arr = (*ce.arguments)[0]; + auto elem = e.e2.isConstructExp().e2; + assert(elem); + + auto cae = new CatAssignExp(e.loc, arr, elem); + cae.type = arr.type; + + result = interpret(cae, istate); + return; + } + // If it creates a variable, and there's no context for // the variable to be created in, we need to create one now. InterState istateComma; @@ -6119,7 +6191,7 @@ public: return; } - if (result.isStringExp()) + if (result.isStringExp() || result.isArrayLiteralExp()) return; if (result.op != EXP.address) @@ -6268,7 +6340,7 @@ public: result = (*se.elements)[i]; if (!result) { - e.error("Internal Compiler Error: null field `%s`", v.toChars()); + e.error("internal compiler error: null field `%s`", v.toChars()); result = CTFEExp.cantexp; return; } @@ -6359,6 +6431,33 @@ public: { assert(0); // This should never be interpreted } + + /********************************************* + * Checks if the given expresion is a call to the runtime hook `id`. + * Params: + * e = the expression to check + * id = the identifier of the runtime hook + * Returns: + * `e` cast to `CallExp` if it's the hook, `null` otherwise + */ + private CallExp isRuntimeHook(Expression e, Identifier id) + { + if (auto ce = e.isCallExp()) + { + if (auto ve = ce.e1.isVarExp()) + { + if (auto fd = ve.var.isFuncDeclaration()) + { + // If `_d_HookTraceImpl` is found, resolve the underlying + // hook and replace `e` and `fd` with it. + removeHookTraceImpl(ce, fd); + return fd.ident == id ? ce : null; + } + } + } + + return null; + } } /******************************************** diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 1f895e0..7604296 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -1335,15 +1335,19 @@ void realToMangleBuffer(OutBuffer* buf, real_t value) private extern (D) const(char)[] externallyMangledIdentifier(Declaration d) { + assert(!d.mangleOverride, "mangle overrides should have been handled earlier"); + + const linkage = d.resolvedLinkage(); const par = d.toParent(); //toParent() skips over mixin templates - if (!par || par.isModule() || d.linkage == LINK.cpp || - (d.linkage == LINK.c && d.isCsymbol() && d.isFuncDeclaration())) + if (!par || par.isModule() || linkage == LINK.cpp || + (linkage == LINK.c && d.isCsymbol() && + (d.isFuncDeclaration() || + (d.isVarDeclaration() && d.isDataseg() && d.storage_class & STC.extern_)))) { - if (d.linkage != LINK.d && d.localNum) + if (linkage != LINK.d && d.localNum) d.error("the same declaration cannot be in multiple scopes with non-D linkage"); - const l = d.linkage == LINK.system ? target.systemLinkage() : d.linkage; - final switch (l) + final switch (linkage) { case LINK.d: break; diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 2d9f651..26a0ff0 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -71,7 +71,7 @@ void semantic3OnDependencies(Module m) */ void removeHdrFilesAndFail(ref Param params, ref Modules modules) nothrow { - if (params.doHdrGeneration) + if (params.dihdr.doOutput) { foreach (m; modules) { @@ -472,7 +472,7 @@ extern (C++) final class Module : Package if (doDocComment) setDocfile(); if (doHdrGen) - hdrfile = setOutfilename(global.params.hdrname, global.params.hdrdir, arg, hdr_ext); + hdrfile = setOutfilename(global.params.dihdr.name, global.params.dihdr.dir, arg, hdr_ext); } extern (D) this(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen) @@ -584,7 +584,7 @@ extern (C++) final class Module : Package extern (D) void setDocfile() { - docfile = setOutfilename(global.params.docname, global.params.docdir, arg, doc_ext); + docfile = setOutfilename(global.params.ddoc.name, global.params.ddoc.dir, arg, doc_ext); } /** @@ -662,11 +662,55 @@ extern (C++) final class Module : Package return true; // already read //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars()); - if (auto result = global.fileManager.lookup(srcfile)) + + /* Preprocess the file if it's a .c file + */ + FileName filename = srcfile; + bool ifile = false; // did we generate a .i file + scope (exit) + { + if (ifile) + File.remove(filename.toChars()); // remove generated file + } + + if (global.preprocess && + FileName.equalsExt(srcfile.toString(), c_ext) && + FileName.exists(srcfile.toString())) + { + /* Look for "importc.h" by searching along import path. + * It should be in the same place as "object.d" + */ + const(char)* importc_h; + + foreach (entry; (global.path ? (*global.path)[] : null)) + { + auto f = FileName.combine(entry, "importc.h"); + if (FileName.exists(f) == 1) + { + importc_h = f; + break; + } + FileName.free(f); + } + + if (importc_h) + { + if (global.params.verbose) + message("include %s", importc_h); + } + else + { + error("cannot find \"importc.h\" along import path"); + fatal(); + } + filename = global.preprocess(srcfile, importc_h, global.params.cppswitches, ifile); // run C preprocessor + } + + if (auto result = global.fileManager.lookup(filename)) { this.src = result; - if (global.params.emitMakeDeps) - global.params.makeDeps.push(srcfile.toChars()); + if (global.params.makeDeps.doOutput) + global.params.makeDeps.files.push(srcfile.toChars()); return true; } diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index d05060d..6eb433e 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -384,11 +384,11 @@ extern(C++) void gendocfile(Module m) // Override with DDOCFILE specified in the sc.ini file char* p = getenv("DDOCFILE"); if (p) - global.params.ddocfiles.shift(p); + global.params.ddoc.files.shift(p); // Override with the ddoc macro files from the command line - for (size_t i = 0; i < global.params.ddocfiles.dim; i++) + for (size_t i = 0; i < global.params.ddoc.files.dim; i++) { - auto buffer = readFile(m.loc, global.params.ddocfiles[i]); + auto buffer = readFile(m.loc, global.params.ddoc.files[i]); // BUG: convert file contents to UTF-8 before use const data = buffer.data; //printf("file: '%.*s'\n", cast(int)data.length, data.ptr); @@ -628,7 +628,7 @@ private void escapeStrayParenthesis(Loc loc, OutBuffer* buf, size_t start, bool break; case '\\': // replace backslash-escaped parens with their macros - if (!inCode && respectBackslashEscapes && u+1 < buf.length && global.params.markdown) + if (!inCode && respectBackslashEscapes && u+1 < buf.length) { if ((*buf)[u+1] == '(' || (*buf)[u+1] == ')') { @@ -2317,8 +2317,6 @@ private void removeBlankLineMacro(ref OutBuffer buf, ref size_t iAt, ref size_t */ private bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_t iLineStart, const ref Loc loc) { - if (!global.params.markdown) - return false; const slice = buf[]; const c = buf[i]; @@ -2335,12 +2333,6 @@ private bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_ { if (j >= buf.length || buf[j] == '\n' || buf[j] == '\r') { - if (global.params.vmarkdown) - { - const s = buf[][i..j]; - message(loc, "Ddoc: converted '%.*s' to a thematic break", cast(int)s.length, s.ptr); - } - buf.remove(iLineStart, j - iLineStart); i = buf.insert(iLineStart, "$(HR)") - 1; return true; @@ -2361,9 +2353,6 @@ private bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_ */ private int detectAtxHeadingLevel(ref OutBuffer buf, const size_t i) { - if (!global.params.markdown) - return 0; - const iHeadingStart = i; const iAfterHashes = skipChars(buf, i, "#"); const headingLevel = cast(int) (iAfterHashes - iHeadingStart); @@ -2433,14 +2422,6 @@ private void removeAnyAtxHeadingSuffix(ref OutBuffer buf, size_t i) */ private void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEnd, const ref Loc loc, ref int headingLevel) { - if (!global.params.markdown) - return; - if (global.params.vmarkdown) - { - const s = buf[][iStart..iEnd]; - message(loc, "Ddoc: added heading '%.*s'", cast(int)s.length, s.ptr); - } - char[5] heading = "$(H0 "; heading[3] = cast(char) ('0' + headingLevel); buf.insert(iStart, heading); @@ -2503,9 +2484,6 @@ private size_t endAllListsAndQuotes(ref OutBuffer buf, ref size_t i, ref Markdow */ private size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int downToLevel = 0) { - if (!global.params.markdown) - return 0; - size_t replaceEmphasisPair(ref MarkdownDelimiter start, ref MarkdownDelimiter end) { immutable count = start.count == 1 || end.count == 1 ? 1 : 2; @@ -2521,12 +2499,6 @@ private size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref if (!end.count) end.type = 0; - if (global.params.vmarkdown) - { - const s = buf[][iStart + count..iEnd]; - message(loc, "Ddoc: emphasized text '%.*s'", cast(int)s.length, s.ptr); - } - buf.remove(iStart, count); iEnd -= count; buf.remove(iEnd, count); @@ -2857,9 +2829,6 @@ private struct MarkdownList */ static MarkdownList parseItem(ref OutBuffer buf, size_t iLineStart, size_t i) { - if (!global.params.markdown) - return MarkdownList(); - if (buf[i] == '+' || buf[i] == '-' || buf[i] == '*') return parseUnorderedListItem(buf, iLineStart, i); else @@ -2931,15 +2900,6 @@ private struct MarkdownList i = iStart - 1; iLineStart = i; - if (global.params.vmarkdown) - { - size_t iEnd = iStart; - while (iEnd < buf.length && buf[iEnd] != '\r' && buf[iEnd] != '\n') - ++iEnd; - const s = buf[][iStart..iEnd]; - message(loc, "Ddoc: starting list item '%.*s'", cast(int)s.length, s.ptr); - } - return true; } @@ -3122,13 +3082,6 @@ private struct MarkdownLink immutable delta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, delimiterIndex); iEnd += delta; i += delta; - - if (global.params.vmarkdown) - { - const s = buf[][delimiter.iStart..iEnd]; - message(loc, "Ddoc: linking '%.*s' to '%.*s'", cast(int)s.length, s.ptr, cast(int)link.href.length, link.href.ptr); - } - link.replaceLink(buf, i, iEnd, delimiter); return true; } @@ -3532,9 +3485,6 @@ private struct MarkdownLink */ private void storeAndReplaceDefinition(ref OutBuffer buf, ref size_t i, size_t iEnd, ref MarkdownLinkReferences linkReferences, const ref Loc loc) { - if (global.params.vmarkdown) - message(loc, "Ddoc: found link reference '%.*s' to '%.*s'", cast(int)label.length, label.ptr, cast(int)href.length, href.ptr); - // Remove the definition and trailing whitespace iEnd = skipChars(buf, iEnd, " \t\r\n"); buf.remove(i, iEnd - i); @@ -4050,12 +4000,6 @@ private bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, cons if (headerRow && cellCount != columnAlignments.length) return false; - if (headerRow && global.params.vmarkdown) - { - const s = buf[][iStart..iEnd]; - message(loc, "Ddoc: formatting table '%.*s'", cast(int)s.length, s.ptr); - } - void replaceTableCell(size_t iCellStart, size_t iCellEnd, int cellIndex, int di) { const eDelta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, di); @@ -4378,17 +4322,8 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s case '>': { - if (leadingBlank && (!inCode || quoteLevel) && global.params.markdown) + if (leadingBlank && (!inCode || quoteLevel)) { - if (!quoteLevel && global.params.vmarkdown) - { - size_t iEnd = i + 1; - while (iEnd < buf.length && buf[iEnd] != '\n') - ++iEnd; - const s = buf[][i .. iEnd]; - message(loc, "Ddoc: starting quote block with '%.*s'", cast(int)s.length, s.ptr); - } - lineQuoted = true; int lineQuoteLevel = 1; size_t iAfterDelimiters = i + 1; @@ -4488,7 +4423,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s } // Perhaps we're starting or ending a Markdown code block - if (leadingBlank && global.params.markdown && count >= 3) + if (leadingBlank && count >= 3) { bool moreBackticks = false; for (size_t j = iAfterDelimiter; !moreBackticks && j < buf.length; ++j) @@ -4548,7 +4483,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s case '~': { - if (leadingBlank && global.params.markdown) + if (leadingBlank) { // Perhaps we're starting or ending a Markdown code block const iAfterDelimiter = skipChars(buf, i, "~"); @@ -4613,7 +4548,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s // BUG: handle UTF PS and LS too if (c != c0 || iInfoString) { - if (global.params.markdown && !iInfoString && !inCode && i - istart >= 3) + if (!iInfoString && !inCode && i - istart >= 3) { // Start a Markdown info string, like ```ruby codeFenceLength = i - istart; @@ -4711,9 +4646,6 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s if (codeLanguage[j] == '\\' && ispunct(codeLanguage[j + 1])) codeLanguage = codeLanguage[0..j] ~ codeLanguage[j + 1..$]; - if (global.params.vmarkdown) - message(loc, "Ddoc: adding code block for language '%.*s'", cast(int)codeLanguage.length, codeLanguage.ptr); - i = buf.insert(i, "$(OTHER_CODE "); i = buf.insert(i, codeLanguage); i = buf.insert(i, ","); @@ -4779,7 +4711,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s case '*': { - if (inCode || inBacktick || !global.params.markdown) + if (inCode || inBacktick) { leadingBlank = false; break; @@ -4829,7 +4761,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s { leadingBlank = false; - if (inCode || !global.params.markdown) + if (inCode) break; if (i < buf.length-1 && buf[i+1] == '[') @@ -4842,7 +4774,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s } case '[': { - if (inCode || !global.params.markdown) + if (inCode) { leadingBlank = false; break; @@ -4860,7 +4792,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s { leadingBlank = false; - if (inCode || !global.params.markdown) + if (inCode) break; for (int d = cast(int) inlineDelimiters.length - 1; d >= 0; --d) @@ -4894,7 +4826,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s case '|': { - if (inCode || !global.params.markdown) + if (inCode) { leadingBlank = false; break; @@ -4909,16 +4841,13 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s case '\\': { leadingBlank = false; - if (inCode || i+1 >= buf.length || !global.params.markdown) + if (inCode || i+1 >= buf.length) break; /* Escape Markdown special characters */ char c1 = buf[i+1]; if (ispunct(c1)) { - if (global.params.vmarkdown) - message(loc, "Ddoc: backslash-escaped %c", c1); - buf.remove(i, 1); auto se = sc._module.escapetable.escapeChar(c1); diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 6339a9e..b546e37 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -63,7 +63,6 @@ enum SCOPE free = 0x8000, /// is on free list fullinst = 0x10000, /// fully instantiate templates - alias_ = 0x20000, /// inside alias declaration. // The following are mutually exclusive printf = 0x4_0000, /// printf-style function diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 74eaa1d..b006940 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -984,7 +984,7 @@ extern (C++) class Dsymbol : ASTNode */ uinteger_t size(const ref Loc loc) { - error("Dsymbol `%s` has no size", toChars()); + error("symbol `%s` has no size", toChars()); return SIZE_INVALID; } @@ -1641,6 +1641,32 @@ public: } } + + /***************************************** + * Returns: the symbols whose members have been imported, i.e. imported modules + * and template mixins. + * + * See_Also: importScope + */ + extern (D) final Dsymbols* getImportedScopes() nothrow @nogc @safe pure + { + return importedScopes; + } + + /***************************************** + * Returns: the array of visibilities associated with each imported scope. The + * length of the array matches the imported scopes array. + * + * See_Also: getImportedScopes + */ + extern (D) final Visibility.Kind[] getImportVisibilities() nothrow @nogc @safe pure + { + if (!importedScopes) + return null; + + return (() @trusted => visibilities[0 .. importedScopes.dim])(); + } + extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow { auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 5415401..5d88056 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -376,7 +376,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // 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._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() @@ -389,7 +389,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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._linkage = sc.linkage; dsym.visibility = sc.visibility; dsym.alignment = sc.alignment(); } @@ -472,8 +472,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { if (dsym.storage_class & STC.gshared && !dsym.isMember()) { - if (sc.func.setUnsafe()) - dsym.error("__gshared not allowed in safe functions; use shared"); + sc.func.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared"); } } @@ -863,20 +862,18 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (dsym._init && dsym._init.isVoidInitializer() && (dsym.type.hasPointers() || dsym.type.hasInvariant())) // also computes type size { - if (sc.func.setUnsafe()) - { - if (dsym.type.hasPointers()) - dsym.error("`void` initializers for pointers not allowed in safe functions"); - else - dsym.error("`void` initializers for structs with invariants are not allowed in safe functions"); - } + if (dsym.type.hasPointers()) + sc.func.setUnsafe(false, dsym.loc, + "`void` initializers for pointers not allowed in safe functions"); + else + sc.func.setUnsafe(false, dsym.loc, + "`void` initializers for structs with invariants are not allowed in safe functions"); } else if (!dsym._init && !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) && dsym.type.hasVoidInitPointers()) { - if (sc.func.setUnsafe()) - dsym.error("`void` initializers for pointers not allowed in safe functions"); + sc.func.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions"); } } @@ -891,6 +888,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else if (dsym.storage_class & STC.manifest) dsym.error("manifest constants must have initializers"); + // Don't allow non-extern, non-__gshared variables to be interfaced with C++ + if (dsym._linkage == LINK.cpp && !(dsym.storage_class & (STC.ctfe | STC.extern_ | STC.gshared)) && dsym.isDataseg()) + { + const char* p = (dsym.storage_class & STC.shared_) ? "shared" : "static"; + dsym.error("cannot have `extern(C++)` linkage because it is `%s`", p); + errorSupplemental(dsym.loc, "perhaps declare it as `__gshared` instead"); + dsym.errors = true; + } + bool isBlit = false; uinteger_t sz; if (sc.flags & SCOPE.Cfile && !dsym._init) @@ -1191,7 +1197,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(TypeInfoDeclaration dsym) { - assert(dsym.linkage == LINK.c); + assert(dsym._linkage == LINK.c); } override void visit(BitFieldDeclaration dsym) @@ -1204,6 +1210,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (dsym.errors) return; + if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration()) + { + dsym.error("bit-field must be member of struct, union, or class"); + } + sc = sc.startCTFE(); auto width = dsym.width.expressionSemantic(sc); sc = sc.endCTFE(); @@ -1239,7 +1250,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(Import imp) { - //printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars()); + static if (LOG) + { + printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars()); + scope(exit) + printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); + } if (imp.semanticRun > PASS.initial) return; @@ -1349,70 +1365,69 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // don't list pseudo modules __entrypoint.d, __main.d // https://issues.dlang.org/show_bug.cgi?id=11117 // https://issues.dlang.org/show_bug.cgi?id=11164 - if (global.params.moduleDeps !is null && !(imp.id == Id.object && sc._module.ident == Id.object) && - strcmp(sc._module.ident.toChars(), "__main") != 0) - { - /* The grammar of the file is: - * ImportDeclaration - * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " - * ModuleAliasIdentifier ] "\n" - * - * BasicImportDeclaration - * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string" - * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" - * - * FilePath - * - any string with '(', ')' and '\' escaped with the '\' character - */ - OutBuffer* ob = global.params.moduleDeps; - Module imod = sc._module; - if (!global.params.moduleDepsFile) - ob.writestring("depsImport "); - ob.writestring(imod.toPrettyChars()); - ob.writestring(" ("); - escapePath(ob, imod.srcfile.toChars()); - ob.writestring(") : "); - // use visibility instead of sc.visibility because it couldn't be - // resolved yet, see the comment above - visibilityToBuffer(ob, imp.visibility); + if (global.params.moduleDeps.buffer is null || (imp.id == Id.object && sc._module.ident == Id.object) || + strcmp(sc._module.ident.toChars(), "__main") == 0) + return; + + /* The grammar of the file is: + * ImportDeclaration + * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " + * ModuleAliasIdentifier ] "\n" + * + * BasicImportDeclaration + * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string" + * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" + * + * FilePath + * - any string with '(', ')' and '\' escaped with the '\' character + */ + OutBuffer* ob = global.params.moduleDeps.buffer; + Module imod = sc._module; + if (!global.params.moduleDeps.name) + ob.writestring("depsImport "); + ob.writestring(imod.toPrettyChars()); + ob.writestring(" ("); + escapePath(ob, imod.srcfile.toChars()); + ob.writestring(") : "); + // use visibility instead of sc.visibility because it couldn't be + // resolved yet, see the comment above + visibilityToBuffer(ob, imp.visibility); + ob.writeByte(' '); + if (imp.isstatic) + { + stcToBuffer(ob, STC.static_); ob.writeByte(' '); - if (imp.isstatic) - { - stcToBuffer(ob, STC.static_); - ob.writeByte(' '); - } - ob.writestring(": "); - foreach (pid; imp.packages) - { - ob.printf("%s.", pid.toChars()); - } - ob.writestring(imp.id.toString()); - ob.writestring(" ("); - if (imp.mod) - escapePath(ob, imp.mod.srcfile.toChars()); + } + ob.writestring(": "); + foreach (pid; imp.packages) + { + ob.printf("%s.", pid.toChars()); + } + ob.writestring(imp.id.toString()); + ob.writestring(" ("); + if (imp.mod) + escapePath(ob, imp.mod.srcfile.toChars()); + else + ob.writestring("???"); + ob.writeByte(')'); + foreach (i, name; imp.names) + { + if (i == 0) + ob.writeByte(':'); else - ob.writestring("???"); - ob.writeByte(')'); - foreach (i, name; imp.names) + ob.writeByte(','); + Identifier _alias = imp.aliases[i]; + if (!_alias) { - if (i == 0) - ob.writeByte(':'); - else - ob.writeByte(','); - Identifier _alias = imp.aliases[i]; - if (!_alias) - { - ob.printf("%s", name.toChars()); - _alias = name; - } - else - ob.printf("%s=%s", _alias.toChars(), name.toChars()); + ob.printf("%s", name.toChars()); + _alias = name; } - if (imp.aliasId) - ob.printf(" -> %s", imp.aliasId.toChars()); - ob.writenl(); + else + ob.printf("%s=%s", _alias.toChars(), name.toChars()); } - //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); + if (imp.aliasId) + ob.printf(" -> %s", imp.aliasId.toChars()); + ob.writenl(); } void attribSemantic(AttribDeclaration ad) @@ -1457,24 +1472,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return; } - if (scd.decl) + if (!scd.decl) + return; + + sc = sc.push(); + sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.gshared); + sc.inunion = scd.isunion ? scd : null; + sc.flags = 0; + for (size_t i = 0; i < scd.decl.dim; i++) { - sc = sc.push(); - sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.gshared); - sc.inunion = scd.isunion ? scd : null; - sc.flags = 0; - for (size_t i = 0; i < scd.decl.dim; i++) + Dsymbol s = (*scd.decl)[i]; + if (auto var = s.isVarDeclaration) { - Dsymbol s = (*scd.decl)[i]; - if (auto var = s.isVarDeclaration) - { - if (scd.isunion) - var.overlapped = true; - } - s.dsymbolSemantic(sc); + if (scd.isunion) + var.overlapped = true; } - sc = sc.pop(); + s.dsymbolSemantic(sc); } + sc = sc.pop(); } override void visit(PragmaDeclaration pd) @@ -1633,32 +1648,33 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } if (pd.ident == Id.msg) { - if (pd.args) + if (!pd.args) + return noDeclarations(); + + for (size_t i = 0; i < pd.args.dim; i++) { - for (size_t i = 0; i < pd.args.dim; i++) + Expression e = (*pd.args)[i]; + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + e = ctfeInterpretForPragmaMsg(e); + if (e.op == EXP.error) { - Expression e = (*pd.args)[i]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = ctfeInterpretForPragmaMsg(e); - if (e.op == EXP.error) - { - errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars()); - return; - } - StringExp se = e.toStringExp(); - if (se) - { - se = se.toUTF8(sc); - fprintf(stderr, "%.*s", cast(int)se.len, se.peekString().ptr); - } - else - fprintf(stderr, "%s", e.toChars()); + errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars()); + return; } - fprintf(stderr, "\n"); + StringExp se = e.toStringExp(); + if (se) + { + se = se.toUTF8(sc); + fprintf(stderr, "%.*s", cast(int)se.len, se.peekString().ptr); + } + else + fprintf(stderr, "%s", e.toChars()); } + fprintf(stderr, "\n"); + return noDeclarations(); } else if (pd.ident == Id.lib) @@ -1675,9 +1691,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor auto name = se.peekString().xarraydup; if (global.params.verbose) message("library %s", name.ptr); - if (global.params.moduleDeps && !global.params.moduleDepsFile) + if (global.params.moduleDeps.buffer && !global.params.moduleDeps.name) { - OutBuffer* ob = global.params.moduleDeps; + OutBuffer* ob = global.params.moduleDeps.buffer; Module imod = sc._module; ob.writestring("depsLib "); ob.writestring(imod.toPrettyChars()); @@ -1892,49 +1908,49 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return Identifier.idPool(sident); } - if (ns.ident is null) - { - ns.cppnamespace = sc.namespace; - sc = sc.startCTFE(); - ns.exp = ns.exp.expressionSemantic(sc); - ns.exp = resolveProperties(sc, ns.exp); - sc = sc.endCTFE(); - ns.exp = ns.exp.ctfeInterpret(); - // Can be either a tuple of strings or a string itself - if (auto te = ns.exp.isTupleExp()) - { - expandTuples(te.exps); - CPPNamespaceDeclaration current = ns.cppnamespace; - for (size_t d = 0; d < te.exps.dim; ++d) + if (ns.ident !is null) + return attribSemantic(ns); + + ns.cppnamespace = sc.namespace; + sc = sc.startCTFE(); + ns.exp = ns.exp.expressionSemantic(sc); + ns.exp = resolveProperties(sc, ns.exp); + sc = sc.endCTFE(); + ns.exp = ns.exp.ctfeInterpret(); + // Can be either a tuple of strings or a string itself + if (auto te = ns.exp.isTupleExp()) + { + expandTuples(te.exps); + CPPNamespaceDeclaration current = ns.cppnamespace; + for (size_t d = 0; d < te.exps.dim; ++d) + { + auto exp = (*te.exps)[d]; + auto prev = d ? current : ns.cppnamespace; + current = (d + 1) != te.exps.dim + ? new CPPNamespaceDeclaration(ns.loc, exp, null) + : ns; + current.exp = exp; + current.cppnamespace = prev; + if (auto se = exp.toStringExp()) { - auto exp = (*te.exps)[d]; - auto prev = d ? current : ns.cppnamespace; - current = (d + 1) != te.exps.dim - ? new CPPNamespaceDeclaration(ns.loc, exp, null) - : ns; - current.exp = exp; - current.cppnamespace = prev; - if (auto se = exp.toStringExp()) - { - current.ident = identFromSE(se); - if (current.ident is null) - return; // An error happened in `identFromSE` - } - else - ns.exp.error("`%s`: index %llu is not a string constant, it is a `%s`", - ns.exp.toChars(), cast(ulong) d, ns.exp.type.toChars()); + current.ident = identFromSE(se); + if (current.ident is null) + return; // An error happened in `identFromSE` } + else + ns.exp.error("`%s`: index %llu is not a string constant, it is a `%s`", + ns.exp.toChars(), cast(ulong) d, ns.exp.type.toChars()); } - else if (auto se = ns.exp.toStringExp()) - ns.ident = identFromSE(se); - // Empty Tuple - else if (ns.exp.isTypeExp() && ns.exp.isTypeExp().type.toBasetype().isTypeTuple()) - { - } - else - ns.exp.error("compile time string constant (or tuple) expected, not `%s`", - ns.exp.toChars()); } + else if (auto se = ns.exp.toStringExp()) + ns.ident = identFromSE(se); + // Empty Tuple + else if (ns.exp.isTypeExp() && ns.exp.isTypeExp().type.toBasetype().isTypeTuple()) + { + } + else + ns.exp.error("compile time string constant (or tuple) expected, not `%s`", + ns.exp.toChars()); attribSemantic(ns); } @@ -2174,7 +2190,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor em.semanticRun = PASS.semantic; em.type = Type.tint32; - em.linkage = LINK.c; + em._linkage = LINK.c; em.storage_class |= STC.manifest; if (em.value) { @@ -2264,7 +2280,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor em.semanticRun = PASS.semantic; em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_); - em.linkage = LINK.d; + em._linkage = LINK.d; em.storage_class |= STC.manifest; // https://issues.dlang.org/show_bug.cgi?id=9701 @@ -2538,7 +2554,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor Scope* paramscope = sc.push(paramsym); paramscope.stc = 0; - if (global.params.doDocComments) + if (global.params.ddoc.doOutput) { tempdecl.origParameters = new TemplateParameters(tempdecl.parameters.dim); for (size_t i = 0; i < tempdecl.parameters.dim; i++) @@ -2824,7 +2840,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ //if (!sc.func && Module.deferred.dim > deferred_dim) {} - AggregateDeclaration ad = tm.toParent().isAggregateDeclaration(); + AggregateDeclaration ad = tm.isMember(); if (sc.func && !ad) { tm.semantic2(sc2); @@ -2855,6 +2871,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor static if (LOG) { printf("+Nspace::semantic('%s')\n", ns.toChars()); + scope(exit) printf("-Nspace::semantic('%s')\n", ns.toChars()); } if (ns._scope) { @@ -2931,36 +2948,34 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Link does not matter here, if the UDA is present it will error UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp); - if (ns.members) + if (!ns.members) + { + ns.semanticRun = PASS.semanticdone; + return; + } + assert(sc); + sc = sc.push(ns); + sc.linkage = LINK.cpp; // note that namespaces imply C++ linkage + sc.parent = ns; + foreach (s; *ns.members) { - assert(sc); - sc = sc.push(ns); - sc.linkage = LINK.cpp; // note that namespaces imply C++ linkage - sc.parent = ns; - foreach (s; *ns.members) + if (repopulateMembers) { - if (repopulateMembers) - { - s.addMember(sc, sc.scopesym); - s.setScope(sc); - } - s.importAll(sc); + s.addMember(sc, sc.scopesym); + s.setScope(sc); } - foreach (s; *ns.members) + s.importAll(sc); + } + foreach (s; *ns.members) + { + static if (LOG) { - static if (LOG) - { - printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); - } - s.dsymbolSemantic(sc); + printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); } - sc.pop(); + s.dsymbolSemantic(sc); } + sc.pop(); ns.semanticRun = PASS.semanticdone; - static if (LOG) - { - printf("-Nspace::semantic('%s')\n", ns.toChars()); - } } void funcDeclarationSemantic(FuncDeclaration funcdecl) @@ -3024,7 +3039,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sc.flags & SCOPE.compile) funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function - funcdecl.linkage = sc.linkage; + funcdecl._linkage = sc.linkage; if (auto fld = funcdecl.isFuncLiteralDeclaration()) { if (fld.treq) @@ -3037,7 +3052,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor fld.tok = TOK.function_; else assert(0); - funcdecl.linkage = treq.nextOf().toTypeFunction().linkage; + funcdecl._linkage = treq.nextOf().toTypeFunction().linkage; } } @@ -3045,19 +3060,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (auto pragmadecl = sc.inlining) funcdecl.inlining = pragmadecl.evalPragmaInline(sc); - // check pragma(crt_constructor) - if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor)) - { - if (funcdecl.linkage != LINK.c) - { - funcdecl.error("must be `extern(C)` for `pragma(%s)`", - (funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor".ptr : "crt_destructor".ptr); - } - } - funcdecl.visibility = sc.visibility; funcdecl.userAttribDecl = sc.userAttribDecl; - UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl.linkage); + UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl._linkage); checkMustUseReserved(funcdecl); if (!funcdecl.originalType) @@ -3193,7 +3198,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor tf.isScopeQual = false; } - sc.linkage = funcdecl.linkage; + sc.linkage = funcdecl._linkage; if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) { @@ -3243,6 +3248,16 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR); } + // check pragma(crt_constructor) signature + if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor)) + { + const idStr = (funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor" : "crt_destructor"; + if (f.nextOf().ty != Tvoid) + funcdecl.error("must return `void` for `pragma(%s)`", idStr.ptr); + if (funcdecl._linkage != LINK.c && f.parameterList.length != 0) + funcdecl.error("must be `extern(C)` for `pragma(%s)` when taking parameters", idStr.ptr); + } + if (funcdecl.overnext && funcdecl.isCsymbol()) { /* C does not allow function overloading, but it does allow @@ -4027,67 +4042,67 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ if (ad && (!ctd.parent.isTemplateInstance() || ctd.parent.isTemplateMixin())) { - if (sd) + if (!sd) { - if (dim == 0 && tf.parameterList.varargs == VarArg.none) // empty default ctor w/o any varargs - { - if (ctd.fbody || !(ctd.storage_class & STC.disable)) - { - ctd.error("default constructor for structs only allowed " ~ - "with `@disable`, no body, and no parameters"); - ctd.storage_class |= STC.disable; - ctd.fbody = null; - } - sd.noDefaultCtor = true; - } - else if (dim == 0 && tf.parameterList.varargs != VarArg.none) // allow varargs only ctor - { - } - else if (dim && tf.parameterList[0].defaultArg) + if (dim == 0 && tf.parameterList.varargs == VarArg.none) + ad.defaultCtor = ctd; + return; + } + + if (dim == 0 && tf.parameterList.varargs == VarArg.none) // empty default ctor w/o any varargs + { + if (ctd.fbody || !(ctd.storage_class & STC.disable)) { - // if the first parameter has a default argument, then the rest does as well - if (ctd.storage_class & STC.disable) - { - ctd.error("is marked `@disable`, so it cannot have default "~ - "arguments for all parameters."); - errorSupplemental(ctd.loc, "Use `@disable this();` if you want to disable default initialization."); - } - else - ctd.error("all parameters have default arguments, "~ - "but structs cannot have default constructors."); + ctd.error("default constructor for structs only allowed " ~ + "with `@disable`, no body, and no parameters"); + ctd.storage_class |= STC.disable; + ctd.fbody = null; } - else if ((dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) + sd.noDefaultCtor = true; + } + else if (dim == 0 && tf.parameterList.varargs != VarArg.none) // allow varargs only ctor + { + } + else if (dim && tf.parameterList[0].defaultArg) + { + // if the first parameter has a default argument, then the rest does as well + if (ctd.storage_class & STC.disable) { - //printf("tf: %s\n", tf.toChars()); - auto param = tf.parameterList[0]; - if (param.storageClass & STC.ref_ && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) - { - //printf("copy constructor\n"); - ctd.isCpCtor = true; - } + ctd.error("is marked `@disable`, so it cannot have default "~ + "arguments for all parameters."); + errorSupplemental(ctd.loc, "Use `@disable this();` if you want to disable default initialization."); } + else + ctd.error("all parameters have default arguments, "~ + "but structs cannot have default constructors."); } - else if (dim == 0 && tf.parameterList.varargs == VarArg.none) + else if ((dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) { - ad.defaultCtor = ctd; + //printf("tf: %s\n", tf.toChars()); + auto param = tf.parameterList[0]; + if (param.storageClass & STC.ref_ && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) + { + //printf("copy constructor\n"); + ctd.isCpCtor = true; + } } } // https://issues.dlang.org/show_bug.cgi?id=22593 else if (auto ti = ctd.parent.isTemplateInstance()) { - if (sd && sd.hasCopyCtor && (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) - { - auto param = tf.parameterList[0]; + if (!sd || !sd.hasCopyCtor || !(dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) + return; - // if the template instance introduces an rvalue constructor - // between the members of a struct declaration, we should check if a - // copy constructor exists and issue an error in that case. - if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) - { - .error(ctd.loc, "Cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars); - .errorSupplemental(ti.loc, "Template instance `%s` creates a rvalue constructor for `struct %s`", - ti.toChars(), sd.toChars()); - } + auto param = tf.parameterList[0]; + + // if the template instance introduces an rvalue constructor + // between the members of a struct declaration, we should check if a + // copy constructor exists and issue an error in that case. + if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) + { + .error(ctd.loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars); + .errorSupplemental(ti.loc, "Template instance `%s` creates a rvalue constructor for `struct %s`", + ti.toChars(), sd.toChars()); } } } @@ -6417,13 +6432,8 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc) ds.visibility = sc.visibility; ds.userAttribDecl = sc.userAttribDecl; - // TypeTraits needs to know if it's located in an AliasDeclaration - const oldflags = sc.flags; - sc.flags |= SCOPE.alias_; - void normalRet() { - sc.flags = oldflags; ds.inuse = 0; ds.semanticRun = PASS.semanticdone; diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index fb41e2b..ed0126e 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -2777,7 +2777,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, fd.storage_class == m.lastf.storage_class && fd.parent == m.lastf.parent && fd.visibility == m.lastf.visibility && - fd.linkage == m.lastf.linkage) + fd._linkage == m.lastf._linkage) { if (fd.fbody && !m.lastf.fbody) goto LfIsBetter; diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 41fb82b..55f7c72 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -82,7 +82,7 @@ extern(C++) void genCppHdrFiles(ref Modules ms) foreach (m; ms) m.accept(v); - if (global.params.doCxxHdrGeneration == CxxHeaderMode.verbose) + if (global.params.cxxhdr.fullOutput) buf.printf("// Automatically generated by %s Compiler v%d", global.vendor.ptr, global.versionNumber()); else buf.printf("// Automatically generated by %s Compiler", global.vendor.ptr); @@ -92,9 +92,9 @@ extern(C++) void genCppHdrFiles(ref Modules ms) buf.writestringln("#pragma once"); buf.writenl(); hashInclude(buf, "<assert.h>"); + hashInclude(buf, "<math.h>"); hashInclude(buf, "<stddef.h>"); hashInclude(buf, "<stdint.h>"); - hashInclude(buf, "<math.h>"); // buf.writestring(buf, "#include <stdio.h>\n"); // buf.writestring("#include <string.h>\n"); @@ -189,7 +189,7 @@ struct _d_dynamicArray final buf.remove(buf.length - 1, 1); - if (global.params.cxxhdrname is null) + if (global.params.cxxhdr.name is null) { // Write to stdout; assume it succeeds size_t n = fwrite(buf[].ptr, 1, buf.length, stdout); @@ -197,7 +197,7 @@ struct _d_dynamicArray final } else { - const(char)[] name = FileName.combine(global.params.cxxhdrdir, global.params.cxxhdrname); + const(char)[] name = FileName.combine(global.params.cxxhdr.dir, global.params.cxxhdr.name); writeFile(Loc.initial, name, buf[]); } } @@ -297,7 +297,7 @@ public: this.fwdbuf = fwdbuf; this.donebuf = donebuf; this.buf = buf; - this.printIgnored = global.params.doCxxHdrGeneration == CxxHeaderMode.verbose; + this.printIgnored = global.params.cxxhdr.fullOutput; } /** @@ -966,12 +966,13 @@ public: if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.gshared) || vd.parent && vd.parent.isModule()) { - if (vd.linkage != LINK.c && vd.linkage != LINK.cpp && !(tdparent && (this.linkage == LINK.c || this.linkage == LINK.cpp))) + const vdLinkage = vd.resolvedLinkage(); + if (vdLinkage != LINK.c && vdLinkage != LINK.cpp && !(tdparent && (this.linkage == LINK.c || this.linkage == LINK.cpp))) { ignored("variable %s because of linkage", vd.toPrettyChars()); return; } - if (vd.mangleOverride && vd.linkage != LINK.c) + if (vd.mangleOverride && vdLinkage != LINK.c) { ignored("variable %s because C++ doesn't support explicit mangling", vd.toPrettyChars()); return; @@ -987,7 +988,7 @@ public: return; } writeProtection(vd.visibility.kind); - if (vd.linkage == LINK.c) + if (vdLinkage == LINK.c) buf.writestring("extern \"C\" "); else if (!adparent) buf.writestring("extern "); @@ -2302,7 +2303,7 @@ public: this.forwarding = fwdStash; } - if (p.storageClass & AST.STC.ref_) + if (p.storageClass & (AST.STC.ref_ | AST.STC.out_)) buf.writeByte('&'); buf.writeByte(' '); if (ident) @@ -2805,7 +2806,10 @@ public: // Check against the internal information which might be missing, e.g. inside of template declarations if (auto dec = sym.isDeclaration()) - return dec.linkage == LINK.cpp || dec.linkage == LINK.c; + { + const l = dec.resolvedLinkage(); + return l == LINK.cpp || l == LINK.c; + } if (auto ad = sym.isAggregateDeclaration()) return ad.classKind == ClassKind.cpp; @@ -2853,8 +2857,11 @@ public: if (!res) { // Check against the internal information which might be missing, e.g. inside of template declarations - auto dec = sym.isDeclaration(); - res = dec && (dec.linkage == LINK.cpp || dec.linkage == LINK.c); + if (auto dec = sym.isDeclaration()) + { + const l = dec.resolvedLinkage(); + res = (l == LINK.cpp || l == LINK.c); + } } // Remember result for later calls diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 44c3757..3f41c29 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -280,13 +280,14 @@ bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag) * sc = used to determine current function and module * fdc = function being called, `null` if called indirectly * par = function parameter (`this` if null) + * parStc = storage classes of function parameter (may have added `scope` from `pure`) * arg = initializer for param * assertmsg = true if the parameter is the msg argument to assert(bool, msg). * gag = do not print error messages * Returns: * `true` if pointers to the stack can escape via assignment */ -bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Expression arg, bool assertmsg, bool gag) +bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC parStc, Expression arg, bool assertmsg, bool gag) { enum log = false; if (log) printf("checkParamArgumentEscape(arg: %s par: %s)\n", @@ -301,42 +302,38 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp escapeByValue(arg, &er); + if (parStc & STC.scope_) + { + // These errors only apply to non-scope parameters + // When the paraneter is `scope`, only `checkScopeVarAddr` on `er.byref` is needed + er.byfunc.setDim(0); + er.byvalue.setDim(0); + er.byexp.setDim(0); + } + if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim) return false; bool result = false; - ScopeRef psr; - if (par && fdc && fdc.type.isTypeFunction()) - psr = buildScopeRef(par.storageClass); - else - psr = ScopeRef.None; - /* 'v' is assigned unsafely to 'par' */ - void unsafeAssign(VarDeclaration v, const char* desc) + void unsafeAssign(string desc)(VarDeclaration v) { - if (setUnsafeDIP1000(sc.func)) + if (assertmsg) { - if (!gag) - { - if (assertmsg) - { - previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) - (arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`", - desc, v.toChars()); - } - else - { - previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) - (arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s", - desc, v.toChars(), - par ? par.toChars() : "this", - fdc ? fdc.toPrettyChars() : "indirectly"); - } - } - if (global.params.useDIP1000 == FeatureState.enabled) - result = true; + result |= sc.setUnsafeDIP1000(gag, arg.loc, + desc ~ " `%s` assigned to non-scope parameter calling `assert()`", v); + } + else if (par) + { + result |= sc.setUnsafeDIP1000(gag, arg.loc, + desc ~ " `%s` assigned to non-scope parameter `%s`", v, par); + } + else + { + result |= sc.setUnsafeDIP1000(gag, arg.loc, + desc ~ " `%s` assigned to non-scope parameter `this`", v); } } @@ -352,14 +349,14 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp if (v.isScope()) { - unsafeAssign(v, "scope variable"); + unsafeAssign!"scope variable"(v); } else if (v.storage_class & STC.variadic && p == sc.func) { Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { - unsafeAssign(v, "variadic variable"); + unsafeAssign!"variadic variable"(v); } } else @@ -382,17 +379,15 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp Dsymbol p = v.toParent2(); notMaybeScope(v); - - if (p == sc.func) + if (checkScopeVarAddr(v, arg, sc, gag)) { - if (psr == ScopeRef.Scope || - psr == ScopeRef.RefScope || - psr == ScopeRef.ReturnRef_Scope) - { - continue; - } + result = true; + continue; + } - unsafeAssign(v, "reference to local variable"); + if (p == sc.func && !(parStc & STC.scope_)) + { + unsafeAssign!"reference to local variable"(v); continue; } } @@ -414,21 +409,26 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp if ((v.isReference() || v.isScope()) && p == sc.func) { - unsafeAssign(v, "reference to local"); + unsafeAssign!"reference to local"(v); continue; } } } + if (!sc.func) + return result; + foreach (Expression ee; er.byexp) { - if (sc.func && sc.func.setUnsafe()) + if (!par) { - if (!gag) - error(ee.loc, "reference to stack allocated value returned by `%s` assigned to non-scope parameter `%s`", - ee.toChars(), - par ? par.toChars() : "this"); - result = true; + result |= sc.setUnsafeDIP1000(gag, ee.loc, + "reference to stack allocated value returned by `%s` assigned to non-scope parameter `this`", ee); + } + else + { + result |= sc.setUnsafeDIP1000(gag, ee.loc, + "reference to stack allocated value returned by `%s` assigned to non-scope parameter `%s`", ee, par); } } @@ -688,25 +688,25 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } } - if (va && va.isScope() && va.storage_class & STC.return_ && !(v.storage_class & STC.return_) && - fd.setUnsafe()) + if (va && va.isScope() && va.storage_class & STC.return_ && !(v.storage_class & STC.return_)) { // va may return its value, but v does not allow that, so this is an error - if (!gag) - error(ae.loc, "scope variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars()); - result = true; - continue; + if (sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to return scope `%s`", v, va)) + { + result = true; + continue; + } } // If va's lifetime encloses v's, then error if (va && !va.isDataseg() && - ((va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp)) || vaIsRef) && - fd.setUnsafe()) + ((va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp)) || vaIsRef)) { - if (!gag) - error(ae.loc, "scope variable `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars()); - result = true; - continue; + if (sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to `%s` with longer lifetime", v, va)) + { + result = true; + continue; + } } if (va && !va.isDataseg() && !va.doNotInferScope) @@ -733,12 +733,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } continue; } - if (fd.setUnsafe()) - { - if (!gag) - error(ae.loc, "scope variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars()); - result = true; - } + result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1); } else if (v.storage_class & STC.variadic && p == fd) { @@ -753,12 +748,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } continue; } - if (fd.setUnsafe()) - { - if (!gag) - error(ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars()); - result = true; - } + result |= sc.setUnsafeDIP1000(gag, ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v, e1); } } else @@ -777,27 +767,22 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (v.isDataseg()) continue; - if (global.params.useDIP1000 != FeatureState.disabled) + if (checkScopeVarAddr(v, ae, sc, gag)) { - if (va && va.isScope() && !v.isReference()) - { - if (!(va.storage_class & STC.return_)) - { - va.doNotInferReturn = true; - } - else if (setUnsafeDIP1000(fd)) - { - if (!gag) - previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) - (ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars()); - + result = true; + continue; + } - if (global.params.useDIP1000 == FeatureState.enabled) - { - result = true; - continue; - } - } + if (va && va.isScope() && !v.isReference()) + { + if (!(va.storage_class & STC.return_)) + { + va.doNotInferReturn = true; + } + else + { + result |= sc.setUnsafeDIP1000(gag, ae.loc, + "address of local variable `%s` assigned to return scope `%s`", v, va); } } @@ -815,19 +800,19 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) // If va's lifetime encloses v's, then error if (va && !(vaIsFirstRef && (v.storage_class & STC.return_)) && - (va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) && - fd.setUnsafe()) + (va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg())) { - if (!gag) - error(ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars()); - result = true; - continue; + if (sc.setUnsafeDIP1000(gag, ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v, va)) + { + result = true; + continue; + } } if (!(va && va.isScope())) notMaybeScope(v); - if ((global.params.useDIP1000 != FeatureState.enabled && v.isReference()) || p != sc.func) + if (p != sc.func) continue; if (va && !va.isDataseg() && !va.doNotInferScope) @@ -842,12 +827,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } if (e1.op == EXP.structLiteral) continue; - if (fd.setUnsafe()) - { - if (!gag) - error(ae.loc, "reference to local variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars()); - result = true; - } + + result |= sc.setUnsafeDIP1000(gag, ae.loc, "reference to local variable `%s` assigned to non-scope `%s`", v, e1); } foreach (FuncDeclaration func; er.byfunc) @@ -886,12 +867,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) //va.storage_class |= STC.scope_ | STC.scopeinferred; continue; } - if (fd.setUnsafe()) - { - if (!gag) - error(ae.loc, "reference to local `%s` assigned to non-scope `%s` in @safe code", v.toChars(), e1.toChars()); - result = true; - } + result |= sc.setUnsafeDIP1000(gag, ae.loc, + "reference to local `%s` assigned to non-scope `%s` in @safe code", v, e1); } } @@ -912,25 +889,23 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } if (ee.op == EXP.call && ee.type.toBasetype().isTypeStruct() && - (!va || !(va.storage_class & STC.temp)) && - fd.setUnsafe()) + (!va || !(va.storage_class & STC.temp))) { - if (!gag) - error(ee.loc, "address of struct temporary returned by `%s` assigned to longer lived variable `%s`", - ee.toChars(), e1.toChars()); - result = true; - continue; + if (sc.setUnsafeDIP1000(gag, ee.loc, "address of struct temporary returned by `%s` assigned to longer lived variable `%s`", ee, e1)) + { + result = true; + continue; + } } if (ee.op == EXP.structLiteral && - (!va || !(va.storage_class & STC.temp)) && - fd.setUnsafe()) + (!va || !(va.storage_class & STC.temp))) { - if (!gag) - error(ee.loc, "address of struct literal `%s` assigned to longer lived variable `%s`", - ee.toChars(), e1.toChars()); - result = true; - continue; + if (sc.setUnsafeDIP1000(gag, ee.loc, "address of struct literal `%s` assigned to longer lived variable `%s`", ee, e1)) + { + result = true; + continue; + } } if (va && !va.isDataseg() && !va.doNotInferScope) @@ -942,13 +917,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) continue; } - if (fd.setUnsafe()) - { - if (!gag) - error(ee.loc, "reference to stack allocated value returned by `%s` assigned to non-scope `%s`", - ee.toChars(), e1.toChars()); - result = true; - } + result |= sc.setUnsafeDIP1000(gag, ee.loc, + "reference to stack allocated value returned by `%s` assigned to non-scope `%s`", ee, e1); } return result; @@ -985,11 +955,8 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag) if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown // despite being `scope` { - if (!gag) - previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) - (e.loc, "scope variable `%s` may not be thrown", v.toChars()); - if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029 - result = true; + // https://issues.dlang.org/show_bug.cgi?id=17029 + result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be thrown", v); continue; } else @@ -1050,16 +1017,8 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) */ !(p.parent == sc.func)) { - if (setUnsafeDIP1000(sc.func)) // https://issues.dlang.org/show_bug.cgi?id=20868 - { - // Only look for errors if in module listed on command line - if (!gag) - previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) - (e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars()); - if (global.params.useDIP1000 == FeatureState.enabled) - result = true; - } - + // https://issues.dlang.org/show_bug.cgi?id=20868 + result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be copied into allocated memory", v); continue; } } @@ -1068,9 +1027,8 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { - if (!gag) - error(e.loc, "copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars()); - result = false; + result |= sc.setUnsafeDIP1000(gag, e.loc, + "copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e, v); } } else @@ -1085,16 +1043,13 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) if (log) printf("byref `%s`\n", v.toChars()); // 'featureState' tells us whether to emit an error or a deprecation, - // depending on the flag passed to the CLI for DIP25 - void escapingRef(VarDeclaration v, FeatureState featureState = FeatureState.enabled) + // depending on the flag passed to the CLI for DIP25 / DIP1000 + bool escapingRef(VarDeclaration v, FeatureState fs) { - if (!gag) - { - const(char)* kind = (v.storage_class & STC.parameter) ? "parameter" : "local"; - const(char)* msg = "copying `%s` into allocated memory escapes a reference to %s variable `%s`"; - previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), kind, v.toChars()); - } - result |= (featureState == FeatureState.enabled); + const(char)* msg = v.isParameter() ? + "copying `%s` into allocated memory escapes a reference to parameter `%s`" : + "copying `%s` into allocated memory escapes a reference to local variable `%s`"; + return sc.setUnsafePreview(fs, gag, e.loc, msg, e, v); } if (v.isDataseg()) @@ -1106,7 +1061,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) { if (p == sc.func) { - escapingRef(v); + result |= escapingRef(v, global.params.useDIP1000); continue; } } @@ -1122,7 +1077,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) { //printf("escaping reference to local ref variable %s\n", v.toChars()); //printf("storage class = x%llx\n", v.storage_class); - escapingRef(v, global.params.useDIP25); + result |= escapingRef(v, global.params.useDIP25); continue; } // Don't need to be concerned if v's parent does not return a ref @@ -1269,14 +1224,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) ) { // https://issues.dlang.org/show_bug.cgi?id=17029 - if (setUnsafeDIP1000(sc.func)) - { - if (!gag) - previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000) - (e.loc, "scope variable `%s` may not be returned", v.toChars()); - if (global.params.useDIP1000 == FeatureState.enabled) - result = true; - } + result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be returned", v); continue; } } @@ -1306,16 +1254,18 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) // 'featureState' tells us whether to emit an error or a deprecation, // depending on the flag passed to the CLI for DIP25 - void escapingRef(VarDeclaration v, ScopeRef vsr, FeatureState featureState = FeatureState.enabled) + void escapingRef(VarDeclaration v, FeatureState featureState) { - if (!gag) - { - const(char)* varKind = v.isParameter() ? "parameter" : "local variable"; - previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, - "returning `%s` escapes a reference to %s `%s`", e.toChars(), varKind, v.toChars()); + const(char)* msg = v.isParameter() ? + "returning `%s` escapes a reference to parameter `%s`" : + "returning `%s` escapes a reference to local variable `%s`"; - if (v.isParameter() && v.isReference()) + if (v.isParameter() && v.isReference()) + { + if (sc.setUnsafePreview(featureState, gag, e.loc, msg, e, v) || + sc.func.isSafeBypassingInference()) { + result = true; if (v.storage_class & STC.returnScope) { previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc, @@ -1329,7 +1279,12 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) } } } - result = true; + else + { + if (!gag) + previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars()); + result = true; + } } if (v.isDataseg()) @@ -1340,14 +1295,23 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) Dsymbol p = v.toParent2(); // https://issues.dlang.org/show_bug.cgi?id=19965 - if (!refs && sc.func.vthis == v) - notMaybeScope(v); + if (!refs) + { + if (sc.func.vthis == v) + notMaybeScope(v); + + if (checkScopeVarAddr(v, e, sc, gag)) + { + result = true; + continue; + } + } if (!v.isReference()) { if (p == sc.func) { - escapingRef(v, vsr, FeatureState.enabled); + escapingRef(v, FeatureState.enabled); continue; } FuncDeclaration fd = p.isFuncDeclaration(); @@ -1388,7 +1352,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { //printf("escaping reference to local ref variable %s\n", v.toChars()); //printf("storage class = x%llx\n", v.storage_class); - escapingRef(v, vsr, global.params.useDIP25); + escapingRef(v, global.params.useDIP25); continue; } // Don't need to be concerned if v's parent does not return a ref @@ -1489,370 +1453,385 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope) void escapeByValue(Expression e, EscapeByResults* er, bool live = false) { //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars()); - extern (C++) final class EscapeVisitor : Visitor - { - alias visit = Visitor.visit; - public: - EscapeByResults* er; - bool live; - - extern (D) this(EscapeByResults* er, bool live) - { - this.er = er; - this.live = live; - } - override void visit(Expression e) - { - } + void visit(Expression e) + { + } - override void visit(AddrExp e) - { - /* Taking the address of struct literal is normally not - * allowed, but CTFE can generate one out of a new expression, - * but it'll be placed in static data so no need to check it. - */ - if (e.e1.op != EXP.structLiteral) - escapeByRef(e.e1, er, live); - } + void visitAddr(AddrExp e) + { + /* Taking the address of struct literal is normally not + * allowed, but CTFE can generate one out of a new expression, + * but it'll be placed in static data so no need to check it. + */ + if (e.e1.op != EXP.structLiteral) + escapeByRef(e.e1, er, live); + } - override void visit(SymOffExp e) - { - VarDeclaration v = e.var.isVarDeclaration(); - if (v) - er.byref.push(v); - } + void visitSymOff(SymOffExp e) + { + VarDeclaration v = e.var.isVarDeclaration(); + if (v) + er.byref.push(v); + } - override void visit(VarExp e) + void visitVar(VarExp e) + { + if (auto v = e.var.isVarDeclaration()) { - if (auto v = e.var.isVarDeclaration()) - { - if (v.type.hasPointers() || // not tracking non-pointers - v.storage_class & STC.lazy_) // lazy variables are actually pointers - er.byvalue.push(v); - } + if (v.type.hasPointers() || // not tracking non-pointers + v.storage_class & STC.lazy_) // lazy variables are actually pointers + er.byvalue.push(v); } + } - override void visit(ThisExp e) - { - if (e.var) - er.byvalue.push(e.var); - } + void visitThis(ThisExp e) + { + if (e.var) + er.byvalue.push(e.var); + } - override void visit(PtrExp e) - { - if (live && e.type.hasPointers()) - e.e1.accept(this); - } + void visitPtr(PtrExp e) + { + if (live && e.type.hasPointers()) + escapeByValue(e.e1, er, live); + } - override void visit(DotVarExp e) + void visitDotVar(DotVarExp e) + { + auto t = e.e1.type.toBasetype(); + if (e.type.hasPointers() && (live || t.ty == Tstruct)) { - auto t = e.e1.type.toBasetype(); - if (e.type.hasPointers() && (live || t.ty == Tstruct)) - { - e.e1.accept(this); - } + escapeByValue(e.e1, er, live); } + } - override void visit(DelegateExp e) - { - Type t = e.e1.type.toBasetype(); - if (t.ty == Tclass || t.ty == Tpointer) - escapeByValue(e.e1, er, live); - else - escapeByRef(e.e1, er, live); - er.byfunc.push(e.func); - } + void visitDelegate(DelegateExp e) + { + Type t = e.e1.type.toBasetype(); + if (t.ty == Tclass || t.ty == Tpointer) + escapeByValue(e.e1, er, live); + else + escapeByRef(e.e1, er, live); + er.byfunc.push(e.func); + } - override void visit(FuncExp e) - { - if (e.fd.tok == TOK.delegate_) - er.byfunc.push(e.fd); - } + void visitFunc(FuncExp e) + { + if (e.fd.tok == TOK.delegate_) + er.byfunc.push(e.fd); + } - override void visit(TupleExp e) - { - assert(0); // should have been lowered by now - } + void visitTuple(TupleExp e) + { + assert(0); // should have been lowered by now + } - override void visit(ArrayLiteralExp e) + void visitArrayLiteral(ArrayLiteralExp e) + { + Type tb = e.type.toBasetype(); + if (tb.ty == Tsarray || tb.ty == Tarray) { - Type tb = e.type.toBasetype(); - if (tb.ty == Tsarray || tb.ty == Tarray) + if (e.basis) + escapeByValue(e.basis, er, live); + foreach (el; *e.elements) { - if (e.basis) - e.basis.accept(this); - foreach (el; *e.elements) - { - if (el) - el.accept(this); - } + if (el) + escapeByValue(el, er, live); } } + } - override void visit(StructLiteralExp e) + void visitStructLiteral(StructLiteralExp e) + { + if (e.elements) { - if (e.elements) + foreach (ex; *e.elements) { - foreach (ex; *e.elements) - { - if (ex) - ex.accept(this); - } + if (ex) + escapeByValue(ex, er, live); } } + } - override void visit(NewExp e) + void visitNew(NewExp e) + { + Type tb = e.newtype.toBasetype(); + if (tb.ty == Tstruct && !e.member && e.arguments) { - Type tb = e.newtype.toBasetype(); - if (tb.ty == Tstruct && !e.member && e.arguments) + foreach (ex; *e.arguments) { - foreach (ex; *e.arguments) - { - if (ex) - ex.accept(this); - } + if (ex) + escapeByValue(ex, er, live); } } + } - override void visit(CastExp e) + void visitCast(CastExp e) + { + if (!e.type.hasPointers()) + return; + Type tb = e.type.toBasetype(); + if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray) { - if (!e.type.hasPointers()) - return; - Type tb = e.type.toBasetype(); - if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray) - { - escapeByRef(e.e1, er, live); - } - else - e.e1.accept(this); + escapeByRef(e.e1, er, live); } + else + escapeByValue(e.e1, er, live); + } - override void visit(SliceExp e) + void visitSlice(SliceExp e) + { + if (auto ve = e.e1.isVarExp()) { - if (auto ve = e.e1.isVarExp()) + VarDeclaration v = ve.var.isVarDeclaration(); + Type tb = e.type.toBasetype(); + if (v) { - VarDeclaration v = ve.var.isVarDeclaration(); - Type tb = e.type.toBasetype(); - if (v) + if (tb.ty == Tsarray) + return; + if (v.storage_class & STC.variadic) { - if (tb.ty == Tsarray) - return; - if (v.storage_class & STC.variadic) - { - er.byvalue.push(v); - return; - } + er.byvalue.push(v); + return; } } - Type t1b = e.e1.type.toBasetype(); - if (t1b.ty == Tsarray) - { - Type tb = e.type.toBasetype(); - if (tb.ty != Tsarray) - escapeByRef(e.e1, er, live); - } - else - e.e1.accept(this); } - - override void visit(IndexExp e) - { - if (e.e1.type.toBasetype().ty == Tsarray || - live && e.type.hasPointers()) - { - e.e1.accept(this); - } - } - - override void visit(BinExp e) + Type t1b = e.e1.type.toBasetype(); + if (t1b.ty == Tsarray) { Type tb = e.type.toBasetype(); - if (tb.ty == Tpointer) - { - e.e1.accept(this); - e.e2.accept(this); - } + if (tb.ty != Tsarray) + escapeByRef(e.e1, er, live); } + else + escapeByValue(e.e1, er, live); + } - override void visit(BinAssignExp e) + void visitIndex(IndexExp e) + { + if (e.e1.type.toBasetype().ty == Tsarray || + live && e.type.hasPointers()) { - e.e1.accept(this); + escapeByValue(e.e1, er, live); } + } - override void visit(AssignExp e) + void visitBin(BinExp e) + { + Type tb = e.type.toBasetype(); + if (tb.ty == Tpointer) { - e.e1.accept(this); + escapeByValue(e.e1, er, live); + escapeByValue(e.e2, er, live); } + } - override void visit(CommaExp e) - { - e.e2.accept(this); - } + void visitBinAssign(BinAssignExp e) + { + escapeByValue(e.e1, er, live); + } + + void visitAssign(AssignExp e) + { + escapeByValue(e.e1, er, live); + } - override void visit(CondExp e) + void visitComma(CommaExp e) + { + escapeByValue(e.e2, er, live); + } + + void visitCond(CondExp e) + { + escapeByValue(e.e1, er, live); + escapeByValue(e.e2, er, live); + } + + void visitCall(CallExp e) + { + //printf("CallExp(): %s\n", e.toChars()); + /* Check each argument that is + * passed as 'return scope'. + */ + Type t1 = e.e1.type.toBasetype(); + TypeFunction tf; + TypeDelegate dg; + if (t1.ty == Tdelegate) { - e.e1.accept(this); - e.e2.accept(this); + dg = t1.isTypeDelegate(); + tf = dg.next.isTypeFunction(); } + else if (t1.ty == Tfunction) + tf = t1.isTypeFunction(); + else + return; + + if (!e.type.hasPointers()) + return; - override void visit(CallExp e) + if (e.arguments && e.arguments.dim) { - //printf("CallExp(): %s\n", e.toChars()); - /* Check each argument that is - * passed as 'return scope'. + /* j=1 if _arguments[] is first argument, + * skip it because it is not passed by ref */ - Type t1 = e.e1.type.toBasetype(); - TypeFunction tf; - TypeDelegate dg; - if (t1.ty == Tdelegate) + int j = tf.isDstyleVariadic(); + for (size_t i = j; i < e.arguments.dim; ++i) { - dg = t1.isTypeDelegate(); - tf = dg.next.isTypeFunction(); - } - else if (t1.ty == Tfunction) - tf = t1.isTypeFunction(); - else - return; - - if (!e.type.hasPointers()) - return; - - if (e.arguments && e.arguments.dim) - { - /* j=1 if _arguments[] is first argument, - * skip it because it is not passed by ref - */ - int j = tf.isDstyleVariadic(); - for (size_t i = j; i < e.arguments.dim; ++i) + Expression arg = (*e.arguments)[i]; + size_t nparams = tf.parameterList.length; + if (i - j < nparams && i >= j) { - Expression arg = (*e.arguments)[i]; - size_t nparams = tf.parameterList.length; - if (i - j < nparams && i >= j) + Parameter p = tf.parameterList[i - j]; + const stc = tf.parameterStorageClass(null, p); + ScopeRef psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) + escapeByValue(arg, er, live); + else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) { - Parameter p = tf.parameterList[i - j]; - const stc = tf.parameterStorageClass(null, p); - ScopeRef psr = buildScopeRef(stc); - if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - arg.accept(this); - else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) + if (tf.isref) { - if (tf.isref) - { - /* Treat: - * ref P foo(return ref P p) - * as: - * p; - */ - arg.accept(this); - } - else - escapeByRef(arg, er, live); + /* Treat: + * ref P foo(return ref P p) + * as: + * p; + */ + escapeByValue(arg, er, live); } + else + escapeByRef(arg, er, live); } } } - // If 'this' is returned, check it too - if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) + } + // If 'this' is returned, check it too + if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) + { + DotVarExp dve = e.e1.isDotVarExp(); + FuncDeclaration fd = dve.var.isFuncDeclaration(); + if (global.params.useDIP1000 == FeatureState.enabled) { - DotVarExp dve = e.e1.isDotVarExp(); - FuncDeclaration fd = dve.var.isFuncDeclaration(); - if (global.params.useDIP1000 == FeatureState.enabled) + if (fd && fd.isThis()) { - if (fd && fd.isThis()) - { - /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this` - */ - - /***************************** - * Concoct storage class for member function's implicit `this` parameter. - * Params: - * fd = member function - * Returns: - * storage class for fd's `this` - */ - StorageClass getThisStorageClass(FuncDeclaration fd) - { - StorageClass stc; - auto tf = fd.type.toBasetype().isTypeFunction(); - if (tf.isreturn) - stc |= STC.return_; - if (tf.isreturnscope) - stc |= STC.returnScope; - auto ad = fd.isThis(); - if (ad.isClassDeclaration() || tf.isScopeQual) - stc |= STC.scope_; - if (ad.isStructDeclaration()) - stc |= STC.ref_; // `this` for a struct member function is passed by `ref` - return stc; - } + /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this` + */ - const psr = buildScopeRef(getThisStorageClass(fd)); - if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - dve.e1.accept(this); - else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) - { - if (tf.isref) - { - /* Treat calling: - * struct S { ref S foo() return; } - * as: - * this; - */ - dve.e1.accept(this); - } - else - escapeByRef(dve.e1, er, live); - } + /***************************** + * Concoct storage class for member function's implicit `this` parameter. + * Params: + * fd = member function + * Returns: + * storage class for fd's `this` + */ + StorageClass getThisStorageClass(FuncDeclaration fd) + { + StorageClass stc; + auto tf = fd.type.toBasetype().isTypeFunction(); + if (tf.isreturn) + stc |= STC.return_; + if (tf.isreturnscope) + stc |= STC.returnScope; + auto ad = fd.isThis(); + if (ad.isClassDeclaration() || tf.isScopeQual) + stc |= STC.scope_; + if (ad.isStructDeclaration()) + stc |= STC.ref_; // `this` for a struct member function is passed by `ref` + return stc; } - } - else - { - // Calling member function before dip1000 - StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_); - if (tf.isreturn) - stc |= STC.return_; - const psr = buildScopeRef(stc); + const psr = buildScopeRef(getThisStorageClass(fd)); if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - dve.e1.accept(this); + escapeByValue(dve.e1, er, live); else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) - escapeByRef(dve.e1, er, live); + { + if (tf.isref) + { + /* Treat calling: + * struct S { ref S foo() return; } + * as: + * this; + */ + escapeByValue(dve.e1, er, live); + } + else + escapeByRef(dve.e1, er, live); + } } + } + else + { + // Calling member function before dip1000 + StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_); + if (tf.isreturn) + stc |= STC.return_; - // If it's also a nested function that is 'return scope' - if (fd && fd.isNested()) - { - if (tf.isreturn && tf.isScopeQual) - er.byexp.push(e); - } + const psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) + escapeByValue(dve.e1, er, live); + else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) + escapeByRef(dve.e1, er, live); } - /* If returning the result of a delegate call, the .ptr - * field of the delegate must be checked. - */ - if (dg) + // If it's also a nested function that is 'return scope' + if (fd && fd.isNested()) { - if (tf.isreturn) - e.e1.accept(this); + if (tf.isreturn && tf.isScopeQual) + er.byexp.push(e); } + } - /* If it's a nested function that is 'return scope' - */ - if (auto ve = e.e1.isVarExp()) + /* If returning the result of a delegate call, the .ptr + * field of the delegate must be checked. + */ + if (dg) + { + if (tf.isreturn) + escapeByValue(e.e1, er, live); + } + + /* If it's a nested function that is 'return scope' + */ + if (auto ve = e.e1.isVarExp()) + { + FuncDeclaration fd = ve.var.isFuncDeclaration(); + if (fd && fd.isNested()) { - FuncDeclaration fd = ve.var.isFuncDeclaration(); - if (fd && fd.isNested()) - { - if (tf.isreturn && tf.isScopeQual) - er.byexp.push(e); - } + if (tf.isreturn && tf.isScopeQual) + er.byexp.push(e); } } } - scope EscapeVisitor v = new EscapeVisitor(er, live); - e.accept(v); + switch (e.op) + { + case EXP.address: return visitAddr(e.isAddrExp()); + case EXP.symbolOffset: return visitSymOff(e.isSymOffExp()); + case EXP.variable: return visitVar(e.isVarExp()); + case EXP.this_: return visitThis(e.isThisExp()); + case EXP.star: return visitPtr(e.isPtrExp()); + case EXP.dotVariable: return visitDotVar(e.isDotVarExp()); + case EXP.delegate_: return visitDelegate(e.isDelegateExp()); + case EXP.function_: return visitFunc(e.isFuncExp()); + case EXP.tuple: return visitTuple(e.isTupleExp()); + case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp()); + case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp()); + case EXP.new_: return visitNew(e.isNewExp()); + case EXP.cast_: return visitCast(e.isCastExp()); + case EXP.slice: return visitSlice(e.isSliceExp()); + case EXP.index: return visitIndex(e.isIndexExp()); + case EXP.blit: return visitAssign(e.isBlitExp()); + case EXP.construct: return visitAssign(e.isConstructExp()); + case EXP.assign: return visitAssign(e.isAssignExp()); + case EXP.comma: return visitComma(e.isCommaExp()); + case EXP.question: return visitCond(e.isCondExp()); + case EXP.call: return visitCall(e.isCallExp()); + default: + if (auto b = e.isBinExp()) + return visitBin(b); + if (auto ba = e.isBinAssignExp()) + return visitBinAssign(ba); + return visit(e); + } } @@ -1877,236 +1856,239 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) void escapeByRef(Expression e, EscapeByResults* er, bool live = false) { //printf("[%s] escapeByRef, e: %s\n", e.loc.toChars(), e.toChars()); - extern (C++) final class EscapeRefVisitor : Visitor + void visit(Expression e) { - alias visit = Visitor.visit; - public: - EscapeByResults* er; - bool live; - - extern (D) this(EscapeByResults* er, bool live) - { - this.er = er; - this.live = live; - } - - override void visit(Expression e) - { - } + } - override void visit(VarExp e) + void visitVar(VarExp e) + { + auto v = e.var.isVarDeclaration(); + if (v) { - auto v = e.var.isVarDeclaration(); - if (v) + if (v.storage_class & STC.ref_ && v.storage_class & (STC.foreach_ | STC.temp) && v._init) { - if (v.storage_class & STC.ref_ && v.storage_class & (STC.foreach_ | STC.temp) && v._init) + /* If compiler generated ref temporary + * (ref v = ex; ex) + * look at the initializer instead + */ + if (ExpInitializer ez = v._init.isExpInitializer()) { - /* If compiler generated ref temporary - * (ref v = ex; ex) - * look at the initializer instead - */ - if (ExpInitializer ez = v._init.isExpInitializer()) - { - if (auto ce = ez.exp.isConstructExp()) - ce.e2.accept(this); - else - ez.exp.accept(this); - } + if (auto ce = ez.exp.isConstructExp()) + escapeByRef(ce.e2, er, live); + else + escapeByRef(ez.exp, er, live); } - else - er.byref.push(v); } + else + er.byref.push(v); } + } - override void visit(ThisExp e) - { - if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext()) - escapeByValue(e, er, live); - else if (e.var) - er.byref.push(e.var); - } + void visitThis(ThisExp e) + { + if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext()) + escapeByValue(e, er, live); + else if (e.var) + er.byref.push(e.var); + } - override void visit(PtrExp e) - { - escapeByValue(e.e1, er, live); - } + void visitPtr(PtrExp e) + { + escapeByValue(e.e1, er, live); + } - override void visit(IndexExp e) + void visitIndex(IndexExp e) + { + Type tb = e.e1.type.toBasetype(); + if (auto ve = e.e1.isVarExp()) { - Type tb = e.e1.type.toBasetype(); - if (auto ve = e.e1.isVarExp()) + VarDeclaration v = ve.var.isVarDeclaration(); + if (tb.ty == Tarray || tb.ty == Tsarray) { - VarDeclaration v = ve.var.isVarDeclaration(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (v && v.storage_class & STC.variadic) { - if (v && v.storage_class & STC.variadic) - { - er.byref.push(v); - return; - } + er.byref.push(v); + return; } } - if (tb.ty == Tsarray) - { - e.e1.accept(this); - } - else if (tb.ty == Tarray) - { - escapeByValue(e.e1, er, live); - } } - - override void visit(StructLiteralExp e) + if (tb.ty == Tsarray) { - if (e.elements) - { - foreach (ex; *e.elements) - { - if (ex) - ex.accept(this); - } - } - er.byexp.push(e); + escapeByRef(e.e1, er, live); } - - override void visit(DotVarExp e) + else if (tb.ty == Tarray) { - Type t1b = e.e1.type.toBasetype(); - if (t1b.ty == Tclass) - escapeByValue(e.e1, er, live); - else - e.e1.accept(this); + escapeByValue(e.e1, er, live); } + } - override void visit(BinAssignExp e) + void visitStructLiteral(StructLiteralExp e) + { + if (e.elements) { - e.e1.accept(this); + foreach (ex; *e.elements) + { + if (ex) + escapeByRef(ex, er, live); + } } + er.byexp.push(e); + } - override void visit(AssignExp e) - { - e.e1.accept(this); - } + void visitDotVar(DotVarExp e) + { + Type t1b = e.e1.type.toBasetype(); + if (t1b.ty == Tclass) + escapeByValue(e.e1, er, live); + else + escapeByRef(e.e1, er, live); + } - override void visit(CommaExp e) - { - e.e2.accept(this); - } + void visitBinAssign(BinAssignExp e) + { + escapeByRef(e.e1, er, live); + } - override void visit(CondExp e) - { - e.e1.accept(this); - e.e2.accept(this); - } + void visitAssign(AssignExp e) + { + escapeByRef(e.e1, er, live); + } - override void visit(CallExp e) + void visitComma(CommaExp e) + { + escapeByRef(e.e2, er, live); + } + + void visitCond(CondExp e) + { + escapeByRef(e.e1, er, live); + escapeByRef(e.e2, er, live); + } + + void visitCall(CallExp e) + { + //printf("escapeByRef.CallExp(): %s\n", e.toChars()); + /* If the function returns by ref, check each argument that is + * passed as 'return ref'. + */ + Type t1 = e.e1.type.toBasetype(); + TypeFunction tf; + if (t1.ty == Tdelegate) + tf = t1.isTypeDelegate().next.isTypeFunction(); + else if (t1.ty == Tfunction) + tf = t1.isTypeFunction(); + else + return; + if (tf.isref) { - //printf("escapeByRef.CallExp(): %s\n", e.toChars()); - /* If the function returns by ref, check each argument that is - * passed as 'return ref'. - */ - Type t1 = e.e1.type.toBasetype(); - TypeFunction tf; - if (t1.ty == Tdelegate) - tf = t1.isTypeDelegate().next.isTypeFunction(); - else if (t1.ty == Tfunction) - tf = t1.isTypeFunction(); - else - return; - if (tf.isref) + if (e.arguments && e.arguments.dim) { - if (e.arguments && e.arguments.dim) + /* j=1 if _arguments[] is first argument, + * skip it because it is not passed by ref + */ + int j = tf.isDstyleVariadic(); + for (size_t i = j; i < e.arguments.dim; ++i) { - /* j=1 if _arguments[] is first argument, - * skip it because it is not passed by ref - */ - int j = tf.isDstyleVariadic(); - for (size_t i = j; i < e.arguments.dim; ++i) + Expression arg = (*e.arguments)[i]; + size_t nparams = tf.parameterList.length; + if (i - j < nparams && i >= j) { - Expression arg = (*e.arguments)[i]; - size_t nparams = tf.parameterList.length; - if (i - j < nparams && i >= j) + Parameter p = tf.parameterList[i - j]; + const stc = tf.parameterStorageClass(null, p); + ScopeRef psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) + escapeByRef(arg, er, live); + else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) { - Parameter p = tf.parameterList[i - j]; - const stc = tf.parameterStorageClass(null, p); - ScopeRef psr = buildScopeRef(stc); - if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) - arg.accept(this); - else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) + if (auto de = arg.isDelegateExp()) { - if (auto de = arg.isDelegateExp()) - { - if (de.func.isNested()) - er.byexp.push(de); - } - else - escapeByValue(arg, er, live); + if (de.func.isNested()) + er.byexp.push(de); } + else + escapeByValue(arg, er, live); } } } - // If 'this' is returned by ref, check it too - if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) + } + // If 'this' is returned by ref, check it too + if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction) + { + DotVarExp dve = e.e1.isDotVarExp(); + + // https://issues.dlang.org/show_bug.cgi?id=20149#c10 + if (dve.var.isCtorDeclaration()) { - DotVarExp dve = e.e1.isDotVarExp(); + er.byexp.push(e); + return; + } - // https://issues.dlang.org/show_bug.cgi?id=20149#c10 - if (dve.var.isCtorDeclaration()) - { - er.byexp.push(e); - return; - } + StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_); + if (tf.isreturn) + stc |= STC.return_; + if (tf.isref) + stc |= STC.ref_; + if (tf.isScopeQual) + stc |= STC.scope_; + if (tf.isreturnscope) + stc |= STC.returnScope; + + const psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) + escapeByRef(dve.e1, er, live); + else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) + escapeByValue(dve.e1, er, live); - StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_); - if (tf.isreturn) - stc |= STC.return_; - if (tf.isref) - stc |= STC.ref_; - if (tf.isScopeQual) - stc |= STC.scope_; - if (tf.isreturnscope) - stc |= STC.returnScope; - - const psr = buildScopeRef(stc); - if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) - dve.e1.accept(this); - else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - escapeByValue(dve.e1, er, live); - - // If it's also a nested function that is 'return ref' - if (FuncDeclaration fd = dve.var.isFuncDeclaration()) + // If it's also a nested function that is 'return ref' + if (FuncDeclaration fd = dve.var.isFuncDeclaration()) + { + if (fd.isNested() && tf.isreturn) { - if (fd.isNested() && tf.isreturn) - { - er.byexp.push(e); - } + er.byexp.push(e); } } - // If it's a delegate, check it too - if (e.e1.op == EXP.variable && t1.ty == Tdelegate) - { - escapeByValue(e.e1, er, live); - } + } + // If it's a delegate, check it too + if (e.e1.op == EXP.variable && t1.ty == Tdelegate) + { + escapeByValue(e.e1, er, live); + } - /* If it's a nested function that is 'return ref' - */ - if (auto ve = e.e1.isVarExp()) + /* If it's a nested function that is 'return ref' + */ + if (auto ve = e.e1.isVarExp()) + { + FuncDeclaration fd = ve.var.isFuncDeclaration(); + if (fd && fd.isNested()) { - FuncDeclaration fd = ve.var.isFuncDeclaration(); - if (fd && fd.isNested()) - { - if (tf.isreturn) - er.byexp.push(e); - } + if (tf.isreturn) + er.byexp.push(e); } } - else - er.byexp.push(e); } + else + er.byexp.push(e); } - scope EscapeRefVisitor v = new EscapeRefVisitor(er, live); - e.accept(v); + switch (e.op) + { + case EXP.variable: return visitVar(e.isVarExp()); + case EXP.this_: return visitThis(e.isThisExp()); + case EXP.star: return visitPtr(e.isPtrExp()); + case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp()); + case EXP.dotVariable: return visitDotVar(e.isDotVarExp()); + case EXP.index: return visitIndex(e.isIndexExp()); + case EXP.blit: return visitAssign(e.isBlitExp()); + case EXP.construct: return visitAssign(e.isConstructExp()); + case EXP.assign: return visitAssign(e.isAssignExp()); + case EXP.comma: return visitComma(e.isCommaExp()); + case EXP.question: return visitCond(e.isCondExp()); + case EXP.call: return visitCall(e.isCallExp()); + default: + if (auto ba = e.isBinAssignExp()) + return visitBinAssign(ba); + return visit(e); + } } @@ -2170,7 +2152,7 @@ public void findAllOuterAccessedVariables(FuncDeclaration fd, VarDeclarations* v */ version (none) { - public void notMaybeScope(string file = __FILE__, int line = __LINE__)(VarDeclaration v) + private void notMaybeScope(string file = __FILE__, int line = __LINE__)(VarDeclaration v) { printf("%.*s(%d): notMaybeScope('%s')\n", cast(int)file.length, file.ptr, line, v.toChars()); v.storage_class &= ~STC.maybescope; @@ -2178,12 +2160,88 @@ version (none) } else { - public void notMaybeScope(VarDeclaration v) + private void notMaybeScope(VarDeclaration v) { v.storage_class &= ~STC.maybescope; } } +/*********************************** + * After semantic analysis of the function body, + * try to infer `scope` / `return` on the parameters + * + * Params: + * funcdecl = function declaration that was analyzed + * f = final function type. `funcdecl.type` started as the 'premature type' before attribute + * inference, then its inferred attributes are copied over to final type `f` + */ +void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) +{ + if (funcdecl.flags & FUNCFLAG.returnInprocess) + { + funcdecl.flags &= ~FUNCFLAG.returnInprocess; + if (funcdecl.storage_class & STC.return_) + { + if (funcdecl.type == f) + f = cast(TypeFunction)f.copy(); + f.isreturn = true; + f.isreturnscope = cast(bool) (funcdecl.storage_class & STC.returnScope); + if (funcdecl.storage_class & STC.returninferred) + f.isreturninferred = true; + } + } + + funcdecl.flags &= ~FUNCFLAG.inferScope; + + // Eliminate maybescope's + { + // Create and fill array[] with maybe candidates from the `this` and the parameters + VarDeclaration[10] tmp = void; + size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.dim : 0); + + import dmd.common.string : SmallBuffer; + auto sb = SmallBuffer!VarDeclaration(dim, tmp[]); + VarDeclaration[] array = sb[]; + + size_t n = 0; + if (funcdecl.vthis) + array[n++] = funcdecl.vthis; + if (funcdecl.parameters) + { + foreach (v; *funcdecl.parameters) + { + array[n++] = v; + } + } + eliminateMaybeScopes(array[0 .. n]); + } + + // Infer STC.scope_ + if (funcdecl.parameters && !funcdecl.errors) + { + assert(f.parameterList.length == funcdecl.parameters.dim); + foreach (u, p; f.parameterList) + { + auto v = (*funcdecl.parameters)[u]; + if (v.storage_class & STC.maybescope) + { + //printf("Inferring scope for %s\n", v.toChars()); + notMaybeScope(v); + v.storage_class |= STC.scope_ | STC.scopeinferred; + p.storageClass |= STC.scope_ | STC.scopeinferred; + assert(!(p.storageClass & STC.maybescope)); + } + } + } + + if (funcdecl.vthis && funcdecl.vthis.storage_class & STC.maybescope) + { + notMaybeScope(funcdecl.vthis); + funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred; + f.isScopeQual = true; + f.isscopeinferred = true; + } +} /********************************************** * Have some variables that are maybescopes that were @@ -2207,7 +2265,7 @@ else * Params: * array = array of variables that were assigned to from maybescope variables */ -public void eliminateMaybeScopes(VarDeclaration[] array) +private void eliminateMaybeScopes(VarDeclaration[] array) { enum log = false; if (log) printf("eliminateMaybeScopes()\n"); @@ -2355,10 +2413,89 @@ private void addMaybe(VarDeclaration va, VarDeclaration v) va.maybes.push(v); } +/*************************************** + * Like `FuncDeclaration.setUnsafe`, but modified for dip25 / dip1000 by default transitions + * + * With `-preview=dip1000` it actually sets the function as unsafe / prints an error, while + * without it, it only prints a deprecation in a `@safe` function. + * With `-revert=preview=dip1000`, it doesn't do anything. + * + * Params: + * sc = used for checking whether we are in a deprecated scope + * fs = command line setting of dip1000 / dip25 + * gag = surpress error message + * loc = location of error + * fmt = printf-style format string + * arg0 = (optional) argument for first %s format specifier + * arg1 = (optional) argument for second %s format specifier + * Returns: whether an actual safe error (not deprecation) occured + */ +private bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg, RootObject arg0 = null, RootObject arg1 = null) +{ + if (fs == FeatureState.disabled) + { + return false; + } + else if (fs == FeatureState.enabled) + { + return sc.func.setUnsafe(gag, loc, msg, arg0, arg1); + } + else + { + if (sc.func.isSafeBypassingInference()) + { + if (!gag) + previewErrorFunc(sc.isDeprecated(), fs)( + loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "" + ); + } + return false; + } +} + +// `setUnsafePreview` partially evaluated for dip1000 +private bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg, RootObject arg0 = null, RootObject arg1 = null) +{ + return setUnsafePreview(sc, global.params.useDIP1000, gag, loc, msg, arg0, arg1); +} -private bool setUnsafeDIP1000(FuncDeclaration f) +/*************************************** + * Check that taking the address of `v` is `@safe` + * + * It's not possible to take the address of a scope variable, because `scope` only applies + * to the top level indirection. + * + * Params: + * v = variable that a reference is created + * e = expression that takes the referene + * sc = used to obtain function / deprecated status + * gag = don't print errors + * Returns: + * true if taking the address of `v` is problematic because of the lack of transitive `scope` + */ +private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool gag) { - return global.params.useDIP1000 == FeatureState.enabled - ? f.setUnsafe() - : f.isSafeBypassingInference(); + if (v.storage_class & STC.temp) + return false; + + if (!v.isScope()) + { + v.storage_class &= ~STC.maybescope; + v.doNotInferScope = true; + return false; + } + + if (!e.type) + return false; + + // When the type after dereferencing has no pointers, it's okay. + // Comes up when escaping `&someStruct.intMember` of a `scope` struct: + // scope does not apply to the `int` + Type t = e.type.baseElemOf(); + if ((t.ty == Tarray || t.ty == Tpointer) && !t.nextOf().toBasetype().hasPointers()) + return false; + + // take address of `scope` variable not allowed, requires transitive scope + return sc.setUnsafeDIP1000(gag, e.loc, + "cannot take address of `scope` variable `%s` since `scope` applies to first indirection only", v); } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 107e85b..0872356 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -1370,10 +1370,9 @@ extern (C++) abstract class Expression : ASTNode */ if (v.storage_class & STC.gshared) { - if (sc.func.setUnsafe()) + if (sc.func.setUnsafe(false, this.loc, + "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v)) { - error("`@safe` %s `%s` cannot access `__gshared` data `%s`", - sc.func.kind(), sc.func.toChars(), v.toChars()); err = true; } } @@ -1411,7 +1410,7 @@ extern (C++) abstract class Expression : ASTNode if (!f.isSafe() && !f.isTrusted()) { - if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe()) + if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f)) { if (!loc.isValid()) // e.g. implicitly generated dtor loc = sc.func.loc; @@ -1420,6 +1419,7 @@ extern (C++) abstract class Expression : ASTNode error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), prettyChars); + f.errorSupplementalInferredSafety(/*max depth*/ 10); .errorSupplemental(f.loc, "`%s` is declared here", prettyChars); checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system"); @@ -1456,7 +1456,8 @@ extern (C++) abstract class Expression : ASTNode // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)), // so don't print anything to avoid double error messages. - if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT)) + if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT + || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX)) error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); @@ -5760,9 +5761,8 @@ extern (C++) final class DelegatePtrExp : UnaExp override Expression modifiableLvalue(Scope* sc, Expression e) { - if (sc.func.setUnsafe()) + if (sc.func.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this)) { - error("cannot modify delegate pointer in `@safe` code `%s`", toChars()); return ErrorExp.get(); } return Expression.modifiableLvalue(sc, e); @@ -5799,9 +5799,8 @@ extern (C++) final class DelegateFuncptrExp : UnaExp override Expression modifiableLvalue(Scope* sc, Expression e) { - if (sc.func.setUnsafe()) + if (sc.func.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this)) { - error("cannot modify delegate function pointer in `@safe` code `%s`", toChars()); return ErrorExp.get(); } return Expression.modifiableLvalue(sc, e); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index d4e96bb..b65b0ed 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -1276,7 +1276,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = // @@@DEPRECATED_2.105@@@ // When turning into error, uncomment the return statement TypeFunction tf = fd.type.isTypeFunction(); - deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`", + deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`", fd.toPrettyChars(), tf.toChars, sc._module.toChars); //return ErrorExp.get(); } @@ -1298,7 +1298,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = { // @@@DEPRECATED_2.105@@@ // When turning into error, uncomment the return statement - deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`", + deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`", fd.toPrettyChars(), tf.toChars, sc._module.toChars); //return ErrorExp.get(); } @@ -2035,20 +2035,26 @@ private bool functionParameters(const ref Loc loc, Scope* sc, /* Argument value can be assigned to firstArg. * Check arg to see if it matters. */ - if (global.params.useDIP1000 == FeatureState.enabled) - err |= checkParamArgumentReturn(sc, firstArg, arg, p, false); + err |= checkParamArgumentReturn(sc, firstArg, arg, p, false); } // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along // as lazy parameters to the next function, but that isn't escaping. - else if (!(pStc & (STC.scope_ | STC.lazy_))) + else if (!(pStc & STC.lazy_)) { /* Argument value can escape from the called function. * Check arg to see if it matters. */ - if (global.params.useDIP1000 == FeatureState.enabled) - err |= checkParamArgumentEscape(sc, fd, p, arg, false, false); + err |= checkParamArgumentEscape(sc, fd, p, cast(STC) pStc, arg, false, false); } - else if (!(pStc & STC.return_)) + + // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference + // may be unreliable when scope violations only manifest as deprecation warnings. + // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope` + const explicitScope = (p.storageClass & STC.lazy_) || + ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred)); + if ((pStc & (STC.scope_ | STC.lazy_)) && + ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) && + !(pStc & STC.return_)) { /* Argument value cannot escape from the called function. */ @@ -2058,13 +2064,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc, ArrayLiteralExp ale; if (p.type.toBasetype().ty == Tarray && - (ale = a.isArrayLiteralExp()) !is null) + (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0) { // allocate the array literal as temporary static array on the stack - ale.type = ale.type.nextOf().sarrayOf(ale.elements ? ale.elements.length : 0); + ale.type = ale.type.nextOf().sarrayOf(ale.elements.length); auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale); auto declareTmp = new DeclarationExp(ale.loc, tmp); - auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp), p.type); + auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp), + p.type.substWildTo(MODFlags.mutable)); arg = CommaExp.combine(declareTmp, castToSlice); arg = arg.expressionSemantic(sc); } @@ -2473,7 +2480,7 @@ Package resolveIsPackage(Dsymbol sym) { if (imp.pkg is null) { - .error(sym.loc, "Internal Compiler Error: unable to process forward-referenced import `%s`", + .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`", imp.toChars()); assert(0); } @@ -2995,7 +3002,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor buffer.write4(0); e.setData(buffer.extractData(), newlen, 4); if (sc && sc.flags & SCOPE.Cfile) - e.type = Type.tuns32.pointerTo(); + e.type = Type.tuns32.sarrayOf(e.len + 1); else e.type = Type.tdchar.immutableOf().arrayOf(); e.committed = 1; @@ -3020,7 +3027,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor buffer.writeUTF16(0); e.setData(buffer.extractData(), newlen, 2); if (sc && sc.flags & SCOPE.Cfile) - e.type = Type.tuns16.pointerTo(); + e.type = Type.tuns16.sarrayOf(e.len + 1); else e.type = Type.twchar.immutableOf().arrayOf(); e.committed = 1; @@ -3032,7 +3039,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor default: if (sc && sc.flags & SCOPE.Cfile) - e.type = Type.tchar.pointerTo(); + e.type = Type.tchar.sarrayOf(e.len + 1); else e.type = Type.tchar.immutableOf().arrayOf(); break; @@ -3170,11 +3177,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor semanticTypeInfo(sc, e.type); - if (global.params.useDIP1000 == FeatureState.enabled) - { - if (checkAssocArrayLiteralEscape(sc, e, false)) - return setError(); - } + if (checkAssocArrayLiteralEscape(sc, e, false)) + return setError(); result = e; } @@ -3261,7 +3265,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // to fix https://issues.dlang.org/show_bug.cgi?id=9490 VarExp ve = e.isVarExp(); if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) && - sc.func && sc.func.needThis && ve.var.toParent2().isAggregateDeclaration()) + sc.func && sc.func.needThis && ve.var.isMember2()) { // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars()); e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false); @@ -3782,13 +3786,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Since a `new` allocation may escape, check each of the arguments for escaping */ - if (global.params.useDIP1000 == FeatureState.enabled) + foreach (arg; *exp.arguments) { - foreach (arg; *exp.arguments) - { - if (arg && checkNewEscape(sc, arg, false)) - return setError(); - } + if (arg && checkNewEscape(sc, arg, false)) + return setError(); } } @@ -4677,7 +4678,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (exp.f.needThis()) { - AggregateDeclaration ad = exp.f.toParentLocal().isAggregateDeclaration(); + AggregateDeclaration ad = exp.f.isMemberLocal(); ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f); if (ue.e1.op == EXP.error) { @@ -4688,7 +4689,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tthis = ue.e1.type; if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual)) { - if (global.params.useDIP1000 == FeatureState.enabled && checkParamArgumentEscape(sc, exp.f, null, ethis, false, false)) + if (checkParamArgumentEscape(sc, exp.f, null, STC.undefined_, ethis, false, false)) return setError(); } } @@ -5393,7 +5394,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp) { - error(exp.loc, "Runtime type information is not supported for `extern(C++)` classes"); + error(exp.loc, "runtime type information is not supported for `extern(C++)` classes"); e = ErrorExp.get(); } else if (!Type.typeinfoclass) @@ -6026,18 +6027,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor const slice = se.peekString(); message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, name); } - if (global.params.moduleDeps !is null) + if (global.params.moduleDeps.buffer !is null) { - OutBuffer* ob = global.params.moduleDeps; + OutBuffer* ob = global.params.moduleDeps.buffer; Module imod = sc._module; - if (!global.params.moduleDepsFile) + if (!global.params.moduleDeps.name) ob.writestring("depsFile "); ob.writestring(imod.toPrettyChars()); ob.writestring(" ("); escapePath(ob, imod.srcfile.toChars()); ob.writestring(") : "); - if (global.params.moduleDepsFile) + if (global.params.moduleDeps.name) ob.writestring("string : "); ob.write(se.peekString()); ob.writestring(" ("); @@ -6045,9 +6046,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ob.writestring(")"); ob.writenl(); } - if (global.params.emitMakeDeps) + if (global.params.makeDeps.doOutput) { - global.params.makeDeps.push(name); + global.params.makeDeps.files.push(name); } { @@ -6349,7 +6350,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.msg = resolveProperties(sc, exp.msg); exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf()); exp.msg = exp.msg.optimize(WANTvalue); - checkParamArgumentEscape(sc, null, null, exp.msg, true, false); + checkParamArgumentEscape(sc, null, null, STC.undefined_, exp.msg, true, false); } if (exp.msg && exp.msg.op == EXP.error) @@ -6625,6 +6626,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.type.addMod(t1.mod); + // https://issues.dlang.org/show_bug.cgi?id=23109 + // Run semantic on the DotVarExp type + if (auto handle = exp.type.isClassHandle()) + { + if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete()) + handle.dsymbolSemantic(null); + } + Dsymbol vparent = exp.var.toParent(); AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null; if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1)) @@ -6705,24 +6714,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e.type = e.type.typeSemantic(e.loc, sc); FuncDeclaration f = e.func.toAliasFunc(); - AggregateDeclaration ad = f.toParentLocal().isAggregateDeclaration(); + AggregateDeclaration ad = f.isMemberLocal(); if (f.needThis()) e.e1 = getRightThis(e.loc, sc, ad, e.e1, f); if (e.e1.op == EXP.error) return setError(); - /* A delegate takes the address of e.e1 in order to set the .ptr field - * https://issues.dlang.org/show_bug.cgi?id=18575 - */ - if (global.params.useDIP1000 == FeatureState.enabled && e.e1.type.toBasetype().ty == Tstruct) - { - if (auto v = expToVariable(e.e1)) - { - if (!checkAddressVar(sc, e.e1, v)) - return setError(); - } - } - if (f.type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)f.type; @@ -6809,20 +6806,26 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (sc.flags & SCOPE.Cfile) { - /* Special handling for &"string" - * since C regards a string literal as an lvalue + /* Special handling for &"string"/&(T[]){0, 1} + * since C regards string/array literals as lvalues */ - if (auto se = exp.e1.isStringExp()) + auto e = exp.e1; + if(e.isStringExp() || e.isArrayLiteralExp()) { - if (auto tp = se.type.toBasetype().isTypePointer()) + e.type = typeSemantic(e.type, Loc.initial, sc); + // if type is already a pointer exp is an illegal expression of the form `&(&"")` + if (!e.type.isTypePointer()) { - /* Switch from pointer-to-char to pointer-to-static-array-of-char - */ - auto ts = new TypeSArray(tp.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t)); - se.type = typeSemantic(ts, Loc.initial, sc).pointerTo(); - result = se; + e.type = e.type.pointerTo(); + result = e; return; } + else + { + // `toLvalue` call further below is upon exp.e1, omitting & from the error message + exp.toLvalue(sc, null); + return setError(); + } } } @@ -6891,19 +6894,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * because it might end up being a pointer to undefined * memory. */ - if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) + if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)) { - exp.error("cannot take address of lazy parameter `%s` in `@safe` function `%s`", - ve.toChars(), sc.func.toChars()); - setError(); - } - else - { - VarExp ve2 = callExp.e1.isVarExp(); - ve2.delegateWasExtracted = true; - ve2.var.storage_class |= STC.scope_; - result = ve2; + if (sc.func.setUnsafe(false, exp.loc, + "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func)) + { + setError(); + return; + } } + VarExp ve2 = callExp.e1.isVarExp(); + ve2.delegateWasExtracted = true; + ve2.var.storage_class |= STC.scope_; + result = ve2; return; } } @@ -6987,15 +6990,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Look for misaligned pointer in @safe mode if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true)) return setError(); - - if (global.params.useDIP1000 == FeatureState.enabled) - { - if (VarDeclaration v = expToVariable(dve.e1)) - { - if (!checkAddressVar(sc, exp.e1, v)) - return setError(); - } - } } else if (exp.e1.op == EXP.variable) { @@ -7049,29 +7043,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; return; } - if (sc.func && !sc.intypeof) + if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)) { - if (!(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) - { - exp.error("`this` reference necessary to take address of member `%s` in `@safe` function `%s`", f.toChars(), sc.func.toChars()); - } + sc.func.setUnsafe(false, exp.loc, + "`this` reference necessary to take address of member `%s` in `@safe` function `%s`", + f, sc.func); } } } } - else if ((exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_) && global.params.useDIP1000 == FeatureState.enabled) - { - if (VarDeclaration v = expToVariable(exp.e1)) - { - if (!checkAddressVar(sc, exp.e1, v)) - return setError(); - } - } - else if (auto ce = exp.e1.isCallExp()) - { - if (!checkAddressCall(sc, ce, "take address of")) - return setError(); - } else if (exp.e1.op == EXP.index) { /* For: @@ -7081,9 +7061,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ if (VarDeclaration v = expToVariable(exp.e1)) { - if (global.params.useDIP1000 == FeatureState.enabled && !checkAddressVar(sc, exp.e1, v)) - return setError(); - exp.e1.checkPurity(sc, v); } } @@ -7839,10 +7816,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) + if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)) { - exp.error("pointer slicing not allowed in safe functions"); - return setError(); + if (sc.func.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions")) + return setError(); } } else if (t1b.ty == Tarray) @@ -7850,34 +7827,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (t1b.ty == Tsarray) { - if (!exp.arrayop && global.params.useDIP1000 == FeatureState.enabled) - { - /* Slicing a static array is like taking the address of it. - * Perform checks as if e[] was &e - */ - if (VarDeclaration v = expToVariable(exp.e1)) - { - if (DotVarExp dve = exp.e1.isDotVarExp()) - { - - if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) && - !(v.storage_class & STC.ref_)) - { - // because it's a class - v = null; - } - } - - if (v && !checkAddressVar(sc, exp.e1, v)) - return setError(); - } - // https://issues.dlang.org/show_bug.cgi?id=22539 - if (auto ce = exp.e1.isCallExp()) - { - if (!checkAddressCall(sc, ce, "slice static array of")) - return setError(); - } - } } else if (t1b.ty == Ttuple) { @@ -8202,7 +8151,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor discardValue(e.e1); } else if (!e.allowCommaExp && !e.isGenerated) - e.error("Using the result of a comma expression is not allowed"); + e.error("using the result of a comma expression is not allowed"); } override void visit(IntervalExp e) @@ -8379,10 +8328,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0) { } - else if (sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) + else if (sc.func && !(sc.flags & SCOPE.debug_)) { - exp.error("safe function `%s` cannot index pointer `%s`", sc.func.toPrettyChars(), exp.e1.toChars()); - return setError(); + if (sc.func.setUnsafe(false, exp.loc, + "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1)) + return setError(); } exp.type = (cast(TypeNext)t1b).next; break; @@ -8675,10 +8625,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { static if (LOGSEMANTIC) { - printf("AssignExp::semantic('%s')\n", exp.toChars()); + if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars()); + if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars()); + if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars()); } - //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, EXPtoString(exp.e1.op).ptr); - //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, EXPtoString(exp.e2.op).ptr); void setResult(Expression e, int line = __LINE__) { @@ -8696,7 +8646,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (auto e2comma = exp.e2.isCommaExp()) { if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile)) - exp.error("Using the result of a comma expression is not allowed"); + exp.error("using the result of a comma expression is not allowed"); /* Rewrite to get rid of the comma from rvalue * e1=(e0,e2) => e0,(e1=e2) @@ -9425,6 +9375,23 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression e1x = exp.e1; Expression e2x = exp.e2; + /* C strings come through as static arrays. May need to adjust the size of the + * string to match the size of e1. + */ + Type t2 = e2x.type.toBasetype(); + if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray()) + { + uinteger_t dim1 = t1.isTypeSArray().dim.toInteger(); + uinteger_t dim2 = t2.isTypeSArray().dim.toInteger(); + if (dim1 + 1 == dim2 || dim2 < dim1) + { + auto tsa2 = t2.isTypeSArray(); + auto newt = tsa2.next.sarrayOf(dim1).immutableOf(); + e2x = castTo(e2x, sc, newt); + exp.e2 = e2x; + } + } + if (e2x.implicitConvTo(e1x.type)) { if (exp.op != EXP.blit && (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue())) @@ -9686,13 +9653,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tsa2 = cast(TypeSArray)toStaticArrayType(se); else tsa2 = t2.isTypeSArray(); + if (tsa1 && tsa2) { uinteger_t dim1 = tsa1.dim.toInteger(); uinteger_t dim2 = tsa2.dim.toInteger(); if (dim1 != dim2) { - exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); + exp.error("mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars()); return setError(); } } @@ -9761,10 +9729,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) { - if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) + if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_)) { - exp.error("cannot copy `void[]` to `void[]` in `@safe` code"); - return setError(); + if (sc.func.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code")) + return setError(); } } } @@ -10190,10 +10158,135 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.e1.type; auto res = exp.reorderSettingAAElem(sc); - if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) && - global.params.useDIP1000 == FeatureState.enabled) + if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) checkAssignEscape(sc, res, false, false); result = res; + + if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && + !(sc.flags & (SCOPE.ctfe | SCOPE.compile))) + { + // if aa ordering is triggered, `res` will be a CommaExp + // and `.e2` will be the rewritten original expression. + + // `output` will point to the expression that the lowering will overwrite + Expression* output; + if (auto comma = res.isCommaExp()) + { + output = &comma.e2; + // manual cast because it could be either CatAssignExp or CatElemAssignExp + exp = cast(CatAssignExp)comma.e2; + } + else + { + output = &result; + exp = cast(CatAssignExp)result; + } + + if (exp.op == EXP.concatenateAssign) + { + Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT; + + if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object)) + return setError(); + + // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2) + Expression id = new IdentifierExp(exp.loc, Id.empty); + id = new DotIdExp(exp.loc, id, Id.object); + id = new DotIdExp(exp.loc, id, hook); + + auto arguments = new Expressions(); + arguments.reserve(5); + if (global.params.tracegc) + { + auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); + arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); + arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); + arguments.push(new StringExp(exp.loc, funcname.toDString())); + } + + arguments.push(exp.e1); + arguments.push(exp.e2); + Expression ce = new CallExp(exp.loc, id, arguments); + *output = ce.expressionSemantic(sc); + } + else if (exp.op == EXP.concatenateElemAssign) + { + /* Do not lower concats to the indices array returned by + *`static foreach`, as this array is only used at compile-time. + */ + if (auto ve = exp.e1.isVarExp) + { + import core.stdc.ctype : isdigit; + // The name of the indices array that static foreach loops uses. + // See dmd.cond.lowerNonArrayAggregate + enum varName = "__res"; + const(char)[] id = ve.var.ident.toString; + if (ve.var.storage_class & STC.temp && id.length > varName.length && + id[0 .. varName.length] == varName && id[varName.length].isdigit) + return; + } + + Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX; + if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object)) + return setError(); + + // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2 + Expression id = new IdentifierExp(exp.loc, Id.empty); + id = new DotIdExp(exp.loc, id, Id.object); + auto tiargs = new Objects(); + tiargs.push(exp.e1.type); + id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs); + id = new DotIdExp(exp.loc, id, hook); + + auto arguments = new Expressions(); + arguments.reserve(5); + if (global.params.tracegc) + { + auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); + arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); + arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); + arguments.push(new StringExp(exp.loc, funcname.toDString())); + } + + Expression eValue1; + Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1); + + arguments.push(value1); + arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t)); + + Expression ce = new CallExp(exp.loc, id, arguments); + + Expression eValue2; + Expression value2 = exp.e2; + if (!value2.isVarExp() && !value2.isConst()) + { + /* Before the template hook, this check was performed in e2ir.d + * for expressions like `a ~= a[$-1]`. Here, $ will be modified + * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in + * a temporary variable. + */ + value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true); + exp.e2 = value2; + + // `__appendtmp*` will be destroyed together with the array `exp.e1`. + auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration(); + vd.storage_class |= STC.nodtor; + } + + auto ale = new ArrayLengthExp(exp.loc, value1); + auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1)); + auto ae = new ConstructExp(exp.loc, elem, value2); + + auto e0 = Expression.combine(ce, ae).expressionSemantic(sc); + e0 = Expression.combine(e0, value1); + e0 = Expression.combine(eValue1, e0); + + e0 = Expression.combine(eValue2, e0); + + *output = e0.expressionSemantic(sc); + } + } + } override void visit(AddExp exp) @@ -11639,7 +11732,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto t1 = exp.e1.type; auto t2 = exp.e2.type; if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2)) - exp.error("Comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`", + exp.error("comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`", t1.toChars(), t2.toChars()); } @@ -11996,7 +12089,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // C11 6.5.1.1 Generic Selection - auto ec = exp.cntlExp.expressionSemantic(sc); + auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc); bool errors = ec.isErrorExp() !is null; auto tc = ec.type; @@ -12622,12 +12715,21 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag) Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t); return e; } - else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp()) + else if ((exp.ident == Id.max || exp.ident == Id.min) && + exp.e1.isVarExp() && + exp.e1.isVarExp().var.isBitFieldDeclaration()) { - // Sizeof string literal includes the terminating 0 - auto se = exp.e1.isStringExp(); - Expression e = new IntegerExp(exp.loc, (se.len + 1) * se.sz, Type.tsize_t); - return e; + // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type + auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration(); + return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type); + } + else if ((exp.ident == Id.max || exp.ident == Id.min) && + exp.e1.isDotVarExp() && + exp.e1.isDotVarExp().var.isBitFieldDeclaration()) + { + // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type + auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration(); + return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type); } else { @@ -12635,7 +12737,9 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag) flag = 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; } } @@ -12982,22 +13086,12 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) if (sc.func && !sc.intypeof && !v.isDataseg()) { const(char)* p = v.isParameter() ? "parameter" : "local"; - if (global.params.useDIP1000 == FeatureState.enabled) - { - // Taking the address of v means it cannot be set to 'scope' later - v.storage_class &= ~STC.maybescope; - v.doNotInferScope = true; - if (exp.type.hasPointers() && v.storage_class & STC.scope_ && - !(v.storage_class & STC.temp) && - !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) - { - exp.error("cannot take address of `scope` %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); - return false; - } - } - else if (!(sc.flags & SCOPE.debug_) && - !(v.storage_class & STC.temp) && - sc.func.setUnsafe()) + v.storage_class &= ~STC.maybescope; + v.doNotInferScope = true; + if (global.params.useDIP1000 != FeatureState.enabled && + !(sc.flags & SCOPE.debug_) && + !(v.storage_class & STC.temp) && + sc.func.setUnsafe()) { exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); return false; @@ -13007,37 +13101,6 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) return true; } -/**************************************************** - * Determine if the address of a `ref return` value of - * a function call with type `tf` can be taken safely. - * - * This is currently stricter than necessary: it can be safe to take the - * address of a `ref` with pointer type when the pointer isn't `scope`, but - * that involves inspecting the function arguments and parameter types, which - * is left as a future enhancement. - * - * Params: - * sc = context - * ce = function call in question - * action = for the error message, how the pointer is taken, e.g. "slice static array of" - * Returns: - * `true` if ok, `false` for error - */ -private bool checkAddressCall(Scope* sc, CallExp ce, const(char)* action) -{ - if (auto tf = ce.e1.type.isTypeFunction()) - { - if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) - && tf.next.hasPointers() && sc.func.setUnsafe()) - { - ce.error("cannot %s `ref return` of `%s()` in `@safe` function `%s`", - action, ce.e1.toChars(), sc.func.toChars()); - ce.errorSupplemental("return type `%s` has pointers that may be `scope`", tf.next.toChars()); - return false; - } - } - return true; -} /******************************* * Checks the attributes of a function. @@ -13241,10 +13304,9 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions { if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize || (v.offset & (target.ptrsize - 1))) && - (sc.func && sc.func.setUnsafe())) + (sc.func && sc.func.setUnsafe(false, loc, + "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v))) { - .error(loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", - sd.toChars(), v.toChars()); return false; } } diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 8d83951..e53a540 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -344,6 +344,10 @@ extern (C++) class FuncDeclaration : Declaration FuncDeclarations *inlinedNestedCallees; + /// In case of failed `@safe` inference, store the error that made the function `@system` for + /// better diagnostics + private AttributeViolation* safetyViolation; + /// Function flags: A collection of boolean packed for memory efficiency /// See the `FUNCFLAG` enum uint flags = FUNCFLAG.NRVO; @@ -1207,12 +1211,12 @@ extern (C++) class FuncDeclaration : Declaration final bool isMain() const { - return ident == Id.main && linkage != LINK.c && !isMember() && !isNested(); + return ident == Id.main && resolvedLinkage() != LINK.c && !isMember() && !isNested(); } final bool isCMain() const { - return ident == Id.main && linkage == LINK.c && !isMember() && !isNested(); + return ident == Id.main && resolvedLinkage() == LINK.c && !isMember() && !isNested(); } final bool isWinMain() const @@ -1220,24 +1224,24 @@ extern (C++) class FuncDeclaration : Declaration //printf("FuncDeclaration::isWinMain() %s\n", toChars()); version (none) { - bool x = ident == Id.WinMain && linkage != LINK.c && !isMember(); + bool x = ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember(); printf("%s\n", x ? "yes" : "no"); return x; } else { - return ident == Id.WinMain && linkage != LINK.c && !isMember(); + return ident == Id.WinMain && resolvedLinkage() != LINK.c && !isMember(); } } final bool isDllMain() const { - return ident == Id.DllMain && linkage != LINK.c && !isMember(); + return ident == Id.DllMain && resolvedLinkage() != LINK.c && !isMember(); } final bool isRtInit() const { - return ident == Id.rt_init && linkage == LINK.c && !isMember() && !isNested(); + return ident == Id.rt_init && resolvedLinkage() == LINK.c && !isMember() && !isNested(); } override final bool isExport() const @@ -1349,8 +1353,7 @@ extern (C++) class FuncDeclaration : Declaration flags |= FUNCFLAG.returnInprocess; // Initialize for inferring STC.scope_ - if (global.params.useDIP1000 == FeatureState.enabled) - flags |= FUNCFLAG.inferScope; + flags |= FUNCFLAG.inferScope; } final PURE isPure() @@ -1427,24 +1430,51 @@ extern (C++) class FuncDeclaration : Declaration } /************************************** - * The function is doing something unsafe, - * so mark it as unsafe. - * If there's a safe error, return true. + * The function is doing something unsafe, so mark it as unsafe. + * + * Params: + * gag = surpress error message (used in escape.d) + * loc = location of error + * fmt = printf-style format string + * arg0 = (optional) argument for first %s format specifier + * arg1 = (optional) argument for second %s format specifier + * Returns: whether there's a safe error */ - extern (D) final bool setUnsafe() + extern (D) final bool setUnsafe( + bool gag = false, Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null, RootObject arg1 = null) { if (flags & FUNCFLAG.safetyInprocess) { flags &= ~FUNCFLAG.safetyInprocess; type.toTypeFunction().trust = TRUST.system; + if (!gag && !safetyViolation && (fmt || arg0)) + safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1); + if (fes) fes.func.setUnsafe(); } else if (isSafe()) + { + if (!gag && fmt) + .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : ""); + return true; + } return false; } + /************************************** + * The function is calling `@system` function `f`, so mark it as unsafe. + * + * Params: + * f = function being called (needed for diagnostic of inferred functions) + * Returns: whether there's a safe error + */ + extern (D) final bool setUnsafeCall(FuncDeclaration f) + { + return setUnsafe(false, f.loc, null, f, null); + } + final bool isNogc() { //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess)); @@ -1474,6 +1504,12 @@ extern (C++) class FuncDeclaration : Declaration return !!(this.flags & FUNCFLAG.naked); } + final void isNaked(bool v) @safe pure nothrow @nogc + { + if (v) this.flags |= FUNCFLAG.naked; + else this.flags &= ~FUNCFLAG.naked; + } + final bool isGenerated() const scope @safe pure nothrow @nogc { return !!(this.flags & FUNCFLAG.generated); @@ -1520,11 +1556,23 @@ extern (C++) class FuncDeclaration : Declaration return !!(this.flags & FUNCFLAG.CRTCtor); } + final void isCrtCtor(bool v) @safe pure nothrow @nogc + { + if (v) this.flags |= FUNCFLAG.CRTCtor; + else this.flags &= ~FUNCFLAG.CRTCtor; + } + final bool isCrtDtor() const scope @safe pure nothrow @nogc { return !!(this.flags & FUNCFLAG.CRTDtor); } + final void isCrtDtor(bool v) @safe pure nothrow @nogc + { + if (v) this.flags |= FUNCFLAG.CRTDtor; + else this.flags &= ~FUNCFLAG.CRTDtor; + } + /************************************** * The function is doing something that may allocate with the GC, * so mark it as not nogc (not no-how). @@ -1758,7 +1806,7 @@ extern (C++) class FuncDeclaration : Declaration auto f = toAliasFunc(); //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars()); return ((f.storage_class & STC.static_) == 0) && - (f.linkage == LINK.d) && + (f._linkage == LINK.d) && (f.toParent2().isFuncDeclaration() !is null || f.toParent2() !is f.toParentLocal()); } @@ -2645,7 +2693,7 @@ extern (C++) class FuncDeclaration : Declaration tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc); fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf); fd.visibility = Visibility(Visibility.Kind.public_); - fd.linkage = LINK.c; + fd._linkage = LINK.c; st.insert(fd); } @@ -2705,6 +2753,7 @@ extern (C++) class FuncDeclaration : Declaration const nparams = tf.parameterList.length; bool argerr; + const linkage = resolvedLinkage(); if (linkage == LINK.d) { if (nparams == 1) @@ -4271,3 +4320,47 @@ extern (C++) final class NewDeclaration : FuncDeclaration v.visit(this); } } + +/// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure` +/// +/// Has two modes: +/// - a regular safety error, stored in (fmtStr, arg0, arg1) +/// - a call to a function without the attribute, which is a special case, because in that case, +/// that function might recursively also have a `AttributeViolation`. This way, in case +/// of a big call stack, the error can go down all the way to the root cause. +/// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`. +private struct AttributeViolation +{ + /// location of error + Loc loc = Loc.init; + /// printf-style format string + const(char)* fmtStr = null; + /// Arguments for up to two `%s` format specifiers in format string + RootObject arg0 = null; + /// ditto + RootObject arg1 = null; +} + +/// Print the reason why `fd` was inferred `@system` as a supplemental error +/// Params: +/// fd = function to check +/// maxDepth = up to how many functions deep to report errors +void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth) +{ + if (auto s = fd.safetyViolation) + { + if (s.fmtStr) + { + errorSupplemental(s.loc, "which was inferred `@system` because of:"); + errorSupplemental(s.loc, s.fmtStr, s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : ""); + } + else if (FuncDeclaration fd2 = cast(FuncDeclaration) s.arg0) + { + if (maxDepth > 0) + { + errorSupplemental(s.loc, "which calls `%s`", fd2.toPrettyChars()); + errorSupplementalInferredSafety(fd2, maxDepth - 1); + } + } + } +} diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 6b6655c..ba4ccbe 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -51,14 +51,6 @@ enum CHECKACTION : ubyte context, /// call D assert with the error context on failure } -/// Position Indepent Code setting -enum PIC : ubyte -{ - fixed, /// located at a specific address - pic, /// Position Independent Code - pie, /// Position Independent Executable -} - /** Each flag represents a field that can be included in the JSON output. @@ -83,14 +75,6 @@ enum CppStdRevision : uint cpp20 = 2020_02, } -/// Configuration for the C++ header generator -enum CxxHeaderMode : uint -{ - none, /// Don't generate headers - silent, /// Generate headers - verbose /// Generate headers and add comments for hidden declarations -} - /// Trivalent boolean to represent the state of a `revert`able change enum FeatureState : byte { @@ -99,15 +83,24 @@ enum FeatureState : byte enabled = 1 /// Specified as `-preview=` } +extern(C++) struct Output +{ + bool doOutput; // Output is enabled + bool fullOutput; // Generate comments for hidden declarations (for -HC), + // and don't strip the bodies of plain (non-template) functions (for -H) + + const(char)[] dir; // write to directory 'dir' + const(char)[] name; // write to file 'name' + Array!(const(char)*) files; // Other files associated with this output, + // e.g. macro include files for Ddoc, dependencies for makedeps + OutBuffer* buffer; // if this output is buffered, this is the buffer + int bufferLines; // number of lines written to the buffer +} /// Put command line switches in here extern (C++) struct Param { bool obj = true; // write object file - bool link = true; // perform link - bool dll; // generate shared dynamic library - bool lib; // write library file instead of object file(s) bool multiobj; // break one object file into multiple ones - bool oneobj; // write one object file instead of multiple ones bool trace; // insert profiling hooks bool tracegc; // instrument calls to 'new' bool verbose; // verbose compile @@ -120,11 +113,7 @@ extern (C++) struct Param 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 DiagnosticReporting useDeprecated = DiagnosticReporting.inform; // how use of deprecated features are handled - bool stackstomp; // add stack stomping code bool useUnitTests; // generate unittest code bool useInline = false; // inline expand functions FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 @@ -133,12 +122,10 @@ extern (C++) struct Param bool release; // build release version bool preservePaths; // true means don't strip path from source file DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled - PIC pic = PIC.fixed; // generate fixed, pic or pie code bool color; // use ANSI colors in console output bool cov; // generate code coverage data ubyte covPercent; // 0..100 code coverage percentage required bool ctfe_cov = false; // generate coverage data for ctfe - bool nofloat; // code should not pull in floating point support bool ignoreUnsupportedPragmas; // rather than error on them bool useModuleInfo = true; // generate runtime module information bool useTypeInfo = true; // generate runtime type information @@ -162,6 +149,7 @@ extern (C++) struct Param FeatureState dtorFields; // destruct fields of partially constructed objects // https://issues.dlang.org/show_bug.cgi?id=14246 bool fieldwise; // do struct equality testing field-wise rather than by memcmp() + bool bitfields; // support C style bit fields FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters // https://dconf.org/2019/talks/alexandrescu.html // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a @@ -170,9 +158,6 @@ extern (C++) struct Param CppStdRevision cplusplus = CppStdRevision.cpp11; // version of C++ standard to support - bool markdown = true; // enable Markdown replacements in Ddoc - bool vmarkdown; // list instances of Markdown replacements in Ddoc - bool showGaggedErrors; // print gagged errors anyway bool printErrorContext; // print errors with the error context (the error line in the source file) bool manual; // open browser on compiler manual @@ -207,27 +192,14 @@ extern (C++) struct Param const(char)[] objname; // .obj file output name const(char)[] libname; // .lib file output name - bool doDocComments; // process embedded documentation comments - const(char)[] docdir; // write documentation file to docdir directory - const(char)[] docname; // write documentation file to docname - Array!(const(char)*) ddocfiles; // macro include files for Ddoc - - bool doHdrGeneration; // process embedded documentation comments - const(char)[] hdrdir; // write 'header' file to docdir directory - const(char)[] hdrname; // write 'header' file to docname - bool hdrStripPlainFunctions = true; // strip the bodies of plain (non-template) functions - - CxxHeaderMode doCxxHdrGeneration; /// Generate 'Cxx header' file - const(char)[] cxxhdrdir; // write 'header' file to docdir directory - const(char)[] cxxhdrname; // write 'header' file to docname - - bool doJsonGeneration; // write JSON file - const(char)[] jsonfilename; // write JSON file to jsonfilename + Output ddoc; // Generate embedded documentation comments + Output dihdr; // Generate `.di` 'header' files + Output cxxhdr; // Generate 'Cxx header' file + Output json; // Generate JSON file JsonFieldFlags jsonFieldFlags; // JSON field flags to include - - OutBuffer* mixinOut; // write expanded mixins for debugging - const(char)* mixinFile; // .mixin file output name - int mixinLines; // Number of lines in writeMixins + Output makeDeps; // Generate make file dependencies + Output mixinOut; // write expanded mixins for debugging + Output moduleDeps; // Generate `.deps` module dependencies uint debuglevel; // debug level Array!(const(char)*)* debugids; // debug identifiers @@ -235,21 +207,12 @@ extern (C++) struct Param uint versionlevel; // version level Array!(const(char)*)* versionids; // version identifiers - const(char)[] defaultlibname; // default library for non-debug builds - const(char)[] debuglibname; // default library for debug builds - const(char)[] mscrtlib; // MS C runtime library - - const(char)[] moduleDepsFile; // filename for deps output - OutBuffer* moduleDeps; // contents to be written to deps file - - bool emitMakeDeps; // whether to emit makedeps - const(char)[] makeDepsFile; // filename for makedeps output - Array!(const(char)*) makeDeps; // dependencies for makedeps MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages bool run; // run resulting executable Strings runargs; // arguments for executable + Array!(const(char)*) cppswitches; // C preprocessor switches // Linker stuff Array!(const(char)*) objfiles; @@ -335,6 +298,8 @@ extern (C++) struct Global enum recursionLimit = 500; /// number of recursive template expansions before abort + extern (C++) FileName function(FileName, const(char)* importc_h, ref Array!(const(char)*) cppswitches, out bool) preprocess; + nothrow: /** @@ -468,15 +433,6 @@ extern (C++) struct Global { return _version.ptr; } - - /** - Returns: the final defaultlibname based on the command-line parameters - */ - extern (D) const(char)[] finalDefaultlibname() const - { - return params.betterC ? null : - params.symdebug ? params.debuglibname : params.defaultlibname; - } } // Because int64_t and friends may be any integral type of the diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 2a33692..5c164fd 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -73,14 +73,6 @@ enum CppStdRevision CppStdRevisionCpp20 = 202002 }; -/// Configuration for the C++ header generator -enum class CxxHeaderMode -{ - none, /// Don't generate headers - silent, /// Generate headers - verbose /// Generate headers and add comments for hidden declarations -}; - /// Trivalent boolean to represent the state of a `revert`able change enum class FeatureState : signed char { @@ -89,15 +81,25 @@ enum class FeatureState : signed char enabled = 1 /// Specified as `-preview=` }; +struct Output +{ + /// Configuration for the compiler generator + bool doOutput; // Output is enabled + bool fullOutput; // Generate comments for hidden declarations (for -HC), + // and don't strip the bodies of plain (non-template) functions (for -H) + DString dir; // write to directory 'dir' + DString name; // write to file 'name' + Array<const char*> files; // Other files associated with this output, + // e.g. macro include files for Ddoc, dependencies for makedeps + OutBuffer* buffer; // if this output is buffered, this is the buffer + int bufferLines; // number of lines written to the buffer +}; + // Put command line switches in here struct Param { bool obj; // write object file - bool link; // perform link - bool dll; // generate shared dynamic library - bool lib; // write library file instead of object file(s) bool multiobj; // break one object file into multiple ones - bool oneobj; // write one object file instead of multiple ones bool trace; // insert profiling hooks bool tracegc; // instrument calls to 'new' bool verbose; // verbose compile @@ -110,11 +112,7 @@ struct Param 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 Diagnostic useDeprecated; - bool stackstomp; // add stack stomping code bool useUnitTests; // generate unittest code bool useInline; // inline expand functions FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 @@ -123,12 +121,10 @@ struct Param bool release; // build release version bool preservePaths; // true means don't strip path from source file Diagnostic warnings; - unsigned char pic; // generate position-independent-code for shared libs bool color; // use ANSI colors in console output bool cov; // generate code coverage data unsigned char covPercent; // 0..100 code coverage percentage required bool ctfe_cov; // generate coverage data for ctfe - bool nofloat; // code should not pull in floating point support bool ignoreUnsupportedPragmas; // rather than error on them bool useModuleInfo; // generate runtime module information bool useTypeInfo; // generate runtime type information @@ -147,10 +143,9 @@ struct Param FeatureState dtorFields; // destruct fields of partially constructed objects // https://issues.dlang.org/show_bug.cgi?id=14246 bool fieldwise; // do struct equality testing field-wise rather than by memcmp() + bool bitfields; // support C style bit fields FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters CppStdRevision cplusplus; // version of C++ name mangling to support - bool markdown; // enable Markdown replacements in Ddoc - bool vmarkdown; // list instances of Markdown replacements in Ddoc bool showGaggedErrors; // print gagged errors anyway bool printErrorContext; // print errors with the error context (the error line in the source file) bool manual; // open browser on compiler manual @@ -185,27 +180,14 @@ struct Param DString objname; // .obj file output name DString libname; // .lib file output name - bool doDocComments; // process embedded documentation comments - DString docdir; // write documentation file to docdir directory - DString docname; // write documentation file to docname - Array<const char *> ddocfiles; // macro include files for Ddoc - - bool doHdrGeneration; // process embedded documentation comments - DString hdrdir; // write 'header' file to docdir directory - DString hdrname; // write 'header' file to docname - bool hdrStripPlainFunctions; // strip the bodies of plain (non-template) functions - - CxxHeaderMode doCxxHdrGeneration; // write 'Cxx header' file - DString cxxhdrdir; // write 'header' file to docdir directory - DString cxxhdrname; // write 'header' file to docname - - bool doJsonGeneration; // write JSON file - DString jsonfilename; // write JSON file to jsonfilename + Output ddoc; // Generate embedded documentation comments + Output dihdr; // Generate `.di` 'header' files + Output cxxhdr; // Generate 'Cxx header' file + Output json; // Generate JSON file unsigned jsonFieldFlags; // JSON field flags to include - - OutBuffer *mixinOut; // write expanded mixins for debugging - const char *mixinFile; // .mixin file output name - int mixinLines; // Number of lines in writeMixins + Output makeDeps; // Generate make file dependencies + Output mixinOut; // write expanded mixins for debugging + Output moduleDeps; // Generate `.deps` module dependencies unsigned debuglevel; // debug level Array<const char *> *debugids; // debug identifiers @@ -213,22 +195,14 @@ struct Param unsigned versionlevel; // version level Array<const char *> *versionids; // version identifiers - DString defaultlibname; // default library for non-debug builds - DString debuglibname; // default library for debug builds - DString mscrtlib; // MS C runtime library - - DString moduleDepsFile; // filename for deps output - OutBuffer *moduleDeps; // contents to be written to deps file - - bool emitMakeDeps; // whether to emit makedeps - DString makeDepsFile; // filename for makedeps output - Array<const char *> makeDeps; // dependencies for makedeps MessageStyle messageStyle; // style of file/line annotations on messages bool run; // run resulting executable Strings runargs; // arguments for executable + Array<const char *> cppswitches; // preprocessor switches + // Linker stuff Array<const char *> objfiles; Array<const char *> linkswitches; @@ -296,6 +270,8 @@ struct Global FileManager* fileManager; + FileName (*preprocess)(FileName, const char*, Array<const char *>& cppswitches, bool&); + /* Start gagging. Return the current number of gagged errors */ unsigned startGagging(); diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 69fdf27..fd35e1c 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -1536,7 +1536,7 @@ public: bodyToBuffer(f); hgs.autoMember--; } - else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions) + else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false) { if (!f.fbody) { @@ -1621,7 +1621,7 @@ public: void bodyToBuffer(FuncDeclaration f) { - if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember)) + if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember)) { if (!f.fbody && (f.fensures || f.frequires)) { diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 11455af..ab9528a 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -349,6 +349,11 @@ immutable Msgtable[] msgtable = { "_d_arraysetlengthTImpl"}, { "_d_arraysetlengthT"}, { "_d_arraysetlengthTTrace"}, + { "_d_arrayappendT" }, + { "_d_arrayappendTTrace" }, + { "_d_arrayappendcTXImpl" }, + { "_d_arrayappendcTX" }, + { "_d_arrayappendcTXTrace" }, // varargs implementation { "stdc" }, @@ -454,6 +459,7 @@ immutable Msgtable[] msgtable = { "getVirtualFunctions" }, { "getVirtualMethods" }, { "classInstanceSize" }, + { "classInstanceAlignment" }, { "allMembers" }, { "derivedMembers" }, { "isSame" }, diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index c84a9f6..2cddd28 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -198,14 +198,16 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ { if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize || (vd.offset & (target.ptrsize - 1))) && - sc.func && sc.func.setUnsafe()) + sc.func) { - 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; + if (sc.func.setUnsafe(false, i.value[j].loc, + "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd)) + { + errors = true; + elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors + ++fieldi; + continue; + } } } @@ -502,6 +504,18 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ i.exp = se.castTo(sc, t); goto L1; } + + /* Lop off terminating 0 of initializer for: + * static char s[5] = "hello"; + */ + if (sc.flags & SCOPE.Cfile && + typeb.ty == Tsarray && + tynto.isSomeChar && + tb.isTypeSArray().dim.toInteger() + 1 == typeb.isTypeSArray().dim.toInteger()) + { + i.exp = se.castTo(sc, t); + goto L1; + } } /* C11 6.7.9-14..15 * Initialize an array of unknown size with a string. @@ -573,7 +587,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } else if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() && tta && (tta.next.ty == Tint8 || tta.next.ty == Tuns8) && - ti.ty == Tpointer && ti.nextOf().ty == Tchar) + ti.ty == Tsarray && ti.nextOf().ty == Tchar) { /* unsigned char bbb[1] = ""; * signed char ccc[1] = ""; diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index fc27039..a22c664 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -446,7 +446,7 @@ public: return; jsonProperties(cast(Dsymbol)d); propertyStorageClass("storageClass", d.storage_class); - property("linkage", d.linkage); + property("linkage", d._linkage); property("type", "deco", d.type); // Emit originalType if it differs from type if (d.type != d.originalType && d.originalType) @@ -934,7 +934,7 @@ public: propertyStart("ddocFiles"); arrayStart(); - foreach (ddocFile; global.params.ddocfiles) + foreach (ddocFile; global.params.ddoc.files) { item(ddocFile.toDString); } diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 13df0d7..be17ab3 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -4375,8 +4375,6 @@ extern (C++) final class TypeFunction : TypeNext { //printf("parameterStorageClass(p: %s)\n", p.toChars()); auto stc = p.storageClass; - if (global.params.useDIP1000 != FeatureState.enabled) - return stc; // When the preview switch is enable, `in` parameters are `scope` if (stc & STC.in_ && global.params.previewIn) @@ -4441,7 +4439,9 @@ extern (C++) final class TypeFunction : TypeNext // Check escaping through return value Type tret = nextOf().toBasetype(); if (isref || tret.hasPointers()) + { return stc | STC.scope_ | STC.return_ | STC.returnScope; + } else return stc | STC.scope_; } @@ -4764,12 +4764,31 @@ extern (C++) final class TypeFunction : TypeNext s ~= "@safe "; if (!f.isNogc && sc.func.setGC()) s ~= "nogc "; - s[$-1] = '\0'; - buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); - + if (s) + { + s[$-1] = '\0'; + buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr); + } + else if (f.isGenerated() && f.isDisabled()) + { + /* https://issues.dlang.org/show_bug.cgi?id=23097 + * Compiler generated copy constructor failed. + */ + buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable", + argStruct.toChars()); + } + else + { + /* Although a copy constructor may exist, no suitable match was found. + * i.e: `inout` constructor creates `const` object, not mutable. + * Fallback to using the original generic error before bugzilla 22202. + */ + goto Lnocpctor; + } } else { + Lnocpctor: buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies", argStruct.toChars(), targ.toChars(), tprm.toChars()); } @@ -5134,22 +5153,6 @@ extern (C++) final class TypeDelegate : TypeNext override Type addStorageClass(StorageClass stc) { TypeDelegate t = cast(TypeDelegate)Type.addStorageClass(stc); - if (global.params.useDIP1000 != FeatureState.enabled) - return t; - - /* The rest is meant to add 'scope' to a delegate declaration if it is of the form: - * alias dg_t = void* delegate(); - * scope dg_t dg = ...; - */ - if(stc & STC.scope_) - { - auto n = t.next.addStorageClass(STC.scope_ | STC.scopeinferred); - if (n != t.next) - { - t.next = n; - t.deco = t.merge().deco; // mangling supposed to not be changed due to STC.scope_inferrred - } - } return t; } @@ -5218,8 +5221,8 @@ extern (C++) final class TypeTraits : Type Loc loc; /// The expression to resolve as type or symbol. TraitsExp exp; - /// After `typeSemantic` the symbol when `exp` doesn't represent a type. - Dsymbol sym; + /// Cached type/symbol after semantic analysis. + RootObject obj; final extern (D) this(const ref Loc loc, TraitsExp exp) { diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 6ba47df..d2b1364 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -670,8 +670,8 @@ class TypeTraits : public Type Loc loc; /// The expression to resolve as type or symbol. TraitsExp *exp; - /// The symbol when exp doesn't represent a type. - Dsymbol *sym; + /// Cached type/symbol after semantic analysis. + RootObject *obj; const char *kind(); TypeTraits *syntaxCopy(); diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 2957b3a..8cf3585 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -84,6 +84,17 @@ public: } f.printGCUsage(e.loc, "setting `length` may cause a GC allocation"); } + else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendcTX) + { + if (f.setGC()) + { + e.error("cannot use operator `~=` in `@nogc` %s `%s`", + f.kind(), f.toPrettyChars()); + err = true; + return; + } + f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation"); + } } override void visit(ArrayLiteralExp e) @@ -181,14 +192,15 @@ public: override void visit(CatAssignExp e) { + /* CatAssignExp will exist in `__traits(compiles, ...)` and in the `.e1` branch of a `__ctfe ? :` CondExp. + * The other branch will be `_d_arrayappendcTX(e1, 1), e1[$-1]=e2` which will generate the warning about + * GC usage. See visit(CallExp). + */ if (f.setGC()) { - e.error("cannot use operator `~=` in `@nogc` %s `%s`", - f.kind(), f.toPrettyChars()); err = true; return; } - f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation"); } override void visit(CatExp e) diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index 9e92212..9afedc1 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -578,7 +578,7 @@ extern(C++) private final class Supported : Objc override void checkLinkage(FuncDeclaration fd) { - if (fd.linkage != LINK.objc && fd.objc.selector) + if (fd._linkage != LINK.objc && fd.objc.selector) fd.error("must have Objective-C linkage to attach a selector"); } @@ -640,11 +640,11 @@ extern(C++) private final class Supported : Objc if (!fd.objc.isOptional) return; - if (fd.linkage != LINK.objc) + if (fd._linkage != LINK.objc) { fd.error("only functions with Objective-C linkage can be declared as optional"); - const linkage = linkageToString(fd.linkage); + const linkage = linkageToString(fd._linkage); errorSupplemental(fd.loc, "function is declared with %.*s linkage", cast(uint) linkage.length, linkage.ptr); diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 3cc36b4..2b7b9ac 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -558,6 +558,41 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) } else if (auto ae = e.e1.isIndexExp()) { + if (ae.e2.isIntegerExp() && ae.e1.isIndexExp()) + { + /* Rewrite `(a[i])[index]` to `(&a[i]) + index*size` + */ + sinteger_t index = ae.e2.toInteger(); + auto ae1 = ae.e1.isIndexExp(); // ae1 is a[i] + if (auto ts = ae1.type.isTypeSArray()) + { + sinteger_t dim = ts.dim.toInteger(); + + if (index < 0 || index > dim) + { + e.error("array index %lld is out of bounds `[0..%lld]`", index, dim); + return error(); + } + + import core.checkedint : mulu; + bool overflow; + const offset = mulu(index, ts.nextOf().size(e.loc), overflow); // offset = index*size + if (overflow) + { + e.error("array offset overflow"); + return error(); + } + + Expression ex = new AddrExp(ae1.loc, ae1); // &a[i] + ex.type = ae1.type.pointerTo(); + + Expression add = new AddExp(ae.loc, ex, new IntegerExp(ae.loc, offset, e.type)); + add.type = e.type; + ret = Expression_optimize(add, result, keepLvalue); + return; + } + } + // Convert &array[n] to &array+n if (ae.e2.isIntegerExp() && ae.e1.isVarExp()) { diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 4b9c0f2..15b7658 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -289,6 +289,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return true; } + /************************************ + * Parse declarations and definitions + * Params: + * once = !=0 means parse exactly one decl or def + * pLastDecl = set to last decl or def parsed + * pAttrs = keep track of attributes + * Returns: + * array of declared symbols + */ AST.Dsymbols* parseDeclDefs(int once, AST.Dsymbol* pLastDecl = null, PrefixAttributes!AST* pAttrs = null) { AST.Dsymbol lastDecl = null; // used to link unittest to its previous declaration @@ -480,7 +489,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * template instantiations in these unittests as candidates for * further codegen culling. */ - if (mod.isRoot() && (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)) + if (mod.isRoot() && (global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput)) { s = parseUnitTest(pAttrs); if (*pLastDecl) @@ -713,7 +722,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // The deprecation period is longer than usual as `body` // was quite widely used. if (tk.value == TOK.identifier && tk.ident == Id._body) - deprecation("Usage of the `body` keyword is deprecated. Use `do` instead."); + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); a = parseDeclarations(true, pAttrs, pAttrs.comment); if (a && a.dim) @@ -2649,7 +2658,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer /** Extract unittest body as a string. Must be done eagerly since memory will be released by the lexer before doc gen. */ char* docline = null; - if (global.params.doDocComments && endPtr > begPtr) + if (global.params.ddoc.doOutput && endPtr > begPtr) { /* Remove trailing whitespaces */ for (const(char)* p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p) @@ -4298,7 +4307,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * These can be: * 1. declarations at global/class level * 2. declarations at statement level - * Return array of Declaration *'s. + * Returns: + * array of Declarations. */ private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment) { @@ -4422,7 +4432,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // The deprecation period is longer than usual as `body` // was quite widely used. if (tk.value == TOK.identifier && tk.ident == Id._body) - deprecation("Usage of the `body` keyword is deprecated. Use `do` instead."); + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); ts = null; } @@ -4459,6 +4469,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else if (t != tfirst) error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars()); + if (token.value == TOK.colon && !ident && t.ty != Tfunction) + { + // Unnamed bit field + ident = Identifier.generateAnonymousId("BitField"); + } + bool isThis = (t.ty == Tident && (cast(AST.TypeIdentifier)t).ident == Id.This && token.value == TOK.assign); if (ident) checkCstyleTypeSyntax(loc, t, alt, ident); @@ -4591,6 +4607,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else if (ident) { + AST.Expression width; + if (token.value == TOK.colon) + { + nextToken(); + width = parseCondExp(); + } + AST.Initializer _init = null; if (token.value == TOK.assign) { @@ -4598,12 +4621,25 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer _init = parseInitializer(); } - auto v = new AST.VarDeclaration(loc, t, ident, _init); - v.storage_class = storage_class; - if (pAttrs) - pAttrs.storageClass = STC.undefined_; - - AST.Dsymbol s = v; + AST.Dsymbol s; + if (width) + { + if (!global.params.bitfields) + error("use -preview=bitfields for bitfield support"); + if (_init) + error("initializer not allowed for bit-field declaration"); + if (storage_class) + error("storage class not allowed for bit-field declaration"); + s = new AST.BitFieldDeclaration(width.loc, t, ident, width); + } + else + { + auto v = new AST.VarDeclaration(loc, t, ident, _init); + v.storage_class = storage_class; + if (pAttrs) + pAttrs.storageClass = STC.undefined_; + s = v; + } if (tpl && _init) { @@ -4616,7 +4652,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { auto ax = new AST.Dsymbols(); ax.push(s); - s = new AST.AlignDeclaration(v.loc, ealign, ax); + s = new AST.AlignDeclaration(s.loc, ealign, ax); } if (link != linkage) { @@ -4646,12 +4682,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: if (loc.linnum != token.loc.linnum) { - error("semicolon needed to end declaration of `%s`, instead of `%s`", v.toChars(), token.toChars()); - errorSupplemental(loc, "`%s` declared here", v.toChars()); + error("semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars()); + errorSupplemental(loc, "`%s` declared here", s.toChars()); } else { - error("semicolon needed to end declaration of `%s` instead of `%s`", v.toChars(), token.toChars()); + error("semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars()); } break; } @@ -4826,7 +4862,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (udas !is null) { if (storage_class != 0) - error("Cannot put a storage-class in an alias declaration."); + error("cannot put a storage-class in an alias declaration."); // parseAttributes shouldn't have set these variables assert(link == linkage && !setAlignment && ealign is null); auto tpl_ = cast(AST.TemplateDeclaration) s; @@ -5034,7 +5070,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer check(TOK.goesTo); if (token.value == TOK.leftCurly) { - deprecation("Using `(args) => { ... }` to create a delegate that returns a delegate is error-prone."); + deprecation("using `(args) => { ... }` to create a delegate that returns a delegate is error-prone."); deprecationSupplemental(token.loc, "Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate."); } const returnloc = token.loc; @@ -5100,7 +5136,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // Deprecated in 2.097 - Can be removed from 2.117 // The deprecation period is longer than usual as `body` // was quite widely used. - deprecation("Usage of the `body` keyword is deprecated. Use `do` instead."); + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); goto case TOK.do_; } goto default; @@ -7426,7 +7462,7 @@ LagainStc: // Deprecated in 2.097 - Can be removed from 2.117 // The deprecation period is longer than usual as `body` // was quite widely used. - deprecation("Usage of the `body` keyword is deprecated. Use `do` instead."); + deprecation("usage of the `body` keyword is deprecated. Use `do` instead."); goto case TOK.do_; } goto default; @@ -8026,7 +8062,7 @@ LagainStc: postfix = token.postfix; } - error("Implicit string concatenation is error-prone and disallowed in D"); + error("implicit string concatenation is error-prone and disallowed in D"); errorSupplemental(token.loc, "Use the explicit syntax instead " ~ "(concatenating literals is `@nogc`): %s ~ %s", prev.toChars(), token.toChars()); @@ -9580,18 +9616,18 @@ private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs) */ private bool writeMixin(const(char)[] s, ref Loc loc) { - if (!global.params.mixinOut) + if (!global.params.mixinOut.doOutput) return false; - OutBuffer* ob = global.params.mixinOut; + OutBuffer* ob = global.params.mixinOut.buffer; ob.writestring("// expansion at "); ob.writestring(loc.toChars()); ob.writenl(); - global.params.mixinLines++; + global.params.mixinOut.bufferLines++; - loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum); + loc = Loc(global.params.mixinOut.name.ptr, global.params.mixinOut.bufferLines + 1, loc.charnum); // write by line to create consistent line endings size_t lastpos = 0; @@ -9603,7 +9639,7 @@ private bool writeMixin(const(char)[] s, ref Loc loc) { ob.writestring(s[lastpos .. i]); ob.writenl(); - global.params.mixinLines++; + global.params.mixinOut.bufferLines++; if (c == '\r') ++i; lastpos = i + 1; @@ -9616,10 +9652,10 @@ private bool writeMixin(const(char)[] s, ref Loc loc) if (s.length == 0 || s[$-1] != '\n') { ob.writenl(); // ensure empty line after expansion - global.params.mixinLines++; + global.params.mixinOut.bufferLines++; } ob.writenl(); - global.params.mixinLines++; + global.params.mixinOut.bufferLines++; return true; } diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index bad071e..1c5275b 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -53,7 +53,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) { if (sc.intypeof || !sc.func || !sc.func.isSafeBypassingInference()) return false; - auto ad = v.toParent2().isAggregateDeclaration(); + auto ad = v.isMember2(); if (!ad) return false; @@ -64,23 +64,22 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) const hasPointers = v.type.hasPointers(); if (hasPointers) { - if (v.overlapped && sc.func.setUnsafe()) + if (v.overlapped) { - if (printmsg) - e.error("field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", - ad.toChars(), v.toChars()); - return true; + if (sc.func.setUnsafe(!printmsg, e.loc, + "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v)) + return true; } } if (v.type.hasInvariant()) { - if (v.overlapped && sc.func.setUnsafe()) + if (v.overlapped) { - if (printmsg) - e.error("field `%s.%s` cannot access structs with invariants in `@safe` code that overlap other fields", - ad.toChars(), v.toChars()); - return true; + if (sc.func.setUnsafe(!printmsg, e.loc, + "field `%s.%s` cannot access structs with invariants in `@safe` code that overlap other fields", + ad, v)) + return true; } } @@ -90,22 +89,22 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) if (hasPointers && v.type.toBasetype().ty != Tstruct) { if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize || - (v.offset & (target.ptrsize - 1))) && - sc.func.setUnsafe()) + (v.offset & (target.ptrsize - 1)))) { - if (printmsg) - e.error("field `%s.%s` cannot modify misaligned pointers in `@safe` code", - ad.toChars(), v.toChars()); - return true; + if (sc.func.setUnsafe(!printmsg, e.loc, + "field `%s.%s` cannot modify misaligned pointers in `@safe` code", ad, v)) + return true; } } - if (v.overlapUnsafe && sc.func.setUnsafe()) + if (v.overlapUnsafe) { - if (printmsg) - e.error("field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes", - ad.toChars(), v.toChars()); - return true; + if (sc.func.setUnsafe(!printmsg, e.loc, + "field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes", + ad, v)) + { + return true; + } } } return false; @@ -215,14 +214,12 @@ bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag) if (!(flag & DotExpFlag.noDeref) && // this use is attempting a dereference sc.func && // inside a function !sc.intypeof && // allow unsafe code in typeof expressions - !(sc.flags & SCOPE.debug_) && // allow unsafe code in debug statements - sc.func.setUnsafe()) // infer this function to be unsafe + !(sc.flags & SCOPE.debug_)) // allow unsafe code in debug statements { if (id == Id.ptr) - e.error("`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e.toChars(), e.toChars()); + return sc.func.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e); else - e.error("`%s.%s` cannot be used in `@safe` code", e.toChars(), id.toChars()); - return true; + return sc.func.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id); } return false; } diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index cd65920..73dcaa6 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -238,7 +238,7 @@ private extern(C++) final class Semantic2Visitor : Visitor return; } - UserAttributeDeclaration.checkGNUABITag(vd, vd.linkage); + UserAttributeDeclaration.checkGNUABITag(vd, vd._linkage); if (vd._init && !vd.toParent().isFuncDeclaration()) { @@ -379,6 +379,7 @@ private extern(C++) final class Semantic2Visitor : Visitor alias f1 = fd; auto tf1 = cast(TypeFunction) f1.type; auto parent1 = f1.toParent2(); + const linkage1 = f1.resolvedLinkage(); overloadApply(f1, (Dsymbol s) { @@ -391,7 +392,7 @@ private extern(C++) final class Semantic2Visitor : Visitor return 0; // Functions with different manglings can never conflict - if (f1.linkage != f2.linkage) + if (linkage1 != f2.resolvedLinkage()) return 0; // Functions with different names never conflict @@ -428,12 +429,12 @@ private extern(C++) final class Semantic2Visitor : Visitor // @@@DEPRECATED_2.104@@@ // Deprecated in 2020-08, make this an error in 2.104 if (parent1.isModule() && - f1.linkage != LINK.d && f1.linkage != LINK.cpp && + linkage1 != LINK.d && linkage1 != LINK.cpp && (!sameAttr || !sameParams) ) { f2.deprecation("cannot overload `extern(%s)` function at %s", - linkageToChars(f1.linkage), + linkageToChars(f1._linkage), f1.loc.toChars()); return 0; } @@ -443,7 +444,7 @@ private extern(C++) final class Semantic2Visitor : Visitor return 0; // Different attributes don't conflict in extern(D) - if (!sameAttr && f1.linkage == LINK.d) + if (!sameAttr && linkage1 == LINK.d) return 0; error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s", @@ -460,7 +461,7 @@ private extern(C++) final class Semantic2Visitor : Visitor return; TypeFunction f = cast(TypeFunction) fd.type; - UserAttributeDeclaration.checkGNUABITag(fd, fd.linkage); + UserAttributeDeclaration.checkGNUABITag(fd, fd._linkage); //semantic for parameters' UDAs foreach (i, param; f.parameterList) { @@ -643,7 +644,7 @@ private extern(C++) final class Semantic2Visitor : Visitor { //printf(" found\n"); // Check that calling conventions match - if (fd.linkage != ifd.linkage) + if (fd._linkage != ifd._linkage) fd.error("linkage doesn't match interface function"); // Check that it is current diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 5119576..a056c99 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -327,7 +327,7 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.scontinue = null; sc2.sw = null; sc2.fes = funcdecl.fes; - sc2.linkage = LINK.d; + sc2.linkage = funcdecl.isCsymbol() ? LINK.c : LINK.d; sc2.stc &= STC.flowThruFunction; sc2.visibility = Visibility(Visibility.Kind.public_); sc2.explicitVisibility = 0; @@ -1053,7 +1053,7 @@ private extern(C++) final class Semantic3Visitor : Visitor { if (!v._init) { - v.error("Zero-length `out` parameters are not allowed."); + v.error("zero-length `out` parameters are not allowed."); return; } ExpInitializer ie = v._init.isExpInitializer(); @@ -1277,70 +1277,7 @@ private extern(C++) final class Semantic3Visitor : Visitor f.isnogc = true; } - if (funcdecl.flags & FUNCFLAG.returnInprocess) - { - funcdecl.flags &= ~FUNCFLAG.returnInprocess; - if (funcdecl.storage_class & STC.return_) - { - if (funcdecl.type == f) - f = cast(TypeFunction)f.copy(); - f.isreturn = true; - f.isreturnscope = cast(bool) (funcdecl.storage_class & STC.returnScope); - if (funcdecl.storage_class & STC.returninferred) - f.isreturninferred = true; - } - } - - funcdecl.flags &= ~FUNCFLAG.inferScope; - - // Eliminate maybescope's - { - // Create and fill array[] with maybe candidates from the `this` and the parameters - VarDeclaration[10] tmp = void; - size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.dim : 0); - - import dmd.common.string : SmallBuffer; - auto sb = SmallBuffer!VarDeclaration(dim, tmp[]); - VarDeclaration[] array = sb[]; - - size_t n = 0; - if (funcdecl.vthis) - array[n++] = funcdecl.vthis; - if (funcdecl.parameters) - { - foreach (v; *funcdecl.parameters) - { - array[n++] = v; - } - } - eliminateMaybeScopes(array[0 .. n]); - } - - // Infer STC.scope_ - if (funcdecl.parameters && !funcdecl.errors) - { - assert(f.parameterList.length == funcdecl.parameters.dim); - foreach (u, p; f.parameterList) - { - auto v = (*funcdecl.parameters)[u]; - if (v.storage_class & STC.maybescope) - { - //printf("Inferring scope for %s\n", v.toChars()); - notMaybeScope(v); - v.storage_class |= STC.scope_ | STC.scopeinferred; - p.storageClass |= STC.scope_ | STC.scopeinferred; - assert(!(p.storageClass & STC.maybescope)); - } - } - } - - if (funcdecl.vthis && funcdecl.vthis.storage_class & STC.maybescope) - { - notMaybeScope(funcdecl.vthis); - funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred; - f.isScopeQual = true; - f.isscopeinferred = true; - } + finishScopeParamInference(funcdecl, f); // reset deco to apply inference result to mangled name if (f != funcdecl.type) @@ -1353,11 +1290,77 @@ private extern(C++) final class Semantic3Visitor : Visitor if (funcdecl.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665 f.isctor = true; sc.stc = 0; - sc.linkage = funcdecl.linkage; // https://issues.dlang.org/show_bug.cgi?id=8496 + sc.linkage = funcdecl._linkage; // https://issues.dlang.org/show_bug.cgi?id=8496 funcdecl.type = f.typeSemantic(funcdecl.loc, sc); sc = sc.pop(); } + // Check `extern(C++)` functions for invalid the return/parameter types + if (funcdecl._linkage == LINK.cpp) + { + static bool isCppNonMappableType(Type type, Parameter param = null, Type origType = null) + { + // Don't allow D `immutable` and `shared` types to be interfaced with C++ + if (type.isImmutable() || type.isShared()) + return true; + else if (Type cpptype = target.cpp.parameterType(type)) + type = cpptype; + + if (origType is null) + origType = type; + + // Permit types that are handled by toCppMangle. This list should be kept in sync with + // each visit method in dmd.cppmangle and dmd.cppmanglewin. + switch (type.ty) + { + case Tnull: + case Tnoreturn: + case Tvector: + case Tpointer: + case Treference: + case Tfunction: + case Tstruct: + case Tenum: + case Tclass: + case Tident: + case Tinstance: + break; + + case Tsarray: + if (!origType.isTypePointer()) + return true; + break; + + default: + if (!type.isTypeBasic()) + return true; + break; + } + + // Descend to the enclosing type + if (auto tnext = type.nextOf()) + return isCppNonMappableType(tnext, param, origType); + + return false; + } + if (isCppNonMappableType(f.next.toBasetype())) + { + funcdecl.error("cannot return type `%s` because its linkage is `extern(C++)`", f.next.toChars()); + funcdecl.errors = true; + } + foreach (i, param; f.parameterList) + { + if (isCppNonMappableType(param.type.toBasetype(), param)) + { + funcdecl.error("cannot have parameter of type `%s` because its linkage is `extern(C++)`", param.type.toChars()); + if (param.type.toBasetype().isTypeSArray()) + errorSupplemental(funcdecl.loc, "perhaps use a `%s*` type instead", + param.type.nextOf().mutableOf().unSharedOf().toChars()); + funcdecl.errors = true; + } + } + } + // Do live analysis if (global.params.useDIP1021 && funcdecl.fbody && funcdecl.type.ty != Terror && funcdecl.type.isTypeFunction().islive) @@ -1535,9 +1538,11 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.pop(); - // don't do it for unused deprecated types - // or error ypes - if (!ad.getRTInfo && Type.rtinfo && (!ad.isDeprecated() || global.params.useDeprecated != DiagnosticReporting.error) && (ad.type && ad.type.ty != Terror)) + // Instantiate RTInfo!S to provide a pointer bitmap for the GC + // Don't do it in -betterC or on unused deprecated / error types + if (!ad.getRTInfo && global.params.useTypeInfo && Type.rtinfo && + (!ad.isDeprecated() || global.params.useDeprecated != DiagnosticReporting.error) && + (ad.type && ad.type.ty != Terror)) { // Evaluate: RTinfo!type auto tiargs = new Objects(); diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 2916bbc..a7ad84f 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3554,13 +3554,13 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor if (!global.params.useExceptions) { - tcs.error("Cannot use try-catch statements with -betterC"); + tcs.error("cannot use try-catch statements with -betterC"); return setError(); } if (!ClassDeclaration.throwable) { - tcs.error("Cannot use try-catch statements because `object.Throwable` was not declared"); + tcs.error("cannot use try-catch statements because `object.Throwable` was not declared"); return setError(); } @@ -3762,13 +3762,13 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor { if (!global.params.useExceptions) { - loc.error("Cannot use `throw` statements with -betterC"); + loc.error("cannot use `throw` statements with -betterC"); return false; } if (!ClassDeclaration.throwable) { - loc.error("Cannot use `throw` statements because `object.Throwable` was not declared"); + loc.error("cannot use `throw` statements because `object.Throwable` was not declared"); return false; } @@ -3927,8 +3927,10 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not"); if (!(cas.stc & STC.nogc) && sc.func.setGC()) cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); - if (!(cas.stc & (STC.trusted | STC.safe)) && sc.func.setUnsafe()) - cas.error("`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); + if (!(cas.stc & (STC.trusted | STC.safe))) + { + sc.func.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); + } sc.pop(); result = cas; @@ -4032,10 +4034,10 @@ void catchSemantic(Catch c, Scope* sc) error(c.loc, "catching C++ class objects not supported for this target"); c.errors = true; } - if (sc.func && !sc.intypeof && !c.internalCatch && sc.func.setUnsafe()) + if (sc.func && !sc.intypeof && !c.internalCatch) { - error(c.loc, "cannot catch C++ class objects in `@safe` code"); - c.errors = true; + if (sc.func.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code")) + c.errors = true; } } else if (cd != ClassDeclaration.throwable && !ClassDeclaration.throwable.isBaseOf(cd, null)) @@ -4044,10 +4046,10 @@ void catchSemantic(Catch c, Scope* sc) c.errors = true; } else if (sc.func && !sc.intypeof && !c.internalCatch && ClassDeclaration.exception && - cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) && - sc.func.setUnsafe()) + cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) && + sc.func.setUnsafe(false, c.loc, + "can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type)) { - error(c.loc, "can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type.toChars()); c.errors = true; } else if (global.params.ehnogc) @@ -4829,7 +4831,7 @@ private Statement toStatement(Dsymbol s) } else { - .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars()); + .error(Loc.initial, "internal compiler error: cannot mixin %s `%s`\n", s.kind(), s.toChars()); result = new ErrorStatement(); } diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 03e8024..170a534 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -608,7 +608,7 @@ static immutable TOK[TOK.max + 1] Ckeywords = enum Ckwds = [ auto_, break_, case_, char_, const_, continue_, default_, do_, float64, else_, enum_, extern_, float32, for_, goto_, if_, inline, int32, int64, register, restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_, - union_, unsigned, void_, volatile, while_, asm_, + union_, unsigned, void_, volatile, while_, asm_, typeof_, _Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn, _Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __attribute__ ]; diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 04e1c47..be95432 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -132,6 +132,7 @@ shared static this() "getVirtualFunctions", "getVirtualMethods", "classInstanceSize", + "classInstanceAlignment", "allMembers", "derivedMembers", "isSame", @@ -1211,7 +1212,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) else assert(0); } - if (e.ident == Id.classInstanceSize) + if (e.ident == Id.classInstanceSize || e.ident == Id.classInstanceAlignment) { if (dim != 1) return dimError(1); @@ -1234,7 +1235,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) return ErrorExp.get(); } - return new IntegerExp(e.loc, cd.structsize, Type.tsize_t); + return new IntegerExp(e.loc, e.ident == Id.classInstanceSize ? cd.structsize : cd.alignsize, Type.tsize_t); } if (e.ident == Id.getAliasThis) { @@ -1381,7 +1382,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) e.error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o.toChars()); return ErrorExp.get(); } - link = fd.linkage; + link = fd._linkage; varargs = fd.getParameterList().varargs; } string style; @@ -1515,7 +1516,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) if (tf) { - link = fd ? fd.linkage : tf.linkage; + link = fd ? fd.toAliasFunc()._linkage : tf.linkage; } else { @@ -1529,7 +1530,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } if (d !is null) - link = d.linkage; + link = d._linkage; else { // Resolves forward references @@ -1574,7 +1575,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) auto s = getDsymbol(o); if (!s) { - e.error("In expression `%s` `%s` can't have members", e.toChars(), o.toChars()); + e.error("in expression `%s` `%s` can't have members", e.toChars(), o.toChars()); e.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", o.toChars()); return ErrorExp.get(); @@ -1595,7 +1596,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) auto sds = s.isScopeDsymbol(); if (!sds || sds.isTemplateDeclaration()) { - e.error("In expression `%s` %s `%s` has no members", e.toChars(), s.kind(), s.toChars()); + e.error("in expression `%s` %s `%s` has no members", e.toChars(), s.kind(), s.toChars()); e.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", s.toChars()); return ErrorExp.get(); } diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index f63b177..ac4c23b 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1154,7 +1154,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) //printf("already done\n"); return mtype; } - //printf("TypeFunction::semantic() this = %p\n", this); + //printf("TypeFunction::semantic() this = %p\n", mtype); //printf("TypeFunction::semantic() %s, sc.stc = %llx\n", mtype.toChars(), sc.stc); bool errors = false; @@ -1788,111 +1788,18 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) Type visitTraits(TypeTraits mtype) { - if (mtype.ty == Terror) - return mtype; - - const inAlias = (sc.flags & SCOPE.alias_) != 0; - if (mtype.exp.ident != Id.allMembers && - mtype.exp.ident != Id.derivedMembers && - mtype.exp.ident != Id.getMember && - mtype.exp.ident != Id.parent && - mtype.exp.ident != Id.parameters && - mtype.exp.ident != Id.child && - mtype.exp.ident != Id.toType && - mtype.exp.ident != Id.getOverloads && - mtype.exp.ident != Id.getVirtualFunctions && - mtype.exp.ident != Id.getVirtualMethods && - mtype.exp.ident != Id.getAttributes && - mtype.exp.ident != Id.getUnitTests && - mtype.exp.ident != Id.getAliasThis) - { - static immutable (const(char)*)[2] ctxt = ["as type", "in alias"]; - .error(mtype.loc, "trait `%s` is either invalid or not supported %s", - mtype.exp.ident.toChars, ctxt[inAlias]); - mtype.ty = Terror; - return mtype; - } - - import dmd.traits : semanticTraits; - Type result; - - if (Expression e = semanticTraits(mtype.exp, sc)) - { - switch (e.op) - { - case EXP.dotVariable: - mtype.sym = e.isDotVarExp().var; - break; - case EXP.variable: - mtype.sym = e.isVarExp().var; - break; - case EXP.function_: - auto fe = e.isFuncExp(); - mtype.sym = fe.td ? fe.td : fe.fd; - break; - case EXP.dotTemplateDeclaration: - mtype.sym = e.isDotTemplateExp().td; - break; - case EXP.dSymbol: - mtype.sym = e.isDsymbolExp().s; - break; - case EXP.template_: - mtype.sym = e.isTemplateExp().td; - break; - case EXP.scope_: - mtype.sym = e.isScopeExp().sds; - break; - case EXP.tuple: - TupleExp te = e.isTupleExp(); - Objects* elems = new Objects(te.exps.dim); - foreach (i; 0 .. elems.dim) - { - auto src = (*te.exps)[i]; - switch (src.op) - { - case EXP.type: - (*elems)[i] = src.isTypeExp().type; - break; - case EXP.dotType: - (*elems)[i] = src.isDotTypeExp().sym.isType(); - break; - case EXP.overloadSet: - (*elems)[i] = src.isOverExp().type; - break; - default: - if (auto sym = isDsymbol(src)) - (*elems)[i] = sym; - else - (*elems)[i] = src; - } - } - TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems); - mtype.sym = td; - break; - case EXP.dotType: - result = e.isDotTypeExp().sym.isType(); - break; - case EXP.type: - result = e.isTypeExp().type; - break; - case EXP.overloadSet: - result = e.isOverExp().type; - break; - default: - break; - } - } + Expression e; + Type t; + Dsymbol s; + mtype.resolve(loc, sc, e, t, s); - if (result) - result = result.addMod(mtype.mod); - if (!inAlias && !result) + if (!t) { if (!global.errors) .error(mtype.loc, "`%s` does not give a valid type", mtype.toChars); return error(); } - - return result; + return t; } Type visitReturn(TypeReturn mtype) @@ -3132,7 +3039,8 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type if (mt.exp.op == EXP.type || mt.exp.op == EXP.scope_) { - if (mt.exp.checkType()) + if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof + mt.exp.checkType()) goto Lerr; /* Today, 'typeof(func)' returns void if func is a @@ -3326,14 +3234,99 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type mt.obj = pe ? pe : (pt ? pt : ps); } - void visitTraits(TypeTraits tt) + void visitTraits(TypeTraits mt) { - if (Type t = typeSemantic(tt, loc, sc)) - returnType(t); - else if (tt.sym) - returnSymbol(tt.sym); + // if already resolved just return the cached object. + if (mt.obj) + { + pt = mt.obj.isType(); + ps = mt.obj.isDsymbol(); + return; + } + + import dmd.traits : semanticTraits; + + if (Expression e = semanticTraits(mt.exp, sc)) + { + switch (e.op) + { + case EXP.dotVariable: + mt.obj = e.isDotVarExp().var; + break; + case EXP.variable: + mt.obj = e.isVarExp().var; + break; + case EXP.function_: + auto fe = e.isFuncExp(); + mt.obj = fe.td ? fe.td : fe.fd; + break; + case EXP.dotTemplateDeclaration: + mt.obj = e.isDotTemplateExp().td; + break; + case EXP.dSymbol: + mt.obj = e.isDsymbolExp().s; + break; + case EXP.template_: + mt.obj = e.isTemplateExp().td; + break; + case EXP.scope_: + mt.obj = e.isScopeExp().sds; + break; + case EXP.tuple: + TupleExp te = e.isTupleExp(); + Objects* elems = new Objects(te.exps.dim); + foreach (i; 0 .. elems.dim) + { + auto src = (*te.exps)[i]; + switch (src.op) + { + case EXP.type: + (*elems)[i] = src.isTypeExp().type; + break; + case EXP.dotType: + (*elems)[i] = src.isDotTypeExp().sym.isType(); + break; + case EXP.overloadSet: + (*elems)[i] = src.isOverExp().type; + break; + default: + if (auto sym = isDsymbol(src)) + (*elems)[i] = sym; + else + (*elems)[i] = src; + } + } + TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems); + mt.obj = td; + break; + case EXP.dotType: + mt.obj = e.isDotTypeExp().sym.isType(); + break; + case EXP.type: + mt.obj = e.isTypeExp().type; + break; + case EXP.overloadSet: + mt.obj = e.isOverExp().type; + break; + default: + break; + } + } + + if (mt.obj) + { + if (auto t = mt.obj.isType()) + returnType(t.addMod(mt.mod)); + else if (auto s = mt.obj.isDsymbol()) + returnSymbol(s); + else + assert(0); + } else + { + mt.obj = Type.terror; return returnError(); + } } switch (mt.ty) @@ -3391,7 +3384,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) v.dsymbolSemantic(null); if (v.isField()) { - auto ad = v.toParent().isAggregateDeclaration(); + auto ad = v.isMember(); objc.checkOffsetof(e, ad); ad.size(e.loc); if (ad.sizeok != Sizeok.done) @@ -3637,12 +3630,16 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) } else { + Expression e0; + Expression ev = e; + ev = extractSideEffect(sc, "__tup", e0, ev); + const length = cast(size_t)mt.dim.toUInteger(); auto exps = new Expressions(); exps.reserve(length); foreach (i; 0 .. length) - exps.push(new IndexExp(e.loc, e, new IntegerExp(e.loc, i, Type.tsize_t))); - e = new TupleExp(e.loc, exps); + exps.push(new IndexExp(e.loc, ev, new IntegerExp(e.loc, i, Type.tsize_t))); + e = new TupleExp(e.loc, e0, exps); } } else diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d index 7f3fb64..5be4a19 100644 --- a/gcc/d/dmd/utils.d +++ b/gcc/d/dmd/utils.d @@ -84,7 +84,7 @@ extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data) ensurePathToNameExists(Loc.initial, filename); if (!File.update(filename, data)) { - error(loc, "Error writing file '%.*s'", cast(int) filename.length, filename.ptr); + error(loc, "error writing file '%.*s'", cast(int) filename.length, filename.ptr); fatal(); } } diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index c683d9d..7f5e683 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -847,53 +847,10 @@ public: } else { + /* Appending an element or array to another array has already been + handled by the front-end. */ gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray); - - if ((tb2->ty == TY::Tarray || tb2->ty == TY::Tsarray) - && same_type_p (etype, tb2->nextOf ()->toBasetype ())) - { - /* Append an array to another array: - The assignment is handled by the D run-time library, so only - need to call `_d_arrayappendT(ti, &e1, e2)' */ - result = build_libcall (LIBCALL_ARRAYAPPENDT, e->type, 3, - build_typeinfo (e->loc, e->type), - ptr, d_array_convert (e->e2)); - } - else if (same_type_p (etype, tb2)) - { - /* Append an element to an array: - The assignment is generated inline, so need to handle temporaries - here, and ensure that they are evaluated in the correct order. - - The generated code should end up being equivalent to: - _d_arrayappendcTX(ti, &e1, 1)[e1.length - 1] = e2 - */ - tree callexp = build_libcall (LIBCALL_ARRAYAPPENDCTX, e->type, 3, - build_typeinfo (e->loc, e->type), - ptr, size_one_node); - callexp = d_save_expr (callexp); - - /* Assign e2 to last element. */ - tree offexp = d_array_length (callexp); - offexp = build2 (MINUS_EXPR, TREE_TYPE (offexp), - offexp, size_one_node); - - tree ptrexp = d_array_ptr (callexp); - ptrexp = void_okay_p (ptrexp); - ptrexp = build_array_index (ptrexp, offexp); - - /* Evaluate expression before appending. */ - tree rhs = build_expr (e->e2); - tree rexpr = stabilize_expr (&rhs); - - if (TREE_CODE (rhs) == CALL_EXPR) - rhs = force_target_expr (rhs); - - result = modify_expr (build_deref (ptrexp), rhs); - result = compound_expr (rexpr, result); - } - else - gcc_unreachable (); + gcc_unreachable (); } /* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr; */ diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index b4b8152..c263582 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -340,6 +340,10 @@ fpreview=all D RejectNegative Turn on all upcoming D language features. +fpreview=bitfields +D RejectNegative +Implement D bit-fields. + fpreview=dip1000 D RejectNegative Implement DIP1000: Scoped pointers. @@ -412,10 +416,6 @@ frevert=intpromote D RejectNegative Use C-style integral promotion for unary '+', '-' and '~'. -frevert=markdown -D RejectNegative -Disable Markdown replacements in Ddoc. - frtti D ; Documented in C @@ -452,10 +452,6 @@ ftransition=tls D RejectNegative List all variables going into thread local storage. -ftransition=vmarkdown -D RejectNegative -List instances of Markdown replacements in Ddoc. - funittest D Compile in unittest code. diff --git a/gcc/d/types.cc b/gcc/d/types.cc index d897ec4..c54049d 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -375,7 +375,7 @@ fixup_anonymous_offset (tree fields, tree offset) /* Iterate over all MEMBERS of an aggregate, and add them as fields to CONTEXT. If INHERITED_P is true, then the members derive from a base class. - Returns the number of fields found. */ + Returns the number of named fields found. */ static size_t layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) @@ -418,7 +418,8 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) /* Insert the field declaration at its given offset. */ if (var->isField ()) { - const char *ident = var->ident ? var->ident->toChars () : NULL; + const char *ident = (var->ident && !var->ident->isAnonymous ()) + ? var->ident->toChars () : NULL; tree field = create_field_decl (declaration_type (var), ident, inherited_p, inherited_p); apply_user_attributes (var, field); @@ -442,7 +443,10 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) var->csym = field; } - fields += 1; + /* Only count the named fields in an aggregate. */ + if (ident != NULL) + fields += 1; + continue; } } diff --git a/gcc/testsuite/gdc.test/compilable/aggr_alignment.d b/gcc/testsuite/gdc.test/compilable/aggr_alignment.d index 0c727e2..7db9531 100644 --- a/gcc/testsuite/gdc.test/compilable/aggr_alignment.d +++ b/gcc/testsuite/gdc.test/compilable/aggr_alignment.d @@ -24,8 +24,8 @@ class C2 // overall alignment: max(vtbl.alignof, monitor.alignof, 1, 2) enum payloadOffset = C2.bytes.offsetof; static assert(C2.int1.offsetof == payloadOffset + 8); -static assert(C2.alignof == size_t.sizeof); -static assert(__traits(classInstanceSize, C2) == payloadOffset + 12); +static assert(__traits(classInstanceAlignment, C2) == size_t.sizeof); +static assert(__traits(classInstanceSize, C2) == payloadOffset + 12); // no tail padding align(8) struct PaddedStruct { @@ -37,6 +37,15 @@ static assert(PaddedStruct.s1.offsetof == 2); static assert(PaddedStruct.alignof == 8); static assert(PaddedStruct.sizeof == 16); +class AlignedPayloadClass +{ + align(64) int field; +} + +static assert(AlignedPayloadClass.field.offsetof == 64); // vtbl, monitor, alignment padding +static assert(__traits(classInstanceAlignment, AlignedPayloadClass) == 64); +static assert(__traits(classInstanceSize, AlignedPayloadClass) == 68); + align(1) struct UglyStruct { bool flag; diff --git a/gcc/testsuite/gdc.test/compilable/compile1.d b/gcc/testsuite/gdc.test/compilable/compile1.d index 40fba48..4678eb5 100644 --- a/gcc/testsuite/gdc.test/compilable/compile1.d +++ b/gcc/testsuite/gdc.test/compilable/compile1.d @@ -3,7 +3,7 @@ // EXTRA_FILES: imports/a12506.d /* TEST_OUTPUT: --- -compilable/compile1.d(229): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead +compilable/compile1.d(230): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead --- */ diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle.d b/gcc/testsuite/gdc.test/compilable/cppmangle.d index 8c112d1..fc74c94 100644 --- a/gcc/testsuite/gdc.test/compilable/cppmangle.d +++ b/gcc/testsuite/gdc.test/compilable/cppmangle.d @@ -1327,3 +1327,8 @@ extern (C++) static assert(funccpp.mangleof == "?funccpp@@YAHP6AXXZ@Z"); } } + +/*****************************************/ + +extern(C++) enum _LIBNAME = "library"; +extern(C++) enum _DEBUG = _LIBNAME.length && 'd' == _LIBNAME[$-1]; diff --git a/gcc/testsuite/gdc.test/compilable/dbitfield.d b/gcc/testsuite/gdc.test/compilable/dbitfield.d new file mode 100644 index 0000000..e2883fd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/dbitfield.d @@ -0,0 +1,88 @@ +/* REQUIRED_ARGS: -preview=bitfields + */ + +/***************************************************/ + +class C +{ + uint a:3; + uint b:1; + ulong c:64; + + int d:3; + int e:1; + long f:64; + + int i; +} + +static assert(C.a.min == 0); +static assert(C.a.max == 7); + +static assert(C.b.min == 0); +static assert(C.b.max == 1); + +static assert(C.c.min == 0); +static assert(C.c.max == ulong.max); + +static assert(C.d.min == -4); +static assert(C.d.max == 3); + +static assert(C.e.min == -1); +static assert(C.e.max == 0); + +static assert(C.f.min == long.min); +static assert(C.f.max == long.max); + +int testc() +{ + scope c = new C(); + c.d = 9; + return c.d; +} + +static assert(testc() == 1); + +/***************************************************/ + +union U +{ + uint a:3; + uint b:1; + ulong c:64; + + int d:3; + int e:1; + long f:64; + + int i; +} + +static assert(U.sizeof == 8); + +static assert(U.a.min == 0); +static assert(U.a.max == 7); + +static assert(U.b.min == 0); +static assert(U.b.max == 1); + +static assert(U.c.min == 0); +static assert(U.c.max == ulong.max); + +static assert(U.d.min == -4); +static assert(U.d.max == 3); + +static assert(U.e.min == -1); +static assert(U.e.max == 0); + +static assert(U.f.min == long.min); +static assert(U.f.max == long.max); + +int testu() +{ + U u; + u.d = 9; + return u.d; +} + +static assert(testu() == 1); diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d deleted file mode 100644 index 1ff26b0..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d +++ /dev/null @@ -1,13 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- -transition=vmarkdown -// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_breaks_verbose.html -// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_breaks_verbose.html - -/++ -Thematic Breaks - -___ -- - - -*** -+/ -module ddoc_markdown_breaks; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d deleted file mode 100644 index eb64c04..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d +++ /dev/null @@ -1,13 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown -// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_code_verbose.html -// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_code_verbose.html - -/++ -Code: - -``` ruby red -RWBY -``` -+/ -module test.compilable.ddoc_markdown_code_verbose; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d deleted file mode 100644 index 07904c1..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d +++ /dev/null @@ -1,13 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- -transition=vmarkdown -// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_emphasis_verbose.html -// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_emphasis_verbose.html - -/++ -Markdown Emphasis: - -*emphasized text* - -**strongly emphasized text** -+/ -module ddoc_markdown_emphasis; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d deleted file mode 100644 index 6448463..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d +++ /dev/null @@ -1,9 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown -// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_headings_verbose.html -// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_headings_verbose.html - -/++ -# Heading -+/ -module ddoc_markdown_headings_verbose; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d deleted file mode 100644 index 435b426..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d +++ /dev/null @@ -1,17 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown -// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_links_verbose.html -// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_links_verbose.html - -/++ -Links: - -A link to [Object]. -An inline link to [the D homepage](https://dlang.org). -A simple link to [dub]. -A slightly less simple link to [dub][]. -An image: ![D-Man](https://dlang.org/images/d3.png) - -[dub]: https://code.dlang.org -+/ -module test.compilable.ddoc_markdown_links_verbose; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d deleted file mode 100644 index 4fd1a80..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d +++ /dev/null @@ -1,9 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown -// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_lists_verbose.html -// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_lists_verbose.html - -/++ -- list item -+/ -module ddoc_markdown_lists_verbose; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d deleted file mode 100644 index f16e539..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d +++ /dev/null @@ -1,11 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown -// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_quote_verbose.html -// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_quote_verbose.html - -/++ -Quote Block: - -> Great, just what I need.. another D in programming. -- Segfault -+/ -module test.compilable.ddoc_markdown_code_verbose; diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d deleted file mode 100644 index d1aac1c..0000000 --- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d +++ /dev/null @@ -1,13 +0,0 @@ -// PERMUTE_ARGS: -// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown -// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_tables_verbose.html -// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_tables_verbose.html - -/++ -Table: - -| this | that | -| ---- | ---- | -| cell | cell | -+/ -module test.compilable.ddoc_markdown_tables_verbose; diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_21217.d b/gcc/testsuite/gdc.test/compilable/dtoh_21217.d index 8836ad1..3e535d2 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_21217.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_21217.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d index 10f5807..64198f9 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d @@ -10,9 +10,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration_98.d b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration_98.d index 1499d04..12edbd2 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration_98.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration_98.d @@ -7,9 +7,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d index 9d68631..20134f5 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d index 6995a67..870387c 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d index 4f13d2b..de4c7ba 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d index 4d56c7c..8c7ba9b 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d index e9e57da..35c4ed7 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_UnionDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_UnionDeclaration.d index b609cc2..48fcf72 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_UnionDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_UnionDeclaration.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d index 7356ba3..1faa51e 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_cpp98_compat.d b/gcc/testsuite/gdc.test/compilable/dtoh_cpp98_compat.d index b291cf6..cf1ae48 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_cpp98_compat.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_cpp98_compat.d @@ -10,9 +10,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_enum.d b/gcc/testsuite/gdc.test/compilable/dtoh_enum.d index 6a0dfd9..8b3e5aa 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_enum.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_enum.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_enum_cpp98.d b/gcc/testsuite/gdc.test/compilable/dtoh_enum_cpp98.d index 2330d76..6a266d9 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_enum_cpp98.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_enum_cpp98.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_expressions.d b/gcc/testsuite/gdc.test/compilable/dtoh_expressions.d index 7919c67..b93c47e 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_expressions.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_expressions.d @@ -7,9 +7,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d b/gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d index 0426a5e..83ac67d 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d @@ -9,9 +9,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d b/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d index 2f5b7df..c9d5bbc 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_functions.d b/gcc/testsuite/gdc.test/compilable/dtoh_functions.d index 1ee6ce6..1feff40 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_functions.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_functions.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE @@ -79,6 +79,8 @@ extern size_t baz5(size_t x = 42); extern size_t& bazRef(size_t& x); +extern size_t bazOut(size_t& x); + enum class E : int64_t { m = 1LL, @@ -219,6 +221,11 @@ extern (C++) ref size_t bazRef(return ref size_t x) return x; } +extern (C++) size_t bazOut(out size_t x) +{ + return x; +} + extern (C++): enum E : long diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d b/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d index d687673..d162a32 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d index c7d4c14..b8e8d05 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d @@ -17,9 +17,9 @@ compilable/dtoh_invalid_identifiers.d(145): Warning: function `__attribute__` is #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d b/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d index 44d0dd5..10967c8 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d @@ -7,9 +7,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_names.d b/gcc/testsuite/gdc.test/compilable/dtoh_names.d index 8a7eb7f..a4b055e 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_names.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_names.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_protection.d b/gcc/testsuite/gdc.test/compilable/dtoh_protection.d index 2180c41..3fd54c7 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_protection.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_protection.d @@ -9,9 +9,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d b/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d index d41cb1b..ab53764 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d @@ -7,9 +7,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d b/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d index a7c0a0d..37b4507 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_unittest_block.d b/gcc/testsuite/gdc.test/compilable/dtoh_unittest_block.d index ac58d0e..7b2943c 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_unittest_block.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_unittest_block.d @@ -8,9 +8,9 @@ TEST_OUTPUT: #pragma once #include <assert.h> +#include <math.h> #include <stddef.h> #include <stdint.h> -#include <math.h> #ifdef CUSTOM_D_ARRAY_TYPE #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_verbose.d b/gcc/testsuite/gdc.test/compilable/dtoh_verbose.d index 505ffdc..891ff0e 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_verbose.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_verbose.d @@ -10,9 +10,9 @@ TEST_OUTPUT: #pragma once
#include <assert.h>
+#include <math.h>
#include <stddef.h>
#include <stdint.h>
-#include <math.h>
#ifdef CUSTOM_D_ARRAY_TYPE
#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
diff --git a/gcc/testsuite/gdc.test/compilable/test17590.d b/gcc/testsuite/gdc.test/compilable/test17590.d index 6eec76f..3e00e9f 100644 --- a/gcc/testsuite/gdc.test/compilable/test17590.d +++ b/gcc/testsuite/gdc.test/compilable/test17590.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -o- +// REQUIRED_ARGS: -o- -preview=dip1000 void lazyfun(scope lazy int a) @nogc; diff --git a/gcc/testsuite/gdc.test/compilable/test20427.d b/gcc/testsuite/gdc.test/compilable/test20427.d new file mode 100644 index 0000000..074ed12 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test20427.d @@ -0,0 +1,3 @@ +// https://issues.dlang.org/show_bug.cgi?id=20427 +extern(C++) void test20427(T)(T) {} +static assert(!__traits(compiles, { test20427([1, 2]); })); diff --git a/gcc/testsuite/gdc.test/compilable/test23047.d b/gcc/testsuite/gdc.test/compilable/test23047.d new file mode 100644 index 0000000..e1ac3e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23047.d @@ -0,0 +1,13 @@ +/* REQUIRED_ARGS: -defaultlib= -c -O + */ + +// https://issues.dlang.org/show_bug.cgi?id=23047 +version(D_SIMD): +alias long2 = __vector(long[2]); + +long2 _mm_srl_epi64 () +{ + long2 r = void; + r[0] = 1; + return r; +} diff --git a/gcc/testsuite/gdc.test/compilable/test23087.d b/gcc/testsuite/gdc.test/compilable/test23087.d new file mode 100644 index 0000000..6927ddf --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23087.d @@ -0,0 +1,9 @@ +// https://issues.dlang.org/show_bug.cgi?id=23087 +struct S +{ + this(bool) {} + this(bool, int) {} +} + +static foreach (ctor; __traits(getOverloads, S, "__ctor")) + static assert(__traits(getLinkage, ctor) == "D"); diff --git a/gcc/testsuite/gdc.test/compilable/test23089.d b/gcc/testsuite/gdc.test/compilable/test23089.d new file mode 100644 index 0000000..1bc2913 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23089.d @@ -0,0 +1,7 @@ +// https://issues.dlang.org/show_bug.cgi?id=23089 +extern(System) int i23089; + +extern(System): + +alias F23089 = void function(int); +F23089 f23089; diff --git a/gcc/testsuite/gdc.test/compilable/test23097.d b/gcc/testsuite/gdc.test/compilable/test23097.d new file mode 100644 index 0000000..092bd77 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23097.d @@ -0,0 +1,33 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23097 +REQUIRED_ARGS: -verrors=spec +TEST_OUTPUT: +--- +(spec:2) compilable/test23097.d(14): Error: `inout` constructor `test23097.S23097.this` creates const object, not mutable +(spec:2) compilable/test23097.d(14): Error: `inout` constructor `test23097.S23097.this` creates const object, not mutable +(spec:1) compilable/test23097.d(14): Error: generated function `test23097.S23097.opAssign(S23097 p)` is not callable using argument types `(const(S23097))` +(spec:2) compilable/test23097.d(14): Error: `inout` constructor `test23097.S23097.this` creates const object, not mutable +(spec:1) compilable/test23097.d(14): `struct S23097` does not define a copy constructor for `const(S23097)` to `S23097` copies +--- +*/ +void emplaceRef(UT, Args)(UT chunk, Args args) +{ + static if (__traits(compiles, chunk = args)) + chunk = args; +} + +struct CpCtor23097(T) +{ + T* payload; + this(ref inout typeof(this)) { } + ref opAssign(typeof(this)) { } +} + +struct S23097 +{ + CpCtor23097!int payload; +} + +void test23097(S23097 lhs, const S23097 rhs) +{ + emplaceRef(lhs, rhs); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23105.d b/gcc/testsuite/gdc.test/compilable/test23105.d new file mode 100644 index 0000000..8595e37 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23105.d @@ -0,0 +1,6 @@ +// https://issues.dlang.org/show_bug.cgi?id=23105 + +module test23105; + +static assert(is(mixin(`__traits(getMember, test23105, "object")`) == module)); +static assert(is(__traits(getMember, test23105, "object") == module)); // Fixed diff --git a/gcc/testsuite/gdc.test/compilable/test3004.d b/gcc/testsuite/gdc.test/compilable/test3004.d index baa0cd7..9912b88 100644 --- a/gcc/testsuite/gdc.test/compilable/test3004.d +++ b/gcc/testsuite/gdc.test/compilable/test3004.d @@ -1,13 +1,15 @@ // https://issues.dlang.org/show_bug.cgi?id=3004 /* REQUIRED_ARGS: -ignore -v -TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|import|semantic|entry|function object|\s*$)") +TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|import|semantic|entry|library|function object|\s*$)") TEST_OUTPUT: --- pragma GNU_attribute (__error) pragma GNU_attribute (__error) code test3004 function test3004.test +function core.internal.array.appending._d_arrayappendcTXImpl!(char[], char)._d_arrayappendcTX +function core.internal.array.utils._d_HookTraceImpl!(char[], _d_arrayappendcTX, "Cannot append to array if compiling without support for runtime type information!")._d_HookTraceImpl --- */ diff --git a/gcc/testsuite/gdc.test/compilable/vcg-ast.d b/gcc/testsuite/gdc.test/compilable/vcg-ast.d index 4673677..cbb150c 100644 --- a/gcc/testsuite/gdc.test/compilable/vcg-ast.d +++ b/gcc/testsuite/gdc.test/compilable/vcg-ast.d @@ -52,8 +52,7 @@ alias wchar_t = __c_wchar_t; T[] values(T)() { - T[] values; - values ~= T(); + T[] values = [T()]; return values; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d new file mode 100644 index 0000000..1fdf5a5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d @@ -0,0 +1,23 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/attributediagnostic.d(16): Error: `@safe` function `attributediagnostic.layer2` cannot call `@system` function `attributediagnostic.layer1` +fail_compilation/attributediagnostic.d(18): which calls `attributediagnostic.layer0` +fail_compilation/attributediagnostic.d(20): which calls `attributediagnostic.system` +fail_compilation/attributediagnostic.d(22): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(22): `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not +fail_compilation/attributediagnostic.d(17): `attributediagnostic.layer1` is declared here +--- +*/ + +// Issue 17374 - Improve inferred attribute error message +// https://issues.dlang.org/show_bug.cgi?id=17374 + +auto layer2() @safe { layer1(); } +auto layer1() { layer0(); } +auto layer0() { system(); } + +auto system() +{ + asm {} +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/b6227.d b/gcc/testsuite/gdc.test/fail_compilation/b6227.d index a9b2a50..c975a43 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b6227.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b6227.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/b6227.d(16): Error: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` +fail_compilation/b6227.d(16): Error: comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` fail_compilation/b6227.d(16): while evaluating: `static assert(!(X.O != Y.U))` -fail_compilation/b6227.d(17): Error: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` +fail_compilation/b6227.d(17): Error: comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType` fail_compilation/b6227.d(17): while evaluating: `static assert(X.O == Y.U)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/betterc.d b/gcc/testsuite/gdc.test/fail_compilation/betterc.d index e1cc4cf..6f4fb03 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/betterc.d +++ b/gcc/testsuite/gdc.test/fail_compilation/betterc.d @@ -1,8 +1,8 @@ /* REQUIRED_ARGS: -betterC * TEST_OUTPUT: --- -fail_compilation/betterc.d(12): Error: Cannot use `throw` statements with -betterC -fail_compilation/betterc.d(17): Error: Cannot use try-catch statements with -betterC +fail_compilation/betterc.d(12): Error: cannot use `throw` statements with -betterC +fail_compilation/betterc.d(17): Error: cannot use try-catch statements with -betterC fail_compilation/betterc.d(29): Error: `TypeInfo` cannot be used with -betterC --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/biterrors.d b/gcc/testsuite/gdc.test/fail_compilation/biterrors.d new file mode 100644 index 0000000..a8f0faa --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/biterrors.d @@ -0,0 +1,15 @@ +/* REQUIRED_ARGS: -preview=bitfields + * TEST_OUTPUT: +--- +fail_compilation/biterrors.d(103): Error: initializer not allowed for bit-field declaration +fail_compilation/biterrors.d(104): Error: storage class not allowed for bit-field declaration +--- + */ + +#line 100 + +struct S +{ + int i : 3 = 7; + static int j : 3; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/biterrors2.d b/gcc/testsuite/gdc.test/fail_compilation/biterrors2.d new file mode 100644 index 0000000..c8390ba --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/biterrors2.d @@ -0,0 +1,17 @@ +/* REQUIRED_ARGS: -preview=bitfields + * TEST_OUTPUT: +--- +fail_compilation/biterrors2.d(100): Error: variable `biterrors2.a` bit-field must be member of struct, union, or class +fail_compilation/biterrors2.d(104): Error: bit-field `b` has zero width +fail_compilation/biterrors2.d(105): Error: bit-field type `float` is not an integer type +--- +*/ + +#line 100 +int a : 2; + +struct S +{ + int b:0; + float c:3; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/biterrors3.d b/gcc/testsuite/gdc.test/fail_compilation/biterrors3.d new file mode 100644 index 0000000..f9e1df2 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/biterrors3.d @@ -0,0 +1,18 @@ +/* REQUIRED_ARGS: -preview=bitfields + * TEST_OUTPUT: +--- +fail_compilation/biterrors3.d(103): Error: storage class not allowed for bit-field declaration +fail_compilation/biterrors3.d(106): Error: `d` is not a valid attribute for enum members +fail_compilation/biterrors3.d(106): Error: `:` is not a valid attribute for enum members +fail_compilation/biterrors3.d(106): Error: `3` is not a valid attribute for enum members +--- +*/ + +#line 100 + +struct S +{ + static int : 3; +} + +enum E { d : 3 } diff --git a/gcc/testsuite/gdc.test/fail_compilation/biterrors4.d b/gcc/testsuite/gdc.test/fail_compilation/biterrors4.d new file mode 100644 index 0000000..0f2ca2d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/biterrors4.d @@ -0,0 +1,19 @@ +/* REQUIRED_ARGS: -preview=bitfields + * TEST_OUTPUT: +--- +fail_compilation/biterrors4.d(109): Error: cannot take address of bit-field `a` +--- +*/ + +#line 100 + +struct S +{ + int a:3; +} + +void test() +{ + S s; + int* p = &s.a; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/commaexp.d b/gcc/testsuite/gdc.test/fail_compilation/commaexp.d index 7d50223..3874fb1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/commaexp.d +++ b/gcc/testsuite/gdc.test/fail_compilation/commaexp.d @@ -1,16 +1,16 @@ /* REQUIRED_ARGS: -o- TEST_OUTPUT: --- -fail_compilation/commaexp.d(27): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(39): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(40): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(41): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(42): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(44): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(45): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(56): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(69): Error: Using the result of a comma expression is not allowed -fail_compilation/commaexp.d(81): Error: Using the result of a comma expression is not allowed +fail_compilation/commaexp.d(27): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(39): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(40): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(41): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(42): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(44): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(45): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(56): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(69): Error: using the result of a comma expression is not allowed +fail_compilation/commaexp.d(81): Error: using the result of a comma expression is not allowed --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/cppvar.d b/gcc/testsuite/gdc.test/fail_compilation/cppvar.d new file mode 100644 index 0000000..885a555 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/cppvar.d @@ -0,0 +1,22 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/cppvar.d(10): Error: variable `cppvar.funcLiteral` cannot have `extern(C++)` linkage because it is `static` +fail_compilation/cppvar.d(10): perhaps declare it as `__gshared` instead +fail_compilation/cppvar.d(20): Error: variable `cppvar.threadLocalVar` cannot have `extern(C++)` linkage because it is `static` +fail_compilation/cppvar.d(20): perhaps declare it as `__gshared` instead +fail_compilation/cppvar.d(21): Error: variable `cppvar.staticVar` cannot have `extern(C++)` linkage because it is `static` +fail_compilation/cppvar.d(21): perhaps declare it as `__gshared` instead +fail_compilation/cppvar.d(22): Error: variable `cppvar.sharedVar` cannot have `extern(C++)` linkage because it is `shared` +fail_compilation/cppvar.d(22): perhaps declare it as `__gshared` instead +fail_compilation/cppvar.d(30): Error: delegate `cppvar.__lambda7` cannot return type `bool[3]` because its linkage is `extern(C++)` +--- +*/ +#line 10 +extern(C++) bool[3] funcLiteral = () { bool[3] a; return a; }; +#line 20 +extern(C++) int threadLocalVar; +extern(C++) static int staticVar; +extern(C++) shared int sharedVar; +#line 30 +extern(C++) __gshared bool[3] gfuncLiteral = () { bool[3] a; return a; }; diff --git a/gcc/testsuite/gdc.test/fail_compilation/dbitfields.d b/gcc/testsuite/gdc.test/fail_compilation/dbitfields.d new file mode 100644 index 0000000..0dd1a0b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/dbitfields.d @@ -0,0 +1,32 @@ +/* REQUIRED_ARGS: -preview=bitfields + * TEST_OUTPUT: +--- +fail_compilation/dbitfields.d(118): Error: reinterpretation through overlapped field `e` is not allowed in CTFE +fail_compilation/dbitfields.d(121): called from here: `testu()` +fail_compilation/dbitfields.d(121): while evaluating: `static assert(testu() == 1)` +--- + */ + +#line 100 + +union U +{ + uint a:3; + uint b:1; + ulong c:64; + + int d:3; + int e:1; + long f:64; + + int i; +} + +int testu() +{ + U u; + u.d = 9; + return u.e; +} + +static assert(testu() == 1); diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d index ed38167..932aa5c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag10805.d(12): Error: delimited string must end in `FOO"` fail_compilation/diag10805.d(14): Error: unterminated string constant starting at fail_compilation/diag10805.d(14) -fail_compilation/diag10805.d(14): Error: Implicit string concatenation is error-prone and disallowed in D +fail_compilation/diag10805.d(14): Error: implicit string concatenation is error-prone and disallowed in D fail_compilation/diag10805.d(14): Use the explicit syntax instead (concatenating literals is `@nogc`): "" ~ "" fail_compilation/diag10805.d(15): Error: semicolon expected following auto declaration, not `End of File` --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d index 00949f1..3e15497 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d @@ -24,7 +24,7 @@ fail_compilation/diag10862.d(74): Error: assignment cannot be used as a conditio fail_compilation/diag10862.d-mixin-77(77): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-78(78): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-79(79): Error: assignment cannot be used as a condition, perhaps `==` was meant? -fail_compilation/diag10862.d-mixin-80(80): Error: Using the result of a comma expression is not allowed +fail_compilation/diag10862.d-mixin-80(80): Error: using the result of a comma expression is not allowed fail_compilation/diag10862.d-mixin-80(80): Error: assignment cannot be used as a condition, perhaps `==` was meant? fail_compilation/diag10862.d-mixin-83(83): Error: `a + b` is not an lvalue and cannot be modified fail_compilation/diag10862.d-mixin-84(84): Error: undefined identifier `c` diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip25.d b/gcc/testsuite/gdc.test/fail_compilation/dip25.d index 4f8ea23..41bfe49 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dip25.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dip25.d @@ -12,15 +12,15 @@ fail_compilation/dip25.d(23): perhaps annotate the parameter with `return struct Data { char[256] buffer; - @property const(char)[] filename() const pure nothrow + @property const(char)[] filename() const pure nothrow @safe { return buffer[]; } } -ref int identity(return ref int x) { return x; } +ref int identity(return ref int x) @safe { return x; } ref int fun(return int x) { return identity(x); } -ref int fun2(ref int x) { return identity(x); } +ref int fun2(ref int x) @safe { return identity(x); } void main() { diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d index 21a12ed..ce81d6b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d @@ -8,6 +8,8 @@ fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is impu fail_compilation/dtor_attributes.d(111): - HasDtor member fail_compilation/dtor_attributes.d(103): impure `HasDtor.~this` is declared here fail_compilation/dtor_attributes.d(118): Error: `@safe` function `dtor_attributes.test1` cannot call `@system` destructor `dtor_attributes.Strict.~this` +fail_compilation/dtor_attributes.d(113): which calls `dtor_attributes.Strict.~this` +fail_compilation/dtor_attributes.d(103): which calls `dtor_attributes.HasDtor.~this` fail_compilation/dtor_attributes.d(113): `dtor_attributes.Strict.~this` is declared here fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is @system because of the following field's destructors: fail_compilation/dtor_attributes.d(111): - HasDtor member diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d index f6cab89..45b23ce 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d @@ -9,6 +9,7 @@ fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` i fail_compilation/dtorfields_attributes.d(115): - HasDtor member fail_compilation/dtorfields_attributes.d(103): impure `HasDtor.~this` is declared here fail_compilation/dtorfields_attributes.d(117): Error: `@safe` constructor `dtorfields_attributes.Strict.this` cannot call `@system` destructor `dtorfields_attributes.Strict.~this` +fail_compilation/dtorfields_attributes.d(103): which calls `dtorfields_attributes.HasDtor.~this` fail_compilation/dtorfields_attributes.d(119): `dtorfields_attributes.Strict.~this` is declared here fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` is @system because of the following field's destructors: fail_compilation/dtorfields_attributes.d(115): - HasDtor member diff --git a/gcc/testsuite/gdc.test/fail_compilation/e7804_1.d b/gcc/testsuite/gdc.test/fail_compilation/e7804_1.d index 38c25fb..1dfcf44 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/e7804_1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/e7804_1.d @@ -1,11 +1,18 @@ /* TEST_OUTPUT: --- -fail_compilation/e7804_1.d(10): Error: trait `farfelu` is either invalid or not supported as type -fail_compilation/e7804_1.d(11): Error: trait `farfelu` is either invalid or not supported in alias +fail_compilation/e7804_1.d(14): Error: undefined identifier `Aggr` +fail_compilation/e7804_1.d(15): Error: unrecognized trait `farfelu` +fail_compilation/e7804_1.d(17): Error: undefined identifier `Aggr` +fail_compilation/e7804_1.d(18): Error: unrecognized trait `farfelu` --- */ module e7804_1; +struct S {} + __traits(farfelu, Aggr, "member") a; +__traits(farfelu, S, "member") a2; + alias foo = __traits(farfelu, Aggr, "member"); +alias foo2 = __traits(farfelu, S, "member"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/extra-files/test23109/object.d b/gcc/testsuite/gdc.test/fail_compilation/extra-files/test23109/object.d new file mode 100644 index 0000000..747b6e9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/extra-files/test23109/object.d @@ -0,0 +1,17 @@ +module object; + +alias size_t = typeof(int.sizeof); +class Object {} +auto opEquals(Object ) { return true; } +class TypeInfo {} +class TypeInfo_Const {} +bool _xopEquals() { return true; } + +bool __equals(T1, T2)(T1[] lhs, T2[] rhs) +{ + static at(R)(R[] r, size_t i) { return r.ptr[i]; } + foreach (u; 0 .. lhs.length) + if (at(lhs, u) != at(rhs, u)) + return false; + return true; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail109.d b/gcc/testsuite/gdc.test/fail_compilation/fail109.d index 3419079..7caae59 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail109.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail109.d @@ -34,7 +34,7 @@ enum E1 : short /* https://issues.dlang.org/show_bug.cgi?id=14950 TEST_OUTPUT: --- -fail_compilation/fail109.d(50): Error: Comparison between different enumeration types `B` and `C`; If this behavior is intended consider using `std.conv.asOriginalType` +fail_compilation/fail109.d(50): Error: comparison between different enumeration types `B` and `C`; If this behavior is intended consider using `std.conv.asOriginalType` fail_compilation/fail109.d(50): Error: enum member `fail109.B.end` initialization with `B.start+1` causes overflow for type `C` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12604.d b/gcc/testsuite/gdc.test/fail_compilation/fail12604.d index 2ed8ebf..bed8735 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12604.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12604.d @@ -66,8 +66,8 @@ void test12606b() // ExpInitializer::semantic /* TEST_OUTPUT: --- -fail_compilation/fail12604.d(77): Error: mismatched array lengths, 4 and 3 -fail_compilation/fail12604.d(78): Error: mismatched array lengths, 4 and 3 +fail_compilation/fail12604.d(77): Error: mismatched array lengths 4 and 3 for assignment `sa1[0..4] = [1, 2, 3]` +fail_compilation/fail12604.d(78): Error: mismatched array lengths 4 and 3 for assignment `sa1[0..4] = sa2` --- */ void testc() diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d index 12a6b6e..47cb65c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d @@ -8,11 +8,11 @@ class C { int v; } /* TEST_OUTPUT: --- -fail_compilation/fail13902.d(45): Error: Using the result of a comma expression is not allowed +fail_compilation/fail13902.d(45): Error: using the result of a comma expression is not allowed fail_compilation/fail13902.d(32): Error: returning `& x` escapes a reference to local variable `x` fail_compilation/fail13902.d(33): Error: returning `&s1.v` escapes a reference to local variable `s1` fail_compilation/fail13902.d(38): Error: returning `& sa1` escapes a reference to local variable `sa1` -fail_compilation/fail13902.d(39): Error: returning `&sa2[0][0]` escapes a reference to local variable `sa2` +fail_compilation/fail13902.d(39): Error: returning `& sa2` escapes a reference to local variable `sa2` fail_compilation/fail13902.d(40): Error: returning `& x` escapes a reference to local variable `x` fail_compilation/fail13902.d(41): Error: returning `(& x+4)` escapes a reference to local variable `x` fail_compilation/fail13902.d(42): Error: returning `& x + cast(long)x * 4L` escapes a reference to local variable `x` @@ -53,11 +53,11 @@ int* testEscape1() /* TEST_OUTPUT: --- -fail_compilation/fail13902.d(88): Error: Using the result of a comma expression is not allowed +fail_compilation/fail13902.d(88): Error: using the result of a comma expression is not allowed fail_compilation/fail13902.d(75): Error: returning `& x` escapes a reference to parameter `x` fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to parameter `s1` fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to parameter `sa1` -fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to parameter `sa2` +fail_compilation/fail13902.d(82): Error: returning `& sa2` escapes a reference to parameter `sa2` fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to parameter `x` fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to parameter `x` fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to parameter `x` @@ -98,7 +98,7 @@ int* testEscape2( /* TEST_OUTPUT: --- -fail_compilation/fail13902.d(123): Error: Using the result of a comma expression is not allowed +fail_compilation/fail13902.d(123): Error: using the result of a comma expression is not allowed --- */ int* testEscape3( diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16001.d b/gcc/testsuite/gdc.test/fail_compilation/fail16001.d index dc480cf..9d0b96f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail16001.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16001.d @@ -2,7 +2,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail16001.d(10): Deprecation: Using `(args) => { ... }` to create a delegate that returns a delegate is error-prone. +fail_compilation/fail16001.d(10): Deprecation: using `(args) => { ... }` to create a delegate that returns a delegate is error-prone. fail_compilation/fail16001.d(10): Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate. --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16575.d b/gcc/testsuite/gdc.test/fail_compilation/fail16575.d new file mode 100644 index 0000000..7f66724 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16575.d @@ -0,0 +1,65 @@ +// https://issues.dlang.org/show_bug.cgi?id=16575 +/* +REQUIRED_ARGS: -m64 +TEST_OUTPUT: +--- +fail_compilation/fail16575.d(10): Error: function `fail16575.immNull` cannot have parameter of type `immutable(typeof(null))*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(11): Error: function `fail16575.shaNull` cannot have parameter of type `shared(typeof(null))*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(20): Error: function `fail16575.immNoReturn` cannot have parameter of type `immutable(noreturn)*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(21): Error: function `fail16575.shaNoReturn` cannot have parameter of type `shared(noreturn)*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(30): Error: function `fail16575.immBasic` cannot have parameter of type `immutable(int)*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(31): Error: function `fail16575.shaBasic` cannot have parameter of type `shared(int)*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(40): Error: function `fail16575.immVector` cannot have parameter of type `immutable(__vector(long[2]))*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(41): Error: function `fail16575.shaVector` cannot have parameter of type `shared(__vector(long[2]))*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(50): Error: function `fail16575.immSArray` cannot have parameter of type `immutable(long[2])` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(50): perhaps use a `long*` type instead +fail_compilation/fail16575.d(51): Error: function `fail16575.shaSArray` cannot have parameter of type `shared(long[2])` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(51): perhaps use a `long*` type instead +fail_compilation/fail16575.d(60): Error: function `fail16575.immPointer` cannot have parameter of type `immutable(int*)` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(61): Error: function `fail16575.shaPointer` cannot have parameter of type `shared(int*)` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(71): Error: function `fail16575.immStruct` cannot have parameter of type `immutable(SPP)*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(72): Error: function `fail16575.shaStruct` cannot have parameter of type `shared(SPP)*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(81): Error: function `fail16575.immClass` cannot have parameter of type `immutable(CPP)` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(82): Error: function `fail16575.shaClass` cannot have parameter of type `shared(CPP)` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(91): Error: function `fail16575.immEnum` cannot have parameter of type `immutable(EPP)*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(92): Error: function `fail16575.shaEnum` cannot have parameter of type `shared(EPP)*` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(100): Error: function `fail16575.typeDArray` cannot have parameter of type `int[]` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(101): Error: function `fail16575.typeAArray` cannot have parameter of type `int[int]` because its linkage is `extern(C++)` +fail_compilation/fail16575.d(102): Error: function `fail16575.typeDelegate` cannot have parameter of type `extern (C++) int delegate()` because its linkage is `extern(C++)` +--- +*/ + +#line 10 +extern(C++) void immNull(immutable(typeof(null))* a) {} +extern(C++) void shaNull(shared(typeof(null))* a) {} +#line 20 +extern(C++) void immNoReturn(immutable(typeof(*null))* a) {} +extern(C++) void shaNoReturn(shared(typeof(*null))* a) {} +#line 30 +extern(C++) void immBasic(immutable(int)* a) {} +extern(C++) void shaBasic(shared(int)* a) {} +#line 40 +extern(C++) void immVector(immutable(__vector(long[2]))* a) {} +extern(C++) void shaVector(shared(__vector(long[2]))* a) {} +#line 50 +extern(C++) void immSArray(immutable(long[2]) a) {} +extern(C++) void shaSArray(shared(long[2]) a) {} +#line 60 +extern(C++) void immPointer(immutable(int*) a) {} +extern(C++) void shaPointer(shared(int*) a) {} +#line 70 +extern(C++) struct SPP {} +extern(C++) void immStruct(immutable(SPP)* a) {} +extern(C++) void shaStruct(shared(SPP)* a) {} +#line 80 +extern(C++) class CPP {} +extern(C++) void immClass(immutable CPP a) {} +extern(C++) void shaClass(shared CPP a) {} +#line 90 +extern(C++) enum EPP {a} +extern(C++) void immEnum(immutable(EPP)* a) {} +extern(C++) void shaEnum(shared(EPP)* a) {} +# line 100 +extern(C++) void typeDArray(int[] a) {} +extern(C++) void typeAArray(int[int] a) {} +extern(C++) void typeDelegate(int delegate() a) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16772.d b/gcc/testsuite/gdc.test/fail_compilation/fail16772.d new file mode 100644 index 0000000..e77951d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16772.d @@ -0,0 +1,7 @@ +// https://issues.dlang.org/show_bug.cgi?id=16772 +/* TEST_OUTPUT: +--- +fail_compilation/fail16772.d(7): Error: function `fail16772.ice16772` cannot return type `ubyte[]` because its linkage is `extern(C++)` +--- +*/ +extern(C++) ubyte[] ice16772() { return []; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail196.d b/gcc/testsuite/gdc.test/fail_compilation/fail196.d index 55c3bd8..2c7d93f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail196.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail196.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail196.d(27): Error: delimited string must end in `)"` -fail_compilation/fail196.d(27): Error: Implicit string concatenation is error-prone and disallowed in D +fail_compilation/fail196.d(27): Error: implicit string concatenation is error-prone and disallowed in D fail_compilation/fail196.d(27): Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\n assert(s == " fail_compilation/fail196.d(28): Error: semicolon needed to end declaration of `s`, instead of `foo` fail_compilation/fail196.d(27): `s` declared here diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19759.d b/gcc/testsuite/gdc.test/fail_compilation/fail19759.d new file mode 100644 index 0000000..cdb65ae --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19759.d @@ -0,0 +1,8 @@ +// https://issues.dlang.org/show_bug.cgi?id=19759 +/* TEST_OUTPUT: +--- +fail_compilation/fail19759.d(8): Error: function `fail19759.fail19759` cannot have parameter of type `float[4]` because its linkage is `extern(C++)` +fail_compilation/fail19759.d(8): perhaps use a `float*` type instead +--- +*/ +extern(C++) bool fail19759(float[4] col); diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19881.d b/gcc/testsuite/gdc.test/fail_compilation/fail19881.d index f4a4d76..62f3dc4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19881.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19881.d @@ -1,7 +1,8 @@ /* REQUIRED_ARGS: -preview=dip1000 * TEST_OUTPUT: --- -fail_compilation/fail19881.d(12): Error: address of local variable `local` assigned to return scope `input` +fail_compilation/fail19881.d(13): Error: address of local variable `local` assigned to return scope `input` +fail_compilation/fail19881.d(13): Error: address of variable `local` assigned to `input` with longer lifetime --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20691.d b/gcc/testsuite/gdc.test/fail_compilation/fail20691.d index 7a43232..54e36fc 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20691.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20691.d @@ -1,12 +1,9 @@ /* REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/fail20691.d(106): Error: cannot take address of `scope` local `sa` in `@safe` function `bar` -fail_compilation/fail20691.d(106): Error: cannot cast expression `sa` of type `char[][2]` to `char[][]` -fail_compilation/fail20691.d(107): Error: cannot take address of `scope` local `sa` in `@safe` function `bar` -fail_compilation/fail20691.d(107): Error: cannot cast expression `sa` of type `char[][2]` to `char[][]` -fail_compilation/fail20691.d(108): Error: cannot take address of `scope` local `sa` in `@safe` function `bar` -fail_compilation/fail20691.d(108): Error: cannot cast expression `sa` of type `char[][2]` to `char[][]` +fail_compilation/fail20691.d(106): Error: cannot take address of `scope` variable `sa` since `scope` applies to first indirection only +fail_compilation/fail20691.d(107): Error: cannot take address of `scope` variable `sa` since `scope` applies to first indirection only +fail_compilation/fail20691.d(108): Error: cannot take address of `scope` variable `sa` since `scope` applies to first indirection only --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21092.d b/gcc/testsuite/gdc.test/fail_compilation/fail21092.d index 2ca826e..d12b387 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail21092.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail21092.d @@ -3,10 +3,10 @@ /* TEST_OUTPUT: --- -fail_compilation/fail21092.d(19): Error: Using the result of a comma expression is not allowed +fail_compilation/fail21092.d(19): Error: using the result of a comma expression is not allowed fail_compilation/fail21092.d(19): Error: using `*` on an array is no longer supported; use `*(T , U).ptr` instead fail_compilation/fail21092.d(19): Error: `*(T , cast(real*)U)` has no effect -fail_compilation/fail21092.d(26): Error: Using the result of a comma expression is not allowed +fail_compilation/fail21092.d(26): Error: using the result of a comma expression is not allowed fail_compilation/fail21092.d(26): Error: using `*` on an array is no longer supported; use `*(w , SmallStirlingCoeffs).ptr` instead fail_compilation/fail21092.d(26): Error: `*(w , cast(real*)SmallStirlingCoeffs)` has no effect --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21206.d b/gcc/testsuite/gdc.test/fail_compilation/fail21206.d new file mode 100644 index 0000000..c3d648e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail21206.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=21206 +/* TEST_OUTPUT: +--- +fail_compilation/fail21206.d(9): Error: function `fail21206.Obj.toString` cannot return type `string` because its linkage is `extern(C++)` +--- +*/ +extern(C++) struct Obj +{ + string toString() + { + return "ret"; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21275.d b/gcc/testsuite/gdc.test/fail_compilation/fail21275.d index dbdedb3..69cdf1a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail21275.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail21275.d @@ -5,8 +5,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail21275.d(18): Deprecation: Function `imports.fail21275a.Foo.x` of type `ref int() return` is not accessible from module `fail21275` -fail_compilation/fail21275.d(21): Deprecation: Function `imports.fail21275a.Bar.x` of type `int(int)` is not accessible from module `fail21275` +fail_compilation/fail21275.d(18): Deprecation: function `imports.fail21275a.Foo.x` of type `ref int() return` is not accessible from module `fail21275` +fail_compilation/fail21275.d(21): Deprecation: function `imports.fail21275a.Bar.x` of type `int(int)` is not accessible from module `fail21275` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21314.d b/gcc/testsuite/gdc.test/fail_compilation/fail21314.d new file mode 100644 index 0000000..78e52ce --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail21314.d @@ -0,0 +1,11 @@ +// https://issues.dlang.org/show_bug.cgi?id=21314 +/* TEST_OUTPUT: +--- +fail_compilation/fail21314.d(10): Error: variable `fail21314.C21314.c21314` cannot have `extern(C++)` linkage because it is `static` +fail_compilation/fail21314.d(10): perhaps declare it as `__gshared` instead +--- +*/ +extern(C++) class C21314 +{ + static C21314[] c21314; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d b/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d index 687a727..0df31d7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d @@ -14,7 +14,7 @@ struct S int* y; } -int* test(ref return scope S s) +int* test(ref return scope S s) @safe { return &s.x; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23108a.d b/gcc/testsuite/gdc.test/fail_compilation/fail23108a.d new file mode 100644 index 0000000..a974871 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23108a.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=23108 +/* TEST_OUTPUT: +--- +fail_compilation/fail23108a.d(9): Error: undefined identifier `_xopEquals` in module `object` +--- +*/ +module object; + +struct Interface +{ + void[] vtbl; +} + +class TypeInfo +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23108b.d b/gcc/testsuite/gdc.test/fail_compilation/fail23108b.d new file mode 100644 index 0000000..10eae37 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23108b.d @@ -0,0 +1,18 @@ +// https://issues.dlang.org/show_bug.cgi?id=23108 +/* TEST_OUTPUT: +--- +fail_compilation/fail23108b.d(10): Error: undefined identifier `_xopEquals` in module `object` +fail_compilation/fail23108b.d(10): Error: undefined identifier `_xopCmp` in module `object` +--- +*/ +module object; + +struct Interface +{ + void[] vtbl; + int opCmp() { return 0; } +} + +class TypeInfo +{ +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23109.d b/gcc/testsuite/gdc.test/fail_compilation/fail23109.d new file mode 100644 index 0000000..91b4e79 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23109.d @@ -0,0 +1,12 @@ +// https://issues.dlang.org/show_bug.cgi?id=23109 +/* +EXTRA_FILES: imports/test23109a.d imports/test23109b.d imports/test23109c.d +EXTRA_SOURCES: extra-files/test23109/object.d +TEST_OUTPUT: +--- +Error: no property `getHash` for type `object.TypeInfo_Const` +Error: no property `getHash` for type `object.TypeInfo_Const` +fail_compilation/imports/test23109a.d(10): Error: template instance `imports.test23109a.Array!(Ensure)` error instantiating +--- +*/ +import imports.test23109a; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3703.d b/gcc/testsuite/gdc.test/fail_compilation/fail3703.d index 6b4edd5..d2d277f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail3703.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail3703.d @@ -3,8 +3,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail3703.d(18): Error: mismatched array lengths, 2 and 1 -fail_compilation/fail3703.d(20): Error: mismatched array lengths, 2 and 1 +fail_compilation/fail3703.d(18): Error: mismatched array lengths 2 and 1 for assignment `b[] = a` +fail_compilation/fail3703.d(20): Error: mismatched array lengths 2 and 1 for assignment `b[] = a` fail_compilation/fail3703.d(22): Error: mismatched array lengths, 3 and 2 fail_compilation/fail3703.d(23): Error: mismatched array lengths, 2 and 3 fail_compilation/fail3703.d(25): Error: mismatched array lengths, 3 and 2 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d index 07c3766..153e90b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d @@ -2,39 +2,40 @@ REQUIRED_ARGS: TEST_OUTPUT: --- -fail_compilation/fail_scope.d(29): Deprecation: scope variable `da` may not be returned -fail_compilation/fail_scope.d(31): Deprecation: scope variable `o` may not be returned -fail_compilation/fail_scope.d(32): Deprecation: scope variable `dg` may not be returned -fail_compilation/fail_scope.d(34): Deprecation: scope variable `da` may not be returned -fail_compilation/fail_scope.d(36): Deprecation: scope variable `o` may not be returned -fail_compilation/fail_scope.d(37): Deprecation: scope variable `dg` may not be returned -fail_compilation/fail_scope.d(39): Deprecation: scope variable `p` may not be returned -fail_compilation/fail_scope.d(44): Error: returning `cast(char[])string` escapes a reference to local variable `string` -fail_compilation/fail_scope.d(62): Error: returning `s.bar()` escapes a reference to local variable `s` -fail_compilation/fail_scope.d(73): Error: `fail_scope.foo8` called with argument types `(int)` matches both: -fail_compilation/fail_scope.d(67): `fail_scope.foo8(ref int x)` +fail_compilation/fail_scope.d(40): Deprecation: scope variable `p` may not be returned +fail_compilation/fail_scope.d(45): Error: returning `cast(char[])string` escapes a reference to local variable `string` +fail_compilation/fail_scope.d(63): Error: returning `s.bar()` escapes a reference to local variable `s` +fail_compilation/fail_scope.d(74): Error: `fail_scope.foo8` called with argument types `(int)` matches both: +fail_compilation/fail_scope.d(68): `fail_scope.foo8(ref int x)` and: -fail_compilation/fail_scope.d(68): `fail_scope.foo8(return ref int x)` -fail_compilation/fail_scope.d(81): Error: returning `& string` escapes a reference to local variable `string` -fail_compilation/fail_scope.d(91): Error: returning `cast(int[])a` escapes a reference to local variable `a` -fail_compilation/fail_scope.d(99): Error: returning `cast(int[])a` escapes a reference to local variable `a` -fail_compilation/fail_scope.d(107): Deprecation: escaping reference to outer local variable `x` -fail_compilation/fail_scope.d(126): Error: returning `s.bar()` escapes a reference to local variable `s` -fail_compilation/fail_scope.d(136): Error: returning `foo16226(i)` escapes a reference to local variable `i` +fail_compilation/fail_scope.d(69): `fail_scope.foo8(return ref int x)` +fail_compilation/fail_scope.d(82): Error: returning `& string` escapes a reference to local variable `string` +fail_compilation/fail_scope.d(92): Error: returning `cast(int[])a` escapes a reference to local variable `a` +fail_compilation/fail_scope.d(100): Error: returning `cast(int[])a` escapes a reference to local variable `a` +fail_compilation/fail_scope.d(108): Deprecation: escaping reference to outer local variable `x` +fail_compilation/fail_scope.d(127): Error: returning `s.bar()` escapes a reference to local variable `s` +fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a reference to local variable `i` --- +//fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned +//fail_compilation/fail_scope.d(32): Error: scope variable `o` may not be returned +//fail_compilation/fail_scope.d(33): Error: scope variable `dg` may not be returned +//fail_compilation/fail_scope.d(35): Error: scope variable `da` may not be returned +//fail_compilation/fail_scope.d(37): Error: scope variable `o` may not be returned +//fail_compilation/fail_scope.d(38): Error: scope variable `dg` may not be returned +//fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned */ alias int delegate() dg_t; -int[] checkEscapeScope1(scope int[] da) @safe { return da; } -int[3] checkEscapeScope2(scope int[3] sa) @safe { return sa; } -Object checkEscapeScope3(scope Object o) @safe { return o; } -dg_t checkEscapeScope4(scope dg_t dg) @safe { return dg; } +int[] checkEscapeScope1(scope int[] da) { return da; } +int[3] checkEscapeScope2(scope int[3] sa) { return sa; } +Object checkEscapeScope3(scope Object o) { return o; } +dg_t checkEscapeScope4(scope dg_t dg) { return dg; } -int[] checkEscapeScope1() @safe { scope int[] da = []; return da; } -int[3] checkEscapeScope2() @safe { scope int[3] sa = [1,2,3]; return sa; } -Object checkEscapeScope3() @safe { scope Object o = new Object; return o; } // same with fail7294.d -dg_t checkEscapeScope4() @safe { scope dg_t dg = () => 1; return dg; } +int[] checkEscapeScope1() { scope int[] da = []; return da; } +int[3] checkEscapeScope2() { scope int[3] sa = [1,2,3]; return sa; } +Object checkEscapeScope3() { scope Object o = new Object; return o; } // same with fail7294.d +dg_t checkEscapeScope4() { scope dg_t dg = () => 1; return dg; } int* test(scope int* p) @safe { return p; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10949.d b/gcc/testsuite/gdc.test/fail_compilation/ice10949.d index 45b18e0..b39548d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10949.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10949.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice10949.d(12): Error: Using the result of a comma expression is not allowed +fail_compilation/ice10949.d(12): Error: using the result of a comma expression is not allowed fail_compilation/ice10949.d(12): Error: array index 3 is out of bounds `[5, 5][0 .. 2]` fail_compilation/ice10949.d(12): Error: array index 17 is out of bounds `[2, 3][0 .. 2]` fail_compilation/ice10949.d(12): while evaluating: `static assert((((([5, 5][3] + global - global) * global / global % global >> global & global | global) ^ global) == 9 , [2, 3][17]) || [3, 3, 3][9] is 4 && [[1, 2, 3]][4].length)` diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14844.d b/gcc/testsuite/gdc.test/fail_compilation/ice14844.d index 9f602a5..d466a30 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14844.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14844.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice14844.d(21): Error: In expression `__traits(allMembers, opDispatch)` template `opDispatch(string name)` has no members +fail_compilation/ice14844.d(21): Error: in expression `__traits(allMembers, opDispatch)` template `opDispatch(string name)` has no members fail_compilation/ice14844.d(21): `opDispatch(string name)` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice22377.d b/gcc/testsuite/gdc.test/fail_compilation/ice22377.d index 4616f99..686e700 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice22377.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice22377.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice22377.d(8): Error: Internal Compiler Error: type `string` cannot be mapped to C++ +fail_compilation/ice22377.d(8): Error: function `ice22377.foo` cannot have parameter of type `string` because its linkage is `extern(C++)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d new file mode 100644 index 0000000..4fd1f61 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d @@ -0,0 +1,28 @@ +/* https://issues.dlang.org/show_bug.cgi?id=23097 +TEST_OUTPUT: +--- +fail_compilation/ice23097.d(12): Error: undefined identifier `ICE` +fail_compilation/ice23097.d(27): Error: template instance `ice23097.ice23097!(S23097)` error instantiating +fail_compilation/ice23097.d(27): Error: function `ice23097.ice23097!(S23097).ice23097(S23097 _param_0)` is not callable using argument types `(S23097)` +fail_compilation/ice23097.d(27): generating a copy constructor for `struct S23097` failed, therefore instances of it are uncopyable +--- +*/ +auto ice23097(I)(I) +{ + ICE; +} + +struct Cpctor23097 +{ + this(ref typeof(this)) { } +} + +struct S23097 +{ + Cpctor23097 cpctor; +} + +auto fail23097(S23097 s) +{ + s.ice23097; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9254a.d b/gcc/testsuite/gdc.test/fail_compilation/ice9254a.d index d7086b4..8ba1cbf 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9254a.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9254a.d @@ -1,11 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed +fail_compilation/ice9254a.d(15): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254a.d(15): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254a.d(15): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254a.d(15): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254a.d(15): Error: using the result of a comma expression is not allowed fail_compilation/ice9254a.d(15): Error: invalid `foreach` aggregate `false` of type `bool` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9254b.d b/gcc/testsuite/gdc.test/fail_compilation/ice9254b.d index 5484abd..04f28fd 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9254b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9254b.d @@ -1,11 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed +fail_compilation/ice9254b.d(17): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254b.d(17): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254b.d(17): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254b.d(17): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254b.d(17): Error: using the result of a comma expression is not allowed fail_compilation/ice9254b.d(17): Error: invalid `foreach` aggregate `false` of type `bool` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9254c.d b/gcc/testsuite/gdc.test/fail_compilation/ice9254c.d index 23eeecc..acecc8d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9254c.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9254c.d @@ -1,11 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed -fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed +fail_compilation/ice9254c.d(15): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254c.d(15): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254c.d(15): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254c.d(15): Error: using the result of a comma expression is not allowed +fail_compilation/ice9254c.d(15): Error: using the result of a comma expression is not allowed fail_compilation/ice9254c.d(15): Error: invalid `foreach` aggregate `false` of type `bool` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test23109a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test23109a.d new file mode 100644 index 0000000..5a11d91 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test23109a.d @@ -0,0 +1,10 @@ +module imports.test23109a; +import imports.test23109c; +import imports.test23109b; +struct Array(T) +{ + T[] data; + enum SMALLARRAYCAP = 1; + T[SMALLARRAYCAP] smallarray; +} +alias Ensures = Array!Ensure; diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test23109b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test23109b.d new file mode 100644 index 0000000..38680d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test23109b.d @@ -0,0 +1,10 @@ +module imports.test23109b; +import imports.test23109a; +import imports.test23109c; +struct Ensure +{ + Statement ensure; + Ensures* arraySyntaxCopy() + { + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test23109c.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test23109c.d new file mode 100644 index 0000000..c6faf5c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test23109c.d @@ -0,0 +1,3 @@ +module imports.test23109c; +import imports.test23109b; +class Statement {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue3827.d b/gcc/testsuite/gdc.test/fail_compilation/issue3827.d index d17cee8..12ae60b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/issue3827.d +++ b/gcc/testsuite/gdc.test/fail_compilation/issue3827.d @@ -2,9 +2,9 @@ /* TEST_OUTPUT: --- -fail_compilation/issue3827.d(14): Error: Implicit string concatenation is error-prone and disallowed in D +fail_compilation/issue3827.d(14): Error: implicit string concatenation is error-prone and disallowed in D fail_compilation/issue3827.d(14): Use the explicit syntax instead (concatenating literals is `@nogc`): "Hello" ~ "World" -fail_compilation/issue3827.d(15): Error: Implicit string concatenation is error-prone and disallowed in D +fail_compilation/issue3827.d(15): Error: implicit string concatenation is error-prone and disallowed in D fail_compilation/issue3827.d(15): Use the explicit syntax instead (concatenating literals is `@nogc`): "A" ~ "B" --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d b/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d index 5a8af97..eb385cb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d +++ b/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d @@ -4,8 +4,8 @@ REQUIRED_ARGS: -c EXTRA_SOURCES: extra-files/minimal/object.d TEST_OUTPUT: --- -fail_compilation/no_Throwable.d(14): Error: Cannot use `throw` statements because `object.Throwable` was not declared -fail_compilation/no_Throwable.d(19): Error: Cannot use try-catch statements because `object.Throwable` was not declared +fail_compilation/no_Throwable.d(14): Error: cannot use `throw` statements because `object.Throwable` was not declared +fail_compilation/no_Throwable.d(19): Error: cannot use try-catch statements because `object.Throwable` was not declared --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope.d b/gcc/testsuite/gdc.test/fail_compilation/retscope.d index 64db4c8..27d5663 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope.d @@ -85,7 +85,7 @@ struct HTTP /* TEST_OUTPUT: --- -fail_compilation/retscope.d(96): Error: reference to local variable `sa` assigned to non-scope parameter `a` calling retscope.bar8 +fail_compilation/retscope.d(96): Error: reference to local variable `sa` assigned to non-scope parameter `a` --- */ // https://issues.dlang.org/show_bug.cgi?id=8838 @@ -234,16 +234,16 @@ void* funretscope(scope dg_t ptr) @safe /* TEST_OUTPUT: --- -fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() @safe` -fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() @safe` -fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda4` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() @safe` -fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda4` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() @safe` +fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe` +fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe` +fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda4` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe` +fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda4` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe` --- */ void escape4() @safe { - alias FunDG = void* delegate () @safe; + alias FunDG = void* delegate () scope @safe; int x = 42; scope FunDG f = () return { return &x; }; scope FunDG g = () { return &x; }; @@ -254,7 +254,7 @@ void escape4() @safe /* TEST_OUTPUT: --- -fail_compilation/retscope.d(266): Error: cannot take address of `scope` local `p` in `@safe` function `escape5` +fail_compilation/retscope.d(266): Error: cannot take address of `scope` variable `p` since `scope` applies to first indirection only --- */ @@ -331,7 +331,7 @@ int* bar10( scope int** ptr ) @safe /* TEST_OUTPUT: --- -fail_compilation/retscope.d(342): Error: cannot take address of `scope` local `aa` in `@safe` function `escape11` +fail_compilation/retscope.d(342): Error: cannot take address of `scope` variable `aa` since `scope` applies to first indirection only --- */ @@ -403,7 +403,7 @@ class Foo13 /* TEST_OUTPUT: --- -fail_compilation/retscope.d(1205): Error: scope variable `f14` assigned to non-scope parameter `this` calling retscope.Foo14.foo +fail_compilation/retscope.d(1205): Error: scope variable `f14` assigned to non-scope parameter `this` --- */ @@ -454,7 +454,7 @@ fail_compilation/retscope.d(1311): Error: scope variable `u2` assigned to `ek` w /* TEST_OUTPUT: --- -fail_compilation/retscope.d(1405): Error: reference to local variable `buf` assigned to non-scope parameter `__anonymous_param` calling retscope.myprintf +fail_compilation/retscope.d(1405): Error: reference to local variable `buf` assigned to non-scope parameter `__anonymous_param` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d index 4f1e324..17d2182 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d @@ -86,8 +86,8 @@ fail_compilation/retscope2.d(504): Error: scope variable `c` may not be returned /* TEST_OUTPUT: --- -fail_compilation/retscope2.d(604): Error: scope variable `_param_0` assigned to non-scope parameter `__anonymous_param` calling retscope2.foo600 -fail_compilation/retscope2.d(604): Error: scope variable `_param_1` assigned to non-scope parameter `__anonymous_param` calling retscope2.foo600 +fail_compilation/retscope2.d(604): Error: scope variable `_param_0` assigned to non-scope parameter `__anonymous_param` +fail_compilation/retscope2.d(604): Error: scope variable `_param_1` assigned to non-scope parameter `__anonymous_param` fail_compilation/retscope2.d(614): Error: template instance `retscope2.test600!(int*, int*)` error instantiating --- */ @@ -156,7 +156,7 @@ fail_compilation/retscope2.d(804): Error: scope variable `e` may not be thrown #line 800 -void foo800() +void foo800() @safe { scope Exception e; throw e; diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d index 6d5807b..b9a85ae 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d @@ -76,9 +76,9 @@ void foo() @safe /* TEST_OUTPUT: --- fail_compilation/retscope6.d(8016): Error: address of variable `i` assigned to `p` with longer lifetime -fail_compilation/retscope6.d(8031): Error: reference to local variable `i` assigned to non-scope parameter `p` calling retscope6.betty!().betty -fail_compilation/retscope6.d(8031): Error: reference to local variable `j` assigned to non-scope parameter `q` calling retscope6.betty!().betty -fail_compilation/retscope6.d(8048): Error: reference to local variable `j` assigned to non-scope parameter `q` calling retscope6.archie!().archie +fail_compilation/retscope6.d(8031): Error: reference to local variable `i` assigned to non-scope parameter `p` +fail_compilation/retscope6.d(8031): Error: reference to local variable `j` assigned to non-scope parameter `q` +fail_compilation/retscope6.d(8048): Error: reference to local variable `j` assigned to non-scope parameter `q` --- */ @@ -172,7 +172,7 @@ T9 testfred() /* TEST_OUTPUT: --- -fail_compilation/retscope6.d(10003): Error: scope variable `values` assigned to non-scope parameter `values` calling retscope6.escape +fail_compilation/retscope6.d(10003): Error: scope variable `values` assigned to non-scope parameter `values` --- */ @@ -234,7 +234,7 @@ const(int)* f_c_20150() @safe nothrow /* TEST_OUTPUT: --- -fail_compilation/retscope6.d(13010): Error: reference to local variable `str` assigned to non-scope parameter `x` calling retscope6.f_throw +fail_compilation/retscope6.d(13010): Error: reference to local variable `str` assigned to non-scope parameter `x` --- */ @@ -254,7 +254,7 @@ void escape_throw_20150() @safe /* TEST_OUTPUT: --- -fail_compilation/retscope6.d(14019): Error: scope variable `scopePtr` assigned to non-scope parameter `x` calling retscope6.noInfer23021 +fail_compilation/retscope6.d(14019): Error: scope variable `scopePtr` assigned to non-scope parameter `x` fail_compilation/retscope6.d(14022): Error: scope variable `scopePtr` may not be returned --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/safe_gshared.d b/gcc/testsuite/gdc.test/fail_compilation/safe_gshared.d new file mode 100644 index 0000000..ea0775c --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/safe_gshared.d @@ -0,0 +1,15 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/safe_gshared.d(13): Error: `@safe` function `f` cannot access `__gshared` data `x` +fail_compilation/safe_gshared.d(14): Error: `@safe` function `f` cannot access `__gshared` data `x` +--- +*/ + +__gshared int x; + +@safe int f() +{ + x++; + return x; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/safe_pointer_index.d b/gcc/testsuite/gdc.test/fail_compilation/safe_pointer_index.d new file mode 100644 index 0000000..4b107db --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/safe_pointer_index.d @@ -0,0 +1,12 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/safe_pointer_index.d(11): Error: `@safe` function `f` cannot index pointer `x` +--- +*/ + +@safe void f(int* x) +{ + int y = x[0]; // allowed, same as *x + int z = x[1]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13536.d b/gcc/testsuite/gdc.test/fail_compilation/test13536.d index c45d76a..f4e2cac 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test13536.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test13536.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/test13536.d(23): Error: field `U.sysDg` cannot access pointers in `@safe` code that overlap other fields -fail_compilation/test13536.d(23): Error: address of variable `s` assigned to `u` with longer lifetime +fail_compilation/test13536.d(23): Deprecation: address of variable `s` assigned to `u` with longer lifetime fail_compilation/test13536.d(24): Error: field `U.safeDg` cannot access pointers in `@safe` code that overlap other fields --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14496.d b/gcc/testsuite/gdc.test/fail_compilation/test14496.d index 92dd3cf..9f628ca 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test14496.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test14496.d @@ -1,11 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/test14496.d(21): Error: variable `test14496.foo.f` `void` initializers for pointers not allowed in safe functions -fail_compilation/test14496.d(24): Error: variable `test14496.foo.Bar.foo` `void` initializers for pointers not allowed in safe functions -fail_compilation/test14496.d(28): Error: variable `test14496.foo.Baz.x` `void` initializers for pointers not allowed in safe functions -fail_compilation/test14496.d(48): Error: variable `test14496.sinister.bar` `void` initializers for pointers not allowed in safe functions -fail_compilation/test14496.d(49): Error: variable `test14496.sinister.baz` `void` initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(21): Error: `void` initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(24): Error: `void` initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(28): Error: `void` initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(48): Error: `void` initializers for pointers not allowed in safe functions +fail_compilation/test14496.d(49): Error: `void` initializers for pointers not allowed in safe functions --- */ // https://issues.dlang.org/show_bug.cgi?id=14496 diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15191.d b/gcc/testsuite/gdc.test/fail_compilation/test15191.d index f2a117c..fbbc1c0 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15191.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15191.d @@ -1,12 +1,11 @@ /* TEST_OUTPUT: REQUIRED_ARGS: -preview=dip1000 --- -fail_compilation/test15191.d(35): Error: returning `&identity(x)` escapes a reference to local variable `x` -fail_compilation/test15191.d(41): Error: returning `&identityPtr(x)` escapes a reference to local variable `x` -fail_compilation/test15191.d(47): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive` -fail_compilation/test15191.d(47): return type `int*` has pointers that may be `scope` -fail_compilation/test15191.d(68): Error: cannot slice static array of `ref return` of `identityArr()` in `@safe` function `sliceOfRefEscape` -fail_compilation/test15191.d(68): return type `int*[1]` has pointers that may be `scope` +fail_compilation/test15191.d(34): Error: returning `&identity(x)` escapes a reference to local variable `x` +fail_compilation/test15191.d(40): Error: returning `&identityPtr(x)` escapes a reference to local variable `x` +fail_compilation/test15191.d(46): Error: returning `&identityPtr(x)` escapes a reference to local variable `x` +fail_compilation/test15191.d(67): Error: cannot take address of `scope` variable `x` since `scope` applies to first indirection only +fail_compilation/test15191.d(69): Error: cannot take address of `scope` variable `x` since `scope` applies to first indirection only --- */ @@ -61,10 +60,24 @@ ref int*[1] identityArr(return ref scope int*[1] x) return x; } -int* sliceOfRefEscape() +int*[] sliceOfRefEscape() { int stackVar = 0xFF; scope int*[1] x = [&stackVar]; - int*[] y = identityArr(x)[]; - return y[0]; + auto y = identityArr(x)[]; // check transitive scope in assignment + cast(void) y; + return identityArr(x)[]; // check transitive scope in return statement +} + +// https://issues.dlang.org/show_bug.cgi?id=23079 +int** p; + +ref int* get() @safe +{ + return *p; +} + +int** g1() @safe +{ + return &get(); } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15373.d b/gcc/testsuite/gdc.test/fail_compilation/test15373.d index 1b3cecd..02a1b32 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15373.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15373.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test15373.d(21): Error: Runtime type information is not supported for `extern(C++)` classes +fail_compilation/test15373.d(21): Error: runtime type information is not supported for `extern(C++)` classes --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16188.d b/gcc/testsuite/gdc.test/fail_compilation/test16188.d index c8ab825..c4a0fa6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test16188.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test16188.d @@ -1,8 +1,8 @@ -TEST_OUTPUT: +/* REQUIRED_ARGS: -preview=bitfields + * TEST_OUTPUT: --- -fail_compilation/test16188.d(1): Error: no identifier for declarator `TEST_OUTPUT` -fail_compilation/test16188.d(1): Error: declaration expected, not `:` -fail_compilation/test16188.d(18): Error: unmatched closing brace +fail_compilation/test16188.d(101): Error: no property `name` for type `test16188.Where` +fail_compilation/test16188.d(101): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message --- */ @@ -15,6 +15,8 @@ fail_compilation/test16188.d(18): Error: unmatched closing brace * I don't understand why. */ +#line 100 + void where() { Where().name; } struct Where diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16365.d b/gcc/testsuite/gdc.test/fail_compilation/test16365.d index a11807f..c987969 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test16365.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test16365.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/test16365.d(21): Error: `this` reference necessary to take address of member `f1` in `@safe` function `main` fail_compilation/test16365.d(23): Error: cannot implicitly convert expression `&f2` of type `void delegate() pure nothrow @nogc @safe` to `void function() @safe` -fail_compilation/test16365.d(27): Error: address of variable `s` assigned to `dg` with longer lifetime +fail_compilation/test16365.d(27): Deprecation: address of variable `s` assigned to `dg` with longer lifetime fail_compilation/test16365.d(28): Error: `dg.funcptr` cannot be used in `@safe` code --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17284.d b/gcc/testsuite/gdc.test/fail_compilation/test17284.d index 5bb3c2c..b7fd979 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test17284.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test17284.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/test17284.d(16): Error: field `U.c` cannot access pointers in `@safe` code that overlap other fields +fail_compilation/test17284.d(17): Error: field `U.c` cannot access pointers in `@safe` code that overlap other fields pure nothrow @safe void(U t) --- +REQUIRED_ARGS: -preview=bitfields */ // https://issues.dlang.org/show_bug.cgi?id=17284 diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17423.d b/gcc/testsuite/gdc.test/fail_compilation/test17423.d index 66a81c3..ec86646 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test17423.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test17423.d @@ -1,7 +1,7 @@ /* REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/test17423.d(26): Error: reference to local `this` assigned to non-scope parameter `dlg` calling test17423.Bar.opApply +fail_compilation/test17423.d(26): Error: reference to local `this` assigned to non-scope parameter `dlg` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17868b.d b/gcc/testsuite/gdc.test/fail_compilation/test17868b.d index 7833b61..18f1844 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test17868b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test17868b.d @@ -2,8 +2,8 @@ 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(14): Error: function `test17868b.bar` must return `void` for `pragma(crt_constructor)` +fail_compilation/test17868b.d(18): Error: function `test17868b.baz` must be `extern(C)` for `pragma(crt_constructor)` when taking parameters ---- */ pragma(crt_constructor): @@ -11,6 +11,14 @@ void foo() { } -void bar() +extern(C) int bar() +{ +} + +void baz(int argc, char** argv) +{ +} + +extern(C) void bazC(int, char**) { } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18130.d b/gcc/testsuite/gdc.test/fail_compilation/test18130.d index 4309a6b..be296f8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test18130.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test18130.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test18130.d(8): Error: variable `test18130.foo.v` Zero-length `out` parameters are not allowed. +fail_compilation/test18130.d(8): Error: variable `test18130.foo.v` zero-length `out` parameters are not allowed. --- */ // https://issues.dlang.org/show_bug.cgi?id=18130 diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18282.d b/gcc/testsuite/gdc.test/fail_compilation/test18282.d index cf26878..580fe1b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test18282.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test18282.d @@ -60,7 +60,7 @@ TEST_OUTPUT: fail_compilation/test18282.d(1007): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo` fail_compilation/test18282.d(1008): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo` fail_compilation/test18282.d(1009): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo` -fail_compilation/test18282.d(1016): Error: copying `&this` into allocated memory escapes a reference to parameter variable `this` +fail_compilation/test18282.d(1016): Error: copying `&this` into allocated memory escapes a reference to parameter `this` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18484.d b/gcc/testsuite/gdc.test/fail_compilation/test18484.d index 55d0ff1..d604f38 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test18484.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test18484.d @@ -10,11 +10,11 @@ fail_compilation/test18484.d(24): Error: escaping reference to stack allocated v struct S { - int* bar() return; + int* bar() @safe return; int i; } -int* test1() +int* test1() @safe { auto x = S(); return x.bar(); // error } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20245.d b/gcc/testsuite/gdc.test/fail_compilation/test20245.d index 74c5384..daa0697 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test20245.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test20245.d @@ -2,15 +2,15 @@ REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/test20245.d(20): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling test20245.escape -fail_compilation/test20245.d(21): Error: copying `&x` into allocated memory escapes a reference to parameter variable `x` +fail_compilation/test20245.d(20): Error: reference to local variable `x` assigned to non-scope parameter `ptr` +fail_compilation/test20245.d(21): Error: copying `&x` into allocated memory escapes a reference to parameter `x` fail_compilation/test20245.d(22): Error: scope variable `a` may not be returned -fail_compilation/test20245.d(26): Error: cannot take address of `scope` parameter `x` in `@safe` function `foo` -fail_compilation/test20245.d(32): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling test20245.escape -fail_compilation/test20245.d(33): Error: copying `&x` into allocated memory escapes a reference to parameter variable `x` +fail_compilation/test20245.d(26): Error: cannot take address of `scope` variable `x` since `scope` applies to first indirection only +fail_compilation/test20245.d(32): Error: reference to local variable `x` assigned to non-scope parameter `ptr` +fail_compilation/test20245.d(33): Error: copying `&x` into allocated memory escapes a reference to parameter `x` fail_compilation/test20245.d(49): Error: reference to local variable `price` assigned to non-scope `this.minPrice` -fail_compilation/test20245.d(68): Error: reference to local variable `this` assigned to non-scope parameter `msg` calling object.Exception.this -fail_compilation/test20245.d(88): Error: reference to local variable `this` assigned to non-scope parameter `content` calling test20245.listUp +fail_compilation/test20245.d(68): Error: reference to local variable `this` assigned to non-scope parameter `msg` +fail_compilation/test20245.d(88): Error: reference to local variable `this` assigned to non-scope parameter `content` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20569.d b/gcc/testsuite/gdc.test/fail_compilation/test20569.d index a5ac98b..7ad50dc 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test20569.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test20569.d @@ -1,8 +1,8 @@ /* REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/test20569.d(19): Error: cannot take address of `scope` local `s1` in `@safe` function `main` -fail_compilation/test20569.d(23): Error: cannot take address of `scope` local `s2` in `@safe` function `main` +fail_compilation/test20569.d(19): Error: cannot take address of `scope` variable `s1` since `scope` applies to first indirection only +fail_compilation/test20569.d(23): Error: cannot take address of `scope` variable `s2` since `scope` applies to first indirection only --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21198.d b/gcc/testsuite/gdc.test/fail_compilation/test21198.d index cab6fc8..04c3bcf 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21198.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21198.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test21198.d(23): Error: Generating an `inout` copy constructor for `struct test21198.U` failed, therefore instances of it are uncopyable +fail_compilation/test21198.d(23): Error: generating an `inout` copy constructor for `struct test21198.U` failed, therefore instances of it are uncopyable --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21204.d b/gcc/testsuite/gdc.test/fail_compilation/test21204.d index 8732cc0..45bb6d7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21204.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21204.d @@ -2,7 +2,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test21204.d(22): Error: Generating an `inout` copy constructor for `struct test21204.B` failed, therefore instances of it are uncopyable +fail_compilation/test21204.d(22): Error: generating an `inout` copy constructor for `struct test21204.B` failed, therefore instances of it are uncopyable --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21665.d b/gcc/testsuite/gdc.test/fail_compilation/test21665.d index a3a348d..b4c2811 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21665.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21665.d @@ -1,6 +1,6 @@ /* TEST_OUTPUT: --- -fail_compilation/test21665.d(18): Error: variable `test21665.test1.s` `void` initializers for structs with invariants are not allowed in safe functions +fail_compilation/test21665.d(18): Error: `void` initializers for structs with invariants are not allowed in safe functions fail_compilation/test21665.d(30): Error: field `U.s` cannot access structs with invariants in `@safe` code that overlap other fields --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22145.d b/gcc/testsuite/gdc.test/fail_compilation/test22145.d index 084083c..394116d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test22145.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test22145.d @@ -1,4 +1,5 @@ /* TEST_OUTPUT: +REQUIRED_ARGS: -preview=dip1000 --- fail_compilation/test22145.d(115): Error: scope variable `x` assigned to non-scope `global` --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22593.d b/gcc/testsuite/gdc.test/fail_compilation/test22593.d index f90287e..a47c0fe 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test22593.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test22593.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test22593.d(14): Error: Cannot define both an rvalue constructor and a copy constructor for `struct Foo` +fail_compilation/test22593.d(14): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo` fail_compilation/test22593.d(22): Template instance `__ctor!(immutable(Foo!int), immutable(Foo!int))` creates a rvalue constructor for `struct Foo` fail_compilation/test22593.d(22): Error: template instance `test22593.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` error instantiating --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/test9150.d b/gcc/testsuite/gdc.test/fail_compilation/test9150.d index e65afec..5f66b36 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test9150.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test9150.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/test9150.d(14): Error: mismatched array lengths, 5 and 3 +fail_compilation/test9150.d(14): Error: mismatched array lengths 5 and 3 for assignment `row[] = __r2[__key3]` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits.d b/gcc/testsuite/gdc.test/fail_compilation/traits.d index 5b9daaa..8c16afe 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/traits.d +++ b/gcc/testsuite/gdc.test/fail_compilation/traits.d @@ -11,13 +11,13 @@ fail_compilation/traits.d(200): Error: undefined identifier `imports.nonexistent fail_compilation/traits.d(201): Error: undefined identifier `imports.nonexistent` fail_compilation/traits.d(202): Error: expected 1 arguments for `isPackage` but had 0 fail_compilation/traits.d(203): Error: expected 1 arguments for `isModule` but had 0 -fail_compilation/traits.d(300): Error: In expression `__traits(allMembers, float)` `float` can't have members +fail_compilation/traits.d(300): Error: in expression `__traits(allMembers, float)` `float` can't have members fail_compilation/traits.d(300): `float` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation -fail_compilation/traits.d(306): Error: In expression `__traits(allMembers, TemplatedStruct)` struct `TemplatedStruct(T)` has no members +fail_compilation/traits.d(306): Error: in expression `__traits(allMembers, TemplatedStruct)` struct `TemplatedStruct(T)` has no members fail_compilation/traits.d(306): `TemplatedStruct(T)` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation -fail_compilation/traits.d(309): Error: In expression `__traits(derivedMembers, float)` `float` can't have members +fail_compilation/traits.d(309): Error: in expression `__traits(derivedMembers, float)` `float` can't have members fail_compilation/traits.d(309): `float` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation -fail_compilation/traits.d(316): Error: In expression `__traits(derivedMembers, TemplatedStruct)` struct `TemplatedStruct(T)` has no members +fail_compilation/traits.d(316): Error: in expression `__traits(derivedMembers, TemplatedStruct)` struct `TemplatedStruct(T)` has no members fail_compilation/traits.d(316): `TemplatedStruct(T)` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation fail_compilation/traits.d(404): Error: function `traits.func1` circular reference in `__traits(GetCppNamespaces,...)` fail_compilation/traits.d(413): Error: function `traits.foo1.func1` circular reference in `__traits(GetCppNamespaces,...)` diff --git a/gcc/testsuite/gdc.test/fail_compilation/udaparams.d b/gcc/testsuite/gdc.test/fail_compilation/udaparams.d index ec760bd..5d0390f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/udaparams.d +++ b/gcc/testsuite/gdc.test/fail_compilation/udaparams.d @@ -12,8 +12,8 @@ fail_compilation/udaparams.d(40): Error: `@safe` attribute for function paramete fail_compilation/udaparams.d(43): Error: `@system` attribute for function parameter is not supported fail_compilation/udaparams.d(44): Error: `@trusted` attribute for function parameter is not supported fail_compilation/udaparams.d(45): Error: `@nogc` attribute for function parameter is not supported -fail_compilation/udaparams.d(51): Error: Cannot put a storage-class in an alias declaration. -fail_compilation/udaparams.d(52): Error: Cannot put a storage-class in an alias declaration. +fail_compilation/udaparams.d(51): Error: cannot put a storage-class in an alias declaration. +fail_compilation/udaparams.d(52): Error: cannot put a storage-class in an alias declaration. fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` declaration fail_compilation/udaparams.d(53): Error: declaration expected, not `=>` fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration diff --git a/gcc/testsuite/gdc.test/runnable/bit.d b/gcc/testsuite/gdc.test/runnable/bit.d new file mode 100644 index 0000000..289e1bc --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/bit.d @@ -0,0 +1,106 @@ +/* REQUIRED_ARGS: -preview=bitfields + */ + +struct T +{ + uint x : 2, y : 3, :0; + int :0; +} + +uint foo(T s) +{ + return s.x + s.y; +} + +void test1() +{ + T s; + s.x = 2; + s.y = 4; + uint u = foo(s); + assert(u == 6); +} + +/********************************************/ + +struct S +{ + uint a:3; + uint b:1; + ulong c:64; + + int d:3; + int e:1; + long f:64; + + int i; + alias f this; +} + +static assert(S.a.min == 0); +static assert(S.a.max == 7); + +static assert(S.b.min == 0); +static assert(S.b.max == 1); + +static assert(S.c.min == 0); +static assert(S.c.max == ulong.max); + +static assert(S.d.min == -4); +static assert(S.d.max == 3); + +static assert(S.e.min == -1); +static assert(S.e.max == 0); + +static assert(S.f.min == long.min); +static assert(S.f.max == long.max); +static assert(S.max == S.f.max); + +void test2() +{ + int x; + S effect() + { + ++x; + return S(); + } + assert(effect().a.max == 7); + assert(effect().i.max == int.max); + assert(x == 0); // ensure effect() was not executed +} + +/********************************************/ + +struct U +{ + int a; + int b:3, c:4; + this(this) + { + b = 2; + } +} + +static assert(U.b.offsetof == 4); +static assert(U.b.sizeof == 4); + +void test3() +{ + U u; + u.c = 4; + U v = u; + assert(v.c == 4); + u = v; + assert(u.b == 2); + assert(__traits(getMember, u, "b") == 2); +} + +/********************************************/ + +int main() +{ + test1(); + test2(); + test3(); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/dbitfields.d b/gcc/testsuite/gdc.test/runnable/dbitfields.d new file mode 100644 index 0000000..0d1877a --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/dbitfields.d @@ -0,0 +1,189 @@ +/* REQUIRED_ARGS: -preview=bitfields + */ + +struct S +{ + int a:2, b:4; +} + +static assert(S.sizeof == 4); + +void test1() +{ + S s; + s.a = 3; + assert(s.a == -1); + + s.b = 4; + assert(s.b == 4); +} + +/******************************************/ + +struct S2 +{ + uint a:2, b:4; +} + +S2 foo() +{ + S2 s = { 7, 8 }; // test struct literal expressions + return s; +} + +void test2() +{ + S2 s = foo(); + + assert(s.a == 3); + assert(s.b == 8); +} + +/******************************************/ + +struct S3 +{ + int i1; + uint a:2, b:4, c:6; + int i2; +} + +static assert(S3.sizeof == 12); + +S3 s3 = { 63, 7, 8 }; + +void test3() +{ + assert(s3.i1 == 63); + assert(s3.a == 3); + assert(s3.b == 8); + assert(s3.c == 0); + assert(s3.i2 == 0); +} + +/******************************************/ + +struct S4 +{ + int i1; + uint a:2, b:31; +} + +static assert(S4.sizeof == 12); + +S4 s4 = { 63, 7, 8 }; + +void test4() +{ + assert(s4.i1 == 63); + assert(s4.a == 3); + assert(s4.b == 8); +} + +/******************************************/ + +struct S5 +{ + int i1; + uint a:2, :0, b:5; +} + +static assert(S5.sizeof == 12); + +S5 s5 = { 63, 7, 8 }; + +void test5() +{ + assert(s5.i1 == 63); + assert(s5.a == 3); + assert(s5.b == 8); +} + +/******************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=22710 + +struct S6 +{ + uint a:2, b:2; +} + +int boo6() +{ + S s; + s.a = 3; + s.b = 1; + s.a += 2; + return s.a; +} + +void test6() +{ + //printf("res: %d\n", test()); + assert(boo6() == 1); +} + +/******************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=22710 + +struct S7 +{ + uint a:2, b:2; + int c:2, d:2; +} + +int test7u() +{ + S7 s; + s.a = 7; + s.b = 1; + s.a += 2; + return s.a; +} + +int test7s() +{ + S7 s; + s.c = 7; + s.d = 1; + s.c += 4; + return s.c; +} + +int test7s2() +{ + S7 s; + s.c = 7; + s.d = 2; + s.c += 4; + return s.d; +} + +void test7() +{ + //printf("uns: %d\n", test7u()); + assert(test7u() == 1); + //printf("sig: %d\n", test7s()); + assert(test7s() == -1); + assert(test7s2() == -2); +} + +static assert(test7u() == 1); +static assert(test7s() == -1); +static assert(test7s2() == -2); + +/******************************************/ + +int main() +{ + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/interpret.d b/gcc/testsuite/gdc.test/runnable/interpret.d index 6b1e89b..16d4c55 100644 --- a/gcc/testsuite/gdc.test/runnable/interpret.d +++ b/gcc/testsuite/gdc.test/runnable/interpret.d @@ -3454,6 +3454,21 @@ void test113() } /************************************************/ + +bool test114() +{ + string fizzBuzz() + { + string result = "fizz "; + return result ~= "buzz"; + } + + assert(fizzBuzz() == "fizz buzz"); + return true; +} +static assert(test114()); + +/************************************************/ // https://issues.dlang.org/show_bug.cgi?id=14140 struct S14140 @@ -3852,6 +3867,7 @@ int main() test109(); test112(); test113(); + test114(); test6439(); test6504(); test8818(); diff --git a/gcc/testsuite/gdc.test/runnable/test17868b.d b/gcc/testsuite/gdc.test/runnable/test17868b.d index d28cae2..44d6951 100644 --- a/gcc/testsuite/gdc.test/runnable/test17868b.d +++ b/gcc/testsuite/gdc.test/runnable/test17868b.d @@ -12,8 +12,6 @@ fini import core.stdc.stdio; -extern(C): - pragma(crt_constructor) pragma(crt_destructor) void ctor_dtor_1() @@ -45,7 +43,7 @@ template fini() alias instantiate = fini!(); -int main() +extern(C) int main() { puts("main"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable/test20734.d b/gcc/testsuite/gdc.test/runnable/test20734.d new file mode 100644 index 0000000..264602b --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test20734.d @@ -0,0 +1,28 @@ +/* +REQUIRED_ARGS: -betterC -preview=dip1000 +*/ + +__gshared int numDtor; + +struct S +{ + int a; + ~this() nothrow @nogc @trusted { ++numDtor; } +} + +void takeScopeSlice(const scope S[] slice) nothrow @nogc @safe {} + +extern(C) int main() nothrow @nogc @safe +{ + takeScopeSlice([ S(1), S(2) ]); // @nogc => no GC allocation + (() @trusted { assert(numDtor == 2); })(); // stack-allocated array literal properly destructed + return 0; +} + +// https://issues.dlang.org/show_bug.cgi?id=23098 +void f23098(scope inout(int)[] d) @safe {} + +void test23098() @safe +{ + f23098([10, 20]); +} diff --git a/gcc/testsuite/gdc.test/runnable/test21416.d b/gcc/testsuite/gdc.test/runnable/test21416.d new file mode 100644 index 0000000..88eebd8 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test21416.d @@ -0,0 +1,9 @@ +// https://issues.dlang.org/show_bug.cgi?id=21416 + +// REQUIRED_ARGS: -betterC + +extern(C) void main() {} + +extern(C++) interface IEntry {} + +extern(C++) class MyEntryInfo : IEntry {} diff --git a/gcc/testsuite/gdc.test/runnable/test23083.d b/gcc/testsuite/gdc.test/runnable/test23083.d new file mode 100644 index 0000000..41c881f --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test23083.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=23083 +int calls = 0; + +int[2] f() +{ + calls++; + return [123, 456]; +} + +void g(int a, int b) {} + +void main() +{ + g(f().tupleof); + assert(calls == 1); +} diff --git a/gcc/testsuite/gdc.test/runnable/testcontracts.d b/gcc/testsuite/gdc.test/runnable/testcontracts.d index ba0dc69..e79c6a0 100644 --- a/gcc/testsuite/gdc.test/runnable/testcontracts.d +++ b/gcc/testsuite/gdc.test/runnable/testcontracts.d @@ -1,19 +1,19 @@ /* PERMUTE_ARGS: -inline -g -O TEST_OUTPUT: --- -runnable/testcontracts.d(323): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(324): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(325): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(326): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(328): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(329): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(330): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(331): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(502): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(503): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(504): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(505): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. -runnable/testcontracts.d(505): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(323): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(324): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(325): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(326): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(328): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(329): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(330): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(331): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(502): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(503): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(504): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(505): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. +runnable/testcontracts.d(505): Deprecation: usage of the `body` keyword is deprecated. Use `do` instead. --- */ extern(C) int printf(const char*, ...); |