[gcc r16-7211] d: Merge upstream dmd, druntime e1f6680f50, phobos f87979028
Iain Buclaw
ibuclaw@gcc.gnu.org
Sat Jan 31 08:48:31 GMT 2026
https://gcc.gnu.org/g:8b0ccc95f1a70415d50bb87397cf0b1761be1e40
commit r16-7211-g8b0ccc95f1a70415d50bb87397cf0b1761be1e40
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date: Fri Jan 30 17:30:33 2026 +0100
d: Merge upstream dmd, druntime e1f6680f50, phobos f87979028
D front-end changes:
- Import latest fixes from v2.112.0-beta.1.
- Associative array operations are now lowered to templates
defined in `core.internal.newaa'.
D runtime changes:
- Import latest fixes from v2.112.0-beta.1.
Phobos changes:
- Import latest fixes from v2.112.0-beta.1.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd e1f6680f50.
* Make-lang.in (D_FRONTEND_OBJS): Remove d/gluelayer.o, d/iasm.o,
d/iasmgcc.o. Add d/iasm-package.o, d/iasm-gcc.o.
(d/iasm-%.o): New recipe.
* d-convert.cc (convert_expr): Remove library call to dynamic_cast.
* d-lang.cc (d_init_options): Set errorSupplementLimit parameter.
* decl.cc (DeclVisitor::visit): Update for new front-end interface.
* expr.cc (ExprVisitor::visit (EqualExp *)): Update for front-end
lowering expression using templates.
(ExprVisitor::visit (InExp *)): Likewise.
(ExprVisitor::visit (IndexExp *)): Likewise.
(ExprVisitor::visit (CastExp *)): Likewise.
(ExprVisitor::visit (RemoveExp *)): Likewise.
(ExprVisitor::visit (AddrExp *)): Likewise.
(ExprVisitor::visit (NewExp *)): Likewise.
(ExprVisitor::visit (ArrayLiteralExp *)): Likewise.
(ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise.
* imports.cc (ImportVisitor::visit (AliasDeclaration *)): Update for
new front-end interface.
* runtime.def (DYNAMIC_CAST): Remove.
(INTERFACE_CAST): Remove.
(ARRAYLITERALTX): Remove.
(ADEQ2): Remove.
(ASSOCARRAYLITERALTX): Remove.
(AANEW): Remove.
(AAEQUAL): Remove.
(AAINX): Remove.
(AAGETY): Remove.
(AAGETRVALUEX): Remove.
(AADELX): Remove.
* typeinfo.cc (TypeInfoVisitor::visit): Layout xopEquals and xtoHash
in TypeInfo_AssociativeArray.
(create_typeinfo): Add new fields to internal typeinfo.
(check_typeinfo_type): Print instantiation trace of error.
* types.cc (TypeVisitor::visit (TypeStruct *)): Update for new
front-end interface.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime e1f6680f50.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add
core/internal/cast_.d. Remove rt/aaA.d, rt/adi.d, rt/cast_.d.
(DRUNTIME_DSOURCES_POSIX): Add core/sys/posix/endian.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos f87979028.
* src/Makefile.am (PHOBOS_DSOURCES): Add std/internal/entropy.d.
* src/Makefile.in: Regenerate.
* testsuite/libphobos.aa/test_aa.d: Adjust test.
* testsuite/libphobos.init_fini/custom_gc.d: Likewise.
gcc/testsuite/ChangeLog:
* gdc.dg/asm1.d: Adjust test.
* gdc.dg/asm5.d: Likewise.
* gdc.dg/pr100967.d: Likewise.
* gdc.dg/rtti1.d: Likewise.
* gdc.dg/rtti2.d: New test.
Diff:
---
gcc/d/Make-lang.in | 9 +-
gcc/d/d-convert.cc | 7 -
gcc/d/d-lang.cc | 1 +
gcc/d/decl.cc | 8 +-
gcc/d/dmd/MERGE | 2 +-
gcc/d/dmd/README.md | 43 +-
gcc/d/dmd/access.d | 1 +
gcc/d/dmd/aggregate.d | 161 +-
gcc/d/dmd/aggregate.h | 3 -
gcc/d/dmd/arrayop.d | 1 +
gcc/d/dmd/astenums.d | 17 +-
gcc/d/dmd/attrib.d | 7 +-
gcc/d/dmd/canthrow.d | 2 +-
gcc/d/dmd/clone.d | 28 +-
gcc/d/dmd/common/bitfields.d | 69 +-
gcc/d/dmd/common/outbuffer.d | 78 +-
gcc/d/dmd/common/outbuffer.h | 2 +-
gcc/d/dmd/cond.d | 4 +-
gcc/d/dmd/constfold.d | 7 +-
gcc/d/dmd/cparse.d | 80 +-
gcc/d/dmd/ctfeexpr.d | 25 +-
gcc/d/dmd/cxxfrontend.d | 56 +-
gcc/d/dmd/dcast.d | 4 +-
gcc/d/dmd/dclass.d | 3 -
gcc/d/dmd/declaration.d | 184 +-
gcc/d/dmd/declaration.h | 15 +-
gcc/d/dmd/delegatize.d | 5 +
gcc/d/dmd/denum.d | 3 +-
gcc/d/dmd/dimport.d | 7 -
gcc/d/dmd/dinterpret.d | 525 +-
gcc/d/dmd/dmodule.d | 139 +-
gcc/d/dmd/dscope.d | 21 +-
gcc/d/dmd/dstruct.d | 172 -
gcc/d/dmd/dsymbol.d | 52 +-
gcc/d/dmd/dsymbol.h | 6 +-
gcc/d/dmd/dsymbolsem.d | 971 +++-
gcc/d/dmd/dtemplate.d | 5619 ++++----------------
gcc/d/dmd/dtoh.d | 6 +-
gcc/d/dmd/dversion.d | 1 -
gcc/d/dmd/enum.h | 2 +-
gcc/d/dmd/enumsem.d | 4 +-
gcc/d/dmd/escape.d | 2 +-
gcc/d/dmd/expression.d | 122 +-
gcc/d/dmd/expression.h | 11 +
gcc/d/dmd/expressionsem.d | 1775 +++++--
gcc/d/dmd/file_manager.d | 168 +-
gcc/d/dmd/func.d | 43 +-
gcc/d/dmd/funcsem.d | 170 +-
gcc/d/dmd/globals.d | 18 +-
gcc/d/dmd/globals.h | 16 +-
gcc/d/dmd/gluelayer.d | 59 -
gcc/d/dmd/hdrgen.d | 1439 ++---
gcc/d/dmd/iasm/gcc.d | 780 +++
gcc/d/dmd/{iasm.d => iasm/package.d} | 23 +-
gcc/d/dmd/iasmgcc.d | 604 ---
gcc/d/dmd/id.d | 22 +-
gcc/d/dmd/identifier.d | 10 +-
gcc/d/dmd/import.h | 1 -
gcc/d/dmd/importc.d | 8 +-
gcc/d/dmd/lambdacomp.d | 1 +
gcc/d/dmd/lexer.d | 8 +-
gcc/d/dmd/mangle/cpp.d | 2 +-
gcc/d/dmd/mangle/package.d | 15 +-
gcc/d/dmd/module.h | 24 +-
gcc/d/dmd/mtype.d | 323 +-
gcc/d/dmd/mtype.h | 9 +-
gcc/d/dmd/mustuse.d | 1 -
gcc/d/dmd/nogc.d | 31 +-
gcc/d/dmd/ob.d | 5 +-
gcc/d/dmd/objc.d | 5 +-
gcc/d/dmd/opover.d | 31 +-
gcc/d/dmd/optimize.d | 9 +-
gcc/d/dmd/parse.d | 115 +-
gcc/d/dmd/root/array.d | 28 +
gcc/d/dmd/root/filename.d | 17 +-
gcc/d/dmd/root/hash.d | 2 +-
gcc/d/dmd/safe.d | 3 +-
gcc/d/dmd/scope.h | 7 +-
gcc/d/dmd/semantic2.d | 42 +-
gcc/d/dmd/semantic3.d | 150 +-
gcc/d/dmd/sideeffect.d | 8 +-
gcc/d/dmd/statement.d | 18 +-
gcc/d/dmd/statement.h | 14 +-
gcc/d/dmd/statementsem.d | 187 +-
gcc/d/dmd/target.d | 4 +-
gcc/d/dmd/template.h | 16 +-
gcc/d/dmd/templatesem.d | 3440 +++++++++++-
gcc/d/dmd/tokens.d | 2 +-
gcc/d/dmd/traits.d | 15 +-
gcc/d/dmd/typesem.d | 417 +-
gcc/d/dmd/typinf.d | 25 +-
gcc/d/dmd/visitor/foreachvar.d | 6 +-
gcc/d/dmd/visitor/postorder.d | 36 +
gcc/d/expr.cc | 299 +-
gcc/d/imports.cc | 2 +-
gcc/d/runtime.def | 40 -
gcc/d/typeinfo.cc | 24 +-
gcc/d/types.cc | 2 +-
gcc/testsuite/gdc.dg/asm1.d | 8 +-
gcc/testsuite/gdc.dg/asm5.d | 2 +-
gcc/testsuite/gdc.dg/pr100967.d | 8 +-
gcc/testsuite/gdc.dg/rtti1.d | 23 +-
gcc/testsuite/gdc.dg/rtti2.d | 29 +
gcc/testsuite/gdc.test/compilable/b1215.d | 2 +-
.../gdc.test/compilable/extra-files/header1.d | 4 +-
.../gdc.test/compilable/extra-files/test21331.d | 17 +
.../gdc.test/compilable/extra-files/test21359a.d | 3 +
.../gdc.test/compilable/extra-files/test21359b.d | 11 +
gcc/testsuite/gdc.test/compilable/imports/h20184.h | 1 +
gcc/testsuite/gdc.test/compilable/interpret4.d | 17 +
gcc/testsuite/gdc.test/compilable/mixintype.d | 6 +-
gcc/testsuite/gdc.test/compilable/parens_inc.d | 5 +-
gcc/testsuite/gdc.test/compilable/shared.d | 4 +-
gcc/testsuite/gdc.test/compilable/test14838.d | 2 +-
gcc/testsuite/gdc.test/compilable/test17146.d | 2 +-
gcc/testsuite/gdc.test/compilable/test20100.d | 4 +-
gcc/testsuite/gdc.test/compilable/test20184.d | 5 +
gcc/testsuite/gdc.test/compilable/test20365.d | 20 +
gcc/testsuite/gdc.test/compilable/test21331.sh | 11 +
gcc/testsuite/gdc.test/compilable/test21359.sh | 15 +
gcc/testsuite/gdc.test/compilable/test21416.d | 17 +
gcc/testsuite/gdc.test/compilable/test21476.d | 13 +
gcc/testsuite/gdc.test/compilable/test23169.d | 2 +-
gcc/testsuite/gdc.test/compilable/test3004.d | 2 +-
gcc/testsuite/gdc.test/compilable/testgotoskips.d | 10 +
gcc/testsuite/gdc.test/compilable/testsctreturn.d | 2 +-
.../compilable/traits_getFunctionAttributes.d | 4 +-
gcc/testsuite/gdc.test/compilable/vcg-ast.d | 2 +
gcc/testsuite/gdc.test/compilable/warn3882.d | 38 +
.../gdc.test/fail_compilation/aa_assign.d | 13 +
gcc/testsuite/gdc.test/fail_compilation/aaerrors.d | 43 +
.../gdc.test/fail_compilation/biterrors.d | 4 +-
.../gdc.test/fail_compilation/biterrors2.d | 6 +-
.../gdc.test/fail_compilation/biterrors3.d | 2 +-
.../gdc.test/fail_compilation/biterrors4.d | 2 +-
.../gdc.test/fail_compilation/biterrors5.d | 15 +-
.../gdc.test/fail_compilation/diag13320.d | 12 +-
.../gdc.test/fail_compilation/diag16976.d | 64 +-
gcc/testsuite/gdc.test/fail_compilation/diag7420.d | 15 +-
.../gdc.test/fail_compilation/discard_value.d | 2 +-
.../gdc.test/fail_compilation/fail13756.d | 9 +-
.../gdc.test/fail_compilation/fail20365.d | 29 +
.../gdc.test/fail_compilation/fail21414.d | 47 +
.../gdc.test/fail_compilation/fail21660.d | 57 +
.../gdc.test/fail_compilation/fail21693.d | 17 +
.../gdc.test/fail_compilation/fail22749.d | 2 +-
gcc/testsuite/gdc.test/fail_compilation/fail6497.d | 11 +-
gcc/testsuite/gdc.test/fail_compilation/fail6795.d | 4 +-
gcc/testsuite/gdc.test/fail_compilation/fix22108.d | 2 +-
.../gdc.test/fail_compilation/foreach_seq.d | 38 +
gcc/testsuite/gdc.test/fail_compilation/ice10938.d | 2 +-
gcc/testsuite/gdc.test/fail_compilation/ice13644.d | 2 +-
.../gdc.test/fail_compilation/issue21630.d | 18 +
.../gdc.test/fail_compilation/previewin3.d | 19 +
.../gdc.test/fail_compilation/pull12941.d | 8 +-
.../gdc.test/fail_compilation/retscope2.d | 2 +-
gcc/testsuite/gdc.test/fail_compilation/shared.d | 8 +-
.../gdc.test/fail_compilation/test15191.d | 4 +-
.../gdc.test/fail_compilation/test15704.d | 9 +-
.../gdc.test/fail_compilation/test18282.d | 2 +-
.../gdc.test/fail_compilation/test20881.d | 2 +-
.../gdc.test/fail_compilation/test21408.d | 23 +
.../gdc.test/fail_compilation/test21429.d | 21 +
.../gdc.test/fail_compilation/test21477.d | 2 +-
.../gdc.test/fail_compilation/test21546.d | 8 +-
.../gdc.test/fail_compilation/test23710.d | 5 +-
.../gdc.test/fail_compilation/varargsstc.d | 6 +-
.../gdc.test/fail_compilation/verifyhookexist.d | 11 +-
gcc/testsuite/gdc.test/runnable/bit.d | 16 +
gcc/testsuite/gdc.test/runnable/bug19652.d | 2 +-
gcc/testsuite/gdc.test/runnable/constfold.d | 2 +-
gcc/testsuite/gdc.test/runnable/foreach5.d | 34 +
gcc/testsuite/gdc.test/runnable/mars1.d | 16 +
gcc/testsuite/gdc.test/runnable/placenew.d | 26 +
gcc/testsuite/gdc.test/runnable/sdtor.d | 17 +
gcc/testsuite/gdc.test/runnable/staticaa.d | 13 +
gcc/testsuite/gdc.test/runnable/test17487.d | 179 +
gcc/testsuite/gdc.test/runnable/test20473.d | 110 +
gcc/testsuite/gdc.test/runnable/test21429.d | 131 +
gcc/testsuite/gdc.test/runnable/test21435.d | 73 +
gcc/testsuite/gdc.test/runnable/test21660.d | 31 +
gcc/testsuite/gdc.test/runnable/test42.d | 4 +-
gcc/testsuite/gdc.test/runnable/testaa2.d | 52 +-
gcc/testsuite/gdc.test/runnable/testaa3.d | 24 +
gcc/testsuite/gdc.test/runnable/testscope2.d | 4 +-
libphobos/libdruntime/MERGE | 2 +-
libphobos/libdruntime/Makefile.am | 41 +-
libphobos/libdruntime/Makefile.in | 110 +-
libphobos/libdruntime/core/atomic.d | 2 +-
libphobos/libdruntime/core/checkedint.d | 50 +-
libphobos/libdruntime/core/gc/config.d | 6 +-
libphobos/libdruntime/core/gc/gcinterface.d | 30 +
libphobos/libdruntime/core/gc/registry.d | 43 +-
.../libdruntime/core/internal/array/appending.d | 204 +-
.../libdruntime/core/internal/array/capacity.d | 59 +
.../libdruntime/core/internal/array/construction.d | 132 +-
.../libdruntime/core/internal/array/duplication.d | 2 +-
.../libdruntime/core/internal/array/equality.d | 165 +-
libphobos/libdruntime/core/internal/array/utils.d | 66 +
libphobos/libdruntime/core/internal/cast_.d | 311 ++
libphobos/libdruntime/core/internal/convert.d | 6 +
libphobos/libdruntime/core/internal/gc/blkcache.d | 15 +-
.../core/internal/gc/impl/conservative/gc.d | 255 +-
.../libdruntime/core/internal/gc/impl/manual/gc.d | 10 +
.../libdruntime/core/internal/gc/impl/proto/gc.d | 27 +
libphobos/libdruntime/core/internal/gc/proxy.d | 2 +-
libphobos/libdruntime/core/internal/hash.d | 46 +-
libphobos/libdruntime/core/internal/lifetime.d | 25 +-
libphobos/libdruntime/core/internal/newaa.d | 1038 +++-
libphobos/libdruntime/core/internal/traits.d | 37 +-
libphobos/libdruntime/core/stdc/config.d | 17 +
libphobos/libdruntime/core/stdc/stdarg.d | 2 +
libphobos/libdruntime/core/stdcpp/string.d | 4 +-
libphobos/libdruntime/core/sys/linux/sched.d | 4 +
libphobos/libdruntime/core/sys/posix/dirent.d | 12 +-
libphobos/libdruntime/core/sys/posix/dlfcn.d | 27 +-
libphobos/libdruntime/core/sys/posix/endian.d | 60 +
libphobos/libdruntime/core/sys/posix/sched.d | 11 +-
libphobos/libdruntime/core/sys/posix/stdio.d | 58 +-
libphobos/libdruntime/core/sys/posix/stdlib.d | 13 +-
libphobos/libdruntime/core/sys/posix/sys/mman.d | 11 +-
libphobos/libdruntime/core/sys/posix/sys/stat.d | 12 +-
libphobos/libdruntime/core/sys/posix/sys/statvfs.d | 6 +-
libphobos/libdruntime/core/thread/threadbase.d | 8 +
libphobos/libdruntime/object.d | 397 +-
libphobos/libdruntime/rt/aaA.d | 867 ---
libphobos/libdruntime/rt/adi.d | 73 -
libphobos/libdruntime/rt/cast_.d | 208 -
libphobos/libdruntime/rt/lifetime.d | 264 +-
libphobos/src/MERGE | 2 +-
libphobos/src/Makefile.am | 9 +-
libphobos/src/Makefile.in | 11 +-
libphobos/src/index.dd | 5 +
libphobos/src/std/algorithm/iteration.d | 7 +
libphobos/src/std/algorithm/mutation.d | 2 +-
libphobos/src/std/algorithm/searching.d | 10 +
libphobos/src/std/ascii.d | 1 +
libphobos/src/std/container/rbtree.d | 25 +-
libphobos/src/std/datetime/date.d | 35 +-
libphobos/src/std/datetime/systime.d | 11 +
libphobos/src/std/datetime/timezone.d | 26 +-
.../allocator/building_blocks/kernighan_ritchie.d | 20 +-
libphobos/src/std/getopt.d | 30 +-
libphobos/src/std/internal/entropy.d | 918 ++++
libphobos/src/std/internal/math/gammafunction.d | 11 +-
libphobos/src/std/mathspecial.d | 39 +-
libphobos/src/std/numeric.d | 52 +-
libphobos/src/std/random.d | 100 +-
libphobos/src/std/range/package.d | 23 +-
libphobos/src/std/string.d | 5 +
libphobos/src/std/traits.d | 21 +-
libphobos/src/std/typecons.d | 18 +-
libphobos/testsuite/libphobos.aa/test_aa.d | 41 +
.../testsuite/libphobos.init_fini/custom_gc.d | 10 +
254 files changed, 15322 insertions(+), 11421 deletions(-)
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 9f048bb4e5d1..9f91346290cc 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -135,10 +135,9 @@ D_FRONTEND_OBJS = \
d/func.o \
d/funcsem.o \
d/globals.o \
- d/gluelayer.o \
d/hdrgen.o \
- d/iasm.o \
- d/iasmgcc.o \
+ d/iasm-package.o \
+ d/iasm-gcc.o \
d/id.o \
d/identifier.o \
d/impcnvtab.o \
@@ -420,6 +419,10 @@ d/common-%.o: d/dmd/common/%.d
$(DCOMPILE) $(D_INCLUDES) $<
$(DPOSTCOMPILE)
+d/iasm-%.o: d/dmd/iasm/%.d
+ $(DCOMPILE) $(D_INCLUDES) $<
+ $(DPOSTCOMPILE)
+
d/mangle-%.o: d/dmd/mangle/%.d
$(DCOMPILE) $(D_INCLUDES) $<
$(DPOSTCOMPILE)
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index 81a1b3cd3cfb..30874e72c0dc 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -448,13 +448,6 @@ convert_expr (tree exp, Type *etype, Type *totype)
break;
}
-
- /* The offset can only be determined at run-time, do dynamic cast. */
- libcall_fn libcall = cdfrom->isInterfaceDeclaration ()
- ? LIBCALL_INTERFACE_CAST : LIBCALL_DYNAMIC_CAST;
-
- return build_libcall (libcall, totype, 2, exp,
- build_address (get_classinfo_decl (cdto)));
}
/* else default conversion. */
break;
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 4dc8eede74ad..eed1ee97fe97 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -304,6 +304,7 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options)
global.params.useDeprecated = DIAGNOSTICinform;
global.params.useWarnings = DIAGNOSTICoff;
global.params.v.errorLimit = flag_max_errors;
+ global.params.v.errorSupplementLimit = flag_max_errors;
global.params.v.messageStyle = MessageStyle::gnu;
/* Extra GDC-specific options. */
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 0b915b5632a4..8e740aedc997 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -449,7 +449,7 @@ public:
if (dmd::isError (d)|| !d->members)
return;
- if (!d->needsCodegen ())
+ if (!dmd::needsCodegen (d))
return;
for (size_t i = 0; i < d->members->length; i++)
@@ -766,7 +766,7 @@ public:
Expression *ie = dmd::initializerToExpression (d->_init);
add_stmt (build_expr (ie));
- Expression *e = d->type->defaultInitLiteral (d->loc);
+ Expression *e = dmd::defaultInitLiteral (d->type, d->loc);
add_stmt (build_expr (e));
}
@@ -775,7 +775,7 @@ public:
if (d->aliasTuple)
{
- this->build_dsymbol (d->toAlias ());
+ this->build_dsymbol (dmd::toAlias (d));
return;
}
@@ -834,7 +834,7 @@ public:
DECL_INITIAL (decl) = layout_struct_initializer (ts->sym);
else
{
- Expression *e = d->type->defaultInitLiteral (d->loc);
+ Expression *e = dmd::defaultInitLiteral (d->type, d->loc);
DECL_INITIAL (decl) = build_expr (e, true);
}
}
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 62d90e5770b5..a9235246e938 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-1017635a9636ef6a7a4bda35b1e091875d829871
+e1f6680f50d147846316c2fa3363461a2aa7ac1d
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 2e93d26fe853..f10b162d2745 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -35,6 +35,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
| [mars.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mars.d) | Argument parsing, path manipulation. |
| [cli.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cli.d) | Define the command line interface |
| [dmdparams.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmdparams.d) | DMD-specific parameters |
+| [dmsc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmsc.d) | Configures and initializes the back-end |
| [globals.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/globals.d) | Define a structure storing command line options |
| [dinifile.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) |
| [vsoptions.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking |
@@ -170,9 +171,10 @@ Note that these groups have no strict meaning, the category assignments are a bi
| File | Purpose |
|-------------------------------------------------------------------------|-------------------------------------------|
-| [iasm.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasm.d) | Inline assembly depending on the compiler |
-| [iasmdmd.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasmdmd.d) | Inline assembly for DMD |
-| [iasmgcc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasmgcc.d) | Inline assembly for GDC |
+| [iasm/package.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasm/package.d) | Inline assembly depending on the compiler |
+| [iasm/dmdx86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasm/dmd.d) | Inline assembly for DMD X86_64 |
+| [iasm/dmdaarch64.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasm/aarch64.d) | Inline assembly for DMD AArch64 |
+| [iasm/gcc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasm/gcc.d) | Inline assembly for GDC |
**Other**
@@ -208,27 +210,28 @@ Note that these groups have no strict meaning, the category assignments are a bi
| [lib/scanmach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/scanmach.d) | Extract symbol names from a library in Mach-O format |
| [lib/scanmscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/scanmscoff.d) | Extract symbol names from a library in COFF format |
+
+### ABI
+| File | Purpose |
+| [argtypes_x86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_x86.d) | Convert a D type into simple (register) types for the 32-bit x86 ABI |
+| [argtypes_sysv_x64.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_sysv_x64.d) | 'argtypes' for the x86_64 System V ABI |
+| [argtypes_aarch64.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_aarch64.d) | 'argtypes' for the AArch64 ABI |
### Code generation / back-end interfacing
| File | Purpose |
|---------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
-| [dmsc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmsc.d) | Configures and initializes the back-end |
-| [toobj.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/toobj.d) | Convert an AST that went through all semantic phases into an object file |
-| [toir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/toir.d) | Convert Dsymbols intermediate representation |
-| [e2ir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/e2ir.d) | Convert Expressions to intermediate representation |
-| [s2ir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/s2ir.d) | Convert Statements to intermediate representation |
-| [stmtstate.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/stmtstate.d) | Used to help transform statement AST into flow graph |
-| [toctype.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/toctype.d) | Convert a D type to a type the back-end understands |
-| [tocsym.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/tocsym.d) | Convert a D symbol to a symbol the linker understands (with mangled name) |
-| [argtypes_x86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_x86.d) | Convert a D type into simple (register) types for the 32-bit x86 ABI |
-| [argtypes_sysv_x64.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_sysv_x64.d) | 'argtypes' for the x86_64 System V ABI |
-| [argtypes_aarch64.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_aarch64.d) | 'argtypes' for the AArch64 ABI |
-| [glue.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/glue.d) | Generate the object file for function declarations |
-| [gluelayer.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/gluelayer.d) | Declarations for back-end functions that the front-end invokes |
-| [todt.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/todt.d) | Convert initializers into structures that the back-end will add to the data segment |
-| [tocvdebug.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/tovcdebug.d) | Generate debug info in the CV4 debug format. |
-| [objc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/objc.d) | Objective-C interfacing |
-| [objc_glue.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/objc_glue.d) | Glue code for Objective-C interop. |
+| [stmtstate.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/stmtstate.d) | Used to help transform statement AST into flow graph |
+| [objc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/objc.d) | Objective-C interfacing |
+| [irgen/toobj.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/toobj.d) | Convert an AST that went through all semantic phases into an object file|
+| [irgen/toir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/toir.d) | Convert Dsymbols intermediate representation |
+| [irgen/e2ir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/e2ir.d) | Convert Expressions to intermediate representation |
+| [irgen/s2ir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/s2ir.d) | Convert Statements to intermediate representation |
+| [irgen/toctype.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/toctype.d) | Convert a D type to a type the back-end understands |
+| [irgen/tocsym.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/tocsym.d) | Convert a D symbol to a symbol the linker understands (with mangled name) |
+| [irgen/package.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/package.d) | Generate the object file for function declarations |
+| [irgen/todt.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/todt.d) | Convert initializers into structures that the back-end will add to the data segment |
+| [irgen/tocvdebug.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/tovcdebug.d)| Generate debug info in the CV4 debug format. |
+| [irgen/objc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/irgen/objc.d)| irgen code for Objective-C interop. |
**Name mangling**
diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d
index eaaa288cb4a2..1871f601b6ef 100644
--- a/gcc/d/dmd/access.d
+++ b/gcc/d/dmd/access.d
@@ -20,6 +20,7 @@ import dmd.dmodule;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
+import dmd.dsymbolsem : toAlias;
import dmd.errors;
import dmd.expression;
import dmd.funcsem : overloadApply;
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index 6359674d4471..d547bb78626c 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -25,19 +25,17 @@ import dmd.declaration;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
-import dmd.dsymbolsem : dsymbolSemantic, determineFields, search, determineSize, include;
+import dmd.dsymbolsem : determineSize;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
import dmd.func;
-import dmd.globals;
import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.tokens;
-import dmd.typesem : defaultInit, addMod, size;
import dmd.visitor;
/**
@@ -171,7 +169,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
sc2.parent = this;
sc2.inunion = isUnionDeclaration();
sc2.visibility = Visibility(Visibility.Kind.public_);
- sc2.explicitVisibility = 0;
+ sc2.explicitVisibility = false;
sc2.aligndecl = null;
sc2.userAttribDecl = null;
sc2.namespace = null;
@@ -187,7 +185,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return fields.length - isNested() - (vthis2 !is null);
}
- override final uinteger_t size(Loc loc)
+ override final ulong size(Loc loc)
{
//printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
bool ok = determineSize(this, loc);
@@ -195,86 +193,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return ok ? structsize : SIZE_INVALID;
}
- /***************************************
- * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
- * field initializers have unique memory space on instance.
- * Returns:
- * true if any errors happen.
- */
- extern (D) final bool checkOverlappedFields()
- {
- //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
- assert(sizeok == Sizeok.done);
- size_t nfields = fields.length;
- if (isNested())
- {
- auto cd = isClassDeclaration();
- if (!cd || !cd.baseClass || !cd.baseClass.isNested())
- nfields--;
- if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
- nfields--;
- }
- bool errors = false;
-
- // Fill in missing any elements with default initializers
- foreach (i; 0 .. nfields)
- {
- auto vd = fields[i];
- if (vd.errors)
- {
- errors = true;
- continue;
- }
-
- const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();
-
- // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
- foreach (j; 0 .. nfields)
- {
- if (i == j)
- continue;
- auto v2 = fields[j];
- if (v2.errors)
- {
- errors = true;
- continue;
- }
- if (!vd.isOverlappedWith(v2))
- continue;
-
- // vd and v2 are overlapping.
- vd.overlapped = true;
- v2.overlapped = true;
-
- if (!MODimplicitConv(vd.type.mod, v2.type.mod))
- v2.overlapUnsafe = true;
- if (!MODimplicitConv(v2.type.mod, vd.type.mod))
- vd.overlapUnsafe = true;
-
- if (i > j)
- continue;
-
- if (!v2._init)
- continue;
-
- if (v2._init.isVoidInitializer())
- continue;
-
- if (vd._init && !vdIsVoidInit && v2._init)
- {
- .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
- errors = true;
- }
- else if (v2._init && i < j)
- {
- .error(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
- v2.toChars(), dmd.hdrgen.toChars(v2._init), vd.toChars());
- errors = true;
- }
- }
- }
- return errors;
- }
override final Type getType()
{
@@ -433,46 +351,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return visibility.kind == Visibility.Kind.export_;
}
- /*******************************************
- * Look for constructor declaration.
- */
- extern (D) final Dsymbol searchCtor()
- {
- auto s = this.search(Loc.initial, Id.ctor);
- if (s)
- {
- if (!(s.isCtorDeclaration() ||
- s.isTemplateDeclaration() ||
- s.isOverloadSet()))
- {
- error(s.loc, "%s name `__ctor` is not allowed", s.kind);
- errorSupplemental(s.loc, "identifiers starting with `__` are reserved for internal use");
- errors = true;
- s = null;
- }
- }
- if (s && s.toParent() != this)
- s = null; // search() looks through ancestor classes
- if (s)
- {
- // Finish all constructors semantics to determine this.noDefaultCtor.
- static int searchCtor(Dsymbol s, void*)
- {
- auto f = s.isCtorDeclaration();
- if (f && f.semanticRun == PASS.initial)
- f.dsymbolSemantic(null);
- return 0;
- }
-
- for (size_t i = 0; i < members.length; i++)
- {
- auto sm = (*members)[i];
- sm.apply(&searchCtor, null);
- }
- }
- return s;
- }
-
override final Visibility visible() pure nothrow @nogc @safe
{
return visibility;
@@ -499,39 +377,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
}
}
-/*********************************
- * Iterate this dsymbol or members of this scoped dsymbol, then
- * call `fp` with the found symbol and `params`.
- * Params:
- * symbol = the dsymbol or parent of members to call fp on
- * fp = function pointer to process the iterated symbol.
- * If it returns nonzero, the iteration will be aborted.
- * ctx = context parameter passed to fp.
- * Returns:
- * nonzero if the iteration is aborted by the return value of fp,
- * or 0 if it's completed.
- */
-int apply(Dsymbol symbol, int function(Dsymbol, void*) fp, void* ctx)
-{
- if (auto nd = symbol.isNspace())
- {
- return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
- }
- if (auto ad = symbol.isAttribDeclaration())
- {
- return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
- }
- if (auto tm = symbol.isTemplateMixin())
- {
- if (tm._scope) // if fwd reference
- dsymbolSemantic(tm, null); // try to resolve it
-
- return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
- }
-
- return fp(symbol, ctx);
-}
-
/****************************
* Do byte or word alignment as necessary.
* Align sizes of 0, as we may not know array sizes yet.
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index d89755cea27c..3c4c84a09398 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -171,7 +171,6 @@ public:
static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
StructDeclaration *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
- bool isPOD();
bool zeroInit() const; // !=0 if initialize with 0 fill
bool zeroInit(bool v);
bool hasIdentityAssign() const; // true if has identity opAssign
@@ -194,7 +193,6 @@ public:
unsigned numArgTypes() const;
Type *argType(unsigned index);
- bool hasRegularCtor(bool ignoreDisabled = false);
};
class UnionDeclaration final : public StructDeclaration
@@ -273,7 +271,6 @@ public:
ThreeState isabstract; // if abstract class
Baseok baseok; // set the progress of base classes resolving
ObjcClassDeclaration objc; // Data for a class declaration that is needed for the Objective-C integration
- Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
const char *toPrettyChars(bool QualifyTypes = false) override;
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index 7d25e185129f..ea6f87f60ec6 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -31,6 +31,7 @@ import dmd.location;
import dmd.mtype;
import dmd.common.outbuffer;
import dmd.tokens;
+import dmd.typesem : isAssignable;
import dmd.visitor;
/**********************************************
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
index b71b6c40aeb0..5cde5b334c5e 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -19,12 +19,12 @@ enum Sizeok : ubyte
}
/// D Language version
-enum Edition : ubyte
+enum Edition : ushort
{
- none,
- legacy, /// Before the introduction of editions
- v2024, /// Experimental first new edition
- latest = v2024 /// Newest edition that this compiler knows of
+ v2023 = 2023, /// Edition.min for default edition
+ v2024, /// first Edition
+ v2025, /// next Edition
+ /// use Edition.max for latest edition
}
enum Baseok : ubyte
@@ -77,9 +77,10 @@ enum STC : ulong // transfer changes to declaration.h
ref_ = 0x4_0000, /// `ref`
scope_ = 0x8_0000, /// `scope`
- scopeinferred = 0x20_0000, /// `scope` has been inferred and should not be part of mangling, `scope_` must also be set
- return_ = 0x40_0000, /// 'return ref' or 'return scope' for function parameters
- returnScope = 0x80_0000, /// if `ref return scope` then resolve to `ref` and `return scope`
+ scopeinferred = 0x10_0000, /// `scope` has been inferred and should not be part of mangling, `scope_` must also be set
+ return_ = 0x20_0000, /// 'return ref' or 'return scope' for function parameters
+ returnScope = 0x40_0000, /// if `ref return scope` then resolve to `ref` and `return scope`
+ returnRef = 0x80_0000, /// if `return ref`
returninferred = 0x100_0000, /// `return` has been inferred and should not be part of mangling, `return_` must also be set
immutable_ = 0x200_0000, /// `immutable`
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index a03e7bbdc0e5..97dfa5ef683f 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -32,10 +32,8 @@ import dmd.declaration;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem : include;
import dmd.expression;
import dmd.func;
-import dmd.globals;
import dmd.hdrgen : visibilityToBuffer;
import dmd.id;
import dmd.identifier;
@@ -80,7 +78,7 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
* the scope after it used.
*/
extern (D) static Scope* createNewScope(Scope* sc, STC stc, LINK linkage,
- CPPMANGLE cppmangle, Visibility visibility, int explicitVisibility,
+ CPPMANGLE cppmangle, Visibility visibility, bool explicitVisibility,
AlignDeclaration aligndecl, PragmaDeclaration inlining)
{
Scope* sc2 = sc;
@@ -414,8 +412,7 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
this.dsym = DSYM.alignDeclaration;
if (exp)
{
- exps = new Expressions();
- exps.push(exp);
+ exps = new Expressions(exp);
}
}
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index 96acf0552931..bd4aa197ab93 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -20,7 +20,7 @@ import dmd.astenums;
import dmd.blockexit : BE, checkThrow;
import dmd.declaration;
import dmd.dsymbol;
-import dmd.dsymbolsem : include;
+import dmd.dsymbolsem : include, toAlias;
import dmd.errorsink;
import dmd.expression;
import dmd.expressionsem : errorSupplementalInferredAttr;
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index a21f5a05be78..f3f359ee3129 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -300,8 +300,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
stc = (stc & ~STC.safe) | STC.trusted;
}
- auto fparams = new Parameters();
- fparams.push(new Parameter(loc, STC.nodtor, sd.type, Id.p, null, null));
+ auto fparams = new Parameters(new Parameter(loc, STC.nodtor, sd.type, Id.p, null, null));
auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_);
auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.opAssign, stc, tf);
fop.storage_class |= STC.inference;
@@ -574,8 +573,8 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
scx.eSink = sc.eSink;
/* const bool opEquals(ref const S s);
*/
- auto parameters = new Parameters();
- parameters.push(new Parameter(Loc.initial, STC.ref_ | STC.const_, sd.type, null, null, null));
+ auto parameters = new Parameters(new Parameter(Loc.initial, STC.ref_ | STC.const_, sd.type,
+ null, null, null));
tfeqptr = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d);
tfeqptr.mod = MODFlags.const_;
tfeqptr = tfeqptr.typeSemantic(Loc.initial, &scx).isTypeFunction();
@@ -602,8 +601,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
}
Loc declLoc; // loc is unnecessary so __xopEquals is never called directly
Loc loc; // loc is unnecessary so errors are gagged
- auto parameters = new Parameters();
- parameters.push(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null));
+ auto parameters = new Parameters(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null));
auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d, STC.const_);
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopEquals;
@@ -649,8 +647,8 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
scx.eSink = sc.eSink;
/* const int opCmp(ref const S s);
*/
- auto parameters = new Parameters();
- parameters.push(new Parameter(Loc.initial, STC.ref_ | STC.const_, sd.type, null, null, null));
+ auto parameters = new Parameters(new Parameter(Loc.initial, STC.ref_ | STC.const_, sd.type,
+ null, null, null));
tfcmpptr = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d);
tfcmpptr.mod = MODFlags.const_;
tfcmpptr = tfcmpptr.typeSemantic(Loc.initial, &scx).isTypeFunction();
@@ -726,8 +724,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
}
Loc declLoc; // loc is unnecessary so __xopCmp is never called directly
Loc loc; // loc is unnecessary so errors are gagged
- auto parameters = new Parameters();
- parameters.push(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null));
+ auto parameters = new Parameters(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null));
auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d, STC.const_);
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopCmp;
@@ -854,8 +851,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
//printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars());
Loc declLoc; // loc is unnecessary so __xtoHash is never called directly
Loc loc; // internal code should have no loc to prevent coverage
- auto parameters = new Parameters();
- parameters.push(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null));
+ auto parameters = new Parameters(new Parameter(loc, STC.ref_ | STC.const_, sd.type, Id.p, null, null));
auto tf = new TypeFunction(ParameterList(parameters), Type.thash_t, LINK.d, STC.nothrow_ | STC.trusted);
Identifier id = Id.xtoHash;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
@@ -872,6 +868,11 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
// workaround https://issues.dlang.org/show_bug.cgi?id=17968
" static if(is(T* : const(.object.Object)*)) " ~
" h = h * 33 + typeid(const(.object.Object)).getHash(cast(const void*)&p.tupleof[i]);" ~
+ // and another workaround for bitfields https://github.com/dlang/dmd/issues/20473
+ " else static if (!__traits(compiles, &p.tupleof[i])) {" ~
+ " auto t = p.tupleof[i];" ~
+ " h = h * 33 + typeid(T).getHash(cast(const void*)&t);" ~
+ " } " ~
" else " ~
" h = h * 33 + typeid(T).getHash(cast(const void*)&p.tupleof[i]);" ~
"return h;";
@@ -1561,10 +1562,9 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
*/
private CtorDeclaration generateCtorDeclaration(StructDeclaration sd, const STC paramStc, const STC funcStc, bool move)
{
- auto fparams = new Parameters();
auto structType = sd.type;
STC stc = move ? STC.none : STC.ref_; // the only difference between copy or move
- fparams.push(new Parameter(Loc.initial, paramStc | stc, structType, Id.p, null, null));
+ auto fparams = new Parameters(new Parameter(Loc.initial, paramStc | stc, structType, Id.p, null, null));
ParameterList pList = ParameterList(fparams);
auto tf = new TypeFunction(pList, structType, LINK.d, STC.ref_);
auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf);
diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d
index 72cb3e7d91c8..5732f9d385f6 100644
--- a/gcc/d/dmd/common/bitfields.d
+++ b/gcc/d/dmd/common/bitfields.d
@@ -10,18 +10,25 @@
*/
module dmd.common.bitfields;
+//version = Has_Bitfields; // does not work (yet) because hashOf doesn't work on bitfields
+version(Has_Bitfields)
+ version = Debugger_friendly; // without Has_Bitfields, this uses more space by using S
+
/**
* Generate code for bit fields inside a struct/class body
* Params:
* S = type of a struct with only boolean fields, which should become bit fields
* T = type of bit fields variable, must have enough bits to store all booleans
+ * field = if provided, assume it is declared and initialized elsewhere
+ * bitOff = start using bits at the given offset
* Returns: D code with a bit fields variable and getter / setter functions
*/
-extern (D) string generateBitFields(S, T)()
+extern (D) string generateBitFields(S, T, string field = "", int bitOff = 0, int ID = __LINE__)()
if (__traits(isUnsigned, T))
{
import core.bitop: bsr;
-
+ // if _fieldName provided, assume it declared and initialized elsewhere
+ enum fieldName = field.length == 0 ? "bitFields" : field;
string result = "extern (C++) pure nothrow @nogc @safe final {";
struct BitInfo
@@ -35,7 +42,7 @@ if (__traits(isUnsigned, T))
// Iterate over members to compute bit offset and bit size for each of them
enum BitInfo bitInfo = () {
BitInfo result;
- int bitOffset = 0;
+ int bitOffset = bitOff;
foreach (size_t i, mem; __traits(allMembers, S))
{
alias memType = typeof(__traits(getMember, S, mem));
@@ -55,22 +62,60 @@ if (__traits(isUnsigned, T))
static assert(bitInfo.totalSize <= T.sizeof * 8,
"sum of bit field size "~toString!(bitInfo.totalSize)~" exceeds storage type `"~T.stringof~"`");
+ version(Debugger_friendly)
+ {
+ // unique name needed to allow same name as in base class using `alias`, but without overloading
+ string bitfieldsName = fieldName ~ toString!(ID);
+ string bitfieldsRead = T.stringof~" "~bitfieldsName~"() const pure { return 0";
+ string bitfieldsWrite = "void "~bitfieldsName~"("~T.stringof~" v) {\n";
+ }
+
foreach (size_t i, mem; __traits(allMembers, S))
{
enum typeName = typeof(__traits(getMember, S, mem)).stringof;
enum shift = toString!(bitInfo.offset[i]);
enum sizeMask = toString!((1 << bitInfo.size[i]) - 1); // 0x01 for bool, 0xFF for ubyte etc.
- result ~= "
- "~typeName~" "~mem~"() const scope { return cast("~typeName~") ((bitFields >>> "~shift~") & "~sizeMask~"); }
- "~typeName~" "~mem~"("~typeName~" v) scope
+ version(Debugger_friendly)
+ {
+ string memacc = mem;
+ bitfieldsRead ~= "\n| (cast("~T.stringof~")("~memacc~" & "~sizeMask~") << "~shift~")";
+ bitfieldsWrite ~= memacc~" = cast("~typeName~")((v >> "~shift~") & "~sizeMask~");\n";
+ result ~= typeName~" "~mem;
+ version(Has_Bitfields)
+ result ~= " : "~toString!(bitInfo.size[i]);
+ enum meminit = __traits(getMember, S.init, mem);
+ result ~= " = "~meminit.stringof~";\n";
+ }
+ else
{
- bitFields &= ~("~sizeMask~" << "~shift~");
- bitFields |= v << "~shift~";
- return v;
- }";
+ result ~= "
+ "~typeName~" "~mem~"() const scope { return cast("~typeName~") (("~fieldName~" >>> "~shift~") & "~sizeMask~"); }
+ "~typeName~" "~mem~"("~typeName~" v) scope
+ {
+ "~fieldName~" &= ~("~sizeMask~" << "~shift~");
+ "~fieldName~" |= v << "~shift~";
+ return v;
+ }";
+ }
+ }
+ version(Debugger_friendly)
+ {
+ bitfieldsRead ~= ";\n}\n";
+ bitfieldsWrite ~= "}\n";
+ if (field.length == 0)
+ result ~= "alias "~fieldName~" = "~bitfieldsName~";\n";
+ result ~= bitfieldsRead ~ bitfieldsWrite;
+ result ~= "\n}\n";
+ return result;
+ }
+ else
+ {
+ result ~= "\n}\n";
+ enum TP initVal = bitInfo.initialValue;
+ if (field.length == 0)
+ result ~= " private "~T.stringof~" "~fieldName~" = " ~ toString!(initVal) ~ ";\n";
+ return result;
}
- enum TP initVal = bitInfo.initialValue;
- return result ~ "\n}\n private "~T.stringof~" bitFields = " ~ toString!(initVal) ~ ";\n";
}
///
diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
index 01fc3774002d..a5340ef8058c 100644
--- a/gcc/d/dmd/common/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -230,9 +230,11 @@ struct OutBuffer
offset += len;
}
- extern (C++) void write(const(void)* data, size_t nbytes) pure nothrow @system
+ alias put = write; // transition to output range which uses put()
+
+ extern (C++) void write(scope const(void)* data, size_t nbytes) pure nothrow @system
{
- write(data[0 .. nbytes]);
+ put(data[0 .. nbytes]);
}
void write(scope const(void)[] buf) pure nothrow @trusted
@@ -244,6 +246,23 @@ struct OutBuffer
offset += buf.length;
}
+ void write(scope string buf) pure nothrow @trusted // so write("hello") chooses this overload
+ {
+ if (doindent && !notlinehead)
+ indent();
+ reserve(buf.length);
+ memcpy(this.data.ptr + offset, buf.ptr, buf.length);
+ offset += buf.length;
+ }
+
+ extern (C++) void write(scope const(char)* s) pure nothrow @trusted
+ {
+ if (!s)
+ return;
+ import core.stdc.string : strlen;
+ put(s[0 .. strlen(s)]);
+ }
+
/**
* Writes a 16 bit value, no reserve check.
*/
@@ -262,7 +281,7 @@ struct OutBuffer
void write16(int v) nothrow
{
auto u = cast(ushort) v;
- write(&u, u.sizeof);
+ put(&u, u.sizeof);
}
/**
@@ -270,7 +289,7 @@ struct OutBuffer
*/
void write32(int v) nothrow @trusted
{
- write(&v, v.sizeof);
+ put(&v, v.sizeof);
}
/**
@@ -278,34 +297,31 @@ struct OutBuffer
*/
@trusted void write64(long v) nothrow
{
- write(&v, v.sizeof);
+ put(&v, v.sizeof);
}
/// Buffer will NOT be zero-terminated
extern (C++) void writestring(const(char)* s) pure nothrow @system
{
- if (!s)
- return;
- import core.stdc.string : strlen;
- write(s[0 .. strlen(s)]);
+ put(s);
}
/// ditto
void writestring(scope const(char)[] s) pure nothrow @safe
{
- write(s);
+ put(s);
}
/// ditto
void writestring(scope string s) pure nothrow @safe
{
- write(s);
+ put(s);
}
/// Buffer will NOT be zero-terminated, followed by newline
void writestringln(const(char)[] s) pure nothrow @safe
{
- writestring(s);
+ put(s);
writenl();
}
@@ -313,13 +329,13 @@ struct OutBuffer
*/
void writeStringz(const(char)* s) pure nothrow @system
{
- write(s[0 .. strlen(s)+1]);
+ put(s[0 .. strlen(s)+1]);
}
/// ditto
void writeStringz(const(char)[] s) pure nothrow @safe
{
- write(s);
+ put(s);
writeByte(0);
}
@@ -382,17 +398,26 @@ struct OutBuffer
* Writes an 8 bit byte, no reserve check.
*/
extern (C++) nothrow @safe
- void writeByten(int b)
+ void writeByten(ubyte b)
{
- this.data[offset++] = cast(ubyte) b;
+ this.data[offset++] = b;
}
- extern (C++) void writeByte(uint b) pure nothrow @safe
+ extern (C++) void writeByte(ubyte b) pure nothrow @safe
{
if (doindent && !notlinehead && b != '\n')
indent();
reserve(1);
- this.data[offset] = cast(ubyte)b;
+ this.data[offset] = b;
+ offset++;
+ }
+
+ void write(ubyte b) pure nothrow @safe
+ {
+ if (doindent && !notlinehead && b != '\n')
+ indent();
+ reserve(1);
+ this.data[offset] = b;
offset++;
}
@@ -502,14 +527,17 @@ struct OutBuffer
offset += 4;
}
- extern (C++) void write(const OutBuffer* buf) pure nothrow @trusted
+ extern (C++) void write(scope const OutBuffer* buf) pure nothrow @trusted
{
if (buf)
- {
- reserve(buf.offset);
- memcpy(data.ptr + offset, buf.data.ptr, buf.offset);
- offset += buf.offset;
- }
+ put(*buf);
+ }
+
+ void write(ref scope const OutBuffer buf) pure nothrow @trusted
+ {
+ reserve(buf.offset);
+ memcpy(data.ptr + offset, buf.data.ptr, buf.offset);
+ offset += buf.offset;
}
extern (C++) void fill0(size_t nbytes) pure nothrow @trusted
@@ -871,7 +899,7 @@ unittest
buf.prependbyte('x');
OutBuffer buf2;
buf2.writestring("mmm");
- buf.write(&buf2);
+ buf.put(&buf2);
char[] s = buf.extractSlice();
assert(s == "xdefabcmmm");
}
diff --git a/gcc/d/dmd/common/outbuffer.h b/gcc/d/dmd/common/outbuffer.h
index 62aca7a8014a..9630f1220157 100644
--- a/gcc/d/dmd/common/outbuffer.h
+++ b/gcc/d/dmd/common/outbuffer.h
@@ -53,7 +53,7 @@ public:
void writestring(const char *string);
void prependstring(const char *string);
void writenl(); // write newline
- void writeByte(unsigned b);
+ void writeByte(uint8_t b);
void writeUTF8(unsigned b);
void prependbyte(unsigned b);
void writewchar(unsigned w);
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index 31c01f1853e6..96c7db9086cd 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -29,7 +29,6 @@ import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.optimize;
-import dmd.typesem;
import dmd.common.outbuffer;
import dmd.rootobject;
import dmd.root.string;
@@ -211,10 +210,9 @@ extern (C++) final class StaticForeach : RootObject
auto sid = Identifier.generateId("Tuple");
auto sdecl = new StructDeclaration(loc, sid, false);
sdecl.storage_class |= STC.static_;
- sdecl.members = new Dsymbols();
auto fid = Identifier.idPool(tupleFieldName);
auto ty = new TypeTypeof(loc, new TupleExp(loc, e));
- sdecl.members.push(new VarDeclaration(loc, ty, fid, null, STC.none));
+ sdecl.members = new Dsymbols(new VarDeclaration(loc, ty, fid, null, STC.none));
auto r = cast(TypeStruct)sdecl.type;
if (global.params.useTypeInfo && Type.dtypeinfo)
r.vtinfo = TypeInfoStructDeclaration.create(r); // prevent typeinfo from going to object file
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index fad9c9ac44f6..1e0024e92cef 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -25,6 +25,7 @@ import dmd.declaration;
import dmd.dstruct;
import dmd.errors;
import dmd.expression;
+import dmd.expressionsem : getField;
import dmd.globals;
import dmd.location;
import dmd.mtype;
@@ -1432,8 +1433,7 @@ UnionExp Cat(Loc loc, Type type, Expression e1, Expression e2)
else
{
// Create an ArrayLiteralExp
- auto elements = new Expressions();
- elements.push(e);
+ auto elements = new Expressions(e);
emplaceExp!(ArrayLiteralExp)(&ue, e.loc, type, elements);
}
assert(ue.exp().type);
@@ -1674,8 +1674,7 @@ UnionExp Cat(Loc loc, Type type, Expression e1, Expression e2)
Type tb = t.toBasetype();
if (tb.ty == Tarray && tb.nextOf().equivalent(e.type))
{
- auto expressions = new Expressions();
- expressions.push(e);
+ auto expressions = new Expressions(e);
emplaceExp!(ArrayLiteralExp)(&ue, loc, t, expressions);
e = ue.exp();
}
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 70369ba20c7a..4a6e5195f5fd 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -655,8 +655,10 @@ final class CParser(AST) : Parser!AST
case TOK.asm_:
switch (peekNext())
{
+ case TOK.const_:
case TOK.goto_:
case TOK.inline:
+ case TOK.restrict:
case TOK.volatile:
case TOK.leftParenthesis:
s = cparseGnuAsm();
@@ -1474,7 +1476,7 @@ final class CParser(AST) : Parser!AST
* logical-OR-expression
* logical-OR-expression ? expression : conditional-expression
*/
- private AST.Expression cparseCondExp()
+ AST.Expression cparseCondExp()
{
const loc = token.loc;
@@ -1637,7 +1639,7 @@ final class CParser(AST) : Parser!AST
*/
private AST.Expression cparseConstantExp()
{
- return cparseAssignExp();
+ return cparseCondExp();
}
/*****************************
@@ -3437,6 +3439,11 @@ final class CParser(AST) : Parser!AST
cparseParens();
}
}
+ else if (token.value == TOK._Noreturn)
+ {
+ specifier.noreturn = true;
+ nextToken();
+ }
else if (token.value == TOK.restrict) // ImportC assigns no semantics to `restrict`, so just ignore the keyword.
nextToken();
else
@@ -3485,19 +3492,51 @@ final class CParser(AST) : Parser!AST
nextToken();
- // Consume all asm-qualifiers. As a future optimization, we could record
- // the `inline` and `volatile` storage classes against the statement.
- while (token.value == TOK.goto_ ||
- token.value == TOK.inline ||
- token.value == TOK.volatile)
- nextToken();
+ // Consume all asm-qualifiers.
+ enum AsmQualifiers { none = 0, goto_ = 1, inline = 2, volatile = 4, }
+ AsmQualifiers asmQualifiers;
+ while (1)
+ {
+ AsmQualifiers qual;
+ switch (token.value)
+ {
+ case TOK.goto_:
+ qual = AsmQualifiers.goto_;
+ goto Lcontinue;
+
+ case TOK.inline:
+ qual = AsmQualifiers.inline;
+ goto Lcontinue;
+
+ case TOK.volatile:
+ qual = AsmQualifiers.volatile;
+ goto Lcontinue;
+
+ Lcontinue:
+ if (asmQualifiers & qual)
+ error(token.loc, "duplicate `asm` qualifier `%s`", token.toChars());
+ else
+ asmQualifiers |= qual;
+ nextToken();
+ continue;
+
+ case TOK.const_:
+ case TOK.restrict:
+ error(token.loc, "`%s` is not a valid `asm` qualifier", token.toChars());
+ nextToken();
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
check(TOK.leftParenthesis);
if (token.value != TOK.string_)
error("string literal expected for Assembler Template, not `%s`", token.toChars());
Token* toklist = null;
Token** ptoklist = &toklist;
- //Identifier label = null;
auto statements = new AST.Statements();
int parens;
@@ -3524,21 +3563,6 @@ final class CParser(AST) : Parser!AST
error("matching `)` expected, not end of file");
break;
- case TOK.colonColon: // treat as two separate : tokens for iasmgcc
- *ptoklist = allocateToken();
- **ptoklist = this.token;
- (*ptoklist).value = TOK.colon;
- ptoklist = &(*ptoklist).next;
-
- *ptoklist = allocateToken();
- **ptoklist = this.token;
- (*ptoklist).value = TOK.colon;
- ptoklist = &(*ptoklist).next;
-
- *ptoklist = null;
- nextToken();
- continue;
-
default:
*ptoklist = allocateToken();
**ptoklist = this.token;
@@ -3550,7 +3574,11 @@ final class CParser(AST) : Parser!AST
if (toklist)
{
// Create AsmStatement from list of tokens we've saved
- AST.Statement s = new AST.AsmStatement(token.loc, toklist);
+ auto s = new AST.AsmStatement(token.loc, toklist);
+ if (asmQualifiers & AsmQualifiers.volatile)
+ s.isVolatile = true;
+ if (asmQualifiers & AsmQualifiers.inline)
+ s.isInline = true;
statements.push(s);
}
break;
@@ -6069,7 +6097,7 @@ final class CParser(AST) : Parser!AST
{
//printf("addSym() %s\n", s.toChars());
if (auto v = s.isVarDeclaration())
- v.isCmacro(true); // mark it as coming from a C #define
+ v.isCmacro = true; // mark it as coming from a C #define
if (auto td = s.isTemplateDeclaration())
td.isCmacro = true; // mark as coming from a C #define
/* If it's already defined, replace the earlier
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 2f577cea92f2..58a00341d4e0 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -26,7 +26,7 @@ import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
import dmd.func;
-import dmd.globals;
+import dmd.globals : dinteger_t, sinteger_t, uinteger_t;
import dmd.location;
import dmd.mtype;
import dmd.root.bitarray;
@@ -241,6 +241,7 @@ UnionExp copyLiteral(Expression e)
AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp();
r.type = aae.type;
r.lowering = aae.lowering;
+ r.loweringCtfe = aae.loweringCtfe;
r.ownedByCtfe = OwnedBy.ctfe;
return ue;
}
@@ -1459,7 +1460,7 @@ UnionExp ctfeCat(Loc loc, Type type, Expression e1, Expression e2)
/* Given an AA literal 'ae', and a key 'e2':
* Return ae[e2] if present, or NULL if not found.
*/
-Expression findKeyInAA(Loc loc, AssocArrayLiteralExp ae, Expression e2)
+Expression findKeyInAA(Loc loc, AssocArrayLiteralExp ae, Expression e2, size_t* pidx = null)
{
/* Search the keys backwards, in case there are duplicate keys
*/
@@ -1470,6 +1471,8 @@ Expression findKeyInAA(Loc loc, AssocArrayLiteralExp ae, Expression e2)
const int eq = ctfeEqual(loc, EXP.equal, ekey, e2);
if (eq)
{
+ if (pidx)
+ *pidx = i;
return (*ae.values)[i];
}
}
@@ -1583,11 +1586,6 @@ Expression ctfeCast(UnionExp* pue, Loc loc, Type type, Type to, Expression e, bo
*/
void assignInPlace(Expression dest, Expression src)
{
- if (!(dest.op == EXP.structLiteral || dest.op == EXP.arrayLiteral || dest.op == EXP.string_))
- {
- printf("invalid op %d %d\n", src.op, dest.op);
- assert(0);
- }
Expressions* oldelems;
Expressions* newelems;
if (dest.op == EXP.structLiteral)
@@ -1622,6 +1620,16 @@ void assignInPlace(Expression dest, Expression src)
sliceAssignStringFromArrayLiteral(dest.isStringExp(), src.isArrayLiteralExp(), 0);
return;
}
+ else if (dest.op == EXP.int64 && src.op == EXP.int64)
+ {
+ dest.isIntegerExp().setInteger(src.isIntegerExp().getInteger());
+ return;
+ }
+ else if (dest.op == EXP.float64 && src.op == EXP.float64)
+ {
+ dest.isRealExp().value = src.isRealExp().value;
+ return;
+ }
else
{
printf("invalid op %d %d\n", src.op, dest.op);
@@ -1829,6 +1837,9 @@ bool isCtfeValueValid(Expression newval)
(
(e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) ||
e1.op == EXP.variable ||
+ e1.op == EXP.int64 ||
+ e1.op == EXP.float64 ||
+ e1.op == EXP.string_ ||
e1.op == EXP.dotVariable && isCtfeReferenceValid(e1) ||
e1.op == EXP.index && isCtfeReferenceValid(e1) ||
e1.op == EXP.slice && e1.type.toBasetype().ty == Tsarray
diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d
index b61137ff20fa..ce474c9bbef1 100644
--- a/gcc/d/dmd/cxxfrontend.d
+++ b/gcc/d/dmd/cxxfrontend.d
@@ -26,12 +26,13 @@ import dmd.dtemplate /*: TemplateInstance, TemplateParameter, Tuple*/;
import dmd.errorsink : ErrorSink;
import dmd.expression /*: Expression*/;
import dmd.func : FuncDeclaration;
-import dmd.globals;
+import dmd.globals : dinteger_t, uinteger_t, JsonFieldFlags;
import dmd.identifier : Identifier;
import dmd.init : Initializer, NeedInterpret;
import dmd.location : Loc;
import dmd.mtype /*: Covariant, Type, Parameter, ParameterList*/;
import dmd.rootobject : RootObject;
+import dmd.semantic3;
import dmd.statement : Statement, AsmStatement, GccAsmStatement;
// NB: At some point in the future, we can switch to shortened function syntax.
@@ -132,7 +133,7 @@ void gendocfile(Module m, const char* ddoctext_ptr, size_t ddoctext_length,
*/
FuncDeclaration search_toString(StructDeclaration sd)
{
- return dmd.dstruct.search_toString(sd);
+ return dmd.semantic3.search_toString(sd);
}
/***********************************************************
@@ -205,6 +206,24 @@ void getLocalClasses(Module mod, ref ClassDeclarations aclasses)
return dmd.dsymbolsem.getLocalClasses(mod, aclasses);
}
+Dsymbol toAlias(Dsymbol s)
+{
+ import dmd.dsymbolsem;
+ return dmd.dsymbolsem.toAlias(s);
+}
+
+Dsymbol toAlias2(Dsymbol s)
+{
+ import dmd.dsymbolsem;
+ return dmd.dsymbolsem.toAlias2(s);
+}
+
+bool isPOD(StructDeclaration sd)
+{
+ import dmd.dsymbolsem;
+ return dmd.dsymbolsem.isPOD(sd);
+}
+
/***********************************************************
* dtemplate.d
*/
@@ -248,6 +267,11 @@ void printTemplateStats(bool listInstances, ErrorSink eSink)
return dmd.dtemplate.printTemplateStats(listInstances, eSink);
}
+void printInstantiationTrace(TemplateInstance ti)
+{
+ return ti.printInstantiationTrace();
+}
+
/***********************************************************
* dtoh.d
*/
@@ -395,14 +419,14 @@ void asmSemantic(CAsmDeclaration d, Scope* sc)
*/
Statement gccAsmSemantic(GccAsmStatement s, Scope* sc)
{
- import dmd.iasmgcc;
- return dmd.iasmgcc.gccAsmSemantic(s, sc);
+ import dmd.iasm.gcc;
+ return dmd.iasm.gcc.gccAsmSemantic(s, sc);
}
void gccAsmSemantic(CAsmDeclaration d, Scope* sc)
{
- import dmd.iasmgcc;
- return dmd.iasmgcc.gccAsmSemantic(d, sc);
+ import dmd.iasm.gcc;
+ return dmd.iasm.gcc.gccAsmSemantic(d, sc);
}
/***********************************************************
@@ -721,6 +745,12 @@ MATCH constConv(Type from, Type to)
return dmd.typesem.constConv(from, to);
}
+Expression defaultInitLiteral(Type t, Loc loc)
+{
+ import dmd.typesem;
+ return dmd.typesem.defaultInitLiteral(t, loc);
+}
+
/***********************************************************
* typinf.d
*/
@@ -754,6 +784,20 @@ TypeInfoDeclaration getTypeInfoAssocArrayDeclaration(TypeAArray t, Scope* sc)
return dmd.typinf.getTypeInfoAssocArrayDeclaration(t, sc);
}
+/**
+ * templatesem.d
+ */
+bool needsCodegen(TemplateInstance ti)
+{
+ import dmd.templatesem;
+ return dmd.templatesem.needsCodegen(ti);
+}
+
+bool isDiscardable(TemplateInstance ti)
+{
+ import dmd.templatesem;
+ return dmd.templatesem.isDiscardable(ti);
+}
version (IN_LLVM)
{
/***********************************************************
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 9e35dde29697..4ac8b1f44711 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -2862,7 +2862,9 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
(*ae.keys)[i] = ex;
}
ae.type = t;
- semanticTypeInfo(sc, ae.type);
+ ae.lowering = null; // we need a different lowering
+ ae.loweringCtfe = null;
+ ae.expressionSemantic(sc);
return ae;
}
return visit(e);
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 51ac939ade09..2129aa00cf60 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -19,7 +19,6 @@ import core.stdc.string;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
-import dmd.gluelayer;
import dmd.declaration;
import dmd.dscope;
import dmd.dsymbol;
@@ -194,8 +193,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
*/
ObjcClassDeclaration objc;
- Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
-
final extern (D) this(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
{
objc = ObjcClassDeclaration(this);
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 25e5c31dcc6f..1bda9948cbf4 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -22,18 +22,16 @@ import dmd.delegatize;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
-import dmd.dsymbolsem : dsymbolSemantic, aliasSemantic;
+import dmd.dsymbolsem : toAlias;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
import dmd.func;
import dmd.globals;
-import dmd.gluelayer;
import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.init;
-import dmd.initsem : initializerToExpression, initializerSemantic;
import dmd.intrange;
import dmd.location;
import dmd.mtype;
@@ -42,7 +40,7 @@ import dmd.rootobject;
import dmd.root.filename;
import dmd.target;
import dmd.tokens;
-import dmd.typesem : toDsymbol, typeSemantic, size, hasPointers;
+import dmd.typesem : typeSemantic, size;
import dmd.visitor;
version (IN_GCC) {}
@@ -122,7 +120,7 @@ extern (C++) abstract class Declaration : Dsymbol
return "declaration";
}
- override final uinteger_t size(Loc loc)
+ override final ulong size(Loc loc)
{
assert(type);
const sz = type.size();
@@ -358,21 +356,6 @@ extern (C++) final class TupleDeclaration : Declaration
return tupletype;
}
- override Dsymbol toAlias2()
- {
- //printf("TupleDeclaration::toAlias2() '%s' objects = %s\n", toChars(), objects.toChars());
- for (size_t i = 0; i < objects.length; i++)
- {
- RootObject o = (*objects)[i];
- if (Dsymbol s = isDsymbol(o))
- {
- s = s.toAlias2();
- (*objects)[i] = s;
- }
- }
- return this;
- }
-
override bool needThis()
{
//printf("TupleDeclaration::needThis(%s)\n", toChars());
@@ -601,117 +584,7 @@ extern (C++) final class AliasDeclaration : Declaration
{
if (type)
return type;
- return toAlias().getType();
- }
-
- override Dsymbol toAlias()
- {
- static if (0)
- printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym: %s, kind: '%s', inuse = %d)\n",
- loc.toChars(), toChars(), this, aliassym ? aliassym.toChars() : "", aliassym ? aliassym.kind() : "", inuse);
- assert(this != aliassym);
- //static int count; if (++count == 10) *(char*)0=0;
-
- Dsymbol err()
- {
- // Avoid breaking "recursive alias" state during errors gagged
- if (global.gag)
- return this;
- aliassym = new AliasDeclaration(loc, ident, Type.terror);
- type = Type.terror;
- return aliassym;
- }
- // Reading the AliasDeclaration
- if (!this.ignoreRead)
- this.wasRead = true; // can never assign to this AliasDeclaration again
-
- if (inuse == 1 && type && _scope)
- {
- inuse = 2;
- const olderrors = global.errors;
- Dsymbol s = type.toDsymbol(_scope);
- //printf("[%s] type = %s, s = %p, this = %p\n", loc.toChars(), type.toChars(), s, this);
- if (global.errors != olderrors)
- return err();
- if (s)
- {
- s = s.toAlias();
- if (global.errors != olderrors)
- return err();
- aliassym = s;
- inuse = 0;
- }
- else
- {
- Type t = type.typeSemantic(loc, _scope);
- if (t.ty == Terror)
- return err();
- if (global.errors != olderrors)
- return err();
- //printf("t = %s\n", t.toChars());
- inuse = 0;
- }
- }
- if (inuse)
- {
- .error(loc, "%s `%s` recursive alias declaration", kind, toPrettyChars);
- return err();
- }
-
- if (semanticRun >= PASS.semanticdone)
- {
- // semantic is already done.
-
- // Do not see aliassym !is null, because of lambda aliases.
-
- // Do not see type.deco !is null, even so "alias T = const int;` needs
- // semantic analysis to take the storage class `const` as type qualifier.
- }
- else
- {
- // stop AliasAssign tuple building
- if (aliassym)
- {
- if (auto td = aliassym.isTupleDeclaration())
- {
- if (td.building)
- {
- td.building = false;
- semanticRun = PASS.semanticdone;
- return td;
- }
- }
- }
- if (_import && _import._scope)
- {
- /* If this is an internal alias for selective/renamed import,
- * load the module first.
- */
- _import.dsymbolSemantic(null);
- }
- if (_scope)
- {
- aliasSemantic(this, _scope);
- }
- }
-
- inuse = 1;
- Dsymbol s = aliassym ? aliassym.toAlias() : this;
- inuse = 0;
- return s;
- }
-
- override Dsymbol toAlias2()
- {
- if (inuse)
- {
- .error(loc, "%s `%s` recursive alias declaration", kind, toPrettyChars);
- return this;
- }
- inuse = 1;
- Dsymbol s = aliassym ? aliassym.toAlias2() : this;
- inuse = 0;
- return s;
+ return toAlias(this).getType();
}
override bool isOverloadable() const
@@ -958,7 +831,7 @@ extern (C++) class VarDeclaration : Declaration
{
isdataseg = 2; // The Variables does not go into the datasegment
- if (!canTakeAddressOf())
+ if (!canTakeAddressOf() || (storage_class & STC.exptemp))
{
return false;
}
@@ -1011,7 +884,7 @@ extern (C++) class VarDeclaration : Declaration
auto bitoffset = offset * 8;
auto vbitoffset = v.offset * 8;
- // Bitsize of types are overridden by any bit-field widths.
+ // Bitsize of types are overridden by any bitfield widths.
ulong tbitsize;
if (auto bf = isBitFieldDeclaration())
{
@@ -1051,49 +924,6 @@ extern (C++) class VarDeclaration : Declaration
return edtor && !(storage_class & STC.nodtor);
}
- /*******************************************
- * If variable has a constant expression initializer, get it.
- * Otherwise, return null.
- */
- extern (D) final Expression getConstInitializer(bool needFullType = true)
- {
- assert(type && _init);
-
- // Ungag errors when not speculative
- const oldgag = global.gag;
- if (global.gag)
- {
- Dsymbol sym = isMember();
- if (sym && !sym.isSpeculative())
- global.gag = 0;
- }
-
- if (_scope)
- {
- inuse++;
- _init = _init.initializerSemantic(_scope, type, INITinterpret);
- import dmd.semantic2 : lowerStaticAAs;
- lowerStaticAAs(this, _scope);
- _scope = null;
- inuse--;
- }
-
- Expression e = _init.initializerToExpression(needFullType ? type : null);
- global.gag = oldgag;
- return e;
- }
-
- override final Dsymbol toAlias()
- {
- //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
- if ((!type || !type.deco) && _scope)
- dsymbolSemantic(this, _scope);
-
- assert(this != aliasTuple);
- Dsymbol s = aliasTuple ? aliasTuple.toAlias() : this;
- return s;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1396,6 +1226,8 @@ extern (C++) final class TypeInfoStaticArrayDeclaration : TypeInfoDeclaration
extern (C++) final class TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration
{
Type entry; // type of TypeInfo_AssociativeArray.Entry!(t.index, t.next)
+ Declaration xopEqual; // implementation of TypeInfo_AssociativeArray.equals
+ Declaration xtoHash; // implementation of TypeInfo_AssociativeArray.getHash
extern (D) this(Type tinfo)
{
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 74ea20cb56f8..7a160770e144 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -71,9 +71,10 @@ namespace dmd
#define STCref 0x40000ULL /// `ref`
#define STCscope 0x80000ULL /// `scope`
- #define STCscopeinferred 0x200000ULL /// `scope` has been inferred and should not be part of mangling, `scope` must also be set
- #define STCreturn 0x400000ULL /// 'return ref' or 'return scope' for function parameters
- #define STCreturnScope 0x800000ULL /// if `ref return scope` then resolve to `ref` and `return scope`
+ #define STCscopeinferred 0x100000ULL /// `scope` has been inferred and should not be part of mangling, `scope` must also be set
+ #define STCreturn 0x200000ULL /// 'return ref' or 'return scope' for function parameters
+ #define STCreturnScope 0x400000ULL /// if `ref return scope` then resolve to `ref` and `return scope`
+ #define STCreturnRef 0x800000ULL, /// if `return ref`
#define STCreturninferred 0x1000000ULL /// `return` has been inferred and should not be part of mangling, `return` must also be set
#define STCimmutable 0x2000000ULL /// `immutable`
@@ -183,7 +184,6 @@ public:
TupleDeclaration *syntaxCopy(Dsymbol *) override;
const char *kind() const override;
Type *getType() override;
- Dsymbol *toAlias2() override;
bool needThis() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -203,8 +203,6 @@ public:
bool overloadInsert(Dsymbol *s) override;
const char *kind() const override;
Type *getType() override;
- Dsymbol *toAlias() override;
- Dsymbol *toAlias2() override;
bool isOverloadable() const override;
void accept(Visitor *v) override { v->visit(this); }
@@ -222,7 +220,6 @@ public:
bool equals(const RootObject * const o) const override;
bool overloadInsert(Dsymbol *s) override;
- Dsymbol *toAlias() override;
Dsymbol *isUnique();
bool isOverloadable() const override;
@@ -300,7 +297,6 @@ public:
bool isOverlappedWith(VarDeclaration *v);
bool canTakeAddressOf();
bool needsScopeDtor();
- Dsymbol *toAlias() override final;
// Eliminate need for dynamic_cast
void accept(Visitor *v) override { v->visit(this); }
};
@@ -395,6 +391,8 @@ class TypeInfoAssociativeArrayDeclaration final : public TypeInfoDeclaration
{
public:
Type* entry;
+ Declaration* xopEqual;
+ Declaration* xtoHash;
static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo);
@@ -727,7 +725,6 @@ public:
virtual bool addPreInvariant();
virtual bool addPostInvariant();
const char *kind() const override;
- bool isUnique();
bool needsClosure();
bool hasNestedFrameRefs();
ParameterList getParameterList();
diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d
index 1f5dca66b598..f37c83cbca7c 100644
--- a/gcc/d/dmd/delegatize.d
+++ b/gcc/d/dmd/delegatize.d
@@ -180,6 +180,11 @@ private void lambdaSetParent(Expression e, FuncDeclaration fd)
iz.accept(this);
}
}
+ override void visit(AssocArrayLiteralExp e)
+ {
+ if (e.lowering)
+ walkPostorder(e.lowering, this);
+ }
}
scope LambdaSetParent lsp = new LambdaSetParent(fd);
diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d
index e1a4ab6d6a3d..8b7d5e501235 100644
--- a/gcc/d/dmd/denum.d
+++ b/gcc/d/dmd/denum.d
@@ -18,7 +18,6 @@ import core.stdc.stdio;
import dmd.astenums;
import dmd.attrib;
-import dmd.gluelayer;
import dmd.declaration;
import dmd.dsymbol;
import dmd.expression;
@@ -62,7 +61,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
import dmd.common.bitfields : generateBitFields;
mixin(generateBitFields!(BitFields, ubyte));
- Symbol* sinit;
+ void* sinit;
extern (D) this(Loc loc, Identifier ident, Type memtype)
{
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index bbd74a4da270..66810cb35fdb 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -141,13 +141,6 @@ extern (C++) final class Import : Dsymbol
scopesym.addAccessiblePackage(mod, visibility); // d
}
- override Dsymbol toAlias()
- {
- if (aliasId)
- return mod;
- return this;
- }
-
override bool overloadInsert(Dsymbol s)
{
/* Allow multiple imports with the same package base, but disallow
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 543c0e22e39f..eaf3d993b019 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -50,7 +50,7 @@ import dmd.rootobject;
import dmd.root.utf;
import dmd.statement;
import dmd.tokens;
-import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf, size;
+import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf, size, merge, defaultInitLiteral;
import dmd.utils : arrayCastBigEndian;
import dmd.visitor;
@@ -569,7 +569,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
istatex.caller = istate;
istatex.fd = fd;
- if (fd.hasDualContext())
+ if (fd.hasDualContext)
{
Expression arg0 = thisarg;
if (arg0 && arg0.type.ty == Tstruct)
@@ -722,7 +722,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
if (tf.isRef && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
e = thisarg;
- if (tf.isRef && fd.hasDualContext() && e.op == EXP.index)
+ if (tf.isRef && fd.hasDualContext && e.op == EXP.index)
{
auto ie = e.isIndexExp();
auto pe = ie.e1.isPtrExp();
@@ -1745,7 +1745,7 @@ public:
if (istate && istate.fd.vthis)
{
result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
- if (istate.fd.hasDualContext())
+ if (istate.fd.hasDualContext)
{
result = ctfeEmplaceExp!PtrExp(e.loc, result);
result.type = Type.tvoidptr.sarrayOf(2);
@@ -1761,7 +1761,7 @@ public:
result = ctfeGlobals.stack.getThis();
if (result)
{
- if (istate && istate.fd.hasDualContext())
+ if (istate && istate.fd.hasDualContext)
{
assert(result.op == EXP.address);
result = result.isAddrExp().e1;
@@ -2348,6 +2348,9 @@ public:
if (ExpInitializer ie = v._init.isExpInitializer())
{
result = interpretRegion(ie.exp, istate, goal);
+ if (result !is null && v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone)
+ if (!getValue(v))
+ setValueWithoutChecking(v, result); // a temporary from extractSideEffects can be a ref
return;
}
else if (v._init.isVoidInitializer())
@@ -2362,7 +2365,12 @@ public:
{
result = v._init.initializerToExpression(v.type);
if (result !is null)
+ {
+ if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone)
+ if (!getValue(v))
+ setValueWithoutChecking(v, result); // a temporary from extractSideEffects can be a ref
return;
+ }
}
error(e.loc, "declaration `%s` is not yet implemented in CTFE", e.toChars());
result = CTFEExp.cantexp;
@@ -2641,6 +2649,8 @@ public:
valuesx !is e.values);
auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
aae.type = e.type;
+ aae.lowering = e.lowering;
+ aae.loweringCtfe = e.loweringCtfe;
aae.ownedByCtfe = OwnedBy.ctfe;
result = aae;
}
@@ -3406,131 +3416,10 @@ public:
// ---------------------------------------
// Interpret left hand side
// ---------------------------------------
- AssocArrayLiteralExp existingAA = null;
- Expression lastIndex = null;
Expression oldval = null;
if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
{
- // ---------------------------------------
- // Deal with AA index assignment
- // ---------------------------------------
- /* This needs special treatment if the AA doesn't exist yet.
- * There are two special cases:
- * (1) If the AA is itself an index of another AA, we may need to create
- * multiple nested AA literals before we can insert the new value.
- * (2) If the ultimate AA is null, no insertion happens at all. Instead,
- * we create nested AA literals, and change it into a assignment.
- */
- IndexExp ie = e1.isIndexExp();
- int depth = 0; // how many nested AA indices are there?
- while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
- {
- assert(ie.modifiable);
- ie = ie.e1.isIndexExp();
- ++depth;
- }
-
- // Get the AA value to be modified.
- Expression aggregate = interpretRegion(ie.e1, istate);
- if (exceptionOrCant(aggregate))
- return;
- if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
- {
- // Normal case, ultimate parent AA already exists
- // We need to walk from the deepest index up, checking that an AA literal
- // already exists on each level.
- lastIndex = interpretRegion(e1.isIndexExp().e2, istate);
- lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
- if (exceptionOrCant(lastIndex))
- return;
-
- while (depth > 0)
- {
- // Walk the syntax tree to find the indexExp at this depth
- IndexExp xe = e1.isIndexExp();
- foreach (d; 0 .. depth)
- xe = xe.e1.isIndexExp();
-
- Expression ekey = interpretRegion(xe.e2, istate);
- if (exceptionOrCant(ekey))
- return;
- UnionExp ekeyTmp = void;
- ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
-
- // Look up this index in it up in the existing AA, to get the next level of AA.
- AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
- if (exceptionOrCant(newAA))
- return;
- if (!newAA)
- {
- // Doesn't exist yet, create an empty AA...
- auto keysx = new Expressions();
- auto valuesx = new Expressions();
- newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
- newAA.type = xe.type;
- newAA.ownedByCtfe = OwnedBy.ctfe;
- //... and insert it into the existing AA.
- existingAA.keys.push(ekey);
- existingAA.values.push(newAA);
- }
- existingAA = newAA;
- --depth;
- }
-
- if (fp)
- {
- oldval = findKeyInAA(e.loc, existingAA, lastIndex);
- if (!oldval)
- oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
- }
- }
- else
- {
- /* The AA is currently null. 'aggregate' is actually a reference to
- * whatever contains it. It could be anything: var, dotvarexp, ...
- * We rewrite the assignment from:
- * aa[i][j] op= newval;
- * into:
- * aa = [i:[j:T.init]];
- * aa[j] op= newval;
- */
- oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
-
- Expression newaae = oldval;
- while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
- {
- Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
- if (exceptionOrCant(ekey))
- return;
- ekey = resolveSlice(ekey); // only happens with AA assignment
-
- auto keysx = new Expressions();
- auto valuesx = new Expressions();
- keysx.push(ekey);
- valuesx.push(newaae);
-
- auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
- aae.type = e1.isIndexExp().e1.type;
- aae.ownedByCtfe = OwnedBy.ctfe;
- if (!existingAA)
- {
- existingAA = aae;
- lastIndex = ekey;
- }
- newaae = aae;
- e1 = e1.isIndexExp().e1;
- }
-
- // We must set to aggregate with newaae
- e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
- if (exceptionOrCant(e1))
- return;
- e1 = assignToLvalue(e, e1, newaae);
- if (exceptionOrCant(e1))
- return;
- }
- assert(existingAA && lastIndex);
- e1 = null; // stomp
+ assert(false, "indexing AA should have been lowered in semantic analysis");
}
else if (e1.op == EXP.arrayLength)
{
@@ -3570,10 +3459,7 @@ public:
if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
{
- IndexExp ie = e1.isIndexExp();
- assert(ie.e1.op == EXP.assocArrayLiteral);
- existingAA = ie.e1.isAssocArrayLiteralExp();
- lastIndex = ie.e2;
+ assert(false, "indexing AA should have been lowered in semantic analysis");
}
}
@@ -3664,23 +3550,6 @@ public:
}
}
- if (existingAA)
- {
- if (existingAA.ownedByCtfe != OwnedBy.ctfe)
- {
- error(e.loc, "cannot modify read-only constant `%s`", existingAA.toChars());
- result = CTFEExp.cantexp;
- return;
- }
-
- //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
- // __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
- assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
-
- // Determine the return value
- result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
- return;
- }
if (e1.op == EXP.arrayLength)
{
/* Change the assignment from:
@@ -3725,7 +3594,7 @@ public:
if (newval == pue.exp())
newval = pue.copy();
- e1 = assignToLvalue(e, e1, newval);
+ e1 = assignToLvalue(e, e1, newval, istate);
if (exceptionOrCant(e1))
return;
@@ -3799,7 +3668,7 @@ public:
/* Assignment to a CTFE reference.
*/
- if (Expression ex = assignToLvalue(e, e1, newval))
+ if (Expression ex = assignToLvalue(e, e1, newval, istate))
result = ex;
return;
@@ -3807,7 +3676,7 @@ public:
/* Set all sibling fields which overlap with v to VoidExp.
*/
- private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
+ private static void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
{
if (!v.overlapped)
return;
@@ -3821,7 +3690,7 @@ public:
}
}
- private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
+ private static Expression assignToLvalue(BinExp e, Expression e1, Expression newval, InterState* istate)
{
//printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
VarDeclaration vd = null;
@@ -3915,7 +3784,8 @@ public:
ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
if (existingAE.ownedByCtfe != OwnedBy.ctfe)
{
- error(e.loc, "cannot modify read-only constant `%s`", existingAE.toChars());
+ Expression literal = existingAE.aaLiteral ? existingAE.aaLiteral : existingAE;
+ error(e.loc, "cannot modify read-only constant `%s`", literal.toChars());
return CTFEExp.cantexp;
}
@@ -4933,7 +4803,7 @@ public:
}
}
- if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
+ if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors)
{
error(e.loc, "CTFE failed because of previous errors in `%s`", fd.toChars());
result = CTFEExp.cantexp;
@@ -5239,16 +5109,6 @@ public:
dinteger_t ofs;
Expression agg = getAggregateFromPointer(e1, &ofs);
- if (agg.op == EXP.null_)
- {
- error(e.loc, "cannot index through null pointer `%s`", e.e1.toChars());
- return false;
- }
- if (agg.op == EXP.int64)
- {
- error(e.loc, "cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
- return false;
- }
// Pointer to a non-array variable
if (agg.op == EXP.symbolOffset)
{
@@ -5267,9 +5127,15 @@ public:
}
else
{
+ // agg is the value accessed, it is not dereferenced again, so offset 0 is always ok
if (ofs + indx != 0)
{
- error(e.loc, "pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
+ if (agg.op == EXP.null_)
+ error(e.loc, "cannot index through null pointer `%s`", e.e1.toChars());
+ else if (agg.op == EXP.int64)
+ error(e.loc, "cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
+ else
+ error(e.loc, "pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
return false;
}
}
@@ -5394,47 +5260,7 @@ public:
if (e.e1.type.toBasetype().ty == Taarray)
{
- Expression e1 = interpretRegion(e.e1, istate);
- if (exceptionOrCant(e1))
- return;
- if (e1.op == EXP.null_)
- {
- if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
- {
- assert(0); // does not reach here?
- }
- error(e.loc, "cannot index null array `%s`", e.e1.toChars());
- result = CTFEExp.cantexp;
- return;
- }
- Expression e2 = interpretRegion(e.e2, istate);
- if (exceptionOrCant(e2))
- return;
-
- if (goal == CTFEGoal.LValue)
- {
- // Pointer or reference of a scalar type
- if (e1 == e.e1 && e2 == e.e2)
- result = e;
- else
- {
- emplaceExp!(IndexExp)(pue, e.loc, e1, e2);
- result = pue.exp();
- result.type = e.type;
- }
- return;
- }
-
- assert(e1.op == EXP.assocArrayLiteral);
- UnionExp e2tmp = void;
- e2 = resolveSlice(e2, &e2tmp);
- result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
- if (!result)
- {
- error(e.loc, "key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
- result = CTFEExp.cantexp;
- }
- return;
+ assert(false, "indexing AA should have been lowered in semantic analysis");
}
Expression agg;
@@ -5662,50 +5488,6 @@ public:
result.type = e.type;
}
- override void visit(InExp e)
- {
- debug (LOG)
- {
- printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars());
- }
- Expression e1 = interpretRegion(e.e1, istate);
- if (exceptionOrCant(e1))
- return;
- Expression e2 = interpretRegion(e.e2, istate);
- if (exceptionOrCant(e2))
- return;
- if (e2.op == EXP.null_)
- {
- emplaceExp!(NullExp)(pue, e.loc, e.type);
- result = pue.exp();
- return;
- }
- if (e2.op != EXP.assocArrayLiteral)
- {
- error(e.loc, "`%s` cannot be interpreted at compile time", e.toChars());
- result = CTFEExp.cantexp;
- return;
- }
-
- e1 = resolveSlice(e1);
- result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
- if (exceptionOrCant(result))
- return;
- if (!result)
- {
- emplaceExp!(NullExp)(pue, e.loc, e.type);
- result = pue.exp();
- }
- else
- {
- // Create a CTFE pointer &aa[index]
- result = ctfeEmplaceExp!IndexExp(e.loc, e2, e1);
- result.type = e.type.nextOf();
- emplaceExp!(AddrExp)(pue, e.loc, result, e.type);
- result = pue.exp();
- }
- }
-
override void visit(CatExp e)
{
debug (LOG)
@@ -6420,45 +6202,6 @@ public:
}
}
- override void visit(RemoveExp e)
- {
- debug (LOG)
- {
- printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
- }
- Expression agg = interpret(e.e1, istate);
- if (exceptionOrCant(agg))
- return;
- Expression index = interpret(e.e2, istate);
- if (exceptionOrCant(index))
- return;
- if (agg.op == EXP.null_)
- {
- result = CTFEExp.voidexp;
- return;
- }
-
- AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
- Expressions* keysx = aae.keys;
- Expressions* valuesx = aae.values;
- size_t removed = 0;
- foreach (j, evalue; *valuesx)
- {
- Expression ekey = (*keysx)[j];
- int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
- if (eq)
- ++removed;
- else if (removed != 0)
- {
- (*keysx)[j - removed] = ekey;
- (*valuesx)[j - removed] = evalue;
- }
- }
- valuesx.length = valuesx.length - removed;
- keysx.length = keysx.length - removed;
- result = IntegerExp.createBool(removed != 0);
- }
-
override void visit(ClassReferenceExp e)
{
//printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
@@ -6703,8 +6446,9 @@ ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp
}
// Little sanity check to make sure it's really a Throwable
ClassReferenceExp boss = oldest.thrown;
- const next = 5; // index of Throwable.next
- assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
+ const next = 5; // index of Throwable._nextInChainPtr
+ with ((*boss.value.elements)[next].type) // Throwable._nextInChainPtr
+ assert(ty == Tpointer || ty == Tclass);
ClassReferenceExp collateral = newest.thrown;
if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException())
{
@@ -7150,6 +6894,53 @@ private Expression interpret_values(UnionExp* pue, InterState* istate, Expressio
return pue.exp();
}
+// signature is bool _d_aaDel(V[K] aa, K key)
+private Expression interpret_aaDel(UnionExp* pue, InterState* istate, Expression aa, Expression key)
+{
+ Expression agg = interpret(aa, istate);
+ if (exceptionOrCantInterpret(agg))
+ return agg;
+ Expression index = interpret(key, istate);
+ if (exceptionOrCantInterpret(index))
+ return index;
+ if (agg.op == EXP.null_)
+ return CTFEExp.voidexp; //???
+
+ AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
+ Expressions* keysx = aae.keys;
+ Expressions* valuesx = aae.values;
+ size_t removed = 0;
+ foreach (j, evalue; *valuesx)
+ {
+ Expression ekey = (*keysx)[j];
+ int eq = ctfeEqual(aa.loc, EXP.equal, ekey, index);
+ if (eq)
+ ++removed;
+ else if (removed != 0)
+ {
+ (*keysx)[j - removed] = ekey;
+ (*valuesx)[j - removed] = evalue;
+ }
+ }
+ valuesx.length = valuesx.length - removed;
+ keysx.length = keysx.length - removed;
+ return IntegerExp.createBool(removed != 0);
+}
+
+// signature is bool _d_aaDel(V[K] aa1, V[K] aa2)
+private Expression interpret_aaEqual(UnionExp* pue, InterState* istate, Expression aa1, Expression aa2)
+{
+ Expression e1 = interpret(aa1, istate);
+ if (exceptionOrCantInterpret(e1))
+ return e1;
+ Expression e2 = interpret(aa2, istate);
+ if (exceptionOrCantInterpret(e2))
+ return e2;
+
+ bool equal = ctfeEqual(aa1.loc, EXP.equal, e1, e2);
+ return IntegerExp.createBool(equal);
+}
+
private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
{
debug (LOG)
@@ -7174,11 +6965,131 @@ private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression e
if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
return e;
}
- aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
+ // repaint type from const(int[int]) to int[int]
+ if (auto taa = earg.type.toBasetype().isTypeAArray())
+ {
+ auto aatype = new TypeAArray(taa.next.mutableOf(), taa.index);
+ aae.type = aatype.merge();
+ }
+ else
+ aae.type = earg.type.mutableOf();
//printf("result is %s\n", aae.toChars());
return aae;
}
+// signature is bool V* _d_aaIn(V[K] aa, K key)
+private Expression interpret_aaIn(UnionExp* pue, InterState* istate, Expression aa, Expression key)
+{
+ debug (LOG)
+ {
+ printf("%s _d_aaIn::interpret() %s in %s\n", aa.loc.toChars(), key.toChars(), aa.toChars());
+ }
+ Expression eaa = interpretRegion(aa, istate);
+ if (exceptionOrCantInterpret(eaa))
+ return eaa;
+ Expression ekey = interpretRegion(key, istate);
+ if (exceptionOrCantInterpret(ekey))
+ return ekey;
+
+ if (eaa.op != EXP.null_)
+ {
+ auto aalit = eaa.isAssocArrayLiteralExp();
+ if (!aalit)
+ {
+ error(aa.loc, "`%s` cannot be interpreted at compile time", aa.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ size_t idx;
+ auto result = findKeyInAA(aa.loc, aalit, ekey, &idx);
+ if (exceptionOrCantInterpret(result))
+ return result;
+ if (result)
+ return pointerToAAValue(pue, aa, aalit, idx);
+ }
+ emplaceExp!(NullExp)(pue, aa.loc, aa.type.nextOf().pointerTo());
+ return pue.exp();
+}
+
+// signature is V* _d_aaGetRvalueX(V[K] aa, K key)
+private Expression interpret_aaGetRvalueX(UnionExp* pue, InterState* istate, Expression aa, Expression key)
+{
+ Expression e1 = interpret(aa, istate);
+ if (exceptionOrCantInterpret(e1))
+ return e1;
+ Expression e2 = interpretRegion(key, istate);
+ if (exceptionOrCantInterpret(e2))
+ return e2;
+
+ auto aalit = e1.isAssocArrayLiteralExp();
+ if (!aalit)
+ {
+ error(aa.loc, "cannot index null array `%s`", aa.toChars());
+ return CTFEExp.cantexp;
+ }
+ size_t idx;
+ Expression result = findKeyInAA(aa.loc, aalit, e2, &idx);
+ if (!result)
+ {
+ error(aa.loc, "key `%s` not found in associative array `%s`", key.toChars(), aa.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ return pointerToAAValue(pue, aa, aalit, idx);
+}
+
+// signature is V* _d_aaGetY(ref V[K] aa, K key, out bool found)
+private Expression interpret_aaGetY(UnionExp* pue, InterState* istate, Expression aa, Expression key, Expression found)
+{
+ Expression eaa = interpretRegion(aa, istate, CTFEGoal.LValue);
+ if (exceptionOrCantInterpret(eaa))
+ return eaa;
+ Expression ekey = interpretRegion(key, istate);
+ if (exceptionOrCantInterpret(ekey))
+ return ekey;
+ Expression efound = interpretRegion(found, istate, CTFEGoal.LValue);
+ if (exceptionOrCantInterpret(efound))
+ return efound;
+
+ auto ie = ctfeEmplaceExp!IndexExp(aa.loc, aa, key); // any BinExp for location in assignToLvalue
+ Expression evalaa = interpretRegion(eaa, istate);
+ auto aalit = evalaa.isAssocArrayLiteralExp();
+ if (!aalit)
+ {
+ auto keysx = new Expressions();
+ auto valuesx = new Expressions();
+ aalit = ctfeEmplaceExp!AssocArrayLiteralExp(aa.loc, keysx, valuesx);
+ aalit.type = aa.type;
+ aalit.ownedByCtfe = OwnedBy.ctfe;
+ Interpreter.assignToLvalue(ie, eaa, aalit, istate);
+ }
+ size_t idx;
+ auto result = findKeyInAA(aa.loc, aalit, ekey, &idx);
+ if (found)
+ Interpreter.assignToLvalue(ie, efound, IntegerExp.createBool(result !is null), istate);
+ if (!result)
+ {
+ aalit.keys.push(ekey);
+ result = copyLiteral(aa.type.nextOf().defaultInitLiteral(aa.loc)).copy();
+ idx = aalit.values.length;
+ aalit.values.push(result);
+ }
+ return pointerToAAValue(pue, aa, aalit, idx);
+}
+
+private Expression pointerToAAValue(UnionExp* pue, Expression aa, AssocArrayLiteralExp aalit, size_t idx)
+{
+ auto arr = ctfeEmplaceExp!(ArrayLiteralExp)(aa.loc, aa.type.nextOf().arrayOf(), aalit.values);
+ arr.ownedByCtfe = aalit.ownedByCtfe;
+ arr.aaLiteral = aalit;
+ auto len = ctfeEmplaceExp!(IntegerExp)(aa.loc, idx, Type.tsize_t);
+ auto idxexp = ctfeEmplaceExp!(IndexExp)(aa.loc, arr, len);
+ idxexp.type = arr.type.nextOf();
+ emplaceExp!(AddrExp)(pue, aa.loc, idxexp);
+ pue.exp().type = idxexp.type.pointerTo();
+ return pue.exp();
+}
+
// signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
{
@@ -7223,7 +7134,10 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi
if (wantRefValue)
{
Type t = evalue.type;
- evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
+ auto arr = ctfeEmplaceExp!(ArrayLiteralExp)(aa.loc, t.arrayOf(), ae.values);
+ arr.ownedByCtfe = ae.ownedByCtfe;
+ auto idx = ctfeEmplaceExp!(IntegerExp)(aa.loc, i, Type.tsize_t);
+ evalue = ctfeEmplaceExp!(IndexExp)(aa.loc, arr, idx);
evalue.type = t;
}
args[numParams - 1] = evalue;
@@ -7481,7 +7395,7 @@ private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, Loc loc,
}
if (!pthis)
{
- if (nargs == 1 || nargs == 3)
+ if (nargs >= 1 && nargs <= 3)
{
Expression firstarg = (*arguments)[0];
if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
@@ -7489,7 +7403,7 @@ private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, Loc loc,
const id = fd.ident;
if (nargs == 1)
{
- if (id == Id.aaLen)
+ if (id == Id._d_aaLen)
return interpret_length(pue, istate, firstarg);
if (fd.toParent2().ident == Id.object)
@@ -7504,12 +7418,25 @@ private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, Loc loc,
return interpret_dup(pue, istate, firstarg);
}
}
+ else if (nargs == 2)
+ {
+ if (id == Id._d_aaGetRvalueX)
+ return interpret_aaGetRvalueX(pue, istate, firstarg, (*arguments)[1]);
+ if (id == Id._d_aaIn)
+ return interpret_aaIn(pue, istate, firstarg, (*arguments)[1]);
+ if (id == Id._d_aaDel)
+ return interpret_aaDel(pue, istate, firstarg, (*arguments)[1]);
+ if (id == Id._d_aaEqual)
+ return interpret_aaEqual(pue, istate, firstarg, (*arguments)[1]);
+ if (id == Id._d_aaApply)
+ return interpret_aaApply(pue, istate, firstarg, (*arguments)[1]);
+ if (id == Id._d_aaApply2)
+ return interpret_aaApply(pue, istate, firstarg, (*arguments)[1]);
+ }
else // (nargs == 3)
{
- if (id == Id._aaApply)
- return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
- if (id == Id._aaApply2)
- return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
+ if (id == Id._d_aaGetY)
+ return interpret_aaGetY(pue, istate, firstarg, (*arguments)[1], (*arguments)[2]);
}
}
}
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 33539d4bf0b8..08400433d099 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -30,15 +30,13 @@ import dmd.dmacro;
import dmd.doc;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem : dsymbolSemantic, importAll, load;
+import dmd.dsymbolsem : dsymbolSemantic;
import dmd.errors;
import dmd.errorsink;
import dmd.expression;
-import dmd.expressionsem;
import dmd.file_manager;
import dmd.func;
import dmd.globals;
-import dmd.gluelayer;
import dmd.id;
import dmd.identifier;
import dmd.location;
@@ -412,6 +410,8 @@ extern (C++) final class Module : Package
SearchOptFlags searchCacheFlags; // cached flags
bool insearch;
+ bool isExplicitlyOutOfBinary; // Is this module known to be out of binary, and must be DllImport'd?
+
/**
* A root module is one that will be compiled all the way to
* object code. This field holds the root module that caused
@@ -456,6 +456,7 @@ extern (C++) final class Module : Package
else if (!FileName.equalsExt(srcfilename, mars_ext) &&
!FileName.equalsExt(srcfilename, hdr_ext) &&
!FileName.equalsExt(srcfilename, c_ext) &&
+ !FileName.equalsExt(srcfilename, h_ext) &&
!FileName.equalsExt(srcfilename, i_ext) &&
!FileName.equalsExt(srcfilename, dd_ext))
{
@@ -474,7 +475,7 @@ extern (C++) final class Module : Package
if (doHdrGen)
hdrfile = setOutfilename(global.params.dihdr.name, global.params.dihdr.dir, arg, hdr_ext);
- this.edition = Edition.legacy;
+ this.edition = Edition.min;
}
extern (D) this(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen)
@@ -492,12 +493,6 @@ extern (C++) final class Module : Package
return new Module(Loc.initial, filename, ident, doDocComment, doHdrGen);
}
- static const(char)* find(const(char)* filename)
- {
- ImportPathInfo pathThatFoundThis; // is this needed? In fact is this function needed still???
- return find(filename.toDString, pathThatFoundThis).ptr;
- }
-
extern (D) static const(char)[] find(const(char)[] filename, out ImportPathInfo pathThatFoundThis)
{
ptrdiff_t whichPathFoundThis;
@@ -532,6 +527,7 @@ extern (C++) final class Module : Package
auto m = new Module(loc, filename, ident, 0, 0);
// TODO: apply import path information (pathInfo) on to module
+ m.isExplicitlyOutOfBinary = importPathThatFindUs.isOutOfBinary;
if (!m.read(loc))
return null;
@@ -700,7 +696,8 @@ extern (C++) final class Module : Package
const(ubyte)[] srctext;
if (global.preprocess &&
- FileName.equalsExt(srcfile.toString(), c_ext) &&
+ (FileName.equalsExt(srcfile.toString(), c_ext) ||
+ FileName.equalsExt(srcfile.toString(), h_ext)) &&
FileName.exists(srcfile.toString()))
{
/* Apply C preprocessor to the .c file, returning the contents
@@ -783,10 +780,12 @@ extern (C++) final class Module : Package
DsymbolTable dst;
Package ppack = null;
- /* If it has the extension ".c", it is a "C" file.
+ /* If it has the extension ".c" or ".h", it is a "C" file.
* If it has the extension ".i", it is a preprocessed "C" file.
*/
- if (FileName.equalsExt(arg, c_ext) || FileName.equalsExt(arg, i_ext))
+ if (FileName.equalsExt(arg, c_ext) ||
+ FileName.equalsExt(arg, h_ext) ||
+ FileName.equalsExt(arg, i_ext))
{
filetype = FileType.c;
@@ -953,32 +952,6 @@ extern (C++) final class Module : Package
return needmoduleinfo || global.params.cov;
}
- /*******************************************
- * Print deprecation warning if we're deprecated, when
- * this module is imported from scope sc.
- *
- * Params:
- * sc = the scope into which we are imported
- * loc = the location of the import statement
- */
- void checkImportDeprecation(Loc loc, Scope* sc)
- {
- if (md && md.isdeprecated && !sc.isDeprecated)
- {
- Expression msg = md.msg;
- if (StringExp se = msg ? msg.toStringExp() : null)
- {
- const slice = se.peekString();
- if (slice.length)
- {
- deprecation(loc, "%s `%s` is deprecated - %.*s", kind, toPrettyChars, cast(int)slice.length, slice.ptr);
- return;
- }
- }
- deprecation(loc, "%s `%s` is deprecated", kind, toPrettyChars);
- }
- }
-
override bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all)
{
if (insearch) // don't follow import cycles
@@ -1170,16 +1143,10 @@ extern (C++) final class Module : Package
}
// Back end
- int doppelganger; // sub-module
- Symbol* cov; // private uint[] __coverage;
+ void* cov; // private uint[] __coverage;
uint[] covb; // bit array of valid code line numbers
- Symbol* sictor; // module order independent constructor
- Symbol* sctor; // module constructor
- Symbol* sdtor; // module destructor
- Symbol* ssharedctor; // module shared constructor
- Symbol* sshareddtor; // module shared destructor
- Symbol* stest; // module unit test
- Symbol* sfilename; // symbol for filename
+ void* sfilename; // symbol for filename
+ bool hasCDtor; // this module has a (shared) module constructor or destructor and we are codegenning it
uint[uint] ctfe_cov; /// coverage information from ctfe execution_count[line]
@@ -1213,75 +1180,6 @@ extern (C++) final class Module : Package
_escapetable = new Escape();
return _escapetable;
}
-
- /****************************
- * A Singleton that loads core.stdc.config
- * Returns:
- * Module of core.stdc.config, null if couldn't find it
- */
- extern (D) static Module loadCoreStdcConfig()
- {
- __gshared Module core_stdc_config;
- auto pkgids = new Identifier[2];
- pkgids[0] = Id.core;
- pkgids[1] = Id.stdc;
- return loadModuleFromLibrary(core_stdc_config, pkgids, Id.config);
- }
-
- /****************************
- * A Singleton that loads core.atomic
- * Returns:
- * Module of core.atomic, null if couldn't find it
- */
- extern (D) static Module loadCoreAtomic()
- {
- __gshared Module core_atomic;
- auto pkgids = new Identifier[1];
- pkgids[0] = Id.core;
- return loadModuleFromLibrary(core_atomic, pkgids, Id.atomic);
- }
-
- /****************************
- * A Singleton that loads std.math
- * Returns:
- * Module of std.math, null if couldn't find it
- */
- extern (D) static Module loadStdMath()
- {
- __gshared Module std_math;
- auto pkgids = new Identifier[1];
- pkgids[0] = Id.std;
- return loadModuleFromLibrary(std_math, pkgids, Id.math);
- }
-
- /**********************************
- * Load a Module from the library.
- * Params:
- * mod = cached return value of this call
- * pkgids = package identifiers
- * modid = module id
- * Returns:
- * Module loaded, null if cannot load it
- */
- extern (D) private static Module loadModuleFromLibrary(ref Module mod, Identifier[] pkgids, Identifier modid)
- {
- if (mod)
- return mod;
-
- auto imp = new Import(Loc.initial, pkgids[], modid, null, true);
- // Module.load will call fatal() if there's no module available.
- // Gag the error here, pushing the error handling to the caller.
- const errors = global.startGagging();
- imp.load(null);
- if (imp.mod)
- {
- imp.mod.importAll(null);
- imp.mod.dsymbolSemantic(null);
- }
- global.endGagging(errors);
- mod = imp.mod;
- return mod;
- }
}
/***********************************************************
@@ -1386,7 +1284,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
dbuf.writeUTF8(u);
}
else
- dbuf.writeByte(u);
+ dbuf.writeByte(cast(ubyte)u);
}
dbuf.writeByte(0); //add null terminator
return dbuf.extractSlice();
@@ -1455,7 +1353,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
dbuf.writeUTF8(u);
}
else
- dbuf.writeByte(u);
+ dbuf.writeByte(cast(ubyte)u);
}
dbuf.writeByte(0); //add a terminating null byte
return dbuf.extractSlice();
@@ -1533,9 +1431,8 @@ FuncDeclaration findGetMembers(ScopeDsymbol dsym)
{
Scope sc;
sc.eSink = global.errorSink;
- auto parameters = new Parameters();
Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
- parameters.push(p);
+ auto parameters = new Parameters(p);
Type tret = null;
TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction();
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index c70e7d381b56..879ffc11268e 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -55,7 +55,8 @@ enum Contract : ubyte
ensure = 3, // out contract
}
-private extern (D) struct BitFields
+/// Bitfield for settable/copyable flags, see `copyFlagsFrom`, `resetAllFlags`
+private extern (D) struct FlagBitFields
{
bool ctor; /// constructor type
bool noAccessCheck; /// don't do access checks
@@ -74,6 +75,14 @@ private extern (D) struct BitFields
bool ctfeBlock; /// inside a `if (__ctfe)` block
}
+private extern (D) struct NonFlagBitFields
+{
+ ubyte intypeof; /// in typeof(exp)
+ bool nofree; /// true if shouldn't free it
+ bool inLoop; /// true if inside a loop (where constructor calls aren't allowed)
+ bool inDefaultArg; /// true if inside a default argument (where __FILE__, etc are evaluated at the call site)
+ bool explicitVisibility; /// set if in an explicit visibility attribute
+}
/// State of -preview switches
///
/// By making them part of a Scope, we reduce reliance on dmd.globals,
@@ -140,10 +149,6 @@ extern (C++) struct Scope
ForeachStatement fes; /// if nested function for ForeachStatement, this is it
Scope* callsc; /// used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__
Dsymbol inunion; /// != null if processing members of a union
- bool nofree; /// true if shouldn't free it
- bool inLoop; /// true if inside a loop (where constructor calls aren't allowed)
- bool inDefaultArg; /// true if inside a default argument (where __FILE__, etc are evaluated at the call site)
- int intypeof; /// in typeof(exp)
VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init
ErrorSink eSink; /// sink for error messages
@@ -174,15 +179,15 @@ extern (C++) struct Scope
/// visibility for class members
Visibility visibility = Visibility(Visibility.Kind.public_);
- int explicitVisibility; /// set if in an explicit visibility attribute
STC stc; /// storage class
DeprecatedDeclaration depdecl; /// customized deprecation message
import dmd.common.bitfields : generateBitFields;
- mixin(generateBitFields!(BitFields, ushort));
-
+ mixin(generateBitFields!(FlagBitFields, ushort));
+ private ushort bitFields2;
+ mixin(generateBitFields!(NonFlagBitFields, ushort, "bitFields2"));
Previews previews;
// user defined attributes
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 5aef3585cafe..b565f159aec8 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -23,13 +23,9 @@ import dmd.declaration;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem : search, setFieldOffset;
import dmd.dtemplate;
-import dmd.errors;
import dmd.expression;
import dmd.func;
-import dmd.funcsem;
-import dmd.globals;
import dmd.id;
import dmd.identifier;
import dmd.location;
@@ -37,35 +33,9 @@ import dmd.mtype;
import dmd.opover;
import dmd.target;
import dmd.tokens;
-import dmd.typesem : isZeroInit, merge, size, hasPointers;
import dmd.typinf;
import dmd.visitor;
-/***************************************
- * Search sd for a member function of the form:
- * `extern (D) string toString();`
- * Params:
- * sd = struct declaration to search
- * Returns:
- * FuncDeclaration of `toString()` if found, `null` if not
- */
-FuncDeclaration search_toString(StructDeclaration sd)
-{
- Dsymbol s = search_function(sd, Id.tostring);
- FuncDeclaration fd = s ? s.isFuncDeclaration() : null;
- if (fd)
- {
- __gshared TypeFunction tftostring;
- if (!tftostring)
- {
- tftostring = new TypeFunction(ParameterList(), Type.tstring, LINK.d);
- tftostring = tftostring.merge().toTypeFunction();
- }
- fd = fd.overloadExactMatch(tftostring);
- }
- return fd;
-}
-
enum StructFlags : int
{
none = 0x0,
@@ -151,100 +121,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
return "struct";
}
- /// Compute cached type properties for `TypeStruct`
- extern(D) final void determineTypeProperties()
- {
- if (computedTypeProperties)
- return;
- foreach (vd; fields)
- {
- import dmd.dsymbolsem : hasPointers;
- if (vd.storage_class & STC.ref_ || vd.hasPointers())
- {
- hasPointerField = true;
- hasUnsafeBitpatterns = true;
- }
-
- if (vd._init && vd._init.isVoidInitializer() && vd.hasPointers())
- hasVoidInitPointers = true;
-
- if (vd.storage_class & STC.system || vd.type.hasUnsafeBitpatterns())
- hasUnsafeBitpatterns = true;
-
- if (!vd._init && vd.type.hasVoidInitPointers())
- hasVoidInitPointers = true;
-
- if (vd.type.hasInvariant())
- hasFieldWithInvariant = true;
- }
- computedTypeProperties = true;
- }
-
- /***************************************
- * Determine if struct is POD (Plain Old Data).
- *
- * POD is defined as:
- * $(OL
- * $(LI not nested)
- * $(LI no postblits, destructors, or assignment operators)
- * $(LI no `ref` fields or fields that are themselves non-POD)
- * )
- * The idea being these are compatible with C structs.
- *
- * Returns:
- * true if struct is POD
- */
- final bool isPOD()
- {
- // If we've already determined whether this struct is POD.
- if (ispod != ThreeState.none)
- return (ispod == ThreeState.yes);
-
- import dmd.clone;
-
- bool hasCpCtorLocal;
- bool hasMoveCtorLocal;
- bool needCopyCtor;
- bool needMoveCtor;
- needCopyOrMoveCtor(this, hasCpCtorLocal, hasMoveCtorLocal, needCopyCtor, needMoveCtor);
-
- if (enclosing || // is nested
- search(this, loc, Id.postblit) || // has postblit
- search(this, loc, Id.dtor) || // has destructor
- /* This is commented out because otherwise buildkite vibe.d:
- `canCAS!Task` fails to compile
- */
- //hasMoveCtorLocal || // has move constructor
- hasCpCtorLocal) // has copy constructor
- {
- ispod = ThreeState.no;
- return false;
- }
-
- // Recursively check all fields are POD.
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration v = fields[i];
- if (v.storage_class & STC.ref_)
- {
- ispod = ThreeState.no;
- return false;
- }
-
- if (auto ts = v.type.baseElemOf().isTypeStruct())
- {
- if (!ts.sym.isPOD())
- {
- ispod = ThreeState.no;
- return false;
- }
- }
- }
-
- ispod = ThreeState.yes;
- return true;
- }
-
/***************************************
* Determine if struct has copy construction (copy constructor or postblit)
* Returns:
@@ -269,54 +145,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
{
return index < numArgTypes() ? (*argTypes.arguments)[index].type : null;
}
-
-
- /***************************************
- * Verifies whether the struct declaration has a
- * constructor that is not a copy constructor.
- * Optionally, it can check whether the struct
- * declaration has a regular constructor, that
- * is not disabled.
- *
- * Params:
- * ignoreDisabled = true to ignore disabled constructors
- * Returns:
- * true, if the struct has a regular (optionally,
- * not disabled) constructor, false otherwise.
- */
- final bool hasRegularCtor(bool ignoreDisabled = false)
- {
- if (!ctor)
- return false;
-
- bool result;
- overloadApply(ctor, (Dsymbol s)
- {
- if (auto td = s.isTemplateDeclaration())
- {
- if (ignoreDisabled && td.onemember)
- {
- if (auto ctorDecl = td.onemember.isCtorDeclaration())
- {
- if (ctorDecl.storage_class & STC.disable)
- return 0;
- }
- }
- result = true;
- return 1;
- }
- if (auto ctorDecl = s.isCtorDeclaration())
- {
- if (!ctorDecl.isCpCtor && (!ignoreDisabled || !(ctorDecl.storage_class & STC.disable)))
- {
- result = true;
- return 1;
- }
- }
- return 0;
- });
- return result;
- }
}
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index e65068c7622b..2059978ef8a5 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -22,7 +22,6 @@ import dmd.arraytypes;
import dmd.attrib;
import dmd.astenums;
import dmd.ast_node;
-import dmd.gluelayer;
import dmd.dclass;
import dmd.declaration;
import dmd.denum;
@@ -31,11 +30,12 @@ import dmd.dmodule;
import dmd.dversion;
import dmd.dscope;
import dmd.dstruct;
+import dmd.dsymbolsem : toAlias;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
+import dmd.expressionsem : getDsymbol;
import dmd.func;
-import dmd.globals;
import dmd.id;
import dmd.identifier;
import dmd.init;
@@ -106,22 +106,6 @@ void foreachDsymbol(Dsymbols* symbols, scope void delegate(Dsymbol) dg)
}
}
-
-struct Ungag
-{
- uint oldgag;
-
- extern (D) this(uint old) nothrow @safe
- {
- this.oldgag = old;
- }
-
- extern (C++) ~this() nothrow
- {
- global.gag = oldgag;
- }
-}
-
struct Visibility
{
///
@@ -334,7 +318,7 @@ extern (C++) class Dsymbol : ASTNode
{
Identifier ident;
Dsymbol parent;
- Symbol* csym; // symbol for code generator
+ void* csym; // symbol for code generator
Scope* _scope; // !=null means context to use for semantic()
private DsymbolAttributes* atts; /// attached attribute declarations
const Loc loc; // where defined
@@ -637,7 +621,7 @@ extern (C++) class Dsymbol : ASTNode
static bool has2This(Dsymbol s)
{
if (auto f = s.isFuncDeclaration())
- return f.hasDualContext();
+ return f.hasDualContext;
if (auto ad = s.isAggregateDeclaration())
return ad.vthis2 !is null;
return false;
@@ -688,14 +672,6 @@ extern (C++) class Dsymbol : ASTNode
return parent.isSpeculative();
}
- final Ungag ungagSpeculative() const
- {
- const oldgag = global.gag;
- if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
- global.gag = 0;
- return Ungag(oldgag);
- }
-
// kludge for template.isSymbol()
override final DYNCAST dyncast() const
{
@@ -757,24 +733,6 @@ extern (C++) class Dsymbol : ASTNode
return "symbol";
}
- /*********************************
- * If this symbol is really an alias for another,
- * return that other.
- * If needed, semantic() is invoked due to resolve forward reference.
- */
- Dsymbol toAlias()
- {
- return this;
- }
-
- /*********************************
- * Resolve recursive tuple expansion in eponymous template.
- */
- Dsymbol toAlias2()
- {
- return toAlias();
- }
-
bool overloadInsert(Dsymbol s)
{
//printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
@@ -785,7 +743,7 @@ extern (C++) class Dsymbol : ASTNode
* Returns:
* SIZE_INVALID when the size cannot be determined
*/
- uinteger_t size(Loc loc)
+ ulong size(Loc loc)
{
.error(loc, "%s `%s` symbol `%s` has no size", kind, toPrettyChars, toChars());
return SIZE_INVALID;
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 77e7dabcb6cf..259817e6038d 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -29,6 +29,7 @@ class AliasDeclaration;
class AggregateDeclaration;
class EnumDeclaration;
class ClassDeclaration;
+class StructDeclaration;
class InterfaceDeclaration;
class StructDeclaration;
class UnionDeclaration;
@@ -101,10 +102,13 @@ namespace dmd
void dsymbolSemantic(Dsymbol *dsym, Scope *sc);
void semantic2(Dsymbol *dsym, Scope *sc);
void semantic3(Dsymbol *dsym, Scope* sc);
+ Dsymbol *toAlias(Dsymbol* s);
+ Dsymbol *toAlias2(Dsymbol* s);
// in iasm.d
void asmSemantic(CAsmDeclaration *ad, Scope *sc);
// in iasmgcc.d
void gccAsmSemantic(CAsmDeclaration *ad, Scope *sc);
+ bool isPOD(StructDeclaration *sd);
}
struct Visibility
@@ -223,8 +227,6 @@ public:
virtual Identifier *getIdent();
virtual const char *toPrettyChars(bool QualifyTypes = false);
virtual const char *kind() const;
- virtual Dsymbol *toAlias(); // resolve real symbol
- virtual Dsymbol *toAlias2();
virtual bool overloadInsert(Dsymbol *s);
virtual uinteger_t size(Loc loc);
virtual bool isforwardRef();
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 43fb0b72e4ba..2c4996573d92 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -154,6 +154,199 @@ AlignDeclaration getAlignment(AlignDeclaration ad, Scope* sc)
return ad;
}
+
+/*********************************
+ * Resolve recursive tuple expansion in eponymous template.
+ */
+Dsymbol toAlias2(Dsymbol s)
+{
+ if (auto ad = s.isAliasDeclaration())
+ {
+ if (ad.inuse)
+ {
+ .error(ad.loc, "%s `%s` recursive alias declaration", ad.kind, ad.toPrettyChars);
+ return ad;
+ }
+ ad.inuse = 1;
+ Dsymbol ds = ad.aliassym ? ad.aliassym.toAlias2() : ad;
+ ad.inuse = 0;
+ return ds;
+ }
+ if (auto td = s.isTupleDeclaration())
+ {
+ //printf("TupleDeclaration::toAlias2() '%s' objects = %s\n", toChars(), objects.toChars());
+ for (size_t i = 0; i < td.objects.length; i++)
+ {
+ RootObject o = (*td.objects)[i];
+ if (Dsymbol ds = isDsymbol(o))
+ {
+ ds = ds.toAlias2();
+ (*td.objects)[i] = ds;
+ }
+ }
+ return td;
+ }
+ return toAlias(s);
+}
+
+private Dsymbol toAliasImpl(AliasDeclaration ad)
+{
+ static if (0)
+ printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym: %s, kind: '%s', inuse = %d)\n",
+ ad.loc.toChars(), ad.toChars(), ad, ad.aliassym ? ad.aliassym.toChars() : "", ad.aliassym ? ad.aliassym.kind() : "", ad.inuse);
+ assert(ad != ad.aliassym);
+ //static int count; if (++count == 10) *(char*)0=0;
+
+ Dsymbol err()
+ {
+ // Avoid breaking "recursive alias" state during errors gagged
+ if (global.gag)
+ return ad;
+ ad.aliassym = new AliasDeclaration(ad.loc, ad.ident, Type.terror);
+ ad.type = Type.terror;
+ return ad.aliassym;
+ }
+ // Reading the AliasDeclaration
+ if (!ad.ignoreRead)
+ ad.wasRead = true; // can never assign to this AliasDeclaration again
+
+ if (ad.inuse == 1 && ad.type && ad._scope)
+ {
+ ad.inuse = 2;
+ const olderrors = global.errors;
+ Dsymbol s = ad.type.toDsymbol(ad._scope);
+ //printf("[%s] type = %s, s = %p, this = %p\n", loc.toChars(), type.toChars(), s, this);
+ if (global.errors != olderrors)
+ return err();
+ if (s)
+ {
+ s = s.toAlias();
+ if (global.errors != olderrors)
+ return err();
+ ad.aliassym = s;
+ ad.inuse = 0;
+ }
+ else
+ {
+ Type t = ad.type.typeSemantic(ad.loc, ad._scope);
+ if (t.ty == Terror)
+ return err();
+ if (global.errors != olderrors)
+ return err();
+ //printf("t = %s\n", t.toChars());
+ ad.inuse = 0;
+ }
+ }
+ if (ad.inuse)
+ {
+ .error(ad.loc, "%s `%s` recursive alias declaration", ad.kind, ad.toPrettyChars);
+ return err();
+ }
+
+ if (ad.semanticRun >= PASS.semanticdone)
+ {
+ // semantic is already done.
+
+ // Do not see aliassym !is null, because of lambda aliases.
+
+ // Do not see type.deco !is null, even so "alias T = const int;` needs
+ // semantic analysis to take the storage class `const` as type qualifier.
+ }
+ else
+ {
+ // stop AliasAssign tuple building
+ if (ad.aliassym)
+ {
+ if (auto td = ad.aliassym.isTupleDeclaration())
+ {
+ if (td.building)
+ {
+ td.building = false;
+ ad.semanticRun = PASS.semanticdone;
+ return td;
+ }
+ }
+ }
+ if (ad._import && ad._import._scope)
+ {
+ /* If this is an internal alias for selective/renamed import,
+ * load the module first.
+ */
+ ad._import.dsymbolSemantic(null);
+ }
+ if (ad._scope)
+ {
+ aliasSemantic(ad, ad._scope);
+ }
+ }
+
+ ad.inuse = 1;
+ Dsymbol s = ad.aliassym ? ad.aliassym.toAlias() : ad;
+ ad.inuse = 0;
+ return s;
+}
+
+/*********************************
+ * If this symbol is really an alias for another,
+ * return that other.
+ * If needed, semantic() is invoked due to resolve forward reference.
+ */
+Dsymbol toAlias(Dsymbol s)
+{
+ if (auto ad = s.isAliasDeclaration())
+ {
+ return ad.toAliasImpl();
+ }
+ if (auto imp = s.isImport())
+ {
+ if (imp.aliasId)
+ return imp.mod;
+ return imp;
+ }
+ if (auto vd = s.isVarDeclaration())
+ {
+ //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
+ if ((!vd.type || !vd.type.deco) && vd._scope)
+ dsymbolSemantic(vd, vd._scope);
+
+ assert(vd != vd.aliasTuple);
+ return vd.aliasTuple ? vd.aliasTuple.toAlias() : vd;
+ }
+ // resolve real symbol
+ if (auto ti = s.isTemplateInstance())
+ {
+ static if (LOG)
+ {
+ printf("TemplateInstance.toAlias()\n");
+ }
+ if (!ti.inst)
+ {
+ // Maybe we can resolve it
+ if (ti._scope)
+ {
+ dsymbolSemantic(ti, ti._scope);
+ }
+ if (!ti.inst)
+ {
+ .error(ti.loc, "%s `%s` cannot resolve forward reference", ti.kind, ti.toPrettyChars);
+ ti.errors = true;
+ return ti;
+ }
+ }
+
+ if (ti.inst != ti)
+ return ti.inst.toAlias();
+
+ if (ti.aliasdecl)
+ {
+ return ti.aliasdecl.toAlias();
+ }
+
+ return ti.inst;
+ }
+ return s;
+}
+
const(char)* getMessage(DeprecatedDeclaration dd)
{
if (auto sc = dd._scope)
@@ -244,6 +437,71 @@ package bool allowsContractWithoutBody(FuncDeclaration funcdecl)
return true;
}
+/***************************************
+ * Determine if struct is POD (Plain Old Data).
+ *
+ * POD is defined as:
+ * $(OL
+ * $(LI not nested)
+ * $(LI no postblits, destructors, or assignment operators)
+ * $(LI no `ref` fields or fields that are themselves non-POD)
+ * )
+ * The idea being these are compatible with C structs.
+ *
+ * Returns:
+ * true if struct is POD
+ */
+bool isPOD(StructDeclaration sd)
+{
+ // If we've already determined whether this struct is POD.
+ if (sd.ispod != ThreeState.none)
+ return (sd.ispod == ThreeState.yes);
+
+ import dmd.clone;
+
+ bool hasCpCtorLocal;
+ bool hasMoveCtorLocal;
+ bool needCopyCtor;
+ bool needMoveCtor;
+ needCopyOrMoveCtor(sd, hasCpCtorLocal, hasMoveCtorLocal, needCopyCtor, needMoveCtor);
+
+ if (sd.enclosing || // is nested
+ search(sd, sd.loc, Id.postblit) || // has postblit
+ search(sd, sd.loc, Id.dtor) || // has destructor
+ /* This is commented out because otherwise buildkite vibe.d:
+ `canCAS!Task` fails to compile
+ */
+ //hasMoveCtorLocal || // has move constructor
+ hasCpCtorLocal) // has copy constructor
+ {
+ sd.ispod = ThreeState.no;
+ return false;
+ }
+
+ // Recursively check all fields are POD.
+ for (size_t i = 0; i < sd.fields.length; i++)
+ {
+ VarDeclaration v = sd.fields[i];
+ if (v.storage_class & STC.ref_)
+ {
+ sd.ispod = ThreeState.no;
+ return false;
+ }
+
+ if (auto ts = v.type.baseElemOf().isTypeStruct())
+ {
+ if (!ts.sym.isPOD())
+ {
+ sd.ispod = ThreeState.no;
+ return false;
+ }
+ }
+ }
+
+ sd.ispod = ThreeState.yes;
+ return true;
+}
+
/*
If sd has a copy constructor and ctor is an rvalue constructor,
issue an error.
@@ -351,7 +609,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
* so resolve it ahead.
*/
{
- int save = sc.intypeof;
+ ubyte save = sc.intypeof;
sc.intypeof = 1; // bypass "need this" error check
e = resolveProperties(sc, e);
sc.intypeof = save;
@@ -431,6 +689,55 @@ void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope* scx)
Module.addDeferredSemantic(s);
}
+struct Ungag
+{
+ uint oldgag;
+
+ extern (D) this(uint old) nothrow @safe
+ {
+ this.oldgag = old;
+ }
+
+ extern (C++) ~this() nothrow
+ {
+ global.gag = oldgag;
+ }
+}
+
+Ungag ungagSpeculative(const Dsymbol s)
+{
+ const oldgag = global.gag;
+ if (global.gag && !s.isSpeculative() && !s.toParent2().isFuncDeclaration())
+ global.gag = 0;
+ return Ungag(oldgag);
+}
+
+/*******************************************
+ * Print deprecation warning if we're deprecated, when
+ * this module is imported from scope sc.
+ *
+ * Params:
+ * m = the module
+ * sc = the scope into which we are imported
+ * loc = the location of the import statement
+ */
+private void checkImportDeprecation(Module m, Loc loc, Scope* sc)
+{
+ if (!m.md || !m.md.isdeprecated || sc.isDeprecated)
+ return;
+
+ Expression msg = m.md.msg;
+ if (StringExp se = msg ? msg.toStringExp() : null)
+ {
+ const slice = se.peekString();
+ if (slice.length)
+ {
+ deprecation(m.loc, "%s `%s` is deprecated - %.*s", m.kind, m.toPrettyChars, cast(int)slice.length, slice.ptr);
+ return;
+ }
+ }
+ deprecation(m.loc, "%s `%s` is deprecated", m.kind, m.toPrettyChars);
+}
private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
@@ -779,8 +1086,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ie = ie.expressionSemantic(sc);
if (nelems > 0 && ie)
{
- auto iexps = new Expressions();
- iexps.push(ie);
+ auto iexps = new Expressions(ie);
auto exps = new Expressions();
for (size_t pos = 0; pos < iexps.length; pos++)
{
@@ -1397,6 +1703,19 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
exp = ErrorExp.get();
}
}
+ else if (exp.isBitField())
+ {
+ if (dsym.storage_class & STC.autoref)
+ {
+ dsym.storage_class &= ~STC.ref_;
+ constructInit(false);
+ }
+ else
+ {
+ .error(dsym.loc, "bitfield `%s` cannot be assigned to `ref %s`", exp.toChars(), dsym.toChars());
+ exp = ErrorExp.get();
+ }
+ }
else
{
constructInit(false);
@@ -1592,7 +1911,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration())
{
- .error(dsym.loc, "%s `%s` - bit-field must be member of struct, union, or class", dsym.kind, dsym.toPrettyChars);
+ .error(dsym.loc, "%s `%s` - bitfield must be member of struct, union, or class", dsym.kind, dsym.toPrettyChars);
}
sc = sc.startCTFE();
@@ -1602,18 +1921,18 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (!dsym.type.isIntegral())
{
// C11 6.7.2.1-5
- error(width.loc, "bit-field type `%s` is not an integer type", dsym.type.toChars());
+ error(width.loc, "bitfield type `%s` is not an integer type", dsym.type.toChars());
dsym.errors = true;
}
if (!width.isIntegerExp())
{
- error(width.loc, "bit-field width `%s` is not an integer constant", dsym.width.toChars());
+ error(width.loc, "bitfield width `%s` is not an integer constant", dsym.width.toChars());
dsym.errors = true;
}
const uwidth = width.toInteger(); // uwidth is unsigned
if (uwidth == 0 && !dsym.isAnonymous())
{
- error(width.loc, "bit-field `%s` has zero width", dsym.toChars());
+ error(width.loc, "bitfield `%s` has zero width", dsym.toChars());
dsym.errors = true;
}
const sz = dsym.type.size();
@@ -1622,7 +1941,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
const max_width = sz * 8;
if (uwidth > max_width)
{
- error(width.loc, "width `%lld` of bit-field `%s` does not fit in type `%s`", cast(long)uwidth, dsym.toChars(), dsym.type.toChars());
+ error(width.loc, "width `%lld` of bitfield `%s` does not fit in type `%s`", cast(long)uwidth, dsym.toChars(), dsym.type.toChars());
dsym.errors = true;
}
dsym.fieldWidth = cast(uint)uwidth;
@@ -2104,7 +2423,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
/* Run semantic on each argument, place results in tiargs[],
* then find best match template with tiargs
*/
- if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, ArgumentList()))
+ if (!tm.findMixinTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, ArgumentList()))
{
if (tm.semanticRun == PASS.initial) // forward reference had occurred
{
@@ -2686,9 +3005,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null);
v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : STC.none);
- auto sa = new Statements();
Statement s = new ExpStatement(Loc.initial, v);
- sa.push(s);
+ auto sa = new Statements(s);
Expression e;
if (isShared)
@@ -3329,7 +3647,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
//
- // For two structures or unions, corresponding bit-fields shall have the same widths.
+ // For two structures or unions, corresponding bitfields shall have the same widths.
//
BitFieldDeclaration bfa = a_field.isBitFieldDeclaration();
BitFieldDeclaration bfb = b_field.isBitFieldDeclaration();
@@ -4377,6 +4695,23 @@ private void attribAddMember(AttribDeclaration atb, Scope* sc, ScopeDsymbol sds)
}
}
+/****************************************************
+ * Declare parameters of template instance, initialize them with the
+ * template instance arguments.
+ */
+private void declareParameters(TemplateInstance ti, Scope* sc)
+{
+ TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+
+ //printf("TemplateInstance.declareParameters()\n");
+ foreach (i, o; ti.tdtypes) // initializer for tp
+ {
+ TemplateParameter tp = (*tempdecl.parameters)[i];
+ //printf("\ttdtypes[%d] = %p\n", i, o);
+ declareParameter(tempdecl, sc, tp, o);
+ }
+}
private extern(C++) class AddMemberVisitor : Visitor
{
alias visit = Visitor.visit;
@@ -4764,6 +5099,173 @@ private bool isDRuntimeHook(Identifier id)
id == Id._d_arrayappendcTX;
}
+/*****************************************
+ * Append `ti` to the specific module `ti.members[]`
+ */
+private Dsymbols* appendToModuleMember(TemplateInstance ti)
+{
+ Module mi = ti.minst; // instantiated . inserted module
+
+ //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
+ // toPrettyChars(),
+ // enclosing ? enclosing.toPrettyChars() : null,
+ // mi ? mi.toPrettyChars() : null);
+ if (global.params.allInst || !mi || mi.isRoot())
+ {
+ /* If the instantiated module is speculative or root, insert to the
+ * member of a root module. Then:
+ * - semantic3 pass will get called on the instance members.
+ * - codegen pass will get a selection chance to do/skip it (needsCodegen()).
+ */
+ static Dsymbol getStrictEnclosing(TemplateInstance ti)
+ {
+ do
+ {
+ if (ti.enclosing)
+ return ti.enclosing;
+ ti = ti.tempdecl.isInstantiated();
+ } while (ti);
+ return null;
+ }
+
+ Dsymbol enc = getStrictEnclosing(ti);
+ // insert target is made stable by using the module
+ // where tempdecl is declared.
+ mi = (enc ? enc : ti.tempdecl).getModule();
+ if (!mi.isRoot())
+ {
+ if (mi.importedFrom)
+ {
+ mi = mi.importedFrom;
+ assert(mi.isRoot());
+ }
+ else
+ {
+ // This can happen when using the frontend as a library.
+ // Append it to the non-root module.
+ }
+ }
+ }
+ else
+ {
+ /* If the instantiated module is non-root, insert to the member of the
+ * non-root module. Then:
+ * - semantic3 pass won't be called on the instance.
+ * - codegen pass won't reach to the instance.
+ * Unless it is re-appended to a root module later (with changed minst).
+ */
+ }
+ //printf("\t-. mi = %s\n", mi.toPrettyChars());
+
+ if (ti.memberOf) // already appended to some module
+ {
+ assert(mi.isRoot(), "can only re-append to a root module");
+ if (ti.memberOf.isRoot())
+ return null; // no need to move to another root module
+ }
+
+ Dsymbols* a = mi.members;
+ a.push(ti);
+ ti.memberOf = mi;
+ if (mi.semanticRun >= PASS.semantic2done && mi.isRoot())
+ Module.addDeferredSemantic2(ti);
+ if (mi.semanticRun >= PASS.semantic3done && mi.isRoot())
+ Module.addDeferredSemantic3(ti);
+ return a;
+}
+
+private void expandMembers(TemplateInstance ti,Scope* sc2)
+{
+ ti.members.foreachDsymbol( (s) { s.setScope (sc2); } );
+
+ ti.members.foreachDsymbol( (s) { s.importAll(sc2); } );
+
+ if (!ti.aliasdecl)
+ {
+ /* static if's are crucial to evaluating aliasdecl correctly. But
+ * evaluating the if/else bodies may require aliasdecl.
+ * So, evaluate the condition for static if's, but not their if/else bodies.
+ * Then try to set aliasdecl.
+ * Later do the if/else bodies.
+ * https://issues.dlang.org/show_bug.cgi?id=23598
+ * It might be better to do this by attaching a lambda to the StaticIfDeclaration
+ * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
+ */
+ bool done;
+ void staticIfDg(Dsymbol s)
+ {
+ if (done || ti.aliasdecl)
+ return;
+ //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
+ if (!s.isStaticIfDeclaration())
+ {
+ //s.dsymbolSemantic(sc2);
+ done = true;
+ return;
+ }
+ auto sid = s.isStaticIfDeclaration();
+ sid.include(sc2);
+ if (ti.members.length)
+ {
+ Dsymbol sa;
+ if (oneMembers(ti.members, sa, ti.tempdecl.ident) && sa)
+ ti.aliasdecl = sa;
+ }
+ done = true;
+ }
+
+ ti.members.foreachDsymbol(&staticIfDg);
+ }
+
+ void symbolDg(Dsymbol s)
+ {
+ //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
+ //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
+ //if (enclosing)
+ // s.parent = sc.parent;
+ //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
+ s.dsymbolSemantic(sc2);
+ //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
+ Module.runDeferredSemantic();
+ }
+
+ ti.members.foreachDsymbol(&symbolDg);
+}
+
+private void tryExpandMembers(TemplateInstance ti, Scope* sc2)
+{
+ __gshared int nest;
+ // extracted to a function to allow windows SEH to work without destructors in the same function
+ //printf("%d\n", nest);
+ if (++nest > global.recursionLimit)
+ {
+ global.gag = 0; // ensure error message gets printed
+ .error(ti.loc, "%s `%s` recursive expansion exceeded allowed nesting limit", ti.kind, ti.toPrettyChars);
+ fatal();
+ }
+
+ ti.expandMembers(sc2);
+
+ nest--;
+}
+
+private void trySemantic3(TemplateInstance ti, Scope* sc2)
+{
+ // extracted to a function to allow windows SEH to work without destructors in the same function
+ __gshared int nest;
+ //printf("%d\n", nest);
+ if (++nest > global.recursionLimit)
+ {
+ global.gag = 0; // ensure error message gets printed
+ .error(ti.loc, "%s `%s` recursive expansion exceeded allowed nesting limit", ti.kind, ti.toPrettyChars);
+ fatal();
+ }
+
+ semantic3(ti, sc2);
+
+ --nest;
+}
+
void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList)
{
//printf("[%s] TemplateInstance.dsymbolSemantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst.loc.toChars(), tempinst.toChars(), tempinst, global.gag, sc);
@@ -5080,8 +5582,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
if (STC stc = ModToStc(t.mod))
{
//printf("t = %s, stc = x%llx\n", t.toChars(), stc);
- auto s = new Dsymbols();
- s.push(new StorageClassDeclaration(stc, tempinst.members));
+ auto s = new Dsymbols(new StorageClassDeclaration(stc, tempinst.members));
tempinst.members = s;
}
break;
@@ -5677,6 +6178,196 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
normalRet();
}
+/**********************************************
+ * Find template declaration corresponding to template instance.
+ *
+ * Returns:
+ * false if finding fails.
+ * Note:
+ * This function is reentrant against error occurrence. If returns false,
+ * any members of this object won't be modified, and repetition call will
+ * reproduce same error.
+ */
+bool findTempDecl(TemplateInstance ti, Scope* sc, WithScopeSymbol* pwithsym)
+{
+ if (pwithsym)
+ *pwithsym = null;
+
+ if (ti.havetempdecl)
+ return true;
+
+ //printf("TemplateInstance.findTempDecl() %s\n", toChars());
+ if (!ti.tempdecl)
+ {
+ /* Given:
+ * foo!( ... )
+ * figure out which TemplateDeclaration foo refers to.
+ */
+ Identifier id = ti.name;
+ Dsymbol scopesym;
+ Dsymbol s = sc.search(ti.loc, id, scopesym);
+ if (!s)
+ {
+ s = sc.search_correct(id);
+ if (s)
+ .error(ti.loc, "%s `%s` template `%s` is not defined, did you mean %s?", ti.kind, ti.toPrettyChars(), id.toChars(), s.toChars());
+ else
+ .error(ti.loc, "%s `%s` template `%s` is not defined", ti.kind, ti.toPrettyChars(), id.toChars());
+ return false;
+ }
+ static if (LOG)
+ {
+ printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind());
+ if (s.parent)
+ printf("s.parent = '%s'\n", s.parent.toChars());
+ }
+ if (pwithsym)
+ *pwithsym = scopesym.isWithScopeSymbol();
+
+ /* We might have found an alias within a template when
+ * we really want the template.
+ */
+ TemplateInstance ti2;
+ if (s.parent && (ti2 = s.parent.isTemplateInstance()) !is null)
+ {
+ if (ti2.tempdecl && ti2.tempdecl.ident == id)
+ {
+ /* This is so that one can refer to the enclosing
+ * template, even if it has the same name as a member
+ * of the template, if it has a !(arguments)
+ */
+ TemplateDeclaration td = ti2.tempdecl.isTemplateDeclaration();
+ assert(td);
+ if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td.overroot; // then get the start
+ s = td;
+ }
+ }
+
+ // The template might originate from a selective import which implies that
+ // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
+ // This is the last place where we see the deprecated alias because it is
+ // stripped below, so check if the selective import was deprecated.
+ // See https://issues.dlang.org/show_bug.cgi?id=20840.
+ if (s.isAliasDeclaration())
+ s.checkDeprecated(ti.loc, sc);
+
+ if (!ti.updateTempDecl(sc, s))
+ {
+ return false;
+ }
+ }
+ assert(ti.tempdecl);
+
+ // Look for forward references
+ auto tovers = ti.tempdecl.isOverloadSet();
+ foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
+ {
+ Dsymbol dstart = tovers ? tovers.a[oi] : ti.tempdecl;
+ int r = overloadApply(dstart, (Dsymbol s)
+ {
+ auto td = s.isTemplateDeclaration();
+ if (!td)
+ return 0;
+
+ if (td.semanticRun == PASS.initial)
+ {
+ if (td._scope)
+ {
+ // Try to fix forward reference. Ungag errors while doing so.
+ auto ungag = td.ungagSpeculative();
+ td.dsymbolSemantic(td._scope);
+ }
+ if (td.semanticRun == PASS.initial)
+ {
+ .error(ti.loc, "%s `%s` `%s` forward references template declaration `%s`",
+ ti.kind, ti.toPrettyChars(), ti.toChars(), td.toChars());
+ return 1;
+ }
+ }
+ return 0;
+ });
+ if (r)
+ return false;
+ }
+ return true;
+}
+
+private bool findMixinTempDecl(TemplateMixin tm, Scope* sc)
+{
+ // Follow qualifications to find the TemplateDeclaration
+ if (!tm.tempdecl)
+ {
+ Expression e;
+ Type t;
+ Dsymbol s;
+ tm.tqual.resolve(tm.loc, sc, e, t, s);
+ if (!s)
+ {
+ .error(tm.loc, "%s `%s` is not defined", tm.kind, tm.toPrettyChars);
+ return false;
+ }
+ s = s.toAlias();
+ tm.tempdecl = s.isTemplateDeclaration();
+ OverloadSet os = s.isOverloadSet();
+
+ /* If an OverloadSet, look for a unique member that is a template declaration
+ */
+ if (os)
+ {
+ Dsymbol ds = null;
+ foreach (i, sym; os.a)
+ {
+ Dsymbol s2 = sym.isTemplateDeclaration();
+ if (s2)
+ {
+ if (ds)
+ {
+ tm.tempdecl = os;
+ break;
+ }
+ ds = s2;
+ }
+ }
+ }
+ if (!tm.tempdecl)
+ {
+ .error(tm.loc, "%s `%s` - `%s` is a %s, not a template", tm.kind,
+ tm.toPrettyChars, s.toChars(), s.kind());
+ return false;
+ }
+ }
+ assert(tm.tempdecl);
+
+ // Look for forward references
+ auto tovers = tm.tempdecl.isOverloadSet();
+ foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
+ {
+ Dsymbol dstart = tovers ? tovers.a[oi] : tm.tempdecl;
+ int r = overloadApply(dstart, (Dsymbol s)
+ {
+ auto td = s.isTemplateDeclaration();
+ if (!td)
+ return 0;
+
+ if (td.semanticRun == PASS.initial)
+ {
+ if (td._scope)
+ td.dsymbolSemantic(td._scope);
+ else
+ {
+ tm.semanticRun = PASS.initial;
+ return 1;
+ }
+ }
+ return 0;
+ });
+ if (r)
+ return false;
+ }
+ return true;
+}
+
/********************
* Perform semantic on AliasAssignment.
* Has a lot of similarities to aliasSemantic(). Perhaps they should share code.
@@ -5939,7 +6630,7 @@ private TupleDeclaration aliasAssignInPlace(Scope* sc, TemplateInstance tempinst
if (td)
aliassym.aliassym = td;
aliassym.semanticRun = PASS.semanticdone;
- if (!TemplateInstance.semanticTiargs(tempinst.loc, sc, tempinst.tiargs, 0, td))
+ if (!TemplateInstance_semanticTiargs(tempinst.loc, sc, tempinst.tiargs, 0, td))
{
tempinst.errors = true;
return null;
@@ -5993,6 +6684,39 @@ private TupleDeclaration aliasAssignInPlace(Scope* sc, TemplateInstance tempinst
return td;
}
+/*********************************
+ * Iterate this dsymbol or members of this scoped dsymbol, then
+ * call `fp` with the found symbol and `params`.
+ * Params:
+ * symbol = the dsymbol or parent of members to call fp on
+ * fp = function pointer to process the iterated symbol.
+ * If it returns nonzero, the iteration will be aborted.
+ * ctx = context parameter passed to fp.
+ * Returns:
+ * nonzero if the iteration is aborted by the return value of fp,
+ * or 0 if it's completed.
+ */
+int apply(Dsymbol symbol, int function(Dsymbol, void*) fp, void* ctx)
+{
+ if (auto nd = symbol.isNspace())
+ {
+ return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
+ }
+ if (auto ad = symbol.isAttribDeclaration())
+ {
+ return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
+ }
+ if (auto tm = symbol.isTemplateMixin())
+ {
+ if (tm._scope) // if fwd reference
+ dsymbolSemantic(tm, null); // try to resolve it
+
+ return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
+ }
+
+ return fp(symbol, ctx);
+}
+
/***************************************
* Check if a template instance is a trivial AliasSeq but without other overloads.
* We can only be 100% sure of being AliasSeq after running semanticTiargs()
@@ -6109,12 +6833,81 @@ bool determineFields(AggregateDeclaration ad)
return true;
}
+/****************************
+ * A Singleton that loads core.stdc.config
+ * Returns:
+ * Module of core.stdc.config, null if couldn't find it
+ */
+Module loadCoreStdcConfig()
+{
+ __gshared Module core_stdc_config;
+ auto pkgids = new Identifier[2];
+ pkgids[0] = Id.core;
+ pkgids[1] = Id.stdc;
+ return loadModuleFromLibrary(core_stdc_config, pkgids, Id.config);
+}
+
+/****************************
+ * A Singleton that loads core.atomic
+ * Returns:
+ * Module of core.atomic, null if couldn't find it
+ */
+private Module loadCoreAtomic()
+{
+ __gshared Module core_atomic;
+ auto pkgids = new Identifier[1];
+ pkgids[0] = Id.core;
+ return loadModuleFromLibrary(core_atomic, pkgids, Id.atomic);
+}
+
+/****************************
+ * A Singleton that loads std.math
+ * Returns:
+ * Module of std.math, null if couldn't find it
+ */
+Module loadStdMath()
+{
+ __gshared Module std_math;
+ auto pkgids = new Identifier[1];
+ pkgids[0] = Id.std;
+ return loadModuleFromLibrary(std_math, pkgids, Id.math);
+}
+
+/**********************************
+ * Load a Module from the library.
+ * Params:
+ * mod = cached return value of this call
+ * pkgids = package identifiers
+ * modid = module id
+ * Returns:
+ * Module loaded, null if cannot load it
+ */
+extern (D) private static Module loadModuleFromLibrary(ref Module mod, Identifier[] pkgids, Identifier modid)
+{
+ if (mod)
+ return mod;
+
+ auto imp = new Import(Loc.initial, pkgids[], modid, null, true);
+ // Module.load will call fatal() if there's no module available.
+ // Gag the error here, pushing the error handling to the caller.
+ const errors = global.startGagging();
+ imp.load(null);
+ if (imp.mod)
+ {
+ imp.mod.importAll(null);
+ imp.mod.dsymbolSemantic(null);
+ }
+ global.endGagging(errors);
+ mod = imp.mod;
+ return mod;
+}
+
/// Do an atomic operation (currently tailored to [shared] static ctors|dtors) needs
private CallExp doAtomicOp (string op, Identifier var, Expression arg)
{
assert(op == "-=" || op == "+=");
- Module mod = Module.loadCoreAtomic();
+ Module mod = loadCoreAtomic();
if (!mod)
return null; // core.atomic couldn't be loaded
@@ -6488,7 +7281,7 @@ private extern(C++) class SearchVisitor : Visitor
{
//printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
if (ident != Id.dollar)
- return setResult(null);
+ return visit(cast(ScopeDsymbol)ass);
VarDeclaration* pvar;
Expression ce;
@@ -6608,10 +7401,9 @@ private extern(C++) class SearchVisitor : Visitor
{
assert(0);
}
- auto tiargs = new Objects();
Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
edim = edim.expressionSemantic(ass._scope);
- tiargs.push(edim);
+ auto tiargs = new Objects(edim);
e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
}
else
@@ -7406,7 +8198,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
const style = target.c.bitFieldStyle;
if (style != TargetC.BitFieldStyle.MS && style != TargetC.BitFieldStyle.Gcc_Clang)
- assert(0, "unsupported bit-field style");
+ assert(0, "unsupported bitfield style");
const isMicrosoftStyle = style == TargetC.BitFieldStyle.MS;
const contributesToAggregateAlignment = target.c.contributesToAggregateAlignment(bfd);
@@ -7476,7 +8268,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
}
else if (!isMicrosoftStyle)
{
- // If the bit-field spans more units of alignment than its type
+ // If the bitfield spans more units of alignment than its type
// and is at the alignment boundary, start a new field at the
// next alignment boundary. This affects when offsetof reports
// a higher number and bitoffsetof starts at zero again.
@@ -7622,14 +8414,56 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
isunion);
// Add to the anon fields the base offset of this anonymous aggregate
- //printf("anon fields, anonoffset = %d\n", anonoffset);
- foreach (const i; fieldstart .. ad.fields.length)
+ //printf("anon fields, anonoffset = %d\n", anond.anonoffset);
+ if (anond.anonoffset)
+ anond.decl.foreachDsymbol( (s) => s.adjustBaseOffset(anond.anonoffset) );
+ }
+ }
+}
+
+// Adds `offset` as the new base offset of all field members in `d`.
+private void adjustBaseOffset(Dsymbol d, uint offset)
+{
+ switch (d.dsym)
+ {
+ case DSYM.nspace:
+ auto ns = cast(Nspace)d;
+ ns.members.foreachDsymbol( s => s.adjustBaseOffset(offset) );
+ break;
+
+ case DSYM.templateMixin:
+ auto tm = cast(TemplateMixin)d;
+ tm.members.foreachDsymbol( s => s.adjustBaseOffset(offset) );
+ break;
+
+ case DSYM.anonDeclaration:
+ auto ad = cast(AnonDeclaration)d;
+ if (ad.decl)
+ ad.decl.foreachDsymbol( s => s.adjustBaseOffset(offset) );
+ break;
+
+ case DSYM.bitFieldDeclaration:
+ auto bfd = cast(BitFieldDeclaration)d;
+ bfd.offset += offset;
+ //printf("\t%s %d : %d\n", bfd.toChars(), bfd.offset, bfd.bitOffset);
+ break;
+
+ default:
+ if (auto vd = d.isVarDeclaration())
{
- VarDeclaration v = ad.fields[i];
- //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
- v.offset += anond.anonoffset;
+ if (vd.aliasTuple)
+ vd.aliasTuple.foreachVar( s => s.adjustBaseOffset(offset) );
+ else if (vd.isField())
+ {
+ vd.offset += offset;
+ //printf("\t%s %d\n", vd.toChars(), vd.offset);
+ }
}
- }
+ else if (auto atd = d.isAttribDeclaration())
+ {
+ atd.include(null).foreachDsymbol( s => s.adjustBaseOffset(offset) );
+ }
+ break;
}
}
@@ -7989,8 +8823,6 @@ private Expression callScopeDtor(VarDeclaration vd, Scope* sc)
const sz = vd.type.size();
assert(sz != SIZE_INVALID);
- if (!sz)
- return null;
if (vd.type.toBasetype().ty == Tstruct)
{
@@ -8644,6 +9476,87 @@ bool _isZeroInit(Expression exp)
}
}
+/***************************************
+ * Calculate `ad.field[i].overlapped` and `overlapUnsafe`, and check that all of explicit
+ * field initializers have unique memory space on instance.
+ * Returns:
+ * true if any errors happen.
+ */
+private bool checkOverlappedFields(AggregateDeclaration ad)
+{
+ //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
+ assert(ad.sizeok == Sizeok.done);
+ size_t nfields = ad.fields.length;
+ if (ad.isNested())
+ {
+ auto cd = ad.isClassDeclaration();
+ if (!cd || !cd.baseClass || !cd.baseClass.isNested())
+ nfields--;
+ if (ad.vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
+ nfields--;
+ }
+ bool errors = false;
+
+ // Fill in missing any elements with default initializers
+ foreach (i; 0 .. nfields)
+ {
+ auto vd = ad.fields[i];
+ if (vd.errors)
+ {
+ errors = true;
+ continue;
+ }
+
+ const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();
+
+ // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
+ foreach (j; 0 .. nfields)
+ {
+ if (i == j)
+ continue;
+ auto v2 = ad.fields[j];
+ if (v2.errors)
+ {
+ errors = true;
+ continue;
+ }
+ if (!vd.isOverlappedWith(v2))
+ continue;
+
+ // vd and v2 are overlapping.
+ vd.overlapped = true;
+ v2.overlapped = true;
+
+ if (!MODimplicitConv(vd.type.mod, v2.type.mod))
+ v2.overlapUnsafe = true;
+ if (!MODimplicitConv(v2.type.mod, vd.type.mod))
+ vd.overlapUnsafe = true;
+
+ if (i > j)
+ continue;
+
+ if (!v2._init)
+ continue;
+
+ if (v2._init.isVoidInitializer())
+ continue;
+
+ if (vd._init && !vdIsVoidInit && v2._init)
+ {
+ .error(ad.loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+ errors = true;
+ }
+ else if (v2._init && i < j)
+ {
+ .error(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
+ v2.toChars(), dmd.hdrgen.toChars(v2._init), vd.toChars());
+ errors = true;
+ }
+ }
+ }
+ return errors;
+}
+
private extern(C++) class FinalizeSizeVisitor : Visitor
{
alias visit = Visitor.visit;
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 16e192da20ff..b2a61dda441b 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -53,13 +53,11 @@ import dmd.dinterpret;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem : dsymbolSemantic, checkDeprecated, aliasSemantic, search, search_correct, setScope, importAll, include, hasStaticCtorOrDtor, oneMembers;
+import dmd.dsymbolsem : aliasSemantic, oneMembers, toAlias;
import dmd.errors;
import dmd.errorsink;
import dmd.expression;
-import dmd.expressionsem : resolveLoc, expressionSemantic, resolveProperties, checkValue;
import dmd.func;
-import dmd.funcsem : functionSemantic, leastAsSpecialized, overloadApply;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -74,16 +72,11 @@ import dmd.optimize;
import dmd.root.array;
import dmd.common.outbuffer;
import dmd.rootobject;
-import dmd.semantic3 : semantic3;
-import dmd.templatesem : matchWithInstance, formatParamsWithTiargs, leastAsSpecialized, declareParameter;
+import dmd.templatesem : getExpression, TemplateInstance_semanticTiargs;
import dmd.tokens;
-import dmd.typesem : hasPointers, typeSemantic, merge, merge2, resolve, toDsymbol,
- addStorageClass, isBaseOf, equivalent, sarrayOf, constOf, mutableOf, unSharedOf,
- unqualify, aliasthisOf, castMod, substWildTo, addMod;
+import dmd.typesem : typeSemantic, isBaseOf, resolveNamedArgs;
import dmd.visitor;
-import dmd.templateparamsem;
-
//debug = FindExistingInstance; // print debug stats of findExistingInstance
private enum LOG = false;
@@ -202,76 +195,6 @@ inout(Type) getType(inout RootObject o)
}
-/***********************************
- * If oarg represents a Dsymbol, return that Dsymbol
- * Params:
- * oarg = argument to check
- * Returns:
- * Dsymbol if a symbol, null if not
- */
-Dsymbol getDsymbol(RootObject oarg)
-{
- //printf("getDsymbol()\n");
- //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
- if (auto ea = isExpression(oarg))
- {
- // Try to convert Expression to symbol
- if (auto ve = ea.isVarExp())
- return ve.var;
- if (auto fe = ea.isFuncExp())
- return fe.td ? fe.td : fe.fd;
- if (auto te = ea.isTemplateExp())
- return te.td;
- if (auto te = ea.isScopeExp())
- return te.sds;
- return null;
- }
- // Try to convert Type to symbol
- if (auto ta = isType(oarg))
- return ta.toDsymbol(null);
- return isDsymbol(oarg); // if already a symbol
-}
-
-
-private Expression getValue(ref Dsymbol s)
-{
- if (s)
- {
- if (VarDeclaration v = s.isVarDeclaration())
- {
- if (v.storage_class & STC.manifest)
- return v.getConstInitializer();
- }
- }
- return null;
-}
-
-/***********************
- * Try to get value from manifest constant
- */
-private Expression getValue(Expression e)
-{
- if (!e)
- return null;
- if (auto ve = e.isVarExp())
- {
- if (auto v = ve.var.isVarDeclaration())
- {
- if (v.storage_class & STC.manifest)
- {
- e = v.getConstInitializer();
- }
- }
- }
- return e;
-}
-
-private Expression getExpression(RootObject o)
-{
- auto s = isDsymbol(o);
- return s ? .getValue(s) : .getValue(isExpression(o));
-}
-
/******************************
* See if two objects match
* Params:
@@ -279,7 +202,7 @@ private Expression getExpression(RootObject o)
* o2 = second object
* Returns: true if they match
*/
-private bool match(RootObject o1, RootObject o2)
+bool match(RootObject o1, RootObject o2)
{
enum log = false;
@@ -766,66 +689,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
return visibility;
}
- /****************************
- * 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(*parameters, *lastConstraintTiargs, isVariadic() !is null, 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();
- }
-
debug (FindExistingInstance)
{
__gshared uint nFound, nNotFound, nAdded, nRemoved;
@@ -947,4068 +810,1165 @@ extern (C++) final class TypeDeduced : Type
argexps.push(e);
tparams.push(tparam);
}
-
- MATCH matchAll(Type tt)
- {
- MATCH match = MATCH.exact;
- foreach (j, e; argexps)
- {
- assert(e);
- if (e == emptyArrayElement)
- continue;
-
- Type t = tt.addMod(tparams[j].mod).substWildTo(MODFlags.const_);
-
- MATCH m = e.implicitConvTo(t);
- if (match > m)
- match = m;
- if (match == MATCH.nomatch)
- break;
- }
- return match;
- }
}
-
/* ======================== Type ============================================ */
-/****
- * Given an identifier, figure out which TemplateParameter it is.
- * Return IDX_NOTFOUND if not found.
+/***********************************************************
+ * Check whether the type t representation relies on one or more the template parameters.
+ * Params:
+ * t = Tested type, if null, returns false.
+ * tparams = Template parameters.
+ * iStart = Start index of tparams to limit the tested parameters. If it's
+ * nonzero, tparams[0..iStart] will be excluded from the test target.
*/
-private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters)
+bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0)
{
- for (size_t i = 0; i < parameters.length; i++)
- {
- TemplateParameter tp = (*parameters)[i];
- if (tp.ident.equals(id))
- return i;
- }
- return IDX_NOTFOUND;
+ return reliesOnTemplateParameters(t, (*tparams)[0 .. tparams.length]);
}
-size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
+/***********************************************************
+ * Check whether the type t representation relies on one or more the template parameters.
+ * Params:
+ * t = Tested type, if null, returns false.
+ * tparams = Template parameters.
+ */
+bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
{
- if (TypeIdentifier tident = tparam.isTypeIdentifier())
+ bool visitVector(TypeVector t)
{
- //printf("\ttident = '%s'\n", tident.toChars());
- return templateIdentifierLookup(tident.ident, parameters);
+ return t.basetype.reliesOnTemplateParameters(tparams);
}
- return IDX_NOTFOUND;
-}
-
-private auto X(T, U)(T m, U n)
-{
- return (m << 4) | n;
-}
-
-ubyte deduceWildHelper(Type t, Type* at, Type tparam)
-{
- if ((tparam.mod & MODFlags.wild) == 0)
- return 0;
- *at = null;
+ bool visitAArray(TypeAArray t)
+ {
+ return t.next.reliesOnTemplateParameters(tparams) ||
+ t.index.reliesOnTemplateParameters(tparams);
+ }
- switch (X(tparam.mod, t.mod))
+ bool visitFunction(TypeFunction t)
{
- case X(MODFlags.wild, 0):
- case X(MODFlags.wild, MODFlags.const_):
- case X(MODFlags.wild, MODFlags.shared_):
- case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.wild, MODFlags.immutable_):
- case X(MODFlags.wildconst, 0):
- case X(MODFlags.wildconst, MODFlags.const_):
- case X(MODFlags.wildconst, MODFlags.shared_):
- case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.wildconst, MODFlags.immutable_):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
- {
- ubyte wm = (t.mod & ~MODFlags.shared_);
- if (wm == 0)
- wm = MODFlags.mutable;
- ubyte m = (t.mod & (MODFlags.const_ | MODFlags.immutable_)) | (tparam.mod & t.mod & MODFlags.shared_);
- *at = t.unqualify(m);
- return wm;
- }
- case X(MODFlags.wild, MODFlags.wild):
- case X(MODFlags.wild, MODFlags.wildconst):
- case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
- case X(MODFlags.wildconst, MODFlags.wild):
- case X(MODFlags.wildconst, MODFlags.wildconst):
- case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
+ foreach (i, fparam; t.parameterList)
{
- *at = t.unqualify(tparam.mod & t.mod);
- return MODFlags.wild;
+ if (fparam.type.reliesOnTemplateParameters(tparams))
+ return true;
}
- default:
- return 0;
+ return t.next.reliesOnTemplateParameters(tparams);
}
-}
-
-/**
- * Returns the common type of the 2 types.
- */
-private Type rawTypeMerge(Type t1, Type t2)
-{
- if (t1.equals(t2))
- return t1;
- if (t1.equivalent(t2))
- return t1.castMod(MODmerge(t1.mod, t2.mod));
-
- auto t1b = t1.toBasetype();
- auto t2b = t2.toBasetype();
- if (t1b.equals(t2b))
- return t1b;
- if (t1b.equivalent(t2b))
- return t1b.castMod(MODmerge(t1b.mod, t2b.mod));
-
- auto ty = implicitConvCommonTy(t1b.ty, t2b.ty);
- if (ty != Terror)
- return Type.basic[ty];
-
- return null;
-}
-MATCH deduceTypeHelper(Type t, out Type at, Type tparam)
-{
- // 9*9 == 81 cases
- switch (X(tparam.mod, t.mod))
+ bool visitIdentifier(TypeIdentifier t)
{
- case X(0, 0):
- case X(0, MODFlags.const_):
- case X(0, MODFlags.wild):
- case X(0, MODFlags.wildconst):
- case X(0, MODFlags.shared_):
- case X(0, MODFlags.shared_ | MODFlags.const_):
- case X(0, MODFlags.shared_ | MODFlags.wild):
- case X(0, MODFlags.shared_ | MODFlags.wildconst):
- case X(0, MODFlags.immutable_):
- // foo(U) T => T
- // foo(U) const(T) => const(T)
- // foo(U) inout(T) => inout(T)
- // foo(U) inout(const(T)) => inout(const(T))
- // foo(U) shared(T) => shared(T)
- // foo(U) shared(const(T)) => shared(const(T))
- // foo(U) shared(inout(T)) => shared(inout(T))
- // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
- // foo(U) immutable(T) => immutable(T)
- {
- at = t;
- return MATCH.exact;
- }
- case X(MODFlags.const_, MODFlags.const_):
- case X(MODFlags.wild, MODFlags.wild):
- case X(MODFlags.wildconst, MODFlags.wildconst):
- case X(MODFlags.shared_, MODFlags.shared_):
- case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
- case X(MODFlags.immutable_, MODFlags.immutable_):
- // foo(const(U)) const(T) => T
- // foo(inout(U)) inout(T) => T
- // foo(inout(const(U))) inout(const(T)) => T
- // foo(shared(U)) shared(T) => T
- // foo(shared(const(U))) shared(const(T)) => T
- // foo(shared(inout(U))) shared(inout(T)) => T
- // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
- // foo(immutable(U)) immutable(T) => T
- {
- at = t.mutableOf().unSharedOf();
- return MATCH.exact;
- }
- case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
- // foo(const(U)) shared(const(T)) => shared(T)
- // foo(inout(U)) shared(inout(T)) => shared(T)
- // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
- {
- at = t.mutableOf();
- return MATCH.exact;
- }
- case X(MODFlags.const_, 0):
- case X(MODFlags.const_, MODFlags.wild):
- case X(MODFlags.const_, MODFlags.wildconst):
- case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
- case X(MODFlags.const_, MODFlags.immutable_):
- case X(MODFlags.shared_ | MODFlags.const_, MODFlags.immutable_):
- // foo(const(U)) T => T
- // foo(const(U)) inout(T) => T
- // foo(const(U)) inout(const(T)) => T
- // foo(const(U)) shared(inout(T)) => shared(T)
- // foo(const(U)) shared(inout(const(T))) => shared(T)
- // foo(const(U)) immutable(T) => T
- // foo(shared(const(U))) immutable(T) => T
- {
- at = t.mutableOf();
- return MATCH.constant;
- }
- case X(MODFlags.const_, MODFlags.shared_):
- // foo(const(U)) shared(T) => shared(T)
- {
- at = t;
- return MATCH.constant;
- }
- case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wildconst):
- // foo(shared(U)) shared(const(T)) => const(T)
- // foo(shared(U)) shared(inout(T)) => inout(T)
- // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
- {
- at = t.unSharedOf();
- return MATCH.exact;
- }
- case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_):
- // foo(shared(const(U))) shared(T) => T
- {
- at = t.unSharedOf();
- return MATCH.constant;
- }
- case X(MODFlags.wildconst, MODFlags.immutable_):
- case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
- // foo(inout(const(U))) immutable(T) => T
- // foo(shared(const(U))) shared(inout(const(T))) => T
- // foo(shared(inout(const(U)))) immutable(T) => T
- // foo(shared(inout(const(U)))) shared(inout(T)) => T
+ foreach (tp; tparams)
{
- at = t.unSharedOf().mutableOf();
- return MATCH.constant;
+ if (tp.ident.equals(t.ident))
+ return true;
}
- case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
- // foo(shared(const(U))) shared(inout(T)) => T
+ return false;
+ }
+
+ bool visitInstance(TypeInstance t)
+ {
+ foreach (tp; tparams)
{
- at = t.unSharedOf().mutableOf();
- return MATCH.constant;
+ if (t.tempinst.name == tp.ident)
+ return true;
}
- case X(MODFlags.wild, 0):
- case X(MODFlags.wild, MODFlags.const_):
- case X(MODFlags.wild, MODFlags.wildconst):
- case X(MODFlags.wild, MODFlags.immutable_):
- case X(MODFlags.wild, MODFlags.shared_):
- case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
- case X(MODFlags.wildconst, 0):
- case X(MODFlags.wildconst, MODFlags.const_):
- case X(MODFlags.wildconst, MODFlags.wild):
- case X(MODFlags.wildconst, MODFlags.shared_):
- case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.shared_, 0):
- case X(MODFlags.shared_, MODFlags.const_):
- case X(MODFlags.shared_, MODFlags.wild):
- case X(MODFlags.shared_, MODFlags.wildconst):
- case X(MODFlags.shared_, MODFlags.immutable_):
- case X(MODFlags.shared_ | MODFlags.const_, 0):
- case X(MODFlags.shared_ | MODFlags.const_, MODFlags.const_):
- case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wild):
- case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wildconst):
- case X(MODFlags.shared_ | MODFlags.wild, 0):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.const_):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wild):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wildconst):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
- case X(MODFlags.shared_ | MODFlags.wildconst, 0):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.const_):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wild):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wildconst):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
- case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.immutable_, 0):
- case X(MODFlags.immutable_, MODFlags.const_):
- case X(MODFlags.immutable_, MODFlags.wild):
- case X(MODFlags.immutable_, MODFlags.wildconst):
- case X(MODFlags.immutable_, MODFlags.shared_):
- case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.const_):
- case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild):
- case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wildconst):
- // foo(inout(U)) T => nomatch
- // foo(inout(U)) const(T) => nomatch
- // foo(inout(U)) inout(const(T)) => nomatch
- // foo(inout(U)) immutable(T) => nomatch
- // foo(inout(U)) shared(T) => nomatch
- // foo(inout(U)) shared(const(T)) => nomatch
- // foo(inout(U)) shared(inout(const(T))) => nomatch
- // foo(inout(const(U))) T => nomatch
- // foo(inout(const(U))) const(T) => nomatch
- // foo(inout(const(U))) inout(T) => nomatch
- // foo(inout(const(U))) shared(T) => nomatch
- // foo(inout(const(U))) shared(const(T)) => nomatch
- // foo(inout(const(U))) shared(inout(T)) => nomatch
- // foo(shared(U)) T => nomatch
- // foo(shared(U)) const(T) => nomatch
- // foo(shared(U)) inout(T) => nomatch
- // foo(shared(U)) inout(const(T)) => nomatch
- // foo(shared(U)) immutable(T) => nomatch
- // foo(shared(const(U))) T => nomatch
- // foo(shared(const(U))) const(T) => nomatch
- // foo(shared(const(U))) inout(T) => nomatch
- // foo(shared(const(U))) inout(const(T)) => nomatch
- // foo(shared(inout(U))) T => nomatch
- // foo(shared(inout(U))) const(T) => nomatch
- // foo(shared(inout(U))) inout(T) => nomatch
- // foo(shared(inout(U))) inout(const(T)) => nomatch
- // foo(shared(inout(U))) immutable(T) => nomatch
- // foo(shared(inout(U))) shared(T) => nomatch
- // foo(shared(inout(U))) shared(const(T)) => nomatch
- // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
- // foo(shared(inout(const(U)))) T => nomatch
- // foo(shared(inout(const(U)))) const(T) => nomatch
- // foo(shared(inout(const(U)))) inout(T) => nomatch
- // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
- // foo(shared(inout(const(U)))) shared(T) => nomatch
- // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
- // foo(immutable(U)) T => nomatch
- // foo(immutable(U)) const(T) => nomatch
- // foo(immutable(U)) inout(T) => nomatch
- // foo(immutable(U)) inout(const(T)) => nomatch
- // foo(immutable(U)) shared(T) => nomatch
- // foo(immutable(U)) shared(const(T)) => nomatch
- // foo(immutable(U)) shared(inout(T)) => nomatch
- // foo(immutable(U)) shared(inout(const(T))) => nomatch
- return MATCH.nomatch;
- default:
- assert(0);
+ if (t.tempinst.tiargs)
+ foreach (arg; *t.tempinst.tiargs)
+ {
+ if (Type ta = isType(arg))
+ {
+ if (ta.reliesOnTemplateParameters(tparams))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool visitTypeof(TypeTypeof t)
+ {
+ //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
+ return t.exp.reliesOnTemplateParameters(tparams);
+ }
+
+ bool visitTuple(TypeTuple t)
+ {
+ if (t.arguments)
+ foreach (arg; *t.arguments)
+ {
+ if (arg.type.reliesOnTemplateParameters(tparams))
+ return true;
+ }
+
+ return false;
+ }
+
+ if (!t)
+ return false;
+
+ Type tb = t.toBasetype();
+ switch (tb.ty)
+ {
+ case Tvector: return visitVector(tb.isTypeVector());
+ case Taarray: return visitAArray(tb.isTypeAArray());
+ case Tfunction: return visitFunction(tb.isTypeFunction());
+ case Tident: return visitIdentifier(tb.isTypeIdentifier());
+ case Tinstance: return visitInstance(tb.isTypeInstance());
+ case Ttypeof: return visitTypeof(tb.isTypeTypeof());
+ case Ttuple: return visitTuple(tb.isTypeTuple());
+ case Tenum: return false;
+ default: return tb.nextOf().reliesOnTemplateParameters(tparams);
}
}
-__gshared Expression emptyArrayElement = null;
-
-/* These form the heart of template argument deduction.
- * Given 'this' being the type argument to the template instance,
- * it is matched against the template declaration parameter specialization
- * 'tparam' to determine the type to be used for the parameter.
- * Example:
- * template Foo(T:T*) // template declaration
- * Foo!(int*) // template instantiation
- * Input:
- * this = int*
- * tparam = T*
- * parameters = [ T:T* ] // Array of TemplateParameter's
- * Output:
- * dedtypes = [ int ] // Array of Expression/Type's
+/***********************************************************
+ * Check whether the expression representation relies on one or more the template parameters.
+ * Params:
+ * e = expression to test
+ * tparams = Template parameters.
+ * Returns:
+ * true if it does
*/
-MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
+private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparams)
{
- extern (C++) final class DeduceType : Visitor
+ extern (C++) final class ReliesOnTemplateParameters : Visitor
{
alias visit = Visitor.visit;
public:
- MATCH result;
+ TemplateParameter[] tparams;
+ bool result;
- extern (D) this() @safe
+ extern (D) this(TemplateParameter[] tparams) @safe
{
- result = MATCH.nomatch;
+ this.tparams = tparams;
}
- override void visit(Type t)
+ override void visit(Expression e)
{
- if (!tparam)
- goto Lnomatch;
-
- if (t == tparam)
- goto Lexact;
+ //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
+ }
- if (tparam.ty == Tident)
+ override void visit(IdentifierExp e)
+ {
+ //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ foreach (tp; tparams)
{
- // Determine which parameter tparam is
- size_t i = templateParameterLookup(tparam, ¶meters);
- if (i == IDX_NOTFOUND)
+ if (e.ident == tp.ident)
{
- if (!sc)
- goto Lnomatch;
-
- /* Need a loc to go with the semantic routine.
- */
- Loc loc;
- if (parameters.length)
- {
- TemplateParameter tp = parameters[0];
- loc = tp.loc;
- }
-
- /* BUG: what if tparam is a template instance, that
- * has as an argument another Tident?
- */
- tparam = tparam.typeSemantic(loc, sc);
- assert(tparam.ty != Tident);
- result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
+ result = true;
return;
}
+ }
+ }
- TemplateParameter tp = parameters[i];
-
- TypeIdentifier tident = tparam.isTypeIdentifier();
- if (tident.idents.length > 0)
+ override void visit(TupleExp e)
+ {
+ //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.exps)
+ {
+ foreach (ea; *e.exps)
{
- //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
- Dsymbol s = t.toDsymbol(sc);
- for (size_t j = tident.idents.length; j-- > 0;)
- {
- RootObject id = tident.idents[j];
- if (id.dyncast() == DYNCAST.identifier)
- {
- if (!s || !s.parent)
- goto Lnomatch;
- Dsymbol s2 = s.parent.search(Loc.initial, cast(Identifier)id);
- if (!s2)
- goto Lnomatch;
- s2 = s2.toAlias();
- //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
- if (s != s2)
- {
- if (Type tx = s2.getType())
- {
- if (s != tx.toDsymbol(sc))
- goto Lnomatch;
- }
- else
- goto Lnomatch;
- }
- s = s.parent;
- }
- else
- goto Lnomatch;
- }
- //printf("[e] s = %s\n", s?s.toChars():"(null)");
- if (tp.isTemplateTypeParameter())
- {
- Type tt = s.getType();
- if (!tt)
- goto Lnomatch;
- Type at = cast(Type)dedtypes[i];
- if (at && at.ty == Tnone)
- at = (cast(TypeDeduced)at).tded;
- if (!at || tt.equals(at))
- {
- dedtypes[i] = tt;
- goto Lexact;
- }
- }
- if (tp.isTemplateAliasParameter())
- {
- Dsymbol s2 = cast(Dsymbol)dedtypes[i];
- if (!s2 || s == s2)
- {
- dedtypes[i] = s;
- goto Lexact;
- }
- }
- goto Lnomatch;
+ ea.accept(this);
+ if (result)
+ return;
}
+ }
+ }
- // Found the corresponding parameter tp
- /+
- https://issues.dlang.org/show_bug.cgi?id=23578
- To pattern match:
- static if (is(S!int == S!av, alias av))
-
- We eventually need to deduce `int` (Tint32 [0]) and `av` (Tident).
- Previously this would not get pattern matched at all, but now we check if the
- template parameter `av` came from.
-
- This note has been left to serve as a hint for further explorers into
- how IsExp matching works.
- +/
- if (auto ta = tp.isTemplateAliasParameter())
- {
- dedtypes[i] = t;
- goto Lexact;
- }
- // (23578) - ensure previous behaviour for non-alias template params
- if (!tp.isTemplateTypeParameter())
+ override void visit(ArrayLiteralExp e)
+ {
+ //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.elements)
+ {
+ foreach (el; *e.elements)
{
- goto Lnomatch;
+ el.accept(this);
+ if (result)
+ return;
}
+ }
+ }
- Type at = cast(Type)dedtypes[i];
- Type tt;
- if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
- {
- // type vs (none)
- if (!at)
- {
- dedtypes[i] = tt;
- *wm |= wx;
- result = MATCH.constant;
- return;
- }
-
- // type vs expressions
- if (at.ty == Tnone)
- {
- auto xt = cast(TypeDeduced)at;
- result = xt.matchAll(tt);
- if (result > MATCH.nomatch)
- {
- dedtypes[i] = tt;
- if (result > MATCH.constant)
- result = MATCH.constant; // limit level for inout matches
- }
- return;
- }
-
- // type vs type
- if (tt.equals(at))
- {
- dedtypes[i] = tt; // Prefer current type match
- goto Lconst;
- }
- if (tt.implicitConvTo(at.constOf()))
- {
- dedtypes[i] = at.constOf().mutableOf();
- *wm |= MODFlags.const_;
- goto Lconst;
- }
- if (at.implicitConvTo(tt.constOf()))
- {
- dedtypes[i] = tt.constOf().mutableOf();
- *wm |= MODFlags.const_;
- goto Lconst;
- }
- goto Lnomatch;
- }
- else if (MATCH m = deduceTypeHelper(t, tt, tparam))
- {
- // type vs (none)
- if (!at)
- {
- dedtypes[i] = tt;
- result = m;
- return;
- }
-
- // type vs expressions
- if (at.ty == Tnone)
- {
- auto xt = cast(TypeDeduced)at;
- result = xt.matchAll(tt);
- if (result > MATCH.nomatch)
- {
- dedtypes[i] = tt;
- }
- return;
- }
-
- // type vs type
- if (tt.equals(at))
- {
- goto Lexact;
- }
- if (tt.ty == Tclass && at.ty == Tclass)
- {
- result = tt.implicitConvTo(at);
- return;
- }
- if (tt.ty == Tsarray && at.ty == Tarray && tt.nextOf().implicitConvTo(at.nextOf()) >= MATCH.constant)
- {
- goto Lexact;
- }
- }
- goto Lnomatch;
- }
-
- if (tparam.ty == Ttypeof)
- {
- /* Need a loc to go with the semantic routine.
- */
- Loc loc;
- if (parameters.length)
- {
- TemplateParameter tp = parameters[0];
- loc = tp.loc;
- }
-
- tparam = tparam.typeSemantic(loc, sc);
- }
- if (t.ty != tparam.ty)
+ override void visit(AssocArrayLiteralExp e)
+ {
+ //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ foreach (ek; *e.keys)
{
- if (Dsymbol sym = t.toDsymbol(sc))
- {
- if (sym.isforwardRef() && !tparam.deco)
- goto Lnomatch;
- }
-
- MATCH m = t.implicitConvTo(tparam);
- if (m == MATCH.nomatch && !ignoreAliasThis)
- {
- if (auto tc = t.isTypeClass())
- {
- if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT))
- {
- if (auto ato = t.aliasthisOf())
- {
- tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracingDT);
- m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
- tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracingDT);
- }
- }
- }
- else if (auto ts = t.isTypeStruct())
- {
- if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT))
- {
- if (auto ato = t.aliasthisOf())
- {
- ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracingDT);
- m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
- ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracingDT);
- }
- }
- }
- }
- result = m;
- return;
+ ek.accept(this);
+ if (result)
+ return;
}
-
- if (t.nextOf())
+ foreach (ev; *e.values)
{
- if (tparam.deco && !tparam.hasWild())
- {
- result = t.implicitConvTo(tparam);
+ ev.accept(this);
+ if (result)
return;
- }
-
- Type tpn = tparam.nextOf();
- if (wm && t.ty == Taarray && tparam.isWild())
- {
- // https://issues.dlang.org/show_bug.cgi?id=12403
- // In IFTI, stop inout matching on transitive part of AA types.
- tpn = tpn.substWildTo(MODFlags.mutable);
- }
-
- result = deduceType(t.nextOf(), sc, tpn, parameters, dedtypes, wm);
- return;
}
-
- Lexact:
- result = MATCH.exact;
- return;
-
- Lnomatch:
- result = MATCH.nomatch;
- return;
-
- Lconst:
- result = MATCH.constant;
}
- override void visit(TypeVector t)
+ override void visit(StructLiteralExp e)
{
- if (auto tp = tparam.isTypeVector())
+ //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.elements)
{
- result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm);
- return;
+ foreach (ea; *e.elements)
+ {
+ ea.accept(this);
+ if (result)
+ return;
+ }
}
- visit(cast(Type)t);
}
- override void visit(TypeDArray t)
+ override void visit(TypeExp e)
{
- visit(cast(Type)t);
+ //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ result = e.type.reliesOnTemplateParameters(tparams);
}
- override void visit(TypeSArray t)
+ override void visit(NewExp e)
{
- // Extra check that array dimensions must match
- if (!tparam)
- {
- visit(cast(Type)t);
- return;
- }
-
- if (tparam.ty == Tarray)
- {
- MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
- result = (m >= MATCH.constant) ? MATCH.convert : MATCH.nomatch;
- return;
- }
-
- TemplateParameter tp = null;
- Expression edim = null;
- size_t i;
- if (auto tsa = tparam.isTypeSArray())
+ //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.placement)
+ e.placement.accept(this);
+ if (e.thisexp)
+ e.thisexp.accept(this);
+ result = e.newtype.reliesOnTemplateParameters(tparams);
+ if (!result && e.arguments)
{
- if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter)
+ foreach (ea; *e.arguments)
{
- Identifier id = tsa.dim.isVarExp().var.ident;
- i = templateIdentifierLookup(id, ¶meters);
- assert(i != IDX_NOTFOUND);
- tp = parameters[i];
+ ea.accept(this);
+ if (result)
+ return;
}
- else
- edim = tsa.dim;
}
- else if (auto taa = tparam.isTypeAArray())
- {
- i = templateParameterLookup(taa.index, ¶meters);
- if (i != IDX_NOTFOUND)
- tp = parameters[i];
- else
- {
- Loc loc;
- // The "type" (it hasn't been resolved yet) of the function parameter
- // does not have a location but the parameter it is related to does,
- // so we use that for the resolution (better error message).
- if (inferStart < parameters.length)
- {
- TemplateParameter loctp = parameters[inferStart];
- loc = loctp.loc;
- }
+ }
- Expression e;
- Type tx;
- Dsymbol s;
- taa.index.resolve(loc, sc, e, tx, s);
- edim = s ? getValue(s) : getValue(e);
- }
- }
- if ((tp && tp.matchArg(sc, t.dim, i, ¶meters, dedtypes, null)) ||
- (edim && edim.isIntegerExp() && edim.toInteger() == t.dim.toInteger())
- )
- {
- result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
- return;
- }
+ override void visit(NewAnonClassExp e)
+ {
+ //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ result = true;
+ }
+
+ override void visit(FuncExp e)
+ {
+ //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ result = true;
+ }
- visit(cast(Type)t);
+ override void visit(TypeidExp e)
+ {
+ //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (auto ea = isExpression(e.obj))
+ ea.accept(this);
+ else if (auto ta = isType(e.obj))
+ result = ta.reliesOnTemplateParameters(tparams);
}
- override void visit(TypeAArray t)
+ override void visit(TraitsExp e)
{
- // Extra check that index type must match
- if (tparam && tparam.ty == Taarray)
+ //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.args)
{
- TypeAArray tp = tparam.isTypeAArray();
- if (!deduceType(t.index, sc, tp.index, parameters, dedtypes))
+ foreach (oa; *e.args)
{
- result = MATCH.nomatch;
- return;
+ if (auto ea = isExpression(oa))
+ ea.accept(this);
+ else if (auto ta = isType(oa))
+ result = ta.reliesOnTemplateParameters(tparams);
+ if (result)
+ return;
}
}
- visit(cast(Type)t);
}
- override void visit(TypeFunction t)
+ override void visit(IsExp e)
{
- // Extra check that function characteristics must match
- if (!tparam)
- return visit(cast(Type)t);
-
- auto tp = tparam.isTypeFunction();
- if (!tp)
- {
- visit(cast(Type)t);
- return;
- }
+ //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ result = e.targ.reliesOnTemplateParameters(tparams);
+ }
- if (t.parameterList.varargs != tp.parameterList.varargs || t.linkage != tp.linkage)
- {
- result = MATCH.nomatch;
- return;
- }
+ override void visit(UnaExp e)
+ {
+ //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ e.e1.accept(this);
+ }
- foreach (fparam; *tp.parameterList.parameters)
+ override void visit(DotTemplateInstanceExp e)
+ {
+ //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(e.isUnaExp());
+ if (!result && e.ti.tiargs)
{
- // https://issues.dlang.org/show_bug.cgi?id=2579
- // Apply function parameter storage classes to parameter types
- fparam.type = fparam.type.addStorageClass(fparam.storageClass);
- fparam.storageClass &= ~STC.TYPECTOR;
-
- // https://issues.dlang.org/show_bug.cgi?id=15243
- // Resolve parameter type if it's not related with template parameters
- if (!reliesOnTemplateParameters(fparam.type, parameters[inferStart .. parameters.length]))
+ foreach (oa; *e.ti.tiargs)
{
- auto tx = fparam.type.typeSemantic(Loc.initial, sc);
- if (tx.ty == Terror)
- {
- result = MATCH.nomatch;
+ if (auto ea = isExpression(oa))
+ ea.accept(this);
+ else if (auto ta = isType(oa))
+ result = ta.reliesOnTemplateParameters(tparams);
+ if (result)
return;
- }
- fparam.type = tx;
}
}
+ }
- const size_t nfargs = t.parameterList.length;
- size_t nfparams = tp.parameterList.length;
-
- /* See if tuple match
- */
- if (nfparams > 0 && nfargs >= nfparams - 1)
+ override void visit(CallExp e)
+ {
+ //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(e.isUnaExp());
+ if (!result && e.arguments)
{
- /* See if 'A' of the template parameter matches 'A'
- * of the type of the last function parameter.
- */
- Parameter fparam = tp.parameterList[nfparams - 1];
- assert(fparam);
- assert(fparam.type);
- if (fparam.type.ty != Tident)
- goto L1;
- TypeIdentifier tid = fparam.type.isTypeIdentifier();
- if (tid.idents.length)
- goto L1;
-
- /* Look through parameters to find tuple matching tid.ident
- */
- size_t tupi = 0;
- for (; 1; tupi++)
- {
- if (tupi == parameters.length)
- goto L1;
- TemplateParameter tx = parameters[tupi];
- TemplateTupleParameter tup = tx.isTemplateTupleParameter();
- if (tup && tup.ident.equals(tid.ident))
- break;
- }
-
- /* The types of the function arguments [nfparams - 1 .. nfargs]
- * now form the tuple argument.
- */
- size_t tuple_dim = nfargs - (nfparams - 1);
-
- /* See if existing tuple, and whether it matches or not
- */
- RootObject o = dedtypes[tupi];
- if (o)
+ foreach (ea; *e.arguments)
{
- // Existing deduced argument must be a tuple, and must match
- Tuple tup = isTuple(o);
- if (!tup || tup.objects.length != tuple_dim)
- {
- result = MATCH.nomatch;
+ ea.accept(this);
+ if (result)
return;
- }
- for (size_t i = 0; i < tuple_dim; i++)
- {
- Parameter arg = t.parameterList[nfparams - 1 + i];
- if (!arg.type.equals(tup.objects[i]))
- {
- result = MATCH.nomatch;
- return;
- }
- }
- }
- else
- {
- // Create new tuple
- auto tup = new Tuple(tuple_dim);
- for (size_t i = 0; i < tuple_dim; i++)
- {
- Parameter arg = t.parameterList[nfparams - 1 + i];
- tup.objects[i] = arg.type;
- }
- dedtypes[tupi] = tup;
}
- nfparams--; // don't consider the last parameter for type deduction
- goto L2;
- }
-
- L1:
- if (nfargs != nfparams)
- {
- result = MATCH.nomatch;
- return;
}
- L2:
- assert(nfparams <= tp.parameterList.length);
- foreach (i, ap; tp.parameterList)
- {
- if (i == nfparams)
- break;
-
- Parameter a = t.parameterList[i];
+ }
- if (!a.isCovariant(t.isRef, ap) ||
- !deduceType(a.type, sc, ap.type, parameters, dedtypes))
- {
- result = MATCH.nomatch;
- return;
- }
- }
+ override void visit(CastExp e)
+ {
+ //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(e.isUnaExp());
+ // e.to can be null for cast() with no type
+ if (!result && e.to)
+ result = e.to.reliesOnTemplateParameters(tparams);
+ }
- visit(cast(Type)t);
+ override void visit(SliceExp e)
+ {
+ //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(e.isUnaExp());
+ if (!result && e.lwr)
+ e.lwr.accept(this);
+ if (!result && e.upr)
+ e.upr.accept(this);
}
- override void visit(TypeIdentifier t)
+ override void visit(IntervalExp e)
{
- // Extra check
- if (tparam && tparam.ty == Tident)
- {
- TypeIdentifier tp = tparam.isTypeIdentifier();
- for (size_t i = 0; i < t.idents.length; i++)
- {
- RootObject id1 = t.idents[i];
- RootObject id2 = tp.idents[i];
- if (!id1.equals(id2))
- {
- result = MATCH.nomatch;
- return;
- }
- }
- }
- visit(cast(Type)t);
+ //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ e.lwr.accept(this);
+ if (!result)
+ e.upr.accept(this);
}
- override void visit(TypeInstance t)
+ override void visit(ArrayExp e)
{
- // Extra check
- if (!tparam || tparam.ty != Tinstance || !t.tempinst.tempdecl)
+ //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(e.isUnaExp());
+ if (!result && e.arguments)
{
- visit(cast(Type)t);
- return;
+ foreach (ea; *e.arguments)
+ ea.accept(this);
}
+ }
- TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
- assert(tempdecl);
-
- TypeInstance tp = tparam.isTypeInstance();
+ override void visit(BinExp e)
+ {
+ //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ e.e1.accept(this);
+ if (!result)
+ e.e2.accept(this);
+ }
- //printf("tempinst.tempdecl = %p\n", tempdecl);
- //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
- if (!tp.tempinst.tempdecl)
- {
- //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
-
- /* Handle case of:
- * template Foo(T : sa!(T), alias sa)
- */
- size_t i = templateIdentifierLookup(tp.tempinst.name, ¶meters);
- if (i == IDX_NOTFOUND)
- {
- /* Didn't find it as a parameter identifier. Try looking
- * it up and seeing if is an alias.
- * https://issues.dlang.org/show_bug.cgi?id=1454
- */
- auto tid = new TypeIdentifier(tp.loc, tp.tempinst.name);
- Type tx;
- Expression e;
- Dsymbol s;
- tid.resolve(tp.loc, sc, e, tx, s);
- if (tx)
- {
- s = tx.toDsymbol(sc);
- if (TemplateInstance ti = s ? s.parent.isTemplateInstance() : null)
- {
- // https://issues.dlang.org/show_bug.cgi?id=14290
- // Try to match with ti.tempecl,
- // only when ti is an enclosing instance.
- Dsymbol p = sc.parent;
- while (p && p != ti)
- p = p.parent;
- if (p)
- s = ti.tempdecl;
- }
- }
- if (s)
- {
- s = s.toAlias();
- TemplateDeclaration td = s.isTemplateDeclaration();
- if (td)
- {
- if (td.overroot)
- td = td.overroot;
- for (; td; td = td.overnext)
- {
- if (td == tempdecl)
- goto L2;
- }
- }
- }
- goto Lnomatch;
- }
+ override void visit(CondExp e)
+ {
+ //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ e.econd.accept(this);
+ if (!result)
+ visit(e.isBinExp());
+ }
+ }
- TemplateParameter tpx = parameters[i];
- if (!tpx.matchArg(sc, tempdecl, i, ¶meters, dedtypes, null))
- goto Lnomatch;
- }
- else if (tempdecl != tp.tempinst.tempdecl)
- goto Lnomatch;
+ scope ReliesOnTemplateParameters v = new ReliesOnTemplateParameters(tparams);
+ e.accept(v);
+ return v.result;
+}
- L2:
- if (!resolveTemplateInstantiation(sc, ¶meters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes))
- goto Lnomatch;
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateParameter
+ */
+extern (C++) class TemplateParameter : ASTNode
+{
+ Loc loc;
+ Identifier ident;
- visit(cast(Type)t);
- return;
+ /* True if this is a part of precedent parameter specialization pattern.
+ *
+ * template A(T : X!TL, alias X, TL...) {}
+ * // X and TL are dependent template parameter
+ *
+ * A dependent template parameter should return MATCH.exact in matchArg()
+ * to respect the match level of the corresponding precedent parameter.
+ */
+ bool dependent;
- Lnomatch:
- //printf("no match\n");
- result = MATCH.nomatch;
- }
+ /* ======================== TemplateParameter =============================== */
+ extern (D) this(Loc loc, Identifier ident) @safe
+ {
+ this.loc = loc;
+ this.ident = ident;
+ }
- override void visit(TypeStruct t)
- {
- /* If this struct is a template struct, and we're matching
- * it against a template instance, convert the struct type
- * to a template instance, too, and try again.
- */
- TemplateInstance ti = t.sym.parent.isTemplateInstance();
+ TemplateTypeParameter isTemplateTypeParameter()
+ {
+ return null;
+ }
- if (tparam && tparam.ty == Tinstance)
- {
- if (ti && ti.toAlias() == t.sym)
- {
- auto tx = new TypeInstance(Loc.initial, ti);
- auto m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
- // if we have a no match we still need to check alias this
- if (m != MATCH.nomatch)
- {
- result = m;
- return;
- }
- }
+ TemplateValueParameter isTemplateValueParameter()
+ {
+ return null;
+ }
- /* Match things like:
- * S!(T).foo
- */
- TypeInstance tpi = tparam.isTypeInstance();
- if (tpi.idents.length)
- {
- RootObject id = tpi.idents[tpi.idents.length - 1];
- if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
- {
- Type tparent = t.sym.parent.getType();
- if (tparent)
- {
- /* Slice off the .foo in S!(T).foo
- */
- tpi.idents.length--;
- result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
- tpi.idents.length++;
- return;
- }
- }
- }
- }
+ TemplateAliasParameter isTemplateAliasParameter()
+ {
+ return null;
+ }
- // Extra check
- if (tparam && tparam.ty == Tstruct)
- {
- TypeStruct tp = tparam.isTypeStruct();
+ TemplateThisParameter isTemplateThisParameter()
+ {
+ return null;
+ }
- //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
- if (wm && t.deduceWild(tparam, false))
- {
- result = MATCH.constant;
- return;
- }
- result = t.implicitConvTo(tp);
- return;
- }
- visit(cast(Type)t);
- }
+ TemplateTupleParameter isTemplateTupleParameter()
+ {
+ return null;
+ }
- override void visit(TypeEnum t)
- {
- // Extra check
- if (tparam && tparam.ty == Tenum)
- {
- TypeEnum tp = tparam.isTypeEnum();
- if (t.sym == tp.sym)
- visit(cast(Type)t);
- else
- result = MATCH.nomatch;
- return;
- }
- Type tb = t.toBasetype();
- if (tb.ty == tparam.ty || tb.ty == Tsarray && tparam.ty == Taarray)
- {
- result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
- if (result == MATCH.exact)
- result = MATCH.convert;
- return;
- }
- visit(cast(Type)t);
- }
+ abstract TemplateParameter syntaxCopy();
- override void visit(TypeClass t)
- {
- //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
+ abstract bool declareParameter(Scope* sc);
- /* If this class is a template class, and we're matching
- * it against a template instance, convert the class type
- * to a template instance, too, and try again.
- */
- TemplateInstance ti = t.sym.parent.isTemplateInstance();
+ abstract void print(RootObject oarg, RootObject oded);
- if (tparam && tparam.ty == Tinstance)
- {
- if (ti && ti.toAlias() == t.sym)
- {
- auto tx = new TypeInstance(Loc.initial, ti);
- MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
- // Even if the match fails, there is still a chance it could match
- // a base class.
- if (m != MATCH.nomatch)
- {
- result = m;
- return;
- }
- }
+ abstract RootObject specialization();
- /* Match things like:
- * S!(T).foo
- */
- TypeInstance tpi = tparam.isTypeInstance();
- if (tpi.idents.length)
- {
- RootObject id = tpi.idents[tpi.idents.length - 1];
- if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
- {
- Type tparent = t.sym.parent.getType();
- if (tparent)
- {
- /* Slice off the .foo in S!(T).foo
- */
- tpi.idents.length--;
- result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
- tpi.idents.length++;
- return;
- }
- }
- }
+ abstract bool hasDefaultArg();
- // If it matches exactly or via implicit conversion, we're done
- visit(cast(Type)t);
- if (result != MATCH.nomatch)
- return;
+ override const(char)* toChars() const
+ {
+ return this.ident.toChars();
+ }
- /* There is still a chance to match via implicit conversion to
- * a base class or interface. Because there could be more than one such
- * match, we need to check them all.
- */
+ override DYNCAST dyncast() const
+ {
+ return DYNCAST.templateparameter;
+ }
- int numBaseClassMatches = 0; // Have we found an interface match?
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
- // Our best guess at dedtypes
- auto best = new Objects(dedtypes.length);
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateTypeParameter
+ * Syntax:
+ * ident : specType = defaultType
+ */
+extern (C++) class TemplateTypeParameter : TemplateParameter
+{
+ Type specType; // if !=null, this is the type specialization
+ Type defaultType;
- ClassDeclaration s = t.sym;
- while (s && s.baseclasses.length > 0)
- {
- // Test the base class
- deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, *best, numBaseClassMatches);
+ extern (D) __gshared Type tdummy = null;
- // Test the interfaces inherited by the base class
- foreach (b; s.interfaces)
- {
- deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, *best, numBaseClassMatches);
- }
- s = (*s.baseclasses)[0].sym;
- }
+ extern (D) this(Loc loc, Identifier ident, Type specType, Type defaultType) @safe
+ {
+ super(loc, ident);
+ this.specType = specType;
+ this.defaultType = defaultType;
+ }
- if (numBaseClassMatches == 0)
- {
- result = MATCH.nomatch;
- return;
- }
+ override final TemplateTypeParameter isTemplateTypeParameter()
+ {
+ return this;
+ }
- // If we got at least one match, copy the known types into dedtypes
- memcpy(dedtypes.tdata(), best.tdata(), best.length * (void*).sizeof);
- result = MATCH.convert;
- return;
- }
+ override TemplateTypeParameter syntaxCopy()
+ {
+ return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
+ }
- // Extra check
- if (tparam && tparam.ty == Tclass)
- {
- TypeClass tp = tparam.isTypeClass();
+ override final bool declareParameter(Scope* sc)
+ {
+ //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
+ auto ti = new TypeIdentifier(loc, ident);
+ Declaration ad = new AliasDeclaration(loc, ident, ti);
+ return sc.insert(ad) !is null;
+ }
- //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
- if (wm && t.deduceWild(tparam, false))
- {
- result = MATCH.constant;
- return;
- }
- result = t.implicitConvTo(tp);
- return;
- }
- visit(cast(Type)t);
- }
+ override final void print(RootObject oarg, RootObject oded)
+ {
+ printf(" %s\n", ident.toChars());
- override void visit(Expression e)
- {
- //printf("Expression.deduceType(e = %s)\n", e.toChars());
- size_t i = templateParameterLookup(tparam, ¶meters);
- if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0)
- {
- if (e == emptyArrayElement && tparam.ty == Tarray)
- {
- Type tn = (cast(TypeNext)tparam).next;
- result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
- return;
- }
- e.type.accept(this);
- return;
- }
+ Type t = isType(oarg);
+ Type ta = isType(oded);
+ assert(ta);
- TemplateTypeParameter tp = parameters[i].isTemplateTypeParameter();
- if (!tp)
- return; // nomatch
+ if (specType)
+ printf("\tSpecialization: %s\n", specType.toChars());
+ if (defaultType)
+ printf("\tDefault: %s\n", defaultType.toChars());
+ printf("\tParameter: %s\n", t ? t.toChars() : "NULL");
+ printf("\tDeduced Type: %s\n", ta.toChars());
+ }
- if (e == emptyArrayElement)
- {
- if (dedtypes[i])
- {
- result = MATCH.exact;
- return;
- }
- if (tp.defaultType)
- {
- tp.defaultType.accept(this);
- return;
- }
- }
+ override final RootObject specialization()
+ {
+ return specType;
+ }
- /* Returns `true` if `t` is a reference type, or an array of reference types
- */
- bool isTopRef(Type t)
- {
- auto tb = t.baseElemOf();
- return tb.ty == Tclass ||
- tb.ty == Taarray ||
- tb.ty == Tstruct && tb.hasPointers();
- }
+ override final bool hasDefaultArg()
+ {
+ return defaultType !is null;
+ }
- Type at = cast(Type)dedtypes[i];
- Type tt;
- if (ubyte wx = deduceWildHelper(e.type, &tt, tparam))
- {
- *wm |= wx;
- result = MATCH.constant;
- }
- else if (MATCH m = deduceTypeHelper(e.type, tt, tparam))
- {
- result = m;
- }
- else if (!isTopRef(e.type))
- {
- /* https://issues.dlang.org/show_bug.cgi?id=15653
- * In IFTI, recognize top-qualifier conversions
- * through the value copy, e.g.
- * int --> immutable(int)
- * immutable(string[]) --> immutable(string)[]
- */
- tt = e.type.mutableOf();
- result = MATCH.convert;
- }
- else
- return; // nomatch
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
- // expression vs (none)
- if (!at)
- {
- dedtypes[i] = new TypeDeduced(tt, e, tparam);
- return;
- }
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateThisParameter
+ * Syntax:
+ * this ident : specType = defaultType
+ */
+extern (C++) final class TemplateThisParameter : TemplateTypeParameter
+{
+ extern (D) this(Loc loc, Identifier ident, Type specType, Type defaultType) @safe
+ {
+ super(loc, ident, specType, defaultType);
+ }
- TypeDeduced xt = null;
- if (at.ty == Tnone)
- {
- xt = cast(TypeDeduced)at;
- at = xt.tded;
- }
+ override TemplateThisParameter isTemplateThisParameter()
+ {
+ return this;
+ }
- // From previous matched expressions to current deduced type
- MATCH match1 = xt ? xt.matchAll(tt) : MATCH.nomatch;
+ override TemplateThisParameter syntaxCopy()
+ {
+ return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
+ }
- // From current expressions to previous deduced type
- Type pt = at.addMod(tparam.mod);
- if (*wm)
- pt = pt.substWildTo(*wm);
- MATCH match2 = e.implicitConvTo(pt);
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
- if (match1 > MATCH.nomatch && match2 > MATCH.nomatch)
- {
- if (at.implicitConvTo(tt) == MATCH.nomatch)
- match1 = MATCH.nomatch; // Prefer at
- else if (tt.implicitConvTo(at) == MATCH.nomatch)
- match2 = MATCH.nomatch; // Prefer tt
- else if (tt.isTypeBasic() && tt.ty == at.ty && tt.mod != at.mod)
- {
- if (!tt.isMutable() && !at.isMutable())
- tt = tt.mutableOf().addMod(MODmerge(tt.mod, at.mod));
- else if (tt.isMutable())
- {
- if (at.mod == 0) // Prefer unshared
- match1 = MATCH.nomatch;
- else
- match2 = MATCH.nomatch;
- }
- else if (at.isMutable())
- {
- if (tt.mod == 0) // Prefer unshared
- match2 = MATCH.nomatch;
- else
- match1 = MATCH.nomatch;
- }
- //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
- }
- else
- {
- match1 = MATCH.nomatch;
- match2 = MATCH.nomatch;
- }
- }
- if (match1 > MATCH.nomatch)
- {
- // Prefer current match: tt
- if (xt)
- xt.update(tt, e, tparam);
- else
- dedtypes[i] = tt;
- result = match1;
- return;
- }
- if (match2 > MATCH.nomatch)
- {
- // Prefer previous match: (*dedtypes)[i]
- if (xt)
- xt.update(e, tparam);
- result = match2;
- return;
- }
-
- /* Deduce common type
- */
- if (Type t = rawTypeMerge(at, tt))
- {
- if (xt)
- xt.update(t, e, tparam);
- else
- dedtypes[i] = t;
-
- pt = tt.addMod(tparam.mod);
- if (*wm)
- pt = pt.substWildTo(*wm);
- result = e.implicitConvTo(pt);
- return;
- }
-
- result = MATCH.nomatch;
- }
-
- MATCH deduceEmptyArrayElement()
- {
- if (!emptyArrayElement)
- {
- emptyArrayElement = new IdentifierExp(Loc.initial, Id.p); // dummy
- emptyArrayElement.type = Type.tvoid;
- }
- assert(tparam.ty == Tarray);
-
- Type tn = (cast(TypeNext)tparam).next;
- return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
- }
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateValueParameter
+ * Syntax:
+ * valType ident : specValue = defaultValue
+ */
+extern (C++) final class TemplateValueParameter : TemplateParameter
+{
+ Type valType;
+ Expression specValue;
+ Expression defaultValue;
- override void visit(NullExp e)
- {
- if (tparam.ty == Tarray && e.type.ty == Tnull)
- {
- // tparam:T[] <- e:null (void[])
- result = deduceEmptyArrayElement();
- return;
- }
- visit(cast(Expression)e);
- }
+ extern (D) __gshared Expression[void*] edummies;
- override void visit(StringExp e)
- {
- Type taai;
- if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
- {
- // Consider compile-time known boundaries
- e.type.nextOf().sarrayOf(e.len).accept(this);
- return;
- }
- visit(cast(Expression)e);
- }
+ extern (D) this(Loc loc, Identifier ident, Type valType,
+ Expression specValue, Expression defaultValue) @safe
+ {
+ super(loc, ident);
+ this.valType = valType;
+ this.specValue = specValue;
+ this.defaultValue = defaultValue;
+ }
- override void visit(ArrayLiteralExp e)
- {
- // https://issues.dlang.org/show_bug.cgi?id=20092
- if (e.elements && e.elements.length && e.type.toBasetype().nextOf().ty == Tvoid)
- {
- result = deduceEmptyArrayElement();
- return;
- }
- if ((!e.elements || !e.elements.length) && e.type.toBasetype().nextOf().ty == Tvoid && tparam.ty == Tarray)
- {
- // tparam:T[] <- e:[] (void[])
- result = deduceEmptyArrayElement();
- return;
- }
+ override TemplateValueParameter isTemplateValueParameter()
+ {
+ return this;
+ }
- if (tparam.ty == Tarray && e.elements && e.elements.length)
- {
- Type tn = (cast(TypeDArray)tparam).next;
- result = MATCH.exact;
- if (e.basis)
- {
- MATCH m = deduceType(e.basis, sc, tn, parameters, dedtypes, wm);
- if (m < result)
- result = m;
- }
- foreach (el; *e.elements)
- {
- if (result == MATCH.nomatch)
- break;
- if (!el)
- continue;
- MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
- if (m < result)
- result = m;
- }
- return;
- }
+ override TemplateValueParameter syntaxCopy()
+ {
+ return new TemplateValueParameter(loc, ident,
+ valType.syntaxCopy(),
+ specValue ? specValue.syntaxCopy() : null,
+ defaultValue ? defaultValue.syntaxCopy() : null);
+ }
- Type taai;
- if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
- {
- // Consider compile-time known boundaries
- e.type.nextOf().sarrayOf(e.elements.length).accept(this);
- return;
- }
- visit(cast(Expression)e);
- }
+ override bool declareParameter(Scope* sc)
+ {
+ /*
+ Do type semantic earlier.
- override void visit(AssocArrayLiteralExp e)
- {
- if (tparam.ty == Taarray && e.keys && e.keys.length)
- {
- TypeAArray taa = cast(TypeAArray)tparam;
- result = MATCH.exact;
- foreach (i, key; *e.keys)
- {
- MATCH m1 = deduceType(key, sc, taa.index, parameters, dedtypes, wm);
- if (m1 < result)
- result = m1;
- if (result == MATCH.nomatch)
- break;
- MATCH m2 = deduceType((*e.values)[i], sc, taa.next, parameters, dedtypes, wm);
- if (m2 < result)
- result = m2;
- if (result == MATCH.nomatch)
- break;
- }
- return;
- }
- visit(cast(Expression)e);
- }
+ This means for certain erroneous value parameters
+ their "type" can be known earlier and thus a better
+ error message given.
- override void visit(FuncExp e)
- {
- //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
- if (e.td)
- {
- Type to = tparam;
- if (!to.nextOf())
- return;
- auto tof = to.nextOf().isTypeFunction();
- if (!tof)
- return;
+ For example:
+ `template test(x* x) {}`
+ now yields "undefined identifier" rather than the opaque
+ "variable `x` is used as a type".
+ */
+ if (valType)
+ valType = valType.typeSemantic(loc, sc);
+ auto v = new VarDeclaration(loc, valType, ident, null);
+ v.storage_class = STC.templateparameter;
+ return sc.insert(v) !is null;
+ }
- // Parameter types inference from 'tof'
- assert(e.td._scope);
- TypeFunction tf = e.fd.type.isTypeFunction();
- //printf("\ttof = %s\n", tof.toChars());
- //printf("\ttf = %s\n", tf.toChars());
- const dim = tf.parameterList.length;
+ override void print(RootObject oarg, RootObject oded)
+ {
+ printf(" %s\n", ident.toChars());
+ Expression ea = isExpression(oded);
+ if (specValue)
+ printf("\tSpecialization: %s\n", specValue.toChars());
+ printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL");
+ }
- if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
- return;
+ override RootObject specialization()
+ {
+ return specValue;
+ }
- auto tiargs = new Objects();
- tiargs.reserve(e.td.parameters.length);
+ override bool hasDefaultArg()
+ {
+ return defaultValue !is null;
+ }
- foreach (tp; *e.td.parameters)
- {
- size_t u = 0;
- foreach (i, p; tf.parameterList)
- {
- if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
- break;
- ++u;
- }
- assert(u < dim);
- Parameter pto = tof.parameterList[u];
- if (!pto)
- break;
- Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
- if (reliesOnTemplateParameters(t, parameters[inferStart .. parameters.length]))
- return;
- t = t.typeSemantic(e.loc, sc);
- if (t.ty == Terror)
- return;
- tiargs.push(t);
- }
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
- // Set target of return type inference
- if (!tf.next && tof.next)
- e.fd.treq = tparam;
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateAliasParameter
+ * Syntax:
+ * specType ident : specAlias = defaultAlias
+ */
+extern (C++) final class TemplateAliasParameter : TemplateParameter
+{
+ Type specType;
+ RootObject specAlias;
+ RootObject defaultAlias;
- auto ti = new TemplateInstance(e.loc, e.td, tiargs);
- Expression ex = (new ScopeExp(e.loc, ti)).expressionSemantic(e.td._scope);
+ extern (D) __gshared Dsymbol sdummy = null;
- // Reset inference target for the later re-semantic
- e.fd.treq = null;
+ extern (D) this(Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias) @safe
+ {
+ super(loc, ident);
+ this.specType = specType;
+ this.specAlias = specAlias;
+ this.defaultAlias = defaultAlias;
+ }
- if (ex.op == EXP.error)
- return;
- if (ex.op != EXP.function_)
- return;
- visit(ex.type);
- return;
- }
+ override TemplateAliasParameter isTemplateAliasParameter()
+ {
+ return this;
+ }
- Type t = e.type;
+ override TemplateAliasParameter syntaxCopy()
+ {
+ return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias));
+ }
- if (t.ty == Tdelegate && tparam.ty == Tpointer)
- return;
+ override bool declareParameter(Scope* sc)
+ {
+ auto ti = new TypeIdentifier(loc, ident);
+ Declaration ad = new AliasDeclaration(loc, ident, ti);
+ return sc.insert(ad) !is null;
+ }
- // Allow conversion from implicit function pointer to delegate
- if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate)
- {
- TypeFunction tf = t.nextOf().isTypeFunction();
- t = (new TypeDelegate(tf)).merge();
- }
- //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
- visit(t);
- }
+ override void print(RootObject oarg, RootObject oded)
+ {
+ printf(" %s\n", ident.toChars());
+ Dsymbol sa = isDsymbol(oded);
+ assert(sa);
+ printf("\tParameter alias: %s\n", sa.toChars());
+ }
- override void visit(SliceExp e)
- {
- Type taai;
- if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
- {
- // Consider compile-time known boundaries
- if (Type tsa = toStaticArrayType(e))
- {
- tsa.accept(this);
- if (result > MATCH.convert)
- result = MATCH.convert; // match with implicit conversion at most
- return;
- }
- }
- visit(cast(Expression)e);
- }
+ override RootObject specialization()
+ {
+ return specAlias;
+ }
- override void visit(CommaExp e)
- {
- e.e2.accept(this);
- }
+ override bool hasDefaultArg()
+ {
+ return defaultAlias !is null;
}
- scope DeduceType v = new DeduceType();
- if (Type t = isType(o))
- t.accept(v);
- else if (Expression e = isExpression(o))
+ override void accept(Visitor v)
{
- assert(wm);
- e.accept(v);
+ v.visit(this);
}
- else
- assert(0);
- return v.result;
}
-
-/* Helper for TypeClass.deduceType().
- * Classes can match with implicit conversion to a base class or interface.
- * This is complicated, because there may be more than one base class which
- * matches. In such cases, one or more parameters remain ambiguous.
- * For example,
- *
- * interface I(X, Y) {}
- * class C : I(uint, double), I(char, double) {}
- * C x;
- * foo(T, U)( I!(T, U) x)
- *
- * deduces that U is double, but T remains ambiguous (could be char or uint).
- *
- * Given a baseclass b, and initial deduced types 'dedtypes', this function
- * tries to match tparam with b, and also tries all base interfaces of b.
- * If a match occurs, numBaseClassMatches is incremented, and the new deduced
- * types are ANDed with the current 'best' estimate for dedtypes.
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateSequenceParameter
+ * Syntax:
+ * ident ...
*/
-private void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, ref Objects best, ref int numBaseClassMatches)
+extern (C++) final class TemplateTupleParameter : TemplateParameter
{
- if (TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null)
+ extern (D) this(Loc loc, Identifier ident) @safe
{
- // Make a temporary copy of dedtypes so we don't destroy it
- auto tmpdedtypes = new Objects(dedtypes.length);
- memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof);
+ super(loc, ident);
+ }
- auto t = new TypeInstance(Loc.initial, parti);
- MATCH m = deduceType(t, sc, tparam, parameters, *tmpdedtypes);
- if (m > MATCH.nomatch)
- {
- // If this is the first ever match, it becomes our best estimate
- if (numBaseClassMatches == 0)
- memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof);
- else
- for (size_t k = 0; k < tmpdedtypes.length; ++k)
- {
- // If we've found more than one possible type for a parameter,
- // mark it as unknown.
- if ((*tmpdedtypes)[k] != best[k])
- best[k] = dedtypes[k];
- }
- ++numBaseClassMatches;
- }
+ override TemplateTupleParameter isTemplateTupleParameter()
+ {
+ return this;
}
- // Now recursively test the inherited interfaces
- foreach (ref bi; b.baseInterfaces)
+ override TemplateTupleParameter syntaxCopy()
{
- deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+ return new TemplateTupleParameter(loc, ident);
}
-}
-/********************
- * Match template `parameters` to the target template instance.
- * Example:
- * struct Temp(U, int Z) {}
- * void foo(T)(Temp!(T, 3));
- * foo(Temp!(int, 3)());
- * Input:
- * sc = context
- * parameters = template params of foo -> [T]
- * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3]
- * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3]
- * tempdecl = <struct Temp!(T, int Z)> -> [T, Z]
- * tp = <Temp!(T, 3)>
- * Output:
- * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int]
- */
-private bool resolveTemplateInstantiation(Scope* sc, TemplateParameters* parameters, Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes)
-{
- for (size_t i = 0; 1; i++)
+ override bool declareParameter(Scope* sc)
{
- //printf("\ttest: tempinst.tiargs[%zu]\n", i);
- RootObject o1 = null;
- if (i < tiargs.length)
- o1 = (*tiargs)[i];
- else if (i < tdtypes.length && i < tp.tempinst.tiargs.length)
- {
- // Pick up default arg
- o1 = (*tdtypes)[i];
- }
- else if (i >= tp.tempinst.tiargs.length)
- break;
- //printf("\ttest: o1 = %s\n", o1.toChars());
- if (i >= tp.tempinst.tiargs.length)
- {
- size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
- while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
- {
- i++;
- }
- if (i >= dim)
- break; // match if all remained parameters are dependent
- return false;
- }
+ auto ti = new TypeIdentifier(loc, ident);
+ Declaration ad = new AliasDeclaration(loc, ident, ti);
+ return sc.insert(ad) !is null;
+ }
- RootObject o2 = (*tp.tempinst.tiargs)[i];
- Type t2 = isType(o2);
- //printf("\ttest: o2 = %s\n", o2.toChars());
- size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1)
- ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
- if (j != IDX_NOTFOUND && j == parameters.length - 1 &&
- (*parameters)[j].isTemplateTupleParameter())
- {
- /* Given:
- * struct A(B...) {}
- * alias A!(int, float) X;
- * static if (is(X Y == A!(Z), Z...)) {}
- * deduce that Z is a tuple(int, float)
- */
-
- /* Create tuple from remaining args
- */
- size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i;
- auto vt = new Tuple(vtdim);
- for (size_t k = 0; k < vtdim; k++)
- {
- RootObject o;
- if (k < tiargs.length)
- o = (*tiargs)[i + k];
- else // Pick up default arg
- o = (*tdtypes)[i + k];
- vt.objects[k] = o;
- }
+ override void print(RootObject oarg, RootObject oded)
+ {
+ printf(" %s... [", ident.toChars());
+ Tuple v = isTuple(oded);
+ assert(v);
- Tuple v = cast(Tuple)(*dedtypes)[j];
- if (v)
- {
- if (!match(v, vt))
- return false;
- }
- else
- (*dedtypes)[j] = vt;
- break;
- }
- else if (!o1)
- break;
-
- Type t1 = isType(o1);
- Dsymbol s1 = isDsymbol(o1);
- Dsymbol s2 = isDsymbol(o2);
- Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
- Expression e2 = isExpression(o2);
- version (none)
+ //printf("|%d| ", v.objects.length);
+ foreach (i, o; v.objects)
{
- Tuple v1 = isTuple(o1);
- Tuple v2 = isTuple(o2);
- if (t1)
- printf("t1 = %s\n", t1.toChars());
- if (t2)
- printf("t2 = %s\n", t2.toChars());
- if (e1)
- printf("e1 = %s\n", e1.toChars());
- if (e2)
- printf("e2 = %s\n", e2.toChars());
- if (s1)
- printf("s1 = %s\n", s1.toChars());
- if (s2)
- printf("s2 = %s\n", s2.toChars());
- if (v1)
- printf("v1 = %s\n", v1.toChars());
- if (v2)
- printf("v2 = %s\n", v2.toChars());
- }
+ if (i)
+ printf(", ");
- if (t1 && t2)
- {
- if (!deduceType(t1, sc, t2, *parameters, *dedtypes))
- return false;
- }
- else if (e1 && e2)
- {
- Le:
- e1 = e1.ctfeInterpret();
+ Dsymbol sa = isDsymbol(o);
+ if (sa)
+ printf("alias: %s", sa.toChars());
+ Type ta = isType(o);
+ if (ta)
+ printf("type: %s", ta.toChars());
+ Expression ea = isExpression(o);
+ if (ea)
+ printf("exp: %s", ea.toChars());
- /* If it is one of the template parameters for this template,
- * we should not attempt to interpret it. It already has a value.
- */
- if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter))
- {
- /*
- * (T:Number!(e2), int e2)
- */
- j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters);
- if (j != IDX_NOTFOUND)
- goto L1;
- // The template parameter was not from this template
- // (it may be from a parent template, for example)
- }
+ assert(!isTuple(o)); // no nested Tuple arguments
+ }
+ printf("]\n");
+ }
- e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
- e2 = e2.ctfeInterpret();
+ override RootObject specialization()
+ {
+ return null;
+ }
- //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
- //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
- if (!e1.equals(e2))
- {
- if (!e2.implicitConvTo(e1.type))
- return false;
+ override bool hasDefaultArg()
+ {
+ return false;
+ }
- e2 = e2.implicitCastTo(sc, e1.type);
- e2 = e2.ctfeInterpret();
- if (!e1.equals(e2))
- return false;
- }
- }
- else if (e1 && t2 && t2.ty == Tident)
- {
- j = templateParameterLookup(t2, parameters);
- L1:
- if (j == IDX_NOTFOUND)
- {
- t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
- if (e2)
- goto Le;
- return false;
- }
- if (!(*parameters)[j].matchArg(sc, e1, j, parameters, *dedtypes, null))
- return false;
- }
- else if (s1 && s2)
- {
- Ls:
- if (!s1.equals(s2))
- return false;
- }
- else if (s1 && t2 && t2.ty == Tident)
- {
- j = templateParameterLookup(t2, parameters);
- if (j == IDX_NOTFOUND)
- {
- t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
- if (s2)
- goto Ls;
- return false;
- }
- if (!(*parameters)[j].matchArg(sc, s1, j, parameters, *dedtypes, null))
- return false;
- }
- else
- return false;
+ override void accept(Visitor v)
+ {
+ v.visit(this);
}
- return true;
}
-
/***********************************************************
- * Check whether the type t representation relies on one or more the template parameters.
- * Params:
- * t = Tested type, if null, returns false.
- * tparams = Template parameters.
- * iStart = Start index of tparams to limit the tested parameters. If it's
- * nonzero, tparams[0..iStart] will be excluded from the test target.
+ * https://dlang.org/spec/template.html#explicit_tmp_instantiation
+ * Given:
+ * foo!(args) =>
+ * name = foo
+ * tiargs = args
*/
-bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0)
+extern (C++) class TemplateInstance : ScopeDsymbol
{
- return reliesOnTemplateParameters(t, (*tparams)[0 .. tparams.length]);
-}
+ Identifier name;
-/***********************************************************
- * Check whether the type t representation relies on one or more the template parameters.
- * Params:
- * t = Tested type, if null, returns false.
- * tparams = Template parameters.
- */
-bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
-{
- bool visitVector(TypeVector t)
+ // Array of Types/Expressions of template
+ // instance arguments [int*, char, 10*10]
+ Objects* tiargs;
+
+ // Array of Types/Expressions corresponding
+ // to TemplateDeclaration.parameters
+ // [int, char, 100]
+ Objects tdtypes;
+
+ // Modules imported by this template instance
+ Modules importedModules;
+
+ Dsymbol tempdecl; // referenced by foo.bar.abc
+ Dsymbol enclosing; // if referencing local symbols, this is the context
+ Dsymbol aliasdecl; // !=null if instance is an alias for its sole member
+
+ /**
+ If this is not null and it has a value that is not the current object,
+ then this field points to an existing template instance
+ and that object has been duplicated into us.
+
+ If this object is a duplicate,
+ the ``memberOf`` field will be set to a root module (passed on CLI).
+
+ This information is useful to deduplicate analysis that may occur
+ after semantic 3 has completed.
+
+ See_Also: memberOf
+ */
+ TemplateInstance inst;
+
+ ScopeDsymbol argsym; // argument symbol table
+ size_t hash; // cached result of toHash()
+
+ /// For function template, these are the function fnames(name and loc of it) and arguments
+ /// Relevant because different resolutions of `auto ref` parameters
+ /// create different template instances even with the same template arguments
+ Expressions* fargs;
+ ArgumentLabels* fnames;
+
+ TemplateInstances* deferred;
+
+ /**
+ If this is not null then this template instance appears in a root module's members.
+
+ Note: This is not useful for determining duplication status of this template instance.
+ Use the field ``inst`` for determining if a template instance has been duplicated into this object.
+
+ See_Also: inst
+ */
+ Module memberOf;
+
+ // Used to determine the instance needs code generation.
+ // Note that these are inaccurate until semantic analysis phase completed.
+ TemplateInstance tinst; // enclosing template instance
+ TemplateInstance tnext; // non-first instantiated instances
+ Module minst; // the top module that instantiated this instance
+
+ private ushort _nest; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
+ ubyte inuse; // for recursive expansion detection
+
+ private enum Flag : uint
{
- return t.basetype.reliesOnTemplateParameters(tparams);
+ semantictiargsdone = 1u << (_nest.sizeof * 8 - 1), // MSB of _nest
+ havetempdecl = semantictiargsdone >> 1,
+ gagged = semantictiargsdone >> 2,
+ available = gagged - 1 // always last flag minus one, 1s for all available bits
}
- bool visitAArray(TypeAArray t)
+ extern(D) final @safe @property pure nothrow @nogc
{
- return t.next.reliesOnTemplateParameters(tparams) ||
- t.index.reliesOnTemplateParameters(tparams);
+ ushort nest() const { return _nest & Flag.available; }
+ void nestUp() { assert(nest() < Flag.available); ++_nest; }
+ void nestDown() { assert(nest() > 0); --_nest; }
+ /// has semanticTiargs() been done?
+ bool semantictiargsdone() const { return (_nest & Flag.semantictiargsdone) != 0; }
+ void semantictiargsdone(bool x)
+ {
+ if (x) _nest |= Flag.semantictiargsdone;
+ else _nest &= ~Flag.semantictiargsdone;
+ }
+ /// if used second constructor
+ bool havetempdecl() const { return (_nest & Flag.havetempdecl) != 0; }
+ void havetempdecl(bool x)
+ {
+ if (x) _nest |= Flag.havetempdecl;
+ else _nest &= ~Flag.havetempdecl;
+ }
+ /// if the instantiation is done with error gagging
+ bool gagged() const { return (_nest & Flag.gagged) != 0; }
+ void gagged(bool x)
+ {
+ if (x) _nest |= Flag.gagged;
+ else _nest &= ~Flag.gagged;
+ }
}
- bool visitFunction(TypeFunction t)
+ extern (D) this(Loc loc, Identifier ident, Objects* tiargs) scope
{
- foreach (i, fparam; t.parameterList)
+ super(loc, null);
+ static if (LOG)
{
- if (fparam.type.reliesOnTemplateParameters(tparams))
- return true;
+ printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null");
}
- return t.next.reliesOnTemplateParameters(tparams);
+ this.dsym = DSYM.templateInstance;
+ this.name = ident;
+ this.tiargs = tiargs;
}
- bool visitIdentifier(TypeIdentifier t)
+ /*****************
+ * This constructor is only called when we figured out which function
+ * template to instantiate.
+ */
+ extern (D) this(Loc loc, TemplateDeclaration td, Objects* tiargs) scope
{
- foreach (tp; tparams)
+ super(loc, null);
+ static if (LOG)
{
- if (tp.ident.equals(t.ident))
- return true;
+ printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars());
}
- return false;
+ this.dsym = DSYM.templateInstance;
+ this.name = td.ident;
+ this.tiargs = tiargs;
+ this.tempdecl = td;
+ this.semantictiargsdone = true;
+ this.havetempdecl = true;
+ assert(tempdecl._scope);
}
- bool visitInstance(TypeInstance t)
+ extern (D) static Objects* arraySyntaxCopy(Objects* objs)
{
- foreach (tp; tparams)
+ Objects* a = null;
+ if (objs)
{
- if (t.tempinst.name == tp.ident)
- return true;
+ a = new Objects(objs.length);
+ foreach (i, o; *objs)
+ (*a)[i] = objectSyntaxCopy(o);
}
-
- if (t.tempinst.tiargs)
- foreach (arg; *t.tempinst.tiargs)
- {
- if (Type ta = isType(arg))
- {
- if (ta.reliesOnTemplateParameters(tparams))
- return true;
- }
- }
-
- return false;
+ return a;
}
- bool visitTypeof(TypeTypeof t)
+ override TemplateInstance syntaxCopy(Dsymbol s)
{
- //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
- return t.exp.reliesOnTemplateParameters(tparams);
+ TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null);
+ ti.tiargs = arraySyntaxCopy(tiargs);
+ TemplateDeclaration td;
+ if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null)
+ td.ScopeDsymbol.syntaxCopy(ti);
+ else
+ ScopeDsymbol.syntaxCopy(ti);
+ return ti;
}
- bool visitTuple(TypeTuple t)
+ override const(char)* kind() const
{
- if (t.arguments)
- foreach (arg; *t.arguments)
- {
- if (arg.type.reliesOnTemplateParameters(tparams))
- return true;
- }
+ return "template instance";
+ }
- return false;
- }
-
- if (!t)
- return false;
-
- Type tb = t.toBasetype();
- switch (tb.ty)
- {
- case Tvector: return visitVector(tb.isTypeVector());
- case Taarray: return visitAArray(tb.isTypeAArray());
- case Tfunction: return visitFunction(tb.isTypeFunction());
- case Tident: return visitIdentifier(tb.isTypeIdentifier());
- case Tinstance: return visitInstance(tb.isTypeInstance());
- case Ttypeof: return visitTypeof(tb.isTypeTypeof());
- case Ttuple: return visitTuple(tb.isTypeTuple());
- case Tenum: return false;
- default: return tb.nextOf().reliesOnTemplateParameters(tparams);
- }
-}
-
-/***********************************************************
- * Check whether the expression representation relies on one or more the template parameters.
- * Params:
- * e = expression to test
- * tparams = Template parameters.
- * Returns:
- * true if it does
- */
-private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparams)
-{
- extern (C++) final class ReliesOnTemplateParameters : Visitor
- {
- alias visit = Visitor.visit;
- public:
- TemplateParameter[] tparams;
- bool result;
-
- extern (D) this(TemplateParameter[] tparams) @safe
- {
- this.tparams = tparams;
- }
-
- override void visit(Expression e)
- {
- //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
- }
-
- override void visit(IdentifierExp e)
- {
- //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- foreach (tp; tparams)
- {
- if (e.ident == tp.ident)
- {
- result = true;
- return;
- }
- }
- }
-
- override void visit(TupleExp e)
- {
- //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- if (e.exps)
- {
- foreach (ea; *e.exps)
- {
- ea.accept(this);
- if (result)
- return;
- }
- }
- }
-
- override void visit(ArrayLiteralExp e)
- {
- //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- if (e.elements)
- {
- foreach (el; *e.elements)
- {
- el.accept(this);
- if (result)
- return;
- }
- }
- }
-
- override void visit(AssocArrayLiteralExp e)
- {
- //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- foreach (ek; *e.keys)
- {
- ek.accept(this);
- if (result)
- return;
- }
- foreach (ev; *e.values)
- {
- ev.accept(this);
- if (result)
- return;
- }
- }
-
- override void visit(StructLiteralExp e)
- {
- //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- if (e.elements)
- {
- foreach (ea; *e.elements)
- {
- ea.accept(this);
- if (result)
- return;
- }
- }
- }
-
- override void visit(TypeExp e)
- {
- //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- result = e.type.reliesOnTemplateParameters(tparams);
- }
-
- override void visit(NewExp e)
- {
- //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- if (e.placement)
- e.placement.accept(this);
- if (e.thisexp)
- e.thisexp.accept(this);
- result = e.newtype.reliesOnTemplateParameters(tparams);
- if (!result && e.arguments)
- {
- foreach (ea; *e.arguments)
- {
- ea.accept(this);
- if (result)
- return;
- }
- }
- }
-
- override void visit(NewAnonClassExp e)
- {
- //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- result = true;
- }
-
- override void visit(FuncExp e)
- {
- //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- result = true;
- }
-
- override void visit(TypeidExp e)
- {
- //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- if (auto ea = isExpression(e.obj))
- ea.accept(this);
- else if (auto ta = isType(e.obj))
- result = ta.reliesOnTemplateParameters(tparams);
- }
-
- override void visit(TraitsExp e)
- {
- //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- if (e.args)
- {
- foreach (oa; *e.args)
- {
- if (auto ea = isExpression(oa))
- ea.accept(this);
- else if (auto ta = isType(oa))
- result = ta.reliesOnTemplateParameters(tparams);
- if (result)
- return;
- }
- }
- }
-
- override void visit(IsExp e)
- {
- //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- result = e.targ.reliesOnTemplateParameters(tparams);
- }
-
- override void visit(UnaExp e)
- {
- //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- e.e1.accept(this);
- }
-
- override void visit(DotTemplateInstanceExp e)
- {
- //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(e.isUnaExp());
- if (!result && e.ti.tiargs)
- {
- foreach (oa; *e.ti.tiargs)
- {
- if (auto ea = isExpression(oa))
- ea.accept(this);
- else if (auto ta = isType(oa))
- result = ta.reliesOnTemplateParameters(tparams);
- if (result)
- return;
- }
- }
- }
-
- override void visit(CallExp e)
- {
- //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(e.isUnaExp());
- if (!result && e.arguments)
- {
- foreach (ea; *e.arguments)
- {
- ea.accept(this);
- if (result)
- return;
- }
- }
- }
-
- override void visit(CastExp e)
- {
- //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(e.isUnaExp());
- // e.to can be null for cast() with no type
- if (!result && e.to)
- result = e.to.reliesOnTemplateParameters(tparams);
- }
-
- override void visit(SliceExp e)
- {
- //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(e.isUnaExp());
- if (!result && e.lwr)
- e.lwr.accept(this);
- if (!result && e.upr)
- e.upr.accept(this);
- }
-
- override void visit(IntervalExp e)
- {
- //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- e.lwr.accept(this);
- if (!result)
- e.upr.accept(this);
- }
-
- override void visit(ArrayExp e)
- {
- //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- visit(e.isUnaExp());
- if (!result && e.arguments)
- {
- foreach (ea; *e.arguments)
- ea.accept(this);
- }
- }
-
- override void visit(BinExp e)
- {
- //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- e.e1.accept(this);
- if (!result)
- e.e2.accept(this);
- }
-
- override void visit(CondExp e)
- {
- //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
- e.econd.accept(this);
- if (!result)
- visit(e.isBinExp());
- }
- }
-
- scope ReliesOnTemplateParameters v = new ReliesOnTemplateParameters(tparams);
- e.accept(v);
- return v.result;
-}
-
-/***********************************************************
- * https://dlang.org/spec/template.html#TemplateParameter
- */
-extern (C++) class TemplateParameter : ASTNode
-{
- Loc loc;
- Identifier ident;
-
- /* True if this is a part of precedent parameter specialization pattern.
- *
- * template A(T : X!TL, alias X, TL...) {}
- * // X and TL are dependent template parameter
- *
- * A dependent template parameter should return MATCH.exact in matchArg()
- * to respect the match level of the corresponding precedent parameter.
- */
- bool dependent;
-
- /* ======================== TemplateParameter =============================== */
- extern (D) this(Loc loc, Identifier ident) @safe
- {
- this.loc = loc;
- this.ident = ident;
- }
-
- TemplateTypeParameter isTemplateTypeParameter()
- {
- return null;
- }
-
- TemplateValueParameter isTemplateValueParameter()
- {
- return null;
- }
-
- TemplateAliasParameter isTemplateAliasParameter()
- {
- return null;
- }
-
- TemplateThisParameter isTemplateThisParameter()
- {
- return null;
- }
-
- TemplateTupleParameter isTemplateTupleParameter()
- {
- return null;
- }
-
- abstract TemplateParameter syntaxCopy();
-
- abstract bool declareParameter(Scope* sc);
-
- abstract void print(RootObject oarg, RootObject oded);
-
- abstract RootObject specialization();
-
- abstract RootObject defaultArg(Loc instLoc, Scope* sc);
-
- abstract bool hasDefaultArg();
-
- override const(char)* toChars() const
- {
- return this.ident.toChars();
- }
-
- override DYNCAST dyncast() const
- {
- return DYNCAST.templateparameter;
- }
-
- override void accept(Visitor v)
- {
- v.visit(this);
- }
-}
-
-/***********************************************************
- * https://dlang.org/spec/template.html#TemplateTypeParameter
- * Syntax:
- * ident : specType = defaultType
- */
-extern (C++) class TemplateTypeParameter : TemplateParameter
-{
- Type specType; // if !=null, this is the type specialization
- Type defaultType;
-
- extern (D) __gshared Type tdummy = null;
-
- extern (D) this(Loc loc, Identifier ident, Type specType, Type defaultType) @safe
- {
- super(loc, ident);
- this.specType = specType;
- this.defaultType = defaultType;
- }
-
- override final TemplateTypeParameter isTemplateTypeParameter()
- {
- return this;
- }
-
- override TemplateTypeParameter syntaxCopy()
- {
- return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
- }
-
- override final bool declareParameter(Scope* sc)
- {
- //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
- auto ti = new TypeIdentifier(loc, ident);
- Declaration ad = new AliasDeclaration(loc, ident, ti);
- return sc.insert(ad) !is null;
- }
-
- override final void print(RootObject oarg, RootObject oded)
- {
- printf(" %s\n", ident.toChars());
-
- Type t = isType(oarg);
- Type ta = isType(oded);
- assert(ta);
-
- if (specType)
- printf("\tSpecialization: %s\n", specType.toChars());
- if (defaultType)
- printf("\tDefault: %s\n", defaultType.toChars());
- printf("\tParameter: %s\n", t ? t.toChars() : "NULL");
- printf("\tDeduced Type: %s\n", ta.toChars());
- }
-
- override final RootObject specialization()
- {
- return specType;
- }
-
- override final RootObject defaultArg(Loc instLoc, Scope* sc)
- {
- Type t = defaultType;
- if (t)
- {
- t = t.syntaxCopy();
- t = t.typeSemantic(loc, sc); // use the parameter loc
- }
- return t;
- }
-
- override final bool hasDefaultArg()
- {
- return defaultType !is null;
- }
-
- override void accept(Visitor v)
- {
- v.visit(this);
- }
-}
-
-/***********************************************************
- * https://dlang.org/spec/template.html#TemplateThisParameter
- * Syntax:
- * this ident : specType = defaultType
- */
-extern (C++) final class TemplateThisParameter : TemplateTypeParameter
-{
- extern (D) this(Loc loc, Identifier ident, Type specType, Type defaultType) @safe
- {
- super(loc, ident, specType, defaultType);
- }
-
- override TemplateThisParameter isTemplateThisParameter()
- {
- return this;
- }
-
- override TemplateThisParameter syntaxCopy()
- {
- return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
- }
-
- override void accept(Visitor v)
- {
- v.visit(this);
- }
-}
-
-/***********************************************************
- * https://dlang.org/spec/template.html#TemplateValueParameter
- * Syntax:
- * valType ident : specValue = defaultValue
- */
-extern (C++) final class TemplateValueParameter : TemplateParameter
-{
- Type valType;
- Expression specValue;
- Expression defaultValue;
-
- extern (D) __gshared Expression[void*] edummies;
-
- extern (D) this(Loc loc, Identifier ident, Type valType,
- Expression specValue, Expression defaultValue) @safe
- {
- super(loc, ident);
- this.valType = valType;
- this.specValue = specValue;
- this.defaultValue = defaultValue;
- }
-
- override TemplateValueParameter isTemplateValueParameter()
- {
- return this;
- }
-
- override TemplateValueParameter syntaxCopy()
- {
- return new TemplateValueParameter(loc, ident,
- valType.syntaxCopy(),
- specValue ? specValue.syntaxCopy() : null,
- defaultValue ? defaultValue.syntaxCopy() : null);
- }
-
- override bool declareParameter(Scope* sc)
- {
- /*
- Do type semantic earlier.
-
- This means for certain erroneous value parameters
- their "type" can be known earlier and thus a better
- error message given.
-
- For example:
- `template test(x* x) {}`
- now yields "undefined identifier" rather than the opaque
- "variable `x` is used as a type".
- */
- if (valType)
- valType = valType.typeSemantic(loc, sc);
- auto v = new VarDeclaration(loc, valType, ident, null);
- v.storage_class = STC.templateparameter;
- return sc.insert(v) !is null;
- }
-
- override void print(RootObject oarg, RootObject oded)
- {
- printf(" %s\n", ident.toChars());
- Expression ea = isExpression(oded);
- if (specValue)
- printf("\tSpecialization: %s\n", specValue.toChars());
- printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL");
- }
-
- override RootObject specialization()
- {
- return specValue;
- }
-
- override RootObject defaultArg(Loc instLoc, Scope* sc)
- {
- Expression e = defaultValue;
- if (!e)
- return null;
-
- e = e.syntaxCopy();
- Scope* sc2 = sc.push();
- sc2.inDefaultArg = true;
- e = e.expressionSemantic(sc2);
- sc2.pop();
- if (e is null)
- return null;
- if (auto te = e.isTemplateExp())
- {
- assert(sc && sc.tinst);
- if (te.td == sc.tinst.tempdecl)
- {
- // defaultValue is a reference to its template declaration
- // i.e: `template T(int arg = T)`
- // Raise error now before calling resolveProperties otherwise we'll
- // start looping on the expansion of the template instance.
- auto td = sc.tinst.tempdecl;
- .error(td.loc, "%s `%s` recursive template expansion", td.kind, td.toPrettyChars);
- return ErrorExp.get();
- }
- }
- if ((e = resolveProperties(sc, e)) is null)
- return null;
- e = e.resolveLoc(instLoc, sc); // use the instantiated loc
- e = e.optimize(WANTvalue);
-
- return e;
- }
-
- override bool hasDefaultArg()
- {
- return defaultValue !is null;
- }
-
- override void accept(Visitor v)
- {
- v.visit(this);
- }
-}
-
-/***********************************************************
- * https://dlang.org/spec/template.html#TemplateAliasParameter
- * Syntax:
- * specType ident : specAlias = defaultAlias
- */
-extern (C++) final class TemplateAliasParameter : TemplateParameter
-{
- Type specType;
- RootObject specAlias;
- RootObject defaultAlias;
-
- extern (D) __gshared Dsymbol sdummy = null;
-
- extern (D) this(Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias) @safe
- {
- super(loc, ident);
- this.specType = specType;
- this.specAlias = specAlias;
- this.defaultAlias = defaultAlias;
- }
-
- override TemplateAliasParameter isTemplateAliasParameter()
- {
- return this;
- }
-
- override TemplateAliasParameter syntaxCopy()
- {
- return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias));
- }
-
- override bool declareParameter(Scope* sc)
- {
- auto ti = new TypeIdentifier(loc, ident);
- Declaration ad = new AliasDeclaration(loc, ident, ti);
- return sc.insert(ad) !is null;
- }
-
- override void print(RootObject oarg, RootObject oded)
- {
- printf(" %s\n", ident.toChars());
- Dsymbol sa = isDsymbol(oded);
- assert(sa);
- printf("\tParameter alias: %s\n", sa.toChars());
- }
-
- override RootObject specialization()
- {
- return specAlias;
- }
-
- override RootObject defaultArg(Loc instLoc, Scope* sc)
- {
- RootObject da = defaultAlias;
- if (auto ta = isType(defaultAlias))
- {
- switch (ta.ty)
- {
- // If the default arg is a template, instantiate for each type
- case Tinstance :
- // same if the default arg is a mixin, traits, typeof
- // since the content might rely on a previous parameter
- // (https://issues.dlang.org/show_bug.cgi?id=23686)
- case Tmixin, Ttypeof, Ttraits :
- da = ta.syntaxCopy();
- break;
- default:
- }
- }
-
- RootObject o = aliasParameterSemantic(loc, sc, da, null); // use the parameter loc
- return o;
- }
-
- override bool hasDefaultArg()
- {
- return defaultAlias !is null;
- }
-
- override void accept(Visitor v)
- {
- v.visit(this);
- }
-}
-
-/***********************************************************
- * https://dlang.org/spec/template.html#TemplateSequenceParameter
- * Syntax:
- * ident ...
- */
-extern (C++) final class TemplateTupleParameter : TemplateParameter
-{
- extern (D) this(Loc loc, Identifier ident) @safe
- {
- super(loc, ident);
- }
-
- override TemplateTupleParameter isTemplateTupleParameter()
- {
- return this;
- }
-
- override TemplateTupleParameter syntaxCopy()
- {
- return new TemplateTupleParameter(loc, ident);
- }
-
- override bool declareParameter(Scope* sc)
- {
- auto ti = new TypeIdentifier(loc, ident);
- Declaration ad = new AliasDeclaration(loc, ident, ti);
- return sc.insert(ad) !is null;
- }
-
- override void print(RootObject oarg, RootObject oded)
- {
- printf(" %s... [", ident.toChars());
- Tuple v = isTuple(oded);
- assert(v);
-
- //printf("|%d| ", v.objects.length);
- foreach (i, o; v.objects)
- {
- if (i)
- printf(", ");
-
- Dsymbol sa = isDsymbol(o);
- if (sa)
- printf("alias: %s", sa.toChars());
- Type ta = isType(o);
- if (ta)
- printf("type: %s", ta.toChars());
- Expression ea = isExpression(o);
- if (ea)
- printf("exp: %s", ea.toChars());
-
- assert(!isTuple(o)); // no nested Tuple arguments
- }
- printf("]\n");
- }
-
- override RootObject specialization()
- {
- return null;
- }
-
- override RootObject defaultArg(Loc instLoc, Scope* sc)
- {
- return null;
- }
-
- override bool hasDefaultArg()
- {
- return false;
- }
-
- override void accept(Visitor v)
- {
- v.visit(this);
- }
-}
-
-/***********************************************************
- * https://dlang.org/spec/template.html#explicit_tmp_instantiation
- * Given:
- * foo!(args) =>
- * name = foo
- * tiargs = args
- */
-extern (C++) class TemplateInstance : ScopeDsymbol
-{
- Identifier name;
-
- // Array of Types/Expressions of template
- // instance arguments [int*, char, 10*10]
- Objects* tiargs;
-
- // Array of Types/Expressions corresponding
- // to TemplateDeclaration.parameters
- // [int, char, 100]
- Objects tdtypes;
-
- // Modules imported by this template instance
- Modules importedModules;
-
- Dsymbol tempdecl; // referenced by foo.bar.abc
- Dsymbol enclosing; // if referencing local symbols, this is the context
- Dsymbol aliasdecl; // !=null if instance is an alias for its sole member
-
- /**
- If this is not null and it has a value that is not the current object,
- then this field points to an existing template instance
- and that object has been duplicated into us.
-
- If this object is a duplicate,
- the ``memberOf`` field will be set to a root module (passed on CLI).
-
- This information is useful to deduplicate analysis that may occur
- after semantic 3 has completed.
-
- See_Also: memberOf
- */
- TemplateInstance inst;
-
- ScopeDsymbol argsym; // argument symbol table
- size_t hash; // cached result of toHash()
-
- /// For function template, these are the function fnames(name and loc of it) and arguments
- /// Relevant because different resolutions of `auto ref` parameters
- /// create different template instances even with the same template arguments
- Expressions* fargs;
- ArgumentLabels* fnames;
-
- TemplateInstances* deferred;
-
- /**
- If this is not null then this template instance appears in a root module's members.
-
- Note: This is not useful for determining duplication status of this template instance.
- Use the field ``inst`` for determining if a template instance has been duplicated into this object.
-
- See_Also: inst
- */
- Module memberOf;
-
- // Used to determine the instance needs code generation.
- // Note that these are inaccurate until semantic analysis phase completed.
- TemplateInstance tinst; // enclosing template instance
- TemplateInstance tnext; // non-first instantiated instances
- Module minst; // the top module that instantiated this instance
-
- private ushort _nest; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
- ubyte inuse; // for recursive expansion detection
-
- private enum Flag : uint
- {
- semantictiargsdone = 1u << (_nest.sizeof * 8 - 1), // MSB of _nest
- havetempdecl = semantictiargsdone >> 1,
- gagged = semantictiargsdone >> 2,
- available = gagged - 1 // always last flag minus one, 1s for all available bits
- }
-
- extern(D) final @safe @property pure nothrow @nogc
- {
- ushort nest() const { return _nest & Flag.available; }
- void nestUp() { assert(nest() < Flag.available); ++_nest; }
- void nestDown() { assert(nest() > 0); --_nest; }
- /// has semanticTiargs() been done?
- bool semantictiargsdone() const { return (_nest & Flag.semantictiargsdone) != 0; }
- void semantictiargsdone(bool x)
- {
- if (x) _nest |= Flag.semantictiargsdone;
- else _nest &= ~Flag.semantictiargsdone;
- }
- /// if used second constructor
- bool havetempdecl() const { return (_nest & Flag.havetempdecl) != 0; }
- void havetempdecl(bool x)
- {
- if (x) _nest |= Flag.havetempdecl;
- else _nest &= ~Flag.havetempdecl;
- }
- /// if the instantiation is done with error gagging
- bool gagged() const { return (_nest & Flag.gagged) != 0; }
- void gagged(bool x)
- {
- if (x) _nest |= Flag.gagged;
- else _nest &= ~Flag.gagged;
- }
- }
-
- extern (D) this(Loc loc, Identifier ident, Objects* tiargs) scope
- {
- super(loc, null);
- static if (LOG)
- {
- printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null");
- }
- this.dsym = DSYM.templateInstance;
- this.name = ident;
- this.tiargs = tiargs;
- }
-
- /*****************
- * This constructor is only called when we figured out which function
- * template to instantiate.
- */
- extern (D) this(Loc loc, TemplateDeclaration td, Objects* tiargs) scope
- {
- super(loc, null);
- static if (LOG)
- {
- printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars());
- }
- this.dsym = DSYM.templateInstance;
- this.name = td.ident;
- this.tiargs = tiargs;
- this.tempdecl = td;
- this.semantictiargsdone = true;
- this.havetempdecl = true;
- assert(tempdecl._scope);
- }
-
- extern (D) static Objects* arraySyntaxCopy(Objects* objs)
- {
- Objects* a = null;
- if (objs)
- {
- a = new Objects(objs.length);
- foreach (i, o; *objs)
- (*a)[i] = objectSyntaxCopy(o);
- }
- return a;
- }
-
- override TemplateInstance syntaxCopy(Dsymbol s)
- {
- TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null);
- ti.tiargs = arraySyntaxCopy(tiargs);
- TemplateDeclaration td;
- if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null)
- td.ScopeDsymbol.syntaxCopy(ti);
- else
- ScopeDsymbol.syntaxCopy(ti);
- return ti;
- }
-
- // resolve real symbol
- override final Dsymbol toAlias()
- {
- static if (LOG)
- {
- printf("TemplateInstance.toAlias()\n");
- }
- if (!inst)
- {
- // Maybe we can resolve it
- if (_scope)
- {
- dsymbolSemantic(this, _scope);
- }
- if (!inst)
- {
- .error(loc, "%s `%s` cannot resolve forward reference", kind, toPrettyChars);
- errors = true;
- return this;
- }
- }
-
- if (inst != this)
- return inst.toAlias();
-
- if (aliasdecl)
- {
- return aliasdecl.toAlias();
- }
-
- return inst;
- }
-
- override const(char)* kind() const
- {
- return "template instance";
- }
-
- override final const(char)* toPrettyCharsHelper()
- {
- OutBuffer buf;
- toCBufferInstance(this, buf, true);
- return buf.extractChars();
- }
-
- /**************************************
- * Given an error instantiating the TemplateInstance,
- * give the nested TemplateInstance instantiations that got
- * us here. Those are a list threaded into the nested scopes.
- * Params:
- * cl = classification of this trace as printing either errors or deprecations
- * max_shown = maximum number of trace elements printed (controlled with -v/-verror-limit)
- */
- extern(D) final void printInstantiationTrace(Classification cl = Classification.error,
- const(uint) max_shown = global.params.v.errorSupplementCount())
- {
- if (global.gag)
- return;
-
- // Print full trace for verbose mode, otherwise only short traces
- const(char)* format = "instantiated from here: `%s`";
-
- // This returns a function pointer
- scope printFn = () {
- final switch (cl)
- {
- case Classification.error:
- return &errorSupplemental;
- case Classification.deprecation:
- return &deprecationSupplemental;
- case Classification.gagged, Classification.tip, Classification.warning:
- assert(0);
- }
- }();
-
- // determine instantiation depth and number of recursive instantiations
- int n_instantiations = 1;
- int n_totalrecursions = 0;
- for (TemplateInstance cur = this; cur; cur = cur.tinst)
- {
- ++n_instantiations;
- // Set error here as we don't want it to depend on the number of
- // entries that are being printed.
- if (cl == Classification.error ||
- (cl == Classification.warning && global.params.useWarnings == DiagnosticReporting.error) ||
- (cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
- cur.errors = true;
-
- // If two instantiations use the same declaration, they are recursive.
- // (this works even if they are instantiated from different places in the
- // same template).
- // In principle, we could also check for multiple-template recursion, but it's
- // probably not worthwhile.
- if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
- ++n_totalrecursions;
- }
-
- if (n_instantiations <= max_shown)
- {
- for (TemplateInstance cur = this; cur; cur = cur.tinst)
- printFn(cur.loc, format, cur.toErrMsg());
- }
- else if (n_instantiations - n_totalrecursions <= max_shown)
- {
- // By collapsing recursive instantiations into a single line,
- // we can stay under the limit.
- int recursionDepth = 0;
- for (TemplateInstance cur = this; cur; cur = cur.tinst)
- {
- if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
- {
- ++recursionDepth;
- }
- else
- {
- if (recursionDepth)
- printFn(cur.loc, "%d recursive instantiations from here: `%s`", recursionDepth + 2, cur.toChars());
- else
- printFn(cur.loc, format, cur.toChars());
- recursionDepth = 0;
- }
- }
- }
- else
- {
- // Even after collapsing the recursions, the depth is too deep.
- // Just display the first few and last few instantiations.
- uint i = 0;
- for (TemplateInstance cur = this; cur; cur = cur.tinst)
- {
- if (i == max_shown / 2)
- printFn(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
-
- if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2)
- printFn(cur.loc, format, cur.toChars());
- ++i;
- }
- }
- }
-
- /*************************************
- * Lazily generate identifier for template instance.
- * This is because 75% of the ident's are never needed.
- */
- override final Identifier getIdent()
- {
- if (!ident && inst && !errors)
- ident = genIdent(tiargs); // need an identifier for name mangling purposes.
- return ident;
- }
-
- /*************************************
- * Compare proposed template instantiation with existing template instantiation.
- * Note that this is not commutative because of the auto ref check.
- * Params:
- * ti = existing template instantiation
- * Returns:
- * true for match
- */
- final bool equalsx(TemplateInstance ti)
- {
- //printf("this = %p, ti = %p\n", this, ti);
- assert(tdtypes.length == ti.tdtypes.length);
-
- // Nesting must match
- if (enclosing != ti.enclosing)
- {
- //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
- return false;
- }
- //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
-
- if (!arrayObjectMatch(tdtypes, ti.tdtypes))
- return false;
-
- /* Template functions may have different instantiations based on
- * "auto ref" parameters.
- */
- auto fd = ti.toAlias().isFuncDeclaration();
- if (!fd)
- return true;
- if (fd.errors)
- return true;
-
- auto resolvedArgs = fd.type.isTypeFunction().resolveNamedArgs(
- ArgumentList(this.fargs, this.fnames), null);
-
- // resolvedArgs can be null when there's an error: fail_compilation/fail14669.d
- // In that case, equalsx returns true to prevent endless template instantiations
- // However, it can also mean the function was explicitly instantiated
- // without function arguments: fail_compilation/fail14669
- // Hence the following check:
- if (this.fargs && !resolvedArgs)
- return true;
-
- Expression[] args = resolvedArgs ? (*resolvedArgs)[] : [];
-
- auto fparameters = fd.getParameterList();
- size_t nfparams = fparameters.length; // Num function parameters
- for (size_t j = 0; j < nfparams; j++)
- {
- Parameter fparam = fparameters[j];
- if (!(fparam.storageClass & STC.autoref) ) // if "auto ref"
- continue;
-
- Expression farg = (j < args.length) ? args[j] : fparam.defaultArg;
- // resolveNamedArgs strips trailing nulls / default params
- // when it doesn't anymore, the ternary can be replaced with:
- // assert(j < resolvedArgs.length);
- if (!farg)
- farg = fparam.defaultArg;
- if (!farg)
- return false;
- if (farg.isLvalue())
- {
- if (!(fparam.storageClass & STC.ref_))
- return false; // auto ref's don't match
- }
- else
- {
- if (fparam.storageClass & STC.ref_)
- return false; // auto ref's don't match
- }
- }
- return true;
- }
-
- extern (D) final size_t toHash()
- {
- if (!hash)
- {
- hash = cast(size_t)cast(void*)enclosing;
- hash += arrayObjectHash(tdtypes);
- hash += hash == 0;
- }
- return hash;
- }
-
- /**
- Returns: true if the instances' innards are discardable.
-
- The idea of this function is to see if the template instantiation
- can be 100% replaced with its eponymous member. All other members
- can be discarded, even in the compiler to free memory (for example,
- the template could be expanded in a region allocator, deemed trivial,
- the end result copied back out independently and the entire region freed),
- and can be elided entirely from the binary.
-
- The current implementation affects code that generally looks like:
-
- ---
- template foo(args...) {
- some_basic_type_or_string helper() { .... }
- enum foo = helper();
- }
- ---
-
- since it was the easiest starting point of implementation but it can and
- should be expanded more later.
- */
- final bool isDiscardable()
- {
- if (aliasdecl is null)
- return false;
-
- auto v = aliasdecl.isVarDeclaration();
- if (v is null)
- return false;
-
- if (!(v.storage_class & STC.manifest))
- return false;
-
- // Currently only doing basic types here because it is the easiest proof-of-concept
- // implementation with minimal risk of side effects, but it could likely be
- // expanded to any type that already exists outside this particular instance.
- if (!(v.type.equals(Type.tstring) || (v.type.isTypeBasic() !is null)))
- return false;
-
- // Static ctors and dtors, even in an eponymous enum template, are still run,
- // so if any of them are in here, we'd better not assume it is trivial lest
- // we break useful code
- foreach(member; *members)
- {
- if(member.hasStaticCtorOrDtor())
- return false;
- if(member.isStaticDtorDeclaration())
- return false;
- if(member.isStaticCtorDeclaration())
- return false;
- }
-
- // but if it passes through this gauntlet... it should be fine. D code will
- // see only the eponymous member, outside stuff can never access it, even through
- // reflection; the outside world ought to be none the wiser. Even dmd should be
- // able to simply free the memory of everything except the final result.
-
- return true;
- }
-
-
- /***********************************************
- * Returns true if this is not instantiated in non-root module, and
- * is a part of non-speculative instantiatiation.
- *
- * Note: minst does not stabilize until semantic analysis is completed,
- * so don't call this function during semantic analysis to return precise result.
- */
- final bool needsCodegen()
- {
- //printf("needsCodegen() %s\n", toChars());
-
- // minst is finalized after the 1st invocation.
- // tnext is only needed for the 1st invocation and
- // cleared for further invocations.
- TemplateInstance tnext = this.tnext;
- TemplateInstance tinst = this.tinst;
- this.tnext = null;
-
- // Don't do codegen if the instance has errors,
- // is a dummy instance (see evaluateConstraint),
- // or is determined to be discardable.
- if (errors || inst is null || inst.isDiscardable())
- {
- minst = null; // mark as speculative
- return false;
- }
-
- // This should only be called on the primary instantiation.
- assert(this is inst);
-
- if (global.params.allInst)
- {
- // Do codegen if there is an instantiation from a root module, to maximize link-ability.
- static ThreeState needsCodegenAllInst(TemplateInstance tithis, TemplateInstance tinst)
- {
- // Do codegen if `this` is instantiated from a root module.
- if (tithis.minst && tithis.minst.isRoot())
- return ThreeState.yes;
-
- // Do codegen if the ancestor needs it.
- if (tinst && tinst.inst && tinst.inst.needsCodegen())
- {
- tithis.minst = tinst.inst.minst; // cache result
- assert(tithis.minst);
- assert(tithis.minst.isRoot());
- return ThreeState.yes;
- }
- return ThreeState.none;
- }
-
- if (const needsCodegen = needsCodegenAllInst(this, tinst))
- return needsCodegen == ThreeState.yes ? true : false;
-
- // Do codegen if a sibling needs it.
- for (; tnext; tnext = tnext.tnext)
- {
- const needsCodegen = needsCodegenAllInst(tnext, tnext.tinst);
- if (needsCodegen == ThreeState.yes)
- {
- minst = tnext.minst; // cache result
- assert(minst);
- assert(minst.isRoot());
- return true;
- }
- else if (!minst && tnext.minst)
- {
- minst = tnext.minst; // cache result from non-speculative sibling
- // continue searching
- }
- else if (needsCodegen != ThreeState.none)
- break;
- }
-
- // Elide codegen because there's no instantiation from any root modules.
- return false;
- }
-
- // Prefer instantiations from non-root modules, to minimize object code size.
-
- /* If a TemplateInstance is ever instantiated from a non-root module,
- * we do not have to generate code for it,
- * because it will be generated when the non-root module is compiled.
- *
- * But, if the non-root 'minst' imports any root modules, it might still need codegen.
- *
- * The problem is if A imports B, and B imports A, and both A
- * and B instantiate the same template, does the compilation of A
- * or the compilation of B do the actual instantiation?
- *
- * See https://issues.dlang.org/show_bug.cgi?id=2500.
- *
- * => Elide codegen if there is at least one instantiation from a non-root module
- * which doesn't import any root modules.
- */
- static ThreeState needsCodegenRootOnly(TemplateInstance tithis, TemplateInstance tinst)
- {
- // If the ancestor isn't speculative,
- // 1. do codegen if the ancestor needs it
- // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
- if (tinst && tinst.inst)
- {
- tinst = tinst.inst;
- const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
- if (tinst.minst) // not speculative
- {
- tithis.minst = tinst.minst; // cache result
- return needsCodegen ? ThreeState.yes : ThreeState.no;
- }
- }
-
- // Elide codegen if `this` doesn't need it.
- if (tithis.minst && !tithis.minst.isRoot() && !tithis.minst.rootImports())
- return ThreeState.no;
-
- return ThreeState.none;
- }
-
- if (const needsCodegen = needsCodegenRootOnly(this, tinst))
- return needsCodegen == ThreeState.yes ? true : false;
-
- // Elide codegen if a (non-speculative) sibling doesn't need it.
- for (; tnext; tnext = tnext.tnext)
- {
- const needsCodegen = needsCodegenRootOnly(tnext, tnext.tinst); // sets tnext.minst
- if (tnext.minst) // not speculative
- {
- if (needsCodegen == ThreeState.no)
- {
- minst = tnext.minst; // cache result
- assert(!minst.isRoot() && !minst.rootImports());
- return false;
- }
- else if (!minst)
- {
- minst = tnext.minst; // cache result from non-speculative sibling
- // continue searching
- }
- else if (needsCodegen != ThreeState.none)
- break;
- }
- }
-
- // Unless `this` is still speculative (=> all further siblings speculative too),
- // do codegen because we found no guaranteed-codegen'd non-root instantiation.
- return minst !is null;
- }
-
- /**********************************************
- * Find template declaration corresponding to template instance.
- *
- * Returns:
- * false if finding fails.
- * Note:
- * This function is reentrant against error occurrence. If returns false,
- * any members of this object won't be modified, and repetition call will
- * reproduce same error.
- */
- extern (D) final bool findTempDecl(Scope* sc, WithScopeSymbol* pwithsym)
+ override final const(char)* toPrettyCharsHelper()
{
- if (pwithsym)
- *pwithsym = null;
-
- if (havetempdecl)
- return true;
-
- //printf("TemplateInstance.findTempDecl() %s\n", toChars());
- if (!tempdecl)
- {
- /* Given:
- * foo!( ... )
- * figure out which TemplateDeclaration foo refers to.
- */
- Identifier id = name;
- Dsymbol scopesym;
- Dsymbol s = sc.search(loc, id, scopesym);
- if (!s)
- {
- s = sc.search_correct(id);
- if (s)
- .error(loc, "%s `%s` template `%s` is not defined, did you mean %s?", kind, toPrettyChars, id.toChars(), s.toChars());
- else
- .error(loc, "%s `%s` template `%s` is not defined", kind, toPrettyChars, id.toChars());
- return false;
- }
- static if (LOG)
- {
- printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind());
- if (s.parent)
- printf("s.parent = '%s'\n", s.parent.toChars());
- }
- if (pwithsym)
- *pwithsym = scopesym.isWithScopeSymbol();
-
- /* We might have found an alias within a template when
- * we really want the template.
- */
- TemplateInstance ti;
- if (s.parent && (ti = s.parent.isTemplateInstance()) !is null)
- {
- if (ti.tempdecl && ti.tempdecl.ident == id)
- {
- /* This is so that one can refer to the enclosing
- * template, even if it has the same name as a member
- * of the template, if it has a !(arguments)
- */
- TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
- assert(td);
- if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
- td = td.overroot; // then get the start
- s = td;
- }
- }
-
- // The template might originate from a selective import which implies that
- // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
- // This is the last place where we see the deprecated alias because it is
- // stripped below, so check if the selective import was deprecated.
- // See https://issues.dlang.org/show_bug.cgi?id=20840.
- if (s.isAliasDeclaration())
- s.checkDeprecated(this.loc, sc);
-
- if (!updateTempDecl(sc, s))
- {
- return false;
- }
- }
- assert(tempdecl);
-
- // Look for forward references
- auto tovers = tempdecl.isOverloadSet();
- foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
- {
- Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
- int r = overloadApply(dstart, (Dsymbol s)
- {
- auto td = s.isTemplateDeclaration();
- if (!td)
- return 0;
-
- if (td.semanticRun == PASS.initial)
- {
- if (td._scope)
- {
- // Try to fix forward reference. Ungag errors while doing so.
- Ungag ungag = td.ungagSpeculative();
- td.dsymbolSemantic(td._scope);
- }
- if (td.semanticRun == PASS.initial)
- {
- .error(loc, "%s `%s` `%s` forward references template declaration `%s`", kind, toPrettyChars,
- toChars(), td.toChars());
- return 1;
- }
- }
- return 0;
- });
- if (r)
- return false;
- }
- return true;
+ OutBuffer buf;
+ toCBufferInstance(this, buf, true);
+ return buf.extractChars();
}
- /**********************************************
- * Confirm s is a valid template, then store it.
- * Input:
- * sc
- * s candidate symbol of template. It may be:
- * TemplateDeclaration
- * FuncDeclaration with findTemplateDeclRoot() != NULL
- * OverloadSet which contains candidates
- * Returns:
- * true if updating succeeds.
+ /**************************************
+ * Given an error instantiating the TemplateInstance,
+ * give the nested TemplateInstance instantiations that got
+ * us here. Those are a list threaded into the nested scopes.
+ * Params:
+ * cl = classification of this trace as printing either errors or deprecations
+ * max_shown = maximum number of trace elements printed (controlled with -v/-verror-limit)
*/
- extern (D) final bool updateTempDecl(Scope* sc, Dsymbol s)
+ extern(D) final void printInstantiationTrace(Classification cl = Classification.error,
+ const(uint) max_shown = global.params.v.errorSupplementCount())
{
- if (!s)
- return tempdecl !is null;
-
- Identifier id = name;
- s = s.toAlias();
-
- /* If an OverloadSet, look for a unique member that is a template declaration
- */
- if (OverloadSet os = s.isOverloadSet())
- {
- s = null;
- foreach (s2; os.a)
- {
- if (FuncDeclaration f = s2.isFuncDeclaration())
- s2 = f.findTemplateDeclRoot();
- else
- s2 = s2.isTemplateDeclaration();
- if (s2)
- {
- if (s)
- {
- tempdecl = os;
- return true;
- }
- s = s2;
- }
- }
- if (!s)
- {
- .error(loc, "%s `%s` template `%s` is not defined", kind, toPrettyChars, id.toChars());
- return false;
- }
- }
-
- if (OverDeclaration od = s.isOverDeclaration())
- {
- tempdecl = od; // TODO: more strict check
- return true;
- }
-
- /* It should be a TemplateDeclaration, not some other symbol
- */
- if (FuncDeclaration f = s.isFuncDeclaration())
- tempdecl = f.findTemplateDeclRoot();
- else
- tempdecl = s.isTemplateDeclaration();
-
- // We're done
- if (tempdecl)
- return true;
+ if (global.gag)
+ return;
- // Error already issued, just return `false`
- if (!s.parent && global.errors)
- return false;
+ // Print full trace for verbose mode, otherwise only short traces
+ const(char)* format = "instantiated from here: `%s`";
- if (!s.parent && s.getType())
- {
- Dsymbol s2 = s.getType().toDsymbol(sc);
- if (!s2)
- {
- .error(loc, "`%s` is not a valid template instance, because `%s` is not a template declaration but a type (`%s == %s`)", toChars(), id.toChars(), id.toChars(), s.getType.kind());
- return false;
- }
- // because s can be the alias created for a TemplateParameter
- const AliasDeclaration ad = s.isAliasDeclaration();
- version (none)
+ // This returns a function pointer
+ scope printFn = () {
+ final switch (cl)
{
- if (ad && ad.isAliasedTemplateParameter())
- printf("`%s` is an alias created from a template parameter\n", s.toChars());
+ case Classification.error:
+ return &errorSupplemental;
+ case Classification.deprecation:
+ return &deprecationSupplemental;
+ case Classification.gagged, Classification.tip, Classification.warning:
+ assert(0);
}
- if (!ad || !ad.isAliasedTemplateParameter())
- s = s2;
- }
-
- TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null;
-
- /* This avoids the VarDeclaration.toAlias() which runs semantic() too soon
- */
- static bool matchId(TemplateInstance ti, Identifier id)
- {
- if (ti.aliasdecl && ti.aliasdecl.isVarDeclaration())
- return ti.aliasdecl.isVarDeclaration().ident == id;
- return ti.toAlias().ident == id;
- }
-
- if (ti && (ti.name == s.ident || matchId(ti, s.ident)) && ti.tempdecl)
- {
- /* This is so that one can refer to the enclosing
- * template, even if it has the same name as a member
- * of the template, if it has a !(arguments)
- */
- TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
- assert(td);
- if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
- td = td.overroot; // then get the start
- tempdecl = td;
- return true;
- }
- else
- {
- .error(loc, "%s `%s` `%s` is not a template declaration, it is a %s", kind, toPrettyChars, id.toChars(), s.kind());
- return false;
- }
- }
-
- /**********************************
- * Run semantic of tiargs as arguments of template.
- * Input:
- * loc
- * sc
- * tiargs array of template arguments
- * flags 1: replace const variables with their initializers
- * 2: don't devolve Parameter to Type
- * atd tuple being optimized. If found, it's not expanded here
- * but in AliasAssign semantic.
- * Returns:
- * false if one or more arguments have errors.
- */
- extern (D) static bool semanticTiargs(Loc loc, Scope* sc, Objects* tiargs, int flags, TupleDeclaration atd = null)
- {
- // Run semantic on each argument, place results in tiargs[]
- //printf("+TemplateInstance.semanticTiargs()\n");
- if (!tiargs)
- return true;
- bool err = false;
-
- // The arguments are not treated as part of a default argument,
- // because they are evaluated at compile time.
- const inCondition = sc.condition;
- sc = sc.push();
- sc.inDefaultArg = false;
-
- // https://issues.dlang.org/show_bug.cgi?id=24699
- sc.condition = inCondition;
+ }();
- for (size_t j = 0; j < tiargs.length; j++)
+ // determine instantiation depth and number of recursive instantiations
+ int n_instantiations = 1;
+ int n_totalrecursions = 0;
+ for (TemplateInstance cur = this; cur; cur = cur.tinst)
{
- RootObject o = (*tiargs)[j];
- Type ta = isType(o);
- Expression ea = isExpression(o);
- Dsymbol sa = isDsymbol(o);
-
- //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
- if (ta)
- {
- //printf("type %s\n", ta.toChars());
-
- // It might really be an Expression or an Alias
- ta.resolve(loc, sc, ea, ta, sa, (flags & 1) != 0);
- if (ea)
- goto Lexpr;
- if (sa)
- goto Ldsym;
- if (ta is null)
- {
- assert(global.errors);
- ta = Type.terror;
- }
-
- Ltype:
- if (TypeTuple tt = ta.isTypeTuple())
- {
- // Expand tuple
- size_t dim = tt.arguments.length;
- tiargs.remove(j);
- if (dim)
- {
- tiargs.reserve(dim);
- foreach (i, arg; *tt.arguments)
- {
- if (flags & 2 && (arg.storageClass & STC.parameter))
- tiargs.insert(j + i, arg);
- else
- tiargs.insert(j + i, arg.type);
- }
- }
- j--;
- continue;
- }
- if (ta.ty == Terror)
- {
- err = true;
- continue;
- }
- (*tiargs)[j] = ta.merge2();
- }
- else if (ea)
- {
- Lexpr:
- //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
- if (flags & 1) // only used by __traits
- {
- ea = ea.expressionSemantic(sc);
-
- // must not interpret the args, excepting template parameters
- if (!ea.isVarExp() || (ea.isVarExp().var.storage_class & STC.templateparameter))
- {
- ea = ea.optimize(WANTvalue);
- }
- }
- else
- {
- sc = sc.startCTFE();
- ea = ea.expressionSemantic(sc);
- sc = sc.endCTFE();
-
- if (auto varExp = ea.isVarExp())
- {
- /* If the parameter is a function that is not called
- * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
- * then it is a dsymbol, not the return value of `func()`
- */
- Declaration vd = varExp.var;
- if (auto fd = vd.isFuncDeclaration())
- {
- sa = fd;
- goto Ldsym;
- }
- /* Otherwise skip substituting a const var with
- * its initializer. The problem is the initializer won't
- * match with an 'alias' parameter. Instead, do the
- * const substitution in TemplateValueParameter.matchArg().
- */
- }
- else if (definitelyValueParameter(ea))
- {
- if (ea.checkValue()) // check void expression
- ea = ErrorExp.get();
- const olderrs = global.errors;
- ea = ea.ctfeInterpret();
- if (global.errors != olderrs)
- ea = ErrorExp.get();
- }
- }
- //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
- if (TupleExp te = ea.isTupleExp())
- {
- // Expand tuple
- size_t dim = te.exps.length;
- tiargs.remove(j);
- if (dim)
- {
- tiargs.reserve(dim);
- foreach (i, exp; *te.exps)
- tiargs.insert(j + i, exp);
- }
- j--;
- continue;
- }
- if (ea.op == EXP.error)
- {
- err = true;
- continue;
- }
- (*tiargs)[j] = ea;
+ ++n_instantiations;
+ // Set error here as we don't want it to depend on the number of
+ // entries that are being printed.
+ if (cl == Classification.error ||
+ (cl == Classification.warning && global.params.useWarnings == DiagnosticReporting.error) ||
+ (cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
+ cur.errors = true;
- if (ea.op == EXP.type)
- {
- ta = ea.type;
- goto Ltype;
- }
- if (ea.op == EXP.scope_)
- {
- sa = ea.isScopeExp().sds;
- goto Ldsym;
- }
- if (FuncExp fe = ea.isFuncExp())
- {
- /* A function literal, that is passed to template and
- * already semanticed as function pointer, never requires
- * outer frame. So convert it to global function is valid.
- */
- if (fe.fd.tok == TOK.reserved && fe.type.ty == Tpointer)
- {
- // change to non-nested
- fe.fd.tok = TOK.function_;
- fe.fd.vthis = null;
- }
- else if (fe.td)
- {
- /* If template argument is a template lambda,
- * get template declaration itself. */
- //sa = fe.td;
- //goto Ldsym;
- }
- }
- if (ea.op == EXP.dotVariable && !(flags & 1))
- {
- // translate expression to dsymbol.
- sa = ea.isDotVarExp().var;
- goto Ldsym;
- }
- if (auto te = ea.isTemplateExp())
- {
- sa = te.td;
- goto Ldsym;
- }
- if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1))
- {
- // translate expression to dsymbol.
- sa = ea.isDotTemplateExp().td;
- goto Ldsym;
- }
- if (auto de = ea.isDotExp())
- {
- if (auto se = de.e2.isScopeExp())
- {
- sa = se.sds;
- goto Ldsym;
- }
- }
- }
- else if (sa)
- {
- Ldsym:
- //printf("dsym %s %s\n", sa.kind(), sa.toChars());
- if (sa.errors)
- {
- err = true;
- continue;
- }
+ // If two instantiations use the same declaration, they are recursive.
+ // (this works even if they are instantiated from different places in the
+ // same template).
+ // In principle, we could also check for multiple-template recursion, but it's
+ // probably not worthwhile.
+ if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
+ ++n_totalrecursions;
+ }
- TupleDeclaration d = sa.toAlias().isTupleDeclaration();
- if (d)
- {
- if (d is atd)
- {
- (*tiargs)[j] = d;
- continue;
- }
- // Expand tuple
- tiargs.remove(j);
- tiargs.insert(j, d.objects);
- j--;
- continue;
- }
- if (FuncAliasDeclaration fa = sa.isFuncAliasDeclaration())
+ if (n_instantiations <= max_shown)
+ {
+ for (TemplateInstance cur = this; cur; cur = cur.tinst)
+ printFn(cur.loc, format, cur.toErrMsg());
+ }
+ else if (n_instantiations - n_totalrecursions <= max_shown)
+ {
+ // By collapsing recursive instantiations into a single line,
+ // we can stay under the limit.
+ int recursionDepth = 0;
+ for (TemplateInstance cur = this; cur; cur = cur.tinst)
+ {
+ if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
{
- FuncDeclaration f = fa.toAliasFunc();
- if (!fa.hasOverloads && f.isUnique())
- {
- // Strip FuncAlias only when the aliased function
- // does not have any overloads.
- sa = f;
- }
+ ++recursionDepth;
}
- (*tiargs)[j] = sa;
-
- TemplateDeclaration td = sa.isTemplateDeclaration();
- if (td && td.semanticRun == PASS.initial && td.literal)
+ else
{
- td.dsymbolSemantic(sc);
+ if (recursionDepth)
+ printFn(cur.loc, "%d recursive instantiations from here: `%s`", recursionDepth + 2, cur.toChars());
+ else
+ printFn(cur.loc, format, cur.toChars());
+ recursionDepth = 0;
}
- FuncDeclaration fd = sa.isFuncDeclaration();
- if (fd)
- functionSemantic(fd);
- }
- else if (isParameter(o))
- {
- }
- else
- {
- assert(0);
}
- //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
}
- sc.pop();
- version (none)
+ else
{
- printf("-TemplateInstance.semanticTiargs()\n");
- for (size_t j = 0; j < tiargs.length; j++)
+ // Even after collapsing the recursions, the depth is too deep.
+ // Just display the first few and last few instantiations.
+ uint i = 0;
+ for (TemplateInstance cur = this; cur; cur = cur.tinst)
{
- RootObject o = (*tiargs)[j];
- Type ta = isType(o);
- Expression ea = isExpression(o);
- Dsymbol sa = isDsymbol(o);
- Tuple va = isTuple(o);
- printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
+ if (i == max_shown / 2)
+ printFn(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
+
+ if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2)
+ printFn(cur.loc, format, cur.toChars());
+ ++i;
}
}
- return !err;
}
- /**********************************
- * Run semantic on the elements of tiargs.
- * Input:
- * sc
- * Returns:
- * false if one or more arguments have errors.
- * Note:
- * This function is reentrant against error occurrence. If returns false,
- * all elements of tiargs won't be modified.
+ /*************************************
+ * Lazily generate identifier for template instance.
+ * This is because 75% of the ident's are never needed.
*/
- extern (D) final bool semanticTiargs(Scope* sc)
+ override final Identifier getIdent()
{
- //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
- if (semantictiargsdone)
- return true;
- if (semanticTiargs(loc, sc, tiargs, 0))
- {
- // cache the result iff semantic analysis succeeded entirely
- semantictiargsdone = 1;
- return true;
- }
- return false;
+ if (!ident && inst && !errors)
+ ident = genIdent(tiargs); // need an identifier for name mangling purposes.
+ return ident;
}
- /**********************************
- * Find the TemplateDeclaration that matches this TemplateInstance best.
- *
+ /*************************************
+ * Compare proposed template instantiation with existing template instantiation.
+ * Note that this is not commutative because of the auto ref check.
* Params:
- * sc = the scope this TemplateInstance resides in
- * argumentList = function arguments in case of a template function
- *
+ * ti = existing template instantiation
* Returns:
- * `true` if a match was found, `false` otherwise
+ * true for match
*/
- extern (D) final bool findBestMatch(Scope* sc, ArgumentList argumentList)
+ final bool equalsx(TemplateInstance ti)
{
- if (havetempdecl)
- {
- TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
- assert(tempdecl);
- assert(tempdecl._scope);
- // Deduce tdtypes
- tdtypes.setDim(tempdecl.parameters.length);
- if (!matchWithInstance(sc, tempdecl, this, tdtypes, argumentList, 2))
- {
- .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars);
- return false;
- }
- // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
- return true;
- }
+ //printf("this = %p, ti = %p\n", this, ti);
+ assert(tdtypes.length == ti.tdtypes.length);
- static if (LOG)
+ // Nesting must match
+ if (enclosing != ti.enclosing)
{
- printf("TemplateInstance.findBestMatch()\n");
+ //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
+ return false;
}
+ //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
- const errs = global.errors;
- TemplateDeclaration td_last = null;
- Objects dedtypes;
+ if (!arrayObjectMatch(tdtypes, ti.tdtypes))
+ return false;
- /* Since there can be multiple TemplateDeclaration's with the same
- * name, look for the best match.
+ /* Template functions may have different instantiations based on
+ * "auto ref" parameters.
*/
- auto tovers = tempdecl.isOverloadSet();
- foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
- {
- TemplateDeclaration td_best;
- TemplateDeclaration td_ambig;
- MATCH m_best = MATCH.nomatch;
-
- Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
- overloadApply(dstart, (Dsymbol s)
- {
- auto td = s.isTemplateDeclaration();
- if (!td)
- return 0;
- if (td == td_best) // skip duplicates
- return 0;
-
- //printf("td = %s\n", td.toPrettyChars());
- // If more arguments than parameters,
- // then this is no match.
- if (td.parameters.length < tiargs.length)
- {
- if (!td.isVariadic())
- return 0;
- }
-
- dedtypes.setDim(td.parameters.length);
- dedtypes.zero();
- assert(td.semanticRun != PASS.initial);
-
- MATCH m = matchWithInstance(sc, td, this, dedtypes, argumentList, 0);
- //printf("matchWithInstance = %d\n", m);
- if (m == MATCH.nomatch) // no match at all
- return 0;
- if (m < m_best) goto Ltd_best;
- if (m > m_best) goto Ltd;
-
- // Disambiguate by picking the most specialized TemplateDeclaration
- {
- 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;
- }
+ auto fd = ti.toAlias().isFuncDeclaration();
+ if (!fd)
+ return true;
+ if (fd.errors)
+ return true;
- td_ambig = td;
- return 0;
-
- Ltd_best:
- // td_best is the best match so far
- td_ambig = null;
- return 0;
-
- Ltd:
- // td is the new best match
- td_ambig = null;
- td_best = td;
- m_best = m;
- tdtypes.setDim(dedtypes.length);
- memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.length * (void*).sizeof);
- return 0;
- });
-
- if (td_ambig)
- {
- .error(loc, "%s `%s.%s` matches more than one template declaration:",
- td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars());
- .errorSupplemental(td_best.loc, "`%s`\nand:", td_best.toChars());
- .errorSupplemental(td_ambig.loc, "`%s`", td_ambig.toChars());
- return false;
- }
- if (td_best)
- {
- if (!td_last)
- td_last = td_best;
- else if (td_last != td_best)
- {
- ScopeDsymbol.multiplyDefined(loc, td_last, td_best);
- return false;
- }
- }
- }
+ auto resolvedArgs = fd.type.isTypeFunction().resolveNamedArgs(
+ ArgumentList(this.fargs, this.fnames), null);
- if (td_last)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=7469
- * Normalize tiargs by using corresponding deduced
- * template value parameters and tuples for the correct mangling.
- *
- * By doing this before hasNestedArgs, CTFEable local variable will be
- * accepted as a value parameter. For example:
- *
- * void foo() {
- * struct S(int n) {} // non-global template
- * const int num = 1; // CTFEable local variable
- * S!num s; // S!1 is instantiated, not S!num
- * }
- */
- size_t dim = td_last.parameters.length - (td_last.isVariadic() ? 1 : 0);
- for (size_t i = 0; i < dim; i++)
- {
- if (tiargs.length <= i)
- tiargs.push(tdtypes[i]);
- assert(i < tiargs.length);
+ // resolvedArgs can be null when there's an error: fail_compilation/fail14669.d
+ // In that case, equalsx returns true to prevent endless template instantiations
+ // However, it can also mean the function was explicitly instantiated
+ // without function arguments: fail_compilation/fail14669
+ // Hence the following check:
+ if (this.fargs && !resolvedArgs)
+ return true;
- auto tvp = (*td_last.parameters)[i].isTemplateValueParameter();
- if (!tvp)
- continue;
- assert(tdtypes[i]);
- // tdtypes[i] is already normalized to the required type in matchArg
+ Expression[] args = resolvedArgs ? (*resolvedArgs)[] : [];
- (*tiargs)[i] = tdtypes[i];
- }
- if (td_last.isVariadic() && tiargs.length == dim && tdtypes[dim])
- {
- Tuple va = isTuple(tdtypes[dim]);
- assert(va);
- tiargs.pushSlice(va.objects[]);
- }
- }
- else if (errors && inst)
- {
- // instantiation was failed with error reporting
- assert(global.errors);
- return false;
- }
- else
+ auto fparameters = fd.getParameterList();
+ size_t nfparams = fparameters.length; // Num function parameters
+ for (size_t j = 0; j < nfparams; j++)
{
- auto tdecl = tempdecl.isTemplateDeclaration();
+ Parameter fparam = fparameters[j];
+ if (!(fparam.storageClass & STC.autoref) ) // if "auto ref"
+ continue;
- if (errs != global.errors)
- errorSupplemental(loc, "while looking for match for `%s`", toChars());
- else if (tdecl && !tdecl.overnext)
+ Expression farg = (j < args.length) ? args[j] : fparam.defaultArg;
+ // resolveNamedArgs strips trailing nulls / default params
+ // when it doesn't anymore, the ternary can be replaced with:
+ // assert(j < resolvedArgs.length);
+ if (!farg)
+ farg = fparam.defaultArg;
+ if (!farg)
+ return false;
+ if (farg.isLvalue())
{
- // Only one template, so we can give better error message
- const(char)* msg = "does not match template declaration";
- const(char)* tip;
- OutBuffer buf;
- HdrGenState hgs;
- hgs.skipConstraints = true;
- toCharsMaybeConstraints(tdecl, buf, hgs);
- const tmsg = buf.peekChars();
- const cmsg = tdecl.getConstraintEvalError(tip);
- if (cmsg)
- {
- .error(loc, "%s `%s` %s `%s`\n%s", kind, toPrettyChars, msg, tmsg, cmsg);
- if (tip)
- .tip(tip);
- }
- else
- {
- .error(loc, "%s `%s` %s `%s`", kind, toPrettyChars, msg, tmsg);
-
- if (tdecl.parameters.length == tiargs.length)
- {
- // https://issues.dlang.org/show_bug.cgi?id=7352
- // print additional information, e.g. `foo` is not a type
- foreach (i, param; *tdecl.parameters)
- {
- MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, dedtypes, null);
- auto arg = (*tiargs)[i];
- auto sym = arg.isDsymbol;
- auto exp = arg.isExpression;
-
- if (exp)
- exp = exp.optimize(WANTvalue);
-
- if (match == MATCH.nomatch &&
- ((sym && sym.isFuncDeclaration) ||
- (exp && exp.isVarExp)))
- {
- if (param.isTemplateTypeParameter)
- errorSupplemental(loc, "`%s` is not a type", arg.toChars);
- else if (auto tvp = param.isTemplateValueParameter)
- errorSupplemental(loc, "`%s` is not of a value of type `%s`",
- arg.toChars, tvp.valType.toChars);
-
- }
- }
- }
- }
+ if (!(fparam.storageClass & STC.ref_))
+ return false; // auto ref's don't match
}
else
{
- .error(loc, "%s `%s` does not match any template declaration", kind(), toPrettyChars());
- bool found;
- overloadApply(tempdecl, (s){
- if (!found)
- errorSupplemental(loc, "Candidates are:");
- found = true;
- errorSupplemental(s.loc, "%s", s.toChars());
- return 0;
- });
+ if (fparam.storageClass & STC.ref_)
+ return false; // auto ref's don't match
}
- return false;
}
+ return true;
+ }
- /* The best match is td_last
- */
- tempdecl = td_last;
+ extern (D) final size_t toHash()
+ {
+ if (!hash)
+ {
+ hash = cast(size_t)cast(void*)enclosing;
+ hash += arrayObjectHash(tdtypes);
+ hash += hash == 0;
+ }
+ return hash;
+ }
- static if (LOG)
+ /**********************************
+ * Run semantic on the elements of tiargs.
+ * Input:
+ * sc
+ * Returns:
+ * false if one or more arguments have errors.
+ * Note:
+ * This function is reentrant against error occurrence. If returns false,
+ * all elements of tiargs won't be modified.
+ */
+ extern (D) final bool semanticTiargs(Scope* sc)
+ {
+ //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
+ if (semantictiargsdone)
+ return true;
+ if (TemplateInstance_semanticTiargs(loc, sc, tiargs, 0))
{
- printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars());
+ // cache the result iff semantic analysis succeeded entirely
+ semantictiargsdone = 1;
+ return true;
}
- return (errs == global.errors);
+ return false;
}
/*****************************************
@@ -5121,108 +2081,15 @@ extern (C++) class TemplateInstance : ScopeDsymbol
L1:
//printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars());
nested |= 1;
- }
- }
- else if (va)
- {
- nested |= cast(int)hasNestedArgs(&va.objects, isstatic);
- }
- }
- //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
- return nested != 0;
- }
-
- /*****************************************
- * Append 'this' to the specific module members[]
- */
- extern (D) final Dsymbols* appendToModuleMember()
- {
- Module mi = minst; // instantiated . inserted module
-
- //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
- // toPrettyChars(),
- // enclosing ? enclosing.toPrettyChars() : null,
- // mi ? mi.toPrettyChars() : null);
- if (global.params.allInst || !mi || mi.isRoot())
- {
- /* If the instantiated module is speculative or root, insert to the
- * member of a root module. Then:
- * - semantic3 pass will get called on the instance members.
- * - codegen pass will get a selection chance to do/skip it (needsCodegen()).
- */
- static Dsymbol getStrictEnclosing(TemplateInstance ti)
- {
- do
- {
- if (ti.enclosing)
- return ti.enclosing;
- ti = ti.tempdecl.isInstantiated();
- } while (ti);
- return null;
- }
-
- Dsymbol enc = getStrictEnclosing(this);
- // insert target is made stable by using the module
- // where tempdecl is declared.
- mi = (enc ? enc : tempdecl).getModule();
- if (!mi.isRoot())
- {
- if (mi.importedFrom)
- {
- mi = mi.importedFrom;
- assert(mi.isRoot());
- }
- else
- {
- // This can happen when using the frontend as a library.
- // Append it to the non-root module.
- }
- }
- }
- else
- {
- /* If the instantiated module is non-root, insert to the member of the
- * non-root module. Then:
- * - semantic3 pass won't be called on the instance.
- * - codegen pass won't reach to the instance.
- * Unless it is re-appended to a root module later (with changed minst).
- */
- }
- //printf("\t-. mi = %s\n", mi.toPrettyChars());
-
- if (memberOf) // already appended to some module
- {
- assert(mi.isRoot(), "can only re-append to a root module");
- if (memberOf.isRoot())
- return null; // no need to move to another root module
- }
-
- Dsymbols* a = mi.members;
- a.push(this);
- memberOf = mi;
- if (mi.semanticRun >= PASS.semantic2done && mi.isRoot())
- Module.addDeferredSemantic2(this);
- if (mi.semanticRun >= PASS.semantic3done && mi.isRoot())
- Module.addDeferredSemantic3(this);
- return a;
- }
-
- /****************************************************
- * Declare parameters of template instance, initialize them with the
- * template instance arguments.
- */
- extern (D) final void declareParameters(Scope* sc)
- {
- TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
- assert(tempdecl);
-
- //printf("TemplateInstance.declareParameters()\n");
- foreach (i, o; tdtypes) // initializer for tp
- {
- TemplateParameter tp = (*tempdecl.parameters)[i];
- //printf("\ttdtypes[%d] = %p\n", i, o);
- declareParameter(tempdecl, sc, tp, o);
+ }
+ }
+ else if (va)
+ {
+ nested |= cast(int)hasNestedArgs(&va.objects, isstatic);
+ }
}
+ //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
+ return nested != 0;
}
/****************************************
@@ -5240,166 +2107,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
return Identifier.idPool(buf[]);
}
- extern (D) final void expandMembers(Scope* sc2)
- {
- members.foreachDsymbol( (s) { s.setScope (sc2); } );
-
- members.foreachDsymbol( (s) { s.importAll(sc2); } );
-
- if (!aliasdecl)
- {
- /* static if's are crucial to evaluating aliasdecl correctly. But
- * evaluating the if/else bodies may require aliasdecl.
- * So, evaluate the condition for static if's, but not their if/else bodies.
- * Then try to set aliasdecl.
- * Later do the if/else bodies.
- * https://issues.dlang.org/show_bug.cgi?id=23598
- * It might be better to do this by attaching a lambda to the StaticIfDeclaration
- * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic().
- */
- bool done;
- void staticIfDg(Dsymbol s)
- {
- if (done || aliasdecl)
- return;
- //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars());
- if (!s.isStaticIfDeclaration())
- {
- //s.dsymbolSemantic(sc2);
- done = true;
- return;
- }
- auto sid = s.isStaticIfDeclaration();
- sid.include(sc2);
- if (members.length)
- {
- Dsymbol sa;
- if (oneMembers(members, sa, tempdecl.ident) && sa)
- aliasdecl = sa;
- }
- done = true;
- }
-
- members.foreachDsymbol(&staticIfDg);
- }
-
- void symbolDg(Dsymbol s)
- {
- //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
- //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
- //if (enclosing)
- // s.parent = sc.parent;
- //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
- s.dsymbolSemantic(sc2);
- //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
- Module.runDeferredSemantic();
- }
-
- members.foreachDsymbol(&symbolDg);
- }
-
- extern (D) final void tryExpandMembers(Scope* sc2)
- {
- __gshared int nest;
- // extracted to a function to allow windows SEH to work without destructors in the same function
- //printf("%d\n", nest);
- if (++nest > global.recursionLimit)
- {
- global.gag = 0; // ensure error message gets printed
- .error(loc, "%s `%s` recursive expansion exceeded allowed nesting limit", kind, toPrettyChars);
- fatal();
- }
-
- expandMembers(sc2);
-
- nest--;
- }
-
- extern (D) final void trySemantic3(Scope* sc2)
- {
- // extracted to a function to allow windows SEH to work without destructors in the same function
- __gshared int nest;
- //printf("%d\n", nest);
- if (++nest > global.recursionLimit)
- {
- global.gag = 0; // ensure error message gets printed
- .error(loc, "%s `%s` recursive expansion exceeded allowed nesting limit", kind, toPrettyChars);
- fatal();
- }
-
- semantic3(this, sc2);
-
- --nest;
- }
-
override void accept(Visitor v)
{
v.visit(this);
}
}
-/**************************************
- * IsExpression can evaluate the specified type speculatively, and even if
- * it instantiates any symbols, they are normally unnecessary for the
- * final executable.
- * However, if those symbols leak to the actual code, compiler should remark
- * them as non-speculative to generate their code and link to the final executable.
- */
-void unSpeculative(Scope* sc, RootObject o)
-{
- if (!o)
- return;
-
- if (Tuple tup = isTuple(o))
- {
- foreach (obj; tup.objects)
- {
- unSpeculative(sc, obj);
- }
- return;
- }
-
- Dsymbol s = getDsymbol(o);
- if (!s)
- return;
-
- if (Declaration d = s.isDeclaration())
- {
- if (VarDeclaration vd = d.isVarDeclaration())
- o = vd.type;
- else if (AliasDeclaration ad = d.isAliasDeclaration())
- {
- o = ad.getType();
- if (!o)
- o = ad.toAlias();
- }
- else
- o = d.toAlias();
-
- s = getDsymbol(o);
- if (!s)
- return;
- }
-
- if (TemplateInstance ti = s.isTemplateInstance())
- {
- // If the instance is already non-speculative,
- // or it is leaked to the speculative scope.
- if (ti.minst !is null || sc.minst is null)
- return;
-
- // Remark as non-speculative instance.
- ti.minst = sc.minst;
- if (!ti.tinst)
- ti.tinst = sc.tinst;
-
- unSpeculative(sc, ti.tempdecl);
- }
-
- if (TemplateInstance ti = s.isInstantiated())
- unSpeculative(sc, ti);
-}
-
/**********************************
* Return true if e could be valid only as a template value parameter.
* Return false if it might be an alias or tuple.
@@ -5491,80 +2204,6 @@ extern (C++) final class TemplateMixin : TemplateInstance
return "mixin";
}
- extern (D) bool findTempDecl(Scope* sc)
- {
- // Follow qualifications to find the TemplateDeclaration
- if (!tempdecl)
- {
- Expression e;
- Type t;
- Dsymbol s;
- tqual.resolve(loc, sc, e, t, s);
- if (!s)
- {
- .error(loc, "%s `%s` is not defined", kind, toPrettyChars);
- return false;
- }
- s = s.toAlias();
- tempdecl = s.isTemplateDeclaration();
- OverloadSet os = s.isOverloadSet();
-
- /* If an OverloadSet, look for a unique member that is a template declaration
- */
- if (os)
- {
- Dsymbol ds = null;
- foreach (i, sym; os.a)
- {
- Dsymbol s2 = sym.isTemplateDeclaration();
- if (s2)
- {
- if (ds)
- {
- tempdecl = os;
- break;
- }
- ds = s2;
- }
- }
- }
- if (!tempdecl)
- {
- .error(loc, "%s `%s` - `%s` is a %s, not a template", kind, toPrettyChars, s.toChars(), s.kind());
- return false;
- }
- }
- assert(tempdecl);
-
- // Look for forward references
- auto tovers = tempdecl.isOverloadSet();
- foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
- {
- Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
- int r = overloadApply(dstart, (Dsymbol s)
- {
- auto td = s.isTemplateDeclaration();
- if (!td)
- return 0;
-
- if (td.semanticRun == PASS.initial)
- {
- if (td._scope)
- td.dsymbolSemantic(td._scope);
- else
- {
- semanticRun = PASS.initial;
- return 1;
- }
- }
- return 0;
- });
- if (r)
- return false;
- }
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -5629,466 +2268,6 @@ struct TemplateInstanceBox
}
}
-/*******************************************
- * Match to a particular TemplateParameter.
- * Input:
- * instLoc location that the template is instantiated.
- * tiargs[] actual arguments to template instance
- * i i'th argument
- * parameters[] template parameters
- * dedtypes[] deduced arguments to template instance
- * *psparam set to symbol declared and initialized to dedtypes[i]
- */
-MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam)
-{
- MATCH matchArgNoMatch()
- {
- if (psparam)
- *psparam = null;
- return MATCH.nomatch;
- }
-
- MATCH matchArgParameter()
- {
- RootObject oarg;
-
- if (i < tiargs.length)
- oarg = (*tiargs)[i];
- else
- {
- // Get default argument instead
- oarg = tp.defaultArg(instLoc, sc);
- if (!oarg)
- {
- assert(i < dedtypes.length);
- // It might have already been deduced
- oarg = dedtypes[i];
- if (!oarg)
- return matchArgNoMatch();
- }
- }
- return tp.matchArg(sc, oarg, i, parameters, dedtypes, psparam);
- }
-
- MATCH matchArgTuple(TemplateTupleParameter ttp)
- {
- /* The rest of the actual arguments (tiargs[]) form the match
- * for the variadic parameter.
- */
- assert(i + 1 == dedtypes.length); // must be the last one
- Tuple ovar;
-
- if (Tuple u = isTuple(dedtypes[i]))
- {
- // It has already been deduced
- ovar = u;
- }
- else if (i + 1 == tiargs.length && isTuple((*tiargs)[i]))
- ovar = isTuple((*tiargs)[i]);
- else
- {
- ovar = new Tuple();
- //printf("ovar = %p\n", ovar);
- if (i < tiargs.length)
- {
- //printf("i = %d, tiargs.length = %d\n", i, tiargs.length);
- ovar.objects.setDim(tiargs.length - i);
- foreach (j, ref obj; ovar.objects)
- obj = (*tiargs)[i + j];
- }
- }
- return ttp.matchArg(sc, ovar, i, parameters, dedtypes, psparam);
- }
-
- if (auto ttp = tp.isTemplateTupleParameter())
- return matchArgTuple(ttp);
-
- return matchArgParameter();
-}
-
-MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam)
-{
- MATCH matchArgNoMatch()
- {
- //printf("\tm = %d\n", MATCH.nomatch);
- if (psparam)
- *psparam = null;
- return MATCH.nomatch;
- }
-
- MATCH matchArgType(TemplateTypeParameter ttp)
- {
- //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
- MATCH m = MATCH.exact;
- Type ta = isType(oarg);
- if (!ta)
- {
- //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
- return matchArgNoMatch();
- }
- //printf("ta is %s\n", ta.toChars());
-
- if (ttp.specType)
- {
- if (!ta || ta == TemplateTypeParameter.tdummy)
- return matchArgNoMatch();
-
- //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
- MATCH m2 = deduceType(ta, sc, ttp.specType, *parameters, dedtypes);
- if (m2 == MATCH.nomatch)
- {
- //printf("\tfailed deduceType\n");
- return matchArgNoMatch();
- }
-
- if (m2 < m)
- m = m2;
- if (dedtypes[i])
- {
- Type t = cast(Type)dedtypes[i];
-
- if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357
- return matchArgNoMatch();
-
- /* This is a self-dependent parameter. For example:
- * template X(T : T*) {}
- * template X(T : S!T, alias S) {}
- */
- //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
- ta = t;
- }
- }
- else
- {
- if (dedtypes[i])
- {
- // Must match already deduced type
- Type t = cast(Type)dedtypes[i];
-
- if (!t.equals(ta))
- {
- //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
- return matchArgNoMatch();
- }
- }
- else
- {
- // So that matches with specializations are better
- m = MATCH.convert;
- }
- }
- dedtypes[i] = ta;
-
- if (psparam)
- *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta);
- //printf("\tm = %d\n", m);
- return ttp.dependent ? MATCH.exact : m;
- }
-
- MATCH matchArgValue(TemplateValueParameter tvp)
- {
- //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
- MATCH m = MATCH.exact;
-
- Expression ei = isExpression(oarg);
- Type vt;
-
- if (!ei && oarg)
- {
- Dsymbol si = isDsymbol(oarg);
- FuncDeclaration f = si ? si.isFuncDeclaration() : null;
- if (!f || !f.fbody || f.needThis())
- return matchArgNoMatch();
-
- ei = new VarExp(tvp.loc, f);
- ei = ei.expressionSemantic(sc);
-
- /* If a function is really property-like, and then
- * it's CTFEable, ei will be a literal expression.
- */
- const olderrors = global.startGagging();
- ei = resolveProperties(sc, ei);
- ei = ei.ctfeInterpret();
- if (global.endGagging(olderrors) || ei.op == EXP.error)
- return matchArgNoMatch();
-
- /* https://issues.dlang.org/show_bug.cgi?id=14520
- * A property-like function can match to both
- * TemplateAlias and ValueParameter. But for template overloads,
- * it should always prefer alias parameter to be consistent
- * template match result.
- *
- * template X(alias f) { enum X = 1; }
- * template X(int val) { enum X = 2; }
- * int f1() { return 0; } // CTFEable
- * int f2(); // body-less function is not CTFEable
- * enum x1 = X!f1; // should be 1
- * enum x2 = X!f2; // should be 1
- *
- * e.g. The x1 value must be same even if the f1 definition will be moved
- * into di while stripping body code.
- */
- m = MATCH.convert;
- }
-
- if (ei && ei.op == EXP.variable)
- {
- // Resolve const variables that we had skipped earlier
- ei = ei.ctfeInterpret();
- }
-
- //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
- vt = tvp.valType.typeSemantic(tvp.loc, sc);
- //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
- //printf("vt = %s\n", vt.toChars());
-
- if (ei.type)
- {
- MATCH m2 = ei.implicitConvTo(vt);
- //printf("m: %d\n", m);
- if (m2 < m)
- m = m2;
- if (m == MATCH.nomatch)
- return matchArgNoMatch();
- ei = ei.implicitCastTo(sc, vt);
- ei = ei.ctfeInterpret();
- }
-
- if (tvp.specValue)
- {
- if (ei is null || (cast(void*)ei.type in TemplateValueParameter.edummies &&
- TemplateValueParameter.edummies[cast(void*)ei.type] == ei))
- return matchArgNoMatch();
-
- Expression e = tvp.specValue;
-
- sc = sc.startCTFE();
- e = e.expressionSemantic(sc);
- e = resolveProperties(sc, e);
- sc = sc.endCTFE();
- e = e.implicitCastTo(sc, vt);
- e = e.ctfeInterpret();
-
- ei = ei.syntaxCopy();
- sc = sc.startCTFE();
- ei = ei.expressionSemantic(sc);
- sc = sc.endCTFE();
- ei = ei.implicitCastTo(sc, vt);
- ei = ei.ctfeInterpret();
- //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
- //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
- if (!ei.equals(e))
- return matchArgNoMatch();
- }
- else
- {
- if (dedtypes[i])
- {
- // Must match already deduced value
- Expression e = cast(Expression)dedtypes[i];
- if (!ei || !ei.equals(e))
- return matchArgNoMatch();
- }
- }
- dedtypes[i] = ei;
-
- if (psparam)
- {
- Initializer _init = new ExpInitializer(tvp.loc, ei);
- Declaration sparam = new VarDeclaration(tvp.loc, vt, tvp.ident, _init);
- sparam.storage_class = STC.manifest;
- *psparam = sparam;
- }
- return tvp.dependent ? MATCH.exact : m;
- }
-
- MATCH matchArgAlias(TemplateAliasParameter tap)
- {
- //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
- MATCH m = MATCH.exact;
- Type ta = isType(oarg);
- RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
- Expression ea = isExpression(oarg);
- if (ea)
- {
- if (auto te = ea.isThisExp())
- sa = te.var;
- else if (auto se = ea.isSuperExp())
- sa = se.var;
- else if (auto se = ea.isScopeExp())
- sa = se.sds;
- }
- if (sa)
- {
- if ((cast(Dsymbol)sa).isAggregateDeclaration())
- m = MATCH.convert;
-
- /* specType means the alias must be a declaration with a type
- * that matches specType.
- */
- if (tap.specType)
- {
- tap.specType = typeSemantic(tap.specType, tap.loc, sc);
- Declaration d = (cast(Dsymbol)sa).isDeclaration();
- if (!d)
- return matchArgNoMatch();
- if (!d.type.equals(tap.specType))
- return matchArgNoMatch();
- }
- }
- else
- {
- sa = oarg;
- if (ea)
- {
- if (tap.specType)
- {
- if (!ea.type.equals(tap.specType))
- return matchArgNoMatch();
- }
- }
- else if (ta && ta.ty == Tinstance && !tap.specAlias)
- {
- /* Specialized parameter should be preferred
- * match to the template type parameter.
- * template X(alias a) {} // a == this
- * template X(alias a : B!A, alias B, A...) {} // B!A => ta
- */
- }
- else if (sa && sa == TemplateTypeParameter.tdummy)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=2025
- * Aggregate Types should preferentially
- * match to the template type parameter.
- * template X(alias a) {} // a == this
- * template X(T) {} // T => sa
- */
- }
- else if (ta && ta.ty != Tident)
- {
- /* Match any type that's not a TypeIdentifier to alias parameters,
- * but prefer type parameter.
- * template X(alias a) { } // a == ta
- *
- * TypeIdentifiers are excluded because they might be not yet resolved aliases.
- */
- m = MATCH.convert;
- }
- else
- return matchArgNoMatch();
- }
-
- if (tap.specAlias)
- {
- if (sa == TemplateAliasParameter.sdummy)
- return matchArgNoMatch();
- // check specialization if template arg is a symbol
- Dsymbol sx = isDsymbol(sa);
- if (sa != tap.specAlias && sx)
- {
- Type talias = isType(tap.specAlias);
- if (!talias)
- return matchArgNoMatch();
-
- TemplateInstance ti = sx.isTemplateInstance();
- if (!ti && sx.parent)
- {
- ti = sx.parent.isTemplateInstance();
- if (ti && ti.name != sx.ident)
- return matchArgNoMatch();
- }
- if (!ti)
- return matchArgNoMatch();
-
- Type t = new TypeInstance(Loc.initial, ti);
- MATCH m2 = deduceType(t, sc, talias, *parameters, dedtypes);
- if (m2 == MATCH.nomatch)
- return matchArgNoMatch();
- }
- // check specialization if template arg is a type
- else if (ta)
- {
- if (Type tspec = isType(tap.specAlias))
- {
- MATCH m2 = ta.implicitConvTo(tspec);
- if (m2 == MATCH.nomatch)
- return matchArgNoMatch();
- }
- else
- {
- error(tap.loc, "template parameter specialization for a type must be a type and not `%s`",
- tap.specAlias.toChars());
- return matchArgNoMatch();
- }
- }
- }
- else if (dedtypes[i])
- {
- // Must match already deduced symbol
- RootObject si = dedtypes[i];
- if (!sa || si != sa)
- return matchArgNoMatch();
- }
- dedtypes[i] = sa;
-
- if (psparam)
- {
- if (Dsymbol s = isDsymbol(sa))
- {
- *psparam = new AliasDeclaration(tap.loc, tap.ident, s);
- }
- else if (Type t = isType(sa))
- {
- *psparam = new AliasDeclaration(tap.loc, tap.ident, t);
- }
- else
- {
- assert(ea);
-
- // Declare manifest constant
- Initializer _init = new ExpInitializer(tap.loc, ea);
- auto v = new VarDeclaration(tap.loc, null, tap.ident, _init);
- v.storage_class = STC.manifest;
- v.dsymbolSemantic(sc);
- *psparam = v;
- }
- }
- return tap.dependent ? MATCH.exact : m;
- }
-
- MATCH matchArgTuple(TemplateTupleParameter ttp)
- {
- //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
- Tuple ovar = isTuple(oarg);
- if (!ovar)
- return MATCH.nomatch;
- if (dedtypes[i])
- {
- Tuple tup = isTuple(dedtypes[i]);
- if (!tup)
- return MATCH.nomatch;
- if (!match(tup, ovar))
- return MATCH.nomatch;
- }
- dedtypes[i] = ovar;
-
- if (psparam)
- *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects);
- return ttp.dependent ? MATCH.exact : MATCH.convert;
- }
-
- if (auto ttp = tp.isTemplateTypeParameter())
- return matchArgType(ttp);
- if (auto tvp = tp.isTemplateValueParameter())
- return matchArgValue(tvp);
- if (auto tap = tp.isTemplateAliasParameter())
- return matchArgAlias(tap);
- if (auto ttp = tp.isTemplateTupleParameter())
- return matchArgTuple(ttp);
- assert(0);
-}
-
-
/***********************************************
* Collect and print statistics on template instantiations.
*/
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 3946c25c9f03..4cb7d1ac5dda 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -895,7 +895,7 @@ public:
{
// Omit redundant declarations - the slot was already
// reserved in the base class
- if (fd.isVirtual() && fd.isIntroducing())
+ if (fd.isVirtual() && fd.isIntroducing)
{
// Hide placeholders because they are not ABI compatible
writeProtection(AST.Visibility.Kind.private_);
@@ -1164,7 +1164,7 @@ public:
auto fd = ad.aliassym.isFuncDeclaration();
- if (fd && (fd.isGenerated() || fd.isDtorDeclaration()))
+ if (fd && (fd.isGenerated || fd.isDtorDeclaration()))
{
// Ignore. It's taken care of while visiting FuncDeclaration
return;
@@ -1197,7 +1197,7 @@ public:
// Print prefix of the base class if this function originates from a superclass
// because alias might be resolved through multiple classes, e.g.
// e.g. for alias visit = typeof(super).visit in the visitors
- if (!fd.isIntroducing())
+ if (!fd.isIntroducing)
printPrefix(ad.toParent().isClassDeclaration().baseClass);
else
printPrefix(pd);
diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d
index 26528e9f5178..1561ebb0b7c4 100644
--- a/gcc/d/dmd/dversion.d
+++ b/gcc/d/dmd/dversion.d
@@ -20,7 +20,6 @@ import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
import dmd.dsymbolsem;
-import dmd.globals;
import dmd.identifier;
import dmd.location;
import dmd.common.outbuffer;
diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h
index 6d5d3022a7fc..2b4d3b52d89e 100644
--- a/gcc/d/dmd/enum.h
+++ b/gcc/d/dmd/enum.h
@@ -59,7 +59,7 @@ public:
bool isSpecial() const;
- Symbol *sinit;
+ void *sinit;
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d
index 6d325e44c964..cdf8a61bd88a 100644
--- a/gcc/d/dmd/enumsem.d
+++ b/gcc/d/dmd/enumsem.d
@@ -240,7 +240,9 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
em.dsymbolSemantic(em._scope);
});
- if (global.params.useTypeInfo && Type.dtypeinfo && !ed.inNonRoot())
+ if (ed.errors)
+ ed.memtype = Type.terror; // avoid infinite recursion in toBaseType
+ else if (global.params.useTypeInfo && Type.dtypeinfo && !ed.inNonRoot())
semanticTypeInfo(sc, ed.memtype);
//printf("ed.defaultval = %lld\n", ed.defaultval);
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index a0c5472375e5..d3473f691d55 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -1557,7 +1557,7 @@ void escapeExp(Expression e, ref scope EscapeByResults er, int deref)
void visitThis(ThisExp e)
{
// Special case because `__this2` isn't `ref` internally
- if (deref == -1 && e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
+ if (deref == -1 && e.var && e.var.toParent2().isFuncDeclaration().hasDualContext)
{
escapeByValue(e, er);
return;
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index c29484d9e7bf..4d873ccecdc0 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -21,6 +21,7 @@ import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
+import dmd.ctfeexpr : isCtfeReferenceValid;
import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
@@ -31,6 +32,7 @@ import dmd.dsymbol;
import dmd.dtemplate;
import dmd.errors;
import dmd.errorsink;
+import dmd.expressionsem : getDsymbol;
import dmd.func;
import dmd.globals;
import dmd.hdrgen;
@@ -49,7 +51,7 @@ import dmd.root.string;
import dmd.root.utf;
import dmd.target;
import dmd.tokens;
-import dmd.typesem;
+import dmd.typesem : toHeadMutable, size, mutableOf, unSharedOf;
import dmd.visitor;
enum LOGSEMANTIC = false;
@@ -527,20 +529,6 @@ extern (C++) abstract class Expression : ASTNode
return false;
}
- /******************************
- * Take address of expression.
- */
- final Expression addressOf()
- {
- //printf("Expression::addressOf()\n");
- debug
- {
- assert(op == EXP.error || isLvalue());
- }
- Expression e = new AddrExp(loc, this, type.pointerTo());
- return e;
- }
-
/******************************
* If this is a reference, dereference it.
*/
@@ -1906,6 +1894,12 @@ extern (C++) final class ArrayLiteralExp : Expression
Expressions* elements;
+ Expression lowering;
+
+ // aaLiteral is set if this is an array of values of an AA literal
+ // only used during CTFE to show the original AA in error messages instead
+ AssocArrayLiteralExp aaLiteral;
+
extern (D) this(Loc loc, Type type, Expressions* elements) @safe
{
super(loc, EXP.arrayLiteral);
@@ -1917,8 +1911,7 @@ extern (C++) final class ArrayLiteralExp : Expression
{
super(loc, EXP.arrayLiteral);
this.type = type;
- elements = new Expressions();
- elements.push(e);
+ elements = new Expressions(e);
}
extern (D) this(Loc loc, Type type, Expression basis, Expressions* elements) @safe
@@ -2009,7 +2002,7 @@ extern (C++) final class ArrayLiteralExp : Expression
if (ch.op != EXP.int64)
return null;
if (sz == 1)
- buf.writeByte(cast(uint)ch.toInteger());
+ buf.writeByte(cast(ubyte)ch.toInteger());
else if (sz == 2)
buf.writeword(cast(uint)ch.toInteger());
else
@@ -2059,8 +2052,9 @@ extern (C++) final class AssocArrayLiteralExp : Expression
Expressions* keys;
Expressions* values;
- /// Lower to core.internal.newaa for static initializaton
- Expression lowering;
+
+ Expression lowering; // call to _d_assocarrayliteralTX()
+ Expression loweringCtfe; // result of interpreting lowering for static initializaton
extern (D) this(Loc loc, Expressions* keys, Expressions* values) @safe
{
@@ -2217,56 +2211,6 @@ extern (C++) final class StructLiteralExp : Expression
return exp;
}
- /**************************************
- * Gets expression at offset of type.
- * Returns NULL if not found.
- */
- extern (D) Expression getField(Type type, uint offset)
- {
- //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
- // /*toChars()*/"", type.toChars(), offset);
- Expression e = null;
- int i = getFieldIndex(type, offset);
-
- if (i != -1)
- {
- //printf("\ti = %d\n", i);
- if (i >= sd.nonHiddenFields())
- return null;
-
- assert(i < elements.length);
- e = (*elements)[i];
- if (e)
- {
- //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
-
- /* If type is a static array, and e is an initializer for that array,
- * then the field initializer should be an array literal of e.
- */
- auto tsa = type.isTypeSArray();
- if (tsa && e.type.castMod(0) != type.castMod(0))
- {
- const length = cast(size_t)tsa.dim.toInteger();
- auto z = new Expressions(length);
- foreach (ref q; *z)
- q = e.copy();
- e = new ArrayLiteralExp(loc, type, z);
- }
- else
- {
- e = e.copy();
- e.type = type;
- }
- if (useStaticInit && e.type.needsNested())
- if (auto se = e.isStructLiteralExp())
- {
- se.useStaticInit = true;
- }
- }
- }
- return e;
- }
-
/************************************
* Get index of field.
* Returns -1 if not found.
@@ -3312,6 +3256,7 @@ extern (C++) final class CallExp : UnaExp
bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
bool isUfcsRewrite; /// the first argument was pushed in here by a UFCS rewrite
VarDeclaration vthis2; // container for multi-context
+ Expression loweredFrom; // set if this is the result of a lowering
/// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
/// The fields are still separate for backwards compatibility
@@ -3486,6 +3431,13 @@ extern (C++) final class AddrExp : UnaExp
type = t;
}
+ override Optional!bool toBool()
+ {
+ if (isCtfeReferenceValid(e1))
+ return typeof(return)(true);
+ return UnaExp.toBool();
+ }
+
override void accept(Visitor v)
{
v.visit(this);
@@ -3574,6 +3526,8 @@ extern (C++) final class ComExp : UnaExp
*/
extern (C++) final class NotExp : UnaExp
{
+ Expression loweredFrom; // for lowering of `aa1 != aa2` to `!_d_aaEqual(aa1, aa2)`
+
extern (D) this(Loc loc, Expression e) @safe
{
super(loc, EXP.not, e);
@@ -3618,6 +3572,7 @@ extern (C++) final class CastExp : UnaExp
Type to; // type to cast to
ubyte mod = cast(ubyte)~0; // MODxxxxx
bool trusted; // assume cast is safe
+ Expression lowering;
extern (D) this(Loc loc, Expression e, Type t) @safe
{
@@ -3797,6 +3752,7 @@ extern (C++) final class ArrayExp : UnaExp
size_t currentDimension; // for opDollar
VarDeclaration lengthVar;
+ bool modifiable = false; // is this expected to be an lvalue in an AssignExp? propagate to IndexExp
extern (D) this(Loc loc, Expression e1, Expression index = null)
{
@@ -3994,6 +3950,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp
extern (C++) final class IndexExp : BinExp
{
VarDeclaration lengthVar;
+ Expression loweredFrom; // for associative array lowering to _d_aaGetY or _d_aaGetRvalueX
bool modifiable = false; // assume it is an rvalue
bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
@@ -4030,29 +3987,6 @@ extern (C++) final class IndexExp : BinExp
return true;
}
- extern (D) Expression markSettingAAElem()
- {
- if (e1.type.toBasetype().ty == Taarray)
- {
- Type t2b = e2.type.toBasetype();
- if (t2b.ty == Tarray && t2b.nextOf().isMutable())
- {
- error(loc, "associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
- return ErrorExp.get();
- }
- modifiable = true;
-
- if (auto ie = e1.isIndexExp())
- {
- Expression ex = ie.markSettingAAElem();
- if (ex.op == EXP.error)
- return ex;
- assert(ex == e1);
- }
- }
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4783,7 +4717,6 @@ extern (C++) final class RemoveExp : BinExp
extern (D) this(Loc loc, Expression e1, Expression e2)
{
super(loc, EXP.remove, e1, e2);
- type = Type.tbool;
}
override void accept(Visitor v)
@@ -4801,6 +4734,7 @@ extern (C++) final class RemoveExp : BinExp
*/
extern (C++) final class EqualExp : BinExp
{
+ Expression lowering;
extern (D) this(EXP op, Loc loc, Expression e1, Expression e2) @safe
{
super(loc, op, e1, e2);
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 6b4298b3308b..7c92ebe66c44 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -407,6 +407,8 @@ public:
d_bool onstack;
Expression *basis;
Expressions *elements;
+ Expression *lowering;
+ AssocArrayLiteralExp* aaLiteral; // set if this is an array of keys/values of an AA literal
static ArrayLiteralExp *create(Loc loc, Expressions *elements);
ArrayLiteralExp *syntaxCopy() override;
@@ -425,6 +427,7 @@ public:
Expressions *keys;
Expressions *values;
Expression* lowering;
+ Expression* loweringCtfe;
bool equals(const RootObject * const o) const override;
AssocArrayLiteralExp *syntaxCopy() override;
@@ -833,6 +836,7 @@ public:
d_bool ignoreAttributes; // don't enforce attributes (e.g. call @gc function in @nogc code)
d_bool isUfcsRewrite; // the first argument was pushed in here by a UFCS rewrite
VarDeclaration *vthis2; // container for multi-context
+ Expression* loweredFrom; // set if this is the result of a lowering
static CallExp *create(Loc loc, Expression *e, Expressions *exps);
static CallExp *create(Loc loc, Expression *e);
@@ -848,6 +852,7 @@ public:
class AddrExp final : public UnaExp
{
public:
+ Optional<bool> toBool() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -880,6 +885,7 @@ public:
class NotExp final : public UnaExp
{
public:
+ Expression* loweredFrom; // for lowering of `aa1 != aa2` to `!_d_aaEqual(aa1, aa2)`
void accept(Visitor *v) override { v->visit(this); }
};
@@ -897,6 +903,7 @@ public:
Type *to; // type to cast to
unsigned char mod; // MODxxxxx
d_bool trusted; // assume cast is safe
+ Expression* lowering;
CastExp *syntaxCopy() override;
bool isLvalue() override;
@@ -986,6 +993,7 @@ public:
Expressions *arguments; // Array of Expression's
size_t currentDimension; // for opDollar
VarDeclaration *lengthVar;
+ d_bool modifiable;
ArrayExp *syntaxCopy() override;
bool isLvalue() override;
@@ -1016,6 +1024,7 @@ class IndexExp final : public BinExp
{
public:
VarDeclaration *lengthVar;
+ Expression* loweredFrom; // for associative array lowering to _d_aaGetY or _d_aaGetRvalueX
d_bool modifiable;
d_bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
@@ -1279,6 +1288,8 @@ public:
class EqualExp final : public BinExp
{
public:
+ Expression* lowering;
+
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 2576d7c0d056..68fe3dca41c0 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -1,4 +1,4 @@
-/**
+/***
* Semantic analysis of expressions.
*
* Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
@@ -29,6 +29,7 @@ import dmd.cond;
import dmd.ctorflow;
import dmd.dscope;
import dmd.dsymbol;
+import dmd.dsymbolsem;
import dmd.declaration;
import dmd.dclass;
import dmd.dcast;
@@ -39,7 +40,7 @@ import dmd.dimport;
import dmd.dinterpret;
import dmd.dmodule;
import dmd.dstruct;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : findTempDecl;
import dmd.dtemplate;
import dmd.errors;
import dmd.errorsink;
@@ -82,7 +83,7 @@ import dmd.semantic3;
import dmd.sideeffect;
import dmd.safe;
import dmd.target;
-import dmd.templatesem : matchWithInstance;
+import dmd.templatesem : matchWithInstance, deduceType, matchArg, updateTempDecl;
import dmd.tokens;
import dmd.traits;
import dmd.typesem;
@@ -202,6 +203,54 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps,
return false;
}
+/***************************************
+ * Verifies whether the struct declaration has a
+ * constructor that is not a copy constructor.
+ * Optionally, it can check whether the struct
+ * declaration has a regular constructor, that
+ * is not disabled.
+ *
+ * Params:
+ * sd = struct declaration
+ * ignoreDisabled = true to ignore disabled constructors
+ * Returns:
+ * true, if the struct has a regular (optionally,
+ * not disabled) constructor, false otherwise.
+ */
+bool hasRegularCtor(StructDeclaration sd, bool ignoreDisabled)
+{
+ if (!sd.ctor)
+ return false;
+
+ bool result;
+ overloadApply(sd.ctor, (Dsymbol s)
+ {
+ if (auto td = s.isTemplateDeclaration())
+ {
+ if (ignoreDisabled && td.onemember)
+ {
+ if (auto ctorDecl = td.onemember.isCtorDeclaration())
+ {
+ if (ctorDecl.storage_class & STC.disable)
+ return 0;
+ }
+ }
+ result = true;
+ return 1;
+ }
+ if (auto ctorDecl = s.isCtorDeclaration())
+ {
+ if (!ctorDecl.isCpCtor && !ctorDecl.isMoveCtor && (!ignoreDisabled || !(ctorDecl.storage_class & STC.disable)))
+ {
+ result = true;
+ return 1;
+ }
+ }
+ return 0;
+ });
+ return result;
+}
+
/*****************************************
* Determine if `this` is available by walking up the enclosing
* scopes until a function is found.
@@ -228,7 +277,7 @@ FuncDeclaration hasThis(Scope* sc)
{
return null;
}
- if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
+ if (!fd.isNested() || fd.isThis() || (fd.hasDualContext && fd.isMember2()))
break;
Dsymbol parent = fd.parent;
@@ -245,7 +294,7 @@ FuncDeclaration hasThis(Scope* sc)
fd = parent.isFuncDeclaration();
}
- if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
+ if (!fd.isThis() && !(fd.hasDualContext && fd.isMember2()))
{
return null;
}
@@ -410,54 +459,6 @@ extern (D) Expression incompatibleTypes(BinExp e, Scope* sc = null)
return ErrorExp.get();
}
-private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
-{
- BinExp be = exp;
-
- auto ie = be.e1.isIndexExp();
- if (!ie)
- return be;
- if (ie.e1.type.toBasetype().ty != Taarray)
- return be;
-
- /* Fix evaluation order of setting AA element
- * https://issues.dlang.org/show_bug.cgi?id=3825
- * Rewrite:
- * aa[k1][k2][k3] op= val;
- * as:
- * auto ref __aatmp = aa;
- * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
- * auto ref __aaval = val;
- * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
- */
-
- Expression e0;
- while (1)
- {
- Expression de;
- ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
- e0 = Expression.combine(de, e0);
-
- auto ie1 = ie.e1.isIndexExp();
- if (!ie1 ||
- ie1.e1.type.toBasetype().ty != Taarray)
- {
- break;
- }
- ie = ie1;
- }
- assert(ie.e1.type.toBasetype().ty == Taarray);
-
- Expression de;
- ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
- e0 = Expression.combine(de, e0);
-
- be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
-
- //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
- return Expression.combine(e0, be);
-}
-
private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
{
auto e1 = binExp.e1;
@@ -612,20 +613,15 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
// https://issues.dlang.org/show_bug.cgi?id=12585
// Extract the side effect part if ue.e1 is comma.
- if (sc.ctfe ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
- {
- /* Even if opDollar is needed, 'e1' should be evaluate only once. So
- * Rewrite:
- * e1.opIndex( ... use of $ ... )
- * e1.opSlice( ... use of $ ... )
- * as:
- * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
- * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
- */
- e1 = extractSideEffect(sc, "__dop", e0, e1, false);
- assert(e1.isVarExp());
- e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression
- }
+ /* Even if opDollar is needed, 'e1' should be evaluate only once. So
+ * Rewrite:
+ * e1.opIndex( ... use of $ ... )
+ * e1.opSlice( ... use of $ ... )
+ * as:
+ * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
+ * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
+ */
+ e1 = extractSideEffect(sc, "__dop", e0, e1, false);
ue.e1 = e1;
return e0;
}
@@ -663,6 +659,72 @@ TupleDeclaration isAliasThisTuple(Expression e)
}
}
+/******************************
+ * Take address of expression.
+ */
+Expression addressOf(Expression e)
+{
+ //printf("Expression::addressOf() %s\n", e.toChars());
+ debug
+ {
+ assert(e.op == EXP.error || e.isLvalue());
+ }
+ return new AddrExp(e.loc, e, e.type.pointerTo());
+}
+
+/**************************************
+ * Gets expression at offset of type.
+ * Returns NULL if not found.
+ */
+Expression getField(StructLiteralExp sle, Type type, uint offset)
+{
+ //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
+ // /*toChars()*/"", type.toChars(), offset);
+ Expression e2 = null;
+ const int i = sle.getFieldIndex(type, offset);
+
+ if (i == -1)
+ return null;
+
+ //printf("\ti = %d\n", i);
+ if (i >= sle.sd.nonHiddenFields())
+ return null;
+
+ assert(i < sle.elements.length);
+ e2 = (*sle.elements)[i];
+ if (!e2)
+ return null;
+
+ //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
+
+ /* If type is a static array, and e is an initializer for that array,
+ * then the field initializer should be an array literal of e.
+ */
+ auto tsa = type.isTypeSArray();
+ if (tsa && e2.type.castMod(0) != type.castMod(0))
+ {
+ const length = cast(size_t)tsa.dim.toInteger();
+ auto z = new Expressions(length);
+ foreach (ref q; *z)
+ q = e2.copy();
+ e2 = new ArrayLiteralExp(sle.loc, type, z);
+ }
+ else
+ {
+ e2 = e2.copy();
+ e2.type = type;
+ }
+ if (sle.useStaticInit && e2.type.needsNested())
+ if (auto se = e2.isStructLiteralExp())
+ {
+ se.useStaticInit = true;
+ }
+
+ return e2;
+}
+
+
+
/**************************************
* Runs semantic on ae.arguments. Declares temporary variables
* if '$' was used.
@@ -712,14 +774,11 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, out Expression pe0)
if (auto ie = e.isIntervalExp())
{
- auto tiargs = new Objects();
Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
edim = edim.expressionSemantic(sc);
- tiargs.push(edim);
+ auto tiargs = new Objects(edim);
- auto fargs = new Expressions(2);
- (*fargs)[0] = ie.lwr;
- (*fargs)[1] = ie.upr;
+ auto fargs = new Expressions(ie.lwr, ie.upr);
const xerrors = global.startGagging();
sc = sc.push();
@@ -1246,7 +1305,8 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
semanticTypeInfo(sc, taa.index);
- return new RemoveExp(loc, eleft, key);
+ e = new RemoveExp(loc, eleft, key);
+ return e.expressionSemantic(sc);
}
}
else
@@ -1817,7 +1877,7 @@ L1:
if (e1.op == EXP.this_)
{
FuncDeclaration f = hasThis(sc);
- if (f && f.hasDualContext())
+ if (f && f.hasDualContext)
{
if (f.followInstantiationContext(ad))
{
@@ -2000,7 +2060,7 @@ void checkOverriddenDtor(FuncDeclaration f, Scope* sc, Loc loc,
scope bool function(DtorDeclaration) check, const string checkName)
{
auto dd = f.isDtorDeclaration();
- if (!dd || !dd.isGenerated())
+ if (!dd || !dd.isGenerated)
return;
// DtorDeclaration without parents should fail at an earlier stage
@@ -2017,7 +2077,7 @@ void checkOverriddenDtor(FuncDeclaration f, Scope* sc, Loc loc,
}
dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
- dd.isGenerated() ? "generated " : "".ptr,
+ dd.isGenerated ? "generated " : "".ptr,
ad.toChars,
cast(int) checkName.length, checkName.ptr);
@@ -2048,7 +2108,7 @@ void checkOverriddenDtor(FuncDeclaration f, Scope* sc, Loc loc,
{
field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
- if (fieldSd.dtor.isGenerated())
+ if (fieldSd.dtor.isGenerated)
fieldSd.dtor.checkOverriddenDtor(sc, loc, check, checkName);
else
fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
@@ -2351,7 +2411,9 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
// so don't print anything to avoid double error messages.
if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
|| f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
- || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
+ || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT
+ || f.ident == Id._d_assocarrayliteralTX || f.ident == Id._d_arrayliteralTX
+ || f.ident == Id._d_aaGetY))
{
error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
@@ -2373,7 +2435,7 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
* t = struct type, or static array of struct type to check
* loc = error message location
* sc = scope in which attributes are checked
- * Returns: true if there's an error
+ * Returns: true if there is an error
*/
private bool checkPostblit(Type t, ref Loc loc, Scope* sc)
{
@@ -2441,8 +2503,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
return ErrorExp.get();
e2 = resolveProperties(sc, e2);
- Expressions* a = new Expressions();
- a.push(e2);
+ Expressions* a = new Expressions(e2);
for (size_t i = 0; i < os.a.length; i++)
{
@@ -2561,8 +2622,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
return ErrorExp.get();
e2 = resolveProperties(sc, e2);
- Expressions* a = new Expressions();
- a.push(e2);
+ Expressions* a = new Expressions(e2);
FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet);
if (fd && fd.type)
@@ -3032,7 +3092,9 @@ private bool functionParameters(Loc loc, Scope* sc,
*/
if (fd && fd.inlining == PINLINE.always)
{
- if (sc._module)
+ if (sc.minst)
+ sc.minst.hasAlwaysInlines = true;
+ else if (sc._module)
sc._module.hasAlwaysInlines = true;
if (sc.func)
sc.func.hasAlwaysInlines = true;
@@ -3754,8 +3816,8 @@ private bool functionParameters(Loc loc, Scope* sc,
int offset;
if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
{
- const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
- const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
+ const(char)* s1 = tret.isNaked ? " mutable" : tret.modToChars();
+ const(char)* s2 = tthis.isNaked ? " mutable" : tthis.modToChars();
.error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
err = true;
}
@@ -3807,6 +3869,326 @@ Package resolveIsPackage(Dsymbol sym)
return pkg;
}
+/**
+ * Performs the lowering of a CastExp to a call to `.object._d_cast`,
+ * populating the `lowering` field of the CastExp.
+ * This is only done for casts between classes/interfaces.
+ *
+ * Params:
+ * cex = the CastExp to lower
+ * sc = the current scope
+ */
+private void lowerCastExp(CastExp cex, Scope* sc)
+{
+ Type t1b = cex.e1.type.toBasetype();
+ Type tob = cex.to.toBasetype();
+
+ if (t1b.ty != Tclass || tob.ty != Tclass)
+ return;
+
+ ClassDeclaration cdfrom = t1b.isClassHandle();
+ ClassDeclaration cdto = tob.isClassHandle();
+
+ int offset;
+ if ((cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME)
+ || cdfrom.classKind == ClassKind.cpp || cdto.classKind == ClassKind.cpp)
+ return;
+
+ Identifier hook = Id._d_cast;
+ if (!verifyHookExist(cex.loc, *sc, hook, "d_cast", Id.object))
+ return;
+
+ // Lower to .object._d_cast!(To)(exp.e1)
+ Expression lowering = new IdentifierExp(cex.loc, Id.empty);
+ lowering = new DotIdExp(cex.loc, lowering, Id.object);
+
+ // Unqualify the type being casted to, avoiding multiple instantiations
+ auto unqual_tob = tob.unqualify(MODFlags.wild | MODFlags.const_ |
+ MODFlags.immutable_ | MODFlags.shared_);
+ auto tiargs = new Objects(unqual_tob);
+ lowering = new DotTemplateInstanceExp(cex.loc, lowering, hook, tiargs);
+
+ // Unqualify the type being casted from to avoid multiple instantiations
+ auto unqual_t1b = t1b.unqualify(MODFlags.wild | MODFlags.const_ |
+ MODFlags.immutable_ | MODFlags.shared_);
+ Expression e1c = cex.e1.copy();
+ e1c.type = unqual_t1b;
+ auto arguments = new Expressions(e1c);
+
+ lowering = new CallExp(cex.loc, lowering, arguments);
+
+ cex.lowering = lowering.expressionSemantic(sc);
+}
+
+/**
+ * Visitor to check if a type is suitable for comparison using `memcmp`.
+ * Currently used when lowering `EqualExp`.
+ */
+private extern(C++) final class IsMemcmpableVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+ public:
+ bool result = false;
+
+ override void visit(Type t)
+ {
+ result = t.ty == Tvoid || (t.isScalar() && !t.isFloating());
+ }
+
+ override void visit(TypeStruct ts)
+ {
+ result = false;
+
+ if (ts.sym.hasIdentityEquals)
+ return; // has custom opEquals
+
+ if (!ts.sym.members)
+ {
+ result = true;
+ return;
+ }
+
+ /* We recursively check all variable declaration within the struct.
+ * The recursiveness is needed to handle cases like this:
+ * struct Test {
+ * nothrow:
+ * int[] contents;
+ * }
+ * Here a `StorageClassDeclaration` symbol will be created, which wraps the variable declaration.
+ */
+ static bool visitAllMembers(Dsymbols* members, TypeStruct root, IsMemcmpableVisitor v)
+ {
+ if (members is null)
+ return true;
+
+ foreach (m; *members)
+ {
+ if (auto vd = m.isVarDeclaration())
+ {
+ if (vd.type is null)
+ continue;
+
+ auto tbvd = vd.type.toBasetype();
+ if (tbvd !is root)
+ tbvd.accept(v);
+
+ if (!v.result)
+ return false;
+ }
+ else if (auto ad = m.isAttribDeclaration())
+ {
+ if(!visitAllMembers(ad.decl, root, v))
+ return false;
+ }
+ }
+ return true;
+ }
+ result = visitAllMembers(ts.sym.members, ts, this);
+ }
+
+ override void visit(TypeSArray tsa)
+ {
+ tsa.nextOf().toBasetype().accept(this);
+ }
+}
+
+/*********************************************
+ * In the current function 'sc.func', we are calling 'fd'.
+ * 1. Check to see if the current function can call 'fd' , issue error if not.
+ * 2. If the current function is not the parent of 'fd' , then add
+ * the current function to the list of siblings of 'fd' .
+ * 3. If the current function is a literal, and it's accessing an uplevel scope,
+ * then mark it as a delegate.
+ * Returns true if error occurs.
+ */
+private bool checkNestedFuncReference(FuncDeclaration fd, Scope* sc, Loc loc)
+{
+ //printf("FuncDeclaration::checkNestedFuncReference() %s\n", toPrettyChars());
+ if (auto fld = fd.isFuncLiteralDeclaration())
+ {
+ if (fld.tok == TOK.reserved)
+ {
+ fld.tok = TOK.function_;
+ fld.vthis = null;
+ }
+ }
+ if (!fd.parent || fd.parent == sc.parent)
+ return false;
+ if (fd.ident == Id.require || fd.ident == Id.ensure)
+ return false;
+ if (!fd.isThis() && !fd.isNested())
+ return false;
+ // The current function
+ FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
+ if (!fdthis)
+ return false; // out of function scope
+ Dsymbol p = fd.toParentLocal();
+ Dsymbol p2 = fd.toParent2();
+ // Function literals from fdthis to p must be delegates
+ ensureStaticLinkTo(fdthis, p);
+ if (p != p2)
+ ensureStaticLinkTo(fdthis, p2);
+ if (!fd.isNested())
+ return false;
+
+ // The function that this function is in
+ bool checkEnclosing(FuncDeclaration fdv)
+ {
+ if (!fdv)
+ return false;
+ if (fdv == fdthis)
+ return false;
+ //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
+ //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
+ //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
+ // Add this function to the list of those which called us
+ if (fdthis != fd)
+ {
+ bool found = false;
+ for (size_t i = 0; i < fd.siblingCallers.length; ++i)
+ {
+ if (fd.siblingCallers[i] == fdthis)
+ found = true;
+ }
+ if (!found)
+ {
+ //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
+ if (!sc.intypeof && !sc.traitsCompiles)
+ {
+ fd.siblingCallers.push(fdthis);
+ fd.computedEscapingSiblings = false;
+ }
+ }
+ }
+ const lv = fdthis.getLevelAndCheck(loc, sc, fdv, fd);
+ if (lv == fd.LevelError)
+ return true; // error
+ if (lv == -1)
+ return false; // downlevel call
+ if (lv == 0)
+ return false; // same level call
+ return false; // Uplevel call
+ }
+ if (checkEnclosing(p.isFuncDeclaration()))
+ return true;
+ if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
+ return true;
+ return false;
+}
+
+Expression lowerArrayLiteral(ArrayLiteralExp ale, Scope* sc)
+{
+ const dim = ale.elements ? ale.elements.length : 0;
+
+ Identifier hook = global.params.tracegc ? Id._d_arrayliteralTXTrace : Id._d_arrayliteralTX;
+ if (!verifyHookExist(ale.loc, *sc, hook, "creating array literals"))
+ return null;
+
+ Expression lowering = new IdentifierExp(ale.loc, Id.empty);
+ lowering = new DotIdExp(ale.loc, lowering, Id.object);
+ // Remove `inout`, `const`, `immutable` and `shared` to reduce template instances
+ auto t = ale.type.nextOf().unqualify(MODFlags.wild | MODFlags.const_ | MODFlags.immutable_ | MODFlags.shared_);
+ auto tiargs = new Objects(t);
+ lowering = new DotTemplateInstanceExp(ale.loc, lowering, hook, tiargs);
+
+ auto arguments = new Expressions(new IntegerExp(dim));
+ lowering = new CallExp(ale.loc, lowering, arguments);
+ ale.lowering = lowering.expressionSemantic(sc);
+
+ return ale.lowering;
+}
+
+/***********************************
+ * If oarg represents a Dsymbol, return that Dsymbol
+ * Params:
+ * oarg = argument to check
+ * Returns:
+ * Dsymbol if a symbol, null if not
+ */
+Dsymbol getDsymbol(RootObject oarg)
+{
+ //printf("getDsymbol()\n");
+ //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
+ if (auto ea = isExpression(oarg))
+ {
+ // Try to convert Expression to symbol
+ if (auto ve = ea.isVarExp())
+ return ve.var;
+ if (auto fe = ea.isFuncExp())
+ return fe.td ? fe.td : fe.fd;
+ if (auto te = ea.isTemplateExp())
+ return te.td;
+ if (auto te = ea.isScopeExp())
+ return te.sds;
+ return null;
+ }
+ // Try to convert Type to symbol
+ if (auto ta = isType(oarg))
+ return ta.toDsymbol(null);
+ return isDsymbol(oarg); // if already a symbol
+}
+
+/**************************************
+ * IsExpression can evaluate the specified type speculatively, and even if
+ * it instantiates any symbols, they are normally unnecessary for the
+ * final executable.
+ * However, if those symbols leak to the actual code, compiler should remark
+ * them as non-speculative to generate their code and link to the final executable.
+ */
+private void unSpeculative(Scope* sc, RootObject o)
+{
+ if (!o)
+ return;
+
+ if (Tuple tup = isTuple(o))
+ {
+ foreach (obj; tup.objects)
+ {
+ unSpeculative(sc, obj);
+ }
+ return;
+ }
+
+ Dsymbol s = getDsymbol(o);
+ if (!s)
+ return;
+
+ if (Declaration d = s.isDeclaration())
+ {
+ if (VarDeclaration vd = d.isVarDeclaration())
+ o = vd.type;
+ else if (AliasDeclaration ad = d.isAliasDeclaration())
+ {
+ o = ad.getType();
+ if (!o)
+ o = ad.toAlias();
+ }
+ else
+ o = d.toAlias();
+
+ s = getDsymbol(o);
+ if (!s)
+ return;
+ }
+
+ if (TemplateInstance ti = s.isTemplateInstance())
+ {
+ // If the instance is already non-speculative,
+ // or it is leaked to the speculative scope.
+ if (ti.minst !is null || sc.minst is null)
+ return;
+
+ // Remark as non-speculative instance.
+ ti.minst = sc.minst;
+ if (!ti.tinst)
+ ti.tinst = sc.tinst;
+
+ unSpeculative(sc, ti.tempdecl);
+ }
+
+ if (TemplateInstance ti = s.isInstantiated())
+ unSpeculative(sc, ti);
+}
private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
@@ -3921,6 +4303,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
}
+ if (exp.rvalue)
+ {
+ if (sc.setUnsafe(false, exp.loc, "moving variable `%s` with `__rvalue`", exp))
+ {
+ setError();
+ }
+ }
scope (exit) result.rvalue = exp.rvalue;
Dsymbol scopesym;
@@ -4318,8 +4707,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
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"));
+ auto moduleNameArgs = new Objects(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());
@@ -4329,21 +4717,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
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"));
+ auto moduleNameArgs = new Objects(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);
+ auto tiargs = new Objects(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));
+ auto arguments = new Expressions(makeNonTemplateItem(Id.InterpolationHeader));
foreach (idx, str; e.interpolatedSet.parts)
{
@@ -4355,8 +4741,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
{
arguments.push(makeTemplateItem(Id.InterpolatedExpression, str));
- Expressions* mix = new Expressions();
- mix.push(new StringExp(e.loc, str));
+ Expressions* mix = new Expressions(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));
}
@@ -4557,6 +4942,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
}
+ void tryLowerAALiteral(AssocArrayLiteralExp aaExp)
+ {
+ auto hookId = Id._d_assocarrayliteralTX;
+ if (!verifyHookExist(aaExp.loc, *sc, hookId, "initializing associative arrays", Id.object))
+ return;
+
+ auto aaType = aaExp.type.toBasetype().isTypeAArray();
+ assert(aaType);
+ Expression hookFunc = new IdentifierExp(aaExp.loc, Id.empty);
+ hookFunc = new DotIdExp(aaExp.loc, hookFunc, Id.object);
+ auto keytype = aaType.index.substWildTo(MODFlags.const_);
+ auto valtype = aaType.nextOf().substWildTo(MODFlags.const_);
+ auto tiargs = new Objects(keytype, valtype);
+ hookFunc = new DotTemplateInstanceExp(aaExp.loc, hookFunc, hookId, tiargs);
+ auto ale1 = new ArrayLiteralExp(aaExp.loc, keytype.arrayOf(), aaExp.keys);
+ auto ale2 = new ArrayLiteralExp(aaExp.loc, valtype.arrayOf(), aaExp.values);
+ lowerArrayLiteral(ale1, sc);
+ lowerArrayLiteral(ale2, sc);
+ auto arguments = new Expressions(ale1, ale2);
+
+ Expression loweredExp = new CallExp(aaExp.loc, hookFunc, arguments);
+ loweredExp = loweredExp.expressionSemantic(sc);
+ loweredExp = resolveProperties(sc, loweredExp);
+ aaExp.lowering = loweredExp;
+
+ semanticTypeInfo(sc, loweredExp.type);
+ }
+
override void visit(AssocArrayLiteralExp e)
{
static if (LOGSEMANTIC)
@@ -4567,6 +4980,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
// already done, but we might have missed generating type info
semanticTypeInfo(sc, e.type);
+ if (!e.lowering)
+ tryLowerAALiteral(e);
result = e;
return;
}
@@ -4593,6 +5008,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e.type = new TypeAArray(tvalue, tkey);
e.type = e.type.typeSemantic(e.loc, sc);
+ tryLowerAALiteral(e);
semanticTypeInfo(sc, e.type);
if (checkAssocArrayLiteralEscape(*sc, e, false))
@@ -4866,14 +5282,45 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
Expression id = new IdentifierExp(ne.loc, Id.empty);
id = new DotIdExp(ne.loc, id, Id.object);
- auto tiargs = new Objects();
/*
* Remove `inout`, `const`, `immutable` and `shared` to reduce the
* number of generated `_d_newitemT` instances.
*/
auto t = ne.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
MODFlags.immutable_ | MODFlags.shared_);
- tiargs.push(t);
+ auto tiargs = new Objects(t);
+ id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs);
+
+ auto arguments = new Expressions();
+ id = new CallExp(ne.loc, id, arguments);
+
+ ne.lowering = id.expressionSemantic(sc);
+ }
+
+ /**
+ * Sets the `lowering` field of a `NewExp` to a call to `_d_newAA` unless
+ * compiling with `-betterC` or within `__traits(compiles)`.
+ *
+ * Params:
+ * ne = the `NewExp` to lower
+ */
+ private void tryLowerToNewAA(NewExp ne)
+ {
+ if (!global.params.useGC || !sc.needsCodegen())
+ return;
+
+ Identifier hook = Id._d_aaNew;
+ if (!verifyHookExist(ne.loc, *sc, hook, "new AA"))
+ return;
+
+ /* Lower the memory allocation and initialization of `new V[K]` to
+ * `_d_newAA!(V[K])()`.
+ */
+ Expression id = new IdentifierExp(ne.loc, Id.empty);
+ id = new DotIdExp(ne.loc, id, Id.object);
+ auto taa = ne.type.isTypeAArray();
+ assert(taa);
+ auto tiargs = new Objects(taa.index, taa.next);
id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs);
auto arguments = new Expressions();
@@ -4907,7 +5354,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
return setError();
}
- if (!exp.placement.type.isNaked())
+ if (!exp.placement.type.isNaked)
{
error(p.loc, "PlacementExpression `%s` of type `%s` be unshared and mutable", p.toChars(), toChars(p.type));
return setError();
@@ -4977,8 +5424,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
{
// --> new T[](edim)
- exp.arguments = new Expressions();
- exp.arguments.push(edim);
+ exp.arguments = new Expressions(edim);
exp.type = exp.type.arrayOf();
}
}
@@ -5226,8 +5672,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression id = new IdentifierExp(exp.loc, Id.empty);
id = new DotIdExp(exp.loc, id, Id.object);
- auto tiargs = new Objects();
- tiargs.push(exp.newtype);
+ auto tiargs = new Objects(exp.newtype);
id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
@@ -5252,9 +5697,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression id = new IdentifierExp(exp.loc, Id.empty);
id = new DotIdExp(exp.loc, id, Id.object);
- auto tiargs = new Objects();
auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout`
- tiargs.push(t);
+ auto tiargs = new Objects(t);
id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
auto arguments = new Expressions();
id = new CallExp(exp.loc, id, arguments);
@@ -5288,7 +5732,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// If the new expression has arguments, we either should call a
// regular constructor of a copy constructor if the first argument
// is the same type as the struct
- if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
+ if (nargs && (sd.hasRegularCtor(false) || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
{
FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
if (!f || f.errors)
@@ -5440,19 +5884,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
Expression lowering = new IdentifierExp(exp.loc, Id.empty);
lowering = new DotIdExp(exp.loc, lowering, Id.object);
- auto tiargs = new Objects();
+
/* Remove `inout`, `const`, `immutable` and `shared` to reduce
* the number of generated `_d_newarrayT` instances.
*/
const isShared = exp.type.nextOf.isShared();
auto t = exp.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
MODFlags.immutable_ | MODFlags.shared_);
- tiargs.push(t);
+ auto tiargs = new Objects(t);
lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
- auto arguments = new Expressions();
- arguments.push((*exp.arguments)[0]);
- arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool));
+ auto arguments = new Expressions((*exp.arguments)[0], new IntegerExp(exp.loc, isShared, Type.tbool));
lowering = new CallExp(exp.loc, lowering, arguments);
exp.lowering = lowering.expressionSemantic(sc);
@@ -5476,15 +5918,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
MODFlags.immutable_ | MODFlags.shared_);
- auto tiargs = new Objects();
- tiargs.push(exp.type);
- tiargs.push(unqualTbn);
+ auto tiargs = new Objects(exp.type, unqualTbn);
lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
- auto arguments = new Expressions();
-
- arguments.push(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments));
- arguments.push(new IntegerExp(exp.loc, tbn.isShared(), Type.tbool));
+ auto arguments = new Expressions(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments),
+ new IntegerExp(exp.loc, tbn.isShared(), Type.tbool));
lowering = new CallExp(exp.loc, lowering, arguments);
exp.lowering = lowering.expressionSemantic(sc);
@@ -5529,6 +5967,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
error(exp.loc, "`new` cannot take arguments for an associative array");
return setError();
}
+ tryLowerToNewAA(exp);
}
else
{
@@ -5702,7 +6141,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
symtab = sds.symtab;
}
assert(symtab);
- Identifier id = Identifier.generateIdWithLoc(s, exp.loc, cast(string) toDString(sc.parent.toPrettyChars()));
+ Identifier id = Identifier.generateIdWithLoc(s, exp.loc, cast(const void*) sc.parent);
exp.fd.ident = id;
if (exp.td)
exp.td.ident = id;
@@ -5916,11 +6355,28 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (TypeFunction tf = exp.f ? cast(TypeFunction)exp.f.type : null)
{
- result.rvalue = tf.isRvalue;
- if (tf.isRvalue && !tf.isRef)
+ if (tf.isRvalue)
{
- error(exp.f.loc, "`__rvalue` only valid on functions that return by `ref`");
- setError();
+ if(!tf.isRef)
+ {
+ error(exp.f.loc, "`__rvalue` only valid on functions that return by `ref`");
+ setError();
+ }
+ else if (sc.setUnsafe(false, exp.loc, "calling `__rvalue`-annotated function `%s`", exp.f))
+ {
+ setError();
+ }
+ else
+ {
+ result.rvalue = true;
+ }
+ }
+ else if (exp.rvalue && tf.isRef)
+ {
+ if (sc.setUnsafe(false, exp.loc, "moving result of `ref` function `%s` with `__rvalue`", exp.f))
+ {
+ setError();
+ }
}
}
}
@@ -6213,7 +6669,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (sd.ctor)
{
auto ctor = sd.ctor.isCtorDeclaration();
- if (ctor && (ctor.isCpCtor || ctor.isMoveCtor) && ctor.isGenerated())
+ if (ctor && (ctor.isCpCtor || ctor.isMoveCtor) && ctor.isGenerated)
sd.ctor = null;
}
@@ -6227,7 +6683,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
If all constructors are copy constructors, then
try default construction.
*/
- if (!sd.hasRegularCtor &&
+ if (!sd.hasRegularCtor(false) &&
// https://issues.dlang.org/show_bug.cgi?id=22639
// we might still have a copy constructor that could be called
(*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
@@ -6898,8 +7354,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!exp.type)
{
exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
- // avoid recursive expression printing
- error(exp.loc, "forward reference to inferred return type of function call `%s`", exp.toErrMsg());
+ // avoid recursive expression printing
+ FuncDeclaration fd = null;
+ if (auto dve = exp.e1.isDotVarExp())
+ fd = cast(FuncDeclaration)dve.var;
+ else if (auto ve = exp.e1.isVarExp())
+ fd = cast(FuncDeclaration)ve.var;
+
+ if (fd && fd.inferRetType && sc && sc.func == fd)
+ {
+ error(exp.loc, "can't infer return type in function `%s`", fd.toChars());
+ }
+ else
+ {
+ error(exp.loc, "forward reference to inferred return type of function call `%s`", exp.toErrMsg());
+ }
return setError();
}
@@ -6911,7 +7380,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (tf.next.isBaseOf(t, &offset) && offset)
{
exp.type = tf.next;
- result = Expression.combine(argprefix, exp.castTo(sc, t));
+ auto casted_exp = exp.castTo(sc, t);
+ if (auto cex = casted_exp.isCastExp())
+ {
+ lowerCastExp(cex, sc);
+ }
+ result = Expression.combine(argprefix, casted_exp);
return;
}
}
@@ -6960,7 +7434,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
// declare dual-context container
- if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
+ if (exp.f && exp.f.hasDualContext && !sc.intypeof && sc.func)
{
// check access to second `this`
if (AggregateDeclaration ad2 = exp.f.isMember2())
@@ -7700,7 +8174,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
assert(e.op == EXP.assign || e == exp);
- result = (cast(BinExp)e).reorderSettingAAElem(sc);
+ result = e;
}
private Expression compileIt(MixinExp exp, Scope* sc)
@@ -7917,7 +8391,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Defensively assume that function calls may have side effects even
// though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
// Rewriting CallExp's also avoids some issues with the inliner/debug generation
- if (op.hasSideEffect(true))
+ if (op.hasSideEffect(true) || op.isAssocArrayLiteralExp())
{
// Don't create an invalid temporary for void-expressions
// Further semantic will issue an appropriate error
@@ -8003,7 +8477,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
isEqualsCallExpression)
{
es = new Expressions(3);
- tiargs = new Objects(1);
if (isEqualsCallExpression)
{
@@ -8042,7 +8515,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
comp = comp.expressionSemantic(sc);
(*es)[0] = comp;
- (*tiargs)[0] = (*es)[1].type;
+ tiargs = new Objects((*es)[1].type);
}
// Format exp.e1 before any additional boolean conversion
@@ -8050,7 +8523,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else if (op != EXP.andAnd && op != EXP.orOr)
{
es = new Expressions(2);
- tiargs = new Objects(1);
if (auto ne = exp.e1.isNotExp())
{
@@ -8074,7 +8546,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
(*es)[1] = maybePromoteToTmp(exp.e1);
}
- (*tiargs)[0] = (*es)[1].type;
+ tiargs = new Objects((*es)[1].type);
// Passing __ctfe to auto ref infers ref and aborts compilation:
// "cannot modify compiler-generated variable __ctfe"
@@ -8185,6 +8657,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
printAST(exp);
}
+ scope (exit)
+ {
+ if (result)
+ result.rvalue = exp.rvalue;
+ else
+ setError();
+ }
if (sc.inCfile)
{
@@ -8467,7 +8946,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
result = e;
// declare dual-context container
- if (f.hasDualContext() && !sc.intypeof && sc.func)
+ if (f.hasDualContext && !sc.intypeof && sc.func)
{
// check access to second `this`
if (AggregateDeclaration ad2 = f.isMember2())
@@ -8641,7 +9120,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
error(exp.loc, "cannot take address of `%s`", exp.e1.toErrMsg());
return setError();
}
- if (!checkAddressable(exp, sc))
+ if (!checkAddressable(exp, sc, "take address of"))
return setError();
bool hasOverloads;
@@ -9299,13 +9778,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression id = new IdentifierExp(exp.loc, Id.empty);
auto dotid = new DotIdExp(exp.loc, id, Id.object);
- auto tiargs = new Objects();
- tiargs.push(tFrom);
- tiargs.push(tTo);
+ auto tiargs = new Objects(tFrom, tTo);
auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
- auto arguments = new Expressions();
- arguments.push(exp.e1);
+ auto arguments = new Expressions(exp.e1);
Expression ce = new CallExp(exp.loc, dt, arguments);
result = expressionSemantic(ce, sc);
@@ -9328,6 +9804,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
ex.type = exp.to;
}
}
+
+ if (auto cex = ex.isCastExp())
+ {
+ lowerCastExp(cex, sc);
+ }
+
result = ex;
}
@@ -9966,7 +10448,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
if (t1b.isStaticOrDynamicArray())
{
- if (!checkAddressable(exp, sc))
+ if (!checkAddressable(exp, sc, "index through"))
return setError();
}
@@ -10053,9 +10535,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
semanticTypeInfo(sc, taa);
- checkNewEscape(*sc, exp.e2, false);
+ bool escape = checkNewEscape(*sc, exp.e2, false);
+ if (escape)
+ return setError();
exp.type = taa.next;
+ if (!exp.modifiable)
+ {
+ result = lowerAAIndexRead(exp, sc);
+ return;
+ }
break;
}
case Ttuple:
@@ -10161,6 +10650,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
+ if (auto ae = exp.e1.isArrayExp())
+ markArrayExpModifiable(ae);
+
if (Expression ex = binSemantic(exp, sc))
{
result = ex;
@@ -10174,6 +10666,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
exp.e1 = e1x;
+ Type[2] aliasThisStop;
+ if (auto res = rewriteIndexAssign(exp, sc, aliasThisStop))
+ {
+ result = res;
+ return;
+ }
if (exp.e1.checkReadModifyWrite(exp.op))
return setError();
@@ -10243,6 +10741,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(PreExp exp)
{
+ if (auto ae = exp.e1.isArrayExp())
+ markArrayExpModifiable(ae);
+
// printf("PreExp::semantic('%s')\n", toChars());
if (Expression e = exp.opOverloadUnary(sc))
{
@@ -10333,6 +10834,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (auto ae = exp.e1.isArrayExp())
{
Expression res;
+ markArrayExpModifiable(ae);
ae.e1 = ae.e1.expressionSemantic(sc);
ae.e1 = resolveProperties(sc, ae.e1);
@@ -10408,8 +10910,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
/* Rewrite (a[i..j] = e2) as:
* a.opSliceAssign(e2, i, j)
*/
- auto a = new Expressions();
- a.push(exp.e2);
+ auto a = new Expressions(exp.e2);
if (ie)
{
a.push(ie.lwr);
@@ -10600,8 +11101,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression e0;
Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
- auto iexps = new Expressions();
- iexps.push(ev);
+ auto iexps = new Expressions(ev);
for (size_t u = 0; u < iexps.length; u++)
{
Lexpand:
@@ -10675,18 +11175,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto t = exp.type;
exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
exp.type = t;
-
- // https://issues.dlang.org/show_bug.cgi?id=13515
- // set Index::modifiable flag for complex AA element initialization
- if (auto ie1 = exp.e1.isIndexExp())
- {
- Expression e1x = ie1.markSettingAAElem();
- if (e1x.op == EXP.error)
- {
- result = e1x;
- return;
- }
- }
}
else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
(cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
@@ -10702,6 +11190,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
+ if (auto res = rewriteIndexAssign(exp, sc, aliasThisStop))
+ {
+ result = res;
+ return;
+ }
+
/* If it is an assignment from a 'foreign' type,
* check for operator overloading.
*/
@@ -10991,91 +11485,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (exp.op == EXP.assign)
{
- if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
- {
- /*
- * Rewrite:
- * aa[key] = e2;
- * as:
- * ref __aatmp = aa;
- * ref __aakey = key;
- * ref __aaval = e2;
- * (__aakey in __aatmp
- * ? __aatmp[__aakey].opAssign(__aaval)
- * : ConstructExp(__aatmp[__aakey], __aaval));
- */
- // ensure we keep the expr modifiable
- Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
- if (esetting.op == EXP.error)
- {
- result = esetting;
- return;
- }
- assert(esetting.op == EXP.index);
- IndexExp ie = cast(IndexExp) esetting;
- Type t2 = e2x.type.toBasetype();
-
- Expression e0 = null;
- Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
- Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
- Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
-
- AssignExp ae = cast(AssignExp)exp.copy();
- ae.e1 = new IndexExp(exp.loc, ea, ek);
- ae.e1 = ae.e1.expressionSemantic(sc);
- ae.e1 = ae.e1.optimize(WANTvalue);
- ae.e2 = ev;
- if (Expression e = ae.opOverloadAssign(sc, aliasThisStop))
- {
- Expression ey = null;
- if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
- {
- ey = ev;
- }
- else if (!ev.implicitConvTo(ie.type) && sd.ctor)
- {
- // Look for implicit constructor call
- // Rewrite as S().ctor(e2)
- ey = new StructLiteralExp(exp.loc, sd, null);
- ey = new DotIdExp(exp.loc, ey, Id.ctor);
- ey = new CallExp(exp.loc, ey, ev);
- ey = ey.trySemantic(sc);
- }
- if (ey)
- {
- Expression ex;
- ex = new IndexExp(exp.loc, ea, ek);
- ex = ex.expressionSemantic(sc);
- ex = ex.modifiableLvalue(sc); // allocate new slot
- ex = ex.optimize(WANTvalue);
-
- ey = new ConstructExp(exp.loc, ex, ey);
- ey = ey.expressionSemantic(sc);
- if (ey.op == EXP.error)
- {
- result = ey;
- return;
- }
- ex = e;
-
- // https://issues.dlang.org/show_bug.cgi?id=14144
- // The whole expression should have the common type
- // of opAssign() return and assigned AA entry.
- // Even if there's no common type, expression should be typed as void.
- if (!typeMerge(sc, EXP.question, ex, ey))
- {
- ex = new CastExp(ex.loc, ex, Type.tvoid);
- ey = new CastExp(ey.loc, ey, Type.tvoid);
- }
- e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
- }
- e = Expression.combine(e0, e);
- e = e.expressionSemantic(sc);
- result = e;
- return;
- }
- }
- else if (Expression e = exp.isAssignExp().opOverloadAssign(sc, aliasThisStop))
+ if (Expression e = exp.isAssignExp().opOverloadAssign(sc, aliasThisStop))
{
result = e;
return;
@@ -11239,7 +11649,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
// Ensure e1 is a modifiable lvalue
- auto ale1x = ale.e1.modifiableLvalueImpl(sc, exp.e1);
+ auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
if (ale1x.op == EXP.error)
return setResult(ale1x);
ale.e1 = ale1x;
@@ -11283,9 +11693,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = id.expressionSemantic(sc);
// Generate call: _d_arraysetlengthT(e1, e2)
- auto arguments = new Expressions();
- arguments.push(ale.e1); // array
- arguments.push(exp.e2); // new length
+ auto arguments = new Expressions(ale.e1, // array
+ exp.e2); // new length
Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc);
auto res = new LoweredAssignExp(exp, ce);
@@ -11319,7 +11728,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
se = cast(SliceExp)se.e1;
if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
{
- se.e1 = se.e1.modifiableLvalueImpl(sc, exp.e1);
+ se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
if (se.e1.op == EXP.error)
return setResult(se.e1);
}
@@ -11343,7 +11752,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Try to do a decent error message with the expression
// before it gets constant folded
if (exp.op == EXP.assign)
- e1x = e1x.modifiableLvalueImpl(sc, e1old);
+ e1x = e1x.modifiableLvalue(sc, e1old);
e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
@@ -11490,7 +11899,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
t1.isStaticOrDynamicArray() &&
t1.nextOf().toBasetype().ty == Tvoid)
{
- if (t2.nextOf().implicitConvTo(t1.nextOf()))
+ auto t2n = t2.nextOf();
+ if (!t2n)
+ {
+ // filling not allowed
+ error(exp.loc, "cannot copy `%s` to `%s`",
+ t2.toChars(), t1.toChars());
+ }
+ else if (t2n.implicitConvTo(t1.nextOf()))
{
if (sc.setUnsafe(false, exp.loc, "copying `%s` to `%s`", t2, t1))
return setError();
@@ -11568,16 +11984,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.type = exp.e1.type;
assert(exp.type);
auto assignElem = exp.e2;
- auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
- /* https://issues.dlang.org/show_bug.cgi?id=22366
- *
- * `reorderSettingAAElem` creates a tree of comma expressions, however,
- * `checkAssignExp` expects only AssignExps.
- */
- if (res == exp) // no `AA[k] = v` rewrite was performed
- checkAssignEscape(*sc, res, false, false);
- else
- checkNewEscape(*sc, assignElem, false); // assigning to AA puts it on heap
+ Expression res = exp;
+ checkAssignEscape(*sc, res, false, false);
if (auto ae = res.isConstructExp())
{
@@ -11639,8 +12047,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = new DotIdExp(exp.loc, id, Id.object);
id = new DotIdExp(exp.loc, id, func);
- auto arguments = new Expressions();
- arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
+ auto arguments = new Expressions(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
if (lowerToArrayCtor)
{
arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
@@ -11721,9 +12128,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = new DotIdExp(ae.loc, id, Id.object);
id = new DotIdExp(ae.loc, id, func);
- auto arguments = new Expressions();
- arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
- .expressionSemantic(sc));
+ auto arguments = new Expressions(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
+ .expressionSemantic(sc));
Expression eValue2, value2 = ae.e2;
if (isArrayAssign && value2.isLvalue())
@@ -11752,14 +12158,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression ce = new CallExp(ae.loc, id, arguments);
res = Expression.combine(eValue2, ce).expressionSemantic(sc);
if (isArrayAssign)
- res = Expression.combine(res, ae.e1).expressionSemantic(sc);
+ res = Expression.combine(res, ae.e1).expressionSemantic(sc).checkGC(sc);
if (global.params.v.verbose)
message("lowered %s =>\n %s", ae.toChars(), res.toChars());
res = new LoweredAssignExp(ae, res);
res.type = ae.type;
- res = res.checkGC(sc);
return res;
}
@@ -11814,7 +12219,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if ((exp.e1.type.isIntegral() || exp.e1.type.isFloating()) && (exp.e2.type.isIntegral() || exp.e2.type.isFloating()))
{
Expression e0 = null;
- Expression e = exp.reorderSettingAAElem(sc);
+ Expression e = exp;
e = Expression.extractLast(e, e0);
assert(e == exp);
@@ -11961,10 +12366,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.type = exp.e1.type;
auto assignElem = exp.e2;
- auto res = exp.reorderSettingAAElem(sc);
- if (res != exp) // `AA[k] = v` rewrite was performed
- checkNewEscape(*sc, assignElem, false);
- else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
+ auto res = exp;
+ if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
checkAssignEscape(*sc, res, false, false);
result = res;
@@ -12000,9 +12403,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = new DotIdExp(exp.loc, id, Id.object);
id = new DotIdExp(exp.loc, id, hook);
- auto arguments = new Expressions();
- arguments.push(exp.e1);
- arguments.push(exp.e2);
+ auto arguments = new Expressions(exp.e1, exp.e2);
Expression ce = new CallExp(exp.loc, id, arguments);
exp.lowering = ce.expressionSemantic(sc);
@@ -12034,12 +12435,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = new DotIdExp(exp.loc, id, Id.object);
id = new DotIdExp(exp.loc, id, hook);
- auto arguments = new Expressions();
Expression eValue1;
Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
- arguments.push(value1);
- arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
+ auto arguments = new Expressions(value1, new IntegerExp(exp.loc, 1, Type.tsize_t));
Expression ce = new CallExp(exp.loc, id, arguments);
@@ -12051,14 +12450,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* for expressions like `a ~= a[$-1]`. Here, $ will be modified
* by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
* a temporary variable.
+ * `__appendtmp*` will be destroyed together with the array `exp.e1`.
*/
- value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
-
- // `__appendtmp*` will be destroyed together with the array `exp.e1`.
- auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
- vd.storage_class |= STC.nodtor;
- // Be more explicit that this "declaration" is local to the expression
- vd.storage_class |= STC.exptemp;
+ value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true, STC.nodtor | STC.exptemp);
}
auto ale = new ArrayLengthExp(exp.loc, value1);
@@ -12392,11 +12786,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression id = new IdentifierExp(exp.loc, Id.empty);
id = new DotIdExp(exp.loc, id, Id.object);
- auto tiargs = new Objects();
- tiargs.push(exp.type);
+ auto tiargs = new Objects(exp.type);
id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
id = new CallExp(exp.loc, id, arguments);
- return id.expressionSemantic(sc);
+ return id.expressionSemantic(sc).checkGC(sc);
}
void trySetCatExpLowering(Expression exp)
@@ -12845,7 +13238,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
- Module mmath = Module.loadStdMath();
+ Module mmath = loadStdMath();
if (!mmath)
{
error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toErrMsg());
@@ -13172,6 +13565,59 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
+ /**
+ * lowers an `InExp` to a call to `_d_aaIn!(V[K])`.
+ *
+ * Params:
+ * ie = the `InExp` to lower
+ * Returns:
+ * the lowered expression or an ErrorExp
+ */
+ private Expression lowerToAAIn(InExp ie)
+ {
+ Identifier hook = Id._d_aaIn;
+ if (!verifyHookExist(ie.loc, *sc, hook, "key in AA"))
+ return ErrorExp.get();
+
+ Expression id = new IdentifierExp(ie.loc, Id.empty);
+ id = new DotIdExp(ie.loc, id, Id.object);
+ auto tiargs = new Objects();
+ id = new DotIdExp(ie.loc, id, hook);
+
+ Expression e1;
+ Expression ekey = extractSideEffect(sc, "__aakey", e1, ie.e1);
+ auto arguments = new Expressions(ie.e2, ekey);
+ auto ce = new CallExp(ie.loc, id, arguments);
+ ce.loweredFrom = ie;
+ e1 = Expression.combine(e1, ce);
+ return e1.expressionSemantic(sc);
+ }
+
+ /**
+ * lowers a `RemoveExp` to a call to `_d_aaDel!(V[K])`.
+ *
+ * Params:
+ * re = the `RemoveExp` to lower
+ * Returns:
+ * the lowered expression or an ErrorExp
+ */
+ private Expression lowerToAADel(RemoveExp re)
+ {
+ Identifier hook = Id._d_aaDel;
+ if (!verifyHookExist(re.loc, *sc, hook, "remove key in AA"))
+ return ErrorExp.get();
+
+ Expression id = new IdentifierExp(re.loc, Id.empty);
+ id = new DotIdExp(re.loc, id, Id.object);
+ auto tiargs = new Objects();
+ id = new DotIdExp(re.loc, id, hook);
+
+ auto arguments = new Expressions(re.e1, re.e2);
+ auto ce = new CallExp(re.loc, id, arguments);
+ ce.loweredFrom = re;
+ return ce.expressionSemantic(sc);
+ }
+
override void visit(InExp exp)
{
if (Expression e = exp.opOverloadBinary(sc, aliasThisStop))
@@ -13194,14 +13640,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
}
+ // for backward compatibility, type accepted during semantic, but errors in glue layer
+ if (exp.e2.isTypeExp())
+ {
+ exp.type = ta.nextOf().pointerTo();
+ break;
+ }
+ result = lowerToAAIn(exp);
+
// even though the glue layer only needs the type info of the index,
// this might be the first time an AA literal is accessed, so check
// the full type info
semanticTypeInfo(sc, ta);
-
- // Return type is pointer to value
- exp.type = ta.nextOf().pointerTo();
- break;
+ return;
}
case Terror:
@@ -13229,7 +13680,39 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = ex;
return;
}
- result = e;
+
+ result = lowerToAADel(e);
+ }
+
+ /**
+ * lower a `EqualExp` to a call to `_d_aaEqual!(aa1, aa2)`.
+ *
+ * Params:
+ * ee = the `EqualExp` to lower
+ * Returns:
+ * the lowered expression or an ErrorExp
+ */
+ private Expression lowerToAAEqual(EqualExp ee)
+ {
+ Identifier hook = Id._d_aaEqual;
+ if (!verifyHookExist(ee.loc, *sc, hook, "compare AAs"))
+ return ErrorExp.get();
+
+ Expression id = new IdentifierExp(ee.loc, Id.empty);
+ id = new DotIdExp(ee.loc, id, Id.object);
+ auto tiargs = new Objects();
+ id = new DotIdExp(ee.loc, id, hook);
+
+ auto arguments = new Expressions(ee.e1, ee.e2);
+ auto ce = new CallExp(ee.loc, id, arguments);
+ if (ee.op == EXP.notEqual)
+ {
+ auto ne = new NotExp(ee.loc, ce);
+ ne.loweredFrom = ee;
+ return ne.expressionSemantic(sc);
+ }
+ ce.loweredFrom = ee;
+ return ce.expressionSemantic(sc);
}
override void visit(EqualExp exp)
@@ -13312,19 +13795,53 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Type t1 = exp.e1.type.toBasetype();
Type t2 = exp.e2.type.toBasetype();
- // Indicates whether the comparison of the 2 specified array types
- // requires an object.__equals() lowering.
- static bool needsDirectEq(Type t1, Type t2, Scope* sc)
+ static bool unifyArrayTypes(Type t1, Type t2, Scope* sc)
{
Type t1n = t1.nextOf().toBasetype();
Type t2n = t2.nextOf().toBasetype();
+
if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
(t1n.ty == Tvoid || t2n.ty == Tvoid))
{
- return false;
+ return true;
}
if (t1n.constOf() != t2n.constOf())
+ {
+ return false;
+ }
+
+ Type t = t1n;
+ while (t.toBasetype().nextOf())
+ t = t.nextOf().toBasetype();
+ if (auto ts = t.isTypeStruct())
+ {
+ // semanticTypeInfo() makes sure hasIdentityEquals has been computed
+ if (global.params.useTypeInfo && Type.dtypeinfo)
+ semanticTypeInfo(sc, ts);
+
+ return !ts.sym.hasIdentityEquals; // has custom opEquals
+ }
+
+ return true;
+ }
+
+ static bool shouldUseMemcmp(Type t1, Type t2, Scope *sc)
+ {
+ Type t1n = t1.nextOf().toBasetype();
+ Type t2n = t2.nextOf().toBasetype();
+ const t1nsz = t1n.size();
+ const t2nsz = t2n.size();
+
+ if ((t1n.ty == Tvoid || (t1n.isScalar() && !t1n.isFloating())) &&
+ (t2n.ty == Tvoid || (t2n.isScalar() && !t1n.isFloating())) &&
+ t1nsz == t2nsz && t1n.isUnsigned() == t2n.isUnsigned())
+ {
return true;
+ }
+ if (t1n.constOf() != t2n.constOf())
+ {
+ return false;
+ }
Type t = t1n;
while (t.toBasetype().nextOf())
@@ -13335,7 +13852,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (global.params.useTypeInfo && Type.dtypeinfo)
semanticTypeInfo(sc, ts);
- return ts.sym.hasIdentityEquals; // has custom opEquals
+ auto v = new IsMemcmpableVisitor();
+ ts.accept(v);
+ return v.result;
}
return false;
@@ -13348,9 +13867,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
const isArrayComparison = t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray();
- const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
- if (!needsArrayLowering)
+ if (!isArrayComparison || unifyArrayTypes(t1, t2, sc))
{
// https://issues.dlang.org/show_bug.cgi?id=23783
if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc))
@@ -13380,7 +13898,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
// lower some array comparisons to object.__equals(e1, e2)
- if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
+ if (isArrayComparison && !shouldUseMemcmp(t1, t2, sc))
{
//printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
@@ -13395,13 +13913,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
- if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
+ Identifier hook = Id.__equals;
+ if (!verifyHookExist(exp.loc, *sc, hook, "equal checks on arrays"))
return setError();
- Expression __equals = new IdentifierExp(exp.loc, Id.empty);
- Identifier id = Identifier.idPool("__equals");
- __equals = new DotIdExp(exp.loc, __equals, Id.object);
- __equals = new DotIdExp(exp.loc, __equals, id);
+ Expression lowering = new IdentifierExp(exp.loc, Id.empty);
+ lowering = new DotIdExp(exp.loc, lowering, Id.object);
+ lowering = new DotIdExp(exp.loc, lowering, hook);
/* https://issues.dlang.org/show_bug.cgi?id=23674
*
@@ -13412,30 +13930,76 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = exp.e1.optimize(WANTvalue);
exp.e2 = exp.e2.optimize(WANTvalue);
+ auto e1c = exp.e1.copy();
+ auto e2c = exp.e2.copy();
+
+ /* Remove qualifiers from the types of the arguments to reduce the number
+ * of generated `__equals` instances.
+ */
+ static void unqualifyExp(Expression e)
+ {
+ e.type = e.type.unqualify(MODFlags.wild | MODFlags.immutable_ | MODFlags.shared_);
+ auto eNext = e.type.nextOf();
+ if (eNext && !eNext.toBasetype().isTypeStruct())
+ e.type = e.type.unqualify(MODFlags.const_);
+
+ if (!e.isArrayLiteralExp())
+ return;
+
+ if (auto elems = e.isArrayLiteralExp().elements)
+ foreach(elem; *elems)
+ if (elem)
+ unqualifyExp(elem);
+ }
+ unqualifyExp(e1c);
+ unqualifyExp(e2c);
+
auto arguments = new Expressions(2);
- (*arguments)[0] = exp.e1;
- (*arguments)[1] = exp.e2;
+ (*arguments)[0] = e1c;
+ (*arguments)[1] = e2c;
- __equals = new CallExp(exp.loc, __equals, arguments);
+ lowering = new CallExp(exp.loc, lowering, arguments);
if (exp.op == EXP.notEqual)
{
- __equals = new NotExp(exp.loc, __equals);
+ lowering = new NotExp(exp.loc, lowering);
}
- __equals = __equals.trySemantic(sc); // for better error message
- if (!__equals)
+ lowering = lowering.trySemantic(sc); // for better error message
+ if (!lowering)
{
- error(exp.loc, "incompatible types for array comparison: `%s` and `%s`",
- exp.e1.type.toChars(), exp.e2.type.toChars());
- __equals = ErrorExp.get();
+ if (sc.func)
+ error(exp.loc, "can't infer return type in function `%s`", sc.func.toChars());
+ else
+ error(exp.loc, "incompatible types for array comparison: `%s` and `%s`",
+ exp.e1.type.toChars(), exp.e2.type.toChars());
+ lowering = ErrorExp.get();
}
-
- result = __equals;
+ exp.lowering = lowering;
+ result = exp;
return;
}
+ // When array comparison is not lowered to `__equals`, `memcmp` is used, but
+ // GC checks occur before the expression is lowered to `memcmp` in e2ir.d.
+ // Thus, we will consider the literal arrays as on-stack arrays to avoid issues
+ // during GC checks.
+ if (isArrayComparison)
+ {
+ if (auto ale1 = exp.e1.isArrayLiteralExp())
+ {
+ ale1.onstack = true;
+ }
+
+ if (auto ale2 = exp.e2.isArrayLiteralExp())
+ {
+ ale2.onstack = true;
+ }
+ }
+
if (exp.e1.type.toBasetype().ty == Taarray)
{
+ result = lowerToAAEqual(exp);
semanticTypeInfo(sc, exp.e1.type.toBasetype());
+ return;
}
if (!target.isVectorOpSupported(t1, exp.op, t2))
@@ -13924,7 +14488,8 @@ private bool expressionSemanticDone(Expression e)
|| e.isTypeExp() // stores its type in the Expression.type field
|| e.isCompoundLiteralExp() // stores its `(type) {}` in type field, gets rewritten to struct literal
|| e.isVarExp() // type sometimes gets set already before semantic
- || (e.isAssocArrayLiteralExp() && !e.type.vtinfo) // semanticTypeInfo not run during initialization
+ || (e.isAssocArrayLiteralExp() && // semanticTypeInfo not run during initialization
+ (!e.type.vtinfo || !e.isAssocArrayLiteralExp().lowering))
);
}
@@ -14410,20 +14975,10 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
return e;
}
- else if ((exp.ident == Id.max || exp.ident == Id.min) &&
- exp.e1.isVarExp() &&
- exp.e1.isVarExp().var.isBitFieldDeclaration())
- {
- // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
- auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
- return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
- }
- else if ((exp.ident == Id.max || exp.ident == Id.min) &&
- exp.e1.isDotVarExp() &&
- exp.e1.isDotVarExp().var.isBitFieldDeclaration())
+ else if ((exp.ident == Id.max || exp.ident == Id.min) && exp.e1.isBitField())
{
// For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
- auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
+ auto bf = exp.e1.isBitField();
return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
}
else
@@ -15346,6 +15901,9 @@ Expression resolveLoc(Expression exp, Loc loc, Scope* sc)
element = element.resolveLoc(loc, sc);
}
+ if (exp.lowering)
+ exp.lowering.resolveLoc(loc, sc);
+
return exp;
}
@@ -15540,25 +16098,23 @@ Expression addDtorHook(Expression e, Scope* sc)
/*******************************
* Try to convert an expression to be an lvalue.
*
- * Give error if we're not an lvalue.
+ * Give error if we are not an lvalue.
* Params:
* _this = expression to convert
* sc = scope
* action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
+ * eorig = original un-lowered expression for error messages, in case of recursive calls; null means use `_this`
* Returns: converted expression, or `ErrorExp` on error
*/
-Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
-{
- return toLvalueImpl(_this, sc, action, _this);
-}
-
-// e = original un-lowered expression for error messages, in case of recursive calls
-private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e)
+Expression toLvalue(Expression _this, Scope* sc, const(char)* action, Expression eorig = null)
{
+ //printf("toLvalue() %s\n", _this.toChars());
+ if (!eorig)
+ eorig = _this;
if (!action)
action = "create lvalue of";
- assert(e);
+ assert(eorig);
Expression visit(Expression _this)
{
// BinaryAssignExp does not have an EXP associated
@@ -15567,14 +16123,14 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
if (_this.isBinAssignExp())
return _this;
if (!_this.loc.isValid())
- _this.loc = e.loc;
+ _this.loc = eorig.loc;
- if (e.op == EXP.type)
- error(_this.loc, "cannot %s type `%s`", action, e.type.toChars());
- else if (e.op == EXP.template_)
- error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toErrMsg());
+ if (eorig.op == EXP.type)
+ error(_this.loc, "cannot %s type `%s`", action, eorig.type.toChars());
+ else if (eorig.op == EXP.template_)
+ error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, eorig.toErrMsg());
else
- error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toErrMsg());
+ error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, eorig.toErrMsg());
return ErrorExp.get();
}
@@ -15582,8 +16138,8 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
Expression visitInteger(IntegerExp _this)
{
if (!_this.loc.isValid())
- _this.loc = e.loc;
- error(e.loc, "cannot %s constant `%s`", action, e.toErrMsg());
+ _this.loc = eorig.loc;
+ error(eorig.loc, "cannot %s constant `%s`", action, eorig.toErrMsg());
return ErrorExp.get();
}
@@ -15652,14 +16208,15 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
{
auto e1 = _this.e1;
auto var = _this.var;
- //printf("DotVarExp::toLvalue(%s)\n", toChars());
+ //printf("DotVarExp::toLvalue(%s)\n", _this.toChars());
if (sc && sc.inCfile)
{
/* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
* is an lvalue if the first expression is an lvalue.
*/
- if (!e1.isLvalue())
- return visit(_this);
+ e1 = e1.toLvalue(sc, action, eorig);
+ if (e1.isErrorExp())
+ return e1;
}
if (!_this.isLvalue())
return visit(_this);
@@ -15720,7 +16277,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
Expression visitVectorArray(VectorArrayExp _this)
{
- _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
+ _this.e1 = _this.e1.toLvalue(sc, action, eorig);
return _this;
}
@@ -15745,13 +16302,13 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
Expression visitDelegatePointer(DelegatePtrExp _this)
{
- _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
+ _this.e1 = _this.e1.toLvalue(sc, action, eorig);
return _this;
}
Expression visitDelegateFuncptr(DelegateFuncptrExp _this)
{
- _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
+ _this.e1 = _this.e1.toLvalue(sc, action, eorig);
return _this;
}
@@ -15778,12 +16335,19 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
Expression visitCond(CondExp _this)
{
+ if (sc && sc.inCfile)
+ {
+ // C11 6.5.15: A conditional expression does not yield an lvalue.
+ return visit(_this);
+ }
// convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
- CondExp e = cast(CondExp)(_this.copy());
- e.e1 = _this.e1.toLvalue(sc, action).addressOf();
- e.e2 = _this.e2.toLvalue(sc, action).addressOf();
- e.type = _this.type.pointerTo();
- return new PtrExp(_this.loc, e, _this.type);
+ CondExp ecopy = cast(CondExp)(_this.copy());
+ ecopy.e1 = _this.e1.toLvalue(sc, action).addressOf();
+ checkAddressable(ecopy.e1, sc, "take address of");
+ ecopy.e2 = _this.e2.toLvalue(sc, action).addressOf();
+ checkAddressable(ecopy.e2, sc, "take address of");
+ ecopy.type = _this.type.pointerTo();
+ return new PtrExp(_this.loc, ecopy, _this.type);
}
@@ -15975,17 +16539,14 @@ Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyF
* Params:
* _this = Expression to convert
* sc = scope
+ * eorig = original / un-lowered expression to print in error messages, if null default to `_this`
* Returns: `_this` converted to an lvalue, or an `ErrorExp`
*/
-Expression modifiableLvalue(Expression _this, Scope* sc)
+Expression modifiableLvalue(Expression _this, Scope* sc, Expression eorig = null)
{
- return modifiableLvalueImpl(_this, sc, _this);
-}
+ if (!eorig)
+ eorig = _this;
-// e = original / un-lowered expression to print in error messages
-private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression e)
-{
- assert(e);
Expression visit(Expression exp)
{
//printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
@@ -16024,7 +16585,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
return ErrorExp.get();
}
}
- return exp.toLvalueImpl(sc, "modify", e);
+ return exp.toLvalue(sc, "modify", eorig);
}
Expression visitString(StringExp exp)
@@ -16073,7 +16634,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
Expression visitComma(CommaExp exp)
{
- exp.e2 = exp.e2.modifiableLvalueImpl(sc, e);
+ exp.e2 = exp.e2.modifiableLvalue(sc, eorig);
return exp;
}
@@ -16095,16 +16656,6 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
return visit(exp);
}
- Expression visitIndex(IndexExp exp)
- {
- //printf("IndexExp::modifiableLvalue(%s)\n", exp.toChars());
- Expression ex = exp.markSettingAAElem();
- if (ex.op == EXP.error)
- return ex;
-
- return visit(exp);
- }
-
Expression visitCond(CondExp exp)
{
if (!exp.e1.isLvalue() && !exp.e2.isLvalue())
@@ -16127,7 +16678,6 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
case EXP.comma: return visitComma(_this.isCommaExp());
case EXP.delegatePointer: return visitDelegatePtr(_this.isDelegatePtrExp());
case EXP.delegateFunctionPointer: return visitDelegateFuncptr(_this.isDelegateFuncptrExp());
- case EXP.index: return visitIndex(_this.isIndexExp());
case EXP.question: return visitCond(_this.isCondExp());
}
}
@@ -16155,9 +16705,12 @@ private bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
}
if (sc.func && !sc.intypeof && !v.isDataseg())
{
+ auto msg = (v.storage_class & STC.ref_) ?
+ "taking the address of local variable `%s`" :
+ "taking the address of stack-allocated local variable `%s`";
if (sc.useDIP1000 != FeatureState.enabled &&
!(v.storage_class & STC.temp) &&
- sc.setUnsafe(false, exp.loc, "taking the address of stack-allocated local variable `%s`", v))
+ sc.setUnsafe(false, exp.loc, msg.ptr, v))
{
return false;
}
@@ -16171,11 +16724,13 @@ private bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
* Params:
* e = expression to check
* sc = context
+ * action = for error messages, what the address is needed for (e.g. ref return, indexing an array)
* Returns:
* true if the expression is addressable
*/
-bool checkAddressable(Expression e, Scope* sc)
+bool checkAddressable(Expression e, Scope* sc, const(char)* action)
{
+ //printf("checkAddressable() %s\n", e.toChars());
Expression ex = e;
while (true)
{
@@ -16183,11 +16738,11 @@ bool checkAddressable(Expression e, Scope* sc)
{
case EXP.dotVariable:
// https://issues.dlang.org/show_bug.cgi?id=22749
- // Error about taking address of any bit-field, regardless of
+ // Error about taking address of any bitfield, regardless of
// whether SCOPE.Cfile is set.
if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
{
- error(e.loc, "cannot take address of bit-field `%s`", bf.toChars());
+ sc.eSink.error(e.loc, "cannot %s bitfield `%s`", action, ex.toErrMsg());
return false;
}
goto case EXP.cast_;
@@ -16203,7 +16758,7 @@ bool checkAddressable(Expression e, Scope* sc)
continue;
case EXP.variable:
- if (sc.inCfile)
+ if (sc && sc.inCfile)
{
// C11 6.5.3.2: A variable that has its address taken cannot be
// stored in a register.
@@ -16211,10 +16766,7 @@ bool checkAddressable(Expression e, Scope* sc)
// or cast to an lvalue pointer cannot be stored in a register.
if (ex.isVarExp().var.storage_class & STC.register)
{
- if (e.isIndexExp())
- error(e.loc, "cannot index through register variable `%s`", ex.toErrMsg());
- else
- error(e.loc, "cannot take address of register variable `%s`", ex.toErrMsg());
+ sc.eSink.error(e.loc, "cannot %s register variable `%s`", action, ex.toErrMsg());
return false;
}
}
@@ -16275,7 +16827,7 @@ Expression getThisSkipNestedFuncs(Loc loc, Scope* sc, Dsymbol s, AggregateDeclar
{
n++;
e1 = new VarExp(loc, f.vthis);
- if (f.hasDualContext())
+ if (f.hasDualContext)
{
// (*__this)[i]
if (n > 1)
@@ -16382,7 +16934,7 @@ private bool fit(StructDeclaration sd, Loc loc, Scope* sc, Expressions* elements
return true;
const nfields = sd.nonHiddenFields();
- size_t offset = 0;
+ ulong bitoffset = 0;
for (size_t i = 0; i < elements.length; i++)
{
Expression e = (*elements)[i];
@@ -16401,7 +16953,13 @@ private bool fit(StructDeclaration sd, Loc loc, Scope* sc, Expressions* elements
return false;
}
VarDeclaration v = sd.fields[i];
- if (v.offset < offset)
+ // Overlap is checked by comparing bit offsets
+ ulong vbitoffset = v.offset * 8;
+ auto vbf = v.isBitFieldDeclaration();
+ if (vbf)
+ vbitoffset += vbf.bitOffset;
+
+ if (vbitoffset < bitoffset)
{
.error(loc, "overlapping initialization for `%s`", v.toChars());
if (!sd.isUnionDeclaration())
@@ -16416,7 +16974,11 @@ private bool fit(StructDeclaration sd, Loc loc, Scope* sc, Expressions* elements
const vsize = v.type.size();
if (vsize == SIZE_INVALID)
return false;
- offset = cast(uint)(v.offset + vsize);
+ // Bitsize of types are overridden by any bitfield widths.
+ if (vbf)
+ bitoffset = vbitoffset + vbf.fieldWidth;
+ else
+ bitoffset = vbitoffset + vsize * 8;
Type t = v.type;
if (stype)
@@ -16615,8 +17177,12 @@ Expression toBoolean(Expression exp, Scope* sc)
if (!t.isBoolean())
{
if (tb != Type.terror)
+ {
error(exp.loc, "expression `%s` of type `%s` does not have a boolean value",
exp.toChars(), t.toChars());
+ if (auto ts = tb.isTypeStruct())
+ errorSupplemental(ts.sym.loc, "perhaps add Cast Operator Overloading with `bool opCast(T : bool)() => ...`");
+ }
return ErrorExp.get();
}
return e;
@@ -17133,7 +17699,7 @@ bool checkDisabled(Declaration d, Loc loc, Scope* sc, bool isAliasedDeclaration
* postblit. Print the first field that has
* a disabled postblit.
*/
- if (postblit.isGenerated())
+ if (postblit.isGenerated)
{
auto sd = p.isStructDeclaration();
assert(sd);
@@ -17175,7 +17741,7 @@ bool checkDisabled(Declaration d, Loc loc, Scope* sc, bool isAliasedDeclaration
if (auto ctor = d.isCtorDeclaration())
{
//printf("checkDisabled() %s %s\n", ctor.toPrettyChars(), toChars(ctor.type));
- if (ctor.isCpCtor && ctor.isGenerated())
+ if (ctor.isCpCtor && ctor.isGenerated)
{
.error(loc, "generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", d.parent.toPrettyChars());
return true;
@@ -17185,6 +17751,39 @@ bool checkDisabled(Declaration d, Loc loc, Scope* sc, bool isAliasedDeclaration
return true;
}
+
+/*******************************************
+ * If variable has a constant expression initializer, get it.
+ * Otherwise, return null.
+ */
+Expression getConstInitializer(VarDeclaration vd, bool needFullType = true)
+{
+ assert(vd.type && vd._init);
+
+ // Ungag errors when not speculative
+ const oldgag = global.gag;
+ if (global.gag)
+ {
+ Dsymbol sym = vd.isMember();
+ if (sym && !sym.isSpeculative())
+ global.gag = 0;
+ }
+
+ if (vd._scope)
+ {
+ vd.inuse++;
+ vd._init = vd._init.initializerSemantic(vd._scope, vd.type, INITinterpret);
+ import dmd.semantic2 : lowerStaticAAs;
+ lowerStaticAAs(vd, vd._scope);
+ vd._scope = null;
+ vd.inuse--;
+ }
+
+ Expression e = vd._init.initializerToExpression(needFullType ? vd.type : null);
+ global.gag = oldgag;
+ return e;
+}
+
/*******************************************
* Helper function for the expansion of manifest constant.
*/
@@ -17200,6 +17799,8 @@ private Expression expandInitializer(VarDeclaration vd, Loc loc)
}
e = e.copy();
+ if (auto aae = e.isAssocArrayLiteralExp())
+ aae.lowering = null; // need to redo lowering as it contains temporary variables that must be renamed
e.loc = loc; // for better error message
return e;
}
@@ -17526,10 +18127,11 @@ void lowerNonArrayAggregate(StaticForeach sfe, Scope* sc)
Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()];
foreach (i; 0 .. nvars)
{
- foreach (params; pparams)
+ foreach (j, params; pparams)
{
auto p = sfe.aggrfe ? (*sfe.aggrfe.parameters)[i] : sfe.rangefe.param;
- params.push(new Parameter(aloc, p.storageClass, p.type, p.ident, null, null));
+ auto storageClass = j == 2 ? p.storageClass : p.storageClass & ~(STC.manifest | STC.alias_);
+ params.push(new Parameter(aloc, storageClass, p.type, p.ident, null, null));
}
}
Expression[2] res;
@@ -17574,12 +18176,12 @@ void lowerNonArrayAggregate(StaticForeach sfe, Scope* sc)
sfe.rangefe.upr = sfe.rangefe.upr.optimize(WANTvalue);
sfe.rangefe.upr = sfe.rangefe.upr.ctfeInterpret();
}
- auto s1 = new Statements();
+
auto stmts = new Statements();
if (tplty) stmts.push(new ExpStatement(sfe.loc, tplty.sym));
stmts.push(new ReturnStatement(aloc, res[0]));
- s1.push(sfe.createForeach(aloc, pparams[0], new CompoundStatement(aloc, stmts)));
- s1.push(new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0)));
+ auto s1 = new Statements(sfe.createForeach(aloc, pparams[0], new CompoundStatement(aloc, stmts)),
+ new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0)));
Type ety = new TypeTypeof(aloc, sfe.wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
auto aty = ety.arrayOf();
auto idres = Identifier.generateId("__res");
@@ -17737,6 +18339,46 @@ int include(Condition c, Scope* sc)
return v.result;
}
+/*******************************************
+ * Look for constructor declaration.
+ */
+Dsymbol searchCtor(AggregateDeclaration ad)
+{
+ auto s = ad.search(Loc.initial, Id.ctor);
+ if (s)
+ {
+ if (!(s.isCtorDeclaration() ||
+ s.isTemplateDeclaration() ||
+ s.isOverloadSet()))
+ {
+ error(s.loc, "%s name `__ctor` is not allowed", s.kind);
+ errorSupplemental(s.loc, "identifiers starting with `__` are reserved for internal use");
+ ad.errors = true;
+ s = null;
+ }
+ }
+ if (s && s.toParent() != ad)
+ s = null; // search() looks through ancestor classes
+ if (s)
+ {
+ // Finish all constructors semantics to determine this.noDefaultCtor.
+ static int searchCtor(Dsymbol s, void*)
+ {
+ auto f = s.isCtorDeclaration();
+ if (f && f.semanticRun == PASS.initial)
+ f.dsymbolSemantic(null);
+ return 0;
+ }
+
+ for (size_t i = 0; i < ad.members.length; i++)
+ {
+ auto sm = (*ad.members)[i];
+ sm.apply(&searchCtor, null);
+ }
+ }
+ return s;
+}
+
private extern(C++) class IncludeVisitor : Visitor {
alias visit = Visitor.visit;
@@ -17869,3 +18511,334 @@ private extern(C++) class IncludeVisitor : Visitor {
result = (sic.inc == Include.yes);
}
}
+
+/***************************************
+* mark ArrayExp on the left side of an assignment recursively as modifiable before
+* semantic analysis to defer potential lowerings into the assignment when
+* the right side of the expression is analyzed, too, i.e.
+*
+* a[i][j] = 1
+*
+* is parsed to
+*
+* AssignExp(ArrayExp(ArrayExp(Id('a'), Id('i')), Id('j')), 1)
+*
+* ArrayExp is converted to IndexExp during semantic analysis, but the lowering
+* for IndexExp on associative arrays is different for reading or writing. For
+* struct types, it can even depend on the right hand side of an assignment.
+*
+* Params:
+* ae = the ArrayExp to mark
+*/
+void markArrayExpModifiable(ArrayExp ae)
+{
+ ae.modifiable = true;
+ for (auto ae1 = ae.e1.isArrayExp(); ae1; ae1 = ae1.e1.isArrayExp())
+ ae1.modifiable = true;
+}
+
+/***************************************
+* convert an IndexExp on an associative array `aa[key]`
+* to `_d_aaGetRvalueX!(K,V)(aa, key)[0]`
+*
+* Params:
+* ie = the IndexExp to lower
+* sc = context
+* Returns:
+* on success, the lowered expression that is still an IndexExp
+* with its `loweredFrom` field set to the original expression
+* on failure, null is returned
+*/
+Expression lowerAAIndexRead(IndexExp ie, Scope* sc)
+{
+ Expression ce = buildAAIndexRValueX(ie.e1.type, ie.e1, ie.e2, sc);
+ if (!ce)
+ return ie;
+ auto rv = new IndexExp(ie.loc, ce, IntegerExp.literal!0);
+ rv.loweredFrom = ie;
+
+ return rv.expressionSemantic(sc);
+}
+
+// helper for lowerAAIndexRead and revertIndexAssignToRvalues
+// to rewrite `aa[key]` to `_d_aaGetRvalueX!(K,V)(aa, key)[0]`
+private Expression buildAAIndexRValueX(Type t, Expression eaa, Expression ekey, Scope* sc)
+{
+ auto taa = t.toBasetype().isTypeAArray();
+ if (!taa)
+ return null;
+
+ auto loc = eaa.loc;
+ Identifier hook = Id._d_aaGetRvalueX;
+ if (!verifyHookExist(loc, *sc, hook, "indexing AA"))
+ return null;
+
+ Expression func = new IdentifierExp(loc, Id.empty);
+ func = new DotIdExp(loc, func, Id.object);
+ auto tiargs = new Objects(taa.index, taa.next);
+ func = new DotTemplateInstanceExp(loc, func, hook, tiargs);
+
+ Expression e0;
+ auto arguments = new Expressions(eaa, ekey);
+ auto call = new CallExp(loc, func, arguments);
+ e0 = Expression.combine(e0, call);
+
+ if (arrayBoundsCheck(sc.func))
+ {
+ // __aaget = _d_aaGetRvalueX(aa, key), __aaget ? __aaget : onRangeError(__FILE__, __LINE__)
+ auto ei = new ExpInitializer(loc, e0);
+ auto vartmp = Identifier.generateId("__aaget");
+ auto vardecl = new VarDeclaration(loc, null, vartmp, ei, STC.exptemp);
+ auto declexp = new DeclarationExp(loc, vardecl);
+
+ //Expression idrange = new IdentifierExp(loc, Identifier.idPool("_d_arraybounds"));
+ Expression idrange = new IdentifierExp(loc, Id.empty);
+ idrange = new DotIdExp(loc, idrange, Id.object);
+ idrange = new DotIdExp(loc, idrange, Identifier.idPool("_d_arraybounds"));
+ auto locargs = new Expressions(new FileInitExp(loc, EXP.file), new LineInitExp(loc));
+ auto ex = new CallExp(loc, idrange, locargs);
+
+ auto idvar1 = new IdentifierExp(loc, vartmp);
+ auto idvar2 = new IdentifierExp(loc, vartmp);
+ auto cond = new CondExp(loc, idvar1, idvar2, ex);
+ auto comma = new CommaExp(loc, declexp, cond);
+ return comma;
+ }
+ return e0;
+}
+
+/***************************************
+* in a multi-dimensional array assignment without the out-most access being to an AA,
+* convert AA accesses back to rvalues
+*
+* Params:
+* ie = the IndexExp to lower
+* sc = context
+* Returns:
+* the lowered expression if the assignment was actually on an associative array,
+* the original expression otherwise,
+* an ErorrExp on failure
+*/
+Expression revertIndexAssignToRvalues(IndexExp ie, Scope* sc)
+{
+ if (auto ie1 = ie.e1.isIndexExp())
+ {
+ // convert inner access first, otherwise we'd have to crawl into the lowered AST
+ ie.e1 = revertIndexAssignToRvalues(ie1, sc);
+ }
+ if (!ie.e1.type.isTypeAArray())
+ return ie;
+
+ assert(ie.modifiable);
+ return lowerAAIndexRead(ie, sc);
+}
+
+// helper for rewriteAAIndexAssign
+private Expression implicitConvertToStruct(Expression ev, StructDeclaration sd, Scope* sc)
+{
+ Type t2 = ev.type.toBasetype();
+ Expression ey = null;
+ if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
+ {
+ ey = ev;
+ }
+ else if (!ev.implicitConvTo(sd.type) && sd.ctor)
+ {
+ // Look for implicit constructor call
+ // Rewrite as S().ctor(e2)
+ ey = new StructLiteralExp(ev.loc, sd, null);
+ ey = new DotIdExp(ev.loc, ey, Id.ctor);
+ ey = new CallExp(ev.loc, ey, ev);
+ ey = ey.trySemantic(sc);
+ }
+ return ey;
+}
+
+// helper for rewriteIndexAssign
+private Expression rewriteAAIndexAssign(BinExp exp, Scope* sc, ref Type[2] aliasThisStop)
+{
+ auto ie = exp.e1.isIndexExp();
+ assert(ie);
+ auto loc = ie.e1.loc;
+
+ Identifier hook = Id._d_aaGetY;
+ if (!verifyHookExist(loc, *sc, hook, "modifying AA"))
+ return ErrorExp.get();
+
+ bool escape = checkNewEscape(*sc, exp.e2, false);
+ if (escape)
+ return ErrorExp.get();
+ auto gcexp = exp.checkGC(sc);
+ if (gcexp.op == EXP.error)
+ return gcexp;
+
+ // build `bool __aafound, auto __aaget = _d_aaGetY(aa, key, found);`
+ auto idfound = Identifier.generateId("__aafound");
+ auto varfound = new VarDeclaration(loc, Type.tbool, idfound, null, STC.temp | STC.ctfe);
+ auto declfound = new DeclarationExp(loc, varfound);
+
+ // handle side effects before the actual AA insert
+ Expression e0 = declfound.expressionSemantic(sc);
+ Expression eaa = ie.e1;
+ // find the AA of multi dimensional access
+ for (auto ieaa = ie.e1.isIndexExp(); ieaa && ieaa.e1.type.isTypeAArray(); ieaa = ieaa.e1.isIndexExp())
+ eaa = ieaa.e1;
+ eaa = extractSideEffect(sc, "__aatmp", e0, eaa);
+ // collect all keys of multi dimensional access
+ Expressions ekeys;
+ ekeys.push(ie.e2);
+ for (auto ieaa = ie.e1.isIndexExp(); ieaa && ieaa.e1.type.isTypeAArray(); ieaa = ieaa.e1.isIndexExp())
+ ekeys.push(ieaa.e2);
+ foreach (ekey; ekeys)
+ {
+ Type tidx = ekey.type.toBasetype();
+ if (tidx.ty == Tarray && tidx.nextOf().isMutable())
+ {
+ error(loc, "associative arrays can only be assigned values with immutable keys, not `%s`", tidx.toChars());
+ return ErrorExp.get();
+ }
+ }
+ // extract side effects in lexical order
+ for (size_t i = ekeys.length; i > 0; --i)
+ ekeys[i-1] = extractSideEffect(sc, "__aakey", e0, ekeys[i-1]);
+ Expression ev = extractSideEffect(sc, "__aaval", e0, exp.e2);
+
+ // generate series of calls to _d_aaGetY
+ for (size_t i = ekeys.length; i > 0; --i)
+ {
+ auto taa = eaa.type.isTypeAArray();
+ assert (taa); // type must not have changed during rewrite
+ Expression func = new IdentifierExp(loc, Id.empty);
+ func = new DotIdExp(loc, func, Id.object);
+ auto tiargs = new Objects(taa.index, taa.next);
+ func = new DotTemplateInstanceExp(loc, func, hook, tiargs);
+
+ auto arguments = new Expressions(eaa, ekeys[i-1], new IdentifierExp(loc, idfound));
+ eaa = new CallExp(loc, func, arguments);
+ if (i > 1)
+ {
+ // extractSideEffect() cannot be used to ref the IndexExp,
+ // because ConstructExp below will not insert a postblit
+ auto ie1 = new IndexExp(loc, eaa, IntegerExp.literal!0);
+ ie1.modifiable = true;
+ ie1.loweredFrom = eaa;
+ eaa = ie1;
+ }
+ eaa = eaa.expressionSemantic(sc);
+ if (eaa.op == EXP.error)
+ return eaa;
+ }
+ Expression eg = extractSideEffect(sc, "__aaget", e0, eaa);
+ auto ie1 = new IndexExp(loc, eg, IntegerExp.literal!0);
+ ie1.modifiable = true;
+ ie1.loweredFrom = ie;
+ auto ex = ie1.expressionSemantic(sc);
+ ex = ex.optimize(WANTvalue);
+ if (ex.op == EXP.error)
+ return ex;
+ if (!exp.isAssignExp())
+ {
+ // modifying assignments work with zero-initialized inserted value
+ BinExp bex = cast(BinExp)exp.copy();
+ bex.e1 = ex;
+ bex.e2 = ev;
+ ex = Expression.combine(e0, bex);
+ ex.isCommaExp().originalExp = exp;
+ return ex.expressionSemantic(sc);
+ }
+ AssignExp ae = new AssignExp(loc, ex, ev);
+ auto ts = ie.type.isTypeStruct();
+ if (Expression overexp = ts ? ae.opOverloadAssign(sc, aliasThisStop) : null)
+ {
+ if (overexp.op == EXP.error)
+ return overexp;
+ if (auto ey = implicitConvertToStruct(ev, ts.sym, sc))
+ {
+ // __aafound ? __aaget.opAssign(__aaval) : __aaget.ctor(__aaval)
+ ey = new ConstructExp(loc, ex, ey);
+ ey = ey.expressionSemantic(sc);
+ if (ey.op == EXP.error)
+ return ey;
+ ex = overexp;
+
+ // https://issues.dlang.org/show_bug.cgi?id=14144
+ // The whole expression should have the common type
+ // of opAssign() return and assigned AA entry.
+ // Even if there's no common type, expression should be typed as void.
+ if (!typeMerge(sc, EXP.question, ex, ey))
+ {
+ ex = new CastExp(ex.loc, ex, Type.tvoid);
+ ey = new CastExp(ey.loc, ey, Type.tvoid);
+ }
+ Expression condfound = new IdentifierExp(loc, idfound);
+ ex = new CondExp(loc, condfound, ex, ey);
+ ex = Expression.combine(e0, ex);
+ ex.isCommaExp().originalExp = exp;
+ }
+ else
+ {
+ // write back to _aaGetRValueX(aa, key)[0].opAssign(__aaval)
+ auto call = buildAAIndexRValueX(ie.e1.type, ie.e1, ie.e2, sc);
+ ie1 = new IndexExp(loc, call, IntegerExp.literal!0);
+ ie1.loweredFrom = ie;
+ ex = ie1.expressionSemantic(sc);
+ ex = ex.optimize(WANTvalue);
+ ae = new AssignExp(loc, ex, ev);
+ ex = ae.opOverloadAssign(sc, aliasThisStop);
+ assert(ex);
+ }
+ }
+ else
+ {
+ ex = Expression.combine(e0, ae);
+ ex.isCommaExp().originalExp = exp;
+ }
+ ex = ex.expressionSemantic(sc);
+ return ex;
+}
+
+/***************************************
+* rewrite multi-dimensional array modifying assignments on associative arrays
+*
+* Params:
+* exp = the assignment expression, AssignExp, ConstructExp, BinAssignExp or PostExp
+* sc = context
+* aliasThisStop = for recursion check on `alias this`
+* Returns:
+* the lowered expression if the assignment was actually on an associative array,
+* null if no modifying index expression was found on the lhs of the assignemnt
+*/
+Expression rewriteIndexAssign(BinExp exp, Scope* sc, Type[2] aliasThisStop)
+{
+ if (auto ie1 = exp.e1.isIndexExp())
+ {
+ if (ie1.e1.type.isTypeAArray())
+ {
+ if (exp.op == EXP.construct)
+ exp.e1 = exp.e1.toLvalue(sc, "initialize");
+ else
+ exp.e1 = exp.e1.modifiableLvalue(sc);
+ if (exp.e1.op == EXP.error)
+ return exp.e1;
+ assert(exp.e1 == ie1);
+ assert(ie1.modifiable);
+ return rewriteAAIndexAssign(exp, sc, aliasThisStop);
+ }
+ exp.e1 = revertIndexAssignToRvalues(ie1, sc);
+ }
+ return null;
+}
+
+/****************************************
+ * Get bitfield from expression.
+ */
+BitFieldDeclaration isBitField(Expression e)
+{
+ if (auto ve = e.isVarExp())
+ return ve.var.isBitFieldDeclaration();
+
+ if (auto dve = e.isDotVarExp())
+ return dve.var.isBitFieldDeclaration();
+
+ return null;
+}
diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d
index 2ccb1d25497d..8116dda79d74 100644
--- a/gcc/d/dmd/file_manager.d
+++ b/gcc/d/dmd/file_manager.d
@@ -175,121 +175,105 @@ nothrow:
whichPathFoundThis = -1;
- // see if we should check for the module locally.
- bool checkLocal = pathCache.pathExists(filename);
- const sdi = FileName.forceExt(filename, hdr_ext);
- if (checkLocal && FileName.exists(sdi) == 1)
- return sdi;
- scope(exit) FileName.free(sdi.ptr);
-
- const sd = FileName.forceExt(filename, mars_e[...]
[diff truncated at 524288 bytes]
More information about the Gcc-cvs
mailing list