From 51c4eb28c192ecff4463c973a0ff089e04a80b89 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sun, 28 Jan 2024 12:23:14 +0100 Subject: [PATCH] d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9 D front-end changes: - Import latest fixes from dmd v2.107.0-beta.1. - Hex strings can now be cast to integer arrays. - Add support for Interpolated Expression Sequences. D runtime changes: - Import latest fixes from druntime v2.107.0-beta.1. - New core.interpolation module to provide run-time support for D interpolated expression sequence literals. Phobos changes: - Import latest fixes from phobos v2.107.0-beta.1. - `std.range.primitives.isBidirectionalRange', and `std.range.primitives.isRandomAccessRange' now take an optional element type. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd e770945277. * Make-lang.in (D_FRONTEND_OBJS): Add d/basicmangle.o, d/enumsem.o, d/funcsem.o, d/templatesem.o. * d-builtins.cc (build_frontend_type): Update for new front-end interface. * d-codegen.cc (declaration_type): Likewise. (parameter_type): Likewise. * d-incpath.cc (add_globalpaths): Likewise. (add_filepaths): Likewise. (add_import_paths): Likewise. * d-lang.cc (d_init_options): Likewise. (d_handle_option): Likewise. (d_parse_file): Likewise. * decl.cc (DeclVisitor::finish_vtable): Likewise. (DeclVisitor::visit (FuncDeclaration *)): Likewise. (get_symbol_decl): Likewise. * expr.cc (ExprVisitor::visit (StringExp *)): Likewise. Implement support for 8-byte hexadecimal strings. * typeinfo.cc (create_tinfo_types): Update internal TypeInfo representation. (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): Update for new front-end interface. (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise. (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Move data for TypeInfo_Class.nameSig to the end of the object. (create_typeinfo): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e770945277. * libdruntime/Makefile.am (DRUNTIME_SOURCES): Add core/interpolation.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 6d6e0b9b9. --- gcc/d/Make-lang.in | 4 + gcc/d/d-builtins.cc | 2 +- gcc/d/d-codegen.cc | 4 +- gcc/d/d-incpath.cc | 41 +- gcc/d/d-lang.cc | 34 +- gcc/d/decl.cc | 37 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/README.md | 4 + gcc/d/dmd/aggregate.h | 3 +- gcc/d/dmd/basicmangle.d | 109 ++ gcc/d/dmd/clone.d | 9 +- gcc/d/dmd/common/outbuffer.d | 27 + gcc/d/dmd/cond.d | 19 +- gcc/d/dmd/constfold.d | 6 +- gcc/d/dmd/ctfeexpr.d | 10 +- gcc/d/dmd/dclass.d | 2 + gcc/d/dmd/declaration.h | 7 +- gcc/d/dmd/denum.d | 85 - gcc/d/dmd/dinterpret.d | 68 +- gcc/d/dmd/dmangle.d | 144 +- gcc/d/dmd/dmodule.d | 6 +- gcc/d/dmd/doc.d | 3 +- gcc/d/dmd/dstruct.d | 2 +- gcc/d/dmd/dsymbolsem.d | 574 +------ gcc/d/dmd/dtemplate.d | 1646 ++------------------ gcc/d/dmd/enum.h | 2 - gcc/d/dmd/enumsem.d | 714 +++++++++ gcc/d/dmd/expression.d | 44 +- gcc/d/dmd/expression.h | 15 +- gcc/d/dmd/expressionsem.d | 103 +- gcc/d/dmd/func.d | 199 +-- gcc/d/dmd/funcsem.d | 219 +++ gcc/d/dmd/globals.d | 12 +- gcc/d/dmd/globals.h | 12 +- gcc/d/dmd/hdrgen.d | 84 + gcc/d/dmd/id.d | 6 + gcc/d/dmd/json.d | 14 +- gcc/d/dmd/lexer.d | 166 +- gcc/d/dmd/mtype.d | 56 +- gcc/d/dmd/mtype.h | 2 +- gcc/d/dmd/parse.d | 9 + gcc/d/dmd/parsetimevisitor.d | 1 + gcc/d/dmd/res/default_ddoc_theme.ddoc | 8 +- gcc/d/dmd/root/filename.d | 67 +- gcc/d/dmd/root/filename.h | 2 +- gcc/d/dmd/semantic3.d | 3 +- gcc/d/dmd/statementsem.d | 3 +- gcc/d/dmd/templatesem.d | 1497 ++++++++++++++++++ gcc/d/dmd/tokens.d | 33 +- gcc/d/dmd/tokens.h | 9 +- gcc/d/dmd/traits.d | 3 +- gcc/d/dmd/typesem.d | 26 +- gcc/d/dmd/typinf.d | 1 + gcc/d/dmd/visitor.h | 2 + gcc/d/expr.cc | 18 +- gcc/d/typeinfo.cc | 35 +- gcc/testsuite/gdc.test/compilable/test13281.d | 33 +- gcc/testsuite/gdc.test/fail_compilation/b19523.d | 11 +- gcc/testsuite/gdc.test/fail_compilation/b20011.d | 23 +- gcc/testsuite/gdc.test/fail_compilation/bug15613.d | 69 +- gcc/testsuite/gdc.test/fail_compilation/bug16165.d | 6 +- gcc/testsuite/gdc.test/fail_compilation/bug9631.d | 26 +- .../gdc.test/fail_compilation/callconst.d | 5 +- .../gdc.test/fail_compilation/constraints_aggr.d | 4 +- .../gdc.test/fail_compilation/constraints_func1.d | 26 +- .../gdc.test/fail_compilation/constraints_func2.d | 28 +- .../gdc.test/fail_compilation/constraints_func3.d | 12 +- .../gdc.test/fail_compilation/constraints_func4.d | 12 +- .../gdc.test/fail_compilation/diag13942.d | 2 +- .../gdc.test/fail_compilation/diag16977.d | 2 +- .../gdc.test/fail_compilation/diag20268.d | 2 +- .../gdc.test/fail_compilation/diag23355.d | 4 +- gcc/testsuite/gdc.test/fail_compilation/diag8101.d | 53 +- gcc/testsuite/gdc.test/fail_compilation/diag8648.d | 6 +- gcc/testsuite/gdc.test/fail_compilation/diag9004.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/diagin.d | 9 +- .../gdc.test/fail_compilation/fail12744.d | 4 +- gcc/testsuite/gdc.test/fail_compilation/fail136.d | 2 +- .../gdc.test/fail_compilation/fail14669.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail162.d | 2 +- .../gdc.test/fail_compilation/fail19948.d | 5 +- .../gdc.test/fail_compilation/fail20183.d | 3 +- .../gdc.test/fail_compilation/fail20730b.d | 2 +- .../gdc.test/fail_compilation/fail20800.d | 9 +- .../gdc.test/fail_compilation/fail22202.d | 5 +- gcc/testsuite/gdc.test/fail_compilation/fail236.d | 2 +- .../gdc.test/fail_compilation/fail24301.d | 5 +- gcc/testsuite/gdc.test/fail_compilation/fail263.d | 9 +- gcc/testsuite/gdc.test/fail_compilation/fail322.d | 14 +- gcc/testsuite/gdc.test/fail_compilation/fail332.d | 122 +- gcc/testsuite/gdc.test/fail_compilation/fail58.d | 14 +- gcc/testsuite/gdc.test/fail_compilation/fail8009.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/fail95.d | 2 +- .../gdc.test/fail_compilation/hexstring.d | 57 +- gcc/testsuite/gdc.test/fail_compilation/ice10922.d | 5 +- .../gdc.test/fail_compilation/ice11856_1.d | 6 +- gcc/testsuite/gdc.test/fail_compilation/ice12501.d | 16 +- gcc/testsuite/gdc.test/fail_compilation/ice14130.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice14907.d | 6 +- gcc/testsuite/gdc.test/fail_compilation/ice14923.d | 11 +- gcc/testsuite/gdc.test/fail_compilation/ice23097.d | 9 +- gcc/testsuite/gdc.test/fail_compilation/ice6538.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice9284.d | 2 +- gcc/testsuite/gdc.test/fail_compilation/ice9540.d | 11 +- .../fail_compilation/iconv_interface_array.d | 51 + .../interpolatedexpressionsequence_postfix.d | 13 + .../fail_compilation/named_arguments_error.d | 101 +- .../gdc.test/fail_compilation/previewin.d | 13 +- .../gdc.test/fail_compilation/pull12941.d | 6 +- .../gdc.test/fail_compilation/test19107.d | 2 +- .../gdc.test/fail_compilation/test19971.d | 7 +- .../gdc.test/fail_compilation/test21008.d | 9 +- .../gdc.test/fail_compilation/test21025.d | 2 +- .../gdc.test/fail_compilation/test21807.d | 3 +- gcc/testsuite/gdc.test/fail_compilation/ufcs.d | 23 +- gcc/testsuite/gdc.test/fail_compilation/vararg2.d | 10 +- .../runnable/interpolatedexpressionsequence.d | 51 + gcc/testsuite/gdc.test/runnable/literal.d | 22 + libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/Makefile.am | 53 +- libphobos/libdruntime/Makefile.in | 100 +- .../libdruntime/core/internal/array/construction.d | 15 +- .../libdruntime/core/internal/array/duplication.d | 10 +- libphobos/libdruntime/core/internal/array/utils.d | 1 - .../core/internal/gc/impl/conservative/gc.d | 4 +- libphobos/libdruntime/core/interpolation.d | 156 ++ libphobos/libdruntime/core/lifetime.d | 2 +- libphobos/libdruntime/core/stdc/string.d | 2 + libphobos/libdruntime/core/sys/posix/string.d | 2 - libphobos/libdruntime/core/thread/osthread.d | 5 +- libphobos/libdruntime/core/thread/threadbase.d | 10 +- libphobos/libdruntime/object.d | 5 +- libphobos/libdruntime/rt/cast_.d | 17 +- libphobos/src/MERGE | 2 +- libphobos/src/std/bitmanip.d | 6 +- libphobos/src/std/range/primitives.d | 99 +- 136 files changed, 4484 insertions(+), 3199 deletions(-) create mode 100644 gcc/d/dmd/basicmangle.d create mode 100644 gcc/d/dmd/enumsem.d create mode 100644 gcc/d/dmd/funcsem.d create mode 100644 gcc/d/dmd/templatesem.d rewrite gcc/testsuite/gdc.test/fail_compilation/bug15613.d (63%) rewrite gcc/testsuite/gdc.test/fail_compilation/fail332.d (74%) create mode 100644 gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d rewrite gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d (67%) create mode 100644 gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d create mode 100644 libphobos/libdruntime/core/interpolation.d diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index f0a03a1e3f3..176105b9a46 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -87,6 +87,7 @@ D_FRONTEND_OBJS = \ d/ast_node.o \ d/astcodegen.o \ d/astenums.o \ + d/basicmangle.o \ d/blockexit.o \ d/builtin.o \ d/canthrow.o \ @@ -122,6 +123,7 @@ D_FRONTEND_OBJS = \ d/dtoh.o \ d/dversion.o \ d/entity.o \ + d/enumsem.o \ d/errors.o \ d/errorsink.o \ d/escape.o \ @@ -130,6 +132,7 @@ D_FRONTEND_OBJS = \ d/file_manager.o \ d/foreachvar.o \ d/func.o \ + d/funcsem.o \ d/globals.o \ d/gluelayer.o \ d/hdrgen.o \ @@ -192,6 +195,7 @@ D_FRONTEND_OBJS = \ d/stmtstate.o \ d/target.o \ d/templateparamsem.o \ + d/templatesem.o \ d/tokens.o \ d/traits.o \ d/transitivevisitor.o \ diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 9d604974f85..1b5b3bea8ca 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -240,7 +240,7 @@ build_frontend_type (tree type) sdecl->sizeok = Sizeok::done; sdecl->type = (TypeStruct::create (sdecl))->addMod (mod); sdecl->type->ctype = type; - sdecl->type->merge2 (); + merge2 (sdecl->type); /* Add both named and anonymous fields as members of the struct. Anonymous fields still need a name in D, so call them "__pad%u". */ diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 22005a45fca..af938ddc04a 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -150,7 +150,7 @@ declaration_type (Declaration *decl) TypeFunction *tf = TypeFunction::create (NULL, decl->type, VARARGnone, LINK::d); TypeDelegate *t = TypeDelegate::create (tf); - return build_ctype (t->merge2 ()); + return build_ctype (merge2 (t)); } /* Static array va_list have array->pointer conversions applied. */ @@ -200,7 +200,7 @@ parameter_type (Parameter *arg) TypeFunction *tf = TypeFunction::create (NULL, arg->type, VARARGnone, LINK::d); TypeDelegate *t = TypeDelegate::create (tf); - return build_ctype (t->merge2 ()); + return build_ctype (merge2 (t)); } /* Static array va_list have array->pointer conversions applied. */ diff --git a/gcc/d/d-incpath.cc b/gcc/d/d-incpath.cc index e505f4ec6be..32ab0b71efa 100644 --- a/gcc/d/d-incpath.cc +++ b/gcc/d/d-incpath.cc @@ -71,9 +71,6 @@ add_globalpaths (Strings *paths) { if (paths) { - if (!global.path) - global.path = d_gc_malloc (); - for (size_t i = 0; i < paths->length; i++) { const char *path = (*paths)[i]; @@ -86,7 +83,7 @@ add_globalpaths (Strings *paths) continue; } - global.path->push (target); + global.path.push (target); } } } @@ -98,9 +95,6 @@ add_filepaths (Strings *paths) { if (paths) { - if (!global.filePath) - global.filePath = d_gc_malloc (); - for (size_t i = 0; i < paths->length; i++) { const char *path = (*paths)[i]; @@ -112,7 +106,7 @@ add_filepaths (Strings *paths) continue; } - global.filePath->push (target); + global.filePath.push (target); } } } @@ -143,9 +137,9 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc) /* Ignore duplicate entries. */ bool found = false; - for (size_t i = 0; i < global.params.imppath->length; i++) + for (size_t i = 0; i < global.params.imppath.length; i++) { - if (strcmp (path, (*global.params.imppath)[i]) == 0) + if (strcmp (path, global.params.imppath[i]) == 0) { found = true; break; @@ -162,33 +156,26 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc) if (imultilib) { char *target_path = concat (path, "/", imultilib, NULL); - global.params.imppath->shift (target_path); + global.params.imppath.shift (target_path); } - global.params.imppath->shift (path); + global.params.imppath.shift (path); } } /* Add import search paths. */ - if (global.params.imppath) + for (size_t i = 0; i < global.params.imppath.length; i++) { - for (size_t i = 0; i < global.params.imppath->length; i++) - { - const char *path = (*global.params.imppath)[i]; - if (path) - add_globalpaths (FileName::splitPath (path)); - } + const char *path = global.params.imppath[i]; + if (path) + add_globalpaths (FileName::splitPath (path)); } /* Add string import search paths. */ - if (global.params.fileImppath) + for (size_t i = 0; i < global.params.fileImppath.length; i++) { - for (size_t i = 0; i < global.params.fileImppath->length; i++) - { - const char *path = (*global.params.fileImppath)[i]; - if (path) - add_filepaths (FileName::splitPath (path)); - } + const char *path = global.params.fileImppath[i]; + if (path) + add_filepaths (FileName::splitPath (path)); } } - diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index aabe1ad43cb..138a7f9d0f9 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -306,9 +306,6 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options) global.params.v.errorLimit = flag_max_errors; global.params.v.messageStyle = MessageStyle::gnu; - global.params.imppath = d_gc_malloc (); - global.params.fileImppath = d_gc_malloc (); - /* Extra GDC-specific options. */ d_option.fonly = NULL; d_option.multilib = NULL; @@ -724,11 +721,11 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_I: - global.params.imppath->push (arg); + global.params.imppath.push (arg); break; case OPT_J: - global.params.fileImppath->push (arg); + global.params.fileImppath.push (arg); break; case OPT_MM: @@ -1045,25 +1042,24 @@ d_parse_file (void) { if (global.params.v.verbose) { + /* Dump information about the D compiler and language version. */ message ("binary %s", global.params.argv0.ptr); message ("version %s", global.versionChars ()); - if (global.versionids) + /* Dump all predefined version identifiers. */ + obstack buffer; + gcc_obstack_init (&buffer); + obstack_grow (&buffer, "predefs ", 9); + for (size_t i = 0; i < global.versionids.length; i++) { - obstack buffer; - gcc_obstack_init (&buffer); - obstack_grow (&buffer, "predefs ", 9); - for (size_t i = 0; i < global.versionids->length; i++) - { - Identifier *id = (*global.versionids)[i]; - const char *str = id->toChars (); - obstack_1grow (&buffer, ' '); - obstack_grow (&buffer, str, strlen (str)); - } - - obstack_1grow (&buffer, '\0'); - message ("%s", (char *) obstack_finish (&buffer)); + Identifier *id = global.versionids[i]; + const char *str = id->toChars (); + obstack_1grow (&buffer, ' '); + obstack_grow (&buffer, str, strlen (str)); } + + obstack_1grow (&buffer, '\0'); + message ("%s", (char *) obstack_finish (&buffer)); } /* Start the main input file, if the debug writer wants it. */ diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 4ca85bb970d..d2e84d3ba61 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -539,7 +539,7 @@ public: continue; /* Ensure function has a return value. */ - if (!fd->functionSemantic ()) + if (!functionSemantic (fd)) has_errors = true; /* No name hiding to check for. */ @@ -563,20 +563,23 @@ public: if (fd2->isFuture ()) continue; - if (fd->leastAsSpecialized (fd2, NULL) != MATCH::nomatch - || fd2->leastAsSpecialized (fd, NULL) != MATCH::nomatch) - { - error_at (make_location_t (fd->loc), "use of %qs", - fd->toPrettyChars ()); - inform (make_location_t (fd2->loc), "is hidden by %qs", - fd2->toPrettyChars ()); - inform (make_location_t (d->loc), - "use % to introduce base class " - "overload set", fd->toChars (), - fd->parent->toChars (), fd->toChars ()); - has_errors = true; - break; - } + if (FuncDeclaration::leastAsSpecialized (fd, fd2, NULL) + == MATCH::nomatch + && FuncDeclaration::leastAsSpecialized (fd2, fd, NULL) + == MATCH::nomatch) + continue; + + /* Hiding detected; same name, overlapping specializations. */ + error_at (make_location_t (fd->loc), "use of %qs", + fd->toPrettyChars ()); + inform (make_location_t (fd2->loc), "is hidden by %qs", + fd2->toPrettyChars ()); + inform (make_location_t (d->loc), + "use % to introduce base class " + "overload set", fd->toChars (), + fd->parent->toChars (), fd->toChars ()); + has_errors = true; + break; } } @@ -943,7 +946,7 @@ public: gcc_assert (!doing_semantic_analysis_p); doing_semantic_analysis_p = true; - d->functionSemantic3 (); + functionSemantic3 (d); Module::runDeferredSemantic3 (); doing_semantic_analysis_p = false; } @@ -1231,7 +1234,7 @@ get_symbol_decl (Declaration *decl) if (fd) { /* Run full semantic on functions we need to know about. */ - if (!fd->functionSemantic ()) + if (!functionSemantic (fd)) { decl->csym = error_mark_node; return decl->csym; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 138b0b6fa7c..9217c654225 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa +e7709452775d374c1e2dfb67566668ada3dec5fc 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 f8ac00117eb..23f3333198d 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -110,6 +110,8 @@ Note that these groups have no strict meaning, the category assignments are a bi | File | Purpose | |-------------------------------------------------------------------------------------------|-------------------------------------------------------------------| | [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) | +| [enumsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/enumsem.d) | Enum semantics | +| [funcsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/funcsem.d) | Function semantics | | [semantic2.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic2.d) | Do semantic 2 pass (symbol initializers) | | [semantic3.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic3.d) | Do semantic 3 pass (function bodies) | | [inline.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/inline.d) | Do inline pass (optimization pass that dmd does in the front-end) | @@ -117,6 +119,7 @@ Note that these groups have no strict meaning, the category assignments are a bi | [expressionsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expressionsem.d) | Do semantic analysis for expressions | | [statementsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statementsem.d) | Do semantic analysis for statements | | [initsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/initsem.d) | Do semantic analysis for initializers | +| [templatesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templatesem.d) | Do semantic analysis for templates | | [templateparamsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters | | [typesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typesem.d) | Do semantic analysis for types | @@ -230,6 +233,7 @@ Note that these groups have no strict meaning, the category assignments are a bi |-----------------------------------------------------------------------------------|------------------------------------------------------------------| | [cppmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmangle.d) | C++ name mangling | | [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmanglewin.d) | C++ name mangling for Windows | +| [basicmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/basicmangle.d) | D name mangling for basic types | | [dmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) | ### Linking diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index 9abdd094b3f..f466ba61740 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -234,7 +234,8 @@ struct ClassFlags hasTypeInfo = 0x20, isAbstract = 0x40, isCPPclass = 0x80, - hasDtor = 0x100 + hasDtor = 0x100, + hasNameSig = 0x200, }; }; diff --git a/gcc/d/dmd/basicmangle.d b/gcc/d/dmd/basicmangle.d new file mode 100644 index 00000000000..52534fa3526 --- /dev/null +++ b/gcc/d/dmd/basicmangle.d @@ -0,0 +1,109 @@ +/** + * Defines the building blocks for creating the mangled names for basic types. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/basicmangle.d, _basicmangle.d) + * Documentation: https://dlang.org/phobos/dmd_basicmangle.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/basicmangle.d + */ +module dmd.basicmangle; + +import dmd.astenums; +import dmd.common.outbuffer : OutBuffer; + +/// Type mangling mapping for basic, derived and user defined types +immutable char[TMAX] mangleChar = +[ + Tchar : 'a', + Tbool : 'b', + Tcomplex80 : 'c', + Tfloat64 : 'd', + Tfloat80 : 'e', + Tfloat32 : 'f', + Tint8 : 'g', + Tuns8 : 'h', + Tint32 : 'i', + Timaginary80 : 'j', + Tuns32 : 'k', + Tint64 : 'l', + Tuns64 : 'm', + Tnull : 'n', + Timaginary32 : 'o', + Timaginary64 : 'p', + Tcomplex32 : 'q', + Tcomplex64 : 'r', + Tint16 : 's', + Tuns16 : 't', + Twchar : 'u', + Tvoid : 'v', + Tdchar : 'w', + // x // const + // y // immutable + Tint128 : 'z', // zi + Tuns128 : 'z', // zk + + Tarray : 'A', + Ttuple : 'B', + Tclass : 'C', + Tdelegate : 'D', + Tenum : 'E', + Tfunction : 'F', // D function + Tsarray : 'G', + Taarray : 'H', + // I // in + // J // out + // K // ref + // L // lazy + // M // has this, or scope + // N // Nh:vector Ng:wild Nn:noreturn + // O // shared + Tpointer : 'P', + // Q // Type/symbol/identifier backward reference + Treference : 'R', + Tstruct : 'S', + // T // Ttypedef + // U // C function + // W // Windows function + // X // variadic T t...) + // Y // variadic T t,...) + // Z // not variadic, end of parameters + + // '@' shouldn't appear anywhere in the deco'd names + Tnone : '@', + Tident : '@', + Tinstance : '@', + Terror : '@', + Ttypeof : '@', + Tslice : '@', + Treturn : '@', + Tvector : '@', + Ttraits : '@', + Tmixin : '@', + Ttag : '@', + Tnoreturn : '@', // becomes 'Nn' +]; + +unittest +{ + foreach (i, mangle; mangleChar) + { + if (mangle == char.init) + { + import core.stdc.stdio; + fprintf(stderr, "ty = %u\n", cast(uint)i); + assert(0); + } + } +} + +/*********************** + * Mangle basic type ty to buf. + */ +void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe +{ + const c = mangleChar[ty]; + buf.writeByte(c); + if (c == 'z') + buf.writeByte(ty == Tint128 ? 'i' : 'k'); +} diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 6fbf8e284de..46470ee9e37 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -27,6 +27,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -905,7 +906,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) a.addMember(sc, ad); // temporarily add to symbol table } - sdv.dtor.functionSemantic(); + functionSemantic(sdv.dtor); stc = mergeFuncAttrs(stc, sdv.dtor); if (stc & STC.disable) @@ -1154,7 +1155,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) ad.members.push(func); func.addMember(sc2, ad); func.dsymbolSemantic(sc2); - func.functionSemantic(); // to infer attributes + functionSemantic(func); // to infer attributes sc2.pop(); return func; @@ -1336,7 +1337,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) // perform semantic on the member postblit in order to // be able to aggregate it later on with the rest of the // postblits - sdv.postblit.functionSemantic(); + functionSemantic(sdv.postblit); stc = mergeFuncAttrs(stc, sdv.postblit); stc = mergeFuncAttrs(stc, sdv.dtor); @@ -1401,7 +1402,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) */ if (sdv.dtor) { - sdv.dtor.functionSemantic(); + functionSemantic(sdv.dtor); // keep a list of fields that need to be destroyed in case // of a future postblit failure diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index cff08ec5d43..cb2439ff746 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -756,6 +756,25 @@ struct OutBuffer } /** + * Write an array as a string of hexadecimal digits + * Params: + * data = bytes to write + * upperCase = whether to upper case hex digits A-F + */ + void writeHexString(scope const(ubyte)[] data, bool upperCase) pure nothrow @safe + { + auto slice = this.allocate(2 * data.length); + const a = upperCase ? 'A' : 'a'; + foreach (i, c; data) + { + char hi = (c >> 4) & 0xF; + slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + a); + char lo = c & 0xF; + slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + a); + } + } + + /** Destructively saves the contents of `this` to `filename`. As an optimization, if the file already has identical contents with the buffer, no copying is done. This is because on SSD drives reading is often much @@ -943,3 +962,11 @@ unittest else assert(buf[] == "\nabc\n\n"); } + +unittest +{ + OutBuffer buf; + buf.writeHexString([0xAA, 0xBB], false); + buf.writeHexString([0xCC], true); + assert(buf[] == "aabbCC"); +} diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index 1b32ff774c8..e194664383e 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -548,8 +548,6 @@ extern (C++) final class DebugCondition : DVCondition /// Ditto extern(D) static void addGlobalIdent(const(char)[] ident) { - if (!global.debugids) - global.debugids = new Identifiers(); global.debugids.push(Identifier.idPool(ident)); } @@ -579,7 +577,7 @@ extern (C++) final class DebugCondition : DVCondition bool definedInModule = false; if (ident) { - if (findCondition(mod.debugids, ident)) + if (mod.debugids && findCondition(*mod.debugids, ident)) { inc = Include.yes; definedInModule = true; @@ -830,8 +828,6 @@ extern (C++) final class VersionCondition : DVCondition /// Ditto extern(D) static void addPredefinedGlobalIdent(const(char)[] ident) { - if (!global.versionids) - global.versionids = new Identifiers(); global.versionids.push(Identifier.idPool(ident)); } @@ -861,7 +857,7 @@ extern (C++) final class VersionCondition : DVCondition bool definedInModule = false; if (ident) { - if (findCondition(mod.versionids, ident)) + if (mod.versionids && findCondition(*mod.versionids, ident)) { inc = Include.yes; definedInModule = true; @@ -983,15 +979,12 @@ extern (C++) final class StaticIfCondition : Condition * Returns: * true if found */ -bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure +bool findCondition(ref Identifiers ids, Identifier ident) @safe nothrow pure { - if (ids) + foreach (id; ids) { - foreach (id; *ids) - { - if (id == ident) - return true; - } + if (id == ident) + return true; } return false; } diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index cee1f6364bc..41fed9cae49 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -711,7 +711,7 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e cmp = 1; // if dim1 winds up being 0 foreach (i; 0 .. dim1) { - uinteger_t c = es1.getCodeUnit(i); + uinteger_t c = es1.getIndex(i); auto ee2 = es2[i]; if (ee2.isConst() != 1) { @@ -1119,7 +1119,7 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) } else { - emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type); + emplaceExp!(IntegerExp)(&ue, loc, es1.getIndex(cast(size_t) i), type); } } else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64) @@ -1282,7 +1282,7 @@ void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringE Type elemType = existingAE.type.nextOf(); foreach (j; 0 .. len) { - const val = newval.getCodeUnit(j); + const val = newval.getIndex(j); (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType); } } diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 5fe1e7dccb0..af83aad5545 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -568,6 +568,9 @@ StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, T case 4: (cast(dchar*)s)[elemi] = value; break; + case 8: + (cast(ulong*)s)[elemi] = value; + break; default: assert(0); } @@ -1494,7 +1497,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len); return CTFEExp.cantexp; } - emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type); + emplaceExp!IntegerExp(pue, loc, es1.getIndex(cast(size_t) indx), type); return pue.exp(); } @@ -1704,7 +1707,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray void* s = mem.xcalloc(newlen + 1, oldse.sz); const data = oldse.peekData(); memcpy(s, data.ptr, copylen * oldse.sz); - const defaultValue = cast(uint)defaultElem.toInteger(); + const defaultValue = cast(ulong)defaultElem.toInteger(); foreach (size_t elemi; copylen .. newlen) { switch (oldse.sz) @@ -1718,6 +1721,9 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray case 4: (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue; break; + case 8: + (cast(ulong*)s)[cast(size_t)(indxlo + elemi)] = cast(ulong)defaultValue; + break; default: assert(0); } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 405e8170b2c..7e5e7e44178 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -123,6 +123,7 @@ extern (C++) struct BaseClass } } +// These must match the values in druntime/src/object.d enum ClassFlags : uint { none = 0x0, @@ -135,6 +136,7 @@ enum ClassFlags : uint isAbstract = 0x40, isCPPclass = 0x80, hasDtor = 0x100, + hasNameSig = 0x200, } /*********************************************************** diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 0e327bedfbd..e4efbbcc91b 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -30,6 +30,9 @@ class StructDeclaration; struct IntRange; struct AttributeViolation; +bool functionSemantic(FuncDeclaration* fd); +bool functionSemantic3(FuncDeclaration* fd); + //enum STC : ulong from astenums.d: #define STCundefined 0ULL @@ -698,14 +701,12 @@ public: FuncDeclaration *fdensure(FuncDeclaration *fde); Expressions *fdrequireParams(Expressions *fdrp); Expressions *fdensureParams(Expressions *fdep); - bool functionSemantic(); - bool functionSemantic3(); bool equals(const RootObject * const o) const override final; int findVtblIndex(Dsymbols *vtbl, int dim); bool overloadInsert(Dsymbol *s) override; bool inUnittest(); - MATCH leastAsSpecialized(FuncDeclaration *g, Identifiers *names); + static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names); LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc); const char *toPrettyChars(bool QualifyTypes = false) override; const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure' diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 5464ff99f58..9abdebd6adc 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -122,91 +122,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return isSpecialEnumIdent(ident) && memtype; } - Expression getDefaultValue(const ref Loc loc) - { - Expression handleErrors(){ - defaultval = ErrorExp.get(); - return defaultval; - } - //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); - // https://issues.dlang.org/show_bug.cgi?id=23904 - // Return defaultval only if it is not ErrorExp. - // A speculative context may set defaultval to ErrorExp; - // subsequent non-speculative contexts need to be able - // to print the error. - if (defaultval && !defaultval.isErrorExp()) - return defaultval; - - if (isCsymbol()) - return memtype.defaultInit(loc, true); - - if (_scope) - dsymbolSemantic(this, _scope); - if (errors) - return handleErrors(); - if (!members) - { - if (isSpecial()) - { - /* Allow these special enums to not need a member list - */ - return defaultval = memtype.defaultInit(loc); - } - - error(loc, "%s `%s` is opaque and has no default initializer", kind, toPrettyChars); - return handleErrors(); - } - - foreach (const i; 0 .. members.length) - { - EnumMember em = (*members)[i].isEnumMember(); - if (em) - { - if (em.semanticRun < PASS.semanticdone) - { - error(loc, "%s `%s` forward reference of `%s.init`", kind, toPrettyChars, toChars()); - return handleErrors(); - } - - defaultval = em.value; - return defaultval; - } - } - return handleErrors(); - } - - Type getMemtype(const ref Loc loc) - { - if (_scope) - { - /* Enum is forward referenced. We don't need to resolve the whole thing, - * just the base type - */ - if (memtype) - { - Loc locx = loc.isValid() ? loc : this.loc; - memtype = memtype.typeSemantic(locx, _scope); - } - else - { - // Run semantic to get the type from a possible first member value - dsymbolSemantic(this, _scope); - } - } - if (!memtype) - { - if (!isAnonymous() && (members || semanticRun >= PASS.semanticdone)) - memtype = Type.tint32; - else - { - Loc locx = loc.isValid() ? loc : this.loc; - error(locx, "is forward referenced looking for base type"); - return Type.terror; - } - } - return memtype; - } - override inout(EnumDeclaration) isEnumDeclaration() inout { return this; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index a3b38d9fee3..d8069c63a56 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -33,6 +33,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -440,7 +441,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta fdError("circular dependency. Functions cannot be interpreted while being compiled"); return CTFEExp.cantexp; } - if (!fd.functionSemantic3()) + if (!functionSemantic3(fd)) return CTFEExp.cantexp; if (fd.semanticRun < PASS.semantic3done) { @@ -6097,11 +6098,35 @@ public: result.type = e.to; return; } + // Disallow array type painting, except for conversions between built-in // types of identical size. if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf())) { + auto se = e1.isStringExp(); + // Allow casting a hex string literal to short[], int[] or long[] + if (se && se.hexString && se.postfix == StringExp.NoPostfix) + { + const sz = cast(size_t) e.to.nextOf().size; + if ((se.len % sz) != 0) + { + error(e.loc, "hex string length %d must be a multiple of %d to cast to `%s`", + cast(int) se.len, cast(int) sz, e.to.toChars()); + result = CTFEExp.cantexp; + return; + } + + auto str = arrayCastBigEndian((cast(const ubyte[]) se.peekString()), sz); + emplaceExp!(StringExp)(pue, e1.loc, str, se.len / sz, cast(ubyte) sz); + result = pue.exp(); + result.type = e.to; + return; + } error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars()); + if (se && se.hexString && se.postfix != StringExp.NoPostfix) + errorSupplemental(e.loc, "perhaps remove postfix `%s` from hex string", + (cast(char) se.postfix ~ "\0").ptr); + result = CTFEExp.cantexp; return; } @@ -7719,3 +7744,44 @@ private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd) if (global.params.v.verbose) message("strip %s =>\n %s", oldCE.toChars(), ce.toChars()); } + +/** + * Cast a `ubyte[]` to an array of larger integers as if we are on a big endian architecture + * Params: + * data = array with big endian data + * size = 1 for ubyte[], 2 for ushort[], 4 for uint[], 8 for ulong[] + * Returns: copy of `data`, with bytes shuffled if compiled for `version(LittleEndian)` + */ +ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size) +{ + ubyte[] impl(T)() + { + auto result = new T[](data.length / T.sizeof); + foreach (i; 0 .. result.length) + { + result[i] = 0; + foreach (j; 0 .. T.sizeof) + { + result[i] |= T(data[i * T.sizeof + j]) << ((T.sizeof - 1 - j) * 8); + } + } + return cast(ubyte[]) result; + } + switch (size) + { + case 1: return data.dup; + case 2: return impl!ushort; + case 4: return impl!uint; + case 8: return impl!ulong; + default: assert(0); + } +} + +unittest +{ + ubyte[] data = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22]; + assert(cast(ulong[]) arrayCastBigEndian(data, 8) == [0xAABBCCDDEEFF1122]); + assert(cast(uint[]) arrayCastBigEndian(data, 4) == [0xAABBCCDD, 0xEEFF1122]); + assert(cast(ushort[]) arrayCastBigEndian(data, 2) == [0xAABB, 0xCCDD, 0xEEFF, 0x1122]); + assert(cast(ubyte[]) arrayCastBigEndian(data, 1) == data); +} diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 15b77eaac4c..5bd1379d170 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -137,6 +137,7 @@ import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; +import dmd.basicmangle; import dmd.dclass; import dmd.declaration; import dmd.dinterpret; @@ -161,89 +162,6 @@ import dmd.target; import dmd.tokens; import dmd.visitor; -private immutable char[TMAX] mangleChar = -[ - Tchar : 'a', - Tbool : 'b', - Tcomplex80 : 'c', - Tfloat64 : 'd', - Tfloat80 : 'e', - Tfloat32 : 'f', - Tint8 : 'g', - Tuns8 : 'h', - Tint32 : 'i', - Timaginary80 : 'j', - Tuns32 : 'k', - Tint64 : 'l', - Tuns64 : 'm', - Tnull : 'n', - Timaginary32 : 'o', - Timaginary64 : 'p', - Tcomplex32 : 'q', - Tcomplex64 : 'r', - Tint16 : 's', - Tuns16 : 't', - Twchar : 'u', - Tvoid : 'v', - Tdchar : 'w', - // x // const - // y // immutable - Tint128 : 'z', // zi - Tuns128 : 'z', // zk - - Tarray : 'A', - Ttuple : 'B', - Tclass : 'C', - Tdelegate : 'D', - Tenum : 'E', - Tfunction : 'F', // D function - Tsarray : 'G', - Taarray : 'H', - // I // in - // J // out - // K // ref - // L // lazy - // M // has this, or scope - // N // Nh:vector Ng:wild Nn:noreturn - // O // shared - Tpointer : 'P', - // Q // Type/symbol/identifier backward reference - Treference : 'R', - Tstruct : 'S', - // T // Ttypedef - // U // C function - // W // Windows function - // X // variadic T t...) - // Y // variadic T t,...) - // Z // not variadic, end of parameters - - // '@' shouldn't appear anywhere in the deco'd names - Tnone : '@', - Tident : '@', - Tinstance : '@', - Terror : '@', - Ttypeof : '@', - Tslice : '@', - Treturn : '@', - Tvector : '@', - Ttraits : '@', - Tmixin : '@', - Ttag : '@', - Tnoreturn : '@', // becomes 'Nn' -]; - -unittest -{ - foreach (i, mangle; mangleChar) - { - if (mangle == char.init) - { - fprintf(stderr, "ty = %u\n", cast(uint)i); - assert(0); - } - } -} - /************************************************ * Append the mangling of type `t` to `buf`. * Params: @@ -584,6 +502,20 @@ public: toBuffer(*buf, id.toString(), s); } + void mangleInteger(dinteger_t v) + { + if (cast(sinteger_t) v < 0) + { + buf.writeByte('N'); + buf.print(-v); + } + else + { + buf.writeByte('i'); + buf.print(v); + } + } + //////////////////////////////////////////////////////////////////////////// void mangleDecl(Declaration sthis) { @@ -991,17 +923,7 @@ public: override void visit(IntegerExp e) { - const v = e.toInteger(); - if (cast(sinteger_t)v < 0) - { - buf.writeByte('N'); - buf.print(-v); - } - else - { - buf.writeByte('i'); - buf.print(v); - } + mangleInteger(e.toInteger()); } override void visit(RealExp e) @@ -1028,6 +950,7 @@ public: char m; OutBuffer tmp; const(char)[] q; + /* Write string in UTF-8 format */ switch (e.sz) @@ -1065,7 +988,15 @@ public: q = tmp[]; break; } - + case 8: + // String of size 8 has to be hexstring cast to long[], mangle as array literal + buf.writeByte('A'); + buf.print(e.len); + foreach (i; 0 .. e.len) + { + mangleInteger(e.getIndex(i)); + } + return; default: assert(0); } @@ -1073,14 +1004,7 @@ public: buf.writeByte(m); buf.print(q.length); buf.writeByte('_'); // nbytes <= 11 - auto slice = buf.allocate(2 * q.length); - foreach (i, c; q) - { - char hi = (c >> 4) & 0xF; - slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a'); - char lo = c & 0xF; - slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a'); - } + buf.writeHexString(cast(const(ubyte)[]) q, false); } override void visit(ArrayLiteralExp e) @@ -1168,6 +1092,7 @@ private struct Backref { if (t.isFunction_Delegate_PtrToFunction()) { + import dmd.typesem : merge2; t = t.merge2(); } } @@ -1213,19 +1138,6 @@ private struct Backref AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf } - -/*********************** - * Mangle basic type ty to buf. - */ - -private void tyToDecoBuffer(ref OutBuffer buf, int ty) @safe -{ - const c = mangleChar[ty]; - buf.writeByte(c); - if (c == 'z') - buf.writeByte(ty == Tint128 ? 'i' : 'k'); -} - /********************************* * Mangling for mod. */ diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 59d40655253..6167e2a7486 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -490,7 +490,7 @@ extern (C++) final class Module : Package extern (D) static const(char)[] find(const(char)[] filename) { - return global.fileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null); + return global.fileManager.lookForSourceFile(filename, global.path[]); } extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident) @@ -644,9 +644,9 @@ extern (C++) final class Module : Package { /* Print path */ - if (global.path) + if (global.path.length) { - foreach (i, p; *global.path) + foreach (i, p; global.path[]) fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p); } else diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index ec3cc91409b..bcf358cb5e9 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -5204,6 +5204,7 @@ void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) highlight = "$(D_COMMENT "; break; case TOK.string_: + case TOK.interpolated: highlight = "$(D_STRING "; break; default: @@ -5216,7 +5217,7 @@ void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) res.writestring(highlight); size_t o = res.length; highlightCode3(sc, res, tok.ptr, lex.p); - if (tok.value == TOK.comment || tok.value == TOK.string_) + if (tok.value == TOK.comment || tok.value == TOK.string_ || tok.value == TOK.interpolated) /* https://issues.dlang.org/show_bug.cgi?id=7656 * https://issues.dlang.org/show_bug.cgi?id=7715 * https://issues.dlang.org/show_bug.cgi?id=10519 diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 5683d5fb1d5..7546fb6146b 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -616,7 +616,7 @@ bool _isZeroInit(Expression exp) foreach (i; 0 .. se.len) { - if (se.getCodeUnit(i)) + if (se.getIndex(i) != 0) return false; } return true; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index e9cdb945b57..658beafdf83 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -38,11 +38,13 @@ import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; import dmd.dversion; +import dmd.enumsem; import dmd.errors; import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -440,6 +442,15 @@ private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc return false; } +// Save the scope and defer semantic analysis on the Dsymbol. +void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope *scx) +{ + s._scope = scx ? scx : sc.copy(); + s._scope.setNoFree(); + Module.addDeferredSemantic(s); +} + + private extern(C++) final class DsymbolSemanticVisitor : Visitor { alias visit = Visitor.visit; @@ -450,14 +461,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor this.sc = sc; } - // Save the scope and defer semantic analysis on the Dsymbol. - private void deferDsymbolSemantic(Dsymbol s, Scope *scx) - { - s._scope = scx ? scx : sc.copy(); - s._scope.setNoFree(); - Module.addDeferredSemantic(s); - } - override void visit(Dsymbol dsym) { .error(dsym.loc, "%s `%s` %p has no semantic routine", dsym.kind, dsym.toPrettyChars, dsym); @@ -2301,543 +2304,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(EnumDeclaration ed) { - //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); - //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); - if (ed.semanticRun >= PASS.semanticdone) - return; // semantic() already completed - if (ed.semanticRun == PASS.semantic) - { - assert(ed.memtype); - error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); - ed.errors = true; - ed.semanticRun = PASS.semanticdone; - return; - } - Scope* scx = null; - if (ed._scope) - { - sc = ed._scope; - scx = ed._scope; // save so we don't make redundant copies - ed._scope = null; - } - - if (!sc) - return; - - ed.parent = sc.parent; - ed.type = ed.type.typeSemantic(ed.loc, sc); - - ed.visibility = sc.visibility; - if (sc.stc & STC.deprecated_) - ed.isdeprecated = true; - ed.userAttribDecl = sc.userAttribDecl; - ed.cppnamespace = sc.namespace; - - ed.semanticRun = PASS.semantic; - UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage); - checkMustUseReserved(ed); - - if (!ed.members && !ed.memtype) // enum ident; - { - ed.semanticRun = PASS.semanticdone; - return; - } - - if (!ed.symtab) - ed.symtab = new DsymbolTable(); - - /* The separate, and distinct, cases are: - * 1. enum { ... } - * 2. enum : memtype { ... } - * 3. enum ident { ... } - * 4. enum ident : memtype { ... } - * 5. enum ident : memtype; - * 6. enum ident; - */ - - if (ed.memtype) - { - ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); - - /* Check to see if memtype is forward referenced - */ - if (auto te = ed.memtype.isTypeEnum()) - { - auto sym = te.toDsymbol(sc).isEnumDeclaration(); - // Special enums like __c_[u]long[long] are fine to forward reference - // see https://issues.dlang.org/show_bug.cgi?id=20599 - if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope)) - { - // memtype is forward referenced, so try again later - deferDsymbolSemantic(ed, scx); - //printf("\tdeferring %s\n", toChars()); - ed.semanticRun = PASS.initial; - return; - } - else - // Ensure that semantic is run to detect. e.g. invalid forward references - sym.dsymbolSemantic(sc); - } - if (ed.memtype.ty == Tvoid) - { - .error(ed.loc, "%s `%s` base type must not be `void`", ed.kind, ed.toPrettyChars); - ed.memtype = Type.terror; - } - if (ed.memtype.ty == Terror) - { - ed.errors = true; - // poison all the members - ed.members.foreachDsymbol( (s) { s.errors = true; } ); - ed.semanticRun = PASS.semanticdone; - return; - } - } - - if (!ed.members) // enum ident : memtype; - { - ed.semanticRun = PASS.semanticdone; - return; - } - - if (ed.members.length == 0) - { - .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars()); - ed.errors = true; - ed.semanticRun = PASS.semanticdone; - return; - } - - if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done - ed.semanticRun = PASS.semanticdone; - - version (none) - { - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.100 - // Make an error in 2.110 - if (sc.stc & STC.scope_) - deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); - } - - Scope* sce; - if (ed.isAnonymous()) - sce = sc; - else - { - sce = sc.push(ed); - sce.parent = ed; - } - sce = sce.startCTFE(); - sce.setNoFree(); // needed for getMaxMinValue() - - /* Each enum member gets the sce scope - */ - ed.members.foreachDsymbol( (s) - { - EnumMember em = s.isEnumMember(); - if (em) - em._scope = sce; - }); - - /* addMember() is not called when the EnumDeclaration appears as a function statement, - * so we have to do what addMember() does and install the enum members in the right symbol - * table - */ - addEnumMembersToSymtab(ed, sc, sc.getScopesym()); - - if (sc.flags & SCOPE.Cfile) - { - /* C11 6.7.2.2 - */ - Type commonType = ed.memtype; - if (!commonType) - commonType = Type.tint32; - ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 - - // C11 6.7.2.2-2 value must be representable as an int. - // The sizemask represents all values that int will fit into, - // from 0..uint.max. We want to cover int.min..uint.max. - IntRange ir = IntRange.fromType(commonType); - - void emSemantic(EnumMember em, ref ulong nextValue) - { - static void errorReturn(EnumMember em) - { - em.value = ErrorExp.get(); - em.errors = true; - em.semanticRun = PASS.semanticdone; - } - - em.semanticRun = PASS.semantic; - em.type = commonType; - em._linkage = LINK.c; - em.storage_class |= STC.manifest; - if (em.value) - { - Expression e = em.value; - assert(e.dyncast() == DYNCAST.expression); - - /* To merge the type of e with commonType, add 0 of type commonType - */ - if (!ed.memtype) - e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType)); - - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - e = e.integralPromotions(sc); - e = e.ctfeInterpret(); - if (e.op == EXP.error) - return errorReturn(em); - auto ie = e.isIntegerExp(); - if (!ie) - { - // C11 6.7.2.2-2 - .error(em.loc, "%s `%s` enum member must be an integral constant expression, not `%s` of type `%s`", em.kind, em.toPrettyChars, e.toChars(), e.type.toChars()); - return errorReturn(em); - } - if (ed.memtype && !ir.contains(getIntRange(ie))) - { - // C11 6.7.2.2-2 - .error(em.loc, "%s `%s` enum member value `%s` does not fit in `%s`", em.kind, em.toPrettyChars, e.toChars(), commonType.toChars()); - return errorReturn(em); - } - nextValue = ie.toInteger(); - if (!ed.memtype) - commonType = e.type; - em.value = new IntegerExp(em.loc, nextValue, commonType); - } - else - { - // C11 6.7.2.2-3 add 1 to value of previous enumeration constant - bool first = (em == (*em.ed.members)[0]); - if (!first) - { - Expression max = getProperty(commonType, null, em.loc, Id.max, 0); - if (nextValue == max.toInteger()) - { - .error(em.loc, "%s `%s` initialization with `%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, max.toChars(), commonType.toChars()); - return errorReturn(em); - } - nextValue += 1; - } - em.value = new IntegerExp(em.loc, nextValue, commonType); - } - em.type = commonType; - em.semanticRun = PASS.semanticdone; - } - - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - emSemantic(em, nextValue); - }); - - if (!ed.memtype) - { - // cast all members to commonType - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - { - em.type = commonType; - em.value = em.value.castTo(sc, commonType); - } - }); - } - - ed.memtype = commonType; - ed.semanticRun = PASS.semanticdone; - return; - } - - ed.members.foreachDsymbol( (s) - { - if (EnumMember em = s.isEnumMember()) - em.dsymbolSemantic(em._scope); - }); - //printf("defaultval = %lld\n", defaultval); - - //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars()); - //printf("members = %s\n", members.toChars()); + enumSemantic(sc, ed); } override void visit(EnumMember em) { - //printf("EnumMember::semantic() %s\n", em.toChars()); - - void errorReturn() - { - em.errors = true; - em.semanticRun = PASS.semanticdone; - } - - if (em.errors || em.semanticRun >= PASS.semanticdone) - return; - if (em.semanticRun == PASS.semantic) - { - .error(em.loc, "%s `%s` circular reference to `enum` member", em.kind, em.toPrettyChars); - return errorReturn(); - } - assert(em.ed); - - em.ed.dsymbolSemantic(sc); - if (em.ed.errors) - return errorReturn(); - if (em.errors || em.semanticRun >= PASS.semanticdone) - return; - - if (em._scope) - sc = em._scope; - if (!sc) - return; - - em.semanticRun = PASS.semantic; - - em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_); - em._linkage = LINK.d; - em.storage_class |= STC.manifest; - - // https://issues.dlang.org/show_bug.cgi?id=9701 - if (em.ed.isAnonymous()) - { - if (em.userAttribDecl) - em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; - else - em.userAttribDecl = em.ed.userAttribDecl; - } - - // Eval UDA in this same scope. Issues 19344, 20835, 21122 - if (em.userAttribDecl) - { - // Set scope but avoid extra sc.uda attachment inside setScope() - auto inneruda = em.userAttribDecl.userAttribDecl; - em.userAttribDecl.setScope(sc); - em.userAttribDecl.userAttribDecl = inneruda; - em.userAttribDecl.dsymbolSemantic(sc); - } - - // The first enum member is special - bool first = (em == (*em.ed.members)[0]); - - if (em.origType) - { - em.origType = em.origType.typeSemantic(em.loc, sc); - em.type = em.origType; - assert(em.value); // "type id;" is not a valid enum member declaration - } - - if (em.value) - { - Expression e = em.value; - assert(e.dyncast() == DYNCAST.expression); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - e = e.ctfeInterpret(); - if (e.op == EXP.error) - return errorReturn(); - if (first && !em.ed.memtype && !em.ed.isAnonymous()) - { - em.ed.memtype = e.type; - if (em.ed.memtype.ty == Terror) - { - em.ed.errors = true; - return errorReturn(); - } - if (em.ed.memtype.ty != Terror) - { - /* https://issues.dlang.org/show_bug.cgi?id=11746 - * All of named enum members should have same type - * with the first member. If the following members were referenced - * during the first member semantic, their types should be unified. - */ - em.ed.members.foreachDsymbol( (s) - { - EnumMember enm = s.isEnumMember(); - if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) - return; - - //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); - Expression ev = enm.value; - ev = ev.implicitCastTo(sc, em.ed.memtype); - ev = ev.ctfeInterpret(); - ev = ev.castTo(sc, em.ed.type); - if (ev.op == EXP.error) - em.ed.errors = true; - enm.value = ev; - }); - - if (em.ed.errors) - { - em.ed.memtype = Type.terror; - return errorReturn(); - } - } - } - - if (em.ed.memtype && !em.origType) - { - e = e.implicitCastTo(sc, em.ed.memtype); - e = e.ctfeInterpret(); - - // save origValue for better json output - em.origValue = e; - - if (!em.ed.isAnonymous()) - { - e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 - e = e.ctfeInterpret(); - } - } - else if (em.origType) - { - e = e.implicitCastTo(sc, em.origType); - e = e.ctfeInterpret(); - assert(em.ed.isAnonymous()); - - // save origValue for better json output - em.origValue = e; - } - em.value = e; - } - else if (first) - { - Type t; - if (em.ed.memtype) - t = em.ed.memtype; - else - { - t = Type.tint32; - if (!em.ed.isAnonymous()) - em.ed.memtype = t; - } - const errors = global.startGagging(); - Expression e = new IntegerExp(em.loc, 0, t); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - error(em.loc, "cannot generate 0 value of type `%s` for `%s`", - t.toChars(), em.toChars()); - } - // save origValue for better json output - em.origValue = e; - - if (!em.ed.isAnonymous()) - { - e = e.castTo(sc, em.ed.type); - e = e.ctfeInterpret(); - } - em.value = e; - } - else - { - /* Find the previous enum member, - * and set this to be the previous value + 1 - */ - EnumMember emprev = null; - em.ed.members.foreachDsymbol( (s) - { - if (auto enm = s.isEnumMember()) - { - if (enm == em) - return 1; // found - emprev = enm; - } - return 0; // continue - }); - - assert(emprev); - if (emprev.semanticRun < PASS.semanticdone) // if forward reference - emprev.dsymbolSemantic(emprev._scope); // resolve it - if (emprev.errors) - return errorReturn(); - - auto errors = global.startGagging(); - Expression eprev = emprev.value; - assert(eprev); - // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 - Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) - ? em.ed.memtype - : eprev.type; - /* - https://issues.dlang.org/show_bug.cgi?id=20777 - Previously this used getProperty, which doesn't consider anything user defined, - this construct does do that and thus fixes the bug. - */ - Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); - emax = emax.expressionSemantic(sc); - emax = emax.ctfeInterpret(); - - // check that (eprev != emax) - Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); - e = e.expressionSemantic(sc); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - // display an introductory error before showing what actually failed - error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars()); - // rerun to show errors - Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); - e2 = e2.expressionSemantic(sc); - e2 = e2.ctfeInterpret(); - e2 = new EqualExp(EXP.equal, em.loc, eprev, e2); - e2 = e2.expressionSemantic(sc); - e2 = e2.ctfeInterpret(); - } - // now any errors are for generating a value - if (e.toInteger()) - { - auto mt = em.ed.memtype; - if (!mt) - mt = eprev.type; - .error(em.loc, "%s `%s` initialization with `%s.%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, - emprev.ed.toChars(), emprev.toChars(), mt.toChars()); - return errorReturn(); - } - errors = global.startGagging(); - // Now set e to (eprev + 1) - e = new AddExp(em.loc, eprev, IntegerExp.literal!1); - e = e.expressionSemantic(sc); - e = e.castTo(sc, eprev.type); - e = e.ctfeInterpret(); - if (global.endGagging(errors)) - { - error(em.loc, "cannot generate value for `%s`", em.toPrettyChars()); - // rerun to show errors - Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1); - e2 = e2.expressionSemantic(sc); - e2 = e2.castTo(sc, eprev.type); - e2 = e2.ctfeInterpret(); - } - // save origValue (without cast) for better json output - if (e.op != EXP.error) // avoid duplicate diagnostics - { - assert(emprev.origValue); - em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); - em.origValue = em.origValue.expressionSemantic(sc); - em.origValue = em.origValue.ctfeInterpret(); - } - - if (e.op == EXP.error) - return errorReturn(); - if (e.type.isfloating()) - { - // Check that e != eprev (not always true for floats) - Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev); - etest = etest.expressionSemantic(sc); - etest = etest.ctfeInterpret(); - if (etest.toInteger()) - { - .error(em.loc, "%s `%s` has inexact value due to loss of precision", em.kind, em.toPrettyChars); - return errorReturn(); - } - } - em.value = e; - } - if (!em.origType) - em.type = em.value.type; - - assert(em.origValue); - em.semanticRun = PASS.semanticdone; + enumMemberSemantic(sc, em); } override void visit(TemplateDeclaration tempdecl) @@ -3026,7 +2498,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (tm.semanticRun == PASS.initial) // forward reference had occurred { //printf("forward reference - deferring\n"); - return deferDsymbolSemantic(tm, scx); + return deferDsymbolSemantic(sc, tm, scx); } tm.inst = tm; @@ -3740,7 +3212,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor continue; if (cbd.parent && cbd.parent.isTemplateInstance()) { - if (!f2.functionSemantic()) + if (!functionSemantic(f2)) goto Ldone; } may_override = true; @@ -4945,7 +4417,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc2.pop(); if (log) printf("\tdeferring %s\n", sd.toChars()); - return deferDsymbolSemantic(sd, scx); + return deferDsymbolSemantic(sc, sd, scx); } /* Look for special member functions. @@ -5336,7 +4808,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { // Forward referencee of one or more bases, try again later //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } cldec.baseok = Baseok.done; @@ -5446,7 +4918,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (tc.sym._scope) Module.addDeferredSemantic(tc.sym); //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } } @@ -5563,7 +5035,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc2.pop(); //printf("\tdeferring %s\n", toChars()); - return deferDsymbolSemantic(cldec, scx); + return deferDsymbolSemantic(sc, cldec, scx); } /* Look for special member functions. @@ -5905,7 +5377,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (idec.baseok == Baseok.none) { // Forward referencee of one or more bases, try again later - return deferDsymbolSemantic(idec, scx); + return deferDsymbolSemantic(sc, idec, scx); } idec.baseok = Baseok.done; @@ -5942,7 +5414,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Forward referencee of one or more bases, try again later if (tc.sym._scope) Module.addDeferredSemantic(tc.sym); - return deferDsymbolSemantic(idec, scx); + return deferDsymbolSemantic(sc, idec, scx); } } @@ -6281,7 +5753,7 @@ private extern(C++) class AddMemberVisitor : Visitor } else { - if (findCondition(m.debugidsNot, ds.ident)) + if (m.debugidsNot && findCondition(*m.debugidsNot, ds.ident)) { .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars); ds.errors = true; @@ -6319,7 +5791,7 @@ private extern(C++) class AddMemberVisitor : Visitor } else { - if (findCondition(m.versionidsNot, vs.ident)) + if (m.versionidsNot && findCondition(*m.versionidsNot, vs.ident)) { .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars); vs.errors = true; diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 13cc32f73e0..465ae7453cd 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -60,6 +60,7 @@ import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -76,6 +77,7 @@ import dmd.common.outbuffer; import dmd.rootobject; import dmd.semantic2; import dmd.semantic3; +import dmd.templatesem; import dmd.tokens; import dmd.typesem; import dmd.visitor; @@ -373,7 +375,7 @@ Lnomatch: /************************************ * Match an array of them. */ -private bool arrayObjectMatch(ref Objects oa1, ref Objects oa2) +bool arrayObjectMatch(ref Objects oa1, ref Objects oa2) { if (&oa1 == &oa2) return true; @@ -586,9 +588,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol // threaded list of previous instantiation attempts on stack TemplatePrevious* previous; - private Expression lastConstraint; /// the constraint after the last failed evaluation - private Array!Expression lastConstraintNegs; /// its negative parts - private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint` + Expression lastConstraint; /// the constraint after the last failed evaluation + Array!Expression lastConstraintNegs; /// its negative parts + Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint` extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false) { @@ -743,1545 +745,75 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol override const(char)* toChars() const { - return toCharsMaybeConstraints(true); - } - - /**************************** - * Similar to `toChars`, but does not print the template constraints - */ - const(char)* toCharsNoConstraints() const - { - return toCharsMaybeConstraints(false); - } - - // Note: this function is not actually `const`, because iterating the - // function parameter list may run dsymbolsemantic on enum types - const(char)* toCharsMaybeConstraints(bool includeConstraints) const - { - OutBuffer buf; - HdrGenState hgs; - - buf.writestring(ident == Id.ctor ? "this" : ident.toString()); - buf.writeByte('('); - foreach (i, const tp; *parameters) - { - if (i) - buf.writestring(", "); - toCBuffer(tp, buf, hgs); - } - buf.writeByte(')'); - - if (onemember) - { - if (const fd = onemember.isFuncDeclaration()) - { - if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) - { - // !! Casted away const - buf.writestring(parametersTypeToChars(tf.parameterList)); - if (tf.mod) - { - buf.writeByte(' '); - buf.MODtoBuffer(tf.mod); - } - } - } - } - - if (includeConstraints && - constraint) - { - buf.writestring(" if ("); - toCBuffer(constraint, buf, hgs); - buf.writeByte(')'); - } - - return buf.extractChars(); - } - - override Visibility visible() pure nothrow @nogc @safe - { - return visibility; - } - - /**************************** - * Check to see if constraint is satisfied. - */ - private bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) - { - /* Detect recursive attempts to instantiate this template declaration, - * https://issues.dlang.org/show_bug.cgi?id=4072 - * void foo(T)(T x) if (is(typeof(foo(x)))) { } - * static assert(!is(typeof(foo(7)))); - * Recursive attempts are regarded as a constraint failure. - */ - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (enclosing is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ - - for (TemplatePrevious* p = previous; p; p = p.prev) - { - if (!arrayObjectMatch(*p.dedargs, *dedargs)) - continue; - //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); - /* It must be a subscope of p.sc, other scope chains are not recursive - * instantiations. - * the chain of enclosing scopes is broken by paramscope (its enclosing - * scope is _scope, but paramscope.callsc is the instantiating scope). So - * it's good enough to check the chain of callsc - */ - for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc) - { - // The first scx might be identical for nested eponymeous templates, e.g. - // template foo() { void foo()() {...} } - if (scx == p.sc && scx !is paramscope.callsc) - return false; - } - /* BUG: should also check for ref param differences - */ - } - - TemplatePrevious pr; - pr.prev = previous; - pr.sc = paramscope.callsc; - pr.dedargs = dedargs; - previous = ≺ // add this to threaded list - - Scope* scx = paramscope.push(ti); - scx.parent = ti; - scx.tinst = null; - scx.minst = null; - // Set SCOPE.constraint before declaring function parameters for the static condition - // (previously, this was immediately before calling evalStaticCondition), so the - // semantic pass knows not to issue deprecation warnings for these throw-away decls. - // https://issues.dlang.org/show_bug.cgi?id=21831 - scx.flags |= SCOPE.constraint; - - assert(!ti.symtab); - if (fd) - { - /* Declare all the function parameters as variables and add them to the scope - * Making parameters is similar to FuncDeclaration.semantic3 - */ - auto tf = fd.type.isTypeFunction(); - - scx.parent = fd; - - Parameters* fparameters = tf.parameterList.parameters; - const nfparams = tf.parameterList.length; - foreach (i, fparam; tf.parameterList) - { - fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); - fparam.storageClass |= STC.parameter; - if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams) - { - fparam.storageClass |= STC.variadic; - /* Don't need to set STC.scope_ because this will only - * be evaluated at compile time - */ - } - } - foreach (fparam; *fparameters) - { - if (!fparam.ident) - continue; - // don't add it, if it has no name - auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null); - fparam.storageClass |= STC.parameter; - v.storage_class = fparam.storageClass; - v.dsymbolSemantic(scx); - if (!ti.symtab) - ti.symtab = new DsymbolTable(); - if (!scx.insert(v)) - .error(loc, "%s `%s` parameter `%s.%s` is already defined", kind, toPrettyChars, toChars(), v.toChars()); - else - v.parent = fd; - } - if (isstatic) - fd.storage_class |= STC.static_; - fd.declareThis(scx); - } - - lastConstraint = constraint.syntaxCopy(); - lastConstraintTiargs = ti.tiargs; - lastConstraintNegs.setDim(0); - - import dmd.staticcond; - - assert(ti.inst is null); - ti.inst = ti; // temporary instantiation to enable genIdent() - bool errors; - const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs); - if (result || errors) - { - lastConstraint = null; - lastConstraintTiargs = null; - lastConstraintNegs.setDim(0); - } - ti.inst = null; - ti.symtab = null; - scx = scx.pop(); - previous = pr.prev; // unlink from threaded list - if (errors) - return false; - return result; - } - - /**************************** - * Destructively get the error message from the last constraint evaluation - * Params: - * tip = tip to show after printing all overloads - */ - const(char)* getConstraintEvalError(ref const(char)* tip) - { - import dmd.staticcond; - - // there will be a full tree view in verbose mode, and more compact list in the usual - const full = global.params.v.verbose; - uint count; - const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count); - scope (exit) - { - lastConstraint = null; - lastConstraintTiargs = null; - lastConstraintNegs.setDim(0); - } - if (!msg) - return null; - - OutBuffer buf; - - assert(parameters && lastConstraintTiargs); - if (parameters.length > 0) - { - formatParamsWithTiargs(*lastConstraintTiargs, buf); - buf.writenl(); - } - if (!full) - { - // choosing singular/plural - const s = (count == 1) ? - " must satisfy the following constraint:" : - " must satisfy one of the following constraints:"; - buf.writestring(s); - buf.writenl(); - // the constraints - buf.writeByte('`'); - buf.writestring(msg); - buf.writeByte('`'); - } - else - { - buf.writestring(" whose parameters have the following constraints:"); - buf.writenl(); - const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`"; - buf.writestring(sep); - buf.writenl(); - // the constraints - buf.writeByte('`'); - buf.writestring(msg); - buf.writeByte('`'); - buf.writestring(sep); - tip = "not satisfied constraints are marked with `>`"; - } - return buf.extractChars(); - } - - private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf) - { - buf.writestring(" with `"); - - // write usual arguments line-by-line - // skips trailing default ones - they are not present in `tiargs` - const bool variadic = isVariadic() !is null; - const end = cast(int)parameters.length - (variadic ? 1 : 0); - uint i; - for (; i < tiargs.length && i < end; i++) - { - if (i > 0) - { - buf.writeByte(','); - buf.writenl(); - buf.writestring(" "); - } - write(buf, (*parameters)[i]); - buf.writestring(" = "); - write(buf, tiargs[i]); - } - // write remaining variadic arguments on the last line - if (variadic) - { - if (i > 0) - { - buf.writeByte(','); - buf.writenl(); - buf.writestring(" "); - } - write(buf, (*parameters)[end]); - buf.writestring(" = "); - buf.writeByte('('); - if (cast(int)tiargs.length - end > 0) - { - write(buf, tiargs[end]); - foreach (j; parameters.length .. tiargs.length) - { - buf.writestring(", "); - write(buf, tiargs[j]); - } - } - buf.writeByte(')'); - } - buf.writeByte('`'); - } - - /****************************** - * Create a scope for the parameters of the TemplateInstance - * `ti` in the parent scope sc from the ScopeDsymbol paramsym. - * - * If paramsym is null a new ScopeDsymbol is used in place of - * paramsym. - * Params: - * ti = the TemplateInstance whose parameters to generate the scope for. - * sc = the parent scope of ti - * Returns: - * a scope for the parameters of ti - */ - Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc) - { - ScopeDsymbol paramsym = new ScopeDsymbol(); - paramsym.parent = _scope.parent; - Scope* paramscope = _scope.push(paramsym); - paramscope.tinst = ti; - paramscope.minst = sc.minst; - paramscope.callsc = sc; - paramscope.stc = 0; - return paramscope; - } - - /*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - private MATCH matchWithInstance(Scope* sc, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag) - { - enum LOGM = 0; - static if (LOGM) - { - printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag); - } - version (none) - { - printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length); - if (ti.tiargs.length) - printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]); - } - MATCH nomatch() - { - static if (LOGM) - { - printf(" no match\n"); - } - return MATCH.nomatch; - } - MATCH m; - size_t dedtypes_dim = dedtypes.length; - - dedtypes.zero(); - - if (errors) - return MATCH.nomatch; - - size_t parameters_dim = parameters.length; - int variadic = isVariadic() !is null; - - // If more arguments than parameters, no match - if (ti.tiargs.length > parameters_dim && !variadic) - { - static if (LOGM) - { - printf(" no match: more arguments than parameters\n"); - } - return MATCH.nomatch; - } - - assert(dedtypes_dim == parameters_dim); - assert(dedtypes_dim >= ti.tiargs.length || variadic); - - assert(_scope); - - // Set up scope for template parameters - Scope* paramscope = scopeForTemplateParameters(ti,sc); - - // Attempt type deduction - m = MATCH.exact; - for (size_t i = 0; i < dedtypes_dim; i++) - { - MATCH m2; - TemplateParameter tp = (*parameters)[i]; - Declaration sparam; - - //printf("\targument [%d]\n", i); - static if (LOGM) - { - //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); - TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); - if (ttp) - printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); - } - - m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam); - //printf("\tm2 = %d\n", m2); - if (m2 == MATCH.nomatch) - { - version (none) - { - printf("\tmatchArg() for parameter %i failed\n", i); - } - return nomatch(); - } - - if (m2 < m) - m = m2; - - if (!flag) - sparam.dsymbolSemantic(paramscope); - if (!paramscope.insert(sparam)) // TODO: This check can make more early - { - // in TemplateDeclaration.semantic, and - // then we don't need to make sparam if flags == 0 - return nomatch(); - } - } - - if (!flag) - { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - foreach (i, ref dedtype; dedtypes) - { - if (!dedtype) - { - assert(i < ti.tiargs.length); - dedtype = cast(Type)(*ti.tiargs)[i]; - } - } - } - - if (m > MATCH.nomatch && constraint && !flag) - { - if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error - ti.parent = ti.enclosing; - else - ti.parent = this.parent; - - // Similar to doHeaderInstantiation - FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null; - if (fd) - { - TypeFunction tf = fd.type.isTypeFunction().syntaxCopy(); - if (argumentList.hasNames) - return nomatch(); - Expressions* fargs = argumentList.arguments; - // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null); - // if (!fargs) - // return nomatch(); - - fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); - fd.parent = ti; - fd.inferRetType = true; - - // Shouldn't run semantic on default arguments and return type. - foreach (ref param; *tf.parameterList.parameters) - param.defaultArg = null; - - tf.next = null; - tf.incomplete = true; - - // Resolve parameter types and 'auto ref's. - tf.fargs = fargs; - uint olderrors = global.startGagging(); - fd.type = tf.typeSemantic(loc, paramscope); - global.endGagging(olderrors); - if (fd.type.ty != Tfunction) - return nomatch(); - fd.originalType = fd.type; // for mangling - } - - // TODO: dedtypes => ti.tiargs ? - if (!evaluateConstraint(ti, sc, paramscope, &dedtypes, fd)) - return nomatch(); - } - - static if (LOGM) - { - // Print out the results - printf("--------------------------\n"); - printf("template %s\n", toChars()); - printf("instance %s\n", ti.toChars()); - if (m > MATCH.nomatch) - { - for (size_t i = 0; i < dedtypes_dim; i++) - { - TemplateParameter tp = (*parameters)[i]; - RootObject oarg; - printf(" [%d]", i); - if (i < ti.tiargs.length) - oarg = (*ti.tiargs)[i]; - else - oarg = null; - tp.print(oarg, (*dedtypes)[i]); - } - } - else - return nomatch(); - } - static if (LOGM) - { - printf(" match = %d\n", m); - } - - paramscope.pop(); - static if (LOGM) - { - printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m); - } - return m; - } - - /******************************************** - * Determine partial specialization order of 'this' vs td2. - * Returns: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - extern (D) MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, ArgumentList argumentList) - { - enum LOG_LEASTAS = 0; - static if (LOG_LEASTAS) - { - printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); - } - - /* This works by taking the template parameters to this template - * declaration and feeding them to td2 as if it were a template - * instance. - * If it works, then this template is at least as specialized - * as td2. - */ - - // Set type arguments to dummy template instance to be types - // generated from the parameters to this template declaration - auto tiargs = new Objects(); - tiargs.reserve(parameters.length); - foreach (tp; *parameters) - { - if (tp.dependent) - break; - RootObject p = tp.dummyArg(); - if (!p) //TemplateTupleParameter - break; - - tiargs.push(p); - } - scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance - - // Temporary Array to hold deduced types - Objects dedtypes = Objects(td2.parameters.length); - - // Attempt a type deduction - MATCH m = td2.matchWithInstance(sc, ti, dedtypes, argumentList, 1); - if (m > MATCH.nomatch) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - TemplateTupleParameter tp = isVariadic(); - if (tp && !tp.dependent && !td2.isVariadic()) - goto L1; - - static if (LOG_LEASTAS) - { - printf(" matches %d, so is least as specialized\n", m); - } - return m; - } - L1: - static if (LOG_LEASTAS) - { - printf(" doesn't match, so is not as specialized\n"); - } - return MATCH.nomatch; - } - - /************************************************* - * Match function arguments against a specific template function. - * - * Params: - * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments - * sc = instantiation scope - * fd = Partially instantiated function declaration, which is set to an instantiated function declaration - * tthis = 'this' argument if !NULL - * argumentList = arguments to function - * - * Returns: - * match pair of initial and inferred template arguments - */ - extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList) - { - version (none) - { - printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars()); - for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) - { - Expression e = (*fargs)[i]; - printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars()); - } - printf("fd = %s\n", fd.toChars()); - printf("fd.type = %s\n", fd.type.toChars()); - if (tthis) - printf("tthis = %s\n", tthis.toChars()); - } - - assert(_scope); - - auto dedargs = new Objects(parameters.length); - dedargs.zero(); - - Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - dedtypes.setDim(parameters.length); - dedtypes.zero(); - - if (errors || fd.errors) - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - - // Set up scope for parameters - Scope* paramscope = scopeForTemplateParameters(ti,sc); - - MATCHpair nomatch() - { - paramscope.pop(); - //printf("\tnomatch\n"); - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - } - - MATCHpair matcherror() - { - // todo: for the future improvement - paramscope.pop(); - //printf("\terror\n"); - return MATCHpair(MATCH.nomatch, MATCH.nomatch); - } - // Mark the parameter scope as deprecated if the templated - // function is deprecated (since paramscope.enclosing is the - // calling scope already) - paramscope.stc |= fd.storage_class & STC.deprecated_; - - TemplateTupleParameter tp = isVariadic(); - Tuple declaredTuple = null; - - version (none) - { - for (size_t i = 0; i < dedargs.length; i++) - { - printf("\tdedarg[%d] = ", i); - RootObject oarg = (*dedargs)[i]; - if (oarg) - printf("%s", oarg.toChars()); - printf("\n"); - } - } - - size_t ntargs = 0; // array size of tiargs - size_t inferStart = 0; // index of first parameter to infer - const Loc instLoc = ti.loc; - MATCH matchTiargs = MATCH.exact; - - if (auto tiargs = ti.tiargs) - { - // Set initial template arguments - ntargs = tiargs.length; - size_t n = parameters.length; - if (tp) - n--; - if (ntargs > n) - { - if (!tp) - return nomatch(); - - /* The extra initial template arguments - * now form the tuple argument. - */ - auto t = new Tuple(ntargs - n); - assert(parameters.length); - (*dedargs)[parameters.length - 1] = t; - - for (size_t i = 0; i < t.objects.length; i++) - { - t.objects[i] = (*tiargs)[n + i]; - } - declareParameter(paramscope, tp, t); - declaredTuple = t; - } - else - n = ntargs; - - memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof); - - for (size_t i = 0; i < n; i++) - { - assert(i < parameters.length); - Declaration sparam = null; - MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m == MATCH.nomatch) - return nomatch(); - if (m < matchTiargs) - matchTiargs = m; - - sparam.dsymbolSemantic(paramscope); - if (!paramscope.insert(sparam)) - return nomatch(); - } - if (n < parameters.length && !declaredTuple) - { - inferStart = n; - } - else - inferStart = parameters.length; - //printf("tiargs matchTiargs = %d\n", matchTiargs); - } - version (none) - { - for (size_t i = 0; i < dedargs.length; i++) - { - printf("\tdedarg[%d] = ", i); - RootObject oarg = (*dedargs)[i]; - if (oarg) - printf("%s", oarg.toChars()); - printf("\n"); - } - } - - ParameterList fparameters = fd.getParameterList(); // function parameter list - const nfparams = fparameters.length; // number of function parameters - if (argumentList.hasNames) - return matcherror(); // TODO: resolve named args - Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * void foo(T, A...)(T t, A a); - * void main() { foo(1,2,3); } - */ - size_t fptupindex = IDX_NOTFOUND; - if (tp) // if variadic - { - // TemplateTupleParameter always makes most lesser matching. - matchTiargs = MATCH.convert; - - if (nfparams == 0 && argumentList.length != 0) // if no function parameters - { - if (!declaredTuple) - { - auto t = new Tuple(); - //printf("t = %p\n", t); - (*dedargs)[parameters.length - 1] = t; - declareParameter(paramscope, tp, t); - declaredTuple = t; - } - } - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? - if (fparam.type.ty != Tident) - continue; - TypeIdentifier tid = fparam.type.isTypeIdentifier(); - if (!tp.ident.equals(tid.ident) || tid.idents.length) - continue; - - if (fparameters.varargs != VarArg.none) // variadic function doesn't - return nomatch(); // go with variadic template - - goto L1; - } - fptupindex = IDX_NOTFOUND; - L1: - } - } - - MATCH match = MATCH.exact; - if (toParent().isModule()) - tthis = null; - if (tthis) - { - bool hasttp = false; - - // Match 'tthis' to any TemplateThisParameter's - foreach (param; *parameters) - { - if (auto ttp = param.isTemplateThisParameter()) - { - hasttp = true; - - Type t = new TypeIdentifier(Loc.initial, ttp.ident); - MATCH m = deduceType(tthis, paramscope, t, *parameters, *dedtypes); - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; // pick worst match - } - } - - // Match attributes of tthis against attributes of fd - if (fd.type && !fd.isCtorDeclaration() && !(_scope.stc & STC.static_)) - { - StorageClass stc = _scope.stc | fd.storage_class2; - // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 - Dsymbol p = parent; - while (p.isTemplateDeclaration() || p.isTemplateInstance()) - p = p.parent; - AggregateDeclaration ad = p.isAggregateDeclaration(); - if (ad) - stc |= ad.storage_class; - - ubyte mod = fd.type.mod; - if (stc & STC.immutable_) - mod = MODFlags.immutable_; - else - { - if (stc & (STC.shared_ | STC.synchronized_)) - mod |= MODFlags.shared_; - if (stc & STC.const_) - mod |= MODFlags.const_; - if (stc & STC.wild) - mod |= MODFlags.wild; - } - - ubyte thismod = tthis.mod; - if (hasttp) - mod = MODmerge(thismod, mod); - MATCH m = MODmethodConv(thismod, mod); - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - } - } - - // Loop through the function parameters - { - //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); - //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); - size_t argi = 0; - size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs - uint inoutMatch = 0; // for debugging only - for (size_t parami = 0; parami < nfparams; parami++) - { - Parameter fparam = fparameters[parami]; - - // Apply function parameter storage classes to parameter types - Type prmtype = fparam.type.addStorageClass(fparam.storageClass); - - Expression farg; - - /* See function parameters which wound up - * as part of a template tuple parameter. - */ - if (fptupindex != IDX_NOTFOUND && parami == fptupindex) - { - TypeIdentifier tid = prmtype.isTypeIdentifier(); - assert(tid); - if (!declaredTuple) - { - /* The types of the function arguments - * now form the tuple argument. - */ - declaredTuple = new Tuple(); - (*dedargs)[parameters.length - 1] = declaredTuple; - - /* Count function parameters with no defaults following a tuple parameter. - * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) - */ - size_t rem = 0; - foreach (j; parami + 1 .. nfparams) - { - Parameter p = fparameters[j]; - if (p.defaultArg) - { - break; - } - if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length])) - { - Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); - if (auto ptt = pt.isTypeTuple()) - rem += ptt.arguments.length; - else - rem += 1; - } - else - { - ++rem; - } - } - - if (nfargs2 - argi < rem) - return nomatch(); - declaredTuple.objects.setDim(nfargs2 - argi - rem); - foreach (i; 0 .. declaredTuple.objects.length) - { - farg = fargs[argi + i]; - - // Check invalid arguments to detect errors early. - if (farg.op == EXP.error || farg.type.ty == Terror) - return nomatch(); - - if (!fparam.isLazy() && farg.type.ty == Tvoid) - return nomatch(); - - Type tt; - MATCH m; - if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) - { - inoutMatch |= wm; - m = MATCH.constant; - } - else - { - m = deduceTypeHelper(farg.type, tt, tid); - } - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - - /* Remove top const for dynamic array types and pointer types - */ - if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue())) - { - tt = tt.mutableOf(); - } - declaredTuple.objects[i] = tt; - } - declareParameter(paramscope, tp, declaredTuple); - } - else - { - // https://issues.dlang.org/show_bug.cgi?id=6810 - // If declared tuple is not a type tuple, - // it cannot be function parameter types. - for (size_t i = 0; i < declaredTuple.objects.length; i++) - { - if (!isType(declaredTuple.objects[i])) - return nomatch(); - } - } - assert(declaredTuple); - argi += declaredTuple.objects.length; - continue; - } - - // If parameter type doesn't depend on inferred template parameters, - // semantic it to get actual type. - if (!reliesOnTemplateParameters(prmtype, (*parameters)[inferStart .. parameters.length])) - { - // should copy prmtype to avoid affecting semantic result - prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); - - if (TypeTuple tt = prmtype.isTypeTuple()) - { - const tt_dim = tt.arguments.length; - for (size_t j = 0; j < tt_dim; j++, ++argi) - { - Parameter p = (*tt.arguments)[j]; - if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && - parami + 1 == nfparams && argi < fargs.length) - { - prmtype = p.type; - goto Lvarargs; - } - if (argi >= fargs.length) - { - if (p.defaultArg) - continue; - - // https://issues.dlang.org/show_bug.cgi?id=19888 - if (fparam.defaultArg) - break; - - return nomatch(); - } - farg = fargs[argi]; - if (!farg.implicitConvTo(p.type)) - return nomatch(); - } - continue; - } - } - - if (argi >= fargs.length) // if not enough arguments - { - if (!fparam.defaultArg) - goto Lvarargs; - - /* https://issues.dlang.org/show_bug.cgi?id=2803 - * Before the starting of type deduction from the function - * default arguments, set the already deduced parameters into paramscope. - * It's necessary to avoid breaking existing acceptable code. Cases: - * - * 1. Already deduced template parameters can appear in fparam.defaultArg: - * auto foo(A, B)(A a, B b = A.stringof); - * foo(1); - * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' - * - * 2. If prmtype depends on default-specified template parameter, the - * default type should be preferred. - * auto foo(N = size_t, R)(R r, N start = 0) - * foo([1,2,3]); - * // at fparam `N start = 0`, N should be 'size_t' before - * // the deduction result from fparam.defaultArg. - */ - if (argi == fargs.length) - { - foreach (ref dedtype; *dedtypes) - { - Type at = isType(dedtype); - if (at && at.ty == Tnone) - { - TypeDeduced xt = cast(TypeDeduced)at; - dedtype = xt.tded; // 'unbox' - } - } - for (size_t i = ntargs; i < dedargs.length; i++) - { - TemplateParameter tparam = (*parameters)[i]; - - RootObject oarg = (*dedargs)[i]; - RootObject oded = (*dedtypes)[i]; - if (oarg) - continue; - - if (oded) - { - if (tparam.specialization() || !tparam.isTemplateTypeParameter()) - { - /* The specialization can work as long as afterwards - * the oded == oarg - */ - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, kind, toPrettyChars, tparam.ident.toChars()); - } - else - { - if (MATCH.convert < matchTiargs) - matchTiargs = MATCH.convert; - } - (*dedargs)[i] = declareParameter(paramscope, tparam, oded); - } - else - { - oded = tparam.defaultArg(instLoc, paramscope); - if (oded) - (*dedargs)[i] = declareParameter(paramscope, tparam, oded); - } - } - } - nfargs2 = argi + 1; - - /* If prmtype does not depend on any template parameters: - * - * auto foo(T)(T v, double x = 0); - * foo("str"); - * // at fparam == 'double x = 0' - * - * or, if all template parameters in the prmtype are already deduced: - * - * auto foo(R)(R range, ElementType!R sum = 0); - * foo([1,2,3]); - * // at fparam == 'ElementType!R sum = 0' - * - * Deducing prmtype from fparam.defaultArg is not necessary. - */ - if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope)) - { - ++argi; - continue; - } - - // Deduce prmtype from the defaultArg. - farg = fparam.defaultArg.syntaxCopy(); - farg = farg.expressionSemantic(paramscope); - farg = resolveProperties(paramscope, farg); - } - else - { - farg = fargs[argi]; - } - { - // Check invalid arguments to detect errors early. - if (farg.op == EXP.error || farg.type.ty == Terror) - return nomatch(); - - Type att = null; - Lretry: - version (none) - { - printf("\tfarg.type = %s\n", farg.type.toChars()); - printf("\tfparam.type = %s\n", prmtype.toChars()); - } - Type argtype = farg.type; - - if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_) - return nomatch(); - - // https://issues.dlang.org/show_bug.cgi?id=12876 - // Optimize argument to allow CT-known length matching - farg = farg.optimize(WANTvalue, fparam.isReference()); - //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars()); - - RootObject oarg = farg; - if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue())) - { - /* Allow expressions that have CT-known boundaries and type [] to match with [dim] - */ - bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray); - if (auto aaType = prmtype.isTypeAArray()) - { - if (auto indexType = aaType.index.isTypeIdentifier()) - { - inferIndexType = indexType.idents.length == 0; - } - } - if (inferIndexType) - { - if (StringExp se = farg.isStringExp()) - { - argtype = se.type.nextOf().sarrayOf(se.len); - } - else if (ArrayLiteralExp ae = farg.isArrayLiteralExp()) - { - argtype = ae.type.nextOf().sarrayOf(ae.elements.length); - } - else if (SliceExp se = farg.isSliceExp()) - { - if (Type tsa = toStaticArrayType(se)) - argtype = tsa; - } - } - - oarg = argtype; - } - else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0) - { - /* The farg passing to the prmtype always make a copy. Therefore, - * we can shrink the set of the deduced type arguments for prmtype - * by adjusting top-qualifier of the argtype. - * - * prmtype argtype ta - * T <- const(E)[] const(E)[] - * T <- const(E[]) const(E)[] - * qualifier(T) <- const(E)[] const(E[]) - * qualifier(T) <- const(E[]) const(E[]) - */ - Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0); - if (ta != argtype) - { - Expression ea = farg.copy(); - ea.type = ta; - oarg = ea; - } - } - - if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length) - goto Lvarargs; - - uint im = 0; - MATCH m = deduceType(oarg, paramscope, prmtype, *parameters, *dedtypes, &im, inferStart); - //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); - inoutMatch |= im; - - /* If no match, see if the argument can be matched by using - * implicit conversions. - */ - if (m == MATCH.nomatch && prmtype.deco) - m = farg.implicitConvTo(prmtype); - - if (m == MATCH.nomatch) - { - AggregateDeclaration ad = isAggregate(farg.type); - if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype)) - { - // https://issues.dlang.org/show_bug.cgi?id=12537 - // The isRecursiveAliasThis() call above - - /* If a semantic error occurs while doing alias this, - * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295), - * just regard it as not a match. - * - * We also save/restore sc.func.flags to avoid messing up - * attribute inference in the evaluation. - */ - const oldflags = sc.func ? sc.func.flags : 0; - auto e = resolveAliasThis(sc, farg, true); - if (sc.func) - sc.func.flags = oldflags; - if (e) - { - farg = e; - goto Lretry; - } - } - } - - if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_) - { - if (!farg.isLvalue()) - { - if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray)) - { - // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] - } - else if (global.params.rvalueRefParam == FeatureState.enabled) - { - // Allow implicit conversion to ref - } - else - return nomatch(); - } - } - if (m > MATCH.nomatch && (fparam.storageClass & STC.out_)) - { - if (!farg.isLvalue()) - return nomatch(); - if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916 - return nomatch(); - } - if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid) - m = MATCH.convert; - if (m != MATCH.nomatch) - { - if (m < match) - match = m; // pick worst match - argi++; - continue; - } - } - - Lvarargs: - /* The following code for variadic arguments closely - * matches TypeFunction.callMatch() - */ - if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams)) - return nomatch(); - - /* Check for match with function parameter T... - */ - Type tb = prmtype.toBasetype(); - switch (tb.ty) - { - // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). - case Tsarray: - case Taarray: - { - // Perhaps we can do better with this, see TypeFunction.callMatch() - if (TypeSArray tsa = tb.isTypeSArray()) - { - dinteger_t sz = tsa.dim.toInteger(); - if (sz != fargs.length - argi) - return nomatch(); - } - else if (TypeAArray taa = tb.isTypeAArray()) - { - Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); - - size_t i = templateParameterLookup(taa.index, parameters); - if (i == IDX_NOTFOUND) - { - Expression e; - Type t; - Dsymbol s; - Scope *sco; - - uint errors = global.startGagging(); - /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 - * The parameter isn't part of the template - * ones, let's try to find it in the - * instantiation scope 'sc' and the one - * belonging to the template itself. */ - sco = sc; - taa.index.resolve(instLoc, sco, e, t, s); - if (!e) - { - sco = paramscope; - taa.index.resolve(instLoc, sco, e, t, s); - } - global.endGagging(errors); - - if (!e) - return nomatch(); - - e = e.ctfeInterpret(); - e = e.implicitCastTo(sco, Type.tsize_t); - e = e.optimize(WANTvalue); - if (!dim.equals(e)) - return nomatch(); - } - else - { - // This code matches code in TypeInstance.deduceType() - TemplateParameter tprm = (*parameters)[i]; - TemplateValueParameter tvp = tprm.isTemplateValueParameter(); - if (!tvp) - return nomatch(); - Expression e = cast(Expression)(*dedtypes)[i]; - if (e) - { - if (!dim.equals(e)) - return nomatch(); - } - else - { - Type vt = tvp.valType.typeSemantic(Loc.initial, sc); - MATCH m = dim.implicitConvTo(vt); - if (m == MATCH.nomatch) - return nomatch(); - (*dedtypes)[i] = dim; - } - } - } - goto case Tarray; - } - case Tarray: - { - TypeArray ta = cast(TypeArray)tb; - Type tret = fparam.isLazyArray(); - for (; argi < fargs.length; argi++) - { - Expression arg = fargs[argi]; - assert(arg); + HdrGenState hgs; + OutBuffer buf; + toCharsMaybeConstraints(this, buf, hgs); + return buf.extractChars(); + } - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - if (tret) - { - if (ta.next.equals(arg.type)) - { - m = MATCH.exact; - } - else - { - m = arg.implicitConvTo(tret); - if (m == MATCH.nomatch) - { - if (tret.toBasetype().ty == Tvoid) - m = MATCH.convert; - } - } - } - else - { - uint wm = 0; - m = deduceType(arg, paramscope, ta.next, *parameters, *dedtypes, &wm, inferStart); - inoutMatch |= wm; - } - if (m == MATCH.nomatch) - return nomatch(); - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; + override Visibility visible() pure nothrow @nogc @safe + { + return visibility; + } - default: - return nomatch(); - } - assert(0); - } - //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); - if (argi != nfargs2 && fparameters.varargs == VarArg.none) - return nomatch(); - } + /**************************** + * Destructively get the error message from the last constraint evaluation + * Params: + * tip = tip to show after printing all overloads + */ + const(char)* getConstraintEvalError(ref const(char)* tip) + { + import dmd.staticcond; - Lmatch: - foreach (ref dedtype; *dedtypes) - { - if (Type at = isType(dedtype)) - { - if (at.ty == Tnone) - { - TypeDeduced xt = cast(TypeDeduced)at; - at = xt.tded; // 'unbox' - } - dedtype = at.merge2(); - } - } - for (size_t i = ntargs; i < dedargs.length; i++) + // there will be a full tree view in verbose mode, and more compact list in the usual + const full = global.params.v.verbose; + uint count; + const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count); + scope (exit) { - TemplateParameter tparam = (*parameters)[i]; - //printf("tparam[%d] = %s\n", i, tparam.ident.toChars()); - - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - RootObject oarg = (*dedargs)[i]; - RootObject oded = (*dedtypes)[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg.toChars()); - //if (oded) printf("oded: %s\n", oded.toChars()); - if (oarg) - continue; - - if (oded) - { - if (tparam.specialization() || !tparam.isTemplateTypeParameter()) - { - /* The specialization can work as long as afterwards - * the oded == oarg - */ - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars()); - } - else - { - // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484 - if (MATCH.convert < matchTiargs) - matchTiargs = MATCH.convert; - } - } - else - { - oded = tparam.defaultArg(instLoc, paramscope); - if (!oded) - { - // if tuple parameter and - // tuple parameter was not in function parameter list and - // we're one or more arguments short (i.e. no tuple argument) - if (tparam == tp && - fptupindex == IDX_NOTFOUND && - ntargs <= dedargs.length - 1) - { - // make tuple argument an empty tuple - oded = new Tuple(); - } - else - return nomatch(); - } - if (isError(oded)) - return matcherror(); - ntargs++; - - /* At the template parameter T, the picked default template argument - * X!int should be matched to T in order to deduce dependent - * template parameter A. - * auto foo(T : X!A = X!int, A...)() { ... } - * foo(); // T <-- X!int, A <-- (int) - */ - if (tparam.specialization()) - { - (*dedargs)[i] = oded; - MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null); - //printf("m2 = %d\n", m2); - if (m2 == MATCH.nomatch) - return nomatch(); - if (m2 < matchTiargs) - matchTiargs = m2; // pick worst match - if (!(*dedtypes)[i].equals(oded)) - .error(loc, "%s `%s` specialization not allowed for deduced parameter `%s`", kind, toPrettyChars, tparam.ident.toChars()); - } - } - oded = declareParameter(paramscope, tparam, oded); - (*dedargs)[i] = oded; + lastConstraint = null; + lastConstraintTiargs = null; + lastConstraintNegs.setDim(0); } + if (!msg) + return null; - /* https://issues.dlang.org/show_bug.cgi?id=7469 - * As same as the code for 7469 in findBestMatch, - * expand a Tuple in dedargs to normalize template arguments. - */ - if (auto d = dedargs.length) - { - if (auto va = isTuple((*dedargs)[d - 1])) - { - dedargs.setDim(d - 1); - dedargs.insert(d - 1, &va.objects); - } - } - ti.tiargs = dedargs; // update to the normalized template arguments. + OutBuffer buf; - // Partially instantiate function for constraint and fd.leastAsSpecialized() + assert(parameters && lastConstraintTiargs); + if (parameters.length > 0) { - assert(paramscope.scopesym); - Scope* sc2 = _scope; - sc2 = sc2.push(paramscope.scopesym); - sc2 = sc2.push(ti); - sc2.parent = ti; - sc2.tinst = ti; - sc2.minst = sc.minst; - sc2.stc |= fd.storage_class & STC.deprecated_; - - fd = doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments); - - sc2 = sc2.pop(); - sc2 = sc2.pop(); - - if (!fd) - return nomatch(); + formatParamsWithTiargs(*parameters, *lastConstraintTiargs, isVariadic() !is null, buf); + buf.writenl(); } - - if (constraint) + if (!full) { - if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd)) - return nomatch(); + // choosing singular/plural + const s = (count == 1) ? + " must satisfy the following constraint:" : + " must satisfy one of the following constraints:"; + buf.writestring(s); + buf.writenl(); + // the constraints + buf.writeByte('`'); + buf.writestring(msg); + buf.writeByte('`'); } - - version (none) + else { - for (size_t i = 0; i < dedargs.length; i++) - { - RootObject o = (*dedargs)[i]; - printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars()); - } + buf.writestring(" whose parameters have the following constraints:"); + buf.writenl(); + const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`"; + buf.writestring(sep); + buf.writenl(); + // the constraints + buf.writeByte('`'); + buf.writestring(msg); + buf.writeByte('`'); + buf.writestring(sep); + tip = "not satisfied constraints are marked with `>`"; } - - paramscope.pop(); - //printf("\tmatch %d\n", match); - return MATCHpair(matchTiargs, match); + return buf.extractChars(); } /************************************************** @@ -2770,8 +1302,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, * This is because f() is "more specialized." */ { - MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names); - MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names); + MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) return firstIsBetter(); if (c1 < c2) return 0; @@ -2876,7 +1408,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, auto ti = new TemplateInstance(loc, td, tiargs); Objects dedtypes = Objects(td.parameters.length); assert(td.semanticRun != PASS.initial); - MATCH mta = td.matchWithInstance(sc, ti, dedtypes, argumentList, 0); + MATCH mta = matchWithInstance(sc, td, ti, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", mta); if (mta == MATCH.nomatch || mta < ta_last) // no match or less match return 0; @@ -3036,8 +1568,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (td_best) { // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList); - MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList); + MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList); + MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList); //printf("1: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -3055,8 +1587,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, } { // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names); - MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names); + MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); //printf("3: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -3199,7 +1731,7 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param return IDX_NOTFOUND; } -private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) +size_t templateParameterLookup(Type tparam, TemplateParameters* parameters) { if (TypeIdentifier tident = tparam.isTypeIdentifier()) { @@ -3209,7 +1741,7 @@ private size_t templateParameterLookup(Type tparam, TemplateParameters* paramete return IDX_NOTFOUND; } -private ubyte deduceWildHelper(Type t, Type* at, Type tparam) +ubyte deduceWildHelper(Type t, Type* at, Type tparam) { if ((tparam.mod & MODFlags.wild) == 0) return 0; @@ -3292,7 +1824,7 @@ private Type rawTypeMerge(Type t1, Type t2) return null; } -private MATCH deduceTypeHelper(Type t, out Type at, Type tparam) +MATCH deduceTypeHelper(Type t, out Type at, Type tparam) { // 9*9 == 81 cases @@ -5000,7 +3532,7 @@ bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0) * t = Tested type, if null, returns false. * tparams = Template parameters. */ -private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams) +bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams) { bool visitVector(TypeVector t) { @@ -6930,7 +5462,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } FuncDeclaration fd = sa.isFuncDeclaration(); if (fd) - fd.functionSemantic(); + functionSemantic(fd); } else if (isParameter(o)) { @@ -7001,7 +5533,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol assert(tempdecl._scope); // Deduce tdtypes tdtypes.setDim(tempdecl.parameters.length); - if (!tempdecl.matchWithInstance(sc, this, tdtypes, argumentList, 2)) + if (!matchWithInstance(sc, tempdecl, this, tdtypes, argumentList, 2)) { .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars); return false; @@ -7051,7 +5583,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol dedtypes.zero(); assert(td.semanticRun != PASS.initial); - MATCH m = td.matchWithInstance(sc, this, dedtypes, argumentList, 0); + MATCH m = matchWithInstance(sc, td, this, dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", m); if (m == MATCH.nomatch) // no match at all return 0; @@ -7060,8 +5592,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol // Disambiguate by picking the most specialized TemplateDeclaration { - MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList); - MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList); + MATCH c1 = leastAsSpecialized(sc, td, td_best, argumentList); + MATCH c2 = leastAsSpecialized(sc, td_best, td, argumentList); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -7159,7 +5691,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol // Only one template, so we can give better error message const(char)* msg = "does not match template declaration"; const(char)* tip; - const tmsg = tdecl.toCharsNoConstraints(); + OutBuffer buf; + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(tdecl, buf, hgs); + const tmsg = buf.peekChars(); const cmsg = tdecl.getConstraintEvalError(tip); if (cmsg) { @@ -7327,7 +5863,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol return 1; } } - MATCH m = td.matchWithInstance(sc, this, dedtypes, ArgumentList(), 0); + MATCH m = matchWithInstance(sc, td, this, dedtypes, ArgumentList(), 0); if (m == MATCH.nomatch) return 0; } @@ -8562,15 +7098,21 @@ extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink) sortedStats.sort!(TemplateDeclarationStats.compare); + OutBuffer buf; foreach (const ref ss; sortedStats[]) { + buf.reset(); + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(ss.td, buf, hgs); + const tchars = buf.peekChars(); if (listInstances && ss.ts.allInstances) { eSink.message(ss.td.loc, "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, - ss.td.toCharsNoConstraints()); + tchars); foreach (const ti; (*ss.ts.allInstances)[]) { if (ti.tinst) // if has enclosing instance @@ -8585,13 +7127,13 @@ extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink) "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found", ss.ts.numInstantiations, ss.ts.uniqueInstantiations, - ss.td.toCharsNoConstraints()); + tchars); } } } /// Pair of MATCHes -private struct MATCHpair +struct MATCHpair { MATCH mta; /// match template parameters by initial template arguments MATCH mfa; /// match template parameters by inferred template arguments @@ -8605,7 +7147,7 @@ private struct MATCHpair } } -private void write(ref OutBuffer buf, RootObject obj) +void write(ref OutBuffer buf, RootObject obj) { if (obj) { diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index a4bb588cac6..650bf3e2c7c 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -52,8 +52,6 @@ public: bool isDeprecated() const override; // is Dsymbol deprecated? Visibility visible() override; bool isSpecial() const; - Expression *getDefaultValue(const Loc &loc); - Type *getMemtype(const Loc &loc); EnumDeclaration *isEnumDeclaration() override { return this; } diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d new file mode 100644 index 00000000000..060396026e9 --- /dev/null +++ b/gcc/d/dmd/enumsem.d @@ -0,0 +1,714 @@ +/** + * Does the semantic passes on enums. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/enumsem.d, _enumsem.d) + * Documentation: https://dlang.org/phobos/dmd_enumsem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/enumsem.d + */ + +module dmd.enumsem; + +import core.stdc.stdio; +import core.stdc.string; + +import dmd.aggregate; +import dmd.aliasthis; +import dmd.arraytypes; +import dmd.astcodegen; +import dmd.astenums; +import dmd.attrib; +import dmd.blockexit; +import dmd.clone; +import dmd.cond; +import dmd.compiler; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.denum; +import dmd.dimport; +import dmd.dinterpret; +import dmd.dmangle; +import dmd.dmodule; +import dmd.dscope; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.dversion; +import dmd.errors; +import dmd.escape; +import dmd.expression; +import dmd.expressionsem; +import dmd.func; +import dmd.funcsem; +import dmd.globals; +import dmd.id; +import dmd.identifier; +import dmd.importc; +import dmd.init; +import dmd.initsem; +import dmd.intrange; +import dmd.hdrgen; +import dmd.location; +import dmd.mtype; +import dmd.mustuse; +import dmd.nogc; +import dmd.nspace; +import dmd.objc; +import dmd.opover; +import dmd.optimize; +import dmd.parse; +import dmd.root.array; +import dmd.root.filename; +import dmd.common.outbuffer; +import dmd.root.rmem; +import dmd.rootobject; +import dmd.root.utf; +import dmd.semantic2; +import dmd.semantic3; +import dmd.sideeffect; +import dmd.statementsem; +import dmd.staticassert; +import dmd.tokens; +import dmd.utils; +import dmd.statement; +import dmd.target; +import dmd.templateparamsem; +import dmd.typesem; +import dmd.visitor; + + +/********************************* + * Perform semantic analysis on enum declaration `em` + */ +void enumSemantic(Scope* sc, EnumDeclaration ed) +{ + //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars()); + //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars()); + if (ed.semanticRun >= PASS.semanticdone) + return; // semantic() already completed + if (ed.semanticRun == PASS.semantic) + { + assert(ed.memtype); + error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars()); + ed.errors = true; + ed.semanticRun = PASS.semanticdone; + return; + } + Scope* scx = null; + if (ed._scope) + { + sc = ed._scope; + scx = ed._scope; // save so we don't make redundant copies + ed._scope = null; + } + + if (!sc) + return; + + ed.parent = sc.parent; + ed.type = ed.type.typeSemantic(ed.loc, sc); + + ed.visibility = sc.visibility; + if (sc.stc & STC.deprecated_) + ed.isdeprecated = true; + ed.userAttribDecl = sc.userAttribDecl; + ed.cppnamespace = sc.namespace; + + ed.semanticRun = PASS.semantic; + UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage); + checkMustUseReserved(ed); + + if (!ed.members && !ed.memtype) // enum ident; + { + ed.semanticRun = PASS.semanticdone; + return; + } + + if (!ed.symtab) + ed.symtab = new DsymbolTable(); + + /* The separate, and distinct, cases are: + * 1. enum { ... } + * 2. enum : memtype { ... } + * 3. enum ident { ... } + * 4. enum ident : memtype { ... } + * 5. enum ident : memtype; + * 6. enum ident; + */ + + if (ed.memtype) + { + ed.memtype = ed.memtype.typeSemantic(ed.loc, sc); + + /* Check to see if memtype is forward referenced + */ + if (auto te = ed.memtype.isTypeEnum()) + { + auto sym = te.toDsymbol(sc).isEnumDeclaration(); + // Special enums like __c_[u]long[long] are fine to forward reference + // see https://issues.dlang.org/show_bug.cgi?id=20599 + if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope)) + { + // memtype is forward referenced, so try again later + deferDsymbolSemantic(sc, ed, scx); + //printf("\tdeferring %s\n", toChars()); + ed.semanticRun = PASS.initial; + return; + } + else + // Ensure that semantic is run to detect. e.g. invalid forward references + sym.dsymbolSemantic(sc); + } + if (ed.memtype.ty == Tvoid) + { + .error(ed.loc, "%s `%s` base type must not be `void`", ed.kind, ed.toPrettyChars); + ed.memtype = Type.terror; + } + if (ed.memtype.ty == Terror) + { + ed.errors = true; + // poison all the members + ed.members.foreachDsymbol( (s) { s.errors = true; } ); + ed.semanticRun = PASS.semanticdone; + return; + } + } + + if (!ed.members) // enum ident : memtype; + { + ed.semanticRun = PASS.semanticdone; + return; + } + + if (ed.members.length == 0) + { + .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars()); + ed.errors = true; + ed.semanticRun = PASS.semanticdone; + return; + } + + if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done + ed.semanticRun = PASS.semanticdone; + + version (none) + { + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sc.stc & STC.scope_) + deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + } + + Scope* sce; + if (ed.isAnonymous()) + sce = sc; + else + { + sce = sc.push(ed); + sce.parent = ed; + } + sce = sce.startCTFE(); + sce.setNoFree(); // needed for getMaxMinValue() + + /* Each enum member gets the sce scope + */ + ed.members.foreachDsymbol( (s) + { + EnumMember em = s.isEnumMember(); + if (em) + em._scope = sce; + }); + + /* addMember() is not called when the EnumDeclaration appears as a function statement, + * so we have to do what addMember() does and install the enum members in the right symbol + * table + */ + addEnumMembersToSymtab(ed, sc, sc.getScopesym()); + + if (sc.flags & SCOPE.Cfile) + { + /* C11 6.7.2.2 + */ + Type commonType = ed.memtype; + if (!commonType) + commonType = Type.tint32; + ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 + + // C11 6.7.2.2-2 value must be representable as an int. + // The sizemask represents all values that int will fit into, + // from 0..uint.max. We want to cover int.min..uint.max. + IntRange ir = IntRange.fromType(commonType); + + void emSemantic(EnumMember em, ref ulong nextValue) + { + static void errorReturn(EnumMember em) + { + em.value = ErrorExp.get(); + em.errors = true; + em.semanticRun = PASS.semanticdone; + } + + em.semanticRun = PASS.semantic; + em.type = commonType; + em._linkage = LINK.c; + em.storage_class |= STC.manifest; + if (em.value) + { + Expression e = em.value; + assert(e.dyncast() == DYNCAST.expression); + + /* To merge the type of e with commonType, add 0 of type commonType + */ + if (!ed.memtype) + e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType)); + + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + e = e.integralPromotions(sc); + e = e.ctfeInterpret(); + if (e.op == EXP.error) + return errorReturn(em); + auto ie = e.isIntegerExp(); + if (!ie) + { + // C11 6.7.2.2-2 + .error(em.loc, "%s `%s` enum member must be an integral constant expression, not `%s` of type `%s`", em.kind, em.toPrettyChars, e.toChars(), e.type.toChars()); + return errorReturn(em); + } + if (ed.memtype && !ir.contains(getIntRange(ie))) + { + // C11 6.7.2.2-2 + .error(em.loc, "%s `%s` enum member value `%s` does not fit in `%s`", em.kind, em.toPrettyChars, e.toChars(), commonType.toChars()); + return errorReturn(em); + } + nextValue = ie.toInteger(); + if (!ed.memtype) + commonType = e.type; + em.value = new IntegerExp(em.loc, nextValue, commonType); + } + else + { + // C11 6.7.2.2-3 add 1 to value of previous enumeration constant + bool first = (em == (*em.ed.members)[0]); + if (!first) + { + Expression max = getProperty(commonType, null, em.loc, Id.max, 0); + if (nextValue == max.toInteger()) + { + .error(em.loc, "%s `%s` initialization with `%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, max.toChars(), commonType.toChars()); + return errorReturn(em); + } + nextValue += 1; + } + em.value = new IntegerExp(em.loc, nextValue, commonType); + } + em.type = commonType; + em.semanticRun = PASS.semanticdone; + } + + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + emSemantic(em, nextValue); + }); + + if (!ed.memtype) + { + // cast all members to commonType + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + { + em.type = commonType; + em.value = em.value.castTo(sc, commonType); + } + }); + } + + ed.memtype = commonType; + ed.semanticRun = PASS.semanticdone; + return; + } + + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + em.dsymbolSemantic(em._scope); + }); + //printf("ed.defaultval = %lld\n", ed.defaultval); + + //if (ed.defaultval) printf("ed.defaultval: %s %s\n", ed.defaultval.toChars(), ed.defaultval.type.toChars()); + //printf("members = %s\n", members.toChars()); +} + +Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc) +{ + Expression handleErrors(){ + ed.defaultval = ErrorExp.get(); + return ed.defaultval; + } + //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars()); + // https://issues.dlang.org/show_bug.cgi?id=23904 + // Return ed.defaultval only if it is not ErrorExp. + // A speculative context may set ed.defaultval to ErrorExp; + // subsequent non-speculative contexts need to be able + // to print the error. + if (ed.defaultval && !ed.defaultval.isErrorExp()) + return ed.defaultval; + + if (ed.isCsymbol()) + return ed.memtype.defaultInit(loc, true); + + if (ed._scope) + dsymbolSemantic(ed, ed._scope); + if (ed.errors) + return handleErrors(); + if (!ed.members) + { + if (ed.isSpecial()) + { + /* Allow these special enums to not need a member list + */ + return ed.defaultval = ed.memtype.defaultInit(loc); + } + + error(loc, "%s `%s` is opaque and has no default initializer", ed.kind, ed.toPrettyChars); + return handleErrors(); + } + + foreach (const i; 0 .. ed.members.length) + { + EnumMember em = (*ed.members)[i].isEnumMember(); + if (em) + { + if (em.semanticRun < PASS.semanticdone) + { + error(loc, "%s `%s` forward reference of `%s.init`", ed.kind, ed.toPrettyChars, ed.toChars()); + return handleErrors(); + } + + ed.defaultval = em.value; + return ed.defaultval; + } + } + return handleErrors(); +} + +Type getMemtype(EnumDeclaration ed, const ref Loc loc) +{ + if (ed._scope) + { + /* Enum is forward referenced. We don't need to resolve the whole thing, + * just the base type + */ + if (ed.memtype) + { + Loc locx = loc.isValid() ? loc : ed.loc; + ed.memtype = ed.memtype.typeSemantic(locx, ed._scope); + } + else + { + // Run semantic to get the type from a possible first member value + dsymbolSemantic(ed, ed._scope); + } + } + if (!ed.memtype) + { + if (!ed.isAnonymous() && (ed.members || ed.semanticRun >= PASS.semanticdone)) + ed.memtype = Type.tint32; + else + { + Loc locx = loc.isValid() ? loc : ed.loc; + error(locx, "is forward referenced looking for base type"); + return Type.terror; + } + } + return ed.memtype; +} + +/********************************* + * Perform semantic analysis on enum member `em` + */ +void enumMemberSemantic(Scope* sc, EnumMember em) +{ + //printf("EnumMember::semantic() %s\n", em.toChars()); + + void errorReturn() + { + em.errors = true; + em.semanticRun = PASS.semanticdone; + } + + if (em.errors || em.semanticRun >= PASS.semanticdone) + return; + if (em.semanticRun == PASS.semantic) + { + .error(em.loc, "%s `%s` circular reference to `enum` member", em.kind, em.toPrettyChars); + return errorReturn(); + } + assert(em.ed); + + em.ed.dsymbolSemantic(sc); + if (em.ed.errors) + return errorReturn(); + if (em.errors || em.semanticRun >= PASS.semanticdone) + return; + + if (em._scope) + sc = em._scope; + if (!sc) + return; + + em.semanticRun = PASS.semantic; + + em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_); + em._linkage = LINK.d; + em.storage_class |= STC.manifest; + + // https://issues.dlang.org/show_bug.cgi?id=9701 + if (em.ed.isAnonymous()) + { + if (em.userAttribDecl) + em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl; + else + em.userAttribDecl = em.ed.userAttribDecl; + } + + // Eval UDA in this same scope. Issues 19344, 20835, 21122 + if (em.userAttribDecl) + { + // Set scope but avoid extra sc.uda attachment inside setScope() + auto inneruda = em.userAttribDecl.userAttribDecl; + em.userAttribDecl.setScope(sc); + em.userAttribDecl.userAttribDecl = inneruda; + em.userAttribDecl.dsymbolSemantic(sc); + } + + // The first enum member is special + bool first = (em == (*em.ed.members)[0]); + + if (em.origType) + { + em.origType = em.origType.typeSemantic(em.loc, sc); + em.type = em.origType; + assert(em.value); // "type id;" is not a valid enum member declaration + } + + if (em.value) + { + Expression e = em.value; + assert(e.dyncast() == DYNCAST.expression); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + e = e.ctfeInterpret(); + if (e.op == EXP.error) + return errorReturn(); + if (first && !em.ed.memtype && !em.ed.isAnonymous()) + { + em.ed.memtype = e.type; + if (em.ed.memtype.ty == Terror) + { + em.ed.errors = true; + return errorReturn(); + } + if (em.ed.memtype.ty != Terror) + { + /* https://issues.dlang.org/show_bug.cgi?id=11746 + * All of named enum members should have same type + * with the first member. If the following members were referenced + * during the first member semantic, their types should be unified. + */ + em.ed.members.foreachDsymbol( (s) + { + EnumMember enm = s.isEnumMember(); + if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType) + return; + + //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun); + Expression ev = enm.value; + ev = ev.implicitCastTo(sc, em.ed.memtype); + ev = ev.ctfeInterpret(); + ev = ev.castTo(sc, em.ed.type); + if (ev.op == EXP.error) + em.ed.errors = true; + enm.value = ev; + }); + + if (em.ed.errors) + { + em.ed.memtype = Type.terror; + return errorReturn(); + } + } + } + + if (em.ed.memtype && !em.origType) + { + e = e.implicitCastTo(sc, em.ed.memtype); + e = e.ctfeInterpret(); + + // save origValue for better json output + em.origValue = e; + + if (!em.ed.isAnonymous()) + { + e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385 + e = e.ctfeInterpret(); + } + } + else if (em.origType) + { + e = e.implicitCastTo(sc, em.origType); + e = e.ctfeInterpret(); + assert(em.ed.isAnonymous()); + + // save origValue for better json output + em.origValue = e; + } + em.value = e; + } + else if (first) + { + Type t; + if (em.ed.memtype) + t = em.ed.memtype; + else + { + t = Type.tint32; + if (!em.ed.isAnonymous()) + em.ed.memtype = t; + } + const errors = global.startGagging(); + Expression e = new IntegerExp(em.loc, 0, t); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + error(em.loc, "cannot generate 0 value of type `%s` for `%s`", + t.toChars(), em.toChars()); + } + // save origValue for better json output + em.origValue = e; + + if (!em.ed.isAnonymous()) + { + e = e.castTo(sc, em.ed.type); + e = e.ctfeInterpret(); + } + em.value = e; + } + else + { + /* Find the previous enum member, + * and set this to be the previous value + 1 + */ + EnumMember emprev = null; + em.ed.members.foreachDsymbol( (s) + { + if (auto enm = s.isEnumMember()) + { + if (enm == em) + return 1; // found + emprev = enm; + } + return 0; // continue + }); + + assert(emprev); + if (emprev.semanticRun < PASS.semanticdone) // if forward reference + emprev.dsymbolSemantic(emprev._scope); // resolve it + if (emprev.errors) + return errorReturn(); + + auto errors = global.startGagging(); + Expression eprev = emprev.value; + assert(eprev); + // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645 + Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable()) + ? em.ed.memtype + : eprev.type; + /* + https://issues.dlang.org/show_bug.cgi?id=20777 + Previously this used getProperty, which doesn't consider anything user defined, + this construct does do that and thus fixes the bug. + */ + Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); + emax = emax.expressionSemantic(sc); + emax = emax.ctfeInterpret(); + + // check that (eprev != emax) + Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax); + e = e.expressionSemantic(sc); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + // display an introductory error before showing what actually failed + error(em.loc, "cannot check `%s` value for overflow", em.toPrettyChars()); + // rerun to show errors + Expression e2 = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max); + e2 = e2.expressionSemantic(sc); + e2 = e2.ctfeInterpret(); + e2 = new EqualExp(EXP.equal, em.loc, eprev, e2); + e2 = e2.expressionSemantic(sc); + e2 = e2.ctfeInterpret(); + } + // now any errors are for generating a value + if (e.toInteger()) + { + auto mt = em.ed.memtype; + if (!mt) + mt = eprev.type; + .error(em.loc, "%s `%s` initialization with `%s.%s+1` causes overflow for type `%s`", em.kind, em.toPrettyChars, + emprev.ed.toChars(), emprev.toChars(), mt.toChars()); + return errorReturn(); + } + errors = global.startGagging(); + // Now set e to (eprev + 1) + e = new AddExp(em.loc, eprev, IntegerExp.literal!1); + e = e.expressionSemantic(sc); + e = e.castTo(sc, eprev.type); + e = e.ctfeInterpret(); + if (global.endGagging(errors)) + { + error(em.loc, "cannot generate value for `%s`", em.toPrettyChars()); + // rerun to show errors + Expression e2 = new AddExp(em.loc, eprev, IntegerExp.literal!1); + e2 = e2.expressionSemantic(sc); + e2 = e2.castTo(sc, eprev.type); + e2 = e2.ctfeInterpret(); + } + // save origValue (without cast) for better json output + if (e.op != EXP.error) // avoid duplicate diagnostics + { + assert(emprev.origValue); + em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1); + em.origValue = em.origValue.expressionSemantic(sc); + em.origValue = em.origValue.ctfeInterpret(); + } + + if (e.op == EXP.error) + return errorReturn(); + if (e.type.isfloating()) + { + // Check that e != eprev (not always true for floats) + Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev); + etest = etest.expressionSemantic(sc); + etest = etest.ctfeInterpret(); + if (etest.toInteger()) + { + .error(em.loc, "%s `%s` has inexact value due to loss of precision", em.kind, em.toPrettyChars); + return errorReturn(); + } + } + em.value = e; + } + if (!em.origType) + em.type = em.value.type; + + assert(em.origValue); + em.semanticRun = PASS.semanticdone; +} diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index cbf01186f98..1603f2bbb53 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -721,6 +721,7 @@ extern (C++) abstract class Expression : ASTNode inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; } inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; } inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; } + inout(InterpExp) isInterpExp() { return op == EXP.interpolated ? cast(typeof(return))this : null; } inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; } inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; } inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; } @@ -1499,6 +1500,7 @@ extern (C++) final class StringExp : Expression char* string; // if sz == 1 wchar* wstring; // if sz == 2 dchar* dstring; // if sz == 4 + ulong* lstring; // if sz == 8 } // (const if ownedByCtfe == OwnedBy.code) size_t len; // number of code units ubyte sz = 1; // 1: char, 2: wchar, 4: dchar @@ -1662,6 +1664,13 @@ extern (C++) final class StringExp : Expression */ dchar getCodeUnit(size_t i) const pure { + assert(this.sz <= dchar.sizeof); + return cast(dchar) getIndex(i); + } + + /// Returns: integer at index `i` + dinteger_t getIndex(size_t i) const pure + { assert(i < len); final switch (sz) { @@ -1671,6 +1680,8 @@ extern (C++) final class StringExp : Expression return wstring[i]; case 4: return dstring[i]; + case 8: + return lstring[i]; } } @@ -1682,6 +1693,11 @@ extern (C++) final class StringExp : Expression */ extern (D) void setCodeUnit(size_t i, dchar c) { + return setIndex(i, c); + } + + extern (D) void setIndex(size_t i, long c) + { assert(i < len); final switch (sz) { @@ -1692,7 +1708,10 @@ extern (C++) final class StringExp : Expression wstring[i] = cast(wchar)c; break; case 4: - dstring[i] = c; + dstring[i] = cast(dchar) c; + break; + case 8: + lstring[i] = c; break; } } @@ -1847,6 +1866,28 @@ extern (C++) final class StringExp : Expression } } +extern (C++) final class InterpExp : Expression +{ + char postfix = NoPostfix; // 'c', 'w', 'd' + OwnedBy ownedByCtfe = OwnedBy.code; + InterpolatedSet* interpolatedSet; + + enum char NoPostfix = 0; + + extern (D) this(const ref Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope + { + super(loc, EXP.interpolated); + this.interpolatedSet = set; + this.postfix = postfix; + } + + override void accept(Visitor v) + { + v.visit(this); + } +} + + /*********************************************************** * A sequence of expressions * @@ -5494,6 +5535,7 @@ private immutable ubyte[EXP.max+1] expSize = [ EXP.preMinusMinus: __traits(classInstanceSize, PreExp), EXP.identifier: __traits(classInstanceSize, IdentifierExp), EXP.string_: __traits(classInstanceSize, StringExp), + EXP.interpolated: __traits(classInstanceSize, InterpExp), EXP.this_: __traits(classInstanceSize, ThisExp), EXP.super_: __traits(classInstanceSize, SuperExp), EXP.halt: __traits(classInstanceSize, HaltExp), diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index f57f6a40295..d53cc3e85cc 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -38,6 +38,7 @@ class TemplateDeclaration; class ClassDeclaration; class OverloadSet; class StringExp; +class InterpExp; class LoweredAssignExp; #ifdef IN_GCC typedef union tree_node Symbol; @@ -129,6 +130,7 @@ public: SuperExp* isSuperExp(); NullExp* isNullExp(); StringExp* isStringExp(); + InterpExp* isInterpExp(); TupleExp* isTupleExp(); ArrayLiteralExp* isArrayLiteralExp(); AssocArrayLiteralExp* isAssocArrayLiteralExp(); @@ -352,7 +354,7 @@ class StringExp final : public Expression public: utf8_t postfix; // 'c', 'w', 'd' OwnedBy ownedByCtfe; - void *string; // char, wchar, or dchar data + void *string; // char, wchar, dchar, or long data size_t len; // number of chars, wchars, or dchars unsigned char sz; // 1: char, 2: wchar, 4: dchar d_bool committed; // if type is committed @@ -362,6 +364,7 @@ public: static StringExp *create(const Loc &loc, const void *s, d_size_t len); bool equals(const RootObject * const o) const override; char32_t getCodeUnit(d_size_t i) const; + dinteger_t getIndex(d_size_t i) const; StringExp *toStringExp() override; Optional toBool() override; bool isLvalue() override; @@ -370,6 +373,16 @@ public: void writeTo(void* dest, bool zero, int tyto = 0) const; }; +class InterpExp final : public Expression +{ +public: + utf8_t postfix; // 'c', 'w', 'd' + OwnedBy ownedByCtfe; + void* interpolatedSet; + + void accept(Visitor* v) override { v->visit(this); } +}; + // Tuple class TupleExp final : public Expression diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index d4645748177..f2133037a23 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -42,10 +42,12 @@ import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.errorsink; +import dmd.enumsem; import dmd.escape; import dmd.expression; import dmd.file_manager; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -1579,7 +1581,7 @@ Lagain: if (auto f = s.isFuncDeclaration()) { f = f.toAliasFunc(); - if (!f.functionSemantic()) + if (!functionSemantic(f)) return ErrorExp.get(); if (!hasOverloads && f.checkForwardRef(loc)) @@ -2866,7 +2868,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, // If inferring return type, and semantic3() needs to be run if not already run if (!tf.next && fd.inferRetType) { - fd.functionSemantic(); + functionSemantic(fd); } else if (fd && fd.parent) { @@ -4145,6 +4147,84 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; } + override void visit(InterpExp e) + { + // the lexer breaks up into an odd/even array of literals and expression code + // we need to turn that into: + /+ + tuple( + .object.imported!"core.interpolation".InterpolationHeader(), + ... + .object.imported!"core.interpolation".InterpolationFooter() + ) + + There the ... loops through them all, making the even ones + .object.imported!"core.interpolation".InterpolatedLiteral!str() + and making the odd ones + .object.imported!"core.interpolation".InterpolatedExpression!str(), + the code represented by str + + Empty string literals are skipped as they provide no additional information. + +/ + + if (e.postfix) + error(e.loc, "String postfixes on interpolated expression sequences are not allowed."); + + Expression makeNonTemplateItem(Identifier which) { + Expression id = new IdentifierExp(e.loc, Id.empty); + id = new DotIdExp(e.loc, id, Id.object); + auto moduleNameArgs = new Objects(); + moduleNameArgs.push(new StringExp(e.loc, "core.interpolation")); + id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs); + id = new DotIdExp(e.loc, id, which); + id = new CallExp(e.loc, id, new Expressions()); + return id; + } + + Expression makeTemplateItem(Identifier which, string arg) { + Expression id = new IdentifierExp(e.loc, Id.empty); + id = new DotIdExp(e.loc, id, Id.object); + auto moduleNameArgs = new Objects(); + moduleNameArgs.push(new StringExp(e.loc, "core.interpolation")); + id = new DotTemplateInstanceExp(e.loc, id, Id.imported, moduleNameArgs); + auto tiargs = new Objects(); + auto templateStringArg = new StringExp(e.loc, arg); + // banning those instead of forwarding them + // templateStringArg.postfix = e.postfix; // forward the postfix to these literals + tiargs.push(templateStringArg); + id = new DotTemplateInstanceExp(e.loc, id, which, tiargs); + id = new CallExp(e.loc, id, new Expressions()); + return id; + } + + auto arguments = new Expressions(); + arguments.push(makeNonTemplateItem(Id.InterpolationHeader)); + + foreach (idx, str; e.interpolatedSet.parts) + { + if (idx % 2 == 0) + { + if (str.length > 0) + arguments.push(makeTemplateItem(Id.InterpolatedLiteral, str)); + } + else + { + arguments.push(makeTemplateItem(Id.InterpolatedExpression, str)); + Expressions* mix = new Expressions(); + mix.push(new StringExp(e.loc, str)); + // FIXME: i'd rather not use MixinExp but idk how to do it lol + arguments.push(new MixinExp(e.loc, mix)); + } + } + + arguments.push(makeNonTemplateItem(Id.InterpolationFooter)); + + auto loweredTo = new TupleExp(e.loc, arguments); + visit(loweredTo); + + result = loweredTo; + } + override void visit(StringExp e) { static if (LOGSEMANTIC) @@ -5366,7 +5446,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (fd) { //printf("L%d fd = %s\n", __LINE__, f.toChars()); - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return setError(); } @@ -6564,10 +6644,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match"); } - .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", - exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); + .error(exp.loc, "%s `%s` is not callable using argument types `%s`", + exp.f.kind(), exp.f.toChars(), buf.peekChars()); if (failMessage) errorSupplemental(exp.loc, "%s", failMessage); + .errorSupplemental(exp.f.loc, "`%s%s` declared here", exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList)); exp.f = null; } @@ -7549,7 +7630,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor se = se.toUTF8(sc); auto namez = se.toStringz(); - if (!global.filePath) + if (!global.filePath.length) { error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr); return setError(); @@ -7580,12 +7661,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - auto resolvedNamez = FileName.searchPath(global.filePath, namez, false); + auto resolvedNamez = FileName.searchPath(global.filePath[], namez, false); if (!resolvedNamez) { error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars()); errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):"); - foreach (idx, path; *global.filePath) + foreach (idx, path; global.filePath[]) { const attr = FileName.exists(path); const(char)* err = attr == 2 ? "" : @@ -8170,7 +8251,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (FuncDeclaration fd = exp.var.isFuncDeclaration()) { // for functions, do checks after overload resolution - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return setError(); /* https://issues.dlang.org/show_bug.cgi?id=13843 @@ -8937,7 +9018,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor bool err = false; if (cd.dtor) { - err |= !cd.dtor.functionSemantic(); + err |= !functionSemantic(cd.dtor); err |= cd.dtor.checkPurity(exp.loc, sc); err |= cd.dtor.checkSafety(exp.loc, sc); err |= cd.dtor.checkNogc(exp.loc, sc); @@ -14356,7 +14437,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) if (auto f = s.isFuncDeclaration()) { //printf("it's a function\n"); - if (!f.functionSemantic()) + if (!functionSemantic(f)) return ErrorExp.get(); Expression e; if (f.needThis()) diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 370da6f0ee6..adfecc83a17 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -39,6 +39,7 @@ import dmd.dtemplate; import dmd.errors; import dmd.escape; import dmd.expression; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -467,102 +468,12 @@ extern (C++) class FuncDeclaration : Declaration } /**************************************************** - * Resolve forward reference of function signature - - * parameter types, return type, and attributes. - * Returns: - * false if any errors exist in the signature. - */ - final bool functionSemantic() - { - //printf("functionSemantic() %p %s\n", this, toChars()); - if (!_scope) - return !errors; - - this.cppnamespace = _scope.namespace; - - if (!originalType) // semantic not yet run - { - TemplateInstance spec = isSpeculative(); - uint olderrs = global.errors; - uint oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - dsymbolSemantic(this, _scope); - global.gag = oldgag; - if (spec && global.errors != olderrs) - spec.errors = (global.errors - olderrs != 0); - if (olderrs != global.errors) // if errors compiling this function - return false; - } - - // if inferring return type, sematic3 needs to be run - // - When the function body contains any errors, we cannot assume - // the inferred return type is valid. - // So, the body errors should become the function signature error. - if (inferRetType && type && !type.nextOf()) - return functionSemantic3(); - - TemplateInstance ti; - if (isInstantiated() && !isVirtualMethod() && - ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)) - { - AggregateDeclaration ad = isMemberLocal(); - if (ad && ad.sizeok != Sizeok.done) - { - /* Currently dmd cannot resolve forward references per methods, - * then setting SIZOKfwd is too conservative and would break existing code. - * So, just stop method attributes inference until ad.dsymbolSemantic() done. - */ - //ad.sizeok = Sizeok.fwd; - } - else - return functionSemantic3() || !errors; - } - - if (storage_class & STC.inference) - return functionSemantic3() || !errors; - - return !errors; - } - - /**************************************************** - * Resolve forward reference of function body. - * Returns false if any errors exist in the body. - */ - final bool functionSemantic3() - { - if (semanticRun < PASS.semantic3 && _scope) - { - /* Forward reference - we need to run semantic3 on this function. - * If errors are gagged, and it's not part of a template instance, - * we need to temporarily ungag errors. - */ - TemplateInstance spec = isSpeculative(); - uint olderrs = global.errors; - uint oldgag = global.gag; - if (global.gag && !spec) - global.gag = 0; - semantic3(this, _scope); - global.gag = oldgag; - - // If it is a speculatively-instantiated template, and errors occur, - // we need to mark the template as having errors. - if (spec && global.errors != olderrs) - spec.errors = (global.errors - olderrs != 0); - if (olderrs != global.errors) // if errors compiling this function - return false; - } - - return !errors && !this.hasSemantic3Errors(); - } - - /**************************************************** * Check that this function type is properly resolved. * If not, report "forward reference error" and return true. */ extern (D) final bool checkForwardRef(const ref Loc loc) { - if (!functionSemantic()) + if (!functionSemantic(this)) return true; /* No deco means the functionSemantic() call could not resolve @@ -579,72 +490,6 @@ extern (C++) class FuncDeclaration : Declaration return false; } - // called from semantic3 - /** - * Creates and returns the hidden parameters for this function declaration. - * - * Hidden parameters include the `this` parameter of a class, struct or - * nested function and the selector parameter for Objective-C methods. - */ - extern (D) final void declareThis(Scope* sc) - { - const bool dualCtx = (toParent2() != toParentLocal()); - if (dualCtx) - this.hasDualContext = true; - auto ad = isThis(); - if (!dualCtx && !ad && !isNested()) - { - vthis = null; - objc.selectorParameter = null; - return; - } - - Type addModStc(Type t) - { - return t.addMod(type.mod).addStorageClass(storage_class); - } - - if (dualCtx || isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - Type tthis = addModStc(dualCtx ? - Type.tvoidptr.sarrayOf(2).pointerTo() : - Type.tvoid.pointerTo()); - vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null); - vthis.storage_class |= STC.parameter | STC.nodtor; - } - else if (ad) - { - Type thandle = addModStc(ad.handleType()); - vthis = new ThisDeclaration(loc, thandle); - vthis.storage_class |= STC.parameter; - if (thandle.ty == Tstruct) - { - vthis.storage_class |= STC.ref_; - } - } - - if (auto tf = type.isTypeFunction()) - { - if (tf.isreturn) - vthis.storage_class |= STC.return_; - if (tf.isScopeQual) - vthis.storage_class |= STC.scope_; - if (tf.isreturnscope) - vthis.storage_class |= STC.returnScope; - } - - vthis.dsymbolSemantic(sc); - if (!sc.insert(vthis)) - assert(0); - vthis.parent = this; - if (ad) - objc.selectorParameter = .objc.createSelectorParameter(this, sc); - } - override final bool equals(const RootObject o) const { if (this == o) @@ -1104,20 +949,24 @@ extern (C++) class FuncDeclaration : Declaration } /************************************* - * Determine partial specialization order of 'this' vs g. + * Determine partial specialization order of functions `f` vs `g`. * This is very similar to TemplateDeclaration::leastAsSpecialized(). + * Params: + * f = first function + * g = second function + * names = names of parameters * Returns: * match 'this' is at least as specialized as g * 0 g is more specialized than 'this' */ - final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names) + static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names) { enum LOG_LEASTAS = 0; static if (LOG_LEASTAS) { import core.stdc.stdio : printf; - printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null"); - printf("%s, %s\n", type.toChars(), g.type.toChars()); + printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null"); + printf("%s, %s\n", f.type.toChars(), g.type.toChars()); } /* This works by calling g() with f()'s parameters, and @@ -1125,15 +974,15 @@ extern (C++) class FuncDeclaration : Declaration * as g() is. */ - TypeFunction tf = type.toTypeFunction(); + TypeFunction tf = f.type.toTypeFunction(); TypeFunction tg = g.type.toTypeFunction(); /* If both functions have a 'this' pointer, and the mods are not * the same and g's is not const, then this is less specialized. */ - if (needThis() && g.needThis() && tf.mod != tg.mod) + if (f.needThis() && g.needThis() && tf.mod != tg.mod) { - if (isCtorDeclaration()) + if (f.isCtorDeclaration()) { if (!MODimplicitConv(tg.mod, tf.mod)) return MATCH.nomatch; @@ -3037,7 +2886,7 @@ Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis) // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394 // For the correct mangling, // run attribute inference on inv if needed. - inv.functionSemantic(); + functionSemantic(inv); } //e = new DsymbolExp(Loc.initial, inv); @@ -3316,7 +3165,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, if (m.count == 1) // exactly one match { if (!(flags & FuncResolveFlag.quiet)) - m.lastf.functionSemantic(); + functionSemantic(m.lastf); return m.lastf; } if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis()) @@ -3386,12 +3235,18 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, // all of overloads are templates if (td) { - const(char)* msg = "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`"; if (!od && !td.overnext) - msg = "%s `%s.%s` is not callable using argument types `!(%s)%s`"; - .error(loc, msg, + { + .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`", + td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); + } + else + { + .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`", td.kind(), td.parent.toPrettyChars(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars()); + } + if (!global.gag || global.params.v.showGaggedErrors) printCandidates(loc, td, sc.isDeprecated()); @@ -3574,7 +3429,11 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) if (!print) return true; - const tmsg = td.toCharsNoConstraints(); + OutBuffer buf; + HdrGenState hgs; + hgs.skipConstraints = true; + toCharsMaybeConstraints(td, buf, hgs); + const tmsg = buf.peekChars(); const cmsg = td.getConstraintEvalError(constraintsTip); // add blank space if there are multiple candidates diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d new file mode 100644 index 00000000000..84201793c0e --- /dev/null +++ b/gcc/d/dmd/funcsem.d @@ -0,0 +1,219 @@ +/** + * Does semantic analysis for functions. + * + * Specification: $(LINK2 https://dlang.org/spec/function.html, Functions) + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/funcsem.d, _funcsem.d) + * Documentation: https://dlang.org/phobos/dmd_funcsem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/funcsem.d + */ + +module dmd.funcsem; + +import core.stdc.stdio; + +import dmd.aggregate; +import dmd.arraytypes; +import dmd.astenums; +import dmd.blockexit; +import dmd.gluelayer; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.delegatize; +import dmd.dinterpret; +import dmd.dmodule; +import dmd.dscope; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.errors; +import dmd.escape; +import dmd.expression; +import dmd.func; +import dmd.globals; +import dmd.hdrgen; +import dmd.id; +import dmd.identifier; +import dmd.init; +import dmd.location; +import dmd.mtype; +import dmd.objc; +import dmd.root.aav; +import dmd.common.outbuffer; +import dmd.rootobject; +import dmd.root.string; +import dmd.root.stringtable; +import dmd.semantic2; +import dmd.semantic3; +import dmd.statement_rewrite_walker; +import dmd.statement; +import dmd.statementsem; +import dmd.tokens; +import dmd.visitor; + +/**************************************************** + * Resolve forward reference of function signature - + * parameter types, return type, and attributes. + * Params: + * fd = function declaration + * Returns: + * false if any errors exist in the signature. + */ +public +extern (C++) +bool functionSemantic(FuncDeclaration fd) +{ + //printf("functionSemantic() %p %s\n", this, toChars()); + if (!fd._scope) + return !fd.errors; + + fd.cppnamespace = fd._scope.namespace; + + if (!fd.originalType) // semantic not yet run + { + TemplateInstance spec = fd.isSpeculative(); + uint olderrs = global.errors; + uint oldgag = global.gag; + if (global.gag && !spec) + global.gag = 0; + dsymbolSemantic(fd, fd._scope); + global.gag = oldgag; + if (spec && global.errors != olderrs) + spec.errors = (global.errors - olderrs != 0); + if (olderrs != global.errors) // if errors compiling this function + return false; + } + + // if inferring return type, sematic3 needs to be run + // - When the function body contains any errors, we cannot assume + // the inferred return type is valid. + // So, the body errors should become the function signature error. + if (fd.inferRetType && fd.type && !fd.type.nextOf()) + return fd.functionSemantic3(); + + TemplateInstance ti; + if (fd.isInstantiated() && !fd.isVirtualMethod() && + ((ti = fd.parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == fd.ident)) + { + AggregateDeclaration ad = fd.isMemberLocal(); + if (ad && ad.sizeok != Sizeok.done) + { + /* Currently dmd cannot resolve forward references per methods, + * then setting SIZOKfwd is too conservative and would break existing code. + * So, just stop method attributes inference until ad.dsymbolSemantic() done. + */ + //ad.sizeok = Sizeok.fwd; + } + else + return fd.functionSemantic3() || !fd.errors; + } + + if (fd.storage_class & STC.inference) + return fd.functionSemantic3() || !fd.errors; + + return !fd.errors; +} + +/**************************************************** + * Resolve forward reference of function body. + * Returns false if any errors exist in the body. + */ +public +extern (C++) +bool functionSemantic3(FuncDeclaration fd) +{ + if (fd.semanticRun < PASS.semantic3 && fd._scope) + { + /* Forward reference - we need to run semantic3 on this function. + * If errors are gagged, and it's not part of a template instance, + * we need to temporarily ungag errors. + */ + TemplateInstance spec = fd.isSpeculative(); + uint olderrs = global.errors; + uint oldgag = global.gag; + if (global.gag && !spec) + global.gag = 0; + semantic3(fd, fd._scope); + global.gag = oldgag; + + // If it is a speculatively-instantiated template, and errors occur, + // we need to mark the template as having errors. + if (spec && global.errors != olderrs) + spec.errors = (global.errors - olderrs != 0); + if (olderrs != global.errors) // if errors compiling this function + return false; + } + + return !fd.errors && !fd.hasSemantic3Errors(); +} + +// called from semantic3 +/** + * Creates and returns the hidden parameters for this function declaration. + * + * Hidden parameters include the `this` parameter of a class, struct or + * nested function and the selector parameter for Objective-C methods. + */ +extern (D) void declareThis(FuncDeclaration fd, Scope* sc) +{ + const bool dualCtx = (fd.toParent2() != fd.toParentLocal()); + if (dualCtx) + fd.hasDualContext = true; + auto ad = fd.isThis(); + if (!dualCtx && !ad && !fd.isNested()) + { + fd.vthis = null; + fd.objc.selectorParameter = null; + return; + } + + Type addModStc(Type t) + { + return t.addMod(fd.type.mod).addStorageClass(fd.storage_class); + } + + if (dualCtx || fd.isNested()) + { + /* The 'this' for a nested function is the link to the + * enclosing function's stack frame. + * Note that nested functions and member functions are disjoint. + */ + Type tthis = addModStc(dualCtx ? + Type.tvoidptr.sarrayOf(2).pointerTo() : + Type.tvoid.pointerTo()); + fd.vthis = new VarDeclaration(fd.loc, tthis, dualCtx ? Id.this2 : Id.capture, null); + fd.vthis.storage_class |= STC.parameter | STC.nodtor; + } + else if (ad) + { + Type thandle = addModStc(ad.handleType()); + fd.vthis = new ThisDeclaration(fd.loc, thandle); + fd.vthis.storage_class |= STC.parameter; + if (thandle.ty == Tstruct) + { + fd.vthis.storage_class |= STC.ref_; + } + } + + if (auto tf = fd.type.isTypeFunction()) + { + if (tf.isreturn) + fd.vthis.storage_class |= STC.return_; + if (tf.isScopeQual) + fd.vthis.storage_class |= STC.scope_; + if (tf.isreturnscope) + fd.vthis.storage_class |= STC.returnScope; + } + + fd.vthis.dsymbolSemantic(sc); + if (!sc.insert(fd.vthis)) + assert(0); + fd.vthis.parent = fd; + if (ad) + fd.objc.selectorParameter = .objc.createSelectorParameter(fd, sc); +} diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index e9e73e8af66..af7b1fa371d 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -219,8 +219,8 @@ extern (C++) struct Param const(char)[] argv0; // program name Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings - Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules - Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules + Array!(const(char)*) imppath; // array of char*'s of where to look for import modules + Array!(const(char)*) fileImppath; // array of char*'s of where to look for file import modules const(char)[] objdir; // .obj/.lib file output directory const(char)[] objname; // .obj file output name const(char)[] libname; // .lib file output name @@ -280,8 +280,8 @@ extern (C++) struct Global string copyright = "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved"; string written = "written by Walter Bright"; - Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path - Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path + Array!(const(char)*) path; /// Array of char*'s which form the import lookup path + Array!(const(char)*) filePath; /// Array of char*'s which form the file import lookup path private enum string _version = import("VERSION"); char[26] datetime; /// string returned by ctime() @@ -296,8 +296,8 @@ extern (C++) struct Global void* console; /// opaque pointer to console for controlling text attributes - Array!Identifier* versionids; /// command line versions and predefined versions - Array!Identifier* debugids; /// command line debug versions and predefined versions + Array!Identifier versionids; /// command line versions and predefined versions + Array!Identifier debugids; /// command line debug versions and predefined versions bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch) uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 93e7c643d4c..f553ae6d8a9 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -202,8 +202,8 @@ struct Param DString argv0; // program name Array modFileAliasStrings; // array of char*'s of -I module filename alias strings - Array *imppath; // array of char*'s of where to look for import modules - Array *fileImppath; // array of char*'s of where to look for file import modules + Array imppath; // array of char*'s of where to look for import modules + Array fileImppath; // array of char*'s of where to look for file import modules DString objdir; // .obj/.lib file output directory DString objname; // .obj file output name DString libname; // .lib file output name @@ -282,8 +282,8 @@ struct Global const DString copyright; const DString written; - Array *path; // Array of char*'s which form the import lookup path - Array *filePath; // Array of char*'s which form the file import lookup path + Array path; // Array of char*'s which form the import lookup path + Array filePath; // Array of char*'s which form the file import lookup path char datetime[26]; /// string returned by ctime() CompileEnv compileEnv; @@ -297,8 +297,8 @@ struct Global void* console; // opaque pointer to console for controlling text attributes - Array* versionids; // command line versions and predefined versions - Array* debugids; // command line debug versions and predefined versions + Array versionids; // command line versions and predefined versions + Array debugids; // command line debug versions and predefined versions d_bool hasMainFunction; unsigned varSequenceNumber; diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 570c662624c..030153c91da 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -60,6 +60,7 @@ struct HdrGenState bool importcHdr; /// true if generating a .di file from an ImportC file bool doFuncBodies; /// include function bodies in output bool vcg_ast; /// write out codegen-ast + bool skipConstraints; // skip constraints when doing templates bool fullQual; /// fully qualify types when printing int tpltMember; @@ -1957,6 +1958,47 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) s.accept(v); } +// Note: this function is not actually `const`, because iterating the +// function parameter list may run dsymbolsemantic on enum types +public +void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, ref HdrGenState hgs) +{ + buf.writestring(td.ident == Id.ctor ? "this" : td.ident.toString()); + buf.writeByte('('); + foreach (i, const tp; *td.parameters) + { + if (i) + buf.writestring(", "); + toCBuffer(tp, buf, hgs); + } + buf.writeByte(')'); + + if (td.onemember) + { + if (const fd = td.onemember.isFuncDeclaration()) + { + if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction()) + { + // !! Casted away const + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } + } + } + } + + if (!hgs.skipConstraints && + td.constraint) + { + buf.writestring(" if ("); + toCBuffer(td.constraint, buf, hgs); + buf.writeByte(')'); + } +} + /***************************************** * Pretty-print a template parameter list to a buffer. @@ -2234,6 +2276,16 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt void visitString(StringExp e) { + if (e.hexString || e.sz == 8) + { + buf.writeByte('x'); + buf.writeByte('"'); + buf.writeHexString(e.peekData, true); + buf.writeByte('"'); + if (e.postfix) + buf.writeByte(e.postfix); + return; + } buf.writeByte('"'); const o = buf.length; foreach (i; 0 .. e.len) @@ -2247,6 +2299,37 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt buf.writeByte(e.postfix); } + void visitInterpolation(InterpExp e) + { + buf.writeByte('i'); + buf.writeByte('"'); + const o = buf.length; + + foreach (idx, str; e.interpolatedSet.parts) + { + if (idx % 2 == 0) + { + foreach(ch; str) + writeCharLiteral(buf, ch); + } + else + { + buf.writeByte('$'); + buf.writeByte('('); + foreach(ch; str) + buf.writeByte(ch); + buf.writeByte(')'); + } + } + + if (hgs.ddoc) + escapeDdocString(buf, o); + buf.writeByte('"'); + if (e.postfix) + buf.writeByte(e.postfix); + + } + void visitArrayLiteral(ArrayLiteralExp e) { buf.writeByte('['); @@ -2827,6 +2910,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt case EXP.super_: return visitSuper(e.isSuperExp()); case EXP.null_: return visitNull(e.isNullExp()); case EXP.string_: return visitString(e.isStringExp()); + case EXP.interpolated: return visitInterpolation(e.isInterpExp()); case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp()); case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp()); case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp()); diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index a66f2af4678..5ad324d6052 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -335,6 +335,12 @@ immutable Msgtable[] msgtable = { "_d_arrayassign_l" }, { "_d_arrayassign_r" }, + { "imported" }, + { "InterpolationHeader" }, + { "InterpolationFooter" }, + { "InterpolatedLiteral" }, + { "InterpolatedExpression" }, + // For pragma's { "Pinline", "inline" }, { "lib" }, diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 9819c3a90cc..7c6506712fc 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -873,12 +873,9 @@ public: propertyStart("predefinedVersions"); arrayStart(); - if (global.versionids) + foreach (const versionid; global.versionids) { - foreach (const versionid; *global.versionids) - { - item(versionid.toString()); - } + item(versionid.toString()); } arrayEnd(); @@ -905,12 +902,9 @@ public: propertyStart("importPaths"); arrayStart(); - if (global.params.imppath) + foreach (importPath; global.params.imppath[]) { - foreach (importPath; *global.params.imppath) - { - item(importPath.toDString); - } + item(importPath.toDString); } arrayEnd(); diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 5eadd721f64..937597cdf89 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -506,6 +506,29 @@ class Lexer } else goto case_ident; + case 'i': + if (Ccompile) + goto case_ident; + if (p[1] == '"') + { + p++; // skip the i + escapeStringConstant(t, true); + return; + } + else if (p[1] == '`') + { + p++; // skip the i + wysiwygStringConstant(t, true); + return; + } + else if (p[1] == 'q' && p[2] == '{') + { + p += 2; // skip the i and q + tokenStringConstant(t, true); + return; + } + else + goto case_ident; case '"': escapeStringConstant(t); return; @@ -517,7 +540,7 @@ class Lexer case 'f': case 'g': case 'h': - case 'i': + /*case 'i':*/ case 'j': case 'k': case 'l': @@ -1429,9 +1452,18 @@ class Lexer Params: result = pointer to the token that accepts the result */ - private void wysiwygStringConstant(Token* result) + private void wysiwygStringConstant(Token* result, bool supportInterpolation = false) { - result.value = TOK.string_; + if (supportInterpolation) + { + result.value = TOK.interpolated; + result.interpolatedSet = null; + } + else + { + result.value = TOK.string_; + } + Loc start = loc(); auto terminator = p[0]; p++; @@ -1451,6 +1483,14 @@ class Lexer c = '\n'; // treat EndOfLine as \n character endOfLine(); break; + case '$': + if (!supportInterpolation) + goto default; + + if (!handleInterpolatedSegment(result, start)) + goto default; + + continue; case 0: case 0x1A: error("unterminated string constant starting at %s", start.toChars()); @@ -1461,7 +1501,11 @@ class Lexer default: if (c == terminator) { - result.setString(stringbuffer); + if (supportInterpolation) + result.appendInterpolatedPart(stringbuffer); + else + result.setString(stringbuffer); + stringPostfix(result); return; } @@ -1736,13 +1780,21 @@ class Lexer Params: result = pointer to the token that accepts the result */ - private void tokenStringConstant(Token* result) + private void tokenStringConstant(Token* result, bool supportInterpolation = false) { - result.value = TOK.string_; + if (supportInterpolation) + { + result.value = TOK.interpolated; + result.interpolatedSet = null; + } + else + { + result.value = TOK.string_; + } uint nest = 1; const start = loc(); - const pstart = ++p; + auto pstart = ++p; inTokenStringConstant++; scope(exit) inTokenStringConstant--; while (1) @@ -1757,11 +1809,29 @@ class Lexer case TOK.rightCurly: if (--nest == 0) { - result.setString(pstart, p - 1 - pstart); + if (supportInterpolation) + result.appendInterpolatedPart(pstart, p - 1 - pstart); + else + result.setString(pstart, p - 1 - pstart); + stringPostfix(result); return; } continue; + case TOK.dollar: + if (!supportInterpolation) + goto default; + + stringbuffer.setsize(0); + stringbuffer.write(pstart, p - 1 - pstart); + if (!handleInterpolatedSegment(result, start)) + goto default; + + stringbuffer.setsize(0); + + pstart = p; + + continue; case TOK.endOfFile: error("unterminated token string constant starting at %s", start.toChars()); result.setString(); @@ -1772,6 +1842,52 @@ class Lexer } } + // returns true if it got special treatment as an interpolated segment + // otherwise returns false, indicating to treat it as just part of a normal string + private bool handleInterpolatedSegment(Token* token, Loc start) + { + switch(*p) + { + case '(': + // expression, at this level we need to scan until the closing ')' + + // always put the string part in first + token.appendInterpolatedPart(stringbuffer); + stringbuffer.setsize(0); + + int openParenCount = 1; + p++; // skip the first open paren + auto pstart = p; + while (openParenCount > 0) + { + // need to scan with the lexer to support embedded strings and other complex cases + Token tok; + scan(&tok); + if (tok.value == TOK.leftParenthesis) + openParenCount++; + if (tok.value == TOK.rightParenthesis) + openParenCount--; + if (tok.value == TOK.endOfFile) + { + // FIXME: make this error better, it spams a lot + error("unterminated interpolated string constant starting at %s", start.toChars()); + return false; + } + } + + // then put the interpolated string segment + token.appendInterpolatedPart(pstart[0 .. p - 1 - pstart]); + + stringbuffer.setsize(0); // make sure this is reset from the last token scan + // otherwise something like i"$(func("thing")) stuff" can still include it + + return true; + default: + // nothing special + return false; + } + } + /** Scan a quoted string while building the processed string value by handling escape sequences. The result is returned in the given `t` token. @@ -1783,9 +1899,17 @@ class Lexer * D https://dlang.org/spec/lex.html#double_quoted_strings * ImportC C11 6.4.5 */ - private void escapeStringConstant(Token* t) + private void escapeStringConstant(Token* t, bool supportInterpolation = false) { - t.value = TOK.string_; + if (supportInterpolation) + { + t.value = TOK.interpolated; + t.interpolatedSet = null; + } + else + { + t.value = TOK.string_; + } const start = loc(); const tc = *p++; // opening quote @@ -1813,11 +1937,28 @@ class Lexer c = escapeSequence(c2); stringbuffer.writeUTF8(c); continue; + case '$': + if (supportInterpolation) + { + p++; // skip escaped $ + stringbuffer.writeByte('$'); + continue; + } + else + goto default; default: c = escapeSequence(c2); break; } break; + case '$': + if (!supportInterpolation) + goto default; + + if (!handleInterpolatedSegment(t, start)) + goto default; + + continue; case '\n': endOfLine(); if (Ccompile) @@ -1835,7 +1976,10 @@ class Lexer case '"': if (c != tc) goto default; - t.setString(stringbuffer); + if (supportInterpolation) + t.appendInterpolatedPart(stringbuffer); + else + t.setString(stringbuffer); if (!Ccompile) stringPostfix(t); return; diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 3d88a1dfad3..276f209d4aa 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -27,9 +27,11 @@ import dmd.denum; import dmd.dstruct; import dmd.dsymbol; import dmd.dtemplate; +import dmd.enumsem; import dmd.errors; import dmd.expression; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -516,16 +518,39 @@ extern (C++) abstract class Type : ASTNode Terror ]; + static Type merge(Type t) + { + import dmd.basicmangle : tyToDecoBuffer; + + OutBuffer buf; + buf.reserve(3); + + if (t.ty == Tnoreturn) + buf.writestring("Nn"); + else + tyToDecoBuffer(buf, t.ty); + + auto sv = t.stringtable.update(buf[]); + if (sv.value) + return sv.value; + else + { + t.deco = cast(char*)sv.toDchars(); + sv.value = t; + return t; + } + } + for (size_t i = 0; basetab[i] != Terror; i++) { Type t = new TypeBasic(basetab[i]); - t = t.merge(); + t = merge(t); basic[basetab[i]] = t; } basic[Terror] = new TypeError(); tnoreturn = new TypeNoreturn(); - tnoreturn.deco = tnoreturn.merge().deco; + tnoreturn.deco = merge(tnoreturn).deco; basic[Tnoreturn] = tnoreturn; tvoid = basic[Tvoid]; @@ -560,7 +585,7 @@ extern (C++) abstract class Type : ASTNode terror = basic[Terror]; tnoreturn = basic[Tnoreturn]; tnull = new TypeNull(); - tnull.deco = tnull.merge().deco; + tnull.deco = merge(tnull).deco; tvoidptr = tvoid.pointerTo(); tstring = tchar.immutableOf().arrayOf(); @@ -601,29 +626,6 @@ extern (C++) abstract class Type : ASTNode return cast(uint)size(Loc.initial); } - /************************************* - * This version does a merge even if the deco is already computed. - * Necessary for types that have a deco, but are not merged. - */ - final Type merge2() - { - //printf("merge2(%s)\n", toChars()); - Type t = this; - assert(t); - if (!t.deco) - return t.merge(); - - auto sv = stringtable.lookup(t.deco, strlen(t.deco)); - if (sv && sv.value) - { - t = sv.value; - assert(t.deco); - } - else - assert(0); - return t; - } - /********************************* * Store this type's modifier name into buf. */ @@ -1693,7 +1695,7 @@ extern (C++) abstract class Type : ASTNode if (callable) { auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet); - if (!fd || fd.errors || !fd.functionSemantic()) + if (!fd || fd.errors || !functionSemantic(fd)) return Type.terror; auto t = fd.type.nextOf(); diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index c777f359da4..8b0a1b24ef1 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -233,7 +233,6 @@ public: uinteger_t size(); virtual uinteger_t size(const Loc &loc); virtual unsigned alignsize(); - Type *merge2(); void modToBuffer(OutBuffer& buf) const; char *modToChars() const; @@ -909,3 +908,4 @@ Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false); bool isBaseOf(Type *tthis, Type *t, int *poffset); Type *trySemantic(Type *type, const Loc &loc, Scope *sc); void purityLevel(TypeFunction *type); +Type *merge2(Type *type); diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 268622a82fc..0dc54ffe762 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -2015,6 +2015,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: @@ -5820,6 +5821,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.true_: case TOK.false_: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.leftParenthesis: case TOK.cast_: @@ -7313,6 +7315,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: @@ -8177,6 +8180,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); break; + case TOK.interpolated: + e = new AST.InterpExp(loc, token.interpolatedSet, token.postfix); + nextToken(); + break; + case TOK.string_: case TOK.hexadecimalString: const bool hexString = token.value == TOK.hexadecimalString; @@ -8810,6 +8818,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: + case TOK.interpolated: case TOK.function_: case TOK.delegate_: case TOK.typeof_: diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d index 3d0a5854625..422c1c8c0ec 100644 --- a/gcc/d/dmd/parsetimevisitor.d +++ b/gcc/d/dmd/parsetimevisitor.d @@ -183,6 +183,7 @@ public: void visit(AST.TypeidExp e) { visit(cast(AST.Expression)e); } void visit(AST.TraitsExp e) { visit(cast(AST.Expression)e); } void visit(AST.StringExp e) { visit(cast(AST.Expression)e); } + void visit(AST.InterpExp e) { visit(cast(AST.Expression)e); } void visit(AST.NewExp e) { visit(cast(AST.Expression)e); } void visit(AST.AssocArrayLiteralExp e) { visit(cast(AST.Expression)e); } void visit(AST.ArrayLiteralExp e) { visit(cast(AST.Expression)e); } diff --git a/gcc/d/dmd/res/default_ddoc_theme.ddoc b/gcc/d/dmd/res/default_ddoc_theme.ddoc index 7ae0db898ef..20269e1a084 100644 --- a/gcc/d/dmd/res/default_ddoc_theme.ddoc +++ b/gcc/d/dmd/res/default_ddoc_theme.ddoc @@ -70,7 +70,7 @@ D_CODE =
    -
  1. $0
  2. +
  3. $0
@@ -81,7 +81,7 @@ OTHER_CODE =
    -
  1. $+
  2. +
  3. $+
@@ -517,6 +517,10 @@ DDOC = white-space: pre-wrap; } + .ddoc .code_lines pre { + display: contents; + } + .ddoc .code_lines li:only-of-type::before { color: rgba(255, 255, 255, 1); content: " "; diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index 5b0bba42fc2..41c2050057d 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -78,7 +78,7 @@ nothrow: private const(char)[] str; /// - extern (D) this(const(char)[] str) pure + extern (D) this(const char[] str) pure { this.str = str.xarraydup; } @@ -96,7 +96,7 @@ nothrow: } /// Ditto - extern (D) static bool equals(const(char)[] name1, const(char)[] name2) pure @nogc + extern (D) static bool equals(const char[] name1, const char[] name2) pure @nogc { if (name1.length != name2.length) return false; @@ -125,7 +125,7 @@ nothrow: } /// Ditto - extern (D) static bool absolute(const(char)[] name) pure @nogc @safe + extern (D) static bool absolute(const char[] name) pure @nogc @safe { if (!name.length) return false; @@ -189,7 +189,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] ext(const(char)[] str) nothrow pure @safe @nogc + extern (D) static const(char)[] ext(const char[] str) nothrow pure @safe @nogc { foreach_reverse (idx, char e; str) { @@ -249,7 +249,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] removeExt(const(char)[] str) + extern (D) static const(char)[] removeExt(const char[] str) { auto e = ext(str); if (e.length) @@ -278,7 +278,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] name(const(char)[] str) pure @nogc @safe + extern (D) static const(char)[] name(const char[] str) pure @nogc @safe { foreach_reverse (idx, char e; str) { @@ -333,7 +333,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] path(const(char)[] str) + extern (D) static const(char)[] path(const char[] str) { const n = name(str); bool hasTrailingSlash; @@ -358,7 +358,7 @@ nothrow: /************************************** * Replace filename portion of path. */ - extern (D) static const(char)[] replaceName(const(char)[] path, const(char)[] name) + extern (D) static const(char)[] replaceName(const char[] path, const char[] name) { if (absolute(name)) return name; @@ -387,7 +387,7 @@ nothrow: } /// Ditto - extern(D) static const(char)[] combine(const(char)[] path, const(char)[] name) + extern(D) static const(char)[] combine(const char[] path, const char[] name) { return !path.length ? name : buildPath(path, name); } @@ -401,7 +401,7 @@ nothrow: assert(combine("foo/"[], "bar"[]) == "foo/bar"); } - static const(char)[] buildPath(const(char)[][] fragments...) + static const(char)[] buildPath(const char[][] fragments...) { size_t size; foreach (f; fragments) @@ -563,7 +563,7 @@ nothrow: * Returns: * A newly allocated string (free with `FileName.free`) */ - extern(D) static char[] addExt(const(char)[] name, const(char)[] ext) pure + extern(D) static char[] addExt(const char[] name, const char[] ext) pure { const len = name.length + ext.length + 2; auto s = cast(char*)mem.xmalloc(len); @@ -584,7 +584,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] defaultExt(const(char)[] name, const(char)[] ext) + extern (D) static const(char)[] defaultExt(const char[] name, const char[] ext) { auto e = FileName.ext(name); if (e.length) // it already has an extension @@ -608,7 +608,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] forceExt(const(char)[] name, const(char)[] ext) + extern (D) static const(char)[] forceExt(const char[] name, const char[] ext) { if (auto e = FileName.ext(name)) return addExt(name[0 .. $ - e.length - 1], ext); @@ -630,7 +630,7 @@ nothrow: } /// Ditto - extern (D) static bool equalsExt(const(char)[] name, const(char)[] ext) pure @nogc + extern (D) static bool equalsExt(const char[] name, const char[] ext) pure @nogc { auto e = FileName.ext(name); if (!e.length && !ext.length) @@ -665,12 +665,12 @@ nothrow: * Returns: * if found, filename combined with path, otherwise null */ - extern (C++) static const(char)* searchPath(Strings* path, const(char)* name, bool cwd) + extern (C++) static const(char)* searchPath(const ref Strings path, const char* name, bool cwd) { - return searchPath(path, name.toDString, cwd).ptr; + return searchPath(path[], name.toDString, cwd).ptr; } - extern (D) static const(char)[] searchPath(Strings* path, const(char)[] name, bool cwd) + extern (D) static const(char)[] searchPath(const char*[] path, const char[] name, bool cwd) { if (absolute(name)) { @@ -681,24 +681,21 @@ nothrow: if (exists(name)) return name; } - if (path) + foreach (p; path) { - foreach (p; *path) + auto n = combine(p.toDString, name); + if (exists(n)) + return n; + //combine might return name + if (n.ptr != name.ptr) { - auto n = combine(p.toDString, name); - if (exists(n)) - return n; - //combine might return name - if (n.ptr != name.ptr) - { - mem.xfree(cast(void*)n.ptr); - } + mem.xfree(cast(void*)n.ptr); } } return null; } - extern (D) static const(char)[] searchPath(const(char)* path, const(char)[] name, bool cwd) + extern (D) static const(char)[] searchPath(const char* path, const char[] name, bool cwd) { if (absolute(name)) { @@ -738,7 +735,7 @@ nothrow: * Returns: * index of the first reserved character in path if found, size_t.max otherwise */ - extern (D) static size_t findReservedChar(const(char)[] name) pure @nogc @safe + extern (D) static size_t findReservedChar(const char[] name) pure @nogc @safe { version (Windows) { @@ -787,7 +784,7 @@ nothrow: * Returns: * true if path contains '..' reference to parent directory */ - extern (D) static bool refersToParentDir(const(char)[] name) pure @nogc @safe + extern (D) static bool refersToParentDir(const char[] name) pure @nogc @safe { size_t s = 0; foreach (i; 0 .. name.length) @@ -845,7 +842,7 @@ nothrow: } /// Ditto - extern (D) static int exists(const(char)[] name) + extern (D) static int exists(const char[] name) { if (!name.length) return 0; @@ -892,7 +889,7 @@ nothrow: Returns: `true` if the directory exists or was successfully created */ - extern (D) static bool ensurePathExists(const(char)[] path) + extern (D) static bool ensurePathExists(const char[] path) { //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); if (!path.length) @@ -967,7 +964,7 @@ nothrow: } /// Ditto - extern (D) static const(char)[] canonicalName(const(char)[] name) + extern (D) static const(char)[] canonicalName(const char[] name) { version (Posix) { @@ -1127,7 +1124,7 @@ version(Windows) * References: * https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx */ - private int _mkdir(const(char)[] path) nothrow + private int _mkdir(const char[] path) nothrow { const createRet = path.extendedPathThen!( p => CreateDirectoryW(&p[0], null /*securityAttributes*/)); @@ -1175,7 +1172,7 @@ version(Windows) * Returns: * The result of calling F on the UTF16 version of str. */ - private auto toWStringzThen(alias F)(const(char)[] str) nothrow + private auto toWStringzThen(alias F)(const char[] str) nothrow { import dmd.common.smallbuffer : SmallBuffer, toWStringz; diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h index d8834a19282..0e52b982323 100644 --- a/gcc/d/dmd/root/filename.h +++ b/gcc/d/dmd/root/filename.h @@ -38,7 +38,7 @@ public: bool equalsExt(const char *ext); - static const char *searchPath(Strings *path, const char *name, bool cwd); + static const char *searchPath(Strings& path, const char *name, bool cwd); static int exists(const char *name); static bool ensurePathExists(const char *path); static const char *canonicalName(const char *name); diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 174d9b4dc14..125a39d179f 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -41,6 +41,7 @@ import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; @@ -384,7 +385,7 @@ private extern(C++) final class Semantic3Visitor : Visitor } } - funcdecl.declareThis(sc2); + declareThis(funcdecl, sc2); // Reverts: https://issues.dlang.org/show_bug.cgi?id=5710 // No compiler supports this, and there was never any spec for it. diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index d4827ae6aa1..840035c46cf 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -43,6 +43,7 @@ import dmd.escape; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.gluelayer; import dmd.hdrgen; @@ -1284,7 +1285,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) Type tfront; if (auto fd = sfront.isFuncDeclaration()) { - if (!fd.functionSemantic()) + if (!functionSemantic(fd)) return rangeError(); tfront = fd.type; } diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d new file mode 100644 index 00000000000..1942afe44ae --- /dev/null +++ b/gcc/d/dmd/templatesem.d @@ -0,0 +1,1497 @@ +/** + * Template semantics. + * + * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templatesem.d, _templatesem.d) + * Documentation: https://dlang.org/phobos/dmd_templatesem.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templatesem.d + */ + +module dmd.templatesem; + +import core.stdc.stdio; +import core.stdc.string; +import dmd.aggregate; +import dmd.aliasthis; +import dmd.arraytypes; +import dmd.astenums; +import dmd.ast_node; +import dmd.attrib; +import dmd.dcast; +import dmd.dclass; +import dmd.declaration; +import dmd.dinterpret; +import dmd.dmangle; +import dmd.dmodule; +import dmd.dscope; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.errors; +import dmd.errorsink; +import dmd.expression; +import dmd.expressionsem; +import dmd.func; +import dmd.funcsem; +import dmd.globals; +import dmd.hdrgen; +import dmd.id; +import dmd.identifier; +import dmd.impcnvtab; +import dmd.init; +import dmd.initsem; +import dmd.location; +import dmd.mtype; +import dmd.opover; +import dmd.optimize; +import dmd.root.array; +import dmd.common.outbuffer; +import dmd.rootobject; +import dmd.semantic2; +import dmd.semantic3; +import dmd.tokens; +import dmd.typesem; +import dmd.visitor; + +/*************************************** + * Given that ti is an instance of this TemplateDeclaration, + * deduce the types of the parameters to this, and store + * those deduced types in dedtypes[]. + * Params: + * sc = context + * td = template + * ti = instance of td + * dedtypes = fill in with deduced types + * argumentList = arguments to template instance + * flag = 1 - don't do semantic() because of dummy types + * 2 - don't change types in matchArg() + * Returns: match level. + */ +public +MATCH matchWithInstance(Scope* sc, TemplateDeclaration td, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag) +{ + enum LOGM = 0; + static if (LOGM) + { + printf("\n+TemplateDeclaration.matchWithInstance(td = %s, ti = %s, flag = %d)\n", td.toChars(), ti.toChars(), flag); + } + version (none) + { + printf("dedtypes.length = %d, parameters.length = %d\n", dedtypes.length, parameters.length); + if (ti.tiargs.length) + printf("ti.tiargs.length = %d, [0] = %p\n", ti.tiargs.length, (*ti.tiargs)[0]); + } + MATCH nomatch() + { + static if (LOGM) + { + printf(" no match\n"); + } + return MATCH.nomatch; + } + MATCH m; + size_t dedtypes_dim = dedtypes.length; + + dedtypes.zero(); + + if (td.errors) + return MATCH.nomatch; + + size_t parameters_dim = td.parameters.length; + int variadic = td.isVariadic() !is null; + + // If more arguments than parameters, no match + if (ti.tiargs.length > parameters_dim && !variadic) + { + static if (LOGM) + { + printf(" no match: more arguments than parameters\n"); + } + return MATCH.nomatch; + } + + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti.tiargs.length || variadic); + + assert(td._scope); + + // Set up scope for template parameters + Scope* paramscope = createScopeForTemplateParameters(td, ti, sc); + + // Attempt type deduction + m = MATCH.exact; + for (size_t i = 0; i < dedtypes_dim; i++) + { + MATCH m2; + TemplateParameter tp = (*td.parameters)[i]; + Declaration sparam; + + //printf("\targument [%d]\n", i); + static if (LOGM) + { + //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null"); + TemplateTypeParameter ttp = tp.isTemplateTypeParameter(); + if (ttp) + printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : ""); + } + + m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, td.parameters, dedtypes, &sparam); + //printf("\tm2 = %d\n", m2); + if (m2 == MATCH.nomatch) + { + version (none) + { + printf("\tmatchArg() for parameter %i failed\n", i); + } + return nomatch(); + } + + if (m2 < m) + m = m2; + + if (!flag) + sparam.dsymbolSemantic(paramscope); + if (!paramscope.insert(sparam)) // TODO: This check can make more early + { + // in TemplateDeclaration.semantic, and + // then we don't need to make sparam if flags == 0 + return nomatch(); + } + } + + if (!flag) + { + /* Any parameter left without a type gets the type of + * its corresponding arg + */ + foreach (i, ref dedtype; dedtypes) + { + if (!dedtype) + { + assert(i < ti.tiargs.length); + dedtype = cast(Type)(*ti.tiargs)[i]; + } + } + } + + if (m > MATCH.nomatch && td.constraint && !flag) + { + if (ti.hasNestedArgs(ti.tiargs, td.isstatic)) // TODO: should gag error + ti.parent = ti.enclosing; + else + ti.parent = td.parent; + + // Similar to doHeaderInstantiation + FuncDeclaration fd = td.onemember ? td.onemember.isFuncDeclaration() : null; + if (fd) + { + TypeFunction tf = fd.type.isTypeFunction().syntaxCopy(); + if (argumentList.hasNames) + return nomatch(); + Expressions* fargs = argumentList.arguments; + // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null); + // if (!fargs) + // return nomatch(); + + fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); + fd.parent = ti; + fd.inferRetType = true; + + // Shouldn't run semantic on default arguments and return type. + foreach (ref param; *tf.parameterList.parameters) + param.defaultArg = null; + + tf.next = null; + tf.incomplete = true; + + // Resolve parameter types and 'auto ref's. + tf.fargs = fargs; + uint olderrors = global.startGagging(); + fd.type = tf.typeSemantic(td.loc, paramscope); + global.endGagging(olderrors); + if (fd.type.ty != Tfunction) + return nomatch(); + fd.originalType = fd.type; // for mangling + } + + // TODO: dedtypes => ti.tiargs ? + if (!evaluateConstraint(td, ti, sc, paramscope, &dedtypes, fd)) + return nomatch(); + } + + static if (LOGM) + { + // Print out the results + printf("--------------------------\n"); + printf("template %s\n", toChars()); + printf("instance %s\n", ti.toChars()); + if (m > MATCH.nomatch) + { + for (size_t i = 0; i < dedtypes_dim; i++) + { + TemplateParameter tp = (*parameters)[i]; + RootObject oarg; + printf(" [%d]", i); + if (i < ti.tiargs.length) + oarg = (*ti.tiargs)[i]; + else + oarg = null; + tp.print(oarg, (*dedtypes)[i]); + } + } + else + return nomatch(); + } + static if (LOGM) + { + printf(" match = %d\n", m); + } + + paramscope.pop(); + static if (LOGM) + { + printf("-TemplateDeclaration.matchWithInstance(td = %s, ti = %s) = %d\n", td.toChars(), ti.toChars(), m); + } + return m; +} + +/**************************** + * Check to see if constraint is satisfied. + */ +bool evaluateConstraint(TemplateDeclaration td, TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd) +{ + /* Detect recursive attempts to instantiate this template declaration, + * https://issues.dlang.org/show_bug.cgi?id=4072 + * void foo(T)(T x) if (is(typeof(foo(x)))) { } + * static assert(!is(typeof(foo(7)))); + * Recursive attempts are regarded as a constraint failure. + */ + /* There's a chicken-and-egg problem here. We don't know yet if this template + * instantiation will be a local one (enclosing is set), and we won't know until + * after selecting the correct template. Thus, function we're nesting inside + * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel(). + * Workaround the problem by setting a flag to relax the checking on frame errors. + */ + + for (TemplatePrevious* p = td.previous; p; p = p.prev) + { + if (!arrayObjectMatch(*p.dedargs, *dedargs)) + continue; + //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars()); + /* It must be a subscope of p.sc, other scope chains are not recursive + * instantiations. + * the chain of enclosing scopes is broken by paramscope (its enclosing + * scope is _scope, but paramscope.callsc is the instantiating scope). So + * it's good enough to check the chain of callsc + */ + for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc) + { + // The first scx might be identical for nested eponymeous templates, e.g. + // template foo() { void foo()() {...} } + if (scx == p.sc && scx !is paramscope.callsc) + return false; + } + /* BUG: should also check for ref param differences + */ + } + + TemplatePrevious pr; + pr.prev = td.previous; + pr.sc = paramscope.callsc; + pr.dedargs = dedargs; + td.previous = ≺ // add this to threaded list + + Scope* scx = paramscope.push(ti); + scx.parent = ti; + scx.tinst = null; + scx.minst = null; + // Set SCOPE.constraint before declaring function parameters for the static condition + // (previously, this was immediately before calling evalStaticCondition), so the + // semantic pass knows not to issue deprecation warnings for these throw-away decls. + // https://issues.dlang.org/show_bug.cgi?id=21831 + scx.flags |= SCOPE.constraint; + + assert(!ti.symtab); + if (fd) + { + /* Declare all the function parameters as variables and add them to the scope + * Making parameters is similar to FuncDeclaration.semantic3 + */ + auto tf = fd.type.isTypeFunction(); + + scx.parent = fd; + + Parameters* fparameters = tf.parameterList.parameters; + const nfparams = tf.parameterList.length; + foreach (i, fparam; tf.parameterList) + { + fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); + fparam.storageClass |= STC.parameter; + if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams) + { + fparam.storageClass |= STC.variadic; + /* Don't need to set STC.scope_ because this will only + * be evaluated at compile time + */ + } + } + foreach (fparam; *fparameters) + { + if (!fparam.ident) + continue; + // don't add it, if it has no name + auto v = new VarDeclaration(fparam.loc, fparam.type, fparam.ident, null); + fparam.storageClass |= STC.parameter; + v.storage_class = fparam.storageClass; + v.dsymbolSemantic(scx); + if (!ti.symtab) + ti.symtab = new DsymbolTable(); + if (!scx.insert(v)) + .error(td.loc, "%s `%s` parameter `%s.%s` is already defined", td.kind, td.toPrettyChars, td.toChars(), v.toChars()); + else + v.parent = fd; + } + if (td.isstatic) + fd.storage_class |= STC.static_; + declareThis(fd, scx); + } + + td.lastConstraint = td.constraint.syntaxCopy(); + td.lastConstraintTiargs = ti.tiargs; + td.lastConstraintNegs.setDim(0); + + import dmd.staticcond; + + assert(ti.inst is null); + ti.inst = ti; // temporary instantiation to enable genIdent() + bool errors; + const bool result = evalStaticCondition(scx, td.constraint, td.lastConstraint, errors, &td.lastConstraintNegs); + if (result || errors) + { + td.lastConstraint = null; + td.lastConstraintTiargs = null; + td.lastConstraintNegs.setDim(0); + } + ti.inst = null; + ti.symtab = null; + scx = scx.pop(); + td.previous = pr.prev; // unlink from threaded list + if (errors) + return false; + return result; +} + +/******************************************* + * Append to buf a textual representation of template parameters with their arguments. + * Params: + * parameters = the template parameters + * tiargs = the correspondeing template arguments + * variadic = if it's a variadic argument list + * buf = where the text output goes + */ +void formatParamsWithTiargs(ref TemplateParameters parameters, ref Objects tiargs, bool variadic, ref OutBuffer buf) +{ + buf.writestring(" with `"); + + // write usual arguments line-by-line + // skips trailing default ones - they are not present in `tiargs` + const end = parameters.length - (variadic ? 1 : 0); + size_t i; + for (; i < tiargs.length && i < end; i++) + { + if (i) + { + buf.writeByte(','); + buf.writenl(); + buf.writestring(" "); + } + write(buf, parameters[i]); + buf.writestring(" = "); + write(buf, tiargs[i]); + } + // write remaining variadic arguments on the last line + if (variadic) + { + if (i) + { + buf.writeByte(','); + buf.writenl(); + buf.writestring(" "); + } + write(buf, parameters[end]); + buf.writestring(" = "); + buf.writeByte('('); + if (end < tiargs.length) + { + write(buf, tiargs[end]); + foreach (j; parameters.length .. tiargs.length) + { + buf.writestring(", "); + write(buf, tiargs[j]); + } + } + buf.writeByte(')'); + } + buf.writeByte('`'); +} + +/****************************** + * Create a scope for the parameters of the TemplateInstance + * `ti` in the parent scope sc from the ScopeDsymbol paramsym. + * + * If paramsym is null a new ScopeDsymbol is used in place of + * paramsym. + * Params: + * td = template that ti is an instance of + * ti = the TemplateInstance whose parameters to generate the scope for. + * sc = the parent scope of ti + * Returns: + * new scope for the parameters of ti + */ +Scope* createScopeForTemplateParameters(TemplateDeclaration td, TemplateInstance ti, Scope* sc) +{ + ScopeDsymbol paramsym = new ScopeDsymbol(); + paramsym.parent = td._scope.parent; + Scope* paramscope = td._scope.push(paramsym); + paramscope.tinst = ti; + paramscope.minst = sc.minst; + paramscope.callsc = sc; + paramscope.stc = 0; + return paramscope; +} + +/******************************************** + * Determine partial specialization order of `td` vs `td2`. + * Params: + * sc = context + * td = first template + * td2 = second template + * argumentList = arguments to template + * Returns: + * MATCH - td is at least as specialized as td2 + * MATCH.nomatch - td2 is more specialized than td + */ +MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td, TemplateDeclaration td2, ArgumentList argumentList) +{ + enum LOG_LEASTAS = 0; + static if (LOG_LEASTAS) + { + printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); + } + + /* This works by taking the template parameters to this template + * declaration and feeding them to td2 as if it were a template + * instance. + * If it works, then this template is at least as specialized + * as td2. + */ + + // Set type arguments to dummy template instance to be types + // generated from the parameters to this template declaration + auto tiargs = new Objects(); + tiargs.reserve(td.parameters.length); + foreach (tp; *td.parameters) + { + if (tp.dependent) + break; + RootObject p = tp.dummyArg(); + if (!p) //TemplateTupleParameter + break; + + tiargs.push(p); + } + scope TemplateInstance ti = new TemplateInstance(Loc.initial, td.ident, tiargs); // create dummy template instance + + // Temporary Array to hold deduced types + Objects dedtypes = Objects(td2.parameters.length); + + // Attempt a type deduction + MATCH m = matchWithInstance(sc, td2, ti, dedtypes, argumentList, 1); + if (m > MATCH.nomatch) + { + /* A non-variadic template is more specialized than a + * variadic one. + */ + TemplateTupleParameter tp = td.isVariadic(); + if (tp && !tp.dependent && !td2.isVariadic()) + goto L1; + + static if (LOG_LEASTAS) + { + printf(" matches %d, so is least as specialized\n", m); + } + return m; + } +L1: + static if (LOG_LEASTAS) + { + printf(" doesn't match, so is not as specialized\n"); + } + return MATCH.nomatch; +} + +/************************************************* + * Match function arguments against a specific template function. + * + * Params: + * td = template declaration for template instance + * ti = template instance. `ti.tdtypes` will be set to Expression/Type deduced template arguments + * sc = instantiation scope + * fd = Partially instantiated function declaration, which is set to an instantiated function declaration + * tthis = 'this' argument if !NULL + * argumentList = arguments to function + * + * Returns: + * match pair of initial and inferred template arguments + */ +extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList) +{ + version (none) + { + printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", td.toChars()); + for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) + { + Expression e = (*fargs)[i]; + printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars()); + } + printf("fd = %s\n", fd.toChars()); + printf("fd.type = %s\n", fd.type.toChars()); + if (tthis) + printf("tthis = %s\n", tthis.toChars()); + } + + assert(td._scope); + + auto dedargs = new Objects(td.parameters.length); + dedargs.zero(); + + Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T + dedtypes.setDim(td.parameters.length); + dedtypes.zero(); + + if (td.errors || fd.errors) + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + + // Set up scope for parameters + Scope* paramscope = createScopeForTemplateParameters(td, ti,sc); + + MATCHpair nomatch() + { + paramscope.pop(); + //printf("\tnomatch\n"); + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + } + + MATCHpair matcherror() + { + // todo: for the future improvement + paramscope.pop(); + //printf("\terror\n"); + return MATCHpair(MATCH.nomatch, MATCH.nomatch); + } + // Mark the parameter scope as deprecated if the templated + // function is deprecated (since paramscope.enclosing is the + // calling scope already) + paramscope.stc |= fd.storage_class & STC.deprecated_; + + TemplateTupleParameter tp = td.isVariadic(); + Tuple declaredTuple = null; + + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + printf("\tdedarg[%d] = ", i); + RootObject oarg = (*dedargs)[i]; + if (oarg) + printf("%s", oarg.toChars()); + printf("\n"); + } + } + + size_t ntargs = 0; // array size of tiargs + size_t inferStart = 0; // index of first parameter to infer + const Loc instLoc = ti.loc; + MATCH matchTiargs = MATCH.exact; + + if (auto tiargs = ti.tiargs) + { + // Set initial template arguments + ntargs = tiargs.length; + size_t n = td.parameters.length; + if (tp) + n--; + if (ntargs > n) + { + if (!tp) + return nomatch(); + + /* The extra initial template arguments + * now form the tuple argument. + */ + auto t = new Tuple(ntargs - n); + assert(td.parameters.length); + (*dedargs)[td.parameters.length - 1] = t; + + for (size_t i = 0; i < t.objects.length; i++) + { + t.objects[i] = (*tiargs)[n + i]; + } + td.declareParameter(paramscope, tp, t); + declaredTuple = t; + } + else + n = ntargs; + + memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof); + + for (size_t i = 0; i < n; i++) + { + assert(i < td.parameters.length); + Declaration sparam = null; + MATCH m = (*td.parameters)[i].matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); + if (m == MATCH.nomatch) + return nomatch(); + if (m < matchTiargs) + matchTiargs = m; + + sparam.dsymbolSemantic(paramscope); + if (!paramscope.insert(sparam)) + return nomatch(); + } + if (n < td.parameters.length && !declaredTuple) + { + inferStart = n; + } + else + inferStart = td.parameters.length; + //printf("tiargs matchTiargs = %d\n", matchTiargs); + } + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + printf("\tdedarg[%d] = ", i); + RootObject oarg = (*dedargs)[i]; + if (oarg) + printf("%s", oarg.toChars()); + printf("\n"); + } + } + + ParameterList fparameters = fd.getParameterList(); // function parameter list + const nfparams = fparameters.length; // number of function parameters + if (argumentList.hasNames) + return matcherror(); // TODO: resolve named args + Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; + + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * void foo(T, A...)(T t, A a); + * void main() { foo(1,2,3); } + */ + size_t fptupindex = IDX_NOTFOUND; + if (tp) // if variadic + { + // TemplateTupleParameter always makes most lesser matching. + matchTiargs = MATCH.convert; + + if (nfparams == 0 && argumentList.length != 0) // if no function parameters + { + if (!declaredTuple) + { + auto t = new Tuple(); + //printf("t = %p\n", t); + (*dedargs)[td.parameters.length - 1] = t; + td.declareParameter(paramscope, tp, t); + declaredTuple = t; + } + } + else + { + /* Figure out which of the function parameters matches + * the tuple template parameter. Do this by matching + * type identifiers. + * Set the index of this function parameter to fptupindex. + */ + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ? + if (fparam.type.ty != Tident) + continue; + TypeIdentifier tid = fparam.type.isTypeIdentifier(); + if (!tp.ident.equals(tid.ident) || tid.idents.length) + continue; + + if (fparameters.varargs != VarArg.none) // variadic function doesn't + return nomatch(); // go with variadic template + + goto L1; + } + fptupindex = IDX_NOTFOUND; + L1: + } + } + + MATCH match = MATCH.exact; + if (td.toParent().isModule()) + tthis = null; + if (tthis) + { + bool hasttp = false; + + // Match 'tthis' to any TemplateThisParameter's + foreach (param; *td.parameters) + { + if (auto ttp = param.isTemplateThisParameter()) + { + hasttp = true; + + Type t = new TypeIdentifier(Loc.initial, ttp.ident); + MATCH m = deduceType(tthis, paramscope, t, *td.parameters, *dedtypes); + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; // pick worst match + } + } + + // Match attributes of tthis against attributes of fd + if (fd.type && !fd.isCtorDeclaration() && !(td._scope.stc & STC.static_)) + { + StorageClass stc = td._scope.stc | fd.storage_class2; + // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504 + Dsymbol p = td.parent; + while (p.isTemplateDeclaration() || p.isTemplateInstance()) + p = p.parent; + AggregateDeclaration ad = p.isAggregateDeclaration(); + if (ad) + stc |= ad.storage_class; + + ubyte mod = fd.type.mod; + if (stc & STC.immutable_) + mod = MODFlags.immutable_; + else + { + if (stc & (STC.shared_ | STC.synchronized_)) + mod |= MODFlags.shared_; + if (stc & STC.const_) + mod |= MODFlags.const_; + if (stc & STC.wild) + mod |= MODFlags.wild; + } + + ubyte thismod = tthis.mod; + if (hasttp) + mod = MODmerge(thismod, mod); + MATCH m = MODmethodConv(thismod, mod); + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + } + } + + // Loop through the function parameters + { + //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0); + //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL); + size_t argi = 0; + size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs + uint inoutMatch = 0; // for debugging only + for (size_t parami = 0; parami < nfparams; parami++) + { + Parameter fparam = fparameters[parami]; + + // Apply function parameter storage classes to parameter types + Type prmtype = fparam.type.addStorageClass(fparam.storageClass); + + Expression farg; + + /* See function parameters which wound up + * as part of a template tuple parameter. + */ + if (fptupindex != IDX_NOTFOUND && parami == fptupindex) + { + TypeIdentifier tid = prmtype.isTypeIdentifier(); + assert(tid); + if (!declaredTuple) + { + /* The types of the function arguments + * now form the tuple argument. + */ + declaredTuple = new Tuple(); + (*dedargs)[td.parameters.length - 1] = declaredTuple; + + /* Count function parameters with no defaults following a tuple parameter. + * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double) + */ + size_t rem = 0; + foreach (j; parami + 1 .. nfparams) + { + Parameter p = fparameters[j]; + if (p.defaultArg) + { + break; + } + if (!reliesOnTemplateParameters(p.type, (*td.parameters)[inferStart .. td.parameters.length])) + { + Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope); + if (auto ptt = pt.isTypeTuple()) + rem += ptt.arguments.length; + else + rem += 1; + } + else + { + ++rem; + } + } + + if (nfargs2 - argi < rem) + return nomatch(); + declaredTuple.objects.setDim(nfargs2 - argi - rem); + foreach (i; 0 .. declaredTuple.objects.length) + { + farg = fargs[argi + i]; + + // Check invalid arguments to detect errors early. + if (farg.op == EXP.error || farg.type.ty == Terror) + return nomatch(); + + if (!fparam.isLazy() && farg.type.ty == Tvoid) + return nomatch(); + + Type tt; + MATCH m; + if (ubyte wm = deduceWildHelper(farg.type, &tt, tid)) + { + inoutMatch |= wm; + m = MATCH.constant; + } + else + { + m = deduceTypeHelper(farg.type, tt, tid); + } + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + + /* Remove top const for dynamic array types and pointer types + */ + if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue())) + { + tt = tt.mutableOf(); + } + declaredTuple.objects[i] = tt; + } + td.declareParameter(paramscope, tp, declaredTuple); + } + else + { + // https://issues.dlang.org/show_bug.cgi?id=6810 + // If declared tuple is not a type tuple, + // it cannot be function parameter types. + for (size_t i = 0; i < declaredTuple.objects.length; i++) + { + if (!isType(declaredTuple.objects[i])) + return nomatch(); + } + } + assert(declaredTuple); + argi += declaredTuple.objects.length; + continue; + } + + // If parameter type doesn't depend on inferred template parameters, + // semantic it to get actual type. + if (!reliesOnTemplateParameters(prmtype, (*td.parameters)[inferStart .. td.parameters.length])) + { + // should copy prmtype to avoid affecting semantic result + prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope); + + if (TypeTuple tt = prmtype.isTypeTuple()) + { + const tt_dim = tt.arguments.length; + for (size_t j = 0; j < tt_dim; j++, ++argi) + { + Parameter p = (*tt.arguments)[j]; + if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe && + parami + 1 == nfparams && argi < fargs.length) + { + prmtype = p.type; + goto Lvarargs; + } + if (argi >= fargs.length) + { + if (p.defaultArg) + continue; + + // https://issues.dlang.org/show_bug.cgi?id=19888 + if (fparam.defaultArg) + break; + + return nomatch(); + } + farg = fargs[argi]; + if (!farg.implicitConvTo(p.type)) + return nomatch(); + } + continue; + } + } + + if (argi >= fargs.length) // if not enough arguments + { + if (!fparam.defaultArg) + goto Lvarargs; + + /* https://issues.dlang.org/show_bug.cgi?id=2803 + * Before the starting of type deduction from the function + * default arguments, set the already deduced parameters into paramscope. + * It's necessary to avoid breaking existing acceptable code. Cases: + * + * 1. Already deduced template parameters can appear in fparam.defaultArg: + * auto foo(A, B)(A a, B b = A.stringof); + * foo(1); + * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int' + * + * 2. If prmtype depends on default-specified template parameter, the + * default type should be preferred. + * auto foo(N = size_t, R)(R r, N start = 0) + * foo([1,2,3]); + * // at fparam `N start = 0`, N should be 'size_t' before + * // the deduction result from fparam.defaultArg. + */ + if (argi == fargs.length) + { + foreach (ref dedtype; *dedtypes) + { + Type at = isType(dedtype); + if (at && at.ty == Tnone) + { + TypeDeduced xt = cast(TypeDeduced)at; + dedtype = xt.tded; // 'unbox' + } + } + for (size_t i = ntargs; i < dedargs.length; i++) + { + TemplateParameter tparam = (*td.parameters)[i]; + + RootObject oarg = (*dedargs)[i]; + RootObject oded = (*dedtypes)[i]; + if (oarg) + continue; + + if (oded) + { + if (tparam.specialization() || !tparam.isTemplateTypeParameter()) + { + /* The specialization can work as long as afterwards + * the oded == oarg + */ + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", + td.kind, td.toPrettyChars, td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + else + { + if (MATCH.convert < matchTiargs) + matchTiargs = MATCH.convert; + } + (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded); + } + else + { + oded = tparam.defaultArg(instLoc, paramscope); + if (oded) + (*dedargs)[i] = td.declareParameter(paramscope, tparam, oded); + } + } + } + nfargs2 = argi + 1; + + /* If prmtype does not depend on any template parameters: + * + * auto foo(T)(T v, double x = 0); + * foo("str"); + * // at fparam == 'double x = 0' + * + * or, if all template parameters in the prmtype are already deduced: + * + * auto foo(R)(R range, ElementType!R sum = 0); + * foo([1,2,3]); + * // at fparam == 'ElementType!R sum = 0' + * + * Deducing prmtype from fparam.defaultArg is not necessary. + */ + if (prmtype.deco || prmtype.syntaxCopy().trySemantic(td.loc, paramscope)) + { + ++argi; + continue; + } + + // Deduce prmtype from the defaultArg. + farg = fparam.defaultArg.syntaxCopy(); + farg = farg.expressionSemantic(paramscope); + farg = resolveProperties(paramscope, farg); + } + else + { + farg = fargs[argi]; + } + { + // Check invalid arguments to detect errors early. + if (farg.op == EXP.error || farg.type.ty == Terror) + return nomatch(); + + Type att = null; + Lretry: + version (none) + { + printf("\tfarg.type = %s\n", farg.type.toChars()); + printf("\tfparam.type = %s\n", prmtype.toChars()); + } + Type argtype = farg.type; + + if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_) + return nomatch(); + + // https://issues.dlang.org/show_bug.cgi?id=12876 + // Optimize argument to allow CT-known length matching + farg = farg.optimize(WANTvalue, fparam.isReference()); + //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars()); + + RootObject oarg = farg; + if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue())) + { + /* Allow expressions that have CT-known boundaries and type [] to match with [dim] + */ + bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray); + if (auto aaType = prmtype.isTypeAArray()) + { + if (auto indexType = aaType.index.isTypeIdentifier()) + { + inferIndexType = indexType.idents.length == 0; + } + } + if (inferIndexType) + { + if (StringExp se = farg.isStringExp()) + { + argtype = se.type.nextOf().sarrayOf(se.len); + } + else if (ArrayLiteralExp ae = farg.isArrayLiteralExp()) + { + argtype = ae.type.nextOf().sarrayOf(ae.elements.length); + } + else if (SliceExp se = farg.isSliceExp()) + { + if (Type tsa = toStaticArrayType(se)) + argtype = tsa; + } + } + + oarg = argtype; + } + else if ((fparam.storageClass & STC.out_) == 0 && + (argtype.ty == Tarray || argtype.ty == Tpointer) && + templateParameterLookup(prmtype, td.parameters) != IDX_NOTFOUND && + prmtype.isTypeIdentifier().idents.length == 0) + { + /* The farg passing to the prmtype always make a copy. Therefore, + * we can shrink the set of the deduced type arguments for prmtype + * by adjusting top-qualifier of the argtype. + * + * prmtype argtype ta + * T <- const(E)[] const(E)[] + * T <- const(E[]) const(E)[] + * qualifier(T) <- const(E)[] const(E[]) + * qualifier(T) <- const(E[]) const(E[]) + */ + Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0); + if (ta != argtype) + { + Expression ea = farg.copy(); + ea.type = ta; + oarg = ea; + } + } + + if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length) + goto Lvarargs; + + uint im = 0; + MATCH m = deduceType(oarg, paramscope, prmtype, *td.parameters, *dedtypes, &im, inferStart); + //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch); + inoutMatch |= im; + + /* If no match, see if the argument can be matched by using + * implicit conversions. + */ + if (m == MATCH.nomatch && prmtype.deco) + m = farg.implicitConvTo(prmtype); + + if (m == MATCH.nomatch) + { + AggregateDeclaration ad = isAggregate(farg.type); + if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype)) + { + // https://issues.dlang.org/show_bug.cgi?id=12537 + // The isRecursiveAliasThis() call above + + /* If a semantic error occurs while doing alias this, + * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295), + * just regard it as not a match. + * + * We also save/restore sc.func.flags to avoid messing up + * attribute inference in the evaluation. + */ + const oldflags = sc.func ? sc.func.flags : 0; + auto e = resolveAliasThis(sc, farg, true); + if (sc.func) + sc.func.flags = oldflags; + if (e) + { + farg = e; + goto Lretry; + } + } + } + + if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_) + { + if (!farg.isLvalue()) + { + if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray)) + { + // Allow conversion from T[lwr .. upr] to ref T[upr-lwr] + } + else if (global.params.rvalueRefParam == FeatureState.enabled) + { + // Allow implicit conversion to ref + } + else + return nomatch(); + } + } + if (m > MATCH.nomatch && (fparam.storageClass & STC.out_)) + { + if (!farg.isLvalue()) + return nomatch(); + if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916 + return nomatch(); + } + if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid) + m = MATCH.convert; + if (m != MATCH.nomatch) + { + if (m < match) + match = m; // pick worst match + argi++; + continue; + } + } + + Lvarargs: + /* The following code for variadic arguments closely + * matches TypeFunction.callMatch() + */ + if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams)) + return nomatch(); + + /* Check for match with function parameter T... + */ + Type tb = prmtype.toBasetype(); + switch (tb.ty) + { + // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic(). + case Tsarray: + case Taarray: + { + // Perhaps we can do better with this, see TypeFunction.callMatch() + if (TypeSArray tsa = tb.isTypeSArray()) + { + dinteger_t sz = tsa.dim.toInteger(); + if (sz != fargs.length - argi) + return nomatch(); + } + else if (TypeAArray taa = tb.isTypeAArray()) + { + Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t); + + size_t i = templateParameterLookup(taa.index, td.parameters); + if (i == IDX_NOTFOUND) + { + Expression e; + Type t; + Dsymbol s; + Scope *sco; + + uint errors = global.startGagging(); + /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 + * The parameter isn't part of the template + * ones, let's try to find it in the + * instantiation scope 'sc' and the one + * belonging to the template itself. */ + sco = sc; + taa.index.resolve(instLoc, sco, e, t, s); + if (!e) + { + sco = paramscope; + taa.index.resolve(instLoc, sco, e, t, s); + } + global.endGagging(errors); + + if (!e) + return nomatch(); + + e = e.ctfeInterpret(); + e = e.implicitCastTo(sco, Type.tsize_t); + e = e.optimize(WANTvalue); + if (!dim.equals(e)) + return nomatch(); + } + else + { + // This code matches code in TypeInstance.deduceType() + TemplateParameter tprm = (*td.parameters)[i]; + TemplateValueParameter tvp = tprm.isTemplateValueParameter(); + if (!tvp) + return nomatch(); + Expression e = cast(Expression)(*dedtypes)[i]; + if (e) + { + if (!dim.equals(e)) + return nomatch(); + } + else + { + Type vt = tvp.valType.typeSemantic(Loc.initial, sc); + MATCH m = dim.implicitConvTo(vt); + if (m == MATCH.nomatch) + return nomatch(); + (*dedtypes)[i] = dim; + } + } + } + goto case Tarray; + } + case Tarray: + { + TypeArray ta = cast(TypeArray)tb; + Type tret = fparam.isLazyArray(); + for (; argi < fargs.length; argi++) + { + Expression arg = fargs[argi]; + assert(arg); + + MATCH m; + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + if (tret) + { + if (ta.next.equals(arg.type)) + { + m = MATCH.exact; + } + else + { + m = arg.implicitConvTo(tret); + if (m == MATCH.nomatch) + { + if (tret.toBasetype().ty == Tvoid) + m = MATCH.convert; + } + } + } + else + { + uint wm = 0; + m = deduceType(arg, paramscope, ta.next, *td.parameters, *dedtypes, &wm, inferStart); + inoutMatch |= wm; + } + if (m == MATCH.nomatch) + return nomatch(); + if (m < match) + match = m; + } + goto Lmatch; + } + case Tclass: + case Tident: + goto Lmatch; + + default: + return nomatch(); + } + assert(0); + } + //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2); + if (argi != nfargs2 && fparameters.varargs == VarArg.none) + return nomatch(); + } + +Lmatch: + foreach (ref dedtype; *dedtypes) + { + if (Type at = isType(dedtype)) + { + if (at.ty == Tnone) + { + TypeDeduced xt = cast(TypeDeduced)at; + at = xt.tded; // 'unbox' + } + dedtype = at.merge2(); + } + } + for (size_t i = ntargs; i < dedargs.length; i++) + { + TemplateParameter tparam = (*td.parameters)[i]; + //printf("tparam[%d] = %s\n", i, tparam.ident.toChars()); + + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ + RootObject oarg = (*dedargs)[i]; + RootObject oded = (*dedtypes)[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); + //if (oarg) printf("oarg: %s\n", oarg.toChars()); + //if (oded) printf("oded: %s\n", oded.toChars()); + if (oarg) + continue; + + if (oded) + { + if (tparam.specialization() || !tparam.isTemplateTypeParameter()) + { + /* The specialization can work as long as afterwards + * the oded == oarg + */ + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + else + { + // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484 + if (MATCH.convert < matchTiargs) + matchTiargs = MATCH.convert; + } + } + else + { + oded = tparam.defaultArg(instLoc, paramscope); + if (!oded) + { + // if tuple parameter and + // tuple parameter was not in function parameter list and + // we're one or more arguments short (i.e. no tuple argument) + if (tparam == tp && + fptupindex == IDX_NOTFOUND && + ntargs <= dedargs.length - 1) + { + // make tuple argument an empty tuple + oded = new Tuple(); + } + else + return nomatch(); + } + if (isError(oded)) + return matcherror(); + ntargs++; + + /* At the template parameter T, the picked default template argument + * X!int should be matched to T in order to deduce dependent + * template parameter A. + * auto foo(T : X!A = X!int, A...)() { ... } + * foo(); // T <-- X!int, A <-- (int) + */ + if (tparam.specialization()) + { + (*dedargs)[i] = oded; + MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, td.parameters, *dedtypes, null); + //printf("m2 = %d\n", m2); + if (m2 == MATCH.nomatch) + return nomatch(); + if (m2 < matchTiargs) + matchTiargs = m2; // pick worst match + if (!(*dedtypes)[i].equals(oded)) + .error(td.loc, "%s `%s` specialization not allowed for deduced parameter `%s`", td.kind, td.toPrettyChars, tparam.ident.toChars()); + } + } + oded = td.declareParameter(paramscope, tparam, oded); + (*dedargs)[i] = oded; + } + + /* https://issues.dlang.org/show_bug.cgi?id=7469 + * As same as the code for 7469 in findBestMatch, + * expand a Tuple in dedargs to normalize template arguments. + */ + if (auto d = dedargs.length) + { + if (auto va = isTuple((*dedargs)[d - 1])) + { + dedargs.setDim(d - 1); + dedargs.insert(d - 1, &va.objects); + } + } + ti.tiargs = dedargs; // update to the normalized template arguments. + + // Partially instantiate function for constraint and fd.leastAsSpecialized() + { + assert(paramscope.scopesym); + Scope* sc2 = td._scope; + sc2 = sc2.push(paramscope.scopesym); + sc2 = sc2.push(ti); + sc2.parent = ti; + sc2.tinst = ti; + sc2.minst = sc.minst; + sc2.stc |= fd.storage_class & STC.deprecated_; + + fd = td.doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments); + sc2 = sc2.pop(); + sc2 = sc2.pop(); + + if (!fd) + return nomatch(); + } + + if (td.constraint) + { + if (!evaluateConstraint(td, ti, sc, paramscope, dedargs, fd)) + return nomatch(); + } + + version (none) + { + for (size_t i = 0; i < dedargs.length; i++) + { + RootObject o = (*dedargs)[i]; + printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars()); + } + } + + paramscope.pop(); + //printf("\tmatch %d\n", match); + return MATCHpair(matchTiargs, match); +} diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 589bc2b53cd..da4a3ee209e 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -124,6 +124,7 @@ enum TOK : ubyte // Leaf operators identifier, string_, + interpolated, hexadecimalString, this_, super_, @@ -380,6 +381,7 @@ enum EXP : ubyte // Leaf operators identifier, string_, + interpolated, this_, super_, halt, @@ -623,6 +625,10 @@ static immutable TOK[TOK.max + 1] Ckeywords = } } (); +struct InterpolatedSet { + // all strings in the parts are zero terminated at length+1 + string[] parts; +} /*********************************************************** */ @@ -645,7 +651,11 @@ extern (C++) struct Token struct { - const(char)* ustring; // UTF8 string + union + { + const(char)* ustring; // UTF8 string + InterpolatedSet* interpolatedSet; + } uint len; ubyte postfix; // 'c', 'w', 'd' } @@ -833,6 +843,7 @@ extern (C++) struct Token // For debugging TOK.error: "error", TOK.string_: "string", + TOK.interpolated: "interpolated string", TOK.onScopeExit: "scope(exit)", TOK.onScopeSuccess: "scope(success)", TOK.onScopeFailure: "scope(failure)", @@ -910,6 +921,24 @@ nothrow: return 0; } + extern(D) void appendInterpolatedPart(const ref OutBuffer buf) { + appendInterpolatedPart(cast(const(char)*)buf[].ptr, buf.length); + } + extern(D) void appendInterpolatedPart(const(char)[] str) { + appendInterpolatedPart(str.ptr, str.length); + } + extern(D) void appendInterpolatedPart(const(char)* ptr, size_t length) { + assert(value == TOK.interpolated); + if (interpolatedSet is null) + interpolatedSet = new InterpolatedSet; + + auto s = cast(char*)mem.xmalloc_noscan(length + 1); + memcpy(s, ptr, length); + s[length] = 0; + + interpolatedSet.parts ~= cast(string) s[0 .. length]; + } + /**** * Set to contents of ptr[0..length] * Params: @@ -918,6 +947,7 @@ nothrow: */ void setString(const(char)* ptr, size_t length) { + value = TOK.string_; auto s = cast(char*)mem.xmalloc_noscan(length + 1); memcpy(s, ptr, length); s[length] = 0; @@ -941,6 +971,7 @@ nothrow: */ void setString() { + value = TOK.string_; ustring = ""; len = 0; postfix = 0; diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index f944663e430..ef91001a996 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -133,6 +133,7 @@ enum class TOK : unsigned char // Leaf operators identifier, string_, + interpolated, hexadecimalString, this_, super_, @@ -390,6 +391,7 @@ enum class EXP : unsigned char // Leaf operators identifier, string_, + interpolated, this_, super_, halt, @@ -461,7 +463,12 @@ struct Token real_t floatvalue; struct - { utf8_t *ustring; // UTF8 string + { + union + { + utf8_t *ustring; // UTF8 string + void *interpolatedSet; + }; unsigned len; unsigned char postfix; // 'c', 'w', 'd' }; diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index c67ee816d2c..be7aa9923c0 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -36,6 +36,7 @@ import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -1306,7 +1307,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) // attribute inference. if (fd && fd.parent && fd.parent.isTemplateInstance) { - fd.functionSemantic3(); + functionSemantic3(fd); tf = fd.type.isTypeFunction(); } diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 714af8a0568..6721fa6544a 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -35,6 +35,7 @@ import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; +import dmd.enumsem; import dmd.errors; import dmd.errorsink; import dmd.expression; @@ -2919,6 +2920,29 @@ extern (C++) Type merge(Type type) return type; } +/************************************* + * This version does a merge even if the deco is already computed. + * Necessary for types that have a deco, but are not merged. + */ +extern(C++) Type merge2(Type type) +{ + //printf("merge2(%s)\n", toChars()); + Type t = type; + assert(t); + if (!t.deco) + return t.merge(); + + auto sv = Type.stringtable.lookup(t.deco, strlen(t.deco)); + if (sv && sv.value) + { + t = sv.value; + assert(t.deco); + } + else + assert(0); + return t; +} + /*************************************** * Calculate built-in properties which just the type is necessary. * @@ -5697,7 +5721,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) * Returns: * An enum value of either `Covariant.yes` or a reason it's not covariant. */ -extern (C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false) +extern(C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false) { version (none) { diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d index 9e062bd631d..6ae6df0e9b5 100644 --- a/gcc/d/dmd/typinf.d +++ b/gcc/d/dmd/typinf.d @@ -65,6 +65,7 @@ extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope fatal(); } + import dmd.typesem : merge2; Type t = torig.merge2(); // do this since not all Type's are merge'd bool needsCodegen = false; if (!t.vtinfo) diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h index 7fa08cb0e8b..6e3d3151888 100644 --- a/gcc/d/dmd/visitor.h +++ b/gcc/d/dmd/visitor.h @@ -195,6 +195,7 @@ class ThisExp; class SuperExp; class NullExp; class StringExp; +class InterpExp; class TupleExp; class ArrayLiteralExp; class AssocArrayLiteralExp; @@ -480,6 +481,7 @@ public: virtual void visit(TypeidExp *e) { visit((Expression *)e); } virtual void visit(TraitsExp *e) { visit((Expression *)e); } virtual void visit(StringExp *e) { visit((Expression *)e); } + virtual void visit(InterpExp *e) { visit((Expression *)e); } virtual void visit(NewExp *e) { visit((Expression *)e); } virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); } virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); } diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 6f596c5ac20..0a85a55b397 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -2495,17 +2495,18 @@ public: for (size_t i = 0; i < e->len; i++) { - tree value = build_integer_cst (e->getCodeUnit (i), etype); + tree value = build_integer_cst (e->getIndex (i), etype); CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value); } tree ctor = build_constructor (type, elms); TREE_CONSTANT (ctor) = 1; this->result_ = ctor; + return; } else { - /* Copy the string contents to a null terminated string. */ + /* Copy the string contents to a null terminated STRING_CST. */ dinteger_t length = (e->len * e->sz); char *string = XALLOCAVEC (char, length + e->sz); memset (string, 0, length + e->sz); @@ -2514,7 +2515,18 @@ public: /* String value and type includes the null terminator. */ tree value = build_string (length + e->sz, string); - TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1); + if (e->sz <= 4) + TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1); + else + { + /* Hexadecimal literal strings with an 8-byte character type are + just an alternative way to store an array of `ulong'. + Treat it as if it were a `uint[]' array instead. */ + dinteger_t resize = e->sz / 4; + TREE_TYPE (value) = make_array_type (Type::tuns32, + (length * resize) + resize); + } + value = build_address (value); if (tb->ty == TY::Tarray) diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index dfab0e651b9..1600ca92bd4 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -259,8 +259,9 @@ create_tinfo_types (Module *mod) array_type_node, array_type_node, array_type_node, array_type_node, ptr_type_node, ptr_type_node, ptr_type_node, d_uint_type, ptr_type_node, - array_type_node, ptr_type_node, d_ulong_type, - d_ulong_type, ptr_type_node, NULL); + array_type_node, ptr_type_node, ptr_type_node, + d_uint_type, d_uint_type, d_uint_type, d_uint_type, + NULL); object_module = mod; } @@ -577,7 +578,7 @@ public: void visit (TypeInfoConstDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + tm = merge2 (tm); /* The vtable for TypeInfo_Const. */ this->layout_base (Type::typeinfoconst); @@ -594,7 +595,7 @@ public: void visit (TypeInfoInvariantDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + tm = merge2 (tm); /* The vtable for TypeInfo_Invariant. */ this->layout_base (Type::typeinfoinvariant); @@ -611,7 +612,7 @@ public: void visit (TypeInfoSharedDeclaration *d) final override { Type *tm = d->tinfo->unSharedOf (); - tm = tm->merge2 (); + tm = merge2 (tm); /* The vtable for TypeInfo_Shared. */ this->layout_base (Type::typeinfoshared); @@ -628,7 +629,7 @@ public: void visit (TypeInfoWildDeclaration *d) final override { Type *tm = d->tinfo->mutableOf (); - tm = tm->merge2 (); + tm = merge2 (tm); /* The vtable for TypeInfo_Inout. */ this->layout_base (Type::typeinfowild); @@ -934,10 +935,6 @@ public: else this->layout_field (null_pointer_node); - /* ulong[2] nameSig; */ - this->layout_field (build_zero_cst (d_ulong_type)); - this->layout_field (build_zero_cst (d_ulong_type)); - /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); @@ -945,6 +942,12 @@ public: this->layout_field (size_one_node); else this->layout_field (null_pointer_node); + + /* uint[4] nameSig; */ + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); } else { @@ -985,15 +988,17 @@ public: this->layout_field (null_array_node); this->layout_field (null_pointer_node); - /* ulong[2] nameSig; */ - this->layout_field (build_zero_cst (d_ulong_type)); - this->layout_field (build_zero_cst (d_ulong_type)); - /* immutable(void)* m_RTInfo; */ if (cd->getRTInfo) this->layout_field (build_expr (cd->getRTInfo, true)); else this->layout_field (null_pointer_node); + + /* uint[4] nameSig; */ + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); + this->layout_field (build_zero_cst (d_uint_type)); } /* Put out array of Interfaces. */ @@ -1546,7 +1551,7 @@ create_typeinfo (Type *type, Module *mod, bool generate) create_frontend_tinfo_types (); /* Do this since not all Type's are merged. */ - Type *t = type->merge2 (); + Type *t = merge2 (type); Identifier *ident; if (!t->vtinfo) diff --git a/gcc/testsuite/gdc.test/compilable/test13281.d b/gcc/testsuite/gdc.test/compilable/test13281.d index 0d747faf3fd..ab92fcc02a0 100644 --- a/gcc/testsuite/gdc.test/compilable/test13281.d +++ b/gcc/testsuite/gdc.test/compilable/test13281.d @@ -36,12 +36,27 @@ static assert((123 ).stringof == "123"); static assert((123u ).stringof == "123u"); static assert((123L ).stringof == "123L"); static assert((123uL).stringof == "123LU"); -static assert((123.5 ).stringof == "1.235e+2"); -static assert((123.5f ).stringof == "1.235e+2F"); -static assert((123.5L ).stringof == "1.235e+2L"); -static assert((123.5i ).stringof == "1.235e+2i"); -static assert((123.5fi).stringof == "1.235e+2Fi"); -static assert((123.5Li).stringof == "1.235e+2Li"); -static assert((123.5 +5.5i ).stringof == "1.235e+2 + 5.5e+0i"); -static assert((123.5f+5.5fi).stringof == "1.235e+2F + 5.5e+0Fi"); -static assert((123.5L+5.5Li).stringof == "1.235e+2L + 5.5e+0Li"); +version (GNU) +{ + static assert((123.5 ).stringof == "1.235e+2"); + static assert((123.5f ).stringof == "1.235e+2F"); + static assert((123.5L ).stringof == "1.235e+2L"); + static assert((123.5i ).stringof == "1.235e+2i"); + static assert((123.5fi).stringof == "1.235e+2Fi"); + static assert((123.5Li).stringof == "1.235e+2Li"); + static assert((123.5 +5.5i ).stringof == "1.235e+2 + 5.5e+0i"); + static assert((123.5f+5.5fi).stringof == "1.235e+2F + 5.5e+0Fi"); + static assert((123.5L+5.5Li).stringof == "1.235e+2L + 5.5e+0Li"); +} +else +{ + static assert((123.5 ).stringof == "123.5"); + static assert((123.5f ).stringof == "123.5F"); + static assert((123.5L ).stringof == "123.5L"); + static assert((123.5i ).stringof == "123.5i"); + static assert((123.5fi).stringof == "123.5Fi"); + static assert((123.5Li).stringof == "123.5Li"); + static assert((123.5 +5.5i ).stringof == "123.5 + 5.5i"); + static assert((123.5f+5.5fi).stringof == "123.5F + 5.5Fi"); + static assert((123.5L+5.5Li).stringof == "123.5L + 5.5Li"); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19523.d b/gcc/testsuite/gdc.test/fail_compilation/b19523.d index 36266669a32..d2a05c73dc1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b19523.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b19523.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/b19523.d(12): Error: undefined identifier `SomeStruct` -fail_compilation/b19523.d(13): Error: function `b19523.foo(int delegate() arg)` is not callable using argument types `(_error_)` -fail_compilation/b19523.d(13): cannot pass argument `__lambda2` of type `_error_` to parameter `int delegate() arg` ---- +---- +fail_compilation/b19523.d(13): Error: undefined identifier `SomeStruct` +fail_compilation/b19523.d(14): Error: function `foo` is not callable using argument types `(_error_)` +fail_compilation/b19523.d(14): cannot pass argument `__lambda2` of type `_error_` to parameter `int delegate() arg` +fail_compilation/b19523.d(19): `b19523.foo(int delegate() arg)` declared here +---- */ module b19523; diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20011.d b/gcc/testsuite/gdc.test/fail_compilation/b20011.d index 3ddcdaaf76b..50ef6aff609 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b20011.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b20011.d @@ -1,16 +1,19 @@ /* TEST_OUTPUT: --- -fail_compilation/b20011.d(25): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue -fail_compilation/b20011.d(28): Error: cannot modify expression `S2(null).member` because it is not an lvalue -fail_compilation/b20011.d(29): Error: cannot modify expression `S2(null).member` because it is not an lvalue -fail_compilation/b20011.d(32): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue -fail_compilation/b20011.d(37): Error: function `b20011.main.assignableByRef(ref ubyte p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(37): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p` -fail_compilation/b20011.d(38): Error: function `b20011.main.assignableByOut(out ubyte p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(38): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `out ubyte p` -fail_compilation/b20011.d(39): Error: function `b20011.main.assignableByConstRef(ref const(ubyte) p)` is not callable using argument types `(ubyte)` -fail_compilation/b20011.d(39): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref const(ubyte) p` +fail_compilation/b20011.d(28): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue +fail_compilation/b20011.d(31): Error: cannot modify expression `S2(null).member` because it is not an lvalue +fail_compilation/b20011.d(32): Error: cannot modify expression `S2(null).member` because it is not an lvalue +fail_compilation/b20011.d(35): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue +fail_compilation/b20011.d(40): Error: function `assignableByRef` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(40): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p` +fail_compilation/b20011.d(37): `b20011.main.assignableByRef(ref ubyte p)` declared here +fail_compilation/b20011.d(41): Error: function `assignableByOut` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(41): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `out ubyte p` +fail_compilation/b20011.d(38): `b20011.main.assignableByOut(out ubyte p)` declared here +fail_compilation/b20011.d(42): Error: function `assignableByConstRef` is not callable using argument types `(ubyte)` +fail_compilation/b20011.d(42): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref const(ubyte) p` +fail_compilation/b20011.d(39): `b20011.main.assignableByConstRef(ref const(ubyte) p)` declared here --- */ module b20011; diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug15613.d b/gcc/testsuite/gdc.test/fail_compilation/bug15613.d dissimilarity index 63% index 5b16f72ca23..ac167f3f8e9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug15613.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug15613.d @@ -1,33 +1,36 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/bug15613.d(16): Error: function `bug15613.f(int...)` is not callable using argument types `(typeof(null))` -fail_compilation/bug15613.d(16): cannot pass argument `null` of type `typeof(null)` to parameter `int...` -fail_compilation/bug15613.d(17): Error: function `bug15613.g(Object, ...)` is not callable using argument types `(int)` -fail_compilation/bug15613.d(17): cannot pass argument `8` of type `int` to parameter `Object` ---- -*/ - -void f(int...); -void g(Object, ...); - -void main() -{ - f(null); - g(8); -} - -/* -TEST_OUTPUT: ---- -fail_compilation/bug15613.d(32): Error: function `bug15613.h(int[]...)` is not callable using argument types `(int, void function(int[]...))` -fail_compilation/bug15613.d(32): cannot pass argument `& h` of type `void function(int[]...)` to parameter `int[]...` ---- -*/ - -void h(int[]...); - -void test() -{ - h(7, &h); -} +/* +TEST_OUTPUT: +--- +fail_compilation/bug15613.d(18): Error: function `f` is not callable using argument types `(typeof(null))` +fail_compilation/bug15613.d(18): cannot pass argument `null` of type `typeof(null)` to parameter `int...` +fail_compilation/bug15613.d(13): `bug15613.f(int...)` declared here +fail_compilation/bug15613.d(19): Error: function `g` is not callable using argument types `(int)` +fail_compilation/bug15613.d(19): cannot pass argument `8` of type `int` to parameter `Object` +fail_compilation/bug15613.d(14): `bug15613.g(Object, ...)` declared here +--- +*/ + +void f(int...); +void g(Object, ...); + +void main() +{ + f(null); + g(8); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/bug15613.d(35): Error: function `h` is not callable using argument types `(int, void function(int[]...))` +fail_compilation/bug15613.d(35): cannot pass argument `& h` of type `void function(int[]...)` to parameter `int[]...` +fail_compilation/bug15613.d(31): `bug15613.h(int[]...)` declared here +--- +*/ + +void h(int[]...); + +void test() +{ + h(7, &h); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d index ca9879733ce..608e3478515 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d @@ -10,9 +10,11 @@ void g() /* TEST_OUTPUT: --- -fail_compilation/bug16165.d(6): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(Object, Object, int)` +fail_compilation/bug16165.d(6): Error: function `f` is not callable using argument types `(Object, Object, int)` fail_compilation/bug16165.d(6): cannot pass argument `o` of type `object.Object` to parameter `int x` -fail_compilation/bug16165.d(7): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(int, int, int)` +fail_compilation/bug16165.d(1): `bug16165.f(int x, Object y)` declared here +fail_compilation/bug16165.d(7): Error: function `f` is not callable using argument types `(int, int, int)` fail_compilation/bug16165.d(7): cannot pass argument `6` of type `int` to parameter `Object y` +fail_compilation/bug16165.d(1): `bug16165.f(int x, Object y)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d index f0a9456035b..13974aa0e9a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d @@ -62,12 +62,13 @@ void test3() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is not callable using argument types `(int, S)` -fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` -fail_compilation/bug9631.d(80): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s` -fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0` +fail_compilation/bug9631.d(80): Error: function `f` is not callable using argument types `(int, S)` +fail_compilation/bug9631.d(80): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` +fail_compilation/bug9631.d(79): `bug9631.arg.f(int i, S s)` declared here +fail_compilation/bug9631.d(81): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(81): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s` +fail_compilation/bug9631.d(87): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(87): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0` --- */ void arg() @@ -89,12 +90,13 @@ void arg() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S __param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0` -fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` is not callable using argument types `!()(S)` -fail_compilation/bug9631.d(105): Candidate is: `ft()(tem!().S)` -fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` is not callable using argument types `!()(S, int)` -fail_compilation/bug9631.d(108): Candidate is: `ft2(T)(S, T)` +fail_compilation/bug9631.d(108): Error: function `ft` is not callable using argument types `(S)` +fail_compilation/bug9631.d(108): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0` +fail_compilation/bug9631.d(107): `bug9631.targ.ft!().ft(S __param_0)` declared here +fail_compilation/bug9631.d(109): Error: template `ft` is not callable using argument types `!()(S)` +fail_compilation/bug9631.d(107): Candidate is: `ft()(tem!().S)` +fail_compilation/bug9631.d(111): Error: template `ft2` is not callable using argument types `!()(S, int)` +fail_compilation/bug9631.d(110): Candidate is: `ft2(T)(S, T)` --- */ void targ() diff --git a/gcc/testsuite/gdc.test/fail_compilation/callconst.d b/gcc/testsuite/gdc.test/fail_compilation/callconst.d index 74c1902b2d4..a3aee7c6b59 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/callconst.d +++ b/gcc/testsuite/gdc.test/fail_compilation/callconst.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/callconst.d(13): Error: function `callconst.func(ref X)` is not callable using argument types `(const(X))` -fail_compilation/callconst.d(13): cannot pass argument `x` of type `const(X)` to parameter `ref X` +fail_compilation/callconst.d(14): Error: function `func` is not callable using argument types `(const(X))` +fail_compilation/callconst.d(14): cannot pass argument `x` of type `const(X)` to parameter `ref X` +fail_compilation/callconst.d(17): `callconst.func(ref X)` declared here --- */ struct X {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d index a3ad34a0ea3..4c31e9e729b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d @@ -2,12 +2,12 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_aggr.d(32): Error: template `imports.constraints.C.f` is not callable using argument types `!()(int)` +fail_compilation/constraints_aggr.d(32): Error: template `f` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(60): Candidate is: `f(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_aggr.d(33): Error: template `imports.constraints.C.g` is not callable using argument types `!()()` +fail_compilation/constraints_aggr.d(33): Error: template `g` is not callable using argument types `!()()` fail_compilation/imports/constraints.d(63): Candidate is: `g(this T)()` with `T = imports.constraints.C` must satisfy the following constraint: diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d index fbb4aa94d53..d15d2817df0 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d @@ -2,72 +2,72 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_func1.d(79): Error: template `imports.constraints.test1` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(79): Error: template `test1` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(80): Error: template `imports.constraints.test2` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(80): Error: template `test2` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(10): Candidate is: `test2(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(81): Error: template `imports.constraints.test3` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(81): Error: template `test3` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(11): Candidate is: `test3(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(82): Error: template `imports.constraints.test4` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(82): Error: template `test4` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(12): Candidate is: `test4(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(83): Error: template `imports.constraints.test5` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(83): Error: template `test5` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(13): Candidate is: `test5(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func1.d(84): Error: template `imports.constraints.test6` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(84): Error: template `test6` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(14): Candidate is: `test6(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T !P!T` -fail_compilation/constraints_func1.d(85): Error: template `imports.constraints.test7` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(85): Error: template `test7` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(15): Candidate is: `test7(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func1.d(86): Error: template `imports.constraints.test8` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(86): Error: template `test8` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(16): Candidate is: `test8(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func1.d(87): Error: template `imports.constraints.test9` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(87): Error: template `test9` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(17): Candidate is: `test9(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(88): Error: template `imports.constraints.test10` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(88): Error: template `test10` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(18): Candidate is: `test10(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(89): Error: template `imports.constraints.test11` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(89): Error: template `test11` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(19): Candidate is: `test11(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T` -fail_compilation/constraints_func1.d(90): Error: template `imports.constraints.test12` is not callable using argument types `!()(int)` +fail_compilation/constraints_func1.d(90): Error: template `test12` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(20): Candidate is: `test12(T)(T v)` with `T = int` must satisfy the following constraint: ` !P!T` -fail_compilation/constraints_func1.d(92): Error: template `imports.constraints.test1` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func1.d(92): Error: template `test1` is not callable using argument types `!()(int, int)` fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d index 4b8ebd5da2b..36fa55423d5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d @@ -2,83 +2,83 @@ EXTRA_FILES: imports/constraints.d TEST_OUTPUT: --- -fail_compilation/constraints_func2.d(94): Error: template `imports.constraints.test13` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(94): Error: template `test13` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(23): Candidate is: `test13(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T` -fail_compilation/constraints_func2.d(95): Error: template `imports.constraints.test14` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(95): Error: template `test14` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(24): Candidate is: `test14(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T N!T` -fail_compilation/constraints_func2.d(96): Error: template `imports.constraints.test15` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(96): Error: template `test15` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(25): Candidate is: `test15(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T !P!T` -fail_compilation/constraints_func2.d(97): Error: template `imports.constraints.test16` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(97): Error: template `test16` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(26): Candidate is: `test16(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(98): Error: template `imports.constraints.test17` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(98): Error: template `test17` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(27): Candidate is: `test17(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(99): Error: template `imports.constraints.test18` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(99): Error: template `test18` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(28): Candidate is: `test18(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(100): Error: template `imports.constraints.test19` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(100): Error: template `test19` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(29): Candidate is: `test19(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T !P!T N!T` -fail_compilation/constraints_func2.d(101): Error: template `imports.constraints.test20` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(101): Error: template `test20` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(30): Candidate is: `test20(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(102): Error: template `imports.constraints.test21` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(102): Error: template `test21` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(31): Candidate is: `test21(T)(T v)` with `T = int` must satisfy one of the following constraints: ` N!T N!T` -fail_compilation/constraints_func2.d(103): Error: template `imports.constraints.test22` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(103): Error: template `test22` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(32): Candidate is: `test22(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T !P!T` -fail_compilation/constraints_func2.d(104): Error: template `imports.constraints.test23` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(104): Error: template `test23` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(33): Candidate is: `test23(T)(T v)` with `T = int` must satisfy one of the following constraints: ` !P!T N!T !P!T` -fail_compilation/constraints_func2.d(105): Error: template `imports.constraints.test24` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(105): Error: template `test24` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(34): Candidate is: `test24(R)(R r)` with `R = int` must satisfy the following constraint: ` __traits(hasMember, R, "stuff")` -fail_compilation/constraints_func2.d(106): Error: template `imports.constraints.test25` is not callable using argument types `!()(int)` +fail_compilation/constraints_func2.d(106): Error: template `test25` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(35): Candidate is: `test25(T)(T v)` with `T = int` must satisfy the following constraint: ` N!T` -fail_compilation/constraints_func2.d(107): Error: template `imports.constraints.test26` is not callable using argument types `!(float)(int)` +fail_compilation/constraints_func2.d(107): Error: template `test26` is not callable using argument types `!(float)(int)` fail_compilation/imports/constraints.d(36): Candidate is: `test26(T, U)(U u)` with `T = float, U = int` diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d index d16bdf0959c..b4bc3fe0279 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d @@ -1,7 +1,7 @@ /* EXTRA_FILES: imports/constraints.d TEST_OUTPUT: ---- +---- fail_compilation/constraints_func3.d(53): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int)` fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)` with `T = int` @@ -23,27 +23,27 @@ fail_compilation/imports/constraints.d(42): `overload(T, must satisfy one of the following constraints: ` N!T N!V` -fail_compilation/constraints_func3.d(56): Error: template `imports.constraints.variadic` is not callable using argument types `!()()` +fail_compilation/constraints_func3.d(56): Error: template `variadic` is not callable using argument types `!()()` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` -fail_compilation/constraints_func3.d(57): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int)` +fail_compilation/constraints_func3.d(57): Error: template `variadic` is not callable using argument types `!()(int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = ()` must satisfy the following constraint: ` N!int` -fail_compilation/constraints_func3.d(58): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func3.d(58): Error: template `variadic` is not callable using argument types `!()(int, int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = (int)` must satisfy the following constraint: ` N!int` -fail_compilation/constraints_func3.d(59): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int, int)` +fail_compilation/constraints_func3.d(59): Error: template `variadic` is not callable using argument types `!()(int, int, int)` fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` with `A = int, T = (int, int)` must satisfy the following constraint: ` N!int` ---- +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d index c4dea0ec451..536a3d46a5a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d +++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d @@ -2,7 +2,7 @@ EXTRA_FILES: imports/constraints.d REQUIRED_ARGS: -verrors=context TEST_OUTPUT: ---- +---- fail_compilation/constraints_func4.d(90): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int)` overload(0); ^ @@ -44,13 +44,13 @@ fail_compilation/imports/constraints.d(42): `overload(T, N!V` void overload(T, V)(T v1, V v2) if (N!T || N!V); ^ -fail_compilation/constraints_func4.d(93): Error: template `imports.constraints.variadic` is not callable using argument types `!()()` +fail_compilation/constraints_func4.d(93): Error: template `variadic` is not callable using argument types `!()()` variadic(); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(94): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int)` +fail_compilation/constraints_func4.d(94): Error: template `variadic` is not callable using argument types `!()(int)` variadic(0); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -60,7 +60,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(95): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int)` +fail_compilation/constraints_func4.d(95): Error: template `variadic` is not callable using argument types `!()(int, int)` variadic(0, 1); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -70,7 +70,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ -fail_compilation/constraints_func4.d(96): Error: template `imports.constraints.variadic` is not callable using argument types `!()(int, int, int)` +fail_compilation/constraints_func4.d(96): Error: template `variadic` is not callable using argument types `!()(int, int, int)` variadic(0, 1, 2); ^ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)` @@ -80,7 +80,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T. ` N!int` void variadic(A, T...)(A a, T v) if (N!int); ^ ---- +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d index 25e0515a5bc..9248e094c15 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/diag13942.d(18): Error: template instance `isRawStaticArray!()` does not match template declaration `isRawStaticArray(T, A...)` -fail_compilation/diag13942.d(26): Error: template `diag13942.to!double.to` is not callable using argument types `!()()` +fail_compilation/diag13942.d(26): Error: template `to` is not callable using argument types `!()()` fail_compilation/diag13942.d(17): Candidate is: `to(A...)(A args)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d index fc8f66032e2..7e2efd2bfa2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag16977.d(25): Error: undefined identifier `undefined`, did you mean function `undefinedId`? fail_compilation/diag16977.d(26): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int` -fail_compilation/diag16977.d(27): Error: template `diag16977.templ` is not callable using argument types `!()(int)` +fail_compilation/diag16977.d(27): Error: template `templ` is not callable using argument types `!()(int)` fail_compilation/diag16977.d(20): Candidate is: `templ(S)(S s)` with `S = int` must satisfy the following constraint: diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d index 053626a603c..06534902670 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag20268.d(12): Error: template `diag20268.__lambda4` is not callable using argument types `!()(int)` +fail_compilation/diag20268.d(12): Error: template `__lambda4` is not callable using argument types `!()(int)` fail_compilation/diag20268.d(11): Candidate is: `__lambda4(__T1, __T2)(x, y)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag23355.d b/gcc/testsuite/gdc.test/fail_compilation/diag23355.d index a530eb60ef0..c21226fa85e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag23355.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag23355.d @@ -2,10 +2,10 @@ TEST_OUTPUT: --- fail_compilation/diag23355.d(1): Error: undefined identifier `n` -fail_compilation/diag23355.d(4): Error: template `diag23355.ffi1` is not callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(4): Error: template `ffi1` is not callable using argument types `!()(int[4])` fail_compilation/diag23355.d(1): Candidate is: `ffi1(T)(T[n] s)` fail_compilation/diag23355.d(2): Error: undefined identifier `n` -fail_compilation/diag23355.d(4): Error: template `diag23355.ffi2` is not callable using argument types `!()(int[4])` +fail_compilation/diag23355.d(4): Error: template `ffi2` is not callable using argument types `!()(int[4])` fail_compilation/diag23355.d(2): Candidate is: `ffi2()(T[n] s)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d index 4c8dfe881ab..0d196205640 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d @@ -1,32 +1,33 @@ /* TEST_OUTPUT: --- -fail_compilation/diag8101.d(61): Error: function `diag8101.f_0(int)` is not callable using argument types `()` -fail_compilation/diag8101.d(61): too few arguments, expected 1, got 0 -fail_compilation/diag8101.d(62): Error: none of the overloads of `f_1` are callable using argument types `()` -fail_compilation/diag8101.d(35): Candidates are: `diag8101.f_1(int)` -fail_compilation/diag8101.d(36): `diag8101.f_1(int, int)` -fail_compilation/diag8101.d(63): Error: none of the overloads of `f_2` are callable using argument types `()` -fail_compilation/diag8101.d(38): Candidates are: `diag8101.f_2(int)` -fail_compilation/diag8101.d(39): `diag8101.f_2(int, int)` -fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int)` -fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, int, int)` -fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int, int)` -fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int, int)` -fail_compilation/diag8101.d(63): ... (1 more, -v to show) ... -fail_compilation/diag8101.d(65): Error: template `diag8101.t_0` is not callable using argument types `!()()` -fail_compilation/diag8101.d(46): Candidate is: `t_0(T1)()` -fail_compilation/diag8101.d(66): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` -fail_compilation/diag8101.d(48): Candidates are: `t_1(T1)()` -fail_compilation/diag8101.d(49): `t_1(T1, T2)()` -fail_compilation/diag8101.d(67): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()` -fail_compilation/diag8101.d(51): Candidates are: `t_2(T1)()` -fail_compilation/diag8101.d(52): `t_2(T1, T2)()` -fail_compilation/diag8101.d(53): `t_2(T1, T2, T3)()` -fail_compilation/diag8101.d(54): `t_2(T1, T2, T3, T4)()` -fail_compilation/diag8101.d(55): `t_2(T1, T2, T3, T4, T5)()` -fail_compilation/diag8101.d(56): `t_2(T1, T2, T3, T4, T5, T6)()` -fail_compilation/diag8101.d(67): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(62): Error: function `f_0` is not callable using argument types `()` +fail_compilation/diag8101.d(62): too few arguments, expected 1, got 0 +fail_compilation/diag8101.d(34): `diag8101.f_0(int)` declared here +fail_compilation/diag8101.d(63): Error: none of the overloads of `f_1` are callable using argument types `()` +fail_compilation/diag8101.d(36): Candidates are: `diag8101.f_1(int)` +fail_compilation/diag8101.d(37): `diag8101.f_1(int, int)` +fail_compilation/diag8101.d(64): Error: none of the overloads of `f_2` are callable using argument types `()` +fail_compilation/diag8101.d(39): Candidates are: `diag8101.f_2(int)` +fail_compilation/diag8101.d(40): `diag8101.f_2(int, int)` +fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, int)` +fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int)` +fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int)` +fail_compilation/diag8101.d(44): `diag8101.f_2(int, int, int, int, int, int)` +fail_compilation/diag8101.d(64): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(66): Error: template `t_0` is not callable using argument types `!()()` +fail_compilation/diag8101.d(47): Candidate is: `t_0(T1)()` +fail_compilation/diag8101.d(67): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` +fail_compilation/diag8101.d(49): Candidates are: `t_1(T1)()` +fail_compilation/diag8101.d(50): `t_1(T1, T2)()` +fail_compilation/diag8101.d(68): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()` +fail_compilation/diag8101.d(52): Candidates are: `t_2(T1)()` +fail_compilation/diag8101.d(53): `t_2(T1, T2)()` +fail_compilation/diag8101.d(54): `t_2(T1, T2, T3)()` +fail_compilation/diag8101.d(55): `t_2(T1, T2, T3, T4)()` +fail_compilation/diag8101.d(56): `t_2(T1, T2, T3, T4, T5)()` +fail_compilation/diag8101.d(57): `t_2(T1, T2, T3, T4, T5, T6)()` +fail_compilation/diag8101.d(68): ... (1 more, -v to show) ... --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d index e48f569b74d..8066d6e8bbe 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d @@ -2,13 +2,13 @@ TEST_OUTPUT: --- fail_compilation/diag8648.d(18): Error: undefined identifier `X` -fail_compilation/diag8648.d(29): Error: template `diag8648.foo` is not callable using argument types `!()(Foo!(int, 1))` +fail_compilation/diag8648.d(29): Error: template `foo` is not callable using argument types `!()(Foo!(int, 1))` fail_compilation/diag8648.d(18): Candidate is: `foo(T, n)(X!(T, n))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` -fail_compilation/diag8648.d(31): Error: template `diag8648.bar` is not callable using argument types `!()(Foo!(int, 1))` +fail_compilation/diag8648.d(31): Error: template `bar` is not callable using argument types `!()(Foo!(int, 1))` fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))` fail_compilation/diag8648.d(20): Error: undefined identifier `a` -fail_compilation/diag8648.d(32): Error: template `diag8648.bar` is not callable using argument types `!()(Foo!(int, f))` +fail_compilation/diag8648.d(32): Error: template `bar` is not callable using argument types `!()(Foo!(int, f))` fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d index 30589bf0cac..4c63bb26d73 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9004.d(21): Error: template `diag9004.bar` is not callable using argument types `!()(Foo!int, int)` +fail_compilation/diag9004.d(21): Error: template `bar` is not callable using argument types `!()(Foo!int, int)` fail_compilation/diag9004.d(14): Candidate is: `bar(FooT)(FooT foo, FooT.T x)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diagin.d b/gcc/testsuite/gdc.test/fail_compilation/diagin.d index 5b8e33162cd..6e8a472cee6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diagin.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diagin.d @@ -2,10 +2,11 @@ REQUIRED_ARGS: -preview=in TEST_OUTPUT: --- -fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()` -fail_compilation/diagin.d(14): too few arguments, expected 1, got 0 -fail_compilation/diagin.d(16): Error: template `diagin.foo1` is not callable using argument types `!()(bool[])` -fail_compilation/diagin.d(20): Candidate is: `foo1(T)(in T v, string)` +fail_compilation/diagin.d(15): Error: function `foo` is not callable using argument types `()` +fail_compilation/diagin.d(15): too few arguments, expected 1, got 0 +fail_compilation/diagin.d(20): `diagin.foo(in int)` declared here +fail_compilation/diagin.d(17): Error: template `foo1` is not callable using argument types `!()(bool[])` +fail_compilation/diagin.d(21): Candidate is: `foo1(T)(in T v, string)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d index 711e57fad30..3b1ab723b9e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d @@ -14,10 +14,10 @@ fail_compilation/fail12744.d(61): Error: template instance `fail12744.bar12744L! fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes `lazy` and `out` fail_compilation/fail12744.d(62): Error: template instance `fail12744.bar12744L!(foo12744O)` error instantiating fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `out` -fail_compilation/fail12744.d(67): Error: template `fail12744.bar12744A` is not callable using argument types `!(foo12744O)(int)` +fail_compilation/fail12744.d(67): Error: template `bar12744A` is not callable using argument types `!(foo12744O)(int)` fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)` fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `lazy` -fail_compilation/fail12744.d(68): Error: template `fail12744.bar12744A` is not callable using argument types `!(foo12744L)(int)` +fail_compilation/fail12744.d(68): Error: template `bar12744A` is not callable using argument types `!(foo12744L)(int)` fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail136.d b/gcc/testsuite/gdc.test/fail_compilation/fail136.d index 3bc86537ed6..3fa42e6cc84 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail136.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail136.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation\fail136.d(10): Error: `"\xef\xbb\xbf"` has no effect +fail_compilation/fail136.d(10): Error: `x"EFBBBF"` has no effect --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d index 45fe1463551..2c2661f8ef5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d @@ -4,7 +4,7 @@ TEST_OUTPUT: fail_compilation/fail14669.d(11): Error: `auto` can only be used as part of `auto ref` for template function parameters fail_compilation/fail14669.d(16): Error: template instance `fail14669.foo1!()` error instantiating fail_compilation/fail14669.d(12): Error: `auto` can only be used as part of `auto ref` for template function parameters -fail_compilation/fail14669.d(17): Error: template `fail14669.foo2` is not callable using argument types `!()(int)` +fail_compilation/fail14669.d(17): Error: template `foo2` is not callable using argument types `!()(int)` fail_compilation/fail14669.d(12): Candidate is: `foo2()(auto int a)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail162.d b/gcc/testsuite/gdc.test/fail_compilation/fail162.d index c79f8d8d548..600e2c9d69c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail162.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail162.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail162.d(25): Error: template `fail162.testHelper` is not callable using argument types `!()(string, string)` +fail_compilation/fail162.d(25): Error: template `testHelper` is not callable using argument types `!()(string, string)` fail_compilation/fail162.d(10): Candidate is: `testHelper(A...)()` fail_compilation/fail162.d(30): Error: template instance `fail162.test!("hello", "world")` error instantiating --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d index ae67443fea4..9c23b78df92 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d @@ -3,8 +3,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail19948.d(15): Error: function `fail19948.func(const(X))` is not callable using argument types `(X)` -fail_compilation/fail19948.d(15): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)` +fail_compilation/fail19948.d(16): Error: function `func` is not callable using argument types `(X)` +fail_compilation/fail19948.d(16): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)` +fail_compilation/fail19948.d(19): `fail19948.func(const(X))` declared here --- */ // DISABLED: win32 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d index 8a08844f843..f04db024932 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d @@ -1,8 +1,9 @@ /* REQUIRED_ARGS: -preview=dip1000 TEST_OUTPUT: --- -fail_compilation/fail20183.d(1016): Error: function `fail20183.addr(return ref int b)` is not callable using argument types `(int)` +fail_compilation/fail20183.d(1016): Error: function `addr` is not callable using argument types `(int)` fail_compilation/fail20183.d(1016): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b` +fail_compilation/fail20183.d(1005): `fail20183.addr(return ref int b)` declared here fail_compilation/fail20183.d(1017): Error: address of struct temporary returned by `s()` assigned to longer lived variable `q` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d b/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d index d36bb0b6e89..7269f42514a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d @@ -3,7 +3,7 @@ REQUIRED_ARGS: -verrors=spec -o- TEST_OUTPUT: --- (spec:1) fail_compilation/fail20730b.d-mixin-43(43): Error: C style cast illegal, use `cast(int)mod` -fail_compilation/fail20730b.d(26): Error: template `fail20730b.atomicOp` is not callable using argument types `!("+=")(shared(uint), int)` +fail_compilation/fail20730b.d(26): Error: template `atomicOp` is not callable using argument types `!("+=")(shared(uint), int)` fail_compilation/fail20730b.d(41): Candidate is: `atomicOp(string op, T, V1)(shared ref T val, V1 mod)` with `op = "+=", T = uint, diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d index 026b7c2df0a..4464222f237 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d @@ -2,10 +2,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail20800.d(22): Error: function `fail20800.fun(int a)` is not callable using argument types `(string)` -fail_compilation/fail20800.d(22): cannot pass argument `(m()).index()` of type `string` to parameter `int a` ---- +---- +fail_compilation/fail20800.d(23): Error: function `fun` is not callable using argument types `(string)` +fail_compilation/fail20800.d(23): cannot pass argument `(m()).index()` of type `string` to parameter `int a` +fail_compilation/fail20800.d(19): `fail20800.fun(int a)` declared here +---- */ struct RegexMatch diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d index d865fd95553..9fb5165a711 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d @@ -3,8 +3,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy __param_0)` is not callable using argument types `(SystemCopy)` -fail_compilation/fail22202.d(21): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context +fail_compilation/fail22202.d(22): Error: function `fun` is not callable using argument types `(SystemCopy)` +fail_compilation/fail22202.d(22): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context +fail_compilation/fail22202.d(17): `fail22202.fun(SystemCopy __param_0)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail236.d b/gcc/testsuite/gdc.test/fail_compilation/fail236.d index accc0e17dd2..96f0ae65518 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail236.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail236.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail236.d(14): Error: undefined identifier `x` -fail_compilation/fail236.d(22): Error: template `fail236.Templ2` is not callable using argument types `!()(int)` +fail_compilation/fail236.d(22): Error: template `Templ2` is not callable using argument types `!()(int)` fail_compilation/fail236.d(12): Candidate is: `Templ2(alias a)(x)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24301.d b/gcc/testsuite/gdc.test/fail_compilation/fail24301.d index be09c883e1c..6ddece6c341 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail24301.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail24301.d @@ -1,8 +1,9 @@ /+ TEST_OUTPUT: --- -fail_compilation/fail24301.d(18): Error: function `fail24301.fun(S __param_0)` is not callable using argument types `(S)` -fail_compilation/fail24301.d(18): `ref S(ref S)` copy constructor cannot be used because it is annotated with `@disable` +fail_compilation/fail24301.d(19): Error: function `fun` is not callable using argument types `(S)` +fail_compilation/fail24301.d(19): `ref S(ref S)` copy constructor cannot be used because it is annotated with `@disable` +fail_compilation/fail24301.d(14): `fail24301.fun(S __param_0)` declared here --- +/ struct S diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail263.d b/gcc/testsuite/gdc.test/fail_compilation/fail263.d index 0fa2f86a14a..e57fc50a1a3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail263.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail263.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail263.d(19): Error: function `fail263.f(byte* p)` is not callable using argument types `(const(byte)*)` -fail_compilation/fail263.d(19): cannot pass argument `cast(const(byte)*)A` of type `const(byte)*` to parameter `byte* p` ---- +---- +fail_compilation/fail263.d(20): Error: function `f` is not callable using argument types `(const(byte)*)` +fail_compilation/fail263.d(20): cannot pass argument `cast(const(byte)*)A` of type `const(byte)*` to parameter `byte* p` +fail_compilation/fail263.d(14): `fail263.f(byte* p)` declared here +---- */ // https://issues.dlang.org/show_bug.cgi?id=2766 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail322.d b/gcc/testsuite/gdc.test/fail_compilation/fail322.d index 491111fe610..faaab68a6ee 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail322.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail322.d @@ -1,11 +1,13 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail322.d(13): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(string)` -fail_compilation/fail322.d(13): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` -fail_compilation/fail322.d(15): Error: function `fail322.digestToString2(ref char[16] digest)` is not callable using argument types `(const(char[16]))` -fail_compilation/fail322.d(15): cannot pass argument `s` of type `const(char[16])` to parameter `ref char[16] digest` ---- +---- +fail_compilation/fail322.d(15): Error: function `digestToString2` is not callable using argument types `(string)` +fail_compilation/fail322.d(15): cannot pass rvalue argument `"1234567890123456"` of type `string` to parameter `ref char[16] digest` +fail_compilation/fail322.d(20): `fail322.digestToString2(ref char[16] digest)` declared here +fail_compilation/fail322.d(17): Error: function `digestToString2` is not callable using argument types `(const(char[16]))` +fail_compilation/fail322.d(17): cannot pass argument `s` of type `const(char[16])` to parameter `ref char[16] digest` +fail_compilation/fail322.d(20): `fail322.digestToString2(ref char[16] digest)` declared here +---- */ void main() diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d dissimilarity index 74% index 77e8cd8eb00..de20333481f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail332.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d @@ -1,56 +1,66 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail332.d(22): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `()` -fail_compilation/fail332.d(22): missing argument for parameter #1: `int __param_0` -fail_compilation/fail332.d(23): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `(typeof(null))` -fail_compilation/fail332.d(23): cannot pass argument `null` of type `typeof(null)` to parameter `int __param_0` -fail_compilation/fail332.d(25): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(string)` -fail_compilation/fail332.d(25): cannot pass argument `""` of type `string` to parameter `int[] __param_0...` -fail_compilation/fail332.d(26): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(int, typeof(null))` -fail_compilation/fail332.d(26): cannot pass argument `null` of type `typeof(null)` to parameter `int[] __param_0...` ---- -*/ - -import core.vararg; - -void foo(int, ...) {} -void baz(int[]...) {} - -void test() -{ - foo(); - foo(null); - - baz(""); - baz(3, null); -} - -/* -TEST_OUTPUT: ---- -fail_compilation/fail332.d(50): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `()` -fail_compilation/fail332.d(50): missing argument for parameter #1: `Object` -fail_compilation/fail332.d(51): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(int)` -fail_compilation/fail332.d(51): cannot pass argument `4` of type `int` to parameter `Object` -fail_compilation/fail332.d(52): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null))` -fail_compilation/fail332.d(52): expected 2 variadic argument(s), not 0 -fail_compilation/fail332.d(53): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int)` -fail_compilation/fail332.d(53): expected 2 variadic argument(s), not 1 -fail_compilation/fail332.d(54): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int, string)` -fail_compilation/fail332.d(54): cannot pass argument `""` of type `string` to parameter `int[2]...` -fail_compilation/fail332.d(55): Error: function `fail332.bar(Object, int[2]...)` is not callable using argument types `(typeof(null), int, int, int)` -fail_compilation/fail332.d(55): expected 2 variadic argument(s), not 3 ---- -*/ -void bar(Object, int[2]...); - -void test2() -{ - bar(); - bar(4); - bar(null); - bar(null, 2); - bar(null, 2, ""); - bar(null, 2,3,4); -} +/* +TEST_OUTPUT: +--- +fail_compilation/fail332.d(26): Error: function `foo` is not callable using argument types `()` +fail_compilation/fail332.d(26): missing argument for parameter #1: `int __param_0` +fail_compilation/fail332.d(21): `fail332.foo(int __param_0, ...)` declared here +fail_compilation/fail332.d(27): Error: function `foo` is not callable using argument types `(typeof(null))` +fail_compilation/fail332.d(27): cannot pass argument `null` of type `typeof(null)` to parameter `int __param_0` +fail_compilation/fail332.d(21): `fail332.foo(int __param_0, ...)` declared here +fail_compilation/fail332.d(29): Error: function `baz` is not callable using argument types `(string)` +fail_compilation/fail332.d(29): cannot pass argument `""` of type `string` to parameter `int[] __param_0...` +fail_compilation/fail332.d(22): `fail332.baz(int[] __param_0...)` declared here +fail_compilation/fail332.d(30): Error: function `baz` is not callable using argument types `(int, typeof(null))` +fail_compilation/fail332.d(30): cannot pass argument `null` of type `typeof(null)` to parameter `int[] __param_0...` +fail_compilation/fail332.d(22): `fail332.baz(int[] __param_0...)` declared here +--- +*/ + +import core.vararg; + +void foo(int, ...) {} +void baz(int[]...) {} + +void test() +{ + foo(); + foo(null); + + baz(""); + baz(3, null); +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail332.d(60): Error: function `bar` is not callable using argument types `()` +fail_compilation/fail332.d(60): missing argument for parameter #1: `Object` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(61): Error: function `bar` is not callable using argument types `(int)` +fail_compilation/fail332.d(61): cannot pass argument `4` of type `int` to parameter `Object` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(62): Error: function `bar` is not callable using argument types `(typeof(null))` +fail_compilation/fail332.d(62): expected 2 variadic argument(s), not 0 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(63): Error: function `bar` is not callable using argument types `(typeof(null), int)` +fail_compilation/fail332.d(63): expected 2 variadic argument(s), not 1 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(64): Error: function `bar` is not callable using argument types `(typeof(null), int, string)` +fail_compilation/fail332.d(64): cannot pass argument `""` of type `string` to parameter `int[2]...` +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +fail_compilation/fail332.d(65): Error: function `bar` is not callable using argument types `(typeof(null), int, int, int)` +fail_compilation/fail332.d(65): expected 2 variadic argument(s), not 3 +fail_compilation/fail332.d(56): `fail332.bar(Object, int[2]...)` declared here +--- +*/ +void bar(Object, int[2]...); + +void test2() +{ + bar(); + bar(4); + bar(null); + bar(null, 2); + bar(null, 2, ""); + bar(null, 2,3,4); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail58.d b/gcc/testsuite/gdc.test/fail_compilation/fail58.d index 89b2351acfe..ae70da259b6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail58.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail58.d @@ -1,11 +1,13 @@ /* TEST_OUTPUT: ---- -fail_compilation/fail58.d(26): Error: function `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` is not callable using argument types `(string, int)` -fail_compilation/fail58.d(26): cannot pass argument `"123"` of type `string` to parameter `dchar[] pText` -fail_compilation/fail58.d(30): Error: function `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` is not callable using argument types `(string, int)` -fail_compilation/fail58.d(30): cannot pass argument `""` of type `string` to parameter `dchar[] pText` ---- +---- +fail_compilation/fail58.d(28): Error: function `SomeFunc` is not callable using argument types `(string, int)` +fail_compilation/fail58.d(28): cannot pass argument `"123"` of type `string` to parameter `dchar[] pText` +fail_compilation/fail58.d(14): `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` declared here +fail_compilation/fail58.d(32): Error: function `SomeFunc` is not callable using argument types `(string, int)` +fail_compilation/fail58.d(32): cannot pass argument `""` of type `string` to parameter `dchar[] pText` +fail_compilation/fail58.d(14): `fail58.SomeFunc(dchar[] pText, out int pStopPosn)` declared here +---- */ debug import std.stdio; const int anything = -1000; // Line #2 diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d index a4844bf66f5..f2abfcc0083 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail8009.d(9): Error: template `fail8009.filter` is not callable using argument types `!()(void)` +fail_compilation/fail8009.d(9): Error: template `filter` is not callable using argument types `!()(void)` fail_compilation/fail8009.d(8): Candidate is: `filter(R)(scope bool delegate(ref BAD!R) func)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail95.d b/gcc/testsuite/gdc.test/fail_compilation/fail95.d index 7065bc11516..0e613363b08 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail95.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail95.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail95.d(19): Error: template `fail95.A` is not callable using argument types `!()(int)` +fail_compilation/fail95.d(19): Error: template `A` is not callable using argument types `!()(int)` fail_compilation/fail95.d(11): Candidate is: `A(alias T)(T)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d index de83db9c5ed..caca3b3e97e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d +++ b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d @@ -1,18 +1,39 @@ -/** -TEST_OUTPUT: ---- -fail_compilation\hexstring.d(16): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])` -fail_compilation\hexstring.d(17): Error: cannot implicitly convert expression `"\x12?"c` of type `string` to `immutable(ubyte[])` -fail_compilation\hexstring.d(18): Error: cannot implicitly convert expression `"\x12?"` of type `string` to `immutable(ubyte[])` -fail_compilation\hexstring.d(15): Error: cannot implicitly convert expression `"\x12?"` of type `string` to `ubyte[]` ---- -*/ -immutable ubyte[] s0 = x"123F"; -static assert(s0[0] == 0x12); -static assert(s0[1] == 0x3F); -immutable byte[] s1 = x"123F"; - -ubyte[] f1 = x"123F"; -immutable ubyte[] f2 = "123F"; -immutable ubyte[] f3 = x"123F"c; -immutable ubyte[] f4 = cast(string) x"123F"; +/** +TEST_OUTPUT: +--- +fail_compilation/hexstring.d(29): Error: cannot implicitly convert expression `"123F"` of type `string` to `immutable(ubyte[])` +fail_compilation/hexstring.d(30): Error: cannot implicitly convert expression `x"123F"c` of type `string` to `immutable(ubyte[])` +fail_compilation/hexstring.d(31): Error: cannot implicitly convert expression `x"123F"` of type `string` to `immutable(ubyte[])` +fail_compilation/hexstring.d(33): Error: hex string length 1 must be a multiple of 2 to cast to `immutable(ushort[])` +fail_compilation/hexstring.d(34): Error: hex string length 3 must be a multiple of 4 to cast to `immutable(uint[])` +fail_compilation/hexstring.d(35): Error: hex string length 5 must be a multiple of 8 to cast to `immutable(ulong[])` +fail_compilation/hexstring.d(36): Error: array cast from `wstring` to `immutable(ulong[])` is not supported at compile time +fail_compilation/hexstring.d(36): perhaps remove postfix `w` from hex string +fail_compilation/hexstring.d(37): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time +fail_compilation/hexstring.d(38): Error: array cast from `string` to `immutable(ushort[])` is not supported at compile time +fail_compilation/hexstring.d(39): Error: array cast from `string` to `immutable(uint[])` is not supported at compile time +fail_compilation/hexstring.d(39): perhaps remove postfix `c` from hex string +fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]` +--- +*/ + +immutable ubyte[] s0 = x"123F"; +static assert(s0[0] == 0x12); +static assert(s0[1] == 0x3F); +immutable byte[] s1 = x"123F"; + +enum E(X) = cast(X[]) x"AABBCCDD"; +static assert(E!int[0] == 0xAABBCCDD); + +ubyte[] f1 = x"123F"; +immutable ubyte[] f2 = "123F"; +immutable ubyte[] f3 = x"123F"c; +immutable ubyte[] f4 = cast(string) x"123F"; + +immutable ushort[] f5 = cast(immutable ushort[]) x"11"; +immutable uint[] f6 = cast(immutable uint[]) x"112233"; +immutable ulong[] f7 = cast(immutable ulong[]) x"1122334455"; +immutable ulong[] f8 = cast(immutable ulong[]) x"1122334455"w; +immutable uint[] f9 = cast(immutable uint[]) "ABCD"; +immutable ushort[] f10 = cast(immutable ushort[]) (x"1122" ~ ""); +immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c; diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d index e76d4ac050d..552a9824f32 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/ice10922.d(10): Error: function `ice10922.__lambda4(in uint n)` is not callable using argument types `()` -fail_compilation/ice10922.d(10): too few arguments, expected 1, got 0 +fail_compilation/ice10922.d(11): Error: function `__lambda4` is not callable using argument types `()` +fail_compilation/ice10922.d(11): too few arguments, expected 1, got 0 +fail_compilation/ice10922.d(10): `ice10922.__lambda4(in uint n)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d index 448e629602d..476c6559c82 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d @@ -1,14 +1,14 @@ /* TEST_OUTPUT: ---- +---- fail_compilation/ice11856_1.d(18): Error: no property `g` for `A()` of type `A` fail_compilation/ice11856_1.d(18): the following error occured while looking for a UFCS match -fail_compilation/ice11856_1.d(18): Error: template `ice11856_1.g` is not callable using argument types `!()(A)` +fail_compilation/ice11856_1.d(18): Error: template `g` is not callable using argument types `!()(A)` fail_compilation/ice11856_1.d(16): Candidate is: `g(T)(T x)` with `T = A` must satisfy the following constraint: ` is(typeof(x.f()))` ---- +---- */ struct A {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12501.d b/gcc/testsuite/gdc.test/fail_compilation/ice12501.d index 2c45c8a359d..c1b1e38a965 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice12501.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice12501.d @@ -1,12 +1,14 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice12501.d(31): Error: function `ice12501.foo(int value)` is not callable using argument types `(int, int)` -fail_compilation/ice12501.d(31): expected 1 argument(s), not 2 -fail_compilation/ice12501.d(31): Error: function `ice12501.foo(int value)` is not callable using argument types `(int, int)` -fail_compilation/ice12501.d(31): expected 1 argument(s), not 2 -fail_compilation/ice12501.d(45): Error: template instance `ice12501.reduce!(foo, foo).reduce!(Tuple!(int, int), int[])` error instantiating ---- +---- +fail_compilation/ice12501.d(33): Error: function `foo` is not callable using argument types `(int, int)` +fail_compilation/ice12501.d(33): expected 1 argument(s), not 2 +fail_compilation/ice12501.d(40): `ice12501.foo(int value)` declared here +fail_compilation/ice12501.d(33): Error: function `foo` is not callable using argument types `(int, int)` +fail_compilation/ice12501.d(33): expected 1 argument(s), not 2 +fail_compilation/ice12501.d(40): `ice12501.foo(int value)` declared here +fail_compilation/ice12501.d(47): Error: template instance `ice12501.reduce!(foo, foo).reduce!(Tuple!(int, int), int[])` error instantiating +---- */ struct Tuple(T...) diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d index 151bf17535c..4b12f8b65ad 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/ice14130.d(10): Error: undefined identifier `Undef` -fail_compilation/ice14130.d(14): Error: template `ice14130.foo` is not callable using argument types `!()(int)` +fail_compilation/ice14130.d(14): Error: template `foo` is not callable using argument types `!()(int)` fail_compilation/ice14130.d(10): Candidate is: `foo(R, F = Undef)(R r, F s = 0)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14907.d b/gcc/testsuite/gdc.test/fail_compilation/ice14907.d index 5d676cd1a12..eeca1b3b3b3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14907.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14907.d @@ -1,14 +1,14 @@ /* TEST_OUTPUT: ---- +---- fail_compilation/ice14907.d(14): Error: struct `ice14907.S(int v = S)` recursive template expansion fail_compilation/ice14907.d(19): while looking for match for `S!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion fail_compilation/ice14907.d(20): while looking for match for `f!()` fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion -fail_compilation/ice14907.d(21): Error: template `ice14907.f` is not callable using argument types `!()()` +fail_compilation/ice14907.d(21): Error: template `f` is not callable using argument types `!()()` fail_compilation/ice14907.d(15): Candidate is: `f(int v = f)()` ---- +---- */ struct S(int v = S) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14923.d b/gcc/testsuite/gdc.test/fail_compilation/ice14923.d index e3b677e2cdb..99d2eeed714 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice14923.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice14923.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice14923.d(22): Error: function `ice14923.parse(C a)` is not callable using argument types `(A)` -fail_compilation/ice14923.d(22): cannot pass argument `b` of type `ice14923.A` to parameter `C a` -fail_compilation/ice14923.d(22): instantiated from here: `bar!((b) => parse(b))` ---- +---- +fail_compilation/ice14923.d(23): Error: function `parse` is not callable using argument types `(A)` +fail_compilation/ice14923.d(23): cannot pass argument `b` of type `ice14923.A` to parameter `C a` +fail_compilation/ice14923.d(21): `ice14923.parse(C a)` declared here +fail_compilation/ice14923.d(23): instantiated from here: `bar!((b) => parse(b))` +---- */ auto bar(alias fun)() diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d index 90cf03f1b48..5cde816c668 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d @@ -1,10 +1,11 @@ /* 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 +fail_compilation/ice23097.d(13): Error: undefined identifier `ICE` +fail_compilation/ice23097.d(28): Error: template instance `ice23097.ice23097!(S23097)` error instantiating +fail_compilation/ice23097.d(28): Error: function `ice23097` is not callable using argument types `(S23097)` +fail_compilation/ice23097.d(28): generating a copy constructor for `struct S23097` failed, therefore instances of it are uncopyable +fail_compilation/ice23097.d(11): `ice23097.ice23097!(S23097).ice23097(S23097 __param_0)` declared here --- */ auto ice23097(I)(I) diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d index 9355a0fcafd..de9fe295dca 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d @@ -7,7 +7,7 @@ TEST_OUTPUT: --- fail_compilation/ice6538.d(23): Error: template instance `Sym!(super)` expression `super` is not a valid template value argument -fail_compilation/ice6538.d(28): Error: template `ice6538.D.foo` is not callable using argument types `!()()` +fail_compilation/ice6538.d(28): Error: template `foo` is not callable using argument types `!()()` fail_compilation/ice6538.d(23): Candidate is: `foo()()` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d index c9ab014b6e6..1e87f0a141d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` is not callable using argument types `!()(int)` +fail_compilation/ice9284.d(14): Error: template `__ctor` is not callable using argument types `!()(int)` fail_compilation/ice9284.d(12): Candidate is: `this()(string)` fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d index 456d3e12f23..662038c19cf 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d @@ -1,10 +1,11 @@ /* TEST_OUTPUT: ---- -fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int __param_0)` is not callable using argument types `()` -fail_compilation/ice9540.d(35): too few arguments, expected 1, got 0 -fail_compilation/ice9540.d(26): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating ---- +---- +fail_compilation/ice9540.d(36): Error: function `dg` is not callable using argument types `()` +fail_compilation/ice9540.d(36): too few arguments, expected 1, got 0 +fail_compilation/ice9540.d(33): `ice9540.A.test.AddFront!(this, f).AddFront.dg(int __param_0)` declared here +fail_compilation/ice9540.d(27): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating +---- */ template Tuple(E...) { alias E Tuple; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d b/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d new file mode 100644 index 00000000000..53c14508358 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/iconv_interface_array.d @@ -0,0 +1,51 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/iconv_interface_array.d(48): Error: function `testA` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(48): cannot pass argument `arr` of type `C[4]` to parameter `I1[4] arr` +fail_compilation/iconv_interface_array.d(27): `iconv_interface_array.testA(I1[4] arr)` declared here +fail_compilation/iconv_interface_array.d(49): Error: function `testB` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(49): cannot pass argument `arr` of type `C[4]` to parameter `I2[4] arr` +fail_compilation/iconv_interface_array.d(33): `iconv_interface_array.testB(I2[4] arr)` declared here +fail_compilation/iconv_interface_array.d(50): Error: function `testC` is not callable using argument types `(C[4])` +fail_compilation/iconv_interface_array.d(50): cannot pass argument `arr` of type `C[4]` to parameter `I3[4] arr` +fail_compilation/iconv_interface_array.d(39): `iconv_interface_array.testC(I3[4] arr)` declared here +--- +*/ + +interface I1 { int a(int); } +interface I2 { int b(int); } +interface I3 { int c(int); } + +class C : I1, I2, I3 +{ + int a(int i) { return 1 * i; } + int b(int i) { return 2 * i; } + int c(int i) { return 3 * i; } +} + +void testA(I1[4] arr) +{ + foreach (uint idx, obj; arr) + assert(obj.a(idx) == 1 * idx); +} + +void testB(I2[4] arr) +{ + foreach (idx, obj; arr) + assert(obj.b(cast(int) idx) == 2 * idx); +} + +void testC(I3[4] arr) +{ + foreach (idx, obj; arr) + assert(obj.c(cast(int) idx) == 3 * idx); +} + +void main() +{ + C[4] arr = [ new C, new C, new C, new C ]; + testA(arr); + testB(arr); + testC(arr); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d b/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d new file mode 100644 index 00000000000..c915c446b49 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/interpolatedexpressionsequence_postfix.d @@ -0,0 +1,13 @@ +/* TEST_OUTPUT: +--- +fail_compilation/interpolatedexpressionsequence_postfix.d(10): Error: String postfixes on interpolated expression sequences are not allowed. +fail_compilation/interpolatedexpressionsequence_postfix.d(11): Error: String postfixes on interpolated expression sequences are not allowed. +fail_compilation/interpolatedexpressionsequence_postfix.d(12): Error: String postfixes on interpolated expression sequences are not allowed. +--- +*/ +void main() { + // all postfixes are banned + auto c = i"foo"c; + auto w = i"foo"w; + auto d = i"foo"d; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d dissimilarity index 67% index 5129f301460..b634a119564 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d +++ b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d @@ -1,48 +1,53 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/named_arguments_error.d(32): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(32): parameter `x` assigned twice -fail_compilation/named_arguments_error.d(33): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(33): argument `4` goes past end of parameter list -fail_compilation/named_arguments_error.d(34): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(34): parameter `y` assigned twice -fail_compilation/named_arguments_error.d(35): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` -fail_compilation/named_arguments_error.d(35): no parameter named `a` -fail_compilation/named_arguments_error.d(36): Error: function `named_arguments_error.g(int x, int y, int z = 3)` is not callable using argument types `(int, int)` -fail_compilation/named_arguments_error.d(36): missing argument for parameter #1: `int x` -fail_compilation/named_arguments_error.d(38): Error: no named argument `element` allowed for array dimension -fail_compilation/named_arguments_error.d(39): Error: no named argument `number` allowed for scalar -fail_compilation/named_arguments_error.d(40): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string` -fail_compilation/named_arguments_error.d(41): Error: named arguments with Implicit Function Template Instantiation are not supported yet -fail_compilation/named_arguments_error.d(41): Error: template `named_arguments_error.tempfun` is not callable using argument types `!()(string, int)` -fail_compilation/named_arguments_error.d(45): Candidate is: `tempfun(T, U)(T t, U u)` ---- -*/ - - - - -void f(int x, int y, int z); - -int g(int x, int y, int z = 3); - -void main() -{ - f(x: 3, x: 3, 5); - f(z: 3, 4, 5); - f(y: 3, x: 4, 5); - f(a: 3, b: 4, 5); - g(y: 4, z: 3); - - auto g0 = new int[](element: 3); - auto g1 = new int(number: 3); - string s = g(x: 3, y: 4, z: 5); - enum x = tempfun(u: "u", t: 0); -} - -// template arguments -int tempfun(T, U)(T t, U u) -{ - return 3; -} +/* +TEST_OUTPUT: +--- +fail_compilation/named_arguments_error.d(37): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(37): parameter `x` assigned twice +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(38): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(38): argument `4` goes past end of parameter list +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(39): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(39): parameter `y` assigned twice +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(40): Error: function `f` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(40): no parameter named `a` +fail_compilation/named_arguments_error.d(31): `named_arguments_error.f(int x, int y, int z)` declared here +fail_compilation/named_arguments_error.d(41): Error: function `g` is not callable using argument types `(int, int)` +fail_compilation/named_arguments_error.d(41): missing argument for parameter #1: `int x` +fail_compilation/named_arguments_error.d(33): `named_arguments_error.g(int x, int y, int z = 3)` declared here +fail_compilation/named_arguments_error.d(43): Error: no named argument `element` allowed for array dimension +fail_compilation/named_arguments_error.d(44): Error: no named argument `number` allowed for scalar +fail_compilation/named_arguments_error.d(45): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string` +fail_compilation/named_arguments_error.d(46): Error: named arguments with Implicit Function Template Instantiation are not supported yet +fail_compilation/named_arguments_error.d(46): Error: template `tempfun` is not callable using argument types `!()(string, int)` +fail_compilation/named_arguments_error.d(50): Candidate is: `tempfun(T, U)(T t, U u)` +--- +*/ + + + + +void f(int x, int y, int z); + +int g(int x, int y, int z = 3); + +void main() +{ + f(x: 3, x: 3, 5); + f(z: 3, 4, 5); + f(y: 3, x: 4, 5); + f(a: 3, b: 4, 5); + g(y: 4, z: 3); + + auto g0 = new int[](element: 3); + auto g1 = new int(number: 3); + string s = g(x: 3, y: 4, z: 5); + enum x = tempfun(u: "u", t: 0); +} + +// template arguments +int tempfun(T, U)(T t, U u) +{ + return 3; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/previewin.d b/gcc/testsuite/gdc.test/fail_compilation/previewin.d index d0e97c8bcd3..486dcd5244d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/previewin.d +++ b/gcc/testsuite/gdc.test/fail_compilation/previewin.d @@ -1,20 +1,23 @@ /* REQUIRED_ARGS: -preview=in -preview=dip1000 TEST_OUTPUT: ---- -fail_compilation/previewin.d(4): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)` +---- +fail_compilation/previewin.d(4): Error: function `takeFunction` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(4): cannot pass argument `__lambda1` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f` -fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here +fail_compilation/previewin.d(5): Error: function `takeFunction` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` -fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here +fail_compilation/previewin.d(6): Error: function `takeFunction` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` +fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to global variable `myGlobal` fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to global variable `myGlobal` fail_compilation/previewin.d(17): Error: scope parameter `arg` may not be returned fail_compilation/previewin.d(18): Error: scope variable `arg` assigned to `ref` variable `escape` with longer lifetime fail_compilation/previewin.d(22): Error: returning `arg` escapes a reference to parameter `arg` fail_compilation/previewin.d(22): perhaps annotate the parameter with `return` ---- +---- */ #line 1 diff --git a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d index fce4ab7345e..ca78050e6ac 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d +++ b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d @@ -4,10 +4,12 @@ fail_compilation/pull12941.d(110): Error: `pull12941.foo` called with argument t fail_compilation/pull12941.d(101): `pull12941.foo(return ref scope int* p)` and: fail_compilation/pull12941.d(102): `pull12941.foo(return out scope int* p)` -fail_compilation/pull12941.d(111): Error: function `pull12941.bar(return scope int* p)` is not callable using argument types `(int)` +fail_compilation/pull12941.d(111): Error: function `bar` is not callable using argument types `(int)` fail_compilation/pull12941.d(111): cannot pass argument `1` of type `int` to parameter `return scope int* p` -fail_compilation/pull12941.d(112): Error: function `pull12941.abc(return ref int* p)` is not callable using argument types `(int)` +fail_compilation/pull12941.d(104): `pull12941.bar(return scope int* p)` declared here +fail_compilation/pull12941.d(112): Error: function `abc` is not callable using argument types `(int)` fail_compilation/pull12941.d(112): cannot pass rvalue argument `1` of type `int` to parameter `return ref int* p` +fail_compilation/pull12941.d(105): `pull12941.abc(return ref int* p)` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19107.d b/gcc/testsuite/gdc.test/fail_compilation/test19107.d index c8021229427..9a6e3358647 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test19107.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test19107.d @@ -2,7 +2,7 @@ EXTRA_FILES: imports/imp19661.d imports/test19107a.d imports/test19107b.d TEST_OUTPUT: --- -fail_compilation/test19107.d(24): Error: template `test19107.all` is not callable using argument types `!((c) => c)(string[])` +fail_compilation/test19107.d(24): Error: template `all` is not callable using argument types `!((c) => c)(string[])` fail_compilation/test19107.d(18): Candidate is: `all(alias pred, T)(T t)` with `pred = __lambda2, T = string[]` diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19971.d b/gcc/testsuite/gdc.test/fail_compilation/test19971.d index f854362459b..3d46eeb82ef 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test19971.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test19971.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/test19971.d(15): Error: function `test19971.f(int x)` is not callable using argument types `(string)` -fail_compilation/test19971.d(15): cannot pass argument `"%s"` of type `string` to parameter `int x` -fail_compilation/test19971.d(16): Error: function literal `__lambda1(int x)` is not callable using argument types `(string)` +fail_compilation/test19971.d(16): Error: function `f` is not callable using argument types `(string)` fail_compilation/test19971.d(16): cannot pass argument `"%s"` of type `string` to parameter `int x` +fail_compilation/test19971.d(13): `test19971.f(int x)` declared here +fail_compilation/test19971.d(17): Error: function literal `__lambda1(int x)` is not callable using argument types `(string)` +fail_compilation/test19971.d(17): cannot pass argument `"%s"` of type `string` to parameter `int x` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21008.d b/gcc/testsuite/gdc.test/fail_compilation/test21008.d index 99491078476..11cfc393cf8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21008.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21008.d @@ -4,13 +4,16 @@ TEST_OUTPUT: fail_compilation/test21008.d(110): Error: function `test21008.C.after` circular reference to class `C` fail_compilation/test21008.d(117): Error: calling non-static function `toString` requires an instance of type `Object` fail_compilation/test21008.d(117): Error: calling non-static function `toHash` requires an instance of type `Object` -fail_compilation/test21008.d(117): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `()` +fail_compilation/test21008.d(117): Error: function `opCmp` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 -fail_compilation/test21008.d(117): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `()` +$p:druntime/import/object.d$($n$): `object.Object.opCmp(Object o)` declared here +fail_compilation/test21008.d(117): Error: function `opEquals` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 +$p:druntime/import/object.d$($n$): `object.Object.opEquals(Object o)` declared here fail_compilation/test21008.d(117): Error: `Monitor` has no effect -fail_compilation/test21008.d(117): Error: function `object.Object.factory(string classname)` is not callable using argument types `()` +fail_compilation/test21008.d(117): Error: function `factory` is not callable using argument types `()` fail_compilation/test21008.d(117): too few arguments, expected 1, got 0 +$p:druntime/import/object.d$($n$): `object.Object.factory(string classname)` declared here fail_compilation/test21008.d(105): called from here: `handleMiddlewareAnnotation()` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21025.d b/gcc/testsuite/gdc.test/fail_compilation/test21025.d index 85641998751..6b2496a5840 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21025.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21025.d @@ -6,7 +6,7 @@ TEST_OUTPUT: --- fail_compilation/test21025.d(15): Error: variable `r` cannot be read at compile time fail_compilation/test21025.d(15): called from here: `binaryFun(r, r)` -fail_compilation/test21025.d(24): Error: template `test21025.uniq` is not callable using argument types `!()(void[])` +fail_compilation/test21025.d(24): Error: template `uniq` is not callable using argument types `!()(void[])` fail_compilation/test21025.d(14): Candidate is: `uniq()(int[] r)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21807.d b/gcc/testsuite/gdc.test/fail_compilation/test21807.d index 9f56bf73a90..aaa56f97098 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test21807.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test21807.d @@ -27,8 +27,9 @@ class Foo /* TEST_OUTPUT: --- -fail_compilation/test21807.d(117): Error: function `test21807.addr(return ref int b)` is not callable using argument types `(int)` +fail_compilation/test21807.d(117): Error: function `addr` is not callable using argument types `(int)` fail_compilation/test21807.d(117): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b` +fail_compilation/test21807.d(106): `test21807.addr(return ref int b)` declared here --- */ #line 100 diff --git a/gcc/testsuite/gdc.test/fail_compilation/ufcs.d b/gcc/testsuite/gdc.test/fail_compilation/ufcs.d index 501ef81927f..3a92a691e2f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ufcs.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ufcs.d @@ -1,19 +1,20 @@ /* TEST_OUTPUT: --- -fail_compilation/ufcs.d(25): Error: no property `regularF` for `s` of type `S` -fail_compilation/ufcs.d(25): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(25): Error: function `ufcs.regularF()` is not callable using argument types `(S)` -fail_compilation/ufcs.d(25): expected 0 argument(s), not 1 -fail_compilation/ufcs.d(26): Error: no property `templateF` for `s` of type `S` +fail_compilation/ufcs.d(26): Error: no property `regularF` for `s` of type `S` fail_compilation/ufcs.d(26): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(26): Error: template `ufcs.templateF` is not callable using argument types `!()(S)` -fail_compilation/ufcs.d(31): Candidate is: `templateF()()` -fail_compilation/ufcs.d(27): Error: no property `templateO` for `s` of type `S` +fail_compilation/ufcs.d(26): Error: function `regularF` is not callable using argument types `(S)` +fail_compilation/ufcs.d(26): expected 0 argument(s), not 1 +fail_compilation/ufcs.d(31): `ufcs.regularF()` declared here +fail_compilation/ufcs.d(27): Error: no property `templateF` for `s` of type `S` fail_compilation/ufcs.d(27): the following error occured while looking for a UFCS match -fail_compilation/ufcs.d(27): Error: none of the overloads of template `ufcs.templateO` are callable using argument types `!()(S)` -fail_compilation/ufcs.d(33): Candidates are: `templateO()(int x)` -fail_compilation/ufcs.d(34): `templateO()(float y)` +fail_compilation/ufcs.d(27): Error: template `templateF` is not callable using argument types `!()(S)` +fail_compilation/ufcs.d(32): Candidate is: `templateF()()` +fail_compilation/ufcs.d(28): Error: no property `templateO` for `s` of type `S` +fail_compilation/ufcs.d(28): the following error occured while looking for a UFCS match +fail_compilation/ufcs.d(28): Error: none of the overloads of template `ufcs.templateO` are callable using argument types `!()(S)` +fail_compilation/ufcs.d(34): Candidates are: `templateO()(int x)` +fail_compilation/ufcs.d(35): `templateO()(float y)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/vararg2.d b/gcc/testsuite/gdc.test/fail_compilation/vararg2.d index eb235583efa..1a2846aa01d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/vararg2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/vararg2.d @@ -1,10 +1,12 @@ /* TEST_OUTPUT: ---- -fail_compilation/vararg2.d(106): Error: function `vararg2.foo(int x, const return ...)` is not callable using argument types `(double)` +---- +fail_compilation/vararg2.d(106): Error: function `foo` is not callable using argument types `(double)` fail_compilation/vararg2.d(106): cannot pass argument `1.0` of type `double` to parameter `int x` -fail_compilation/vararg2.d(111): Error: function `vararg2.bar(int x, scope shared ...)` is not callable using argument types `(double)` +fail_compilation/vararg2.d(101): `vararg2.foo(int x, const return ...)` declared here +fail_compilation/vararg2.d(111): Error: function `bar` is not callable using argument types `(double)` fail_compilation/vararg2.d(111): cannot pass argument `1.0` of type `double` to parameter `int x` ---- +fail_compilation/vararg2.d(102): `vararg2.bar(int x, scope shared ...)` declared here +---- */ #line 100 diff --git a/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d b/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d new file mode 100644 index 00000000000..831150792f9 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/interpolatedexpressionsequence.d @@ -0,0 +1,51 @@ +import core.interpolation; + +alias AliasSeq(T...) = T; + +string simpleToString(T...)(T thing) { + string s; + foreach(item; thing) + // all the items provided by core.interpolation have + // toString to return an appropriate value + // + // then this particular example only has embedded strings + // and chars, to we can append them directly + static if(__traits(hasMember, item, "toString")) + s ~= item.toString(); + else + s ~= item; + + return s; +} + +void main() { + int a = 1; + string b = "one"; + // parser won't permit alias = i".." directly; i"..." is meant to + // be used as a function/template parameter at this time. + alias expr = AliasSeq!i"$(a) $(b)"; + // elements from the source code are available at compile time, so + // we static assert those, but the values, of course, are different + static assert(expr[0] == InterpolationHeader()); + static assert(expr[1] == InterpolatedExpression!"a"()); + assert(expr[2] == a); // actual value not available at compile time + static assert(expr[3] == InterpolatedLiteral!" "()); + // the parens around the expression are not included + static assert(expr[4] == InterpolatedExpression!"b"()); + assert(expr[5] == b); // actual value not available at compile time + static assert(expr[6] == InterpolationFooter()); + + // it does currently allow `auto` to be used, it creates a value tuple + // you can embed any D expressions inside the parenthesis, and the + // token is not ended until you get the *outer* ) and ". + auto thing = i"$(b) $("$" ~ ')' ~ `"`)"; + assert(simpleToString(thing) == "one $)\""); + + assert(simpleToString(i"$b") == "$b"); // support for $ident removed by popular demand + + // i`` and iq{} should also work + assert(simpleToString(i` $(b) is $(b)!`) == " one is one!"); + assert(simpleToString(iq{ $(b) is $(b)!}) == " one is one!"); + assert(simpleToString(i`\$('$')`) == "\\$"); // no \ escape there + assert(simpleToString(iq{{$('$')}}) == "{$}"); // {} needs to work +} diff --git a/gcc/testsuite/gdc.test/runnable/literal.d b/gcc/testsuite/gdc.test/runnable/literal.d index 99b177759b4..69971240d94 100644 --- a/gcc/testsuite/gdc.test/runnable/literal.d +++ b/gcc/testsuite/gdc.test/runnable/literal.d @@ -241,6 +241,27 @@ void test12950() assert(0b00_00_00_01UL.op12950() == 12951); } +void testHexstring() +{ + static immutable uint[] x = cast(immutable uint[]) x"FFAADDEE"; + static assert(x[0] == 0xFFAADDEE); + assert(x[0] == 0xFFAADDEE); + + static immutable ulong[] y = cast(immutable ulong[]) x"1122334455667788AABBCCDDEEFF0099"; + static assert(y[0] == 0x1122334455667788); + static assert(y[1] == 0xAABBCCDDEEFF0099); + assert(y[0] == 0x1122334455667788); + assert(y[1] == 0xAABBCCDDEEFF0099); + + // Test that mangling of StringExp with size 8 is the same as array literal mangling: + void f(immutable ulong[] a)() {} + static assert(f!y.mangleof == f!([0x1122334455667788, 0xAABBCCDDEEFF0099]).mangleof); + + // Test printing StringExp with size 8 + enum toStr(immutable ulong[] v) = v.stringof; + static assert(toStr!y == `x"88776655443322119900FFEEDDCCBBAA"`); +} + /***************************************************/ int main() @@ -249,6 +270,7 @@ int main() test2(); test13907(); test12950(); + testHexstring(); printf("Success\n"); return 0; diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 138b0b6fa7c..9217c654225 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa +e7709452775d374c1e2dfb67566668ada3dec5fc The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am index 3ef98dcc737..d2fb6e218c1 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -196,32 +196,33 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/internal/parseoptions.d core/internal/postblit.d \ core/internal/qsort.d core/internal/spinlock.d core/internal/string.d \ core/internal/switch_.d core/internal/traits.d core/internal/utf.d \ - core/internal/util/array.d core/internal/util/math.d core/lifetime.d \ - core/math.d core/memory.d core/runtime.d core/simd.d \ - core/stdc/assert_.d core/stdc/complex.d core/stdc/config.d \ - core/stdc/ctype.d core/stdc/errno.d core/stdc/fenv.d \ - core/stdc/float_.d core/stdc/inttypes.d core/stdc/limits.d \ - core/stdc/locale.d core/stdc/math.d core/stdc/signal.d \ - core/stdc/stdarg.d core/stdc/stdatomic.d core/stdc/stddef.d \ - core/stdc/stdint.d core/stdc/stdio.d core/stdc/stdlib.d \ - core/stdc/string.d core/stdc/tgmath.d core/stdc/time.d \ - core/stdc/wchar_.d core/stdc/wctype.d core/sync/barrier.d \ - core/sync/condition.d core/sync/config.d core/sync/event.d \ - core/sync/exception.d core/sync/mutex.d core/sync/package.d \ - core/sync/rwmutex.d core/sync/semaphore.d core/thread/context.d \ - core/thread/fiber.d core/thread/osthread.d core/thread/package.d \ - core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \ - core/time.d core/vararg.d core/volatile.d etc/valgrind/valgrind.d \ - gcc/attribute.d gcc/attributes.d gcc/backtrace.d gcc/builtins.d \ - gcc/deh.d gcc/emutls.d gcc/gthread.d gcc/sections/common.d \ - gcc/sections/elf.d gcc/sections/macho.d gcc/sections/package.d \ - gcc/sections/pecoff.d gcc/simd.d gcc/unwind/arm.d \ - gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \ - gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \ - rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \ - rt/deh.d rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d \ - rt/memory.d rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d \ - rt/tlsgc.d rt/util/typeinfo.d rt/util/utility.d + core/internal/util/array.d core/internal/util/math.d \ + core/interpolation.d core/lifetime.d core/math.d core/memory.d \ + core/runtime.d core/simd.d core/stdc/assert_.d core/stdc/complex.d \ + core/stdc/config.d core/stdc/ctype.d core/stdc/errno.d \ + core/stdc/fenv.d core/stdc/float_.d core/stdc/inttypes.d \ + core/stdc/limits.d core/stdc/locale.d core/stdc/math.d \ + core/stdc/signal.d core/stdc/stdarg.d core/stdc/stdatomic.d \ + core/stdc/stddef.d core/stdc/stdint.d core/stdc/stdio.d \ + core/stdc/stdlib.d core/stdc/string.d core/stdc/tgmath.d \ + core/stdc/time.d core/stdc/wchar_.d core/stdc/wctype.d \ + core/sync/barrier.d core/sync/condition.d core/sync/config.d \ + core/sync/event.d core/sync/exception.d core/sync/mutex.d \ + core/sync/package.d core/sync/rwmutex.d core/sync/semaphore.d \ + core/thread/context.d core/thread/fiber.d core/thread/osthread.d \ + core/thread/package.d core/thread/threadbase.d \ + core/thread/threadgroup.d core/thread/types.d core/time.d \ + core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \ + gcc/attributes.d gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d \ + gcc/gthread.d gcc/sections/common.d gcc/sections/elf.d \ + gcc/sections/macho.d gcc/sections/package.d gcc/sections/pecoff.d \ + gcc/simd.d gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \ + gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \ + rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \ + rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \ + rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \ + rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \ + rt/util/utility.d DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \ core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index 1d2bd66817d..3e3ab567a82 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -220,29 +220,29 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \ core/internal/string.lo core/internal/switch_.lo \ core/internal/traits.lo core/internal/utf.lo \ core/internal/util/array.lo core/internal/util/math.lo \ - core/lifetime.lo core/math.lo core/memory.lo core/runtime.lo \ - core/simd.lo core/stdc/assert_.lo core/stdc/complex.lo \ - core/stdc/config.lo core/stdc/ctype.lo core/stdc/errno.lo \ - core/stdc/fenv.lo core/stdc/float_.lo core/stdc/inttypes.lo \ - core/stdc/limits.lo core/stdc/locale.lo core/stdc/math.lo \ - core/stdc/signal.lo core/stdc/stdarg.lo core/stdc/stdatomic.lo \ - core/stdc/stddef.lo core/stdc/stdint.lo core/stdc/stdio.lo \ - core/stdc/stdlib.lo core/stdc/string.lo core/stdc/tgmath.lo \ - core/stdc/time.lo core/stdc/wchar_.lo core/stdc/wctype.lo \ - core/sync/barrier.lo core/sync/condition.lo \ - core/sync/config.lo core/sync/event.lo core/sync/exception.lo \ - core/sync/mutex.lo core/sync/package.lo core/sync/rwmutex.lo \ - core/sync/semaphore.lo core/thread/context.lo \ - core/thread/fiber.lo core/thread/osthread.lo \ - core/thread/package.lo core/thread/threadbase.lo \ - core/thread/threadgroup.lo core/thread/types.lo core/time.lo \ - core/vararg.lo core/volatile.lo etc/valgrind/valgrind.lo \ - gcc/attribute.lo gcc/attributes.lo gcc/backtrace.lo \ - gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \ - gcc/sections/common.lo gcc/sections/elf.lo \ - gcc/sections/macho.lo gcc/sections/package.lo \ - gcc/sections/pecoff.lo gcc/simd.lo gcc/unwind/arm.lo \ - gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \ + core/interpolation.lo core/lifetime.lo core/math.lo \ + core/memory.lo core/runtime.lo core/simd.lo \ + core/stdc/assert_.lo core/stdc/complex.lo core/stdc/config.lo \ + core/stdc/ctype.lo core/stdc/errno.lo core/stdc/fenv.lo \ + core/stdc/float_.lo core/stdc/inttypes.lo core/stdc/limits.lo \ + core/stdc/locale.lo core/stdc/math.lo core/stdc/signal.lo \ + core/stdc/stdarg.lo core/stdc/stdatomic.lo core/stdc/stddef.lo \ + core/stdc/stdint.lo core/stdc/stdio.lo core/stdc/stdlib.lo \ + core/stdc/string.lo core/stdc/tgmath.lo core/stdc/time.lo \ + core/stdc/wchar_.lo core/stdc/wctype.lo core/sync/barrier.lo \ + core/sync/condition.lo core/sync/config.lo core/sync/event.lo \ + core/sync/exception.lo core/sync/mutex.lo core/sync/package.lo \ + core/sync/rwmutex.lo core/sync/semaphore.lo \ + core/thread/context.lo core/thread/fiber.lo \ + core/thread/osthread.lo core/thread/package.lo \ + core/thread/threadbase.lo core/thread/threadgroup.lo \ + core/thread/types.lo core/time.lo core/vararg.lo \ + core/volatile.lo etc/valgrind/valgrind.lo gcc/attribute.lo \ + gcc/attributes.lo gcc/backtrace.lo gcc/builtins.lo gcc/deh.lo \ + gcc/emutls.lo gcc/gthread.lo gcc/sections/common.lo \ + gcc/sections/elf.lo gcc/sections/macho.lo \ + gcc/sections/package.lo gcc/sections/pecoff.lo gcc/simd.lo \ + gcc/unwind/arm.lo gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \ gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \ object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \ rt/arraycat.lo rt/cast_.lo rt/config.lo rt/critical_.lo \ @@ -874,32 +874,33 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/internal/parseoptions.d core/internal/postblit.d \ core/internal/qsort.d core/internal/spinlock.d core/internal/string.d \ core/internal/switch_.d core/internal/traits.d core/internal/utf.d \ - core/internal/util/array.d core/internal/util/math.d core/lifetime.d \ - core/math.d core/memory.d core/runtime.d core/simd.d \ - core/stdc/assert_.d core/stdc/complex.d core/stdc/config.d \ - core/stdc/ctype.d core/stdc/errno.d core/stdc/fenv.d \ - core/stdc/float_.d core/stdc/inttypes.d core/stdc/limits.d \ - core/stdc/locale.d core/stdc/math.d core/stdc/signal.d \ - core/stdc/stdarg.d core/stdc/stdatomic.d core/stdc/stddef.d \ - core/stdc/stdint.d core/stdc/stdio.d core/stdc/stdlib.d \ - core/stdc/string.d core/stdc/tgmath.d core/stdc/time.d \ - core/stdc/wchar_.d core/stdc/wctype.d core/sync/barrier.d \ - core/sync/condition.d core/sync/config.d core/sync/event.d \ - core/sync/exception.d core/sync/mutex.d core/sync/package.d \ - core/sync/rwmutex.d core/sync/semaphore.d core/thread/context.d \ - core/thread/fiber.d core/thread/osthread.d core/thread/package.d \ - core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \ - core/time.d core/vararg.d core/volatile.d etc/valgrind/valgrind.d \ - gcc/attribute.d gcc/attributes.d gcc/backtrace.d gcc/builtins.d \ - gcc/deh.d gcc/emutls.d gcc/gthread.d gcc/sections/common.d \ - gcc/sections/elf.d gcc/sections/macho.d gcc/sections/package.d \ - gcc/sections/pecoff.d gcc/simd.d gcc/unwind/arm.d \ - gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \ - gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \ - rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \ - rt/deh.d rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d \ - rt/memory.d rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d \ - rt/tlsgc.d rt/util/typeinfo.d rt/util/utility.d + core/internal/util/array.d core/internal/util/math.d \ + core/interpolation.d core/lifetime.d core/math.d core/memory.d \ + core/runtime.d core/simd.d core/stdc/assert_.d core/stdc/complex.d \ + core/stdc/config.d core/stdc/ctype.d core/stdc/errno.d \ + core/stdc/fenv.d core/stdc/float_.d core/stdc/inttypes.d \ + core/stdc/limits.d core/stdc/locale.d core/stdc/math.d \ + core/stdc/signal.d core/stdc/stdarg.d core/stdc/stdatomic.d \ + core/stdc/stddef.d core/stdc/stdint.d core/stdc/stdio.d \ + core/stdc/stdlib.d core/stdc/string.d core/stdc/tgmath.d \ + core/stdc/time.d core/stdc/wchar_.d core/stdc/wctype.d \ + core/sync/barrier.d core/sync/condition.d core/sync/config.d \ + core/sync/event.d core/sync/exception.d core/sync/mutex.d \ + core/sync/package.d core/sync/rwmutex.d core/sync/semaphore.d \ + core/thread/context.d core/thread/fiber.d core/thread/osthread.d \ + core/thread/package.d core/thread/threadbase.d \ + core/thread/threadgroup.d core/thread/types.d core/time.d \ + core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \ + gcc/attributes.d gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d \ + gcc/gthread.d gcc/sections/common.d gcc/sections/elf.d \ + gcc/sections/macho.d gcc/sections/package.d gcc/sections/pecoff.d \ + gcc/simd.d gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \ + gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \ + rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \ + rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \ + rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \ + rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \ + rt/util/utility.d DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \ core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \ @@ -1296,6 +1297,7 @@ core/internal/util/$(am__dirstamp): @: > core/internal/util/$(am__dirstamp) core/internal/util/array.lo: core/internal/util/$(am__dirstamp) core/internal/util/math.lo: core/internal/util/$(am__dirstamp) +core/interpolation.lo: core/$(am__dirstamp) core/lifetime.lo: core/$(am__dirstamp) core/math.lo: core/$(am__dirstamp) core/memory.lo: core/$(am__dirstamp) diff --git a/libphobos/libdruntime/core/internal/array/construction.d b/libphobos/libdruntime/core/internal/array/construction.d index 655acc8db57..0950b5a5aa9 100644 --- a/libphobos/libdruntime/core/internal/array/construction.d +++ b/libphobos/libdruntime/core/internal/array/construction.d @@ -339,17 +339,20 @@ void _d_arraysetctor(Tarr : T[], T)(scope Tarr p, scope ref T value) @trusted * Returns: * newly allocated array */ -T[] _d_newarrayU(T)(size_t length, bool isShared=false) pure nothrow @nogc @trusted +T[] _d_newarrayUPureNothrow(T)(size_t length, bool isShared=false) pure nothrow @trusted { - alias PureType = T[] function(size_t length, bool isShared) pure nothrow @nogc @trusted; - return (cast(PureType) &_d_newarrayUImpl!T)(length, isShared); + alias PureType = T[] function(size_t length, bool isShared) pure nothrow @trusted; + return (cast(PureType) &_d_newarrayU!T)(length, isShared); } -T[] _d_newarrayUImpl(T)(size_t length, bool isShared=false) @trusted +T[] _d_newarrayU(T)(size_t length, bool isShared=false) @trusted { import core.exception : onOutOfMemoryError; + import core.internal.traits : Unqual; import core.internal.array.utils : __arrayStart, __setArrayAllocLength, __arrayAlloc; + alias UnqT = Unqual!T; + size_t elemSize = T.sizeof; size_t arraySize; @@ -392,14 +395,14 @@ Loverflow: assert(0); Lcontinue: - auto info = __arrayAlloc!T(arraySize); + auto info = __arrayAlloc!UnqT(arraySize); if (!info.base) goto Loverflow; debug(PRINTF) printf("p = %p\n", info.base); auto arrstart = __arrayStart(info); - __setArrayAllocLength!T(info, arraySize, isShared); + __setArrayAllocLength!UnqT(info, arraySize, isShared); return (cast(T*) arrstart)[0 .. length]; } diff --git a/libphobos/libdruntime/core/internal/array/duplication.d b/libphobos/libdruntime/core/internal/array/duplication.d index 21894c29d38..eec6af92fef 100644 --- a/libphobos/libdruntime/core/internal/array/duplication.d +++ b/libphobos/libdruntime/core/internal/array/duplication.d @@ -8,8 +8,6 @@ Source: $(DRUNTIMESRC core/internal/_array/_duplication.d) */ module core.internal.array.duplication; -private extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length) pure nothrow; - U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T)) { if (__ctfe) @@ -22,8 +20,9 @@ U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T)) else { import core.stdc.string : memcpy; - auto arr = _d_newarrayU(typeid(T[]), a.length); - memcpy(arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length); + import core.internal.array.construction: _d_newarrayUPureNothrow; + auto arr = _d_newarrayUPureNothrow!T(a.length, is(T == shared)); + memcpy(cast(void*) arr.ptr, cast(const(void)*) a.ptr, T.sizeof * a.length); return *cast(U[]*) &arr; } } @@ -55,8 +54,9 @@ U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T)) else { import core.lifetime: copyEmplace; + import core.internal.array.construction: _d_newarrayU; U[] res = () @trusted { - auto arr = cast(U*) _d_newarrayU(typeid(T[]), a.length); + auto arr = cast(U*) _d_newarrayU!T(a.length, is(T == shared)); size_t i; scope (failure) { diff --git a/libphobos/libdruntime/core/internal/array/utils.d b/libphobos/libdruntime/core/internal/array/utils.d index 57eb14bd6a7..89ce6ca2183 100644 --- a/libphobos/libdruntime/core/internal/array/utils.d +++ b/libphobos/libdruntime/core/internal/array/utils.d @@ -33,7 +33,6 @@ private auto gcStatsPure() nothrow pure { import core.memory : GC; - auto impureBypass = cast(GC.Stats function() pure nothrow)&GC.stats; return impureBypass(); } diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d index ca4577f0195..73fe087861a 100644 --- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d +++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d @@ -2283,7 +2283,7 @@ struct Gcx alias toscan = scanStack!precise; debug(MARK_PRINTF) - printf("marking range: [%p..%p] (%#llx)\n", pbot, ptop, cast(long)(ptop - pbot)); + printf("marking range: [%p..%p] (%#llx)\n", rng.pbot, rng.ptop, cast(long)(rng.ptop - rng.pbot)); // limit the amount of ranges added to the toscan stack enum FANOUT_LIMIT = 32; @@ -2351,7 +2351,7 @@ struct Gcx size_t bin = pool.pagetable[pn]; // not Bins to avoid multiple size extension instructions debug(MARK_PRINTF) - printf("\t\tfound pool %p, base=%p, pn = %lld, bin = %d\n", pool, pool.baseAddr, cast(long)pn, bin); + printf("\t\tfound pool %p, base=%p, pn = %llu, bin = %llu\n", pool, pool.baseAddr, cast(ulong)pn, cast(ulong)bin); // Adjust bit to be at start of allocated memory block if (bin < Bins.B_PAGE) diff --git a/libphobos/libdruntime/core/interpolation.d b/libphobos/libdruntime/core/interpolation.d new file mode 100644 index 00000000000..0d45fe79088 --- /dev/null +++ b/libphobos/libdruntime/core/interpolation.d @@ -0,0 +1,156 @@ +/++ + This module provides definitions to support D's + interpolated expression sequence literal, sometimes + called string interpolation. + + + --- + string str; + int num; + // the compiler uses this module to implement the + // i"..." literal used here. + auto a = i"$​(str) has $​(num) items."; + --- + + The variable `a` is a sequence of expressions: + + --- + a[0] == InterpolationHeader() + a[$-1] == InterpolationFooter() + --- + + First and last, you see the header and footer, to + clearly indicate where interpolation begins and ends. + Note that there may be nested interpolated sequences too, + each with their own header and footer. Think of them + as a set of balanced parenthesis around the contents. + + Inside, you will find three general categories of + content: `InterpolatedLiteral!"string"` for string + expressions, `InterpolatedExpression!"code"` for code + expressions, and then the values themselves as their + own type. + + In the example: + --- + auto a = i"$​(str) has $​(num) items."; + --- + + We will find: + --- + a[0] == InterpolationHeader() + a[1] == InterpolatedExpression!"str" + a[2] == str + a[3] == InterpolatedLiteral!" has "; + a[4] == InterpolatedExpression!"num"; + a[5] == num + a[6] == InterpolatedLiteral!" items."; + a[7] == InterpolationFooter() + a.length == 8; + --- + + You can see the correspondence with the original + input: when you write `$​(expression)`, the string of the + expression is passed as `InterpolatedExpression!ThatString`, + (excluding any parenthesis around the expression), + and everything else is passed as `InterpolatedLiteral!str`, + in the same sequence as they appeared in the source. + + After an `InterpolatedExpression!...`, you will find the + actual value(s) in the tuple. (If the expression expanded + to multiple values - for example, if it was itself a tuple, + there will be multiple values for a single expression.) + + Library functions should NOT attempt to mixin the code + from an `InterpolatedExpression` themselves. Doing so + will fail, since it is coming from a different scope anyway. + The string is provided to you only for informational purposes + and as a sentinel to separate things the user wrote. + + Your code should be able to handle an empty code string + in `InterpolatedExpression` or even an entirely missing + `InterpolatedExpression`, in case an implementation decides to + not emit these. + + The `toString` members on these return `null`, except for + the `InterpolatedLiteral`, which returns the literal string. + This is to ease processing by generic functions like + `std.stdio.write` or `std.conv.text`, making them effectively + transparently skipped. + + To extract the string from an `InterpolatedLiteral`, you can + use an `is` expression or the `.toString` method. + + To extract the string from a `InterpolatedExpression`, you can + use an `is` expression or the `.expression` member. + + None of these structures have runtime state. + + History: + Added in dmd 2.10x frontend, released in late 2023. ++/ +module core.interpolation; + +/++ + Sentinel values to indicate the beginning and end of an + interpolated expression sequence. + + Note that these can nest, so while processing a sequence, + it may be helpful to keep a nesting count if that knowledge + is important to your application. ++/ +struct InterpolationHeader { + /++ + Returns `null` for easy compatibility with existing functions + like `std.stdio.writeln` and `std.conv.text`. + +/ + string toString() const @nogc pure nothrow @safe { + return null; + } +} + +/// ditto +struct InterpolationFooter { + /++ + Returns `null` for easy compatibility with existing functions + like `std.stdio.writeln` and `std.conv.text`. + +/ + string toString() const @nogc pure nothrow @safe { + return null; + } +} + +/++ + Represents a fragment of a string literal in between expressions + passed as part of an interpolated expression sequence. ++/ +struct InterpolatedLiteral(string text) { + /++ + Returns the text of the interpolated string literal for this + segment of the tuple, for easy access and compatibility with + existing functions like `std.stdio.writeln` and `std.conv.text`. + +/ + string toString() const @nogc pure nothrow @safe { + return text; + } +} + +/++ + Represents the source code of an expression passed as part of an + interpolated expression sequence. ++/ +struct InterpolatedExpression(string text) { + /++ + Returns the text of an interpolated expression used in the + original literal, if provided by the implementation. + +/ + enum expression = text; + + /++ + Returns `null` for easy compatibility with existing functions + like `std.stdio.writeln` and `std.conv.text`. + +/ + string toString() const @nogc pure nothrow @safe { + return null; + } +} diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index 6b083eaa926..9e563ad43a3 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -3009,5 +3009,5 @@ version (D_ProfileGC) template TypeInfoSize(T) { import core.internal.traits : hasElaborateDestructor; - enum TypeInfoSize = hasElaborateDestructor!T ? size_t.sizeof : 0; + enum TypeInfoSize = (is (T == struct) && hasElaborateDestructor!T) ? size_t.sizeof : 0; } diff --git a/libphobos/libdruntime/core/stdc/string.d b/libphobos/libdruntime/core/stdc/string.d index b9e3bb7568c..3e906b10d4a 100644 --- a/libphobos/libdruntime/core/stdc/string.d +++ b/libphobos/libdruntime/core/stdc/string.d @@ -64,6 +64,8 @@ size_t strcspn(scope const char* s1, scope const char* s2) pure; /// char* strdup(scope const char *s); /// +char* strndup(scope const char *str, size_t size); +/// char* strerror(int errnum); // This `strerror_r` definition is not following the POSIX standard version (ReturnStrerrorR) diff --git a/libphobos/libdruntime/core/sys/posix/string.d b/libphobos/libdruntime/core/sys/posix/string.d index 8c4ea38cc83..b2d6ea772ec 100644 --- a/libphobos/libdruntime/core/sys/posix/string.d +++ b/libphobos/libdruntime/core/sys/posix/string.d @@ -39,8 +39,6 @@ char* stpncpy(return scope char* dst, const char* src, size_t len) pure; int strcoll_l(scope const char* s1, scope const char* s2, locale_t locale); /// char* strerror_l(int, locale_t); -/// Save a copy of a string -char* strndup(scope const char* str, size_t len); /// Find length of string up to `maxlen` size_t strnlen(scope const char* str, size_t maxlen) pure; /// System signal messages diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d index 9ddc187b374..93902439fbf 100644 --- a/libphobos/libdruntime/core/thread/osthread.d +++ b/libphobos/libdruntime/core/thread/osthread.d @@ -493,9 +493,8 @@ class Thread : ThreadBase slock.lock_nothrow(); scope(exit) slock.unlock_nothrow(); { - ++nAboutToStart; - pAboutToStart = cast(ThreadBase*)realloc(pAboutToStart, Thread.sizeof * nAboutToStart); - pAboutToStart[nAboutToStart - 1] = this; + incrementAboutToStart(this); + version (Windows) { if ( ResumeThread( m_hndl ) == -1 ) diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d index 909bffc162b..84f9203f23b 100644 --- a/libphobos/libdruntime/core/thread/threadbase.d +++ b/libphobos/libdruntime/core/thread/threadbase.d @@ -588,8 +588,8 @@ package(core.thread): __gshared size_t sm_tlen; // can't use core.internal.util.array in public code - __gshared ThreadBase* pAboutToStart; - __gshared size_t nAboutToStart; + private __gshared ThreadBase* pAboutToStart; + private __gshared size_t nAboutToStart; // // Used for ordering threads in the global thread list. @@ -658,6 +658,12 @@ package(core.thread): // Global Thread List Operations /////////////////////////////////////////////////////////////////////////// + package static void incrementAboutToStart(ThreadBase t) nothrow @nogc + { + ++nAboutToStart; + pAboutToStart = cast(ThreadBase*)realloc(pAboutToStart, ThreadBase.sizeof * nAboutToStart); + pAboutToStart[nAboutToStart - 1] = t; + } // // Add a thread to the global thread list. diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 710f4cc90d1..4264ecf6fd6 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -65,7 +65,7 @@ alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0); alias sizediff_t = ptrdiff_t; // For backwards compatibility only. /** * Bottom type. - * See $(DDSUBLINK spec/type, noreturn). + * See $(DDSUBLINK spec/type, noreturn, `noreturn`). */ alias noreturn = typeof(*null); @@ -1667,11 +1667,12 @@ class TypeInfo_Class : TypeInfo void* deallocator; OffsetTypeInfo[] m_offTi; void function(Object) defaultConstructor; // default Constructor - ulong[2] nameSig; /// unique signature for `name` immutable(void)* m_RTInfo; // data for precise GC override @property immutable(void)* rtInfo() const { return m_RTInfo; } + uint[4] nameSig; /// unique signature for `name` + /** * Search all modules for TypeInfo_Class corresponding to classname. * Returns: null if not found diff --git a/libphobos/libdruntime/rt/cast_.d b/libphobos/libdruntime/rt/cast_.d index 44e0f7a9ccc..43ddd5a9316 100644 --- a/libphobos/libdruntime/rt/cast_.d +++ b/libphobos/libdruntime/rt/cast_.d @@ -24,11 +24,18 @@ pure: extern (D) private bool areClassInfosEqual(scope const ClassInfo a, scope const ClassInfo b) @safe { // same class if signatures match, works with potential duplicates across binaries - return a is b || - (a.m_flags & TypeInfo_Class.ClassFlags.hasNameSig - ? (a.nameSig[0] == b.nameSig[0] && - a.nameSig[1] == b.nameSig[1]) // new fast way - : (a is b || a.name == b.name)); // old slow way for temporary binary compatibility + if (a is b) + return true; + + // new fast way + if (a.m_flags & TypeInfo_Class.ClassFlags.hasNameSig) + return a.nameSig[0] == b.nameSig[0] + && a.nameSig[1] == b.nameSig[1] + && a.nameSig[2] == b.nameSig[2] + && a.nameSig[3] == b.nameSig[3]; + + // old slow way for temporary binary compatibility + return a.name == b.name; } /****************************************** diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index b04aee2c581..1d41231db9d 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -c6e1f98fab2cac046ed631b5c26c850a323aea53 +6d6e0b9b9fb5e882c7296f719baf829feb4939a3 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d index e9f61919b0d..c9813e35476 100644 --- a/libphobos/src/std/bitmanip.d +++ b/libphobos/src/std/bitmanip.d @@ -263,9 +263,9 @@ Implementation_details: `Bitfields` are internally stored in an `ubyte`, `ushort`, `uint` or `ulong` depending on the number of bits used. The bits are filled in the order given by the parameters, starting with the lowest significant bit. The name of the (private) -variable used for saving the `bitfield` is created by a prefix `_bf` -and concatenating all of the variable names, each preceded by an -underscore. +variable used for saving the `bitfield` is created by concatenating +all of the variable names, each preceded by an underscore, and +a suffix `_bf`. Params: T = A list of template parameters divided into chunks of 3 items. Each chunk consists (in this order) of a type, a diff --git a/libphobos/src/std/range/primitives.d b/libphobos/src/std/range/primitives.d index fec5c85cbef..dddcae9afd2 100644 --- a/libphobos/src/std/range/primitives.d +++ b/libphobos/src/std/range/primitives.d @@ -1011,6 +1011,15 @@ have a `save` function. See_Also: The header of $(MREF std,range) for tutorials on ranges. + +Params: + R = type to be tested + E = if present, the elements of the range must be + $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) + to this type + +Returns: + `true` if R is a forward range (possibly with element type `E`), `false` if not */ enum bool isForwardRange(R) = isInputRange!R && is(typeof((R r) { return r.save; } (R.init)) == R); @@ -1068,12 +1077,25 @@ element in the range. Calling `r.back` is allowed only if calling See_Also: The header of $(MREF std,range) for tutorials on ranges. + +Params: + R = type to be tested + E = if present, the elements of the range must be + $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) + to this type + +Returns: + `true` if R is a bidirectional range (possibly with element type `E`), `false` if not */ enum bool isBidirectionalRange(R) = isForwardRange!R && is(typeof((R r) => r.popBack)) && (is(typeof((return ref R r) => r.back)) || is(typeof(ref (return ref R r) => r.back))) && is(typeof(R.init.back.init) == ElementType!R); +/// ditto +enum bool isBidirectionalRange(R, E) = + .isBidirectionalRange!R && isQualifierConvertible!(ElementType!R, E); + /// @safe unittest { @@ -1084,6 +1106,18 @@ enum bool isBidirectionalRange(R) = isForwardRange!R auto t = r.back; // can get the back of the range auto w = r.front; static assert(is(typeof(t) == typeof(w))); // same type for front and back + + // Checking the element type + static assert( isBidirectionalRange!(int[], const int)); + static assert(!isBidirectionalRange!(int[], immutable int)); + + static assert(!isBidirectionalRange!(const(int)[], int)); + static assert( isBidirectionalRange!(const(int)[], const int)); + static assert(!isBidirectionalRange!(const(int)[], immutable int)); + + static assert(!isBidirectionalRange!(immutable(int)[], int)); + static assert( isBidirectionalRange!(immutable(int)[], const int)); + static assert( isBidirectionalRange!(immutable(int)[], immutable int)); } @safe unittest @@ -1133,6 +1167,15 @@ are bidirectional ranges only. See_Also: The header of $(MREF std,range) for tutorials on ranges. + +Params: + R = type to be tested + E = if present, the elements of the range must be + $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible) + to this type + +Returns: + `true` if R is a random-access range (possibly with element type `E`), `false` if not */ enum bool isRandomAccessRange(R) = is(typeof(lvalueOf!R[1]) == ElementType!R) @@ -1143,6 +1186,10 @@ enum bool isRandomAccessRange(R) = && (isInfinite!R || !is(typeof(lvalueOf!R[$ - 1])) || is(typeof(lvalueOf!R[$ - 1]) == ElementType!R)); +/// ditto +enum bool isRandomAccessRange(R, E) = + .isRandomAccessRange!R && isQualifierConvertible!(ElementType!R, E); + /// @safe unittest { @@ -1171,6 +1218,18 @@ enum bool isRandomAccessRange(R) = static if (!isInfinite!R) static assert(is(typeof(f) == typeof(r[$ - 1]))); } + + // Checking the element type + static assert( isRandomAccessRange!(int[], const int)); + static assert(!isRandomAccessRange!(int[], immutable int)); + + static assert(!isRandomAccessRange!(const(int)[], int)); + static assert( isRandomAccessRange!(const(int)[], const int)); + static assert(!isRandomAccessRange!(const(int)[], immutable int)); + + static assert(!isRandomAccessRange!(immutable(int)[], int)); + static assert( isRandomAccessRange!(immutable(int)[], const int)); + static assert( isRandomAccessRange!(immutable(int)[], immutable int)); } @safe unittest @@ -1695,11 +1754,9 @@ For finite ranges, the result of `opSlice` must be of the same type as the original range type. If the range defines `opDollar`, then it must support subtraction. -For infinite ranges, when $(I not) using `opDollar`, the result of -`opSlice` must be the result of $(LREF take) or $(LREF takeExactly) on the -original range (they both return the same type for infinite ranges). However, -when using `opDollar`, the result of `opSlice` must be that of the -original range type. +For infinite ranges, when $(I not) using `opDollar`, the result of `opSlice` +may be a forward range of any type. However, when using `opDollar`, the result +of `opSlice` must be of the same type as the original range type. The following expression must be true for `hasSlicing` to be `true`: @@ -1774,6 +1831,38 @@ enum bool hasSlicing(R) = isForwardRange!R static assert(hasSlicing!InfOnes); } +// https://issues.dlang.org/show_bug.cgi?id=24348 +@safe unittest +{ + static struct Slice + { + size_t length; + bool empty() => length == 0; + int front() => 0; + void popFront() { --length; } + Slice save() => this; + } + + static struct InfZeros + { + enum empty = false; + int front() => 0; + void popFront() {} + InfZeros save() => this; + + Slice opIndex(size_t[2] bounds) + { + size_t i = bounds[0], j = bounds[1]; + size_t length = i <= j ? j - i : 0; + return Slice(length); + } + + size_t[2] opSlice(size_t dim : 0)(size_t i, size_t j) => [i, j]; + } + + static assert(hasSlicing!InfZeros); +} + /** This is a best-effort implementation of `length` for any kind of range. -- 2.11.4.GIT