aboutsummaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d')
-rw-r--r--gcc/d/ChangeLog591
-rw-r--r--gcc/d/ChangeLog-20061
-rw-r--r--gcc/d/ChangeLog-20071
-rw-r--r--gcc/d/ChangeLog-20081
-rw-r--r--gcc/d/ChangeLog-20091
-rw-r--r--gcc/d/ChangeLog-20101
-rw-r--r--gcc/d/ChangeLog-20111
-rw-r--r--gcc/d/ChangeLog-20121
-rw-r--r--gcc/d/ChangeLog-20131
-rw-r--r--gcc/d/ChangeLog-20141
-rw-r--r--gcc/d/ChangeLog-20151
-rw-r--r--gcc/d/ChangeLog-20161
-rw-r--r--gcc/d/ChangeLog-20171
-rw-r--r--gcc/d/ChangeLog-20221
-rw-r--r--gcc/d/ChangeLog-20231
-rw-r--r--gcc/d/ChangeLog-2024294
-rw-r--r--gcc/d/Make-lang.in44
-rw-r--r--gcc/d/config-lang.in2
-rw-r--r--gcc/d/d-attribs.cc4
-rw-r--r--gcc/d/d-builtins.cc29
-rw-r--r--gcc/d/d-codegen.cc145
-rw-r--r--gcc/d/d-compiler.cc47
-rw-r--r--gcc/d/d-convert.cc31
-rw-r--r--gcc/d/d-ctfloat.cc8
-rw-r--r--gcc/d/d-diagnostic.cc28
-rw-r--r--gcc/d/d-frontend.cc8
-rw-r--r--gcc/d/d-frontend.h2
-rw-r--r--gcc/d/d-gimplify.cc2
-rw-r--r--gcc/d/d-incpath.cc66
-rw-r--r--gcc/d/d-lang.cc63
-rw-r--r--gcc/d/d-longdouble.cc14
-rw-r--r--gcc/d/d-port.cc6
-rw-r--r--gcc/d/d-spec.cc52
-rw-r--r--gcc/d/d-system.h2
-rw-r--r--gcc/d/d-target-def.h2
-rw-r--r--gcc/d/d-target.cc40
-rw-r--r--gcc/d/d-target.def2
-rw-r--r--gcc/d/d-target.h2
-rw-r--r--gcc/d/d-tree.def2
-rw-r--r--gcc/d/d-tree.h10
-rw-r--r--gcc/d/decl.cc104
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/README.md47
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/access.d15
-rw-r--r--gcc/d/dmd/aggregate.d253
-rw-r--r--gcc/d/dmd/aggregate.h19
-rw-r--r--gcc/d/dmd/aliasthis.d10
-rw-r--r--gcc/d/dmd/aliasthis.h2
-rw-r--r--gcc/d/dmd/arrayop.d31
-rw-r--r--gcc/d/dmd/arraytypes.d6
-rw-r--r--gcc/d/dmd/arraytypes.h2
-rw-r--r--gcc/d/dmd/ast_node.d6
-rw-r--r--gcc/d/dmd/ast_node.h2
-rw-r--r--gcc/d/dmd/astenums.d40
-rw-r--r--gcc/d/dmd/attrib.d585
-rw-r--r--gcc/d/dmd/attrib.h45
-rw-r--r--gcc/d/dmd/attribsem.d87
-rw-r--r--gcc/d/dmd/blockexit.d109
-rw-r--r--gcc/d/dmd/builtin.d8
-rw-r--r--gcc/d/dmd/canthrow.d24
-rw-r--r--gcc/d/dmd/chkformat.d33
-rw-r--r--gcc/d/dmd/clone.d587
-rw-r--r--gcc/d/dmd/common/bitfields.d78
-rw-r--r--gcc/d/dmd/common/charactertables.d268
-rw-r--r--gcc/d/dmd/common/charactertables.h29
-rw-r--r--gcc/d/dmd/common/file.d177
-rw-r--r--gcc/d/dmd/common/identifiertables.d4241
-rw-r--r--gcc/d/dmd/common/outbuffer.d26
-rw-r--r--gcc/d/dmd/common/outbuffer.h2
-rw-r--r--gcc/d/dmd/common/smallbuffer.d6
-rw-r--r--gcc/d/dmd/compiler.d7
-rw-r--r--gcc/d/dmd/compiler.h2
-rw-r--r--gcc/d/dmd/cond.d434
-rw-r--r--gcc/d/dmd/cond.h9
-rw-r--r--gcc/d/dmd/constfold.d177
-rw-r--r--gcc/d/dmd/cparse.d473
-rw-r--r--gcc/d/dmd/ctfe.h5
-rw-r--r--gcc/d/dmd/ctfeexpr.d128
-rw-r--r--gcc/d/dmd/ctorflow.d6
-rw-r--r--gcc/d/dmd/cxxfrontend.d175
-rw-r--r--gcc/d/dmd/dcast.d625
-rw-r--r--gcc/d/dmd/dclass.d79
-rw-r--r--gcc/d/dmd/declaration.d703
-rw-r--r--gcc/d/dmd/declaration.h89
-rw-r--r--gcc/d/dmd/delegatize.d17
-rw-r--r--gcc/d/dmd/denum.d31
-rw-r--r--gcc/d/dmd/deps.d141
-rw-r--r--gcc/d/dmd/dimport.d48
-rw-r--r--gcc/d/dmd/dinterpret.d147
-rw-r--r--gcc/d/dmd/dmacro.d14
-rw-r--r--gcc/d/dmd/dmodule.d142
-rw-r--r--gcc/d/dmd/doc.d192
-rw-r--r--gcc/d/dmd/doc.h2
-rw-r--r--gcc/d/dmd/dscope.d229
-rw-r--r--gcc/d/dmd/dstruct.d220
-rw-r--r--gcc/d/dmd/dsymbol.d513
-rw-r--r--gcc/d/dmd/dsymbol.h168
-rw-r--r--gcc/d/dmd/dsymbolsem.d1969
-rw-r--r--gcc/d/dmd/dtemplate.d1132
-rw-r--r--gcc/d/dmd/dtoh.d64
-rw-r--r--gcc/d/dmd/dversion.d68
-rw-r--r--gcc/d/dmd/entity.d6
-rw-r--r--gcc/d/dmd/enum.h7
-rw-r--r--gcc/d/dmd/enumsem.d32
-rw-r--r--gcc/d/dmd/errors.d109
-rw-r--r--gcc/d/dmd/errors.h19
-rw-r--r--gcc/d/dmd/errorsink.d123
-rw-r--r--gcc/d/dmd/escape.d1372
-rw-r--r--gcc/d/dmd/expression.d780
-rw-r--r--gcc/d/dmd/expression.h108
-rw-r--r--gcc/d/dmd/expressionsem.d4963
-rw-r--r--gcc/d/dmd/file_manager.d323
-rw-r--r--gcc/d/dmd/func.d2287
-rw-r--r--gcc/d/dmd/funcsem.d1939
-rw-r--r--gcc/d/dmd/globals.d102
-rw-r--r--gcc/d/dmd/globals.h110
-rw-r--r--gcc/d/dmd/gluelayer.d12
-rw-r--r--gcc/d/dmd/hdrgen.d373
-rw-r--r--gcc/d/dmd/hdrgen.h2
-rw-r--r--gcc/d/dmd/iasm.d12
-rw-r--r--gcc/d/dmd/iasmgcc.d239
-rw-r--r--gcc/d/dmd/id.d89
-rw-r--r--gcc/d/dmd/id.h2
-rw-r--r--gcc/d/dmd/identifier.d109
-rw-r--r--gcc/d/dmd/identifier.h2
-rw-r--r--gcc/d/dmd/impcnvtab.d6
-rw-r--r--gcc/d/dmd/imphint.d8
-rw-r--r--gcc/d/dmd/import.h3
-rw-r--r--gcc/d/dmd/importc.d18
-rw-r--r--gcc/d/dmd/init.d37
-rw-r--r--gcc/d/dmd/init.h7
-rw-r--r--gcc/d/dmd/initsem.d361
-rw-r--r--gcc/d/dmd/inline.d6
-rw-r--r--gcc/d/dmd/intrange.d90
-rw-r--r--gcc/d/dmd/json.d93
-rw-r--r--gcc/d/dmd/json.h2
-rw-r--r--gcc/d/dmd/lambdacomp.d102
-rw-r--r--gcc/d/dmd/lexer.d465
-rw-r--r--gcc/d/dmd/location.d454
-rw-r--r--gcc/d/dmd/mangle.h2
-rw-r--r--gcc/d/dmd/mangle/basic.d (renamed from gcc/d/dmd/basicmangle.d)8
-rw-r--r--gcc/d/dmd/mangle/cpp.d (renamed from gcc/d/dmd/cppmangle.d)126
-rw-r--r--gcc/d/dmd/mangle/package.d (renamed from gcc/d/dmd/dmangle.d)37
-rw-r--r--gcc/d/dmd/module.h20
-rw-r--r--gcc/d/dmd/mtype.d1502
-rw-r--r--gcc/d/dmd/mtype.h191
-rw-r--r--gcc/d/dmd/mustuse.d31
-rw-r--r--gcc/d/dmd/nogc.d140
-rw-r--r--gcc/d/dmd/nspace.d14
-rw-r--r--gcc/d/dmd/nspace.h3
-rw-r--r--gcc/d/dmd/ob.d180
-rw-r--r--gcc/d/dmd/objc.d87
-rw-r--r--gcc/d/dmd/objc.h2
-rw-r--r--gcc/d/dmd/opover.d2135
-rw-r--r--gcc/d/dmd/optimize.d106
-rw-r--r--gcc/d/dmd/parse.d560
-rw-r--r--gcc/d/dmd/postordervisitor.d153
-rw-r--r--gcc/d/dmd/pragmasem.d45
-rw-r--r--gcc/d/dmd/printast.d12
-rw-r--r--gcc/d/dmd/root/aav.d6
-rw-r--r--gcc/d/dmd/root/array.d8
-rw-r--r--gcc/d/dmd/root/array.h6
-rw-r--r--gcc/d/dmd/root/bitarray.d6
-rw-r--r--gcc/d/dmd/root/bitarray.h4
-rw-r--r--gcc/d/dmd/root/complex.d6
-rw-r--r--gcc/d/dmd/root/complex_t.h2
-rw-r--r--gcc/d/dmd/root/ctfloat.d6
-rw-r--r--gcc/d/dmd/root/ctfloat.h2
-rw-r--r--gcc/d/dmd/root/dcompat.h4
-rw-r--r--gcc/d/dmd/root/dsystem.h2
-rw-r--r--gcc/d/dmd/root/file.d94
-rw-r--r--gcc/d/dmd/root/filename.d46
-rw-r--r--gcc/d/dmd/root/filename.h6
-rw-r--r--gcc/d/dmd/root/hash.d6
-rw-r--r--gcc/d/dmd/root/longdouble.d4
-rw-r--r--gcc/d/dmd/root/optional.d6
-rw-r--r--gcc/d/dmd/root/optional.h6
-rw-r--r--gcc/d/dmd/root/port.d6
-rw-r--r--gcc/d/dmd/root/port.h2
-rw-r--r--gcc/d/dmd/root/region.d6
-rw-r--r--gcc/d/dmd/root/rmem.d11
-rw-r--r--gcc/d/dmd/root/rmem.h2
-rw-r--r--gcc/d/dmd/root/speller.d6
-rw-r--r--gcc/d/dmd/root/string.d237
-rw-r--r--gcc/d/dmd/root/stringtable.d6
-rw-r--r--gcc/d/dmd/root/utf.d281
-rw-r--r--gcc/d/dmd/rootobject.d6
-rw-r--r--gcc/d/dmd/rootobject.h2
-rw-r--r--gcc/d/dmd/safe.d469
-rw-r--r--gcc/d/dmd/sapply.d179
-rw-r--r--gcc/d/dmd/scope.h71
-rw-r--r--gcc/d/dmd/semantic2.d137
-rw-r--r--gcc/d/dmd/semantic3.d318
-rw-r--r--gcc/d/dmd/sideeffect.d33
-rw-r--r--gcc/d/dmd/statement.d242
-rw-r--r--gcc/d/dmd/statement.h80
-rw-r--r--gcc/d/dmd/statementsem.d398
-rw-r--r--gcc/d/dmd/staticassert.d26
-rw-r--r--gcc/d/dmd/staticassert.h4
-rw-r--r--gcc/d/dmd/staticcond.d6
-rw-r--r--gcc/d/dmd/stmtstate.d6
-rw-r--r--gcc/d/dmd/target.d35
-rw-r--r--gcc/d/dmd/target.h21
-rw-r--r--gcc/d/dmd/template.h28
-rw-r--r--gcc/d/dmd/templateparamsem.d15
-rw-r--r--gcc/d/dmd/templatesem.d157
-rw-r--r--gcc/d/dmd/timetrace.d82
-rw-r--r--gcc/d/dmd/tokens.d33
-rw-r--r--gcc/d/dmd/tokens.h6
-rw-r--r--gcc/d/dmd/traits.d151
-rw-r--r--gcc/d/dmd/typesem.d1632
-rw-r--r--gcc/d/dmd/typinf.d87
-rw-r--r--gcc/d/dmd/typinf.h10
-rw-r--r--gcc/d/dmd/utils.d94
-rw-r--r--gcc/d/dmd/version.h10
-rw-r--r--gcc/d/dmd/visitor.h2
-rw-r--r--gcc/d/dmd/visitor/foreachvar.d (renamed from gcc/d/dmd/foreachvar.d)11
-rw-r--r--gcc/d/dmd/visitor/package.d (renamed from gcc/d/dmd/visitor.d)24
-rw-r--r--gcc/d/dmd/visitor/parsetime.d (renamed from gcc/d/dmd/parsetimevisitor.d)2
-rw-r--r--gcc/d/dmd/visitor/permissive.d (renamed from gcc/d/dmd/permissivevisitor.d)4
-rw-r--r--gcc/d/dmd/visitor/postorder.d318
-rw-r--r--gcc/d/dmd/visitor/statement_rewrite_walker.d (renamed from gcc/d/dmd/statement_rewrite_walker.d)8
-rw-r--r--gcc/d/dmd/visitor/transitive.d (renamed from gcc/d/dmd/transitivevisitor.d)20
-rw-r--r--gcc/d/expr.cc193
-rw-r--r--gcc/d/gdc.texi10
-rw-r--r--gcc/d/implement-d.texi10
-rw-r--r--gcc/d/imports.cc12
-rw-r--r--gcc/d/intrinsics.cc2
-rw-r--r--gcc/d/intrinsics.def2
-rw-r--r--gcc/d/lang-specs.h4
-rw-r--r--gcc/d/lang.opt13
-rw-r--r--gcc/d/lang.opt.urls30
-rw-r--r--gcc/d/longdouble.h2
-rw-r--r--gcc/d/modules.cc23
-rw-r--r--gcc/d/runtime.cc2
-rw-r--r--gcc/d/runtime.def6
-rw-r--r--gcc/d/toir.cc18
-rw-r--r--gcc/d/typeinfo.cc172
-rw-r--r--gcc/d/types.cc50
240 files changed, 24460 insertions, 18084 deletions
diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog
index e1bfdde..b6815d3 100644
--- a/gcc/d/ChangeLog
+++ b/gcc/d/ChangeLog
@@ -1,227 +1,432 @@
-2024-07-21 Sam James <sam@gentoo.org>
+2025-04-29 Iain Buclaw <ibuclaw@gdcproject.org>
- * Make-lang.in (WARN_DFLAGS): Drop NOCOMMON_FLAG.
+ PR d/103044
+ * d-tree.h (build_clear_padding_call): New prototype.
+ * d-codegen.cc (build_clear_padding_call): New function.
+ (build_memset_call): Remove generated call to __builtin_memcpy.
+ (build_address): Replace generated call to __builtin_memset with
+ __builtin_clear_padding.
+ (build_array_from_exprs): Likewise.
+ * expr.cc (ExprVisitor::visit (AssignExp *)): Remove generated call to
+ __builtin_memset.
+ (ExprVisitor::visit (ArrayLiteralExp *)): Likewise. Insert call to
+ __builtin_clear_padding after copying array into GC memory.
+ (ExprVisitor::visit (StructLiteralExp *)): Remove generated call to
+ __builtin_memset.
+ * toir.cc (IRVisitor::visit (ReturnStatement *)): Likewise.
-2024-06-05 Kewen Lin <linkw@linux.ibm.com>
- Iain Buclaw <ibuclaw@gdcproject.org>
+2025-04-17 Iain Buclaw <ibuclaw@gdcproject.org>
- * d-target.cc (Target::_init): Use int_size_in_bytes of
- long_double_type_node to replace the expression with
- LONG_DOUBLE_TYPE_SIZE for c.long_doublesize assignment.
+ * dmd/MERGE: Merge upstream dmd 956e73d64e.
-2024-04-19 Iain Buclaw <ibuclaw@gdcproject.org>
+2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org>
- PR d/111650
- * decl.cc (get_fndecl_arguments): Move generation of frame type to ...
- (DeclVisitor::visit (FuncDeclaration *)): ... here, after the call to
- build_closure.
+ PR d/119826
+ * types.cc (TypeVisitor::visit (TypeEnum *)): Propagate flags of main
+ enum types to all forward-referenced variants.
-2024-04-06 Iain Buclaw <ibuclaw@gdcproject.org>
+2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org>
- * dmd/MERGE: Merge upstream dmd b65767825f.
- * dmd/VERSION: Bump version to v2.108.0.
+ PR d/119799
+ * decl.cc (DeclVisitor::visit (VarDeclaration *)): Check front-end
+ type size before building the VAR_DECL. Allow C symbols to have a
+ size of `0'.
-2024-03-17 Iain Buclaw <ibuclaw@gdcproject.org>
+2025-04-15 Iain Buclaw <ibuclaw@gdcproject.org>
- * dmd/MERGE: Merge upstream dmd 855353a1d9.
- * dmd/VERSION:
+ PR d/119817
+ * imports.cc (ImportVisitor::visit (OverloadSet *)): Don't push
+ NULL_TREE to vector of import symbols.
-2024-03-10 Iain Buclaw <ibuclaw@gdcproject.org>
+2025-04-12 Iain Buclaw <ibuclaw@gdcproject.org>
- PR d/112285
- PR d/112290
- * d-target.cc (Target::preferPassByRef): Return true for all static
- array and struct types.
+ PR d/109023
+ * d-compiler.cc: Include dmd/errors.h.
+ (Compiler::onImport): Implement.
+ * d-lang.cc (d_handle_option): Handle -finclude-imports.
+ (d_parse_file): Run semantic on included imports.
+ * gdc.texi: Document -finclude-imports.
+ * lang.opt: Add finclude-imports.
+ * lang.opt.urls: Regenerate.
-2024-03-03 Iain Buclaw <ibuclaw@gdcproject.org>
+2025-04-12 Iain Buclaw <ibuclaw@gdcproject.org>
- * dmd/MERGE: Merge upstream dmd f8bae04558.
- * dmd/VERSION: Bump version to v2.108.0-beta.1.
+ PR d/119758
+ * d-lang.cc (d_parse_file): Use endswith in test for -fonly= argument.
+ * d-spec.cc (lang_specific_driver): Rework -fonly= and pass all input
+ files to the front-end compiler when the option is seen.
+
+2025-04-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 1b34fea478.
+
+2025-04-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/118309
+ * modules.cc: Include debug.h
+ (d_finish_compilation): Call debug_hooks->type_decl on all TYPE_DECLs.
+ * types.cc: Remove toplev.h include.
+ (finish_aggregate_type): Don't call rest_of_type_compilation or
+ rest_of_decl_compilation on type.
+ (TypeVisitor::visit (TypeEnum *)): Likewise.
+
+2025-04-09 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/117832
+ * d-tree.h (build_padded_constructor): New prototype.
+ * d-codegen.cc (build_padded_constructor): New function.
+ (d_array_value): Call it.
+ (build_memset_call): Likewise.
+ (build_struct_literal): Likewise.
+ (underlying_complex_expr): Likewise.
+ (build_array_from_val): Likewise.
+ (build_array_from_exprs): Likewise.
+ (d_build_call): Likewise.
+ (get_frame_for_symbol): Likewise.
+ * d-convert.cc (convert_for_rvalue): Likewise.
+ (convert_for_assignment): Likewise.
+ * decl.cc (class DeclVisitor): Likewise.
+ * expr.cc (class ExprVisitor): Likewise.
+ * modules.cc (layout_moduleinfo): Likewise.
+ * typeinfo.cc (class TypeInfoVisitor): Likewise.
+
+2025-04-08 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 51816cd01d.
+
+2025-04-06 Sandra Loosemore <sloosemore@baylibre.com>
+
+ * lang.opt.urls: Regenerate.
+
+2025-04-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd ed17b3e95d.
+
+2025-03-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd c6863be720.
+ * dmd/VERSION: Bump version to v2.111.0.
+
+2025-03-31 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/117002
+ * decl.cc (aggregate_initializer_decl): Set explicit decl alignment of
+ class instance.
+ * expr.cc (ExprVisitor::visit (NewExp *)): Likewise.
+ * types.cc (TypeVisitor::visit (TypeClass *)): Mark the record type of
+ classes as packed.
+
+2025-03-30 Sandra Loosemore <sloosemore@baylibre.com>
+
+ * lang.opt.urls: Regenerate.
+
+2025-03-26 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 02a64d2e13.
+
+2025-03-23 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/117621
+ * types.cc (finish_aggregate_type): Propagate TYPE_PACKED to variants.
+
+2025-03-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 032e24446b.
+ * dmd/VERSION: Bump version to v2.111.0-rc.1.
+
+2025-03-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 9d2f034398.
+
+2025-03-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 94950cae58.
+ * d-lang.cc (d_handle_option): Add case for CppStdRevisionCpp23.
+ * gdc.texi: Document -fextern-std=c++23.
+ * lang.opt (fextern-std=): Add c++23.
+
+2025-03-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 8db14cf846.
+
+2025-03-22 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * runtime.def (INVARIANT): Update signature of run-time function.
+
+2025-03-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/118545
+ * d-lang.cc (d_handle_option): Adjust quoted options.
+
+2025-03-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd fde0f8c40a.
+
+2025-03-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 51be8bb729.
+
+2025-03-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 603225372b.
+ * dmd/VERSION: Bump version to v2.111.0-beta.1.
* d-builtins.cc (build_frontend_type): Update for new front-end
interface.
- * d-codegen.cc (build_assert_call): Likewise.
- * d-convert.cc (d_array_convert): Likewise.
- * decl.cc (get_vtable_decl): Likewise.
- * expr.cc (ExprVisitor::visit (EqualExp *)): Likewise.
- (ExprVisitor::visit (VarExp *)): Likewise.
- (ExprVisitor::visit (ArrayLiteralExp *)): Likewise.
- (ExprVisitor::visit (AssocArrayLiteralExp)): Likewise.
- * intrinsics.cc (build_shuffle_mask_type): Likewise.
- (maybe_warn_intrinsic_mismatch): Likewise.
- * runtime.cc (get_libcall_type): Likewise.
- * typeinfo.cc (TypeInfoVisitor::layout_string): Likewise.
- (TypeInfoVisitor::visit(TypeInfoTupleDeclaration *)): Likewise.
-
-2024-03-03 Iain Buclaw <ibuclaw@gdcproject.org>
-
- PR d/114171
- * d-codegen.cc (lower_struct_comparison): Keep alignment of original
- type in reinterpret cast for comparison.
-
-2024-02-25 Iain Buclaw <ibuclaw@gdcproject.org>
-
- * dmd/MERGE: Merge upstream dmd ceff48bf7d.
-
-2024-02-17 Iain Buclaw <ibuclaw@gdcproject.org>
-
- * dmd/MERGE: Merge upstream dmd 9471b25db9.
- * dmd/VERSION: Bump version to v2.107.1-rc.1.
- * Make-lang.in (D_FRONTEND_OBJS): Add d/cxxfrontend.o.
- * d-attribs.cc (build_attributes): Update for new front-end interface.
- * d-builtins.cc (build_frontend_type): Likewise.
- (strip_type_modifiers): Likewise.
- (covariant_with_builtin_type_p): Likewise.
- * d-codegen.cc (declaration_type): Likewise.
- (parameter_type): Likewise.
- (build_array_struct_comparison): Likewise.
- (void_okay_p): Likewise.
- * d-convert.cc (convert_expr): Likewise.
- (check_valist_conversion): Likewise.
- * d-lang.cc (d_generate_ddoc_file): Likewise.
- (d_parse_file): Likewise.
- * d-target.cc (TargetCPP::toMangle): Likewise.
- (TargetCPP::typeInfoMangle): Likewise.
- (TargetCPP::thunkMangle): Likewise.
- (TargetCPP::parameterType): Likewise.
- * decl.cc (d_mangle_decl): Likewise.
- (DeclVisitor::visit): Likewise.
- (DeclVisitor::visit (CAsmDeclaration *)): New method.
- (get_symbol_decl): Update for new front-end interface.
+ * decl.cc (Class DeclVisitor): Likewise.
+ (maybe_build_decl_tree): Likewise.
+ (get_vtable_decl): Likewise.
(layout_class_initializer): Likewise.
- * expr.cc (ExprVisitor::visit): Likewise.
- * intrinsics.cc (maybe_set_intrinsic): Likewise.
- (expand_intrinsic_rotate): Likewise.
- * modules.cc (layout_moduleinfo_fields): Likewise.
- (layout_moduleinfo): Likewise.
- * runtime.cc (get_libcall_type): Likewise.
- * typeinfo.cc (make_frontend_typeinfo): Likewise.
- (TypeInfoVisitor::visit): Likewise.
- (create_typeinfo): Likewise.
- * types.cc (same_type_p): Likewise.
- (build_ctype): Likewise.
-
-2024-02-12 Iain Buclaw <ibuclaw@gdcproject.org>
-
- PR d/113125
- * types.cc (TypeVisitor::visit (TypeStruct *)): Generate TYPE_DECL and
- apply UDAs to opaque struct declarations.
-
-2024-02-12 Iain Buclaw <ibuclaw@gdcproject.org>
-
- PR d/113772
- * dmd/MERGE: Merge upstream dmd 11240a9663.
- * d-builtins.cc (build_frontend_type): Update for new front-end
+ * expr.cc (class ExprVisitor): Likewise.
+ (ExprVisitor::visit (NewExp *)): Implement placement new for class,
+ struct, and pointer types.
+ * modules.cc (get_internal_fn): Update for new front-end interface.
+
+2025-03-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 53a1cc8d13.
+ * d-tree.h (create_typeinfo): Change second parameter to Scope *.
+ (speculative_type_p): Remove prototype.
+ * d-frontend.cc (getTypeInfoType): Adjust.
+ * decl.cc: Include dmd/typinf.h.
+ (DeclVisitor::visit (TypeInfoDeclaration *)): Update for new front-end
interface.
- * types.cc (same_type_p): Likewise.
+ * typeinfo.cc (create_typeinfo): Likewise.
+ (class SpeculativeTypeVisitor): Remove class.
+ (speculative_type_p): Remove function.
+
+2025-03-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd ffbad272b6.
+ * d-tree.h (make_location_t): Add overload taking a const SourceLoc &.
+ * d-codegen.cc (make_location_t): Likewise.
+ * d-diagnostic.cc (d_diagnostic_report_diagnostic): Change first
+ parameter type to const SourceLoc &.
+ (verrorReport): Update for new front-end interface.
+ (verrorReportSupplemental): Likewise.
+ * d-frontend.cc (eval_builtin): Likewise.
+ (getTypeInfoType): Likewise.
+ * d-lang.cc (d_parse_file): Likewise.
+ * d-target.cc (Target::va_listType): Likewise.
+ (Target::getTargetInfo): Likewise.
+ * decl.cc (build_decl_tree): Likewise.
+ * imports.cc (ImportVisitor::visit (Module *)): Likewise.
+ * modules.cc (get_internal_fn): Likewise.
-2024-02-12 Iain Buclaw <ibuclaw@gdcproject.org>
+2025-03-15 Iain Buclaw <ibuclaw@gdcproject.org>
- PR d/113758
- * d-codegen.cc (d_build_call): Force a TARGET_EXPR when callee
- destorys its arguments.
- * decl.cc (DeclVisitor::visit (VarDeclaration *)): Set
- SET_DECL_VALUE_EXPR on the temporary variable to make it a placeholder
- for the TARGET_EXPR_SLOT.
+ * dmd/MERGE: Merge upstream dmd d29e3eca45.
+ * d-codegen.cc (can_elide_copy_p): Update for new front-end interface.
+ * d-lang.cc (d_handle_option): Likewise.
+ * expr.cc (class ExprVisitor): Likewise.
-2024-02-04 Iain Buclaw <ibuclaw@gdcproject.org>
+2025-03-15 Iain Buclaw <ibuclaw@gdcproject.org>
- * dmd/MERGE: Merge upstream dmd a6f1083699.
- * dmd/VERSION: Bump version to v2.107.0
- * Make-lang.in (D_FRONTEND_OBJS): Add d/pragmasem.o.
- * d-builtins.cc (strip_type_modifiers): Update for new front-end
- interface.
- * d-codegen.cc (declaration_type): Likewise.
- (parameter_type): Likewise.
- * d-target.cc (TargetCPP::parameterType): Likewise.
- * expr.cc (ExprVisitor::visit (IndexExp *)): Likewise.
- (ExprVisitor::visit (VarExp *)): Likewise.
- (ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise.
- * runtime.cc (get_libcall_type): Likewise.
- * typeinfo.cc (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)):
- Likewise.
- (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise.
- (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise.
- (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise.
- * types.cc (build_ctype): Likewise.
-
-2024-02-03 Iain Buclaw <ibuclaw@gdcproject.org>
-
- * dmd/MERGE: Merge upstream dmd e770945277.
- * Make-lang.in (D_FRONTEND_OBJS): Add d/basicmangle.o, d/enumsem.o,
- d/funcsem.o, d/templatesem.o.
- * d-builtins.cc (build_frontend_type): Update for new front-end
+ * dmd/MERGE: Merge upstream b7e3b3b617.
+
+2025-03-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/119139
+ * decl.cc (get_symbol_decl): Don't set TREE_READONLY for __result
+ declarations.
+
+2025-02-28 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/116961
+ * d-codegen.cc (build_float_cst): Change new_value type from real_t to
+ real_value.
+ * d-ctfloat.cc (CTFloat::fabs): Default initialize the return value.
+ (CTFloat::ldexp): Likewise.
+ (CTFloat::parse): Likewise.
+ * d-longdouble.cc (longdouble::add): Likewise.
+ (longdouble::sub): Likewise.
+ (longdouble::mul): Likewise.
+ (longdouble::div): Likewise.
+ (longdouble::mod): Likewise.
+ (longdouble::neg): Likewise.
+ * d-port.cc (Port::isFloat32LiteralOutOfRange): Likewise.
+ (Port::isFloat64LiteralOutOfRange): Likewise.
+
+2025-02-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/118654
+ * implement-d.texi: Document CET version and traits key.
+
+2025-02-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (check_gdc_parallelize): Increase to 128.
+
+2025-01-29 Arsen Arsenović <arsen@aarsen.me>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR d/118477
+ * Make-lang.in (DCOMPILE, DPOSTCOMPILE): Use $(basename $(@F))
+ instead of $(*F).
+
+2025-01-22 Arsen Arsenović <arsen@aarsen.me>
+
+ * lang-specs.h: Replace %{nostdinc*} with %{nostdinc}.
+
+2025-01-20 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/114434
+ * expr.cc (ExprVisitor::visit (PtrExp *)): Get the offset as a
+ dinteger_t rather than a size_t.
+ (ExprVisitor::visit (SymOffExp *)): Likewise.
+
+2025-01-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd d115713410.
+
+2025-01-16 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/115249
+ * typeinfo.cc (create_tinfo_types): Update internal Typenfo
+ representation.
+ (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Likewise.
+
+2025-01-14 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/118438
+ PR d/118448
+ PR d/118449
+ * dmd/MERGE: Merge upstream dmd d6f693b46a.
+ * d-incpath.cc (add_import_paths): Update for new front-end interface.
+
+2025-01-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd c7902293d7.
+ * dmd/VERSION: Bump version to v2.110.0-rc.1.
+
+2025-01-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd c57da0cf59.
+ * d-codegen.cc (can_elide_copy_p): New.
+ (d_build_call): Use it.
+ * d-lang.cc (d_post_options): Update for new front-end interface.
+
+2025-01-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 82a5d2a7c4.
+ * d-lang.cc (d_handle_option): Handle new option `-fpreview=safer'.
+ * expr.cc (ExprVisitor::NewExp): Remove gcc_unreachable for the
+ generation of `_d_newThrowable'.
+ * lang.opt: Add -fpreview=safer.
+
+2025-01-11 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 2b89c2909d.
+ * Make-lang.in (D_FRONTEND_OBJS): Rename d/basicmangle.o to
+ d/mangle-basic.o, d/cppmangle.o to d/mangle-cpp.o, and d/dmangle.o to
+ d/mangle-package.o.
+ (d/mangle-%.o): New rule.
+ * d-builtins.cc (maybe_set_builtin_1): Update for new front-end
interface.
- * d-codegen.cc (declaration_type): Likewise.
- (parameter_type): Likewise.
- * d-incpath.cc (add_globalpaths): Likewise.
- (add_filepaths): Likewise.
- (add_import_paths): Likewise.
+ * d-diagnostic.cc (verrorReport): Likewise.
+ (verrorReportSupplemental): Likewise.
+ * d-frontend.cc (getTypeInfoType): Likewise.
* d-lang.cc (d_init_options): Likewise.
(d_handle_option): Likewise.
- (d_parse_file): Likewise.
- * decl.cc (DeclVisitor::finish_vtable): Likewise.
- (DeclVisitor::visit (FuncDeclaration *)): Likewise.
- (get_symbol_decl): Likewise.
- * expr.cc (ExprVisitor::visit (StringExp *)): Likewise.
- Implement support for 8-byte hexadecimal strings.
- * typeinfo.cc (create_tinfo_types): Update internal TypeInfo
- representation.
- (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): Update for new
- front-end interface.
- (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise.
- (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise.
- (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise.
- (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Move data for
- TypeInfo_Class.nameSig to the end of the object.
- (create_typeinfo): Update for new front-end interface.
-
-2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org>
-
- * dmd/MERGE: Merge upstream dmd bce5c1f7b5.
- * d-attribs.cc (build_attributes): Update for new front-end interface.
- * d-lang.cc (d_parse_file): Likewise.
- * decl.cc (DeclVisitor::visit (VarDeclaration *)): Likewise.
- * expr.cc (build_lambda_tree): New function.
- (ExprVisitor::visit (FuncExp *)): Use build_lambda_tree.
- (ExprVisitor::visit (SymOffExp *)): Likewise.
- (ExprVisitor::visit (VarExp *)): Likewise.
- * typeinfo.cc (create_tinfo_types): Add two ulong fields to internal
- TypeInfo representation.
- (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Emit stub data
- for TypeInfo_Class.nameSig.
- (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Update for new
- front-end interface.
-
-2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org>
-
- * dmd/MERGE: Merge upstream dmd d8e3976a58.
- * dmd/VERSION: Bump version to v2.107.0-beta.1.
- * d-lang.cc (d_parse_file): Update for new front-end interface.
- * modules.cc (struct module_info): Add standalonectors.
- (build_module_tree): Implement @standalone.
- (register_module_decl): Likewise.
-
-2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org>
-
- * dmd/MERGE: Merge upstream dmd f1a045928e.
- * dmd/VERSION: Bump version to v2.106.1-rc.1.
- * gdc.texi (fignore-unknown-pragmas): Update documentation.
- * d-builtins.cc (covariant_with_builtin_type_p): Update for new
- front-end interface.
- * d-lang.cc (d_parse_file): Likewise.
- * typeinfo.cc (make_frontend_typeinfo): Likewise.
+ (d_post_options): Likewise.
+ * d-target.cc (TargetC::contributesToAggregateAlignment): New.
+ * d-tree.h (create_typeinfo): Adjust prototype.
+ * decl.cc (layout_struct_initializer): Update for new front-end
+ interface.
+ * typeinfo.cc (create_typeinfo): Remove generate parameter.
+ * types.cc (layout_aggregate_members): Update for new front-end
+ interface.
+
+2025-01-10 Iain Buclaw <ibuclaw@gdcproject.org>
-2024-01-04 David Malcolm <dmalcolm@redhat.com>
+ * dmd/MERGE: Merge upstream dmd 4ccb01fde5.
+ * Make-lang.in (D_FRONTEND_OBJS): Rename d/foreachvar.o to
+ d/visitor-foreachvar.o, d/visitor.o to d/visitor-package.o, and
+ d/statement_rewrite_walker.o to d/visitor-statement_rewrite_walker.o.
+ (D_FRONTEND_OBJS): Rename
+ d/{parsetime,permissive,postorder,transitive}visitor.o to
+ d/visitor-{parsetime,permissive,postorder,transitive}.o.
+ (D_FRONTEND_OBJS): Remove d/sapply.o.
+ (d.tags): Add dmd/common/*.h.
+ (d/visitor-%.o:): New rule.
+ * d-codegen.cc (get_frameinfo): Update for new front-end interface.
- * lang.opt.urls: New file, autogenerated by
- regenerate-opt-urls.py.
+2025-01-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 6884b433d2.
+ * d-builtins.cc (build_frontend_type): Update for new front-end
+ interface.
+ (d_build_builtins_module): Likewise.
+ (matches_builtin_type): Likewise.
+ (covariant_with_builtin_type_p): Likewise.
+ * d-codegen.cc (lower_struct_comparison): Likewise.
+ (call_side_effect_free_p): Likewise.
+ * d-compiler.cc (Compiler::paintAsType): Likewise.
+ * d-convert.cc (convert_expr): Likewise.
+ (convert_for_assignment): Likewise.
+ * d-target.cc (Target::isVectorTypeSupported): Likewise.
+ (Target::isVectorOpSupported): Likewise.
+ (Target::isReturnOnStack): Likewise.
+ * decl.cc (get_symbol_decl): Likewise.
+ * expr.cc (build_return_dtor): Likewise.
+ * imports.cc (class ImportVisitor): Likewise.
+ * toir.cc (class IRVisitor): Likewise.
+ * types.cc (class TypeVisitor): Likewise.
+
+2025-01-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 34875cd6e1.
+ * dmd/VERSION: Bump version to v2.110.0-beta.1.
+ * Make-lang.in (D_FRONTEND_OBJS): Add d/deps.o, d/timetrace.o.
+ * decl.cc (class DeclVisitor): Update for new front-end interface.
+ * expr.cc (class ExprVisitor): Likewise
+ * typeinfo.cc (check_typeinfo_type): Likewise.
+
+2025-01-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 66b93fc24a.
+ * dmd/VERSION: Bump version to v2.109.1.
+ * d-builtins.cc (build_frontend_type): Update for new front-end
+ interface.
+ (matches_builtin_type): Likewise.
+ * d-codegen.cc (identity_compare_p): Likewise.
+ (call_side_effect_free_p): Likewise.
+ * d-convert.cc (convert_expr): Likewise.
+ (check_valist_conversion): Likewise.
+ * d-lang.cc (d_types_compatible_p): Likewise.
+ * d-target.cc (Target::isVectorTypeSupported): Likewise.
+ (Target::isReturnOnStack): Likewise.
+ (Target::preferPassByRef): Likewise.
+ * decl.cc (class DeclVisitor): Likewise.
+ * expr.cc (class ExprVisitor): Likewise.
+ * typeinfo.cc (class TypeInfoVisitor): Likewise.
+ * types.cc (class TypeVisitor): Likewise.
+
+2025-01-05 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * decl.cc (DeclVisitor::finish_vtable): Update for new front-end
+ interface.
+ * dmd/MERGE: Merge upstream dmd 07bc5b9b3c.
+ * dmd/VERSION: Bump version to v2.109.0.
+
+2025-01-05 Iain Buclaw <ibuclaw@symmetryinvestments.com>
+
+ * Make-lang.in (D_FRONTEND_OBJS): Add d/attribsem.o,
+ d/common-charactertables.o, d/common-identifiertables.o.
+ * d-attribs.cc (apply_user_attributes): Update for new front-end
+ interface.
+ * d-builtins.cc (d_init_versions): Predefine CppRuntime_GNU.
+ * d-incpath.cc (add_globalpaths): Update for new front-end interface.
+ (add_filepaths): Likewise.
+ (add_import_paths): Likewise.
+ * d-lang.cc (d_post_options): Likewise.
+ * dmd/MERGE: Merge upstream dmd c11e1d1708.
+ * dmd/VERSION: Bump version to v2.108.1.
-2024-01-03 Jakub Jelinek <jakub@redhat.com>
+2025-01-02 Jakub Jelinek <jakub@redhat.com>
* gdc.texi: Bump @copyrights-d year.
-Copyright (C) 2024 Free Software Foundation, Inc.
+Copyright (C) 2025 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
diff --git a/gcc/d/ChangeLog-2006 b/gcc/d/ChangeLog-2006
index 4160b0f..f5c686b 100644
--- a/gcc/d/ChangeLog-2006
+++ b/gcc/d/ChangeLog-2006
@@ -945,7 +945,6 @@
2006-06-01 David Friedman <dvdfrdmn@users.sf.net>
* Start of SourceForge repository
-
Copyright (C) 2006 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2007 b/gcc/d/ChangeLog-2007
index a2e5043..e95a195 100644
--- a/gcc/d/ChangeLog-2007
+++ b/gcc/d/ChangeLog-2007
@@ -1331,7 +1331,6 @@
* d-codegen.cc (convertTo): Use 64-bit for Tarray, Tsarray conversion.
* d-codegen.{h, cc} (darrayVal): use uinteger_t arg
-
Copyright (C) 2007 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2008 b/gcc/d/ChangeLog-2008
index 23dc712..fa0c585 100644
--- a/gcc/d/ChangeLog-2008
+++ b/gcc/d/ChangeLog-2008
@@ -322,7 +322,6 @@
outer class functions.
* Rename patch-build_gcc-4.0 to patch-build_gcc-4.0.x
-
Copyright (C) 2008 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2009 b/gcc/d/ChangeLog-2009
index 90a204d..057ae98 100644
--- a/gcc/d/ChangeLog-2009
+++ b/gcc/d/ChangeLog-2009
@@ -176,7 +176,6 @@
* d-glue.cc, d-objfile.cc, d-codegen.cc, d-lang.h, d-builtins2.cc,
d-convert.cc, d-codegen.h: Replace calls to build macro by appropriate
buildN function (build is removed in GCC > 4.1).
-
Copyright (C) 2009 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2010 b/gcc/d/ChangeLog-2010
index 40c8fa4..f430aebe 100644
--- a/gcc/d/ChangeLog-2010
+++ b/gcc/d/ChangeLog-2010
@@ -1475,7 +1475,6 @@
* phobos/std/string.d: Fix a set of bugs in std.string.split which
made delemiters of length > 1 segfault.
-
Copyright (C) 2010 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2011 b/gcc/d/ChangeLog-2011
index a5c1558..e4fce46 100644
--- a/gcc/d/ChangeLog-2011
+++ b/gcc/d/ChangeLog-2011
@@ -1239,7 +1239,6 @@
d/d-glue.cc, d/d-lang-45.h, d/d-lang.cc, d/d-lang.h, d/d-objfile.cc:
Declare d_build_decl as extern "C". Add function d_build_decl_loc.
[29253025adb2]
-
Copyright (C) 2011 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2012 b/gcc/d/ChangeLog-2012
index 741747b..443c025 100644
--- a/gcc/d/ChangeLog-2012
+++ b/gcc/d/ChangeLog-2012
@@ -848,7 +848,6 @@
(ReturnStatement::toIR): Don't call postblit on nrvo returns.
(DtorExpStatement::toIR): Don't call destructor if var is returned as
the nrvo variable.
-
Copyright (C) 2012 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2013 b/gcc/d/ChangeLog-2013
index eeb12c9..c863a30 100644
--- a/gcc/d/ChangeLog-2013
+++ b/gcc/d/ChangeLog-2013
@@ -1212,7 +1212,6 @@
(d_init): Fix definition of D_LP64 version.
* setup-gcc.sh: Likewise.
* target-ver-syms.sh: Likewise.
-
Copyright (C) 2013 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2014 b/gcc/d/ChangeLog-2014
index cf8c8ac..fded72b 100644
--- a/gcc/d/ChangeLog-2014
+++ b/gcc/d/ChangeLog-2014
@@ -651,7 +651,6 @@
(d_finish_function): Set function local if function body was compiled.
* d-decls.cc (Dsymbol::toSymbolX): Use unsigned integer format for the
prefix string length.
-
Copyright (C) 2014 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2015 b/gcc/d/ChangeLog-2015
index 918068b..8e6a3bd 100644
--- a/gcc/d/ChangeLog-2015
+++ b/gcc/d/ChangeLog-2015
@@ -762,7 +762,6 @@
2015-01-02 Iain Buclaw <ibuclaw@gdcproject.org>
* d-codegen.h (build_boolop): Don't eagerly fold comparison expressions.
-
Copyright (C) 2015 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2016 b/gcc/d/ChangeLog-2016
index dbd7573..9db9890 100644
--- a/gcc/d/ChangeLog-2016
+++ b/gcc/d/ChangeLog-2016
@@ -1253,7 +1253,6 @@
function attributes.
* d-codegen.h (LibCallFlag): Remove type.
* runtime.def: Replace LibCallFlag with ECF everywhere.
-
Copyright (C) 2016 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2017 b/gcc/d/ChangeLog-2017
index 4f64c31..be37a8d 100644
--- a/gcc/d/ChangeLog-2017
+++ b/gcc/d/ChangeLog-2017
@@ -1166,7 +1166,6 @@
(ExprVisitor::lvalue_p): New function.
(ExprVisitor::visit(AssignExp)): Check for dtor in array assignments.
(ExprVisitor::visit(TypeidExp)): Cast result to expression type.
-
Copyright (C) 2017 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2022 b/gcc/d/ChangeLog-2022
index 7630f24..48279d7 100644
--- a/gcc/d/ChangeLog-2022
+++ b/gcc/d/ChangeLog-2022
@@ -824,7 +824,6 @@
2022-01-03 Jakub Jelinek <jakub@redhat.com>
* gdc.texi: Bump @copyrights-d year.
-
Copyright (C) 2022 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2023 b/gcc/d/ChangeLog-2023
index 5510b99..2cf8a33 100644
--- a/gcc/d/ChangeLog-2023
+++ b/gcc/d/ChangeLog-2023
@@ -484,7 +484,6 @@
2023-01-02 Jakub Jelinek <jakub@redhat.com>
* gdc.texi: Bump @copyrights-d year.
-
Copyright (C) 2023 Free Software Foundation, Inc.
diff --git a/gcc/d/ChangeLog-2024 b/gcc/d/ChangeLog-2024
new file mode 100644
index 0000000..a2d9cf4
--- /dev/null
+++ b/gcc/d/ChangeLog-2024
@@ -0,0 +1,294 @@
+2024-11-22 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR bootstrap/117737
+ * d-attribs.cc (INCLUDE_MEMORY): Remove.
+ * d-builtins.cc (INCLUDE_MEMORY): Remove.
+ * d-codegen.cc (INCLUDE_MEMORY): Remove.
+ * d-convert.cc (INCLUDE_MEMORY): Remove.
+ * d-diagnostic.cc (INCLUDE_MEMORY): Remove.
+ * d-frontend.cc (INCLUDE_MEMORY): Remove.
+ * d-lang.cc (INCLUDE_MEMORY): Remove.
+ * d-longdouble.cc (INCLUDE_MEMORY): Remove.
+ * d-target.cc (INCLUDE_MEMORY): Remove.
+ * decl.cc (INCLUDE_MEMORY): Remove.
+ * expr.cc (INCLUDE_MEMORY): Remove.
+ * intrinsics.cc (INCLUDE_MEMORY): Remove.
+ * modules.cc (INCLUDE_MEMORY): Remove.
+ * toir.cc (INCLUDE_MEMORY): Remove.
+ * typeinfo.cc (INCLUDE_MEMORY): Remove.
+ * types.cc (INCLUDE_MEMORY): Remove.
+
+2024-10-29 David Malcolm <dmalcolm@redhat.com>
+
+ PR other/116613
+ * d-diagnostic.cc (d_diagnostic_report_diagnostic): Update for
+ m_printer becoming reference printer.
+
+2024-10-24 David Malcolm <dmalcolm@redhat.com>
+ Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR other/116613
+ * d-attribs.cc: Add #define INCLUDE_MEMORY.
+ * d-builtins.cc: Likewise.
+ * d-codegen.cc: Likewise.
+ * d-convert.cc: Likewise.
+ * d-diagnostic.cc: Likewise.
+ * d-frontend.cc: Likewise.
+ * d-lang.cc: Likewise.
+ * d-longdouble.cc: Likewise.
+ * d-target.cc: Likewise.
+ * decl.cc: Likewise.
+ * expr.cc: Likewise.
+ * intrinsics.cc: Likewise.
+ * modules.cc: Likewise.
+ * toir.cc: Likewise.
+ * typeinfo.cc: Likewise.
+ * types.cc: Likewise.
+
+2024-09-25 Mikael Morin <mikael@gcc.gnu.org>
+
+ PR other/116801
+ * lang.opt.urls: Regenerate.
+
+2024-09-09 David Malcolm <dmalcolm@redhat.com>
+
+ * d-diagnostic.cc (d_diagnostic_report_diagnostic): Update for
+ renaming of diagnostic_info field.
+
+2024-09-09 David Malcolm <dmalcolm@redhat.com>
+
+ PR other/116613
+ * d-diagnostic.cc (d_diagnostic_report_diagnostic): Rename
+ diagnostic_context's "printer" field to "m_printer".
+
+2024-09-02 Richard Sandiford <richard.sandiford@arm.com>
+
+ * toir.cc (IRVisitor): Rename ASM_INPUT_P to ASM_BASIC_P.
+
+2024-07-21 Sam James <sam@gentoo.org>
+
+ * Make-lang.in (WARN_DFLAGS): Drop NOCOMMON_FLAG.
+
+2024-06-05 Kewen Lin <linkw@linux.ibm.com>
+ Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * d-target.cc (Target::_init): Use int_size_in_bytes of
+ long_double_type_node to replace the expression with
+ LONG_DOUBLE_TYPE_SIZE for c.long_doublesize assignment.
+
+2024-04-19 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/111650
+ * decl.cc (get_fndecl_arguments): Move generation of frame type to ...
+ (DeclVisitor::visit (FuncDeclaration *)): ... here, after the call to
+ build_closure.
+
+2024-04-06 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd b65767825f.
+ * dmd/VERSION: Bump version to v2.108.0.
+
+2024-03-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 855353a1d9.
+ * dmd/VERSION:
+
+2024-03-10 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/112285
+ PR d/112290
+ * d-target.cc (Target::preferPassByRef): Return true for all static
+ array and struct types.
+
+2024-03-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd f8bae04558.
+ * dmd/VERSION: Bump version to v2.108.0-beta.1.
+ * d-builtins.cc (build_frontend_type): Update for new front-end
+ interface.
+ * d-codegen.cc (build_assert_call): Likewise.
+ * d-convert.cc (d_array_convert): Likewise.
+ * decl.cc (get_vtable_decl): Likewise.
+ * expr.cc (ExprVisitor::visit (EqualExp *)): Likewise.
+ (ExprVisitor::visit (VarExp *)): Likewise.
+ (ExprVisitor::visit (ArrayLiteralExp *)): Likewise.
+ (ExprVisitor::visit (AssocArrayLiteralExp)): Likewise.
+ * intrinsics.cc (build_shuffle_mask_type): Likewise.
+ (maybe_warn_intrinsic_mismatch): Likewise.
+ * runtime.cc (get_libcall_type): Likewise.
+ * typeinfo.cc (TypeInfoVisitor::layout_string): Likewise.
+ (TypeInfoVisitor::visit(TypeInfoTupleDeclaration *)): Likewise.
+
+2024-03-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/114171
+ * d-codegen.cc (lower_struct_comparison): Keep alignment of original
+ type in reinterpret cast for comparison.
+
+2024-02-25 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd ceff48bf7d.
+
+2024-02-17 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 9471b25db9.
+ * dmd/VERSION: Bump version to v2.107.1-rc.1.
+ * Make-lang.in (D_FRONTEND_OBJS): Add d/cxxfrontend.o.
+ * d-attribs.cc (build_attributes): Update for new front-end interface.
+ * d-builtins.cc (build_frontend_type): Likewise.
+ (strip_type_modifiers): Likewise.
+ (covariant_with_builtin_type_p): Likewise.
+ * d-codegen.cc (declaration_type): Likewise.
+ (parameter_type): Likewise.
+ (build_array_struct_comparison): Likewise.
+ (void_okay_p): Likewise.
+ * d-convert.cc (convert_expr): Likewise.
+ (check_valist_conversion): Likewise.
+ * d-lang.cc (d_generate_ddoc_file): Likewise.
+ (d_parse_file): Likewise.
+ * d-target.cc (TargetCPP::toMangle): Likewise.
+ (TargetCPP::typeInfoMangle): Likewise.
+ (TargetCPP::thunkMangle): Likewise.
+ (TargetCPP::parameterType): Likewise.
+ * decl.cc (d_mangle_decl): Likewise.
+ (DeclVisitor::visit): Likewise.
+ (DeclVisitor::visit (CAsmDeclaration *)): New method.
+ (get_symbol_decl): Update for new front-end interface.
+ (layout_class_initializer): Likewise.
+ * expr.cc (ExprVisitor::visit): Likewise.
+ * intrinsics.cc (maybe_set_intrinsic): Likewise.
+ (expand_intrinsic_rotate): Likewise.
+ * modules.cc (layout_moduleinfo_fields): Likewise.
+ (layout_moduleinfo): Likewise.
+ * runtime.cc (get_libcall_type): Likewise.
+ * typeinfo.cc (make_frontend_typeinfo): Likewise.
+ (TypeInfoVisitor::visit): Likewise.
+ (create_typeinfo): Likewise.
+ * types.cc (same_type_p): Likewise.
+ (build_ctype): Likewise.
+
+2024-02-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/113125
+ * types.cc (TypeVisitor::visit (TypeStruct *)): Generate TYPE_DECL and
+ apply UDAs to opaque struct declarations.
+
+2024-02-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/113772
+ * dmd/MERGE: Merge upstream dmd 11240a9663.
+ * d-builtins.cc (build_frontend_type): Update for new front-end
+ interface.
+ * types.cc (same_type_p): Likewise.
+
+2024-02-12 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/113758
+ * d-codegen.cc (d_build_call): Force a TARGET_EXPR when callee
+ destorys its arguments.
+ * decl.cc (DeclVisitor::visit (VarDeclaration *)): Set
+ SET_DECL_VALUE_EXPR on the temporary variable to make it a placeholder
+ for the TARGET_EXPR_SLOT.
+
+2024-02-04 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd a6f1083699.
+ * dmd/VERSION: Bump version to v2.107.0
+ * Make-lang.in (D_FRONTEND_OBJS): Add d/pragmasem.o.
+ * d-builtins.cc (strip_type_modifiers): Update for new front-end
+ interface.
+ * d-codegen.cc (declaration_type): Likewise.
+ (parameter_type): Likewise.
+ * d-target.cc (TargetCPP::parameterType): Likewise.
+ * expr.cc (ExprVisitor::visit (IndexExp *)): Likewise.
+ (ExprVisitor::visit (VarExp *)): Likewise.
+ (ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise.
+ * runtime.cc (get_libcall_type): Likewise.
+ * typeinfo.cc (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)):
+ Likewise.
+ (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise.
+ (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise.
+ (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise.
+ * types.cc (build_ctype): Likewise.
+
+2024-02-03 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd e770945277.
+ * Make-lang.in (D_FRONTEND_OBJS): Add d/basicmangle.o, d/enumsem.o,
+ d/funcsem.o, d/templatesem.o.
+ * d-builtins.cc (build_frontend_type): Update for new front-end
+ interface.
+ * d-codegen.cc (declaration_type): Likewise.
+ (parameter_type): Likewise.
+ * d-incpath.cc (add_globalpaths): Likewise.
+ (add_filepaths): Likewise.
+ (add_import_paths): Likewise.
+ * d-lang.cc (d_init_options): Likewise.
+ (d_handle_option): Likewise.
+ (d_parse_file): Likewise.
+ * decl.cc (DeclVisitor::finish_vtable): Likewise.
+ (DeclVisitor::visit (FuncDeclaration *)): Likewise.
+ (get_symbol_decl): Likewise.
+ * expr.cc (ExprVisitor::visit (StringExp *)): Likewise.
+ Implement support for 8-byte hexadecimal strings.
+ * typeinfo.cc (create_tinfo_types): Update internal TypeInfo
+ representation.
+ (TypeInfoVisitor::visit (TypeInfoConstDeclaration *)): Update for new
+ front-end interface.
+ (TypeInfoVisitor::visit (TypeInfoInvariantDeclaration *)): Likewise.
+ (TypeInfoVisitor::visit (TypeInfoSharedDeclaration *)): Likewise.
+ (TypeInfoVisitor::visit (TypeInfoWildDeclaration *)): Likewise.
+ (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Move data for
+ TypeInfo_Class.nameSig to the end of the object.
+ (create_typeinfo): Update for new front-end interface.
+
+2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd bce5c1f7b5.
+ * d-attribs.cc (build_attributes): Update for new front-end interface.
+ * d-lang.cc (d_parse_file): Likewise.
+ * decl.cc (DeclVisitor::visit (VarDeclaration *)): Likewise.
+ * expr.cc (build_lambda_tree): New function.
+ (ExprVisitor::visit (FuncExp *)): Use build_lambda_tree.
+ (ExprVisitor::visit (SymOffExp *)): Likewise.
+ (ExprVisitor::visit (VarExp *)): Likewise.
+ * typeinfo.cc (create_tinfo_types): Add two ulong fields to internal
+ TypeInfo representation.
+ (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Emit stub data
+ for TypeInfo_Class.nameSig.
+ (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Update for new
+ front-end interface.
+
+2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd d8e3976a58.
+ * dmd/VERSION: Bump version to v2.107.0-beta.1.
+ * d-lang.cc (d_parse_file): Update for new front-end interface.
+ * modules.cc (struct module_info): Add standalonectors.
+ (build_module_tree): Implement @standalone.
+ (register_module_decl): Likewise.
+
+2024-02-02 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd f1a045928e.
+ * dmd/VERSION: Bump version to v2.106.1-rc.1.
+ * gdc.texi (fignore-unknown-pragmas): Update documentation.
+ * d-builtins.cc (covariant_with_builtin_type_p): Update for new
+ front-end interface.
+ * d-lang.cc (d_parse_file): Likewise.
+ * typeinfo.cc (make_frontend_typeinfo): Likewise.
+
+2024-01-04 David Malcolm <dmalcolm@redhat.com>
+
+ * lang.opt.urls: New file, autogenerated by
+ regenerate-opt-urls.py.
+
+2024-01-03 Jakub Jelinek <jakub@redhat.com>
+
+ * gdc.texi: Bump @copyrights-d year.
+
+Copyright (C) 2024 Free Software Foundation, Inc.
+
+Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 077668f..2d444c9 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -1,5 +1,5 @@
# Make-lang.in -- Top level -*- makefile -*- fragment for the D frontend.
-# Copyright (C) 2006-2024 Free Software Foundation, Inc.
+# Copyright (C) 2006-2025 Free Software Foundation, Inc.
# GCC is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -65,8 +65,8 @@ ALL_DFLAGS = $(DFLAGS-$@) $(GDCFLAGS) -fversion=IN_GCC $(CHECKING_DFLAGS) \
$(WARN_DFLAGS)
DCOMPILE.base = $(GDC) -c $(ALL_DFLAGS) -o $@
-DCOMPILE = $(DCOMPILE.base) -MT $@ -MMD -MP -MF $(@D)/$(DEPDIR)/$(*F).TPo
-DPOSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(*F).TPo $(@D)/$(DEPDIR)/$(*F).Po
+DCOMPILE = $(DCOMPILE.base) -MT $@ -MMD -MP -MF $(@D)/$(DEPDIR)/$(basename $(@F)).TPo
+DPOSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(basename $(@F)).TPo $(@D)/$(DEPDIR)/$(basename $(@F)).Po
DLINKER = $(GDC) $(NO_PIE_FLAG) -lstdc++
# Like LINKER, but use a mutex for serializing front end links.
@@ -84,24 +84,25 @@ D_FRONTEND_OBJS = \
d/arrayop.o \
d/arraytypes.o \
d/attrib.o \
+ d/attribsem.o \
d/ast_node.o \
d/astcodegen.o \
d/astenums.o \
- d/basicmangle.o \
d/blockexit.o \
d/builtin.o \
d/canthrow.o \
d/chkformat.o \
d/clone.o \
d/common-bitfields.o \
+ d/common-charactertables.o \
d/common-file.o \
+ d/common-identifiertables.o \
d/common-outbuffer.o \
d/common-smallbuffer.o \
d/compiler.o \
d/cond.o \
d/constfold.o \
d/cparse.o \
- d/cppmangle.o \
d/ctfeexpr.o \
d/ctorflow.o \
d/cxxfrontend.o \
@@ -110,10 +111,10 @@ D_FRONTEND_OBJS = \
d/declaration.o \
d/delegatize.o \
d/denum.o \
+ d/deps.o \
d/dimport.o \
d/dinterpret.o \
d/dmacro.o \
- d/dmangle.o \
d/dmodule.o \
d/doc.o \
d/dscope.o \
@@ -131,7 +132,6 @@ D_FRONTEND_OBJS = \
d/expression.o \
d/expressionsem.o \
d/file_manager.o \
- d/foreachvar.o \
d/func.o \
d/funcsem.o \
d/globals.o \
@@ -152,6 +152,9 @@ D_FRONTEND_OBJS = \
d/lambdacomp.o \
d/lexer.o \
d/location.o \
+ d/mangle-basic.o \
+ d/mangle-cpp.o \
+ d/mangle-package.o \
d/mtype.o \
d/mustuse.o \
d/nogc.o \
@@ -161,9 +164,6 @@ D_FRONTEND_OBJS = \
d/opover.o \
d/optimize.o \
d/parse.o \
- d/parsetimevisitor.o \
- d/permissivevisitor.o \
- d/postordervisitor.o \
d/pragmasem.o \
d/printast.o \
d/root-aav.o \
@@ -185,12 +185,10 @@ D_FRONTEND_OBJS = \
d/root-utf.o \
d/rootobject.o \
d/safe.o \
- d/sapply.o \
d/semantic2.o \
d/semantic3.o \
d/sideeffect.o \
d/statement.o \
- d/statement_rewrite_walker.o \
d/statementsem.o \
d/staticassert.o \
d/staticcond.o \
@@ -198,13 +196,19 @@ D_FRONTEND_OBJS = \
d/target.o \
d/templateparamsem.o \
d/templatesem.o \
+ d/timetrace.o \
d/tokens.o \
d/traits.o \
- d/transitivevisitor.o \
d/typesem.o \
d/typinf.o \
d/utils.o \
- d/visitor.o
+ d/visitor-foreachvar.o \
+ d/visitor-package.o \
+ d/visitor-parsetime.o \
+ d/visitor-permissive.o \
+ d/visitor-postorder.o \
+ d/visitor-statement_rewrite_walker.o \
+ d/visitor-transitive.o
# Language-specific object files for D.
D_OBJS = \
@@ -291,7 +295,7 @@ d.srcextra:
d.tags: force
cd $(srcdir)/d; \
- $(ETAGS) -o TAGS.sub *.cc *.h dmd/*.h dmd/root/*.h; \
+ $(ETAGS) -o TAGS.sub *.cc *.h dmd/*.h dmd/common/*.h dmd/root/*.h; \
$(ETAGS) --include TAGS.sub --include ../TAGS.sub
d.man: doc/gdc.1
@@ -304,7 +308,7 @@ d.srcman: doc/gdc.1
check-d: check-gdc
lang_checks += check-gdc
lang_checks_parallelized += check-gdc
-check_gdc_parallelize = 10
+check_gdc_parallelize = 128
# No D-specific selftests.
selftest-d:
@@ -416,6 +420,14 @@ d/common-%.o: d/dmd/common/%.d
$(DCOMPILE) $(D_INCLUDES) $<
$(DPOSTCOMPILE)
+d/mangle-%.o: d/dmd/mangle/%.d
+ $(DCOMPILE) $(D_INCLUDES) $<
+ $(DPOSTCOMPILE)
+
d/root-%.o: d/dmd/root/%.d
$(DCOMPILE) $(D_INCLUDES) $<
$(DPOSTCOMPILE)
+
+d/visitor-%.o: d/dmd/visitor/%.d
+ $(DCOMPILE) $(D_INCLUDES) $<
+ $(DPOSTCOMPILE)
diff --git a/gcc/d/config-lang.in b/gcc/d/config-lang.in
index 13cd177..d2c1a03 100644
--- a/gcc/d/config-lang.in
+++ b/gcc/d/config-lang.in
@@ -1,5 +1,5 @@
# config-lang.in -- Top level configure fragment for gcc D frontend.
-# Copyright (C) 2006-2024 Free Software Foundation, Inc.
+# Copyright (C) 2006-2025 Free Software Foundation, Inc.
# GCC is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index 0f7ca10..77315dc 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -1,5 +1,5 @@
/* d-attribs.c -- D attributes handling.
- Copyright (C) 2015-2024 Free Software Foundation, Inc.
+ Copyright (C) 2015-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -440,7 +440,7 @@ apply_user_attributes (Dsymbol *sym, tree node)
if (TYPE_P (node) && !COMPLETE_TYPE_P (node))
attr_flags |= ATTR_FLAG_TYPE_IN_PLACE;
- Expressions *attrs = uda->getAttributes ();
+ Expressions *attrs = dmd::getAttributes (uda);
decl_attributes (&node, build_attributes (attrs), attr_flags);
input_location = saved_location;
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 4546c0e..9c14645 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -1,5 +1,5 @@
/* d-builtins.cc -- GCC builtins support for D.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -139,8 +139,8 @@ build_frontend_type (tree type)
dtype = Type::basic[i];
/* Search for type matching size and signedness. */
- if (unsignedp != dtype->isunsigned ()
- || size != dtype->size ())
+ if (unsignedp != dtype->isUnsigned ()
+ || size != dmd::size (dtype))
continue;
return dmd::addMod (dtype, mod);
@@ -157,7 +157,7 @@ build_frontend_type (tree type)
dtype = Type::basic[i];
/* Search for type matching size. */
- if (dtype->size () != size)
+ if (dmd::size (dtype) != size)
continue;
return dmd::addMod (dtype, mod);
@@ -174,7 +174,7 @@ build_frontend_type (tree type)
dtype = Type::basic[i];
/* Search for type matching size. */
- if (dtype->size () != size)
+ if (dmd::size (dtype) != size)
continue;
return dmd::addMod (dtype, mod);
@@ -215,7 +215,7 @@ build_frontend_type (tree type)
break;
dtype = dmd::addMod (dmd::sarrayOf (dtype, nunits), mod);
- if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ()))
+ if (target.isVectorTypeSupported (dmd::size (dtype), dtype->nextOf ()))
break;
dtype = dmd::addMod (TypeVector::create (dtype), mod);
@@ -279,7 +279,7 @@ build_frontend_type (tree type)
NULL);
vd->parent = sdecl;
vd->offset = tree_to_uhwi (byte_position (field));
- vd->semanticRun = PASS::semanticdone;
+ vd->semanticRun (PASS::semanticdone);
vd->csym = field;
sdecl->members->push (vd);
sdecl->fields.push (vd);
@@ -522,6 +522,7 @@ d_init_versions (void)
targetdm.d_cpu_versions ();
targetdm.d_os_versions ();
+ VersionCondition::addPredefinedGlobalIdent ("CppRuntime_GNU");
VersionCondition::addPredefinedGlobalIdent ("CppRuntime_Gcc");
}
@@ -571,8 +572,8 @@ d_build_builtins_module (Module *m)
tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUST::safe
: TREE_NOTHROW (decl) ? TRUST::trusted
: TRUST::system;
- tf->isnothrow (true);
- tf->isnogc (true);
+ tf->isNothrow (true);
+ tf->isNogc (true);
FuncDeclaration *func
= FuncDeclaration::create (Loc (), Loc (),
@@ -711,11 +712,11 @@ matches_builtin_type (Type *t1, Type *t2)
if (((tb1->isTypePointer () && tb2->isTypePointer ())
|| (tb1->isTypeVector () && tb2->isTypeVector ()))
- && tb1->implicitConvTo (tb2) != MATCH::nomatch)
+ && dmd::implicitConvTo (tb1, tb2) != MATCH::nomatch)
return true;
- if (tb1->isintegral () == tb2->isintegral ()
- && tb1->size () == tb2->size ())
+ if (tb1->isIntegral () == tb2->isIntegral ()
+ && dmd::size (tb1) == dmd::size (tb2))
return true;
return false;
@@ -738,7 +739,7 @@ covariant_with_builtin_type_p (Type *t1, Type *t2)
/* Check for obvious reasons why types may be distinct. */
if (tf1 == NULL || tf2 == NULL
- || tf1->isref () != tf2->isref ()
+ || tf1->isRef () != tf2->isRef ()
|| tf1->parameterList.varargs != tf2->parameterList.varargs
|| tf1->parameterList.length () != tf2->parameterList.length ())
return false;
@@ -776,7 +777,7 @@ maybe_set_builtin_1 (Dsymbol *d)
if (ad != NULL)
{
/* Recursively search through attribute decls. */
- Dsymbols *decls = ad->include (NULL);
+ Dsymbols *decls = dmd::include (ad, NULL);
if (decls && decls->length)
{
for (size_t i = 0; i < decls->length; i++)
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 2b3089b..e35f75a 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -1,5 +1,5 @@
/* d-codegen.cc -- Code generation and routines for manipulation of GCC trees.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -43,24 +43,33 @@ along with GCC; see the file COPYING3. If not see
#include "d-tree.h"
-/* Return the GCC location for the D frontend location LOC. */
+/* Return the GCC location for the D frontend source location LOC. */
location_t
-make_location_t (const Loc &loc)
+make_location_t (const SourceLoc &loc)
{
location_t gcc_location = input_location;
- if (const char *filename = loc.filename ())
+ if (loc.filename.length != 0)
{
- linemap_add (line_table, LC_ENTER, 0, filename, loc.linnum ());
- linemap_line_start (line_table, loc.linnum (), 0);
- gcc_location = linemap_position_for_column (line_table, loc.charnum ());
+ linemap_add (line_table, LC_ENTER, 0, loc.filename.ptr, loc.line);
+ linemap_line_start (line_table, loc.line, 0);
+ gcc_location = linemap_position_for_column (line_table, loc.column);
linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
}
return gcc_location;
}
+/* Likewise, but converts LOC from a compact opaque location. */
+
+location_t
+make_location_t (const Loc loc)
+{
+ const SourceLoc sloc = loc.toSourceLoc ();
+ return make_location_t (sloc);
+}
+
/* Return the DECL_CONTEXT for symbol DSYM. */
tree
@@ -246,15 +255,15 @@ build_integer_cst (dinteger_t value, tree type)
tree
build_float_cst (const real_t &value, Type *totype)
{
- real_t new_value;
+ real_value new_value;
TypeBasic *tb = totype->isTypeBasic ();
gcc_assert (tb != NULL);
tree type_node = build_ctype (tb);
- real_convert (&new_value.rv (), TYPE_MODE (type_node), &value.rv ());
+ real_convert (&new_value, TYPE_MODE (type_node), &value.rv ());
- return build_real (type_node, new_value.rv ());
+ return build_real (type_node, new_value);
}
/* Returns the .length component from the D dynamic array EXP. */
@@ -308,7 +317,7 @@ d_array_value (tree type, tree len, tree data)
CONSTRUCTOR_APPEND_ELT (ce, len_field, len);
CONSTRUCTOR_APPEND_ELT (ce, ptr_field, data);
- return build_constructor (type, ce);
+ return build_padded_constructor (type, ce);
}
/* Returns value representing the array length of expression EXP.
@@ -631,6 +640,37 @@ force_target_expr (tree exp)
return build_target_expr (decl, exp);
}
+/* Determine whether expression EXP can have a copy of its value elided. */
+
+static bool
+can_elide_copy_p (Expression *exp)
+{
+ /* Explicit `__rvalue(exp)'. */
+ if (exp->rvalue ())
+ return true;
+
+ /* Look for variable expression. */
+ Expression *last = exp;
+ while (CommaExp *ce = last->isCommaExp ())
+ last = ce->e2;
+
+ if (VarExp *ve = last->isVarExp ())
+ {
+ if (VarDeclaration *vd = ve->var->isVarDeclaration ())
+ {
+ /* Variable is an implicit copy of an lvalue. */
+ if (vd->storage_class & STCrvalue)
+ return true;
+
+ /* The destructor is going to run on the variable. */
+ if (vd->isArgDtorVar ())
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Returns the address of the expression EXP. */
tree
@@ -677,10 +717,11 @@ build_address (tree exp)
if (AGGREGATE_TYPE_P (TREE_TYPE (exp))
&& !aggregate_value_p (TREE_TYPE (exp), exp))
{
- tree tmp = build_local_temp (TREE_TYPE (exp));
- init = compound_expr (init, build_memset_call (tmp));
- init = compound_expr (init, modify_expr (tmp, exp));
- exp = tmp;
+ tree target = force_target_expr (exp);
+ tree ptr = build_address (TARGET_EXPR_SLOT (target));
+ init = compound_expr (init, target);
+ init = compound_expr (init, build_clear_padding_call (ptr));
+ exp = TARGET_EXPR_SLOT (target);
}
else
exp = force_target_expr (exp);
@@ -851,14 +892,13 @@ build_memset_call (tree ptr, tree num)
}
/* Use a zero constant to fill the destination if setting the entire object.
- For CONSTRUCTORs, the memcpy() is lowered to a ref-all pointer assignment,
- which can then be merged with other stores to the object. */
+ For CONSTRUCTORs, also set CONSTRUCTOR_ZERO_PADDING_BITS. */
tree valtype = TREE_TYPE (TREE_TYPE (ptr));
if (tree_int_cst_equal (TYPE_SIZE_UNIT (valtype), num))
{
tree cst = build_zero_cst (valtype);
if (TREE_CODE (cst) == CONSTRUCTOR)
- return build_memcpy_call (ptr, build_address (cst), num);
+ CONSTRUCTOR_ZERO_PADDING_BITS (cst) = 1;
return modify_expr (build_deref (ptr), cst);
}
@@ -867,6 +907,18 @@ build_memset_call (tree ptr, tree num)
ptr, integer_zero_node, num);
}
+/* Build a call to built-in clear_padding(), clears padding bits inside of the
+ object representation of object pointed by PTR. */
+
+tree
+build_clear_padding_call (tree ptr)
+{
+ gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr)));
+
+ return build_call_expr (builtin_decl_explicit (BUILT_IN_CLEAR_PADDING), 1,
+ ptr);
+}
+
/* Return TRUE if the struct SD is suitable for comparison using memcmp.
This is because we don't guarantee that padding is zero-initialized for
a stack variable, so we can't use memcmp to compare struct values. */
@@ -904,7 +956,7 @@ identity_compare_p (StructDeclaration *sd)
if (offset != vd->offset)
return false;
- offset += vd->type->size ();
+ offset += dmd::size (vd->type);
}
}
@@ -972,15 +1024,15 @@ lower_struct_comparison (tree_code code, StructDeclaration *sd,
/* Compare inner data structures. */
tcmp = lower_struct_comparison (code, ts->sym, t1ref, t2ref);
}
- else if (type->ty != TY::Tvector && type->isintegral ())
+ else if (type->ty != TY::Tvector && type->isIntegral ())
{
/* Integer comparison, no special handling required. */
tcmp = build_boolop (code, t1ref, t2ref);
}
- else if (type->ty != TY::Tvector && type->isfloating ())
+ else if (type->ty != TY::Tvector && type->isFloating ())
{
/* Floating-point comparison, don't compare padding in type. */
- if (!type->iscomplex ())
+ if (!type->isComplex ())
tcmp = build_float_identity (code, t1ref, t2ref);
else
{
@@ -1165,7 +1217,7 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init)
{
/* If the initializer was empty, use default zero initialization. */
if (vec_safe_is_empty (init))
- return build_constructor (type, NULL);
+ return build_padded_constructor (type, NULL);
/* Struct literals can be seen for special enums representing `_Complex',
make sure to reinterpret the literal as the correct type. */
@@ -1266,7 +1318,7 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init)
/* Ensure that we have consumed all values. */
gcc_assert (vec_safe_is_empty (init) || ANON_AGGR_TYPE_P (type));
- tree ctor = build_constructor (type, ve);
+ tree ctor = build_padded_constructor (type, ve);
if (constant_p)
TREE_CONSTANT (ctor) = 1;
@@ -1274,6 +1326,17 @@ build_struct_literal (tree type, vec <constructor_elt, va_gc> *init)
return ctor;
}
+/* Return a new zero padded CONSTRUCTOR node whose type is TYPE and values are
+ in the vec pointed to by VALS. */
+
+tree
+build_padded_constructor (tree type, vec<constructor_elt, va_gc> *vals)
+{
+ tree ctor = build_constructor (type, vals);
+ CONSTRUCTOR_ZERO_PADDING_BITS (ctor) = 1;
+ return ctor;
+}
+
/* Given the TYPE of an anonymous field inside T, return the
FIELD_DECL for the field. If not found return NULL_TREE.
Because anonymous types can nest, we must also search all
@@ -1607,7 +1670,7 @@ underlying_complex_expr (tree type, tree expr)
real_part (expr));
CONSTRUCTOR_APPEND_ELT (ve, TREE_CHAIN (TYPE_FIELDS (type)),
imaginary_part (expr));
- return build_constructor (type, ve);
+ return build_padded_constructor (type, ve);
}
/* Replace type in the reinterpret cast with a cast to the record type. */
@@ -1812,7 +1875,7 @@ build_array_from_val (Type *type, tree val)
for (size_t i = 0; i < dims; i++)
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), val);
- return build_constructor (build_ctype (type), elms);
+ return build_padded_constructor (build_ctype (type), elms);
}
/* Build a static array of type TYPE from an array of EXPS.
@@ -1839,15 +1902,13 @@ build_array_from_exprs (Type *type, Expressions *exps, bool const_p)
/* Create a new temporary to store the array. */
tree var = build_local_temp (satype);
+ /* Initialize the temporary. */
+ tree assign = modify_expr (var, build_padded_constructor (satype, elms));
+
/* Fill any alignment holes with zeroes. */
- TypeStruct *ts = etype->baseElemOf ()->isTypeStruct ();
- tree init = NULL;
- if (ts && (!identity_compare_p (ts->sym) || ts->sym->isUnionDeclaration ()))
- init = build_memset_call (var);
+ tree clear_padding = build_clear_padding_call (build_address (var));
- /* Initialize the temporary. */
- tree assign = modify_expr (var, build_constructor (satype, elms));
- return compound_expr (compound_expr (init, assign), var);
+ return compound_expr (compound_expr (assign, clear_padding), var);
}
@@ -2119,7 +2180,7 @@ call_side_effect_free_p (FuncDeclaration *func, Type *type)
/* Must be a `nothrow' function. */
TypeFunction *tf = func->type->toTypeFunction ();
- if (!tf->isnothrow ())
+ if (!tf->isNothrow ())
return false;
/* Return type can't be `void' or `noreturn', as that implies all work is
@@ -2128,7 +2189,7 @@ call_side_effect_free_p (FuncDeclaration *func, Type *type)
return false;
/* Only consider it as `pure' if it can't modify its arguments. */
- if (func->isPure () == PURE::const_)
+ if (dmd::isPure (func) == PURE::const_)
return true;
}
@@ -2137,7 +2198,7 @@ call_side_effect_free_p (FuncDeclaration *func, Type *type)
TypeFunction *tf = get_function_type (type);
/* Must be a `nothrow` function type. */
- if (tf == NULL || !tf->isnothrow ())
+ if (tf == NULL || !tf->isNothrow ())
return false;
/* Return type can't be `void' or `noreturn', as that implies all work is
@@ -2261,7 +2322,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
if (empty_aggregate_p (TREE_TYPE (targ)) && !TREE_ADDRESSABLE (targ)
&& TREE_CODE (targ) != CONSTRUCTOR)
{
- tree t = build_constructor (TREE_TYPE (targ), NULL);
+ tree t = build_padded_constructor (TREE_TYPE (targ), NULL);
targ = build2 (COMPOUND_EXPR, TREE_TYPE (t), targ, t);
}
@@ -2280,8 +2341,10 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
- The ABI of the function expects the callee to destroy its
arguments; when the caller is handles destruction, then `targ'
has already been made into a temporary. */
- if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor)
- || target.isCalleeDestroyingArgs (tf))
+ if (!can_elide_copy_p (arg)
+ && (arg->op == EXP::structLiteral
+ || (!sd->postblit && !sd->dtor)
+ || target.isCalleeDestroyingArgs (tf)))
targ = force_target_expr (targ);
targ = convert (build_reference_type (TREE_TYPE (targ)),
@@ -2571,7 +2634,7 @@ get_frame_for_symbol (Dsymbol *sym)
framefields = DECL_CHAIN (framefields);
}
- frame_ref = build_address (build_constructor (type, ve));
+ frame_ref = build_address (build_padded_constructor (type, ve));
}
}
@@ -2915,7 +2978,7 @@ get_frameinfo (FuncDeclaration *fd)
symbols, give it a decent error for now. */
if (requiresClosure != fd->requiresClosure
&& (fd->nrvo_var || !global.params.useGC))
- fd->checkClosure ();
+ dmd::checkClosure (fd);
/* Set-up a closure frame, this will be allocated on the heap. */
FRAMEINFO_CREATES_FRAME (ffi) = 1;
diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc
index 3eb3a76..e18f5d3 100644
--- a/gcc/d/d-compiler.cc
+++ b/gcc/d/d-compiler.cc
@@ -1,5 +1,5 @@
/* d-compiler.cc -- D frontend interface to the gcc back-end.
- Copyright (C) 2020-2024 Free Software Foundation, Inc.
+ Copyright (C) 2020-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "dmd/compiler.h"
+#include "dmd/errors.h"
#include "dmd/expression.h"
#include "dmd/identifier.h"
#include "dmd/module.h"
@@ -46,9 +47,9 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
Type *tb = type->toBasetype ();
- if (expr->type->isintegral ())
+ if (expr->type->isIntegral ())
cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type));
- else if (expr->type->isfloating ())
+ else if (expr->type->isFloating ())
cst = build_float_cst (expr->toReal (), expr->type);
else if (expr->op == EXP::arrayLiteral)
{
@@ -60,13 +61,13 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
for (size_t i = 0; i < elements->length; i++)
{
Expression *e = (*elements)[i];
- if (e->type->isintegral ())
+ if (e->type->isIntegral ())
{
tree value = build_integer_cst (e->toInteger (),
build_ctype (e->type));
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
}
- else if (e->type->isfloating ())
+ else if (e->type->isFloating ())
{
tree value = build_float_cst (e->toReal (), e->type);
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
@@ -164,7 +165,39 @@ Compiler::onParseModule (Module *m)
driver intends on compiling the import. */
bool
-Compiler::onImport (Module *)
+Compiler::onImport (Module *m)
{
- return false;
+ if (!includeImports)
+ return false;
+
+ if (m->filetype != FileType::d && m->filetype != FileType::c)
+ return false;
+
+ /* All imports modules are included except those in the runtime library. */
+ ModuleDeclaration *md = m->md;
+ if (md && md->id)
+ {
+ if (md->packages.length >= 1)
+ {
+ if (!strcmp (md->packages.ptr[0]->toChars (), "core")
+ || !strcmp (md->packages.ptr[0]->toChars (), "std")
+ || !strcmp (md->packages.ptr[0]->toChars (), "gcc")
+ || !strcmp (md->packages.ptr[0]->toChars (), "etc"))
+ return false;
+ }
+ else if (!strcmp (md->id->toChars (), "object"))
+ return false;
+ }
+ else if (m->ident)
+ {
+ if (!strcmp (m->ident->toChars (), "object"))
+ return false;
+ }
+
+ /* This import will be compiled. */
+ if (global.params.v.verbose)
+ message ("compileimport (%s)", m->srcfile.toChars ());
+
+ compiledImports.push (m);
+ return true;
}
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index 5c79cdf..c5b0d65 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -1,5 +1,5 @@
/* d-convert.cc -- Data type conversion routines.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -384,7 +384,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
case TY::Tstruct:
if (tbtype->ty == TY::Tstruct)
{
- if (totype->size () == etype->size ())
+ if (dmd::size (totype) == dmd::size (etype))
{
/* Allowed to cast to structs with same type size. */
result = build_vconvert (build_ctype (totype), exp);
@@ -467,8 +467,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
else if (tbtype->ty == TY::Tarray)
{
dinteger_t dim = ebtype->isTypeSArray ()->dim->toInteger ();
- dinteger_t esize = ebtype->nextOf ()->size ();
- dinteger_t tsize = tbtype->nextOf ()->size ();
+ dinteger_t esize = dmd::size (ebtype->nextOf ());
+ dinteger_t tsize = dmd::size (tbtype->nextOf ());
tree ptrtype = build_ctype (dmd::pointerTo (tbtype->nextOf ()));
@@ -498,10 +498,11 @@ convert_expr (tree exp, Type *etype, Type *totype)
{
/* And allows casting a static array to any struct type too.
Type sizes should have already been checked by the frontend. */
- gcc_assert (totype->size () == etype->size ());
+ gcc_assert (dmd::size (totype) == dmd::size (etype));
result = build_vconvert (build_ctype (totype), exp);
}
- else if (tbtype->ty == TY::Tvector && tbtype->size () == ebtype->size ())
+ else if (tbtype->ty == TY::Tvector
+ && dmd::size (tbtype) == dmd::size (ebtype))
{
/* Allow casting from array to vector as if its an unaligned load. */
tree type = build_ctype (totype);
@@ -526,8 +527,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
else if (tbtype->ty == TY::Tarray)
{
/* Assume tvoid->size() == 1. */
- dinteger_t fsize = ebtype->nextOf ()->toBasetype ()->size ();
- dinteger_t tsize = tbtype->nextOf ()->toBasetype ()->size ();
+ dinteger_t fsize = dmd::size (ebtype->nextOf ()->toBasetype ());
+ dinteger_t tsize = dmd::size (tbtype->nextOf ()->toBasetype ());
if (fsize != tsize)
{
@@ -594,7 +595,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
case TY::Tvector:
if (tbtype->ty == TY::Tsarray)
{
- if (tbtype->size () == ebtype->size ())
+ if (dmd::size (tbtype) == dmd::size (ebtype))
return build_vconvert (build_ctype (totype), exp);
}
break;
@@ -602,8 +603,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
default:
/* All casts between imaginary and non-imaginary result in 0.0,
except for casts between complex and imaginary types. */
- if (!ebtype->iscomplex () && !tbtype->iscomplex ()
- && (ebtype->isimaginary () != tbtype->isimaginary ()))
+ if (!ebtype->isComplex () && !tbtype->isComplex ()
+ && (ebtype->isImaginary () != tbtype->isImaginary ()))
{
warning (OPT_Wcast_result,
"cast from %qs to %qs will produce zero result",
@@ -687,7 +688,7 @@ convert_for_rvalue (tree expr, Type *etype, Type *totype)
CONSTRUCTOR_APPEND_ELT (elms, index, value);
}
- return build_constructor (build_ctype (totype), elms);
+ return build_padded_constructor (build_ctype (totype), elms);
}
}
@@ -740,7 +741,7 @@ check_valist_conversion (Expression *expr, Type *totype, bool in_assignment)
&& valist_array_p (decl->type));
/* OK if conversion between types is allowed. */
- if (type->implicitConvTo (totype) != MATCH::nomatch)
+ if (dmd::implicitConvTo (type, totype) != MATCH::nomatch)
return;
if (in_assignment)
@@ -787,7 +788,7 @@ convert_for_assignment (Expression *expr, Type *totype, bool literalp)
TypeSArray *sa_type = tbtype->isTypeSArray ();
uinteger_t count = sa_type->dim->toUInteger ();
- tree ctor = build_constructor (build_ctype (totype), NULL);
+ tree ctor = build_padded_constructor (build_ctype (totype), NULL);
if (count)
{
vec <constructor_elt, va_gc> *ce = NULL;
@@ -813,7 +814,7 @@ convert_for_assignment (Expression *expr, Type *totype, bool literalp)
/* D Front end uses IntegerExp(0) to mean zero-init an array or structure. */
if ((tbtype->ty == TY::Tsarray || tbtype->ty == TY::Tstruct)
- && ebtype->isintegral ())
+ && ebtype->isIntegral ())
{
tree ret = build_expr (expr, false, literalp);
gcc_assert (integer_zerop (ret));
diff --git a/gcc/d/d-ctfloat.cc b/gcc/d/d-ctfloat.cc
index e77365a..659d561 100644
--- a/gcc/d/d-ctfloat.cc
+++ b/gcc/d/d-ctfloat.cc
@@ -1,5 +1,5 @@
/* d-ctfloat.cc -- D frontend interface to the gcc back-end.
- Copyright (C) 2020-2024 Free Software Foundation, Inc.
+ Copyright (C) 2020-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,7 +33,7 @@ along with GCC; see the file COPYING3. If not see
real_t
CTFloat::fabs (real_t r)
{
- real_t x;
+ real_t x = {};
real_arithmetic (&x.rv (), ABS_EXPR, &r.rv (), NULL);
return x.normalize ();
}
@@ -43,7 +43,7 @@ CTFloat::fabs (real_t r)
real_t
CTFloat::ldexp (real_t r, int exp)
{
- real_t x;
+ real_t x = {};
real_ldexp (&x.rv (), &r.rv (), exp);
return x.normalize ();
}
@@ -87,7 +87,7 @@ CTFloat::isInfinity (real_t r)
real_t
CTFloat::parse (const char *buffer, bool &overflow)
{
- real_t r;
+ real_t r = {};
real_from_string3 (&r.rv (), buffer, TYPE_MODE (long_double_type_node));
/* Front-end checks overflow to see if the value is representable. */
diff --git a/gcc/d/d-diagnostic.cc b/gcc/d/d-diagnostic.cc
index b2accf9..55cb42e 100644
--- a/gcc/d/d-diagnostic.cc
+++ b/gcc/d/d-diagnostic.cc
@@ -1,5 +1,5 @@
/* d-diagnostics.cc -- D frontend interface to gcc diagnostics.
- Copyright (C) 2017-2024 Free Software Foundation, Inc.
+ Copyright (C) 2017-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -183,13 +183,14 @@ escape_d_format (const char *format)
front-end, which does not get translated by the gcc diagnostic routines. */
static void ATTRIBUTE_GCC_DIAG(3,0)
-d_diagnostic_report_diagnostic (const Loc &loc, int opt, const char *format,
- va_list ap, diagnostic_t kind, bool verbatim)
+d_diagnostic_report_diagnostic (const SourceLoc &loc, int opt,
+ const char *format, va_list ap,
+ diagnostic_t kind, bool verbatim)
{
va_list argp;
va_copy (argp, ap);
- if (loc.filename () || !verbatim)
+ if (loc.filename.length != 0 || !verbatim)
{
rich_location rich_loc (line_table, make_location_t (loc));
diagnostic_info diagnostic;
@@ -198,7 +199,7 @@ d_diagnostic_report_diagnostic (const Loc &loc, int opt, const char *format,
diagnostic_set_info_translated (&diagnostic, xformat, &argp,
&rich_loc, kind);
if (opt != 0)
- diagnostic.option_index = opt;
+ diagnostic.option_id = opt;
diagnostic_report_diagnostic (global_dc, &diagnostic);
}
@@ -207,8 +208,9 @@ d_diagnostic_report_diagnostic (const Loc &loc, int opt, const char *format,
/* Write verbatim messages with no location direct to stream. */
text_info text (expand_d_format (format), &argp, errno, nullptr);
- pp_format_verbatim (global_dc->printer, &text);
- pp_newline_and_flush (global_dc->printer);
+ pretty_printer *const pp = global_dc->get_reference_printer ();
+ pp_format_verbatim (pp, &text);
+ pp_newline_and_flush (pp);
}
va_end (argp);
@@ -219,8 +221,8 @@ d_diagnostic_report_diagnostic (const Loc &loc, int opt, const char *format,
error count depending on how KIND is treated. */
void D_ATTRIBUTE_FORMAT(2,0) ATTRIBUTE_GCC_DIAG(2,0)
-verrorReport (const Loc& loc, const char *format, va_list ap, ErrorKind kind,
- const char *prefix1, const char *prefix2)
+verrorReport (const SourceLoc loc, const char *format, va_list ap,
+ ErrorKind kind, const char *prefix1, const char *prefix2)
{
diagnostic_t diag_kind = DK_UNSPECIFIED;
int opt = 0;
@@ -240,7 +242,7 @@ verrorReport (const Loc& loc, const char *format, va_list ap, ErrorKind kind,
}
else if (kind == ErrorKind::warning)
{
- if (global.gag || global.params.warnings == DIAGNOSTICoff)
+ if (global.gag || global.params.useWarnings == DIAGNOSTICoff)
{
if (global.gag)
global.gaggedWarnings++;
@@ -249,7 +251,7 @@ verrorReport (const Loc& loc, const char *format, va_list ap, ErrorKind kind,
}
/* Warnings don't count if not treated as errors. */
- if (global.params.warnings == DIAGNOSTICerror)
+ if (global.params.useWarnings == DIAGNOSTICerror)
global.warnings++;
diag_kind = DK_WARNING;
@@ -303,7 +305,7 @@ verrorReport (const Loc& loc, const char *format, va_list ap, ErrorKind kind,
explicit location LOC. This doesn't increase the global error count. */
void D_ATTRIBUTE_FORMAT(2,0) ATTRIBUTE_GCC_DIAG(2,0)
-verrorReportSupplemental (const Loc& loc, const char* format, va_list ap,
+verrorReportSupplemental (const SourceLoc loc, const char* format, va_list ap,
ErrorKind kind)
{
if (kind == ErrorKind::error)
@@ -313,7 +315,7 @@ verrorReportSupplemental (const Loc& loc, const char* format, va_list ap,
}
else if (kind == ErrorKind::warning)
{
- if (global.params.warnings == DIAGNOSTICoff || global.gag)
+ if (global.params.useWarnings == DIAGNOSTICoff || global.gag)
return;
}
else if (kind == ErrorKind::deprecation)
diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
index 0d7f4a3..3778cc6 100644
--- a/gcc/d/d-frontend.cc
+++ b/gcc/d/d-frontend.cc
@@ -1,5 +1,5 @@
/* d-frontend.cc -- D frontend interface to the gcc back-end.
- Copyright (C) 2013-2024 Free Software Foundation, Inc.
+ Copyright (C) 2013-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -52,7 +52,7 @@ isBuiltin (FuncDeclaration *fd)
Return result; NULL if cannot evaluate it. */
Expression *
-eval_builtin (const Loc &loc, FuncDeclaration *fd, Expressions *arguments)
+eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
{
if (fd->builtin == BUILTIN::unimp)
return NULL;
@@ -79,11 +79,11 @@ eval_builtin (const Loc &loc, FuncDeclaration *fd, Expressions *arguments)
/* Build and return typeinfo type for TYPE. */
Type *
-getTypeInfoType (const Loc &loc, Type *type, Scope *sc, bool genObjCode)
+getTypeInfoType (Loc loc, Type *type, Scope *sc)
{
gcc_assert (type->ty != TY::Terror);
check_typeinfo_type (loc, sc);
- create_typeinfo (type, sc ? sc->_module->importedFrom : NULL, genObjCode);
+ create_typeinfo (type, sc);
return type->vtinfo->type;
}
diff --git a/gcc/d/d-frontend.h b/gcc/d/d-frontend.h
index 7cc5e5e..00f3666 100644
--- a/gcc/d/d-frontend.h
+++ b/gcc/d/d-frontend.h
@@ -1,5 +1,5 @@
/* d-frontend.h -- D frontend interface to the gcc back-end.
- Copyright (C) 2019-2024 Free Software Foundation, Inc.
+ Copyright (C) 2019-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/d-gimplify.cc b/gcc/d/d-gimplify.cc
index 55a5608..9e31f3a 100644
--- a/gcc/d/d-gimplify.cc
+++ b/gcc/d/d-gimplify.cc
@@ -1,5 +1,5 @@
/* D-specific tree lowering bits; see also gimple.cc.
- Copyright (C) 2020-2024 Free Software Foundation, Inc.
+ Copyright (C) 2020-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/d-incpath.cc b/gcc/d/d-incpath.cc
index 32ab0b7..155dc99 100644
--- a/gcc/d/d-incpath.cc
+++ b/gcc/d/d-incpath.cc
@@ -1,5 +1,5 @@
/* d-incpath.cc -- Set up combined import paths for the D frontend.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -67,47 +67,41 @@ prefixed_path (const char *path, const char *iprefix)
/* Add PATHS to the global import lookup path. */
static void
-add_globalpaths (Strings *paths)
+add_globalpaths (Strings &paths)
{
- if (paths)
+ for (size_t i = 0; i < paths.length; i++)
{
- for (size_t i = 0; i < paths->length; i++)
- {
- const char *path = (*paths)[i];
- const char *target = lrealpath (path);
-
- if (target == NULL || !FileName::exists (target))
- {
- if (target)
- free (CONST_CAST (char *, target));
- continue;
- }
+ const char *path = paths[i];
+ const char *target = lrealpath (path);
- global.path.push (target);
+ if (target == NULL || !FileName::exists (target))
+ {
+ if (target)
+ free (CONST_CAST (char *, target));
+ continue;
}
+
+ global.path.push (target);
}
}
/* Add PATHS to the global file import lookup path. */
static void
-add_filepaths (Strings *paths)
+add_filepaths (Strings &paths)
{
- if (paths)
+ for (size_t i = 0; i < paths.length; i++)
{
- for (size_t i = 0; i < paths->length; i++)
- {
- const char *path = (*paths)[i];
- const char *target = lrealpath (path);
-
- if (!FileName::exists (target))
- {
- free (CONST_CAST (char *, target));
- continue;
- }
+ const char *path = paths[i];
+ const char *target = lrealpath (path);
- global.filePath.push (target);
+ if (!FileName::exists (target))
+ {
+ free (CONST_CAST (char *, target));
+ continue;
}
+
+ global.filePath.push (target);
}
}
@@ -139,7 +133,7 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc)
bool found = false;
for (size_t i = 0; i < global.params.imppath.length; i++)
{
- if (strcmp (path, global.params.imppath[i]) == 0)
+ if (strcmp (path, global.params.imppath[i].path) == 0)
{
found = true;
break;
@@ -166,9 +160,13 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc)
/* Add import search paths. */
for (size_t i = 0; i < global.params.imppath.length; i++)
{
- const char *path = global.params.imppath[i];
+ const char *path = global.params.imppath[i].path;
if (path)
- add_globalpaths (FileName::splitPath (path));
+ {
+ Strings array;
+ FileName::appendSplitPath (path, array);
+ add_globalpaths (array);
+ }
}
/* Add string import search paths. */
@@ -176,6 +174,10 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc)
{
const char *path = global.params.fileImppath[i];
if (path)
- add_filepaths (FileName::splitPath (path));
+ {
+ Strings array;
+ FileName::appendSplitPath (path, array);
+ add_filepaths (array);
+ }
}
}
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 89ffa7e..ec2ea59 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -1,5 +1,5 @@
/* d-lang.cc -- Language-dependent hooks for D.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -302,7 +302,7 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options)
/* Warnings and deprecations are disabled by default. */
global.params.useDeprecated = DIAGNOSTICinform;
- global.params.warnings = DIAGNOSTICoff;
+ global.params.useWarnings = DIAGNOSTICoff;
global.params.v.errorLimit = flag_max_errors;
global.params.v.messageStyle = MessageStyle::gnu;
@@ -450,7 +450,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
case OPT_fdebug:
- global.params.debuglevel = value ? 1 : 0;
+ global.params.debugEnabled = value ? true : false;
break;
case OPT_fdebug_:
@@ -460,7 +460,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
}
- error ("bad argument for %<-fdebug%>: %qs", arg);
+ error ("bad argument for %<-fdebug=%>: %qs", arg);
break;
case OPT_fdoc:
@@ -510,6 +510,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
case CppStdRevisionCpp14:
case CppStdRevisionCpp17:
case CppStdRevisionCpp20:
+ case CppStdRevisionCpp23:
global.params.cplusplus = (CppStdRevision) value;
break;
@@ -522,6 +523,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.ignoreUnsupportedPragmas = value;
break;
+ case OPT_finclude_imports:
+ includeImports = true;
+ break;
+
case OPT_finvariants:
global.params.useInvariants = value ? CHECKENABLEon : CHECKENABLEoff;
break;
@@ -533,7 +538,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
case OPT_fmodule_file_:
global.params.modFileAliasStrings.push (arg);
if (!strchr (arg, '='))
- error ("bad argument for %<-fmodule-file%>: %qs", arg);
+ error ("bad argument for %<-fmodule-file=%>: %qs", arg);
break;
case OPT_fmoduleinfo:
@@ -563,6 +568,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.previewIn = value;
global.params.fix16997 = value;
global.params.noSharedAccess = FeatureState::enabled;
+ global.params.safer = FeatureState::enabled;
global.params.rvalueRefParam = FeatureState::enabled;
global.params.inclusiveInContracts = value;
global.params.systemVariables = FeatureState::enabled;
@@ -613,6 +619,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.noSharedAccess = FeatureState::enabled;
break;
+ case OPT_fpreview_safer:
+ global.params.safer = FeatureState::enabled;
+ break;
+
case OPT_fpreview_rvaluerefparam:
global.params.rvalueRefParam = FeatureState::enabled;
break;
@@ -695,7 +705,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
}
- error ("bad argument for %<-fversion%>: %qs", arg);
+ error ("bad argument for %<-fversion=%>: %qs", arg);
break;
case OPT_H:
@@ -772,7 +782,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
case OPT_Wall:
if (value)
- global.params.warnings = DIAGNOSTICinform;
+ global.params.useWarnings = DIAGNOSTICinform;
break;
case OPT_Wdeprecated:
@@ -781,7 +791,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
case OPT_Werror:
if (value)
- global.params.warnings = DIAGNOSTICerror;
+ global.params.useWarnings = DIAGNOSTICerror;
break;
case OPT_Wspeculative:
@@ -907,7 +917,7 @@ d_post_options (const char ** fn)
/* Error about use of deprecated features. */
if (global.params.useDeprecated == DIAGNOSTICinform
- && global.params.warnings == DIAGNOSTICerror)
+ && global.params.useWarnings == DIAGNOSTICerror)
global.params.useDeprecated = DIAGNOSTICerror;
if (flag_excess_precision == EXCESS_PRECISION_DEFAULT)
@@ -920,7 +930,8 @@ d_post_options (const char ** fn)
global.params.v.errorLimit = flag_max_errors;
global.params.v.showColumns = flag_show_column;
- global.params.v.printErrorContext = flag_diagnostics_show_caret;
+ global.params.v.errorPrintMode = flag_diagnostics_show_caret
+ ? ErrorPrintMode::printErrorContext : ErrorPrintMode::simpleError;
/* Keep the front-end location type in sync with params. */
Loc::set (global.params.v.showColumns, global.params.v.messageStyle);
@@ -933,7 +944,12 @@ d_post_options (const char ** fn)
/* The front-end parser only has access to `compileEnv', synchronize its
fields with params. */
global.compileEnv.previewIn = global.params.previewIn;
+ global.compileEnv.transitionIn = global.params.v.vin;
global.compileEnv.ddocOutput = global.params.ddoc.doOutput;
+ global.compileEnv.cCharLookupTable =
+ IdentifierCharLookup::forTable (IdentifierTable::C11);
+ global.compileEnv.dCharLookupTable =
+ IdentifierCharLookup::forTable (IdentifierTable::LR);
if (warn_return_type == -1)
warn_return_type = 0;
@@ -1073,9 +1089,9 @@ d_parse_file (void)
/* Buffer for contents of .ddoc files. */
OutBuffer ddocbuf;
- /* In this mode, the first file name is supposed to be a duplicate
- of one of the input files. */
- if (d_option.fonly && strcmp (d_option.fonly, main_input_filename) != 0)
+ /* In this mode, the main input file is supposed to be the same as the one
+ given by -fonly=. */
+ if (d_option.fonly && !endswith (main_input_filename, d_option.fonly))
error ("%<-fonly=%> argument is different from first input file name");
for (size_t i = 0; i < num_in_fnames; i++)
@@ -1102,7 +1118,7 @@ d_parse_file (void)
if (count < 0)
{
- error (Loc ("stdin", 0, 0), "%s", xstrerror (errno));
+ error (Loc::singleFilename ("stdin"), "%s", xstrerror (errno));
free (buffer);
continue;
}
@@ -1297,6 +1313,21 @@ d_parse_file (void)
dmd::semantic3 (m, NULL);
}
+ if (includeImports)
+ {
+ for (size_t i = 0; i < compiledImports.length; i++)
+ {
+ Module *m = compiledImports[i];
+ gcc_assert (m->isRoot ());
+
+ if (global.params.v.verbose)
+ message ("semantic3 %s", m->toChars ());
+
+ dmd::semantic3 (m, NULL);
+ modules.push (m);
+ }
+ }
+
Module::runDeferredSemantic3 ();
/* Check again, incase semantic3 pass loaded any more modules. */
@@ -1705,8 +1736,8 @@ d_types_compatible_p (tree x, tree y)
return true;
/* Type system allows implicit conversion between. */
- if (tx->implicitConvTo (ty) != MATCH::nomatch
- || ty->implicitConvTo (tx) != MATCH::nomatch)
+ if (dmd::implicitConvTo (tx, ty) != MATCH::nomatch
+ || dmd::implicitConvTo (ty, tx) != MATCH::nomatch)
return true;
}
diff --git a/gcc/d/d-longdouble.cc b/gcc/d/d-longdouble.cc
index e4c8c5e6..193a828 100644
--- a/gcc/d/d-longdouble.cc
+++ b/gcc/d/d-longdouble.cc
@@ -1,5 +1,5 @@
/* d-longdouble.cc -- Software floating-point emulation for the frontend.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -113,7 +113,7 @@ longdouble::to_bool (void) const
longdouble
longdouble::add (const longdouble &r) const
{
- longdouble x;
+ longdouble x = {};
real_arithmetic (&x.rv (), PLUS_EXPR, &this->rv (), &r.rv ());
return x.normalize ();
}
@@ -121,7 +121,7 @@ longdouble::add (const longdouble &r) const
longdouble
longdouble::sub (const longdouble &r) const
{
- longdouble x;
+ longdouble x = {};
real_arithmetic (&x.rv (), MINUS_EXPR, &this->rv (), &r.rv ());
return x.normalize ();
}
@@ -129,7 +129,7 @@ longdouble::sub (const longdouble &r) const
longdouble
longdouble::mul (const longdouble &r) const
{
- longdouble x;
+ longdouble x = {};
real_arithmetic (&x.rv (), MULT_EXPR, &this->rv (), &r.rv ());
return x.normalize ();
}
@@ -137,7 +137,7 @@ longdouble::mul (const longdouble &r) const
longdouble
longdouble::div (const longdouble &r) const
{
- longdouble x;
+ longdouble x = {};
real_arithmetic (&x.rv (), RDIV_EXPR, &this->rv (), &r.rv ());
return x.normalize ();
}
@@ -145,7 +145,7 @@ longdouble::div (const longdouble &r) const
longdouble
longdouble::mod (const longdouble &r) const
{
- longdouble x;
+ longdouble x = {};
real_value q;
if (r.rv ().cl == rvc_zero || REAL_VALUE_ISINF (this->rv ()))
@@ -172,7 +172,7 @@ longdouble::mod (const longdouble &r) const
longdouble
longdouble::neg (void) const
{
- longdouble x;
+ longdouble x = {};
real_arithmetic (&x.rv (), NEGATE_EXPR, &this->rv (), NULL);
return x.normalize ();
}
diff --git a/gcc/d/d-port.cc b/gcc/d/d-port.cc
index f15f24d..a66fabc 100644
--- a/gcc/d/d-port.cc
+++ b/gcc/d/d-port.cc
@@ -1,5 +1,5 @@
/* d-port.cc -- D frontend interface to the gcc back-end.
- Copyright (C) 2013-2024 Free Software Foundation, Inc.
+ Copyright (C) 2013-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -74,7 +74,7 @@ Port::strupr (char *s)
bool
Port::isFloat32LiteralOutOfRange (const char *buffer)
{
- real_t r;
+ real_t r = {};
real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node));
@@ -87,7 +87,7 @@ Port::isFloat32LiteralOutOfRange (const char *buffer)
bool
Port::isFloat64LiteralOutOfRange (const char *buffer)
{
- real_t r;
+ real_t r = {};
real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node));
diff --git a/gcc/d/d-spec.cc b/gcc/d/d-spec.cc
index cf0d418..c788048 100644
--- a/gcc/d/d-spec.cc
+++ b/gcc/d/d-spec.cc
@@ -1,5 +1,5 @@
/* d-spec.c -- Specific flags and argument handling of the D front end.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -104,8 +104,8 @@ lang_specific_driver (cl_decoded_option **in_decoded_options,
/* The total number of arguments with the new stuff. */
unsigned int num_args = 1;
- /* "-fonly" if it appears on the command line. */
- const char *only_source_option = 0;
+ /* "-fonly=" if it appears on the command line. */
+ const char *only_source_arg = 0;
/* Whether the -o option was used. */
bool saw_opt_o = false;
@@ -280,13 +280,13 @@ lang_specific_driver (cl_decoded_option **in_decoded_options,
case OPT_fonly_:
args[i] |= SKIPOPT;
- only_source_option = decoded_options[i].orig_option_with_args_text;
+ only_source_arg = arg;
if (arg != NULL)
{
- const char *suffix = strrchr (only_source_option, '.');
+ const char *suffix = strrchr (only_source_arg, '.');
if (suffix == NULL || strcmp (suffix, ".d") != 0)
- only_source_option = concat (only_source_option, ".d", NULL);
+ only_source_arg = concat (only_source_arg, ".d", NULL);
}
break;
@@ -335,48 +335,52 @@ lang_specific_driver (cl_decoded_option **in_decoded_options,
+ (phobos_library != PHOBOS_NOLINK) * 4 + 2;
new_decoded_options = XNEWVEC (cl_decoded_option, num_args);
- i = 0;
j = 0;
/* Copy the 0th argument, i.e., the name of the program itself. */
- new_decoded_options[j++] = decoded_options[i++];
+ new_decoded_options[j++] = decoded_options[0];
/* NOTE: We start at 1 now, not 0. */
- while (i < argc)
+ for (i = 1; i < argc; i++)
{
if (args[i] & SKIPOPT)
- {
- ++i;
- continue;
- }
-
- new_decoded_options[j] = decoded_options[i];
+ continue;
if (!saw_libcxx && (args[i] & WITHLIBCXX))
{
- --j;
saw_libcxx = &decoded_options[i];
+ continue;
}
- if (args[i] & DSOURCE)
+ if (only_source_arg && (args[i] & DSOURCE))
{
- if (only_source_option)
- --j;
+ if (!endswith (decoded_options[i].arg, only_source_arg))
+ continue;
}
- i++;
+ new_decoded_options[j] = decoded_options[i];
j++;
}
- if (only_source_option)
+ if (only_source_arg)
{
- const char *only_source_arg = only_source_option + 7;
+ /* Generate -fonly= option, then copy D input sources that were initially
+ skipped in first pass over all decoded_options. */
generate_option (OPT_fonly_, only_source_arg, 1, CL_DRIVER,
&new_decoded_options[j]);
j++;
- generate_option_input_file (only_source_arg,
- &new_decoded_options[j++]);
+ for (i = 1; i < argc; i++)
+ {
+ if (!(args[i] & DSOURCE))
+ continue;
+
+ if (endswith (decoded_options[i].arg, only_source_arg))
+ continue;
+
+ new_decoded_options[j] = decoded_options[i];
+ j++;
+ }
}
/* If no reason to link against libphobos library, then don't add it. */
diff --git a/gcc/d/d-system.h b/gcc/d/d-system.h
index 426e3f8..7df5bdc 100644
--- a/gcc/d/d-system.h
+++ b/gcc/d/d-system.h
@@ -1,5 +1,5 @@
/* d-system.h -- DMD frontend inclusion of gcc header files.
- * Copyright (C) 2018-2024 Free Software Foundation, Inc.
+ * Copyright (C) 2018-2025 Free Software Foundation, Inc.
*
* GCC is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/d-target-def.h b/gcc/d/d-target-def.h
index 5eaa1d7..39a7f06 100644
--- a/gcc/d/d-target-def.h
+++ b/gcc/d/d-target-def.h
@@ -1,5 +1,5 @@
/* d-target-def.h -- Default initializers for D target hooks.
- Copyright (C) 2017-2024 Free Software Foundation, Inc.
+ Copyright (C) 2017-2025 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index dd46e53..ce25bf8 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -1,5 +1,5 @@
/* d-target.cc -- Target interface for the D front end.
- Copyright (C) 2013-2024 Free Software Foundation, Inc.
+ Copyright (C) 2013-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -241,7 +241,7 @@ Target::fieldalign (Type *type)
/* Returns a Type for the va_list type of the target. */
Type *
-Target::va_listType (const Loc &, Scope *)
+Target::va_listType (Loc, Scope *)
{
if (this->tvalist)
return this->tvalist;
@@ -274,13 +274,13 @@ Target::isVectorTypeSupported (int sz, Type *type)
type = Type::tuns8;
/* No support for non-trivial types, complex types, or booleans. */
- if (!type->isTypeBasic () || type->iscomplex () || type->ty == TY::Tbool)
+ if (!type->isTypeBasic () || type->isComplex () || type->ty == TY::Tbool)
return 2;
/* In [simd/vector extensions], which vector types are supported depends on
the target. The implementation is expected to only support the vector
types that are implemented in the target's hardware. */
- unsigned HOST_WIDE_INT nunits = sz / type->size ();
+ unsigned HOST_WIDE_INT nunits = sz / dmd::size (type);
tree ctype = build_vector_type (build_ctype (type), nunits);
if (!targetm.vector_mode_supported_p (TYPE_MODE (ctype)))
@@ -300,7 +300,7 @@ Target::isVectorOpSupported (Type *type, EXP op, Type *)
return true;
/* Don't support if type is non-scalar, such as __vector(void[]). */
- if (!type->isscalar ())
+ if (!type->isScalar ())
return false;
/* Don't support if expression cannot be represented. */
@@ -314,7 +314,7 @@ Target::isVectorOpSupported (Type *type, EXP op, Type *)
case EXP::mod:
case EXP::modAssign:
/* fmod() is lowered as a function call. */
- if (type->isfloating ())
+ if (type->isFloating ())
return false;
break;
@@ -449,11 +449,11 @@ Target::isReturnOnStack (TypeFunction *tf, bool)
/* Need the back-end type to determine this, but this is called from the
frontend before semantic processing is finished. An accurate value
is not currently needed anyway. */
- if (tf->isref ())
+ if (tf->isRef ())
return false;
Type *tn = tf->next->toBasetype ();
- if (tn->size () == SIZE_INVALID)
+ if (dmd::size (tn) == SIZE_INVALID)
return false;
return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray);
@@ -517,7 +517,7 @@ d_handle_target_object_format (void)
LOC is the location to use for the returned expression. */
Expression *
-Target::getTargetInfo (const char *key, const Loc &loc)
+Target::getTargetInfo (const char *key, Loc loc)
{
unsigned ix;
d_target_info_spec *spec;
@@ -583,8 +583,28 @@ Target::preferPassByRef (Type *param_type)
{
/* See note in Target::isReturnOnStack. */
Type *tb = param_type->toBasetype ();
- if (tb->size () == SIZE_INVALID)
+ if (dmd::size (tb) == SIZE_INVALID)
return false;
return (tb->ty == TY::Tstruct || tb->ty == TY::Tsarray);
}
+
+/* Returns true if the specified bit-field FIELD contributes to the alignment
+ of the containing aggregate. */
+
+bool
+TargetC::contributesToAggregateAlignment(BitFieldDeclaration *field)
+{
+ if (this->bitFieldStyle == TargetC::BitFieldStyle::MS)
+ return true;
+
+ if (PCC_BITFIELD_TYPE_MATTERS)
+ {
+ /* Named bit-fields contribute to alignment. Some targets also apply the
+ same rules to unnamed bit-fields too. */
+ if (!field->isAnonymous () || targetm.align_anon_bitfield ())
+ return true;
+ }
+
+ return false;
+}
diff --git a/gcc/d/d-target.def b/gcc/d/d-target.def
index 0b0332d..c5a6e96 100644
--- a/gcc/d/d-target.def
+++ b/gcc/d/d-target.def
@@ -1,5 +1,5 @@
/* d-target.def -- Target hook definitions for the D front end.
- Copyright (C) 2017-2024 Free Software Foundation, Inc.
+ Copyright (C) 2017-2025 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
diff --git a/gcc/d/d-target.h b/gcc/d/d-target.h
index 1958ec5..b781419 100644
--- a/gcc/d/d-target.h
+++ b/gcc/d/d-target.h
@@ -1,5 +1,5 @@
/* d-target.h -- Data structure definitions for target-specific D behavior.
- Copyright (C) 2017-2024 Free Software Foundation, Inc.
+ Copyright (C) 2017-2025 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
diff --git a/gcc/d/d-tree.def b/gcc/d/d-tree.def
index b076c63..2ca0c13 100644
--- a/gcc/d/d-tree.def
+++ b/gcc/d/d-tree.def
@@ -1,6 +1,6 @@
/* d-tree.def -- Definitions and documentation for additional tree codes used
in the D compiler (see tree.def for standard codes).
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
index 492c669..9d576e2 100644
--- a/gcc/d/d-tree.h
+++ b/gcc/d/d-tree.h
@@ -1,5 +1,5 @@
/* d-tree.h -- Definitions and declarations for code generation.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -534,7 +534,8 @@ extern Expression *d_eval_constant_expression (const Loc &, tree);
extern void d_init_versions (void);
/* In d-codegen.cc. */
-extern location_t make_location_t (const Loc &);
+extern location_t make_location_t (const SourceLoc &);
+extern location_t make_location_t (const Loc);
extern tree d_decl_context (Dsymbol *);
extern tree copy_aggregate_type (tree);
extern bool declaration_reference_p (Declaration *);
@@ -567,6 +568,7 @@ extern tree d_mark_read (tree);
extern tree build_memcmp_call (tree, tree, tree);
extern tree build_memcpy_call (tree, tree, tree);
extern tree build_memset_call (tree, tree = NULL_TREE);
+extern tree build_clear_padding_call (tree);
extern bool identity_compare_p (StructDeclaration *);
extern tree build_float_identity (tree_code, tree, tree);
extern tree build_struct_comparison (tree_code, StructDeclaration *,
@@ -574,6 +576,7 @@ extern tree build_struct_comparison (tree_code, StructDeclaration *,
extern tree build_array_struct_comparison (tree_code, StructDeclaration *,
tree, tree, tree);
extern tree build_struct_literal (tree, vec <constructor_elt, va_gc> *);
+extern tree build_padded_constructor (tree, vec <constructor_elt, va_gc> *);
extern tree component_ref (tree, tree);
extern tree build_assign (tree_code, tree, tree);
extern tree modify_expr (tree, tree);
@@ -703,11 +706,10 @@ extern tree get_classinfo_decl (ClassDeclaration *);
extern void check_typeinfo_type (const Loc &, Scope *, Expression * = NULL);
extern tree build_typeinfo (const Loc &, Type *, Expression * = NULL);
extern tree build_typeinfo (Expression *, Type *);
-extern void create_typeinfo (Type *, Module *, bool = true);
+extern void create_typeinfo (Type *, Scope *);
extern void create_tinfo_types (Module *);
extern void layout_cpp_typeinfo (ClassDeclaration *);
extern tree get_cpp_typeinfo_decl (ClassDeclaration *);
-extern bool speculative_type_p (Type *);
/* In toir.cc. */
extern void push_binding_level (level_kind);
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 0a87c85..9ddf7cf 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -1,5 +1,5 @@
/* decl.cc -- Lower D frontend declarations to GCC trees.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/nspace.h"
#include "dmd/target.h"
#include "dmd/template.h"
+#include "dmd/typinf.h"
#include "tree.h"
#include "tree-iterator.h"
@@ -255,18 +256,18 @@ public:
void visit (Module *d) final override
{
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
build_module_tree (d);
- d->semanticRun = PASS::obj;
+ d->semanticRun (PASS::obj);
}
/* Write the imported symbol to debug. */
void visit (Import *d) final override
{
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
/* Implements import declarations by telling the debug back-end we are
@@ -319,7 +320,7 @@ public:
false, false);
}
- d->semanticRun = PASS::obj;
+ d->semanticRun (PASS::obj);
}
/* Finish a top-level `asm` definition. */
@@ -350,7 +351,7 @@ public:
void visit (AttribDeclaration *d) final override
{
- Dsymbols *ds = d->include (NULL);
+ Dsymbols *ds = dmd::include (d, NULL);
if (!ds)
return;
@@ -471,7 +472,7 @@ public:
void visit (StructDeclaration *d) final override
{
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
if (d->type->ty == TY::Terror)
@@ -519,7 +520,7 @@ public:
if (d->xhash)
this->build_dsymbol (d->xhash);
- d->semanticRun = PASS::obj;
+ d->semanticRun (PASS::obj);
}
/* Finish semantic analysis of functions in vtbl for class CD. */
@@ -541,7 +542,7 @@ public:
has_errors = true;
/* No name hiding to check for. */
- if (!d->isFuncHidden (fd) || fd->isFuture ())
+ if (!dmd::isFuncHidden (d, fd) || fd->isFuture ())
continue;
/* The function fd is hidden from the view of the class.
@@ -561,10 +562,8 @@ public:
if (fd2->isFuture ())
continue;
- if (FuncDeclaration::leastAsSpecialized (fd, fd2, NULL)
- == MATCH::nomatch
- && FuncDeclaration::leastAsSpecialized (fd2, fd, NULL)
- == MATCH::nomatch)
+ if (dmd::leastAsSpecialized (fd, fd2, NULL) == MATCH::nomatch
+ && dmd::leastAsSpecialized (fd2, fd, NULL) == MATCH::nomatch)
continue;
/* Hiding detected; same name, overlapping specializations. */
@@ -589,7 +588,7 @@ public:
void visit (ClassDeclaration *d) final override
{
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
if (d->type->ty == TY::Terror)
@@ -618,7 +617,7 @@ public:
/* Generate C symbols. */
d->csym = get_classinfo_decl (d);
- Dsymbol *vtblsym = d->vtblSymbol ();
+ Dsymbol *vtblsym = dmd::vtblSymbol (d);
vtblsym->csym = get_vtable_decl (d);
tree sinit = aggregate_initializer_decl (d);
@@ -652,10 +651,10 @@ public:
}
DECL_INITIAL (vtblsym->csym)
- = build_constructor (TREE_TYPE (vtblsym->csym), elms);
+ = build_padded_constructor (TREE_TYPE (vtblsym->csym), elms);
d_finish_decl (vtblsym->csym);
- d->semanticRun = PASS::obj;
+ d->semanticRun (PASS::obj);
}
/* Write out compiler generated TypeInfo and vtables for the given interface
@@ -663,7 +662,7 @@ public:
void visit (InterfaceDeclaration *d) final override
{
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
if (d->type->ty == TY::Terror)
@@ -698,7 +697,7 @@ public:
DECL_INITIAL (d->csym) = layout_classinfo (d);
d_finish_decl (d->csym);
- d->semanticRun = PASS::obj;
+ d->semanticRun (PASS::obj);
}
/* Write out compiler generated TypeInfo and initializer for the given
@@ -706,10 +705,10 @@ public:
void visit (EnumDeclaration *d) final override
{
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
- if (d->errors || d->type->ty == TY::Terror)
+ if (d->errors () || d->type->ty == TY::Terror)
{
error_at (make_location_t (d->loc),
"had semantic errors when compiling");
@@ -729,7 +728,7 @@ public:
create_typeinfo (d->type, NULL);
TypeEnum *tc = d->type->isTypeEnum ();
- if (tc->sym->members && !d->type->isZeroInit ())
+ if (tc->sym->members && !dmd::isZeroInit (d->type))
{
/* Generate static initializer. */
d->sinit = enum_initializer_decl (d);
@@ -737,7 +736,7 @@ public:
d_finish_decl (d->sinit);
}
- d->semanticRun = PASS::obj;
+ d->semanticRun (PASS::obj);
}
/* Finish up a variable declaration and push it into the current scope.
@@ -745,7 +744,7 @@ public:
void visit (VarDeclaration *d) final override
{
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
if (d->type->ty == TY::Terror)
@@ -783,7 +782,7 @@ public:
{
/* Do not store variables we cannot take the address of,
but keep the values for purposes of debugging. */
- if (d->type->isscalar () && !dmd::hasPointers (d->type))
+ if (d->type->isScalar () && !dmd::hasPointers (d->type))
{
tree decl = get_symbol_decl (d);
d_pushdecl (decl);
@@ -792,6 +791,12 @@ public:
}
else if (d->isDataseg ())
{
+ /* When the front-end type size is invalid, an error has already been
+ given for the declaration or type. */
+ dinteger_t size = dmd::size (d->type, d->loc);
+ if (size == SIZE_INVALID)
+ return;
+
tree decl = get_symbol_decl (d);
/* Only need to build the VAR_DECL for extern declarations. */
@@ -805,9 +810,7 @@ public:
return;
/* How big a symbol can be should depend on back-end. */
- tree size = build_integer_cst (d->type->size (d->loc),
- build_ctype (Type::tsize_t));
- if (!valid_constant_size_p (size))
+ if (!valid_constant_size_p (build_integer_cst (size, size_type_node)))
{
error_at (make_location_t (d->loc), "size is too large");
return;
@@ -823,7 +826,7 @@ public:
DECL_INITIAL (decl) = build_expr (e, true);
}
}
- else if (!d->type->isZeroInit ())
+ else if (!dmd::isZeroInit (d->type))
{
/* Use default initializer for the type. */
if (TypeStruct *ts = d->type->isTypeStruct ())
@@ -836,8 +839,9 @@ public:
}
/* Frontend should have already caught this. */
- gcc_assert (!integer_zerop (size)
- || d->type->toBasetype ()->isTypeSArray ());
+ gcc_assert ((size != 0 && size != SIZE_INVALID)
+ || d->type->toBasetype ()->isTypeSArray ()
+ || d->isCsymbol ());
d_finish_decl (decl);
@@ -890,7 +894,7 @@ public:
}
}
- d->semanticRun = PASS::obj;
+ d->semanticRun (PASS::obj);
}
/* Generate and compile a static TypeInfo declaration, but only if it is
@@ -898,16 +902,16 @@ public:
void visit (TypeInfoDeclaration *d) final override
{
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
- if (speculative_type_p (d->tinfo))
+ if (dmd::isSpeculativeType (d->tinfo))
return;
tree t = get_typeinfo_decl (d);
DECL_INITIAL (t) = layout_typeinfo (d);
d_finish_decl (t);
- d->semanticRun = PASS::obj;
+ d->semanticRun (PASS::obj);
}
/* Finish up a function declaration and compile it all the way
@@ -916,7 +920,7 @@ public:
void visit (FuncDeclaration *d) final override
{
/* Already generated the function. */
- if (d->semanticRun >= PASS::obj)
+ if (d->semanticRun () >= PASS::obj)
return;
/* Don't emit any symbols from gcc.attributes module. */
@@ -958,7 +962,7 @@ public:
}
/* Ensure all semantic passes have run. */
- if (d->semanticRun < PASS::semantic3)
+ if (d->semanticRun () < PASS::semantic3)
{
gcc_assert (!doing_semantic_analysis_p);
@@ -972,8 +976,8 @@ public:
return;
/* Start generating code for this function. */
- gcc_assert (d->semanticRun == PASS::semantic3done);
- d->semanticRun = PASS::obj;
+ gcc_assert (d->semanticRun () == PASS::semantic3done);
+ d->semanticRun (PASS::obj);
/* Duplicated FuncDeclarations map to the same symbol. Check if this
is the one declaration which will be emitted. */
@@ -1116,7 +1120,7 @@ build_decl_tree (Dsymbol *d)
if (d->loc.filename ())
input_location = make_location_t (d->loc);
else
- input_location = make_location_t (Loc ("<no_file>", 1, 0));
+ input_location = make_location_t (Loc::singleFilename ("<no_file>"));
DeclVisitor v = DeclVisitor ();
v.build_dsymbol (d);
@@ -1180,7 +1184,7 @@ maybe_build_decl_tree (Declaration *decl)
/* Still running semantic analysis on declaration, or it has already had its
code generated. */
- if (doing_semantic_analysis_p || decl->semanticRun >= PASS::obj)
+ if (doing_semantic_analysis_p || decl->semanticRun () >= PASS::obj)
return decl->csym;
if (error_operand_p (decl->csym))
@@ -1247,7 +1251,7 @@ get_symbol_decl (Declaration *decl)
/* CONST_DECL was initially intended for enumerals and may be used for
scalars in general, but not for aggregates. Here a non-constant
value is generated anyway so as its value can be used. */
- if (!vd->canTakeAddressOf () && !vd->type->isscalar ())
+ if (!vd->canTakeAddressOf () && !vd->type->isScalar ())
{
gcc_assert (vd->_init && !vd->_init->isVoidInitializer ());
Expression *ie = dmd::initializerToExpression (vd->_init);
@@ -1308,7 +1312,7 @@ get_symbol_decl (Declaration *decl)
/* Cannot make an expression out of a void initializer. */
gcc_assert (vd->_init && !vd->_init->isVoidInitializer ());
/* Non-scalar manifest constants have already been dealt with. */
- gcc_assert (vd->type->isscalar ());
+ gcc_assert (vd->type->isScalar ());
Expression *ie = dmd::initializerToExpression (vd->_init);
DECL_INITIAL (decl->csym) = build_expr (ie, true);
@@ -1325,7 +1329,7 @@ get_symbol_decl (Declaration *decl)
/* `const` applies to data that cannot be changed by the const reference
to that data. It may, however, be changed by another reference to that
same data. */
- if (vd->isConst () && !vd->isDataseg ())
+ if (vd->isConst () && !vd->isResult () && !vd->isDataseg ())
TREE_READONLY (decl->csym) = 1;
}
@@ -2213,7 +2217,7 @@ get_vtable_decl (ClassDeclaration *decl)
will have a different type. However the back-end seems to accept this. */
tree type = build_ctype (dmd::sarrayOf (Type::tvoidptr, decl->vtbl.length));
- Dsymbol *vtblsym = decl->vtblSymbol ();
+ Dsymbol *vtblsym = dmd::vtblSymbol (decl);
vtblsym->csym = declare_extern_var (ident, type);
DECL_LANG_SPECIFIC (vtblsym->csym) = build_lang_decl (NULL);
@@ -2394,6 +2398,12 @@ aggregate_initializer_decl (AggregateDeclaration *decl)
SET_DECL_ALIGN (sinit, sd->alignment.get () * BITS_PER_UNIT);
DECL_USER_ALIGN (sinit) = true;
}
+ else if (sd == NULL)
+ {
+ /* Alignment of class is determined its biggest field alignment. */
+ SET_DECL_ALIGN (sinit, decl->alignsize * BITS_PER_UNIT);
+ DECL_USER_ALIGN (sinit) = true;
+ }
decl->sinit = sinit;
return sinit;
@@ -2404,7 +2414,7 @@ aggregate_initializer_decl (AggregateDeclaration *decl)
tree
layout_class_initializer (ClassDeclaration *cd)
{
- NewExp *ne = NewExp::create (cd->loc, NULL, cd->type, NULL);
+ NewExp *ne = NewExp::create (cd->loc, NULL, NULL, cd->type, NULL);
ne->type = cd->type;
Expression *e = dmd::ctfeInterpret (ne);
@@ -2418,7 +2428,7 @@ layout_struct_initializer (StructDeclaration *sd)
{
StructLiteralExp *sle = StructLiteralExp::create (sd->loc, sd, NULL);
- if (!sd->fill (sd->loc, *sle->elements, true))
+ if (!dmd::fill (sd, sd->loc, *sle->elements, true))
gcc_unreachable ();
sle->type = sd->type;
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index dc47db8..58d19b4 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-b65767825f365dbc153457fc86e1054b03196c6d
+956e73d64e532a68213970316c2590c572ec03f3
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 282e818..2e93d26 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -41,8 +41,11 @@ Note that these groups have no strict meaning, the category assignments are a bi
| [frontend.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/frontend.d) | An interface for using DMD as a library |
| [errors.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d) | Error reporting implementation |
| [errorsink.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errorsink.d) | Error reporting interface |
+| [sarif.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/sarif.d) | Generates SARIF reports for errors and warnings. |
| [target.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/target.d) | Manage target-specific parameters for cross-compiling (for LDC/GDC) |
| [compiler.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/compiler.d) | Describe a back-end compiler and implements compiler-specific actions |
+| [deps.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/deps.d) | Implement the `-deps` and `-makedeps` switches |
+| [timetrace.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/timetrace.d) | Build time profiling utility |
### Lexing / parsing
@@ -96,19 +99,20 @@ Note that these groups have no strict meaning, the category assignments are a bi
| File | Purpose |
|-----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
-| [parsetimevisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/parsetimevisitor.d) | General [visitor](https://en.wikipedia.org/wiki/Visitor_pattern) for AST nodes |
-| [permissivevisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/permissivevisitor.d) | Subclass of ParseTimeVisitor that does not `assert(0)` on unimplemented nodes |
-| [strictvisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/strictvisitor.d) | Visitor that forces derived classes to implement `visit` for every possible node |
-| [visitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor.d) | A visitor implementing `visit` for all nodes present in the compiler |
-| [transitivevisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/transitivevisitor.d) | Provide a mixin template with visit methods for the parse time AST |
-| [postordervisitor.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/postordervisitor.d) | Depth-first expression visitor |
-| [sapply.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/sapply.d) | Depth-first statement visitor |
-| [statement_rewrite_walker.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statement_rewrite_walker.d) | Statement visitor that allows replacing the currently visited node |
+| [visitor/parsetime.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/parsetime.d) | General [visitor](https://en.wikipedia.org/wiki/Visitor_pattern) for AST nodes |
+| [visitor/permissive.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/permissive.d) | Subclass of ParseTimeVisitor that does not `assert(0)` on unimplemented nodes |
+| [visitor/strict.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/strict.d) | Visitor that forces derived classes to implement `visit` for every possible node |
+| [visitor/package.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/package.d) | A visitor implementing `visit` for all nodes present in the compiler |
+| [visitor/transitive.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/transitive.d) | Provide a mixin template with visit methods for the parse time AST |
+| [visitor/postorder.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/postorder.d) | Depth-first expression & statement visitor |
+| [visitor/statement_rewrite_walker.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/statement_rewrite_walker.d) | Statement visitor that allows replacing the currently visited node |
+| [visitor/foreachvar.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/foreachvar.d) | Used in `ob.d` to iterate over all variables in an expression |
**Semantic passes**
| File | Purpose |
|-------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
+| [attribsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/attribsem.d) | Attribute semantics |
| [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) |
| [enumsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/enumsem.d) | Enum semantics |
| [funcsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/funcsem.d) | Function semantics |
@@ -196,15 +200,13 @@ Note that these groups have no strict meaning, the category assignments are a bi
| File | Purpose |
|-------------------------------------------------------------------------------|------------------------------------------------------|
-| [lib.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib.d) | Abstract library class |
-| [libelf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libelf.d) | Library in ELF format (Unix) |
-| [libmach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libmach.d) | Library in Mach-O format (macOS) |
-| [libmscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libmscoff.d) | Library in COFF format (32/64-bit Windows) |
-| [libomf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libomf.d) | Library in OMF format (legacy 32-bit Windows) |
-| [scanelf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanelf.d) | Extract symbol names from a library in ELF format |
-| [scanmach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanmach.d) | Extract symbol names from a library in Mach-O format |
-| [scanmscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanmscoff.d) | Extract symbol names from a library in COFF format |
-| [scanomf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanomf.d) | Extract symbol names from a library in OMF format |
+| [lib/package.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/package.d) | Abstract library class |
+| [lib/elf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/elf.d) | Library in ELF format (Unix) |
+| [lib/mach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/mach.d) | Library in Mach-O format (macOS) |
+| [lib/mscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/mscoff.d) | Library in COFF format (32/64-bit Windows) |
+| [lib/scanelf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/scanelf.d) | Extract symbol names from a library in ELF format |
+| [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 |
### Code generation / back-end interfacing
@@ -232,10 +234,10 @@ Note that these groups have no strict meaning, the category assignments are a bi
| File | Purpose |
|-----------------------------------------------------------------------------------|------------------------------------------------------------------|
-| [cppmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmangle.d) | C++ name mangling |
-| [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmanglewin.d) | C++ name mangling for Windows |
-| [basicmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/basicmangle.d) | D name mangling for basic types |
-| [dmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) |
+| [mangle/cpp.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/cpp.d) | C++ name mangling |
+| [mangle/cppwin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/cppwin.d) | C++ name mangling for Windows |
+| [mangle/basic.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/basic.d) | D name mangling for basic types |
+| [mangle/package.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/package.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) |
### Linking
@@ -252,6 +254,8 @@ Note that these groups have no strict meaning, the category assignments are a bi
| [hdrgen.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/hdrgen.d) | Convert an AST into D source code for `.di` header generation, as well as `-vcg-ast` and error messages |
| [json.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/json.d) | Describe the module in a `.json` file for the `-X` flag |
| [dtoh.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dtoh.d) | C++ header generation from D source files |
+| [disasm86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/x86/disasm86.d) | x86-64 disassembly generation
+| [disasmarm.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/arm/disasmarm.d) | AArch64 disassembly generation
### Utility
@@ -267,4 +271,3 @@ Note: many other utilities are in [dmd/root](https://github.com/dlang/dmd/tree/m
|---------------------------------------------------------------------------------|---------------------------------------------------------------|
| [asttypename.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/asttypename.d) | Print the internal name of an AST node (for debugging only) |
| [printast.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/printast.d) | Print the AST data structure |
-| [foreachvar.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/foreachvar.d) | Used in `ob.d` to iterate over all variables in an expression |
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 5868b87..e972d6e 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.108.0
+v2.111.0
diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d
index 8d02203..eaaa288 100644
--- a/gcc/d/dmd/access.d
+++ b/gcc/d/dmd/access.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/attribute.html#visibility_attributes, Visibility Attributes)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/access.d, _access.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/access.d, _access.d)
* Documentation: https://dlang.org/phobos/dmd_access.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/access.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/access.d
*/
module dmd.access;
@@ -22,6 +22,7 @@ import dmd.dstruct;
import dmd.dsymbol;
import dmd.errors;
import dmd.expression;
+import dmd.funcsem : overloadApply;
import dmd.location;
import dmd.tokens;
@@ -141,7 +142,7 @@ private bool hasPackageAccess(Module mod, Dsymbol s)
/****************************************
* Determine if scope sc has protected level access to cd.
*/
-private bool hasProtectedAccess(Scope *sc, Dsymbol s)
+private bool hasProtectedAccess(Scope* sc, Dsymbol s)
{
if (auto cd = s.isClassMember()) // also includes interfaces
{
@@ -163,7 +164,7 @@ private bool hasProtectedAccess(Scope *sc, Dsymbol s)
*/
bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d)
{
- if (sc.flags & SCOPE.noaccesscheck)
+ if (sc.noAccessCheck)
return false;
static if (LOG)
{
@@ -272,7 +273,7 @@ bool symbolIsVisible(Dsymbol origin, Dsymbol s)
* s = symbol to check for visibility
* Returns: true if s is visible by origin
*/
-bool symbolIsVisible(Scope *sc, Dsymbol s)
+bool symbolIsVisible(Scope* sc, Dsymbol s)
{
s = mostVisibleOverload(s);
return checkSymbolAccess(sc, s);
@@ -287,7 +288,7 @@ bool symbolIsVisible(Scope *sc, Dsymbol s)
* s = symbol to check for visibility
* Returns: true if s is visible by origin
*/
-bool checkSymbolAccess(Scope *sc, Dsymbol s)
+bool checkSymbolAccess(Scope* sc, Dsymbol s)
{
final switch (s.visible().kind)
{
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index 2c7622a..51d6fc4 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -4,12 +4,12 @@
* Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions),
* $(LINK2 https://dlang.org/spec/class.html, Class).
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/aggregate.d, _aggregate.d)
* Documentation: https://dlang.org/phobos/dmd_aggregate.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aggregate.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/aggregate.d
*/
module dmd.aggregate;
@@ -25,7 +25,7 @@ import dmd.declaration;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, determineFields, search, determineSize, include;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
@@ -37,7 +37,7 @@ import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.tokens;
-import dmd.typesem : defaultInit, addMod;
+import dmd.typesem : defaultInit, addMod, size;
import dmd.visitor;
/**
@@ -96,10 +96,10 @@ struct MangleOverride
extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
{
Type type; ///
- StorageClass storage_class; ///
+ STC storage_class; ///
uint structsize; /// size of struct
uint alignsize; /// size of struct for alignment purposes
- VarDeclarations fields; /// VarDeclaration fields
+ VarDeclarations fields; /// VarDeclaration fields including flattened AnonDeclaration members
Dsymbol deferred; /// any deferred semantic2() or semantic3() symbol
/// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface
@@ -154,7 +154,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
bool disableNew; /// disallow allocations using `new`
Sizeok sizeok = Sizeok.none; /// set when structsize contains valid data
- final extern (D) this(const ref Loc loc, Identifier id)
+ final extern (D) this(Loc loc, Identifier id)
{
super(loc, id);
visibility = Visibility(Visibility.Kind.public_);
@@ -187,70 +187,12 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return fields.length - isNested() - (vthis2 !is null);
}
- /***************************************
- * Collect all instance fields, then determine instance size.
- * Returns:
- * false if failed to determine the size.
- */
- extern (D) final bool determineSize(const ref Loc loc)
- {
- //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
-
- // The previous instance size finalizing had:
- if (type.ty == Terror || errors)
- return false; // failed already
- if (sizeok == Sizeok.done)
- return true; // succeeded
-
- if (!members)
- {
- .error(loc, "%s `%s` unknown size", kind, toPrettyChars);
- return false;
- }
-
- if (_scope)
- dsymbolSemantic(this, null);
-
- // Determine the instance size of base class first.
- if (auto cd = isClassDeclaration())
- {
- cd = cd.baseClass;
- if (cd && !cd.determineSize(loc))
- goto Lfail;
- }
-
- // Determine instance fields when sizeok == Sizeok.none
- if (!this.determineFields())
- goto Lfail;
- if (sizeok != Sizeok.done)
- finalizeSize();
-
- // this aggregate type has:
- if (type.ty == Terror)
- return false; // marked as invalid during the finalizing.
- if (sizeok == Sizeok.done)
- return true; // succeeded to calculate instance size.
-
- Lfail:
- // There's unresolvable forward reference.
- if (type != Type.terror)
- error(loc, "%s `%s` no size because of forward reference", kind, toPrettyChars);
- // Don't cache errors from speculative semantic, might be resolvable later.
- // https://issues.dlang.org/show_bug.cgi?id=16574
- if (!global.gag)
- {
- type = Type.terror;
- errors = true;
- }
- return false;
- }
-
abstract void finalizeSize();
- override final uinteger_t size(const ref Loc loc)
+ override final uinteger_t size(Loc loc)
{
//printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
- bool ok = determineSize(loc);
+ bool ok = determineSize(this, loc);
//printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
return ok ? structsize : SIZE_INVALID;
}
@@ -336,161 +278,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return errors;
}
- /***************************************
- * Fill out remainder of elements[] with default initializers for fields[].
- * Params:
- * loc = location
- * elements = explicit arguments which given to construct object.
- * ctorinit = true if the elements will be used for default initialization.
- * Returns:
- * false if any errors occur.
- * Otherwise, returns true and the missing arguments will be pushed in elements[].
- */
- final bool fill(const ref Loc loc, ref Expressions elements, bool ctorinit)
- {
- //printf("AggregateDeclaration::fill() %s\n", toChars());
- assert(sizeok == Sizeok.done);
- const nfields = nonHiddenFields();
- bool errors = false;
-
- size_t dim = elements.length;
- elements.setDim(nfields);
- foreach (size_t i; dim .. nfields)
- elements[i] = null;
-
- // Fill in missing any elements with default initializers
- foreach (i; 0 .. nfields)
- {
- if (elements[i])
- continue;
-
- auto vd = fields[i];
- auto vx = vd;
- if (vd._init && vd._init.isVoidInitializer())
- vx = null;
-
- // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
- size_t fieldi = i;
- foreach (j; 0 .. nfields)
- {
- if (i == j)
- continue;
- auto v2 = fields[j];
- if (!vd.isOverlappedWith(v2))
- continue;
-
- if (elements[j])
- {
- vx = null;
- break;
- }
- if (v2._init && v2._init.isVoidInitializer())
- continue;
-
- version (all)
- {
- /* Prefer first found non-void-initialized field
- * union U { int a; int b = 2; }
- * U u; // Error: overlapping initialization for field a and b
- */
- if (!vx)
- {
- vx = v2;
- fieldi = j;
- }
- else if (v2._init)
- {
- .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
- errors = true;
- }
- }
- else
- {
- // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
-
- /* Prefer explicitly initialized field
- * union U { int a; int b = 2; }
- * U u; // OK (u.b == 2)
- */
- if (!vx || !vx._init && v2._init)
- {
- vx = v2;
- fieldi = j;
- }
- else if (vx != vd && !vx.isOverlappedWith(v2))
- {
- // Both vx and v2 fills vd, but vx and v2 does not overlap
- }
- else if (vx._init && v2._init)
- {
- .error(loc, "overlapping default initialization for field `%s` and `%s`",
- v2.toChars(), vd.toChars());
- errors = true;
- }
- else
- assert(vx._init || !vx._init && !v2._init);
- }
- }
- if (vx)
- {
- Expression e;
- if (vx.type.size() == 0)
- {
- e = null;
- }
- else if (vx._init)
- {
- assert(!vx._init.isVoidInitializer());
- if (vx.inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
- {
- .error(loc, "%s `%s` recursive initialization of field", vx.kind(), vx.toPrettyChars());
- errors = true;
- }
- else
- e = vx.getConstInitializer(false);
- }
- else
- {
- if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
- {
- .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
- type.toChars(), vx.toChars());
- errors = true;
- }
- /* https://issues.dlang.org/show_bug.cgi?id=12509
- * Get the element of static array type.
- */
- Type telem = vx.type;
- if (telem.ty == Tsarray)
- {
- /* We cannot use Type::baseElemOf() here.
- * If the bottom of the Tsarray is an enum type, baseElemOf()
- * will return the base of the enum, and its default initializer
- * would be different from the enum's.
- */
- TypeSArray tsa;
- while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
- telem = tsa.next;
- if (telem.ty == Tvoid)
- telem = Type.tuns8.addMod(telem.mod);
- }
- if (telem.needsNested() && ctorinit)
- e = telem.defaultInit(loc);
- else
- e = telem.defaultInitLiteral(loc);
- }
- elements[fieldi] = e;
- }
- }
- foreach (e; elements)
- {
- if (e && e.op == EXP.error)
- return false;
- }
-
- return !errors;
- }
-
override final Type getType()
{
/* Apply storage classes to forward references. (Issue 22254)
@@ -660,7 +447,8 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
s.isTemplateDeclaration() ||
s.isOverloadSet()))
{
- .error(s.loc, "%s `%s` is not a constructor; identifiers starting with `__` are reserved for the implementation", s.kind(), s.toPrettyChars());
+ 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;
}
@@ -707,11 +495,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
// Back end
void* sinit; /// initializer symbol
- override final inout(AggregateDeclaration) isAggregateDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -793,6 +576,7 @@ public uint alignmember(structalign_t alignment, uint memalignsize, uint offset)
/****************************************
* Place a field (mem) into an aggregate (agg), which can be a struct, union or class
* Params:
+ * loc = source location for error messages
* nextoffset = location just past the end of the previous field in the aggregate.
* Updated to be just past the end of this field to be placed, i.e. the future nextoffset
* memsize = size of field
@@ -805,8 +589,8 @@ public uint alignmember(structalign_t alignment, uint memalignsize, uint offset)
* aligned offset to place field at
*
*/
-public uint placeField(ref uint nextoffset, uint memsize, uint memalignsize,
- structalign_t alignment, ref uint aggsize, ref uint aggalignsize, bool isunion) @safe pure nothrow
+public uint placeField(Loc loc, ref uint nextoffset, uint memsize, uint memalignsize,
+ structalign_t alignment, ref uint aggsize, ref uint aggalignsize, bool isunion) @trusted nothrow
{
static if (0)
{
@@ -829,7 +613,12 @@ public uint placeField(ref uint nextoffset, uint memsize, uint memalignsize,
bool overflow;
const sz = addu(memsize, actualAlignment, overflow);
addu(ofs, sz, overflow);
- if (overflow) assert(0);
+ if (overflow)
+ {
+ error(loc, "max object size %u exceeded from adding field size %u + alignment adjustment %u + field offset %u when placing field in aggregate",
+ uint.max, memsize, actualAlignment, ofs);
+ return 0;
+ }
// Skip no-op for noreturn without custom aligment
if (memalignsize != 0 || !alignment.isDefault())
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index c972f0a..82f8aec 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -45,6 +45,9 @@ namespace dmd
{
FuncDeclaration *search_toString(StructDeclaration *sd);
void semanticTypeInfoMembers(StructDeclaration *sd);
+ bool fill(StructDeclaration* sd, Loc loc, Expressions &elements, bool ctorinit);
+ bool isFuncHidden(ClassDeclaration* cd, FuncDeclaration* fd);
+ Dsymbol* vtblSymbol(ClassDeclaration *cd);
}
enum class ClassKind : uint8_t
@@ -118,8 +121,7 @@ public:
virtual Scope *newScope(Scope *sc);
virtual void finalizeSize() = 0;
- uinteger_t size(const Loc &loc) override final;
- bool fill(const Loc &loc, Expressions &elements, bool ctorinit);
+ uinteger_t size(Loc loc) override final;
Type *getType() override final;
bool isDeprecated() const override final; // is aggregate deprecated?
bool isNested() const;
@@ -135,7 +137,6 @@ public:
// Back end
void *sinit;
- AggregateDeclaration *isAggregateDeclaration() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -168,7 +169,7 @@ public:
private:
uint16_t bitFields;
public:
- static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject);
+ static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
StructDeclaration *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
void finalizeSize() override final;
@@ -191,7 +192,6 @@ public:
bool requestTypeInfo() const;
bool requestTypeInfo(bool v);
- StructDeclaration *isStructDeclaration() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
unsigned numArgTypes() const;
@@ -205,7 +205,6 @@ public:
UnionDeclaration *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
- UnionDeclaration *isUnionDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -278,7 +277,7 @@ public:
ObjcClassDeclaration objc; // Data for a class declaration that is needed for the Objective-C integration
Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
- static ClassDeclaration *create(const Loc &loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
+ static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
const char *toPrettyChars(bool QualifyTypes = false) override;
ClassDeclaration *syntaxCopy(Dsymbol *s) override;
Scope *newScope(Scope *sc) override;
@@ -290,7 +289,6 @@ public:
bool isBaseInfoComplete();
void finalizeSize() override;
bool hasMonitor();
- bool isFuncHidden(FuncDeclaration *fd);
bool isCOMclass() const;
virtual bool isCOMinterface() const;
bool isCPPclass() const;
@@ -303,9 +301,7 @@ public:
// Back end
Dsymbol *vtblsym;
- Dsymbol *vtblSymbol();
- ClassDeclaration *isClassDeclaration() override final { return (ClassDeclaration *)this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -320,6 +316,5 @@ public:
bool isCPPinterface() const override;
bool isCOMinterface() const override;
- InterfaceDeclaration *isInterfaceDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d
index 0e063ca..632cf95 100644
--- a/gcc/d/dmd/aliasthis.d
+++ b/gcc/d/dmd/aliasthis.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/class.html#alias-this, Alias This)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/aliasthis.d, _aliasthis.d)
* Documentation: https://dlang.org/phobos/dmd_aliasthis.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aliasthis.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/aliasthis.d
*/
module dmd.aliasthis;
@@ -31,9 +31,9 @@ extern (C++) final class AliasThis : Dsymbol
/// Whether this `alias this` is deprecated or not
bool isDeprecated_;
- extern (D) this(const ref Loc loc, Identifier ident) @safe
+ extern (D) this(Loc loc, Identifier ident) @safe
{
- super(loc, null); // it's anonymous (no identifier)
+ super(DSYM.aliasThis, loc, null); // it's anonymous (no identifier)
this.ident = ident;
}
diff --git a/gcc/d/dmd/aliasthis.h b/gcc/d/dmd/aliasthis.h
index 88ba353..249da70 100644
--- a/gcc/d/dmd/aliasthis.h
+++ b/gcc/d/dmd/aliasthis.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 2009-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2009-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index af3875e..7d25e18 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/arrays.html#array-operations, Array Operations)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d, _arrayop.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/arrayop.d, _arrayop.d)
* Documentation: https://dlang.org/phobos/dmd_arrayop.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/arrayop.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/arrayop.d
*/
module dmd.arrayop;
@@ -16,6 +16,7 @@ module dmd.arrayop;
import core.stdc.stdio;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.dcast : implicitConvTo;
import dmd.declaration;
import dmd.dscope;
import dmd.dsymbol;
@@ -43,12 +44,12 @@ bool isArrayOpValid(Expression e)
if (e.op == EXP.arrayLiteral)
{
Type t = e.type.toBasetype();
- while (t.ty == Tarray || t.ty == Tsarray)
+ while (t.isStaticOrDynamicArray())
t = t.nextOf().toBasetype();
return (t.ty != Tvoid);
}
Type tb = e.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
if (isUnaArrayOp(e.op))
{
@@ -79,7 +80,7 @@ bool isNonAssignmentArrayOp(Expression e)
return isNonAssignmentArrayOp(e.isSliceExp().e1);
Type tb = e.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
return (isUnaArrayOp(e.op) || isBinArrayOp(e.op));
}
@@ -118,7 +119,7 @@ Expression arrayOp(BinExp e, Scope* sc)
{
//printf("BinExp.arrayOp() %s\n", e.toChars());
Type tb = e.type.toBasetype();
- assert(tb.ty == Tarray || tb.ty == Tsarray);
+ assert(tb.isStaticOrDynamicArray());
Type tbn = tb.nextOf().toBasetype();
if (tbn.ty == Tvoid)
{
@@ -145,7 +146,10 @@ Expression arrayOp(BinExp e, Scope* sc)
if (auto te = id.isTemplateExp())
arrayOp = te.td;
else
- ObjectNotFound(idArrayOp); // fatal error
+ {
+ ObjectNotFound(e.loc, idArrayOp); // fatal error
+ return ErrorExp.get();
+ }
}
auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, ArgumentList(args), FuncResolveFlag.standard);
@@ -283,9 +287,8 @@ bool isUnaArrayOp(EXP op) @safe
case EXP.tilde:
return true;
default:
- break;
+ return false;
}
- return false;
}
/***********************************************
@@ -306,9 +309,8 @@ bool isBinArrayOp(EXP op) @safe
case EXP.pow:
return true;
default:
- break;
+ return false;
}
- return false;
}
/***********************************************
@@ -329,9 +331,8 @@ bool isBinAssignArrayOp(EXP op) @safe
case EXP.powAssign:
return true;
default:
- break;
+ return false;
}
- return false;
}
/***********************************************
@@ -345,7 +346,7 @@ bool isArrayOpOperand(Expression e)
if (e.op == EXP.arrayLiteral)
{
Type t = e.type.toBasetype();
- while (t.ty == Tarray || t.ty == Tsarray)
+ while (t.isStaticOrDynamicArray())
t = t.nextOf().toBasetype();
return (t.ty != Tvoid);
}
diff --git a/gcc/d/dmd/arraytypes.d b/gcc/d/dmd/arraytypes.d
index feab9a4..2cd446e 100644
--- a/gcc/d/dmd/arraytypes.d
+++ b/gcc/d/dmd/arraytypes.d
@@ -1,12 +1,12 @@
/**
* Provide aliases for arrays of certain declarations or statements.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/arraytypes.d, _arraytypes.d)
* Documentation: https://dlang.org/phobos/dmd_arraytypes.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/arraytypes.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/arraytypes.d
*/
module dmd.arraytypes;
diff --git a/gcc/d/dmd/arraytypes.h b/gcc/d/dmd/arraytypes.h
index 7796428..28165f3 100644
--- a/gcc/d/dmd/arraytypes.h
+++ b/gcc/d/dmd/arraytypes.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 2006-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2006-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/ast_node.d b/gcc/d/dmd/ast_node.d
index c8c95fa..ad49169 100644
--- a/gcc/d/dmd/ast_node.d
+++ b/gcc/d/dmd/ast_node.d
@@ -1,12 +1,12 @@
/**
* Defines the base class for all nodes which are part of the AST.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d, _ast_node.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ast_node.d, _ast_node.d)
* Documentation: https://dlang.org/phobos/dmd_ast_node.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ast_node.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/ast_node.d
*/
module dmd.ast_node;
diff --git a/gcc/d/dmd/ast_node.h b/gcc/d/dmd/ast_node.h
index db8608e..0782d7e 100644
--- a/gcc/d/dmd/ast_node.h
+++ b/gcc/d/dmd/ast_node.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
index 4fc1514..b71b6c4 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -1,11 +1,11 @@
/**
* Defines enums common to dmd and dmd as parse library.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d, _astenums.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/astenums.d, _astenums.d)
* Documentation: https://dlang.org/phobos/dmd_astenums.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/astenums.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/astenums.d
*/
module dmd.astenums;
@@ -18,6 +18,15 @@ enum Sizeok : ubyte
done, /// size of aggregate is set correctly
}
+/// D Language version
+enum Edition : ubyte
+{
+ none,
+ legacy, /// Before the introduction of editions
+ v2024, /// Experimental first new edition
+ latest = v2024 /// Newest edition that this compiler knows of
+}
+
enum Baseok : ubyte
{
none, /// base classes not computed yet
@@ -41,7 +50,7 @@ alias MOD = ubyte;
enum STC : ulong // transfer changes to declaration.h
{
- undefined_ = 0,
+ none = 0,
static_ = 1, /// `static`
extern_ = 2, /// `extern`
@@ -134,6 +143,9 @@ enum STC : ulong // transfer changes to declaration.h
}
+// Alias for C++ interface functions which use plain integer instead of enum class,
+// since C++ enum class doesn't support | & and conversion to bool. Maybe this can
+// be refactored to a struct with operator overloads or bit fields at some point.
alias StorageClass = ulong;
/********
@@ -293,7 +305,7 @@ enum ThreeState : ubyte
enum TRUST : ubyte
{
default_ = 0,
- system = 1, // @system (same as TRUST.default)
+ system = 1, // @system (same as TRUST.default_ unless feature "safer" is enabled)
trusted = 2, // @trusted
safe = 3, // @safe
}
@@ -441,6 +453,24 @@ enum FileType : ubyte
c, /// C source file
}
+/// In which context checks for assertions, contracts, bounds checks etc. are enabled
+enum CHECKENABLE : ubyte
+{
+ _default, /// initial value
+ off, /// never do checking
+ on, /// always do checking
+ safeonly, /// do checking only in @safe functions
+}
+
+/// What should happend when an assertion fails
+enum CHECKACTION : ubyte
+{
+ D, /// call D assert on failure
+ C, /// call C assert on failure
+ halt, /// cause program halt on failure
+ context, /// call D assert with the error context on failure
+}
+
extern (C++) struct structalign_t
{
private:
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index d7d3eca6..1bfe790 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -14,12 +14,12 @@
* - Protection (`private`, `public`)
* - Deprecated declarations (`@deprecated`)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/attrib.d, _attrib.d)
* Documentation: https://dlang.org/phobos/dmd_attrib.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/attrib.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/attrib.d
*/
module dmd.attrib;
@@ -32,10 +32,8 @@ import dmd.declaration;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem;
-import dmd.errors;
+import dmd.dsymbolsem : include;
import dmd.expression;
-import dmd.expressionsem;
import dmd.func;
import dmd.globals;
import dmd.hdrgen : visibilityToBuffer;
@@ -59,36 +57,29 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
extern (D) this(Dsymbols* decl) @safe
{
+ super(DSYM.attribDeclaration);
this.decl = decl;
}
- extern (D) this(const ref Loc loc, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, Dsymbols* decl) @safe
{
- super(loc, null);
+ super(DSYM.attribDeclaration, loc, null);
this.decl = decl;
}
- extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, Identifier ident, Dsymbols* decl) @safe
{
- super(loc, ident);
+ super(DSYM.attribDeclaration, loc, ident);
this.decl = decl;
}
- Dsymbols* include(Scope* sc)
- {
- if (errors)
- return null;
-
- return decl;
- }
-
/****************************************
* Create a new scope if one or more given attributes
* are different from the sc's.
* If the returned scope != sc, the caller should pop
* the scope after it used.
*/
- extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage,
+ extern (D) static Scope* createNewScope(Scope* sc, STC stc, LINK linkage,
CPPMANGLE cppmangle, Visibility visibility, int explicitVisibility,
AlignDeclaration aligndecl, PragmaDeclaration inlining)
{
@@ -114,48 +105,14 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
return sc2;
}
- /****************************************
- * A hook point to supply scope for members.
- * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
- */
- Scope* newScope(Scope* sc)
- {
- return sc;
- }
-
- override void addComment(const(char)* comment)
- {
- //printf("AttribDeclaration::addComment %s\n", comment);
- if (comment)
- {
- include(null).foreachDsymbol( s => s.addComment(comment) );
- }
- }
-
override const(char)* kind() const
{
return "attribute";
}
- override bool oneMember(out Dsymbol ps, Identifier ident)
- {
- Dsymbols* d = include(null);
- return Dsymbol.oneMembers(d, ps, ident);
- }
-
override final bool hasPointers()
{
- return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
- }
-
- override final bool hasStaticCtorOrDtor()
- {
- return include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
- }
-
- override final void checkCtorConstInit()
- {
- include(null).foreachDsymbol( s => s.checkCtorConstInit() );
+ return this.include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
}
/****************************************
@@ -165,11 +122,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
objc.addSymbols(this, classes, categories);
}
- override inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -183,18 +135,20 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
*/
extern (C++) class StorageClassDeclaration : AttribDeclaration
{
- StorageClass stc;
+ STC stc;
- extern (D) this(StorageClass stc, Dsymbols* decl) @safe
+ extern (D) this(STC stc, Dsymbols* decl) @safe
{
super(decl);
this.stc = stc;
+ this.dsym = DSYM.storageClassDeclaration;
}
- extern (D) this(const ref Loc loc, StorageClass stc, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, STC stc, Dsymbols* decl) @safe
{
super(loc, decl);
this.stc = stc;
+ this.dsym = DSYM.storageClassDeclaration;
}
override StorageClassDeclaration syntaxCopy(Dsymbol s)
@@ -203,60 +157,6 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration
return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl));
}
- override Scope* newScope(Scope* sc)
- {
- StorageClass scstc = sc.stc;
- /* These sets of storage classes are mutually exclusive,
- * so choose the innermost or most recent one.
- */
- if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
- scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
- if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared))
- scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared);
- if (stc & (STC.const_ | STC.immutable_ | STC.manifest))
- scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
- if (stc & (STC.gshared | STC.shared_))
- scstc &= ~(STC.gshared | STC.shared_);
- if (stc & (STC.safe | STC.trusted | STC.system))
- scstc &= ~(STC.safe | STC.trusted | STC.system);
- scstc |= stc;
- //printf("scstc = x%llx\n", scstc);
- return createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
- sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);
- }
-
- override final bool oneMember(out Dsymbol ps, Identifier ident)
- {
- bool t = Dsymbol.oneMembers(decl, ps, ident);
- if (t && ps)
- {
- /* This is to deal with the following case:
- * struct Tick {
- * template to(T) { const T to() { ... } }
- * }
- * For eponymous function templates, the 'const' needs to get attached to 'to'
- * before the semantic analysis of 'to', so that template overloading based on the
- * 'this' pointer can be successful.
- */
- FuncDeclaration fd = ps.isFuncDeclaration();
- if (fd)
- {
- /* Use storage_class2 instead of storage_class otherwise when we do .di generation
- * we'll wind up with 'const const' rather than 'const'.
- */
- /* Don't think we need to worry about mutually exclusive storage classes here
- */
- fd.storage_class2 |= stc;
- }
- }
- return t;
- }
-
- override inout(StorageClassDeclaration) isStorageClassDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -288,25 +188,6 @@ extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
}
- /**
- * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
- *
- * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
- * in any function overriding `newScope`), then set the `Scope`'s depdecl.
- *
- * Returns:
- * Always a new scope, to use for this `DeprecatedDeclaration`'s members.
- */
- override Scope* newScope(Scope* sc)
- {
- auto scx = super.newScope(sc);
- // The enclosing scope is deprecated as well
- if (scx == sc)
- scx = sc.push();
- scx.depdecl = this;
- return scx;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -323,14 +204,15 @@ extern (C++) final class LinkDeclaration : AttribDeclaration
{
LINK linkage; /// either explicitly set or `default_`
- extern (D) this(const ref Loc loc, LINK linkage, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, LINK linkage, Dsymbols* decl) @safe
{
super(loc, null, decl);
//printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
this.linkage = linkage;
+ this.dsym = DSYM.linkDeclaration;
}
- static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl) @safe
+ static LinkDeclaration create(Loc loc, LINK p, Dsymbols* decl) @safe
{
return new LinkDeclaration(loc, p, decl);
}
@@ -341,22 +223,6 @@ extern (C++) final class LinkDeclaration : AttribDeclaration
return new LinkDeclaration(loc, linkage, Dsymbol.arraySyntaxCopy(decl));
}
- override Scope* newScope(Scope* sc)
- {
- return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
- sc.aligndecl, sc.inlining);
- }
-
- override const(char)* toChars() const
- {
- return toString().ptr;
- }
-
- extern(D) override const(char)[] toString() const
- {
- return "extern ()";
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -375,11 +241,12 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration
{
CPPMANGLE cppmangle;
- extern (D) this(const ref Loc loc, CPPMANGLE cppmangle, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, CPPMANGLE cppmangle, Dsymbols* decl) @safe
{
super(loc, null, decl);
//printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl);
this.cppmangle = cppmangle;
+ this.dsym = DSYM.cppMangleDeclaration;
}
override CPPMangleDeclaration syntaxCopy(Dsymbol s)
@@ -388,22 +255,6 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration
return new CPPMangleDeclaration(loc, cppmangle, Dsymbol.arraySyntaxCopy(decl));
}
- override Scope* newScope(Scope* sc)
- {
- return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.visibility, sc.explicitVisibility,
- sc.aligndecl, sc.inlining);
- }
-
- override const(char)* toChars() const
- {
- return toString().ptr;
- }
-
- extern(D) override const(char)[] toString() const
- {
- return "extern ()";
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -438,21 +289,24 @@ extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
/// CTFE-able expression, resolving to `TupleExp` or `StringExp`
Expression exp;
- extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, Identifier ident, Dsymbols* decl) @safe
{
super(loc, ident, decl);
+ this.dsym = DSYM.cppNamespaceDeclaration;
}
- extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, Expression exp, Dsymbols* decl) @safe
{
super(loc, null, decl);
+ this.dsym = DSYM.cppNamespaceDeclaration;
this.exp = exp;
}
- extern (D) this(const ref Loc loc, Identifier ident, Expression exp, Dsymbols* decl,
+ extern (D) this(Loc loc, Identifier ident, Expression exp, Dsymbols* decl,
CPPNamespaceDeclaration parent) @safe
{
super(loc, ident, decl);
+ this.dsym = DSYM.cppNamespaceDeclaration;
this.exp = exp;
this.cppnamespace = parent;
}
@@ -464,34 +318,10 @@ extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
this.loc, this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
}
- /**
- * Returns:
- * A copy of the parent scope, with `this` as `namespace` and C++ linkage
- */
- override Scope* newScope(Scope* sc)
- {
- auto scx = sc.copy();
- scx.linkage = LINK.cpp;
- scx.namespace = this;
- return scx;
- }
-
- override const(char)* toChars() const
- {
- return toString().ptr;
- }
-
- extern(D) override const(char)[] toString() const
- {
- return "extern (C++, `namespace`)";
- }
-
override void accept(Visitor v)
{
v.visit(this);
}
-
- override inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return this; }
}
/***********************************************************
@@ -511,9 +341,10 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration
* visibility = visibility attribute data
* decl = declarations which are affected by this visibility attribute
*/
- extern (D) this(const ref Loc loc, Visibility visibility, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, Visibility visibility, Dsymbols* decl) @safe
{
super(loc, null, decl);
+ this.dsym = DSYM.visibilityDeclaration;
this.visibility = visibility;
//printf("decl = %p\n", decl);
}
@@ -524,9 +355,10 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration
* pkg_identifiers = list of identifiers for a qualified package name
* decl = declarations which are affected by this visibility attribute
*/
- extern (D) this(const ref Loc loc, Identifier[] pkg_identifiers, Dsymbols* decl)
+ extern (D) this(Loc loc, Identifier[] pkg_identifiers, Dsymbols* decl)
{
super(loc, null, decl);
+ this.dsym = DSYM.visibilityDeclaration;
this.visibility.kind = Visibility.Kind.package_;
this.pkg_identifiers = pkg_identifiers;
if (pkg_identifiers.length > 0)
@@ -547,13 +379,6 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration
return new VisibilityDeclaration(this.loc, visibility, Dsymbol.arraySyntaxCopy(decl));
}
- override Scope* newScope(Scope* sc)
- {
- if (pkg_identifiers)
- dsymbolSemantic(this, sc);
- return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining);
- }
-
override const(char)* kind() const
{
return "visibility attribute";
@@ -567,11 +392,6 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration
return buf.extractChars();
}
- override inout(VisibilityDeclaration) isVisibilityDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -593,9 +413,10 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
structalign_t salign;
- extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
+ extern (D) this(Loc loc, Expression exp, Dsymbols* decl)
{
super(loc, null, decl);
+ this.dsym = DSYM.alignDeclaration;
if (exp)
{
exps = new Expressions();
@@ -603,15 +424,17 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
}
}
- extern (D) this(const ref Loc loc, Expressions* exps, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, Expressions* exps, Dsymbols* decl) @safe
{
super(loc, null, decl);
+ this.dsym = DSYM.alignDeclaration;
this.exps = exps;
}
- extern (D) this(const ref Loc loc, structalign_t salign, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, structalign_t salign, Dsymbols* decl) @safe
{
super(loc, null, decl);
+ this.dsym = DSYM.alignDeclaration;
this.salign = salign;
}
@@ -623,11 +446,6 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
Dsymbol.arraySyntaxCopy(decl));
}
- override Scope* newScope(Scope* sc)
- {
- return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -645,9 +463,10 @@ extern (C++) final class AnonDeclaration : AttribDeclaration
uint anonstructsize; /// size of anonymous struct
uint anonalignsize; /// size of anonymous struct for alignment purposes
- extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, bool isunion, Dsymbols* decl) @safe
{
super(loc, null, decl);
+ this.dsym = DSYM.anonDeclaration;
this.isunion = isunion;
}
@@ -662,11 +481,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration
return (isunion ? "anonymous union" : "anonymous struct");
}
- override inout(AnonDeclaration) isAnonDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -683,9 +497,10 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration
{
Expressions* args; /// parameters of this pragma
- extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) @safe
+ extern (D) this(Loc loc, Identifier ident, Expressions* args, Dsymbols* decl) @safe
{
super(loc, ident, decl);
+ this.dsym = DSYM.pragmaDeclaration;
this.args = args;
}
@@ -696,17 +511,6 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration
return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl));
}
- override Scope* newScope(Scope* sc)
- {
- if (ident == Id.Pinline)
- {
- // We keep track of this pragma inside scopes,
- // then it's evaluated on demand in function semantic
- return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this);
- }
- return sc;
- }
-
override const(char)* kind() const
{
return "pragma";
@@ -729,9 +533,10 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
Condition condition; /// condition deciding whether decl or elsedecl applies
Dsymbols* elsedecl; /// array of Dsymbol's for else block
- extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
+ extern (D) this(Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
{
super(loc, null, decl);
+ this.dsym = DSYM.conditionalDeclaration;
//printf("ConditionalDeclaration::ConditionalDeclaration()\n");
this.condition = condition;
this.elsedecl = elsedecl;
@@ -743,48 +548,6 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
}
- override final bool oneMember(out Dsymbol ps, Identifier ident)
- {
- //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
- if (condition.inc != Include.notComputed)
- {
- Dsymbols* d = condition.include(null) ? decl : elsedecl;
- return Dsymbol.oneMembers(d, ps, ident);
- }
- else
- {
- bool res = (Dsymbol.oneMembers(decl, ps, ident) && ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && ps is null);
- ps = null;
- return res;
- }
- }
-
- // Decide if 'then' or 'else' code should be included
- override Dsymbols* include(Scope* sc)
- {
- //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
-
- if (errors)
- return null;
-
- assert(condition);
- return condition.include(_scope ? _scope : sc) ? decl : elsedecl;
- }
-
- override final void addComment(const(char)* comment)
- {
- /* Because addComment is called by the parser, if we called
- * include() it would define a version before it was used.
- * But it's no problem to drill down to both decl and elsedecl,
- * so that's the workaround.
- */
- if (comment)
- {
- decl .foreachDsymbol( s => s.addComment(comment) );
- elsedecl.foreachDsymbol( s => s.addComment(comment) );
- }
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -799,12 +562,13 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
{
ScopeDsymbol scopesym; /// enclosing symbol (e.g. module) where symbols will be inserted
- private bool addisdone = false; /// true if members have been added to scope
- private bool onStack = false; /// true if a call to `include` is currently active
+ bool addisdone = false; /// true if members have been added to scope
+ bool onStack = false; /// true if a call to `include` is currently active
- extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
+ extern (D) this(Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
{
super(loc, condition, decl, elsedecl);
+ this.dsym = DSYM.staticIfDeclaration;
//printf("StaticIfDeclaration::StaticIfDeclaration()\n");
}
@@ -814,52 +578,11 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
}
- /****************************************
- * Different from other AttribDeclaration subclasses, include() call requires
- * the completion of addMember and setScope phases.
- */
- override Dsymbols* include(Scope* sc)
- {
- //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
-
- if (errors || onStack)
- return null;
- onStack = true;
- scope(exit) onStack = false;
-
- if (sc && condition.inc == Include.notComputed)
- {
- assert(scopesym); // addMember is already done
- assert(_scope); // setScope is already done
- Dsymbols* d = ConditionalDeclaration.include(_scope);
- if (d && !addisdone)
- {
- // Add members lazily.
- d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
-
- // Set the member scopes lazily.
- d.foreachDsymbol( s => s.setScope(_scope) );
-
- addisdone = true;
- }
- return d;
- }
- else
- {
- return ConditionalDeclaration.include(sc);
- }
- }
-
override const(char)* kind() const
{
return "static if";
}
- override inout(StaticIfDeclaration) isStaticIfDeclaration() inout pure @safe
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -890,6 +613,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
extern (D) this(StaticForeach sfe, Dsymbols* decl) @safe
{
super(sfe.loc, null, decl);
+ this.dsym = DSYM.staticForeachDeclaration;
this.sfe = sfe;
}
@@ -901,64 +625,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
Dsymbol.arraySyntaxCopy(decl));
}
- override bool oneMember(out Dsymbol ps, Identifier ident)
- {
- // Required to support IFTI on a template that contains a
- // `static foreach` declaration. `super.oneMember` calls
- // include with a `null` scope. As `static foreach` requires
- // the scope for expansion, `oneMember` can only return a
- // precise result once `static foreach` has been expanded.
- if (cached)
- {
- return super.oneMember(ps, ident);
- }
- ps = null; // a `static foreach` declaration may in general expand to multiple symbols
- return false;
- }
-
- override Dsymbols* include(Scope* sc)
- {
- if (errors || onStack)
- return null;
- if (cached)
- {
- assert(!onStack);
- return cache;
- }
- onStack = true;
- scope(exit) onStack = false;
-
- if (_scope)
- {
- sfe.prepare(_scope); // lower static foreach aggregate
- }
- if (!sfe.ready())
- {
- return null; // TODO: ok?
- }
-
- // expand static foreach
- import dmd.statementsem: makeTupleForeach;
- Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl;
- if (d) // process generated declarations
- {
- // Add members lazily.
- d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
-
- // Set the member scopes lazily.
- d.foreachDsymbol( s => s.setScope(_scope) );
- }
- cached = true;
- cache = d;
- return d;
- }
-
- override void addComment(const(char)* comment)
- {
- // do nothing
- // change this to give semantics to documentation comments on static foreach declarations
- }
-
override const(char)* kind() const
{
return "static foreach";
@@ -985,7 +651,7 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
* pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
* }
*
- * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
+ * static assert(!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
*
* A StaticForeachDeclaration generates one
* ForwardingAttribDeclaration for each expansion of its body. The
@@ -1003,30 +669,17 @@ extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
this(Dsymbols* decl) @safe
{
super(decl);
+ this.dsym = DSYM.forwardingAttribDeclaration;
sym = new ForwardingScopeDsymbol();
sym.symtab = new DsymbolTable();
}
- /**************************************
- * Use the ForwardingScopeDsymbol as the parent symbol for members.
- */
- override Scope* newScope(Scope* sc)
- {
- return sc.push(sym);
- }
-
- override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
}
}
-
/***********************************************************
* Mixin declarations, like:
* mixin("int x");
@@ -1039,10 +692,11 @@ extern (C++) final class MixinDeclaration : AttribDeclaration
ScopeDsymbol scopesym;
bool compiled;
- extern (D) this(const ref Loc loc, Expressions* exps) @safe
+ extern (D) this(Loc loc, Expressions* exps) @safe
{
super(loc, null, null);
//printf("MixinDeclaration(loc = %d)\n", loc.linnum);
+ this.dsym = DSYM.mixinDeclaration;
this.exps = exps;
}
@@ -1057,11 +711,6 @@ extern (C++) final class MixinDeclaration : AttribDeclaration
return "mixin";
}
- override inout(MixinDeclaration) isMixinDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1080,6 +729,7 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
extern (D) this(Expressions* atts, Dsymbols* decl) @safe
{
super(decl);
+ this.dsym = DSYM.userAttributeDeclaration;
this.atts = atts;
}
@@ -1090,18 +740,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl));
}
- override Scope* newScope(Scope* sc)
- {
- Scope* sc2 = sc;
- if (atts && atts.length)
- {
- // create new one for changes
- sc2 = sc.copy();
- sc2.userAttribDecl = this;
- }
- return sc2;
- }
-
extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
{
Expressions* udas;
@@ -1121,21 +759,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
return udas;
}
- Expressions* getAttributes()
- {
- if (auto sc = _scope)
- {
- _scope = null;
- arrayExpressionSemantic(atts.peekSlice(), sc);
- }
- auto exps = new Expressions();
- if (userAttribDecl && userAttribDecl !is this)
- exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes()));
- if (atts && atts.length)
- exps.push(new TupleExp(Loc.initial, atts));
- return exps;
- }
-
override const(char)* kind() const
{
return "UserAttribute";
@@ -1145,70 +768,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
{
v.visit(this);
}
-
- /**
- * Check if the provided expression references `core.attribute.gnuAbiTag`
- *
- * This should be called after semantic has been run on the expression.
- * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
- *
- * Params:
- * e = Expression to check (usually from `UserAttributeDeclaration.atts`)
- *
- * Returns:
- * `true` if the expression references the compiler-recognized `gnuAbiTag`
- */
- static bool isGNUABITag(Expression e)
- {
- if (global.params.cplusplus < CppStdRevision.cpp11)
- return false;
-
- auto ts = e.type ? e.type.isTypeStruct() : null;
- if (!ts)
- return false;
- if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
- return false;
- // Can only be defined in druntime
- Module m = ts.sym.parent.isModule();
- if (!m || !m.isCoreModule(Id.attribute))
- return false;
- return true;
- }
-
- /**
- * Called from a symbol's semantic to check if `gnuAbiTag` UDA
- * can be applied to them
- *
- * Directly emits an error if the UDA doesn't work with this symbol
- *
- * Params:
- * sym = symbol to check for `gnuAbiTag`
- * linkage = Linkage of the symbol (Declaration.link or sc.link)
- */
- static void checkGNUABITag(Dsymbol sym, LINK linkage)
- {
- if (global.params.cplusplus < CppStdRevision.cpp11)
- return;
-
- foreachUdaNoSemantic(sym, (exp) {
- if (isGNUABITag(exp))
- {
- if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
- {
- .error(exp.loc, "`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
- sym.errors = true;
- }
- else if (linkage != LINK.cpp)
- {
- .error(exp.loc, "`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
- sym.errors = true;
- }
- // Only one `@gnuAbiTag` is allowed by semantic2
- return 1; // break
- }
- return 0; // continue
- });
- }
}
/**
@@ -1232,43 +791,6 @@ bool isCoreUda(Dsymbol sym, Identifier ident)
}
/**
- * Iterates the UDAs attached to the given symbol.
- *
- * Params:
- * sym = the symbol to get the UDAs from
- * sc = scope to use for semantic analysis of UDAs
- * dg = called once for each UDA
- *
- * Returns:
- * If `dg` returns `!= 0`, stops the iteration and returns that value.
- * Otherwise, returns 0.
- */
-int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
-{
- if (!sym.userAttribDecl)
- return 0;
-
- auto udas = sym.userAttribDecl.getAttributes();
- arrayExpressionSemantic(udas.peekSlice(), sc, true);
-
- return udas.each!((uda) {
- if (!uda.isTupleExp())
- return 0;
-
- auto exps = uda.isTupleExp().exps;
-
- return exps.each!((e) {
- assert(e);
-
- if (auto result = dg(e))
- return result;
-
- return 0;
- });
- });
-}
-
-/**
* Iterates the UDAs attached to the given symbol, without performing semantic
* analysis.
*
@@ -1297,7 +819,6 @@ int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg)
return 0;
}
-
/**
* Returns: true if the given expression is an enum from `core.attribute` named `id`
*/
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index 344a7e9..ef37e0a 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -17,23 +17,19 @@ class Expression;
class Condition;
class StaticForeach;
+namespace dmd
+{
+ Expressions *getAttributes(UserAttributeDeclaration *a);
+}
+
/**************************************************************/
class AttribDeclaration : public Dsymbol
{
public:
Dsymbols *decl; // array of Dsymbol's
-
- virtual Dsymbols *include(Scope *sc);
- virtual Scope *newScope(Scope *sc);
- void addComment(const utf8_t *comment) override;
const char *kind() const override;
- bool oneMember(Dsymbol *&ps, Identifier *ident) override;
bool hasPointers() override final;
- bool hasStaticCtorOrDtor() override final;
- void checkCtorConstInit() override final;
- AttribDeclaration *isAttribDeclaration() override { return this; }
-
void accept(Visitor *v) override { v->visit(this); }
};
@@ -43,9 +39,6 @@ public:
StorageClass stc;
StorageClassDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
- bool oneMember(Dsymbol *&ps, Identifier *ident) override final;
- StorageClassDeclaration *isStorageClassDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -57,7 +50,6 @@ public:
const char *msgstr;
DeprecatedDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -66,10 +58,8 @@ class LinkDeclaration final : public AttribDeclaration
public:
LINK linkage;
- static LinkDeclaration *create(const Loc &loc, LINK p, Dsymbols *decl);
+ static LinkDeclaration *create(Loc loc, LINK p, Dsymbols *decl);
LinkDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
- const char *toChars() const override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -79,8 +69,6 @@ public:
CPPMANGLE cppmangle;
CPPMangleDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
- const char *toChars() const override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -90,8 +78,6 @@ public:
Expression *exp;
CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
- const char *toChars() const override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -102,10 +88,8 @@ public:
DArray<Identifier*> pkg_identifiers;
VisibilityDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
const char *kind() const override;
const char *toPrettyChars(bool unused) override;
- VisibilityDeclaration *isVisibilityDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -116,7 +100,6 @@ public:
structalign_t salign;
AlignDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -131,7 +114,6 @@ public:
AnonDeclaration *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
- AnonDeclaration *isAnonDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -141,7 +123,6 @@ public:
Expressions *args; // array of Expression's
PragmaDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -153,9 +134,6 @@ public:
Dsymbols *elsedecl; // array of Dsymbol's for else block
ConditionalDeclaration *syntaxCopy(Dsymbol *s) override;
- bool oneMember(Dsymbol *&ps, Identifier *ident) override final;
- Dsymbols *include(Scope *sc) override;
- void addComment(const utf8_t *comment) override final;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -167,8 +145,6 @@ public:
d_bool onStack;
StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
- Dsymbols *include(Scope *sc) override;
- StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -183,9 +159,6 @@ public:
Dsymbols *cache;
StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override;
- bool oneMember(Dsymbol *&ps, Identifier *ident) override;
- Dsymbols *include(Scope *sc) override;
- void addComment(const utf8_t *comment) override;
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -195,8 +168,6 @@ class ForwardingAttribDeclaration final : public AttribDeclaration
public:
ForwardingScopeDsymbol *sym;
- Scope *newScope(Scope *sc) override;
- ForwardingAttribDeclaration *isForwardingAttribDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -225,8 +196,6 @@ public:
Expressions *atts;
UserAttributeDeclaration *syntaxCopy(Dsymbol *s) override;
- Scope *newScope(Scope *sc) override;
- Expressions *getAttributes();
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/attribsem.d b/gcc/d/dmd/attribsem.d
new file mode 100644
index 0000000..bc966bb
--- /dev/null
+++ b/gcc/d/dmd/attribsem.d
@@ -0,0 +1,87 @@
+/**
+ * Does semantic analysis for attributes.
+ *
+ * The term 'attribute' refers to things that can apply to a larger scope than a single declaration.
+ * Among them are:
+ * - Alignment (`align(8)`)
+ * - User defined attributes (`@UDA`)
+ * - Function Attributes (`@safe`)
+ * - Storage classes (`static`, `__gshared`)
+ * - Mixin declarations (`mixin("int x;")`)
+ * - Conditional compilation (`static if`, `static foreach`)
+ * - Linkage (`extern(C)`)
+ * - Anonymous structs / unions
+ * - Protection (`private`, `public`)
+ * - Deprecated declarations (`@deprecated`)
+ *
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/attribsem.d, _attrib.d)
+ * Documentation: https://dlang.org/phobos/dmd_attribsem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/attribsem.d
+ */
+
+module dmd.attribsem;
+
+import dmd.arraytypes;
+import dmd.attrib;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.location;
+import dmd.root.array; // for each
+
+
+Expressions* getAttributes(UserAttributeDeclaration a)
+{
+ if (auto sc = a._scope)
+ {
+ a._scope = null;
+ arrayExpressionSemantic(a.atts.peekSlice(), sc);
+ }
+ auto exps = new Expressions();
+ if (a.userAttribDecl && a.userAttribDecl !is a)
+ exps.push(new TupleExp(Loc.initial, a.userAttribDecl.getAttributes()));
+ if (a.atts && a.atts.length)
+ exps.push(new TupleExp(Loc.initial, a.atts));
+ return exps;
+}
+
+/**
+ * Iterates the UDAs attached to the given symbol.
+ *
+ * Params:
+ * sym = the symbol to get the UDAs from
+ * sc = scope to use for semantic analysis of UDAs
+ * dg = called once for each UDA
+ *
+ * Returns:
+ * If `dg` returns `!= 0`, stops the iteration and returns that value.
+ * Otherwise, returns 0.
+ */
+int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
+{
+ if (!sym.userAttribDecl)
+ return 0;
+
+ auto udas = sym.userAttribDecl.getAttributes();
+ arrayExpressionSemantic(udas.peekSlice(), sc, true);
+
+ return udas.each!((uda) {
+ if (!uda.isTupleExp())
+ return 0;
+
+ auto exps = uda.isTupleExp().exps;
+
+ return exps.each!((e) {
+ assert(e);
+
+ if (auto result = dg(e))
+ return result;
+
+ return 0;
+ });
+ });
+}
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index d77af7e..ae2f12f 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -1,12 +1,12 @@
/**
* Find out in what ways control flow can exit a statement block.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d, _blockexit.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/blockexit.d, _blockexit.d)
* Documentation: https://dlang.org/phobos/dmd_blockexit.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/blockexit.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/blockexit.d
*/
module dmd.blockexit;
@@ -80,26 +80,25 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink)
void visitExp(ExpStatement s)
{
result = BE.fallthru;
- if (s.exp)
+ if (!s.exp)
+ return;
+
+ if (s.exp.op == EXP.halt)
{
- if (s.exp.op == EXP.halt)
+ result = BE.halt;
+ return;
+ }
+ if (AssertExp a = s.exp.isAssertExp())
+ {
+ if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
{
result = BE.halt;
return;
}
- if (AssertExp a = s.exp.isAssertExp())
- {
- if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
- {
- result = BE.halt;
- return;
- }
- }
- if (s.exp.type && s.exp.type.toBasetype().isTypeNoreturn())
- result = BE.halt;
-
- result |= canThrow(s.exp, func, eSink);
}
+ if (s.exp.type && s.exp.type.toBasetype().isTypeNoreturn())
+ result = BE.halt;
+ result |= canThrow(s.exp, func, eSink);
}
void visitDtorExp(DtorExpStatement s)
@@ -120,44 +119,39 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink)
Statement slast = null;
foreach (s; *cs.statements)
{
- if (s)
+ if (!s)
+ continue;
+
+ //printf("result = x%x\n", result);
+ //printf("s: %s\n", s.toChars());
+ if (result & BE.fallthru && slast)
{
- //printf("result = x%x\n", result);
- //printf("s: %s\n", s.toChars());
- if (result & BE.fallthru && slast)
+ slast = slast.last();
+ if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement()))
{
- slast = slast.last();
- if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement()))
+ // Allow if last case/default was empty
+ CaseStatement sc = slast.isCaseStatement();
+ DefaultStatement sd = slast.isDefaultStatement();
+ auto sl = (sc ? sc.statement : (sd ? sd.statement : null));
+
+ if (sl && (!sl.hasCode() || sl.isErrorStatement()))
{
- // Allow if last case/default was empty
- CaseStatement sc = slast.isCaseStatement();
- DefaultStatement sd = slast.isDefaultStatement();
- auto sl = (sc ? sc.statement : (sd ? sd.statement : null));
-
- if (sl && (!sl.hasCode() || sl.isErrorStatement()))
- {
- }
- else if (func.getModule().filetype != FileType.c)
- {
- const(char)* gototype = s.isCaseStatement() ? "case" : "default";
- // @@@DEPRECATED_2.110@@@ https://issues.dlang.org/show_bug.cgi?id=22999
- // Deprecated in 2.100
- // Make an error in 2.110
- if (sl && sl.isCaseStatement())
- global.errorSink.deprecation(s.loc, "switch case fallthrough - use 'goto %s;' if intended", gototype);
- else
- global.errorSink.error(s.loc, "switch case fallthrough - use 'goto %s;' if intended", gototype);
- }
+ }
+ else if (func.getModule().filetype != FileType.c)
+ {
+ const(char)* gototype = s.isCaseStatement() ? "case" : "default";
+ // https://issues.dlang.org/show_bug.cgi?id=22999
+ global.errorSink.error(s.loc, "switch case fallthrough - use 'goto %s;' if intended", gototype);
}
}
+ }
- if ((result & BE.fallthru) || s.comeFrom())
- {
- result &= ~BE.fallthru;
- result |= blockExit(s, func, eSink);
- }
- slast = s;
+ if ((result & BE.fallthru) || s.comeFrom())
+ {
+ result &= ~BE.fallthru;
+ result |= blockExit(s, func, eSink);
}
+ slast = s;
}
}
@@ -166,13 +160,12 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink)
result = BE.fallthru;
foreach (s; *uls.statements)
{
- if (s)
- {
- int r = blockExit(s, func, eSink);
- result |= r & ~(BE.break_ | BE.continue_ | BE.fallthru);
- if ((r & (BE.fallthru | BE.continue_ | BE.break_)) == 0)
- result &= ~BE.fallthru;
- }
+ if (!s)
+ continue;
+ int r = blockExit(s, func, eSink);
+ result |= r & ~(BE.break_ | BE.continue_ | BE.fallthru);
+ if ((r & (BE.fallthru | BE.continue_ | BE.break_)) == 0)
+ result &= ~BE.fallthru;
}
}
@@ -485,7 +478,7 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink)
if (!(s.stc & STC.nothrow_))
{
if(func)
- func.setThrow(s.loc, "`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
+ func.setThrow(s.loc, "executing an `asm` statement without a `nothrow` annotation");
if (eSink)
eSink.error(s.loc, "`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); // TODO
else
@@ -517,7 +510,7 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink)
+
+ Returns: `BE.[err]throw` depending on the type of `exp`
+/
-BE checkThrow(ref const Loc loc, Expression exp, FuncDeclaration func, ErrorSink eSink)
+BE checkThrow(Loc loc, Expression exp, FuncDeclaration func, ErrorSink eSink)
{
Type t = exp.type.toBasetype();
ClassDeclaration cd = t.isClassHandle();
@@ -530,7 +523,7 @@ BE checkThrow(ref const Loc loc, Expression exp, FuncDeclaration func, ErrorSink
if (eSink)
eSink.error(loc, "`%s` is thrown but not caught", exp.type.toChars());
else if (func)
- func.setThrow(loc, "`%s` is thrown but not caught", exp.type);
+ func.setThrow(loc, "`%s` being thrown but not caught", exp.type);
return BE.throw_;
}
diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d
index d29092b..53307fc 100644
--- a/gcc/d/dmd/builtin.d
+++ b/gcc/d/dmd/builtin.d
@@ -3,12 +3,12 @@
*
* Currently includes functions from `std.math`, `core.math` and `core.bitop`.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/builtin.d, _builtin.d)
* Documentation: https://dlang.org/phobos/dmd_builtin.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/builtin.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/builtin.d
*/
module dmd.builtin;
@@ -28,4 +28,4 @@ public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd);
* Evaluate builtin function.
* Return result; NULL if cannot evaluate it.
*/
-public extern (C++) Expression eval_builtin(const ref Loc loc, FuncDeclaration fd, Expressions* arguments);
+public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments);
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index 31155f1..96acf05 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/function.html#nothrow-functions, Nothrow Functions)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d, _canthrow.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/canthrow.d, _canthrow.d)
* Documentation: https://dlang.org/phobos/dmd_canthrow.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/canthrow.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/canthrow.d
*/
module dmd.canthrow;
@@ -20,15 +20,17 @@ import dmd.astenums;
import dmd.blockexit : BE, checkThrow;
import dmd.declaration;
import dmd.dsymbol;
+import dmd.dsymbolsem : include;
import dmd.errorsink;
import dmd.expression;
+import dmd.expressionsem : errorSupplementalInferredAttr;
import dmd.func;
import dmd.globals;
import dmd.init;
import dmd.mtype;
-import dmd.postordervisitor;
import dmd.tokens;
import dmd.visitor;
+import dmd.visitor.postorder;
/**
* Status indicating what kind of throwable might be caused by an expression.
@@ -72,16 +74,16 @@ CT canThrow(Expression e, FuncDeclaration func, ErrorSink eSink)
void checkFuncThrows(Expression e, FuncDeclaration f)
{
auto tf = f.type.toBasetype().isTypeFunction();
- if (tf && !tf.isnothrow)
+ if (tf && !tf.isNothrow)
{
if (eSink)
{
eSink.error(e.loc, "%s `%s` is not `nothrow`", f.kind(), f.toPrettyChars());
if (!f.isDtorDeclaration())
- errorSupplementalInferredAttr(f, 10, false, STC.nothrow_);
+ errorSupplementalInferredAttr(f, 10, false, STC.nothrow_, eSink);
import dmd.expressionsem : checkOverriddenDtor;
- f.checkOverriddenDtor(null, e.loc, dd => dd.type.toTypeFunction().isnothrow, "not nothrow");
+ f.checkOverriddenDtor(null, e.loc, dd => dd.type.toTypeFunction().isNothrow, "not nothrow");
}
else if (func)
{
@@ -111,11 +113,9 @@ CT canThrow(Expression e, FuncDeclaration func, ErrorSink eSink)
if (ce.f && ce.arguments.length > 0)
{
Type tb = (*ce.arguments)[0].type.toBasetype();
- auto tbNext = tb.nextOf();
- if (tbNext)
+ if (auto tbNext = tb.nextOf())
{
- auto ts = tbNext.baseElemOf().isTypeStruct();
- if (ts)
+ if (auto ts = tbNext.baseElemOf().isTypeStruct())
{
auto sd = ts.sym;
const id = ce.f.ident;
@@ -135,7 +135,7 @@ CT canThrow(Expression e, FuncDeclaration func, ErrorSink eSink)
if (ce.f && ce.f == func)
return;
const tf = ce.calledFunctionType();
- if (tf && tf.isnothrow)
+ if (tf && tf.isNothrow)
return;
if (ce.f)
diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d
index 5024f9b..8b2d5b4 100644
--- a/gcc/d/dmd/chkformat.d
+++ b/gcc/d/dmd/chkformat.d
@@ -1,12 +1,12 @@
/**
* Check the arguments to `printf` and `scanf` against the `format` string.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d, _chkformat.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/chkformat.d, _chkformat.d)
* Documentation: https://dlang.org/phobos/dmd_chkformat.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/chkformat.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/chkformat.d
*/
module dmd.chkformat;
@@ -21,6 +21,7 @@ import dmd.globals;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
+import dmd.typesem;
import dmd.target;
@@ -62,7 +63,7 @@ import dmd.target;
* https://www.cplusplus.com/reference/cstdio/printf/
*/
public
-bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list, ErrorSink eSink)
+bool checkPrintfFormat(Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list, ErrorSink eSink)
{
//printf("checkPrintFormat('%.*s')\n", cast(int)format.length, format.ptr);
size_t n; // index in args
@@ -173,13 +174,13 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
case Format.lu: // unsigned long int
case Format.ld: // long int
- if (!(t.isintegral() && t.size() == c_longsize))
+ if (!(t.isIntegral() && t.size() == c_longsize))
{
if (fmt == Format.lu)
errorMsg(null, e, (c_longsize == 4 ? "uint" : "ulong"), t);
else
errorMsg(null, e, (c_longsize == 4 ? "int" : "long"), t);
- if (t.isintegral() && t.size() != c_longsize)
+ if (t.isIntegral() && t.size() != c_longsize)
eSink.errorSupplemental(e.loc, "C `long` is %d bytes on your system", c_longsize);
}
break;
@@ -202,12 +203,12 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
break;
case Format.zd: // size_t
- if (!(t.isintegral() && t.size() == ptrsize))
+ if (!(t.isIntegral() && t.size() == ptrsize))
errorMsg(null, e, "size_t", t);
break;
case Format.td: // ptrdiff_t
- if (!(t.isintegral() && t.size() == ptrsize))
+ if (!(t.isIntegral() && t.size() == ptrsize))
errorMsg(null, e, "ptrdiff_t", t);
break;
@@ -233,7 +234,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
break;
case Format.ln: // pointer to long int
- if (!(t.ty == Tpointer && tnext.isintegral() && tnext.size() == c_longsize))
+ if (!(t.ty == Tpointer && tnext.isIntegral() && tnext.size() == c_longsize))
errorMsg(null, e, (c_longsize == 4 ? "int*" : "long*"), t);
break;
@@ -258,12 +259,12 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
break;
case Format.zn: // pointer to size_t
- if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == ptrsize))
+ if (!(t.ty == Tpointer && tnext.isIntegral() && tnext.isUnsigned() && tnext.size() == ptrsize))
errorMsg(null, e, "size_t*", t);
break;
case Format.tn: // pointer to ptrdiff_t
- if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == ptrsize))
+ if (!(t.ty == Tpointer && tnext.isIntegral() && !tnext.isUnsigned() && tnext.size() == ptrsize))
errorMsg(null, e, "ptrdiff_t*", t);
break;
@@ -338,7 +339,7 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
* https://www.cplusplus.com/reference/cstdio/scanf/
*/
public
-bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list, ErrorSink eSink)
+bool checkScanfFormat(Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list, ErrorSink eSink)
{
size_t n = 0;
for (size_t i = 0; i < format.length;)
@@ -413,7 +414,7 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres
case Format.ln:
case Format.ld: // pointer to long int
- if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == c_longsize))
+ if (!(t.ty == Tpointer && tnext.isIntegral() && !tnext.isUnsigned() && tnext.size() == c_longsize))
errorMsg(null, e, (c_longsize == 4 ? "int*" : "long*"), t);
break;
@@ -431,13 +432,13 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres
case Format.zn:
case Format.zd: // pointer to size_t
- if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == ptrsize))
+ if (!(t.ty == Tpointer && tnext.isIntegral() && tnext.isUnsigned() && tnext.size() == ptrsize))
errorMsg(null, e, "size_t*", t);
break;
case Format.tn:
case Format.td: // pointer to ptrdiff_t
- if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == ptrsize))
+ if (!(t.ty == Tpointer && tnext.isIntegral() && !tnext.isUnsigned() && tnext.size() == ptrsize))
errorMsg(null, e, "ptrdiff_t*", t);
break;
@@ -457,7 +458,7 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres
break;
case Format.lu: // pointer to unsigned long int
- if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == c_longsize))
+ if (!(t.ty == Tpointer && tnext.isIntegral() && tnext.isUnsigned() && tnext.size() == c_longsize))
errorMsg(null, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
break;
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 2e4833e..a21f5a0 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -2,12 +2,12 @@
* Builds struct member functions if needed and not defined by the user.
* Includes `opEquals`, `opAssign`, post blit, copy constructor and destructor.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/clone.d, _clone.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/clone.d, _clone.d)
* Documentation: https://dlang.org/phobos/dmd_clone.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/clone.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/clone.d
*/
module dmd.clone;
@@ -51,13 +51,13 @@ import dmd.tokens;
* Returns:
* merged storage class
*/
-StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
+STC mergeFuncAttrs(STC s1, const FuncDeclaration f) pure @safe
{
if (!f)
return s1;
- StorageClass s2 = (f.storage_class & STC.disable);
+ STC s2 = (f.storage_class & STC.disable);
- TypeFunction tf = cast(TypeFunction)f.type;
+ auto tf = f.type.isTypeFunction();
if (tf.trust == TRUST.safe)
s2 |= STC.safe;
else if (tf.trust == TRUST.system)
@@ -67,15 +67,15 @@ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
if (tf.purity != PURE.impure)
s2 |= STC.pure_;
- if (tf.isnothrow)
+ if (tf.isNothrow)
s2 |= STC.nothrow_;
- if (tf.isnogc)
+ if (tf.isNogc)
s2 |= STC.nogc;
const sa = s1 & s2;
const so = s1 | s2;
- StorageClass stc = (sa & (STC.pure_ | STC.nothrow_ | STC.nogc)) | (so & STC.disable);
+ STC stc = (sa & (STC.pure_ | STC.nothrow_ | STC.nogc)) | (so & STC.disable);
if (so & STC.system)
stc |= STC.system;
@@ -96,56 +96,60 @@ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
* sc = current scope
* Returns:
* if found, returns FuncDeclaration of opAssign, otherwise null
+ * References:
+ * https://dlang.org/spec/operatoroverloading.html#assignment
*/
FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc)
{
- Dsymbol assign = search_function(ad, Id.assign);
- if (assign)
- {
- /* check identity opAssign exists
- */
- scope er = new NullExp(ad.loc, ad.type); // dummy rvalue
- scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
- el.type = ad.type;
- auto a = new Expressions(1);
- const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
- sc = sc.push();
- sc.tinst = null;
- sc.minst = null;
+ Dsymbol assign = search_function(ad, Id.opAssign);
+ if (!assign)
+ return null;
- (*a)[0] = er;
- auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet);
- if (!f)
- {
- (*a)[0] = el;
- f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet);
- }
+ /* check identity opAssign exists
+ */
+ scope er = new NullExp(ad.loc, ad.type); // dummy rvalue
+ scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
+ el.type = ad.type;
+ const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
+ sc = sc.push();
+ sc.tinst = null;
+ sc.minst = null;
- sc = sc.pop();
- global.endGagging(errors);
- if (f)
- {
- if (f.errors)
- return null;
- auto fparams = f.getParameterList();
- if (fparams.length)
- {
- auto fparam0 = fparams[0];
- if (fparam0.type.toDsymbol(null) != ad)
- f = null;
- }
- }
- // BUGS: This detection mechanism cannot find some opAssign-s like follows:
- // struct S { void opAssign(ref immutable S) const; }
- return f;
+ auto a = new Expressions(1);
+ (*a)[0] = er;
+ auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet);
+ if (!f)
+ {
+ (*a)[0] = el;
+ f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet);
}
- return null;
+
+ sc = sc.pop();
+ global.endGagging(errors);
+ if (!f)
+ return null;
+ if (f.errors)
+ return null;
+ auto fparams = f.getParameterList();
+ if (fparams.length)
+ {
+ auto fparam0 = fparams[0];
+ if (fparam0.type.toDsymbol(null) != ad)
+ f = null;
+ }
+ // BUGS: This detection mechanism cannot find some opAssign-s like follows:
+ // struct S { void opAssign(ref immutable S) const; }
+ return f;
}
/*******************************************
* We need an opAssign for the struct if
* it has a destructor or a postblit.
- * We need to generate one if a user-specified one does not exist.
+ * (We will later generate one if a user-specified one does not exist)
+ * Params:
+ * sd = struct to check
+ * Returns:
+ * true if an opAssign is needed
*/
private bool needOpAssign(StructDeclaration sd)
{
@@ -175,9 +179,8 @@ private bool needOpAssign(StructDeclaration sd)
if (v.overlapped) // if field of a union
continue; // user must handle it themselves
Type tv = v.type.baseElemOf();
- if (tv.ty == Tstruct)
+ if (auto ts = tv.isTypeStruct())
{
- TypeStruct ts = cast(TypeStruct)tv;
if (ts.sym.isUnionDeclaration())
continue;
if (needOpAssign(ts.sym))
@@ -251,7 +254,7 @@ private bool needOpAssign(StructDeclaration sd)
* sd = struct to generate opAssign for
* sc = context
* Returns:
- * generated `opAssign` function
+ * generated `opAssign` function, or null if it is not needed
*/
FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
{
@@ -266,7 +269,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
return null;
//printf("StructDeclaration::buildOpAssign() %s\n", sd.toChars());
- StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ STC stc = STC.safe;
Loc declLoc = sd.loc;
Loc loc; // internal code should have no loc to prevent coverage
@@ -281,10 +284,10 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
if (v.overlapped)
continue;
Type tv = v.type.baseElemOf();
- if (tv.ty != Tstruct)
- continue;
- StructDeclaration sdv = (cast(TypeStruct)tv).sym;
- stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc));
+ if (auto tvs = tv.isTypeStruct())
+ {
+ stc = mergeFuncAttrs(stc, hasIdentityOpAssign(tvs.sym, sc));
+ }
}
if (sd.dtor || sd.postblit)
@@ -300,7 +303,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
auto fparams = new Parameters();
fparams.push(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.assign, stc, tf);
+ auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.opAssign, stc, tf);
fop.storage_class |= STC.inference;
fop.isGenerated = true;
Expression e;
@@ -314,8 +317,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
else if (sd.dtor)
{
//printf("\tswap copy\n");
- TypeFunction tdtor = cast(TypeFunction)sd.dtor.type;
- assert(tdtor.ty == Tfunction);
+ auto tdtor = sd.dtor.type.isTypeFunction();
auto idswap = Identifier.generateId("__swap");
auto swap = new VarDeclaration(loc, sd.type, idswap, new VoidInitializer(loc));
@@ -378,14 +380,14 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
auto er = new ThisExp(loc);
Statement s2 = new ReturnStatement(loc, er);
fop.fbody = new CompoundStatement(loc, s1, s2);
- tf.isreturn = true;
+ tf.isReturn = true;
}
sd.members.push(fop);
fop.addMember(sc, sd);
sd.hasIdentityAssign = true; // temporary mark identity assignable
const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
Scope* sc2 = sc.push();
- sc2.stc = 0;
+ sc2.stc = STC.none;
sc2.linkage = LINK.d;
fop.dsymbolSemantic(sc2);
fop.semantic2(sc2);
@@ -407,21 +409,34 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
/*******************************************
* We need an opEquals for the struct if
- * any fields has an opEquals.
- * Generate one if a user-specified one does not exist.
+ * any field has an opEquals and a user-specified one does not exist.
+ * Params:
+ * sd = struct to check
+ * Returns:
+ * true if need to generate one
*/
bool needOpEquals(StructDeclaration sd)
{
+ bool dontneed()
+ {
+ //printf("\tdontneed\n");
+ return false;
+ }
+ bool need()
+ {
+ //printf("\tneed\n");
+ return true;
+ }
//printf("StructDeclaration::needOpEquals() %s\n", sd.toChars());
if (sd.isUnionDeclaration())
{
/* If a union has only one field, treat it like a struct
*/
if (sd.fields.length != 1)
- goto Ldontneed;
+ return dontneed();
}
if (sd.hasIdentityEquals)
- goto Lneed;
+ return need();
/* If any of the fields has an opEquals, then we
* need it too.
*/
@@ -433,84 +448,84 @@ bool needOpEquals(StructDeclaration sd)
continue;
Type tv = v.type.toBasetype();
auto tvbase = tv.baseElemOf();
- if (tvbase.ty == Tstruct)
+ if (auto ts = tvbase.isTypeStruct())
{
- TypeStruct ts = cast(TypeStruct)tvbase;
if (ts.sym.isUnionDeclaration() && ts.sym.fields.length != 1)
continue;
if (needOpEquals(ts.sym))
- goto Lneed;
+ return need();
}
- if (tvbase.isfloating())
+ if (tvbase.isFloating())
{
// This is necessray for:
// 1. comparison of +0.0 and -0.0 should be true.
// 2. comparison of NANs should be false always.
- goto Lneed;
+ return need();
}
if (tvbase.ty == Tarray)
- goto Lneed;
+ return need();
if (tvbase.ty == Taarray)
- goto Lneed;
+ return need();
if (tvbase.ty == Tclass)
- goto Lneed;
+ return need();
}
-Ldontneed:
- //printf("\tdontneed\n");
- return false;
-Lneed:
- //printf("\tneed\n");
- return true;
+ return dontneed();
}
/*******************************************
* Check given aggregate actually has an identity opEquals or not.
+ * ad = aggregate to check
+ * sc = context
+ * Returns:
+ * identity opEquals if it is there, null if not
*/
private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc)
{
FuncDeclaration f;
- if (Dsymbol eq = search_function(ad, Id.eq))
+ Dsymbol eq = search_function(ad, Id.opEquals);
+ if (!eq)
+ return null;
+
+ /* check identity opEquals exists
+ */
+ scope er = new NullExp(ad.loc, null); // dummy rvalue
+ scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
+ auto a = new Expressions(1);
+
+ bool hasIt(Type tthis)
{
- /* check identity opEquals exists
- */
- scope er = new NullExp(ad.loc, null); // dummy rvalue
- scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
- auto a = new Expressions(1);
+ const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it
+ sc = sc.push();
+ sc.tinst = null;
+ sc.minst = null;
- bool hasIt(Type tthis)
+ FuncDeclaration rfc(Expression e)
{
- const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it
- sc = sc.push();
- sc.tinst = null;
- sc.minst = null;
-
- FuncDeclaration rfc(Expression e)
- {
- (*a)[0] = e;
- (*a)[0].type = tthis;
- return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(a), FuncResolveFlag.quiet);
- }
+ (*a)[0] = e;
+ (*a)[0].type = tthis;
+ return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(a), FuncResolveFlag.quiet);
+ }
- f = rfc(er);
- if (!f)
- f = rfc(el);
+ f = rfc(er);
+ if (!f)
+ f = rfc(el);
- sc = sc.pop();
- global.endGagging(errors);
+ sc = sc.pop();
+ global.endGagging(errors);
- return f !is null;
- }
+ return f !is null;
+ }
- if (hasIt(ad.type) ||
- hasIt(ad.type.constOf()) ||
- hasIt(ad.type.immutableOf()) ||
- hasIt(ad.type.sharedOf()) ||
- hasIt(ad.type.sharedConstOf()))
- {
- if (f.errors)
- return null;
- }
+ if (hasIt(ad.type) ||
+ hasIt(ad.type.constOf()) ||
+ hasIt(ad.type.immutableOf()) ||
+ hasIt(ad.type.sharedOf()) ||
+ hasIt(ad.type.sharedConstOf()))
+ {
+ if (f.errors)
+ return null;
}
+
return f;
}
@@ -522,7 +537,7 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc)
* opEquals is changed to be never implicitly generated.
* Now, struct objects comparison s1 == s2 is translated to:
* s1.tupleof == s2.tupleof
- * to calculate structural equality. See EqualExp.op_overload.
+ * to calculate structural equality. See `opOverloadEquals`.
*/
FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc)
{
@@ -549,7 +564,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
return null; // bitwise comparison would work
//printf("StructDeclaration::buildXopEquals() %s\n", sd.toChars());
- if (Dsymbol eq = search_function(sd, Id.eq))
+ if (Dsymbol eq = search_function(sd, Id.opEquals))
{
if (FuncDeclaration fd = eq.isFuncDeclaration())
{
@@ -563,7 +578,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
parameters.push(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 = cast(TypeFunction)tfeqptr.typeSemantic(Loc.initial, &scx);
+ tfeqptr = tfeqptr.typeSemantic(Loc.initial, &scx).isTypeFunction();
}
fd = fd.overloadExactMatch(tfeqptr);
if (fd)
@@ -592,16 +607,16 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d, STC.const_);
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopEquals;
- auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
+ auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.none, tf);
fop.isGenerated = true;
fop.parent = sd;
Expression e1 = new IdentifierExp(loc, Id.This);
Expression e2 = new IdentifierExp(loc, Id.p);
Expression e = new EqualExp(EXP.equal, loc, e1, e2);
fop.fbody = new ReturnStatement(loc, e);
- uint errors = global.startGagging(); // Do not report errors
+ const errors = global.startGagging(); // Do not report errors
Scope* sc2 = sc.push();
- sc2.stc = 0;
+ sc2.stc = STC.none;
sc2.linkage = LINK.d;
fop.dsymbolSemantic(sc2);
fop.semantic2(sc2);
@@ -624,7 +639,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
{
//printf("StructDeclaration::buildXopCmp() %s\n", toChars());
- if (Dsymbol cmp = search_function(sd, Id.cmp))
+ if (Dsymbol cmp = search_function(sd, Id.opCmp))
{
if (FuncDeclaration fd = cmp.isFuncDeclaration())
{
@@ -638,11 +653,10 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
parameters.push(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 = cast(TypeFunction)tfcmpptr.typeSemantic(Loc.initial, &scx);
+ tfcmpptr = tfcmpptr.typeSemantic(Loc.initial, &scx).isTypeFunction();
}
- fd = fd.overloadExactMatch(tfcmpptr);
- if (fd)
- return fd;
+ if (auto fdo = fd.overloadExactMatch(tfcmpptr))
+ return fdo;
}
}
else
@@ -653,7 +667,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
* Consider 'alias this', but except opDispatch.
*/
Expression e = new DsymbolExp(sd.loc, sd);
- e = new DotIdExp(sd.loc, e, Id.cmp);
+ e = new DotIdExp(sd.loc, e, Id.opCmp);
Scope* sc2 = sc.push();
e = e.trySemantic(sc2);
sc2.pop();
@@ -674,7 +688,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
default:
break;
}
- if (!s || s.ident != Id.cmp)
+ if (!s || s.ident != Id.opCmp)
e = null; // there's no valid member 'opCmp'
}
if (!e)
@@ -717,16 +731,16 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d, STC.const_);
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopCmp;
- auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
+ auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.none, tf);
fop.isGenerated = true;
fop.parent = sd;
Expression e1 = new IdentifierExp(loc, Id.This);
Expression e2 = new IdentifierExp(loc, Id.p);
- Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2);
+ Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.opCmp), e2);
fop.fbody = new ReturnStatement(loc, e);
- uint errors = global.startGagging(); // Do not report errors
+ const errors = global.startGagging(); // Do not report errors
Scope* sc2 = sc.push();
- sc2.stc = 0;
+ sc2.stc = STC.none;
sc2.linkage = LINK.d;
fop.dsymbolSemantic(sc2);
fop.semantic2(sc2);
@@ -739,15 +753,31 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
/*******************************************
* We need a toHash for the struct if
* any fields has a toHash.
- * Generate one if a user-specified one does not exist.
+ * (will generate one if a user-specified one does not exist)
+ * Params:
+ * sd = struct to check
+ * Returns:
+ * need to generate toHash()
+ * References:
+ * https://dlang.org/spec/hash-map.html#using_struct_as_key
*/
private bool needToHash(StructDeclaration sd)
{
+ bool dontneed()
+ {
+ //printf("\tdontneed\n");
+ return false;
+ }
+ bool need()
+ {
+ //printf("\tneed\n");
+ return true;
+ }
//printf("StructDeclaration::needToHash() %s\n", sd.toChars());
if (sd.isUnionDeclaration())
- goto Ldontneed;
+ return dontneed();
if (sd.xhash)
- goto Lneed;
+ return need();
/* If any of the fields has an toHash, then we
* need it too.
@@ -760,34 +790,28 @@ private bool needToHash(StructDeclaration sd)
continue;
Type tv = v.type.toBasetype();
auto tvbase = tv.baseElemOf();
- if (tvbase.ty == Tstruct)
+ if (auto ts = tvbase.isTypeStruct())
{
- TypeStruct ts = cast(TypeStruct)tvbase;
if (ts.sym.isUnionDeclaration())
continue;
if (needToHash(ts.sym))
- goto Lneed;
+ return need();
}
- if (tvbase.isfloating())
+ if (tvbase.isFloating())
{
/* This is necessary because comparison of +0.0 and -0.0 should be true,
* i.e. not a bit compare.
*/
- goto Lneed;
+ return need();
}
if (tvbase.ty == Tarray)
- goto Lneed;
+ return need();
if (tvbase.ty == Taarray)
- goto Lneed;
+ return need();
if (tvbase.ty == Tclass)
- goto Lneed;
+ return need();
}
-Ldontneed:
- //printf("\tdontneed\n");
- return false;
-Lneed:
- //printf("\tneed\n");
- return true;
+ return dontneed();
}
/******************************************
@@ -803,13 +827,12 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
{
tftohash = new TypeFunction(ParameterList(), Type.thash_t, LINK.d);
tftohash.mod = MODFlags.const_;
- tftohash = cast(TypeFunction)tftohash.merge();
+ tftohash = tftohash.merge().isTypeFunction();
}
if (FuncDeclaration fd = s.isFuncDeclaration())
{
- fd = fd.overloadExactMatch(tftohash);
- if (fd)
- return fd;
+ if (auto fdo = fd.overloadExactMatch(tftohash))
+ return fdo;
}
}
if (!needToHash(sd))
@@ -825,7 +848,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
* Note that it would only be necessary if it has floating point fields.
* For now, we'll just not generate a toHash() for C files.
*/
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
return null;
//printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars());
@@ -854,7 +877,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
"return h;";
fop.fbody = new MixinStatement(loc, new StringExp(loc, code));
Scope* sc2 = sc.push();
- sc2.stc = 0;
+ sc2.stc = STC.none;
sc2.linkage = LINK.d;
fop.dsymbolSemantic(sc2);
fop.semantic2(sc2);
@@ -882,7 +905,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
if (ad.isUnionDeclaration())
return; // unions don't have destructors
- StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ STC stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
Loc declLoc = ad.userDtors.length ? ad.userDtors[0].loc : ad.loc;
Loc loc; // internal code should have no loc to prevent coverage
FuncDeclaration xdtor_fwd = null;
@@ -900,10 +923,10 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
continue;
if (v.overlapped)
continue;
- auto tv = v.type.baseElemOf();
- if (tv.ty != Tstruct)
+ auto tvs = v.type.baseElemOf().isTypeStruct();
+ if (!tvs)
continue;
- auto sdv = (cast(TypeStruct)tv).sym;
+ auto sdv = tvs.sym;
if (!sdv.dtor)
continue;
@@ -925,8 +948,8 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
}
Expression ex;
- tv = v.type.toBasetype();
- if (tv.ty == Tstruct)
+ Type tv = v.type.toBasetype();
+ if (tv.isTypeStruct())
{
// this.v.__xdtor()
@@ -1086,7 +1109,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
// // TODO: if (del) delete (char*)this;
// return (void*) this;
// }
- Parameter delparam = new Parameter(Loc.initial, STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null);
+ Parameter delparam = new Parameter(Loc.initial, STC.none, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null);
Parameters* params = new Parameters;
params.push(delparam);
const stc = dtor.storage_class & ~STC.scope_; // because we add the `return this;` later
@@ -1179,6 +1202,14 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
* invs[0](), invs[1](), ...;
* }
* ---
+ * Params:
+ * ad = aggregate for creating invariant
+ * sc = context
+ * Returns:
+ * generated invariant, null if not needed
+ * References:
+ * https://dlang.org/spec/class.html#invariants
+ * https://dlang.org/spec/struct.html#Invariant
*/
FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc)
{
@@ -1193,8 +1224,8 @@ FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc)
default:
Expression e = null;
- StorageClass stcx = 0;
- StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ STC stcx = STC.none;
+ STC stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
foreach (i, inv; ad.invs)
{
stc = mergeFuncAttrs(stc, inv);
@@ -1203,7 +1234,7 @@ FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc)
// What should do?
}
const stcy = (inv.storage_class & STC.synchronized_) |
- (inv.type.mod & MODFlags.shared_ ? STC.shared_ : 0);
+ (inv.type.mod & MODFlags.shared_ ? STC.shared_ : STC.none);
if (i == 0)
stcx = stcy;
else if (stcx ^ stcy)
@@ -1232,6 +1263,11 @@ FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc)
* all the members.
* Note the close similarity with AggregateDeclaration::buildDtor(),
* and the ordering changes (runs forward instead of backwards).
+ * Params:
+ * sd = struct to create postblit for
+ * sc = context
+ * Returns:
+ * generated postblit, or null if not
*/
FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
{
@@ -1242,7 +1278,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
const hasUserDefinedPosblit = sd.postblits.length && !sd.postblits[0].isDisabled ? true : false;
// by default, the storage class of the created postblit
- StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ STC stc = STC.safe;
Loc declLoc = sd.postblits.length ? sd.postblits[0].loc : sd.loc;
Loc loc; // internal code should have no loc to prevent coverage
@@ -1262,10 +1298,10 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
if (structField.overlapped)
continue;
// if it's a struct declaration or an array of structs
- Type tv = structField.type.baseElemOf();
- if (tv.ty != Tstruct)
+ TypeStruct tvs = structField.type.baseElemOf().isTypeStruct();
+ if (!tvs)
continue;
- auto sdv = (cast(TypeStruct)tv).sym;
+ auto sdv = tvs.sym;
// which has a postblit declaration
if (!sdv.postblit)
continue;
@@ -1275,15 +1311,15 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
// block to destroy any prior successfully postblitted fields should
// this field's postblit fail.
// Don't generate it for betterC code since it cannot throw exceptions.
- if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow && global.params.useExceptions)
+ if (fieldsToDestroy.length > 0 && !sdv.postblit.type.isTypeFunction().isNothrow && global.params.useExceptions)
{
// create a list of destructors that need to be called
Expression[] dtorCalls;
foreach(sf; fieldsToDestroy)
{
Expression ex;
- tv = sf.type.toBasetype();
- if (tv.ty == Tstruct)
+ Type tv = sf.type.toBasetype();
+ if (auto tvs2 = tv.isTypeStruct())
{
// this.v.__xdtor()
@@ -1297,9 +1333,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
if (stc & STC.safe)
stc = (stc & ~STC.safe) | STC.trusted;
- auto sfv = (cast(TypeStruct)sf.type.baseElemOf()).sym;
-
- ex = new DotVarExp(loc, ex, sfv.dtor, false);
+ ex = new DotVarExp(loc, ex, tvs2.sym.dtor, false);
ex = new CallExp(loc, ex);
dtorCalls ~= ex;
@@ -1346,6 +1380,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
// perform semantic on the member postblit in order to
// be able to aggregate it later on with the rest of the
// postblits
+ sdv.postblit.isGenerated = true;
functionSemantic(sdv.postblit);
stc = mergeFuncAttrs(stc, sdv.postblit);
@@ -1361,8 +1396,8 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
}
Expression ex;
- tv = structField.type.toBasetype();
- if (tv.ty == Tstruct)
+ Type tv = structField.type.toBasetype();
+ if (tv.isTypeStruct())
{
// this.v.__xpostblit()
@@ -1411,6 +1446,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
*/
if (sdv.dtor)
{
+ sdv.dtor.isGenerated = true;
functionSemantic(sdv.dtor);
// keep a list of fields that need to be destroyed in case
@@ -1511,25 +1547,27 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
}
/**
- * Generates a copy constructor declaration with the specified storage
+ * Generates a copy or move constructor declaration with the specified storage
* class for the parameter and the function.
*
* Params:
- * sd = the `struct` that contains the copy constructor
- * paramStc = the storage class of the copy constructor parameter
- * funcStc = the storage class for the copy constructor declaration
+ * sd = the `struct` that contains the constructor
+ * paramStc = the storage class of the constructor parameter
+ * funcStc = the storage class for the constructor declaration
+ * move = true for move constructor, false for copy constructor
*
* Returns:
* The copy constructor declaration for struct `sd`.
*/
-private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc)
+private CtorDeclaration generateCtorDeclaration(StructDeclaration sd, const STC paramStc, const STC funcStc, bool move)
{
auto fparams = new Parameters();
auto structType = sd.type;
- fparams.push(new Parameter(Loc.initial, paramStc | STC.ref_ | STC.return_ | STC.scope_, structType, Id.p, null, null));
+ 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));
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, true);
+ auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf);
ccd.storage_class |= funcStc;
ccd.storage_class |= STC.inference;
ccd.isGenerated = true;
@@ -1537,28 +1575,37 @@ private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const
}
/**
- * Generates a trivial copy constructor body that simply does memberwise
- * initialization:
+ * Generates a trivial copy or move constructor body that simply does memberwise
+ * initialization.
*
+ * for copy construction:
* this.field1 = rhs.field1;
* this.field2 = rhs.field2;
* ...
+ * for move construction:
+ * this.field1 = __rvalue(rhs.field1);
+ * this.field2 = __rvalue(rhs.field2);
+ * ...
*
* Params:
- * sd = the `struct` declaration that contains the copy constructor
+ * sd = the `struct` declaration that contains the constructor
+ * move = true for move constructor, false for copy constructor
*
* Returns:
- * A `CompoundStatement` containing the body of the copy constructor.
+ * A `CompoundStatement` containing the body of the constructor.
*/
-private Statement generateCopyCtorBody(StructDeclaration sd)
+private Statement generateCtorBody(StructDeclaration sd, bool move)
{
Loc loc;
Expression e;
foreach (v; sd.fields)
{
+ Expression rhs = new DotVarExp(loc, new IdentifierExp(loc, Id.p), v);
+ if (move)
+ rhs.rvalue = true;
auto ec = new AssignExp(loc,
new DotVarExp(loc, new ThisExp(loc), v),
- new DotVarExp(loc, new IdentifierExp(loc, Id.p), v));
+ rhs);
e = Expression.combine(e, ec);
//printf("e.toChars = %s\n", e.toChars());
}
@@ -1566,27 +1613,18 @@ private Statement generateCopyCtorBody(StructDeclaration sd)
return new CompoundStatement(loc, s1);
}
-/**
- * Determine if a copy constructor is needed for struct sd,
- * if the following conditions are met:
- *
- * 1. sd does not define a copy constructor
- * 2. at least one field of sd defines a copy constructor
- *
+/******************************************
+ * Find root `this` constructor for struct sd.
+ * (root is starting position for overloaded constructors)
* Params:
- * sd = the `struct` for which the copy constructor is generated
- * hasCpCtor = set to true if a copy constructor is already present
- *
- * Returns:
- * `true` if one needs to be generated
- * `false` otherwise
+ * sd = the `struct` to be searched
+ * ctor = `this` if found, otherwise null
+ * Result:
+ * false means `this` found in overload set
*/
-bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
+private bool findStructConstructorRoot(StructDeclaration sd, out Dsymbol ctor)
{
- if (global.errors)
- return false;
-
- auto ctor = sd.search(sd.loc, Id.ctor);
+ ctor = sd.search(sd.loc, Id.ctor); // Aggregate.searchCtor() ?
if (ctor)
{
if (ctor.isOverloadSet())
@@ -1594,13 +1632,18 @@ bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
if (auto td = ctor.isTemplateDeclaration())
ctor = td.funcroot;
}
+ return true;
+}
- CtorDeclaration cpCtor;
- CtorDeclaration rvalueCtor;
-
- if (!ctor)
- goto LcheckFields;
-
+/***********************************************
+ * Find move and copy constructors (if any) starting at `ctor`
+ * Params:
+ * ctor = `this` constructor root
+ * copyCtor = set to first copy constructor found, or null
+ * moveCtor = set to first move constructor found, or null
+ */
+private void findMoveAndCopyConstructors(Dsymbol ctor, out CtorDeclaration copyCtor, out CtorDeclaration moveCtor)
+{
overloadApply(ctor, (Dsymbol s)
{
if (s.isTemplateDeclaration())
@@ -1609,38 +1652,63 @@ bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
assert(ctorDecl);
if (ctorDecl.isCpCtor)
{
- if (!cpCtor)
- cpCtor = ctorDecl;
- return 0;
+ if (!copyCtor)
+ copyCtor = ctorDecl;
}
-
- auto tf = ctorDecl.type.toTypeFunction();
- const dim = tf.parameterList.length;
- if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))
+ else if (ctorDecl.isMoveCtor)
{
- auto param = tf.parameterList[0];
- if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
- {
- rvalueCtor = ctorDecl;
- }
+ if (!moveCtor)
+ moveCtor = ctorDecl;
}
return 0;
});
+}
- if (cpCtor)
- {
- if (rvalueCtor)
- {
- .error(sd.loc, "`struct %s` may not define both a rvalue constructor and a copy constructor", sd.toChars());
- errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
- errorSupplemental(cpCtor.loc, "copy constructor defined here");
- }
- hasCpCtor = true;
- return false;
- }
+/**
+ * Determine if a copy constructor is needed for struct sd,
+ * if the following conditions are met:
+ *
+ * 1. sd does not define a copy constructor
+ * 2. at least one field of sd defines a copy constructor
+ *
+ * Params:
+ * sd = the `struct` for which the copy constructor is generated
+ * hasCopyCtor = set to true if a copy constructor is already present
+ * hasMoveCtor = set to true if a move constructor is already present
+ * needCopyCtor = set to true if a copy constructor is not present, but needed
+ * needMoveCtor = set to true if a move constructor is not present, but needed
+ *
+ * Returns:
+ * `true` if one needs to be generated
+ * `false` otherwise
+ */
+void needCopyOrMoveCtor(StructDeclaration sd, out bool hasCopyCtor, out bool hasMoveCtor, out bool needCopyCtor, out bool needMoveCtor)
+{
+ //printf("needCopyOrMoveCtor() %s\n", sd.toChars());
+ if (global.errors)
+ return;
+
+ Dsymbol ctor;
+ if (!findStructConstructorRoot(sd, ctor))
+ return;
+
+ CtorDeclaration copyCtor;
+ CtorDeclaration moveCtor;
+
+ if (ctor)
+ findMoveAndCopyConstructors(ctor, copyCtor, moveCtor);
+
+ if (moveCtor)
+ hasMoveCtor = true;
+
+ if (copyCtor)
+ hasCopyCtor = true;
+
+ if (hasMoveCtor && hasCopyCtor)
+ return;
-LcheckFields:
VarDeclaration fieldWithCpCtor;
+ VarDeclaration fieldWithMoveCtor;
// see if any struct members define a copy constructor
foreach (v; sd.fields)
{
@@ -1655,20 +1723,25 @@ LcheckFields:
if (ts.sym.hasCopyCtor)
{
fieldWithCpCtor = v;
- break;
+ }
+ if (ts.sym.hasMoveCtor)
+ {
+ fieldWithMoveCtor = v;
}
}
- if (fieldWithCpCtor && rvalueCtor)
+ if (0 && fieldWithCpCtor && moveCtor)
{
.error(sd.loc, "`struct %s` may not define a rvalue constructor and have fields with copy constructors", sd.toChars());
- errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
+ errorSupplemental(moveCtor.loc,"rvalue constructor defined here");
errorSupplemental(fieldWithCpCtor.loc, "field with copy constructor defined here");
- return false;
+ return;
}
- else if (!fieldWithCpCtor)
- return false;
- return true;
+
+ if (fieldWithCpCtor && !hasCopyCtor)
+ needCopyCtor = true;
+ if (fieldWithMoveCtor && !hasMoveCtor)
+ needMoveCtor = true;
}
/**
@@ -1682,30 +1755,25 @@ LcheckFields:
* }
*
* Params:
- * sd = the `struct` for which the copy constructor is generated
- * sc = the scope where the copy constructor is generated
- *
- * Returns:
- * `true` if `struct` sd defines a copy constructor (explicitly or generated),
- * `false` otherwise.
+ * sd = the `struct` for which the constructor is generated
+ * sc = the scope where the constructor is generated
+ * move = true means generate the move constructor, otherwise copy constructor
+ * References:
+ * https://dlang.org/spec/struct.html#struct-copy-constructor
*/
-bool buildCopyCtor(StructDeclaration sd, Scope* sc)
+void buildCopyOrMoveCtor(StructDeclaration sd, Scope* sc, bool move)
{
- bool hasCpCtor;
- if (!needCopyCtor(sd, hasCpCtor))
- return hasCpCtor;
-
- //printf("generating copy constructor for %s\n", sd.toChars());
+ //printf("buildCopyOrMoveCtor() generating %s constructor for %s\n", move ? "move".ptr : "copy".ptr, sd.toChars());
const MOD paramMod = MODFlags.wild;
const MOD funcMod = MODFlags.wild;
- auto ccd = generateCopyCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod));
- auto copyCtorBody = generateCopyCtorBody(sd);
- ccd.fbody = copyCtorBody;
+ auto ccd = generateCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod), move);
+ auto ctorBody = generateCtorBody(sd, move);
+ ccd.fbody = ctorBody;
sd.members.push(ccd);
ccd.addMember(sc, sd);
const errors = global.startGagging();
Scope* sc2 = sc.push();
- sc2.stc = 0;
+ sc2.stc = STC.none;
sc2.linkage = LINK.d;
ccd.dsymbolSemantic(sc2);
ccd.semantic2(sc2);
@@ -1717,5 +1785,4 @@ bool buildCopyCtor(StructDeclaration sd, Scope* sc)
ccd.storage_class |= STC.disable;
ccd.fbody = null;
}
- return true;
}
diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d
index 01aa56d..72cb3e7 100644
--- a/gcc/d/dmd/common/bitfields.d
+++ b/gcc/d/dmd/common/bitfields.d
@@ -1,12 +1,12 @@
/**
* A library bitfields utility
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Dennis Korpel
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d, common/bitfields.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/bitfields.d, common/bitfields.d)
* Documentation: https://dlang.org/phobos/dmd_common_bitfields.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/bitfields.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/common/bitfields.d
*/
module dmd.common.bitfields;
@@ -20,43 +20,79 @@ module dmd.common.bitfields;
extern (D) string generateBitFields(S, T)()
if (__traits(isUnsigned, T))
{
+ import core.bitop: bsr;
+
string result = "extern (C++) pure nothrow @nogc @safe final {";
- enum structName = __traits(identifier, S);
- string initialValue = "";
+ struct BitInfo
+ {
+ int[] offset;
+ int[] size;
+ T initialValue;
+ int totalSize;
+ }
+
+ // Iterate over members to compute bit offset and bit size for each of them
+ enum BitInfo bitInfo = () {
+ BitInfo result;
+ int bitOffset = 0;
+ foreach (size_t i, mem; __traits(allMembers, S))
+ {
+ alias memType = typeof(__traits(getMember, S, mem));
+ enum int bitSize = bsr(memType.max | 1) + 1;
+ result.offset ~= bitOffset;
+ result.size ~= bitSize;
+ result.initialValue |= cast(T) __traits(getMember, S.init, mem) << bitOffset;
+ bitOffset += bitSize;
+ }
+ result.totalSize = bitOffset;
+ return result;
+ } ();
+
+ alias TP = typeof(T.init + 0u); // type that `T` gets promoted to, uint or ulong
+ enum string toString(TP i) = i.stringof; // compile time 'integer to string'
+
+ static assert(bitInfo.totalSize <= T.sizeof * 8,
+ "sum of bit field size "~toString!(bitInfo.totalSize)~" exceeds storage type `"~T.stringof~"`");
+
foreach (size_t i, mem; __traits(allMembers, S))
{
- static assert(is(typeof(__traits(getMember, S, mem)) == bool));
- static assert(i < T.sizeof * 8, "too many fields for bit field storage of type `"~T.stringof~"`");
- enum mask = "(1 << "~i.stringof~")";
+ 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 ~= "
- /// set or get the corresponding "~structName~" member
- bool "~mem~"() const scope { return !!(bitFields & "~mask~"); }
- /// ditto
- bool "~mem~"(bool v)
+ "~typeName~" "~mem~"() const scope { return cast("~typeName~") ((bitFields >>> "~shift~") & "~sizeMask~"); }
+ "~typeName~" "~mem~"("~typeName~" v) scope
{
- v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~");
+ bitFields &= ~("~sizeMask~" << "~shift~");
+ bitFields |= v << "~shift~";
return v;
}";
-
- initialValue = (__traits(getMember, S.init, mem) ? "1" : "0") ~ initialValue;
}
- return result ~ "}\n private "~T.stringof~" bitFields = 0b" ~ initialValue ~ ";\n";
+ enum TP initVal = bitInfo.initialValue;
+ return result ~ "\n}\n private "~T.stringof~" bitFields = " ~ toString!(initVal) ~ ";\n";
}
///
unittest
{
+ enum E
+ {
+ a, b, c,
+ }
+
static struct B
{
bool x;
bool y;
+ E e = E.c;
bool z = 1;
+ private ubyte w = 77;
}
static struct S
{
- mixin(generateBitFields!(B, ubyte));
+ mixin(generateBitFields!(B, ushort));
}
S s;
@@ -69,5 +105,13 @@ unittest
s.y = true;
assert(s.y);
assert(!s.x);
+
+ assert(s.e == E.c);
+ s.e = E.a;
+ assert(s.e == E.a);
+
assert(s.z);
+ assert(s.w == 77);
+ s.w = 3;
+ assert(s.w == 3);
}
diff --git a/gcc/d/dmd/common/charactertables.d b/gcc/d/dmd/common/charactertables.d
new file mode 100644
index 0000000..7df5234
--- /dev/null
+++ b/gcc/d/dmd/common/charactertables.d
@@ -0,0 +1,268 @@
+/**
+ * Character tables related to identifiers.
+ *
+ * Supports UAX31, C99, C11 and least restrictive (All).
+ *
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 https://cattermole.co.nz, Richard (Rikki) Andrew Cattermole)
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/charactertables.d, common/charactertables.d)
+ * Documentation: https://dlang.org/phobos/dmd_common_charactertables.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/common/charactertables.d
+ */
+module dmd.common.charactertables;
+
+@safe nothrow @nogc pure:
+
+extern(C++):
+
+///
+enum IdentifierTable {
+ UAX31, ///
+ C99, ///
+ C11, ///
+ LR, /// Least Restrictive aka All
+}
+
+///
+struct IdentifierCharLookup
+{
+ @safe nothrow @nogc pure:
+
+ ///
+ extern(C++) bool function(dchar) isStart;
+ ///
+ extern(C++) bool function(dchar) isContinue;
+
+ /// Lookup the table given the table name
+ extern(C++) static IdentifierCharLookup forTable(IdentifierTable table)
+ {
+ import dmd.common.identifiertables;
+
+ // Awful solution to require these lambdas.
+ // However without them the extern(C++) ABI issues crop up for isInRange,
+ // and then it can't access the tables.
+ final switch(table)
+ {
+ case IdentifierTable.UAX31:
+ return IdentifierCharLookup(
+ (c) => isInRange!UAX31_Start(c),
+ (c) => isInRange!UAX31_Continue(c));
+ case IdentifierTable.C99:
+ return IdentifierCharLookup(
+ (c) => isInRange!FixedTable_C99_Start(c),
+ (c) => isInRange!FixedTable_C99_Continue(c));
+ case IdentifierTable.C11:
+ return IdentifierCharLookup(
+ (c) => isInRange!FixedTable_C11_Start(c),
+ (c) => isInRange!FixedTable_C11_Continue(c));
+ case IdentifierTable.LR:
+ return IdentifierCharLookup(
+ (c) => isInRange!LeastRestrictive_Start(c),
+ (c) => isInRange!LeastRestrictive_Continue(c));
+ }
+ }
+}
+
+/**
+Convenience function for use in places where we just don't care,
+what the identifier ranges are, or if it is start/continue.
+
+Returns: is character a member of least restrictive of all.
+*/
+bool isAnyIdentifierCharacter(dchar c)
+{
+ import dmd.common.identifiertables;
+ return isInRange!LeastRestrictive_OfAll(c);
+}
+
+///
+unittest
+{
+ assert(isAnyIdentifierCharacter('ÄŸ'));
+}
+
+/**
+Convenience function for use in places where we just don't care,
+what the identifier ranges are.
+
+Returns: is character a member of restrictive Start
+*/
+bool isAnyStart(dchar c)
+{
+ import dmd.common.identifiertables;
+ return isInRange!LeastRestrictive_Start(c);
+}
+
+///
+unittest
+{
+ assert(isAnyStart('ÄŸ'));
+}
+
+/**
+Convenience function for use in places where we just don't care,
+what the identifier ranges are.
+
+Returns: is character a member of least restrictive Continue
+*/
+bool isAnyContinue(dchar c)
+{
+ import dmd.common.identifiertables;
+ return isInRange!LeastRestrictive_Continue(c);
+}
+
+///
+unittest
+{
+ assert(isAnyContinue('ÄŸ'));
+}
+
+/// UTF line separator
+enum LS = 0x2028;
+/// UTF paragraph separator
+enum PS = 0x2029;
+
+private
+{
+ enum CMoctal = 0x1;
+ enum CMhex = 0x2;
+ enum CMidchar = 0x4;
+ enum CMzerosecond = 0x8;
+ enum CMdigitsecond = 0x10;
+ enum CMsinglechar = 0x20;
+}
+
+///
+bool isoctal(const char c)
+{
+ return (cmtable[c] & CMoctal) != 0;
+}
+
+///
+bool ishex(const char c)
+{
+ return (cmtable[c] & CMhex) != 0;
+}
+
+///
+bool isidchar(const char c)
+{
+ return (cmtable[c] & CMidchar) != 0;
+}
+
+///
+bool isZeroSecond(const char c)
+{
+ return (cmtable[c] & CMzerosecond) != 0;
+}
+
+///
+bool isDigitSecond(const char c)
+{
+ return (cmtable[c] & CMdigitsecond) != 0;
+}
+
+///
+bool issinglechar(const char c)
+{
+ return (cmtable[c] & CMsinglechar) != 0;
+}
+
+///
+bool c_isxdigit(const int c)
+{
+ return (( c >= '0' && c <= '9') ||
+ ( c >= 'a' && c <= 'f') ||
+ ( c >= 'A' && c <= 'F'));
+}
+
+///
+bool c_isalnum(const int c)
+{
+ return (( c >= '0' && c <= '9') ||
+ ( c >= 'a' && c <= 'z') ||
+ ( c >= 'A' && c <= 'Z'));
+}
+
+extern(D) private:
+
+// originally from dmd.root.utf
+bool isInRange(alias Ranges)(dchar c)
+{
+ size_t high = Ranges.length - 1;
+ // Shortcut search if c is out of range
+ size_t low = (c < Ranges[0][0] || Ranges[high][1] < c) ? high + 1 : 0;
+ // Binary search
+ while (low <= high)
+ {
+ const size_t mid = low + ((high - low) >> 1);
+ if (c < Ranges[mid][0])
+ high = mid - 1;
+ else if (Ranges[mid][1] < c)
+ low = mid + 1;
+ else
+ {
+ assert(Ranges[mid][0] <= c && c <= Ranges[mid][1]);
+ return true;
+ }
+ }
+ return false;
+}
+
+/********************************************
+ * Do our own char maps
+ */
+// originally from dmd.lexer (was private)
+static immutable cmtable = ()
+{
+ ubyte[256] table;
+ foreach (const c; 0 .. table.length)
+ {
+ if ('0' <= c && c <= '7')
+ table[c] |= CMoctal;
+ if (c_isxdigit(c))
+ table[c] |= CMhex;
+ if (c_isalnum(c) || c == '_')
+ table[c] |= CMidchar;
+
+ switch (c)
+ {
+ case 'x': case 'X':
+ case 'b': case 'B':
+ table[c] |= CMzerosecond;
+ break;
+
+ case '0': .. case '9':
+ case 'e': case 'E':
+ case 'f': case 'F':
+ case 'l': case 'L':
+ case 'p': case 'P':
+ case 'u': case 'U':
+ case 'i':
+ case '.':
+ case '_':
+ table[c] |= CMzerosecond | CMdigitsecond;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (c)
+ {
+ case '\\':
+ case '\n':
+ case '\r':
+ case 0:
+ case 0x1A:
+ case '\'':
+ break;
+ default:
+ if (!(c & 0x80))
+ table[c] |= CMsinglechar;
+ break;
+ }
+ }
+ return table;
+}();
diff --git a/gcc/d/dmd/common/charactertables.h b/gcc/d/dmd/common/charactertables.h
new file mode 100644
index 0000000..b38409e
--- /dev/null
+++ b/gcc/d/dmd/common/charactertables.h
@@ -0,0 +1,29 @@
+/**
+ * Character tables related to identifiers.
+ *
+ * Supports UAX31, C99, C11 and least restrictive (All).
+ *
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 https://cattermole.co.nz, Richard (Rikki) Andrew Cattermole)
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/charactertables.h, common/charactertables.d)
+ */
+
+#pragma once
+
+enum class IdentifierTable
+{
+ UAX31,
+ C99,
+ C11,
+ LR, // Least Restrictive aka All
+};
+
+struct IdentifierCharLookup final
+{
+ bool(*isStart)(char32_t);
+ bool(*isContinue)(char32_t);
+
+ // constructor not provided here.
+ static IdentifierCharLookup forTable(IdentifierTable table);
+};
diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d
index 80677f6..1b01a28 100644
--- a/gcc/d/dmd/common/file.d
+++ b/gcc/d/dmd/common/file.d
@@ -4,25 +4,33 @@
* Functions and objects dedicated to file I/O and management. TODO: Move here artifacts
* from places such as root/ so both the frontend and the backend have access to them.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d, common/_file.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/file.d, common/_file.d)
* Documentation: https://dlang.org/phobos/dmd_common_file.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/file.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/common/file.d
*/
module dmd.common.file;
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+import core.stdc.limits;
+
import core.stdc.errno : errno;
import core.stdc.stdio : fprintf, remove, rename, stderr;
import core.stdc.stdlib;
import core.stdc.string : strerror, strlen, memcpy;
import dmd.common.smallbuffer;
+import dmd.root.filename;
+import dmd.root.rmem;
version (Windows)
{
+ import core.stdc.wchar_;
import core.sys.windows.winbase;
import core.sys.windows.winnls : CP_ACP;
import core.sys.windows.winnt;
@@ -32,6 +40,7 @@ version (Windows)
}
else version (Posix)
{
+ import core.sys.posix.dirent;
import core.sys.posix.fcntl;
import core.sys.posix.sys.mman;
import core.sys.posix.sys.stat;
@@ -566,7 +575,7 @@ else version (Windows)
private ulong fileSize(HANDLE fd)
{
ulong result;
- if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
+ if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result))
return result;
return ulong.max;
}
@@ -587,3 +596,163 @@ private auto ref fakePure(F)(scope F fun) pure
mixin("alias PureFun = " ~ F.stringof ~ " pure;");
return (cast(PureFun) fun)();
}
+
+/***********************************
+ * Recursively search all the directories and files under dir_path
+ * for files that match one of the extensions in exts[].
+ * Pass the matches to sink.
+ * Params:
+ * dir_path = root of directories to search
+ * exts = array of filename extensions to match
+ * recurse = go into subdirectories
+ * filenameSink = accepts the resulting matches
+ * Returns:
+ * true for failed to open the directory
+ */
+bool findFiles(const char* dir_path, const char[][] exts, bool recurse, void delegate(const(char)[]) nothrow filenameSink)
+{
+ enum log = false;
+ if (log) printf("findFiles() dir_path: %s\n", dir_path);
+ version (Windows)
+ {
+ debug
+ enum BufLength = 10; // trigger any reallocation bugs
+ else
+ enum BufLength = 100;
+ char[BufLength + 1] buf = void;
+ char* fullPath = buf.ptr;
+ size_t fullPathLength = BufLength;
+
+ // fullPath = dir_path \ *.*
+ const dir_pathLength = strlen(dir_path);
+ auto count = dir_pathLength + 1 + 3;
+ if (count > fullPathLength)
+ {
+ fullPathLength = count;
+ fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
+ }
+ memcpy(fullPath, dir_path, dir_pathLength);
+ strcpy(fullPath + dir_pathLength, "\\*.*".ptr);
+
+ if (log) printf("fullPath: %s\n", fullPath);
+
+ WIN32_FIND_DATAW ffd = void;
+ HANDLE hFind = fullPath[0 .. strlen(fullPath)].extendedPathThen!(p => FindFirstFileW(p.ptr, &ffd));
+ if (hFind == INVALID_HANDLE_VALUE)
+ return true;
+
+ do
+ {
+ if (log) wprintf("ffd.cFileName: %s\n", ffd.cFileName.ptr);
+ if (ffd.cFileName[0] == 0)
+ continue; // ignore
+
+ if (ffd.cFileName[0] == '.')
+ continue; // ignore files that start with a ., also ignore . and .. directories
+
+ const(char)[] name = toNarrowStringz(ffd.cFileName[0 .. wcslen(ffd.cFileName.ptr)], null);
+ if (log) printf("name: %s\n", name.ptr);
+
+ // fullPath = dir_path \ name.ptr
+ count = dir_pathLength + 1 + name.length;
+ if (count > fullPathLength)
+ {
+ fullPathLength = count;
+ fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
+ }
+ strcpy(fullPath + dir_pathLength + 1, name.ptr);
+
+ if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if (recurse)
+ findFiles(fullPath, exts, recurse, filenameSink);
+ }
+ else
+ {
+ const(char)[] nameExt = FileName.ext(name);
+ foreach (ext; exts[])
+ {
+ if (nameExt == ext)
+ {
+ if (log) printf("adding %s\n", fullPath);
+ filenameSink(fullPath[0 .. count]);
+ }
+ }
+ }
+ mem.xfree(cast(void*)name.ptr);
+
+ } while (FindNextFileW(hFind, &ffd) != 0);
+
+ if (fullPath != buf.ptr)
+ mem.xfree(fullPath);
+ FindClose(hFind);
+ if (log) printf("findFiles() exit\n");
+ return false;
+ }
+ else version (Posix)
+ {
+ DIR* dir = opendir(dir_path);
+ if (!dir)
+ return true;
+
+ debug
+ enum BufLength = 10; // trigger any reallocation bugs
+ else
+ enum BufLength = 100;
+ char[BufLength + 1] buf = void;
+ char* fullPath = buf.ptr;
+ size_t fullPathLength = BufLength;
+
+ dirent* entry;
+ while ((entry = readdir(dir)) != null)
+ {
+ //printf("entry: %s\n", entry.d_name.ptr);
+ if (entry.d_name[0] == '.')
+ continue; // ignore files that start with a .
+
+ // fullPath = dir_path / entry.d_name.ptr
+ const dir_pathLength = strlen(dir_path);
+ const count = dir_pathLength + 1 + strlen(entry.d_name.ptr);
+ if (count > fullPathLength)
+ {
+ fullPathLength = count;
+ fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
+ }
+ memcpy(fullPath, dir_path, dir_pathLength);
+ fullPath[dir_pathLength] = '/';
+ strcpy(fullPath + dir_pathLength + 1, entry.d_name.ptr);
+
+ stat_t statbuf;
+ if (lstat(fullPath, &statbuf) == -1)
+ continue;
+
+ const(char)[] name = entry.d_name.ptr[0 .. strlen(entry.d_name.ptr)]; // convert to D string
+ if (!name.length)
+ continue; // ignore
+
+ if (S_ISDIR(statbuf.st_mode))
+ {
+ if (recurse && !(name == "." || name == ".."))
+ findFiles(fullPath, exts, recurse, filenameSink);
+ }
+ else if (S_ISREG(statbuf.st_mode))
+ {
+ foreach (ext; exts)
+ {
+ if (FileName.ext(name) == ext)
+ {
+ //printf("%s\n", fullPath);
+ filenameSink(fullPath[0 .. count]);
+ }
+ }
+ }
+ }
+
+ if (fullPath != buf.ptr)
+ mem.xfree(fullPath);
+ closedir(dir);
+ return false;
+ }
+ else
+ static assert(0);
+}
diff --git a/gcc/d/dmd/common/identifiertables.d b/gcc/d/dmd/common/identifiertables.d
new file mode 100644
index 0000000..b87e9fa
--- /dev/null
+++ b/gcc/d/dmd/common/identifiertables.d
@@ -0,0 +1,4241 @@
+// Generated by compiler/tools/unicode_tables.d DO NOT MODIFY!!!
+module dmd.common.identifiertables;
+
+/**
+UAX31 profile Start
+Entries: 136892
+*/
+static immutable dchar[2][] UAX31_Start = [
+ [0xAA, 0xAA],
+ [0xB5, 0xB5],
+ [0xBA, 0xBA],
+ [0xC0, 0xD6],
+ [0xD8, 0xF6],
+ [0xF8, 0x2C1],
+ [0x2C6, 0x2D1],
+ [0x2E0, 0x2E4],
+ [0x2EC, 0x2EC],
+ [0x2EE, 0x2EE],
+ [0x370, 0x374],
+ [0x376, 0x377],
+ [0x37B, 0x37D],
+ [0x37F, 0x37F],
+ [0x386, 0x386],
+ [0x388, 0x38A],
+ [0x38C, 0x38C],
+ [0x38E, 0x3A1],
+ [0x3A3, 0x3F5],
+ [0x3F7, 0x481],
+ [0x48A, 0x52F],
+ [0x531, 0x556],
+ [0x559, 0x559],
+ [0x560, 0x588],
+ [0x5D0, 0x5EA],
+ [0x5EF, 0x5F2],
+ [0x620, 0x64A],
+ [0x66E, 0x66F],
+ [0x671, 0x6D3],
+ [0x6D5, 0x6D5],
+ [0x6E5, 0x6E6],
+ [0x6EE, 0x6EF],
+ [0x6FA, 0x6FC],
+ [0x6FF, 0x6FF],
+ [0x710, 0x710],
+ [0x712, 0x72F],
+ [0x74D, 0x7A5],
+ [0x7B1, 0x7B1],
+ [0x7CA, 0x7EA],
+ [0x7F4, 0x7F5],
+ [0x7FA, 0x7FA],
+ [0x800, 0x815],
+ [0x81A, 0x81A],
+ [0x824, 0x824],
+ [0x828, 0x828],
+ [0x840, 0x858],
+ [0x860, 0x86A],
+ [0x870, 0x887],
+ [0x889, 0x88E],
+ [0x8A0, 0x8C9],
+ [0x904, 0x939],
+ [0x93D, 0x93D],
+ [0x950, 0x950],
+ [0x958, 0x961],
+ [0x971, 0x980],
+ [0x985, 0x98C],
+ [0x98F, 0x990],
+ [0x993, 0x9A8],
+ [0x9AA, 0x9B0],
+ [0x9B2, 0x9B2],
+ [0x9B6, 0x9B9],
+ [0x9BD, 0x9BD],
+ [0x9CE, 0x9CE],
+ [0x9DC, 0x9DD],
+ [0x9DF, 0x9E1],
+ [0x9F0, 0x9F1],
+ [0x9FC, 0x9FC],
+ [0xA05, 0xA0A],
+ [0xA0F, 0xA10],
+ [0xA13, 0xA28],
+ [0xA2A, 0xA30],
+ [0xA32, 0xA33],
+ [0xA35, 0xA36],
+ [0xA38, 0xA39],
+ [0xA59, 0xA5C],
+ [0xA5E, 0xA5E],
+ [0xA72, 0xA74],
+ [0xA85, 0xA8D],
+ [0xA8F, 0xA91],
+ [0xA93, 0xAA8],
+ [0xAAA, 0xAB0],
+ [0xAB2, 0xAB3],
+ [0xAB5, 0xAB9],
+ [0xABD, 0xABD],
+ [0xAD0, 0xAD0],
+ [0xAE0, 0xAE1],
+ [0xAF9, 0xAF9],
+ [0xB05, 0xB0C],
+ [0xB0F, 0xB10],
+ [0xB13, 0xB28],
+ [0xB2A, 0xB30],
+ [0xB32, 0xB33],
+ [0xB35, 0xB39],
+ [0xB3D, 0xB3D],
+ [0xB5C, 0xB5D],
+ [0xB5F, 0xB61],
+ [0xB71, 0xB71],
+ [0xB83, 0xB83],
+ [0xB85, 0xB8A],
+ [0xB8E, 0xB90],
+ [0xB92, 0xB95],
+ [0xB99, 0xB9A],
+ [0xB9C, 0xB9C],
+ [0xB9E, 0xB9F],
+ [0xBA3, 0xBA4],
+ [0xBA8, 0xBAA],
+ [0xBAE, 0xBB9],
+ [0xBD0, 0xBD0],
+ [0xC05, 0xC0C],
+ [0xC0E, 0xC10],
+ [0xC12, 0xC28],
+ [0xC2A, 0xC39],
+ [0xC3D, 0xC3D],
+ [0xC58, 0xC5A],
+ [0xC5D, 0xC5D],
+ [0xC60, 0xC61],
+ [0xC80, 0xC80],
+ [0xC85, 0xC8C],
+ [0xC8E, 0xC90],
+ [0xC92, 0xCA8],
+ [0xCAA, 0xCB3],
+ [0xCB5, 0xCB9],
+ [0xCBD, 0xCBD],
+ [0xCDD, 0xCDE],
+ [0xCE0, 0xCE1],
+ [0xCF1, 0xCF2],
+ [0xD04, 0xD0C],
+ [0xD0E, 0xD10],
+ [0xD12, 0xD3A],
+ [0xD3D, 0xD3D],
+ [0xD4E, 0xD4E],
+ [0xD54, 0xD56],
+ [0xD5F, 0xD61],
+ [0xD7A, 0xD7F],
+ [0xD85, 0xD96],
+ [0xD9A, 0xDB1],
+ [0xDB3, 0xDBB],
+ [0xDBD, 0xDBD],
+ [0xDC0, 0xDC6],
+ [0xE01, 0xE30],
+ [0xE32, 0xE32],
+ [0xE40, 0xE46],
+ [0xE81, 0xE82],
+ [0xE84, 0xE84],
+ [0xE86, 0xE8A],
+ [0xE8C, 0xEA3],
+ [0xEA5, 0xEA5],
+ [0xEA7, 0xEB0],
+ [0xEB2, 0xEB2],
+ [0xEBD, 0xEBD],
+ [0xEC0, 0xEC4],
+ [0xEC6, 0xEC6],
+ [0xEDC, 0xEDF],
+ [0xF00, 0xF00],
+ [0xF40, 0xF47],
+ [0xF49, 0xF6C],
+ [0xF88, 0xF8C],
+ [0x1000, 0x102A],
+ [0x103F, 0x103F],
+ [0x1050, 0x1055],
+ [0x105A, 0x105D],
+ [0x1061, 0x1061],
+ [0x1065, 0x1066],
+ [0x106E, 0x1070],
+ [0x1075, 0x1081],
+ [0x108E, 0x108E],
+ [0x10A0, 0x10C5],
+ [0x10C7, 0x10C7],
+ [0x10CD, 0x10CD],
+ [0x10D0, 0x10FA],
+ [0x10FC, 0x1248],
+ [0x124A, 0x124D],
+ [0x1250, 0x1256],
+ [0x1258, 0x1258],
+ [0x125A, 0x125D],
+ [0x1260, 0x1288],
+ [0x128A, 0x128D],
+ [0x1290, 0x12B0],
+ [0x12B2, 0x12B5],
+ [0x12B8, 0x12BE],
+ [0x12C0, 0x12C0],
+ [0x12C2, 0x12C5],
+ [0x12C8, 0x12D6],
+ [0x12D8, 0x1310],
+ [0x1312, 0x1315],
+ [0x1318, 0x135A],
+ [0x1380, 0x138F],
+ [0x13A0, 0x13F5],
+ [0x13F8, 0x13FD],
+ [0x1401, 0x166C],
+ [0x166F, 0x167F],
+ [0x1681, 0x169A],
+ [0x16A0, 0x16EA],
+ [0x16EE, 0x16F8],
+ [0x1700, 0x1711],
+ [0x171F, 0x1731],
+ [0x1740, 0x1751],
+ [0x1760, 0x176C],
+ [0x176E, 0x1770],
+ [0x1780, 0x17B3],
+ [0x17D7, 0x17D7],
+ [0x17DC, 0x17DC],
+ [0x1820, 0x1878],
+ [0x1880, 0x18A8],
+ [0x18AA, 0x18AA],
+ [0x18B0, 0x18F5],
+ [0x1900, 0x191E],
+ [0x1950, 0x196D],
+ [0x1970, 0x1974],
+ [0x1980, 0x19AB],
+ [0x19B0, 0x19C9],
+ [0x1A00, 0x1A16],
+ [0x1A20, 0x1A54],
+ [0x1AA7, 0x1AA7],
+ [0x1B05, 0x1B33],
+ [0x1B45, 0x1B4C],
+ [0x1B83, 0x1BA0],
+ [0x1BAE, 0x1BAF],
+ [0x1BBA, 0x1BE5],
+ [0x1C00, 0x1C23],
+ [0x1C4D, 0x1C4F],
+ [0x1C5A, 0x1C7D],
+ [0x1C80, 0x1C88],
+ [0x1C90, 0x1CBA],
+ [0x1CBD, 0x1CBF],
+ [0x1CE9, 0x1CEC],
+ [0x1CEE, 0x1CF3],
+ [0x1CF5, 0x1CF6],
+ [0x1CFA, 0x1CFA],
+ [0x1D00, 0x1DBF],
+ [0x1E00, 0x1F15],
+ [0x1F18, 0x1F1D],
+ [0x1F20, 0x1F45],
+ [0x1F48, 0x1F4D],
+ [0x1F50, 0x1F57],
+ [0x1F59, 0x1F59],
+ [0x1F5B, 0x1F5B],
+ [0x1F5D, 0x1F5D],
+ [0x1F5F, 0x1F7D],
+ [0x1F80, 0x1FB4],
+ [0x1FB6, 0x1FBC],
+ [0x1FBE, 0x1FBE],
+ [0x1FC2, 0x1FC4],
+ [0x1FC6, 0x1FCC],
+ [0x1FD0, 0x1FD3],
+ [0x1FD6, 0x1FDB],
+ [0x1FE0, 0x1FEC],
+ [0x1FF2, 0x1FF4],
+ [0x1FF6, 0x1FFC],
+ [0x2071, 0x2071],
+ [0x207F, 0x207F],
+ [0x2090, 0x209C],
+ [0x2102, 0x2102],
+ [0x2107, 0x2107],
+ [0x210A, 0x2113],
+ [0x2115, 0x2115],
+ [0x2118, 0x211D],
+ [0x2124, 0x2124],
+ [0x2126, 0x2126],
+ [0x2128, 0x2128],
+ [0x212A, 0x2139],
+ [0x213C, 0x213F],
+ [0x2145, 0x2149],
+ [0x214E, 0x214E],
+ [0x2160, 0x2188],
+ [0x2C00, 0x2CE4],
+ [0x2CEB, 0x2CEE],
+ [0x2CF2, 0x2CF3],
+ [0x2D00, 0x2D25],
+ [0x2D27, 0x2D27],
+ [0x2D2D, 0x2D2D],
+ [0x2D30, 0x2D67],
+ [0x2D6F, 0x2D6F],
+ [0x2D80, 0x2D96],
+ [0x2DA0, 0x2DA6],
+ [0x2DA8, 0x2DAE],
+ [0x2DB0, 0x2DB6],
+ [0x2DB8, 0x2DBE],
+ [0x2DC0, 0x2DC6],
+ [0x2DC8, 0x2DCE],
+ [0x2DD0, 0x2DD6],
+ [0x2DD8, 0x2DDE],
+ [0x3005, 0x3007],
+ [0x3021, 0x3029],
+ [0x3031, 0x3035],
+ [0x3038, 0x303C],
+ [0x3041, 0x3096],
+ [0x309D, 0x309F],
+ [0x30A1, 0x30FA],
+ [0x30FC, 0x30FF],
+ [0x3105, 0x312F],
+ [0x3131, 0x318E],
+ [0x31A0, 0x31BF],
+ [0x31F0, 0x31FF],
+ [0x3400, 0x4DBF],
+ [0x4E00, 0xA48C],
+ [0xA4D0, 0xA4FD],
+ [0xA500, 0xA60C],
+ [0xA610, 0xA61F],
+ [0xA62A, 0xA62B],
+ [0xA640, 0xA66E],
+ [0xA67F, 0xA69D],
+ [0xA6A0, 0xA6EF],
+ [0xA717, 0xA71F],
+ [0xA722, 0xA788],
+ [0xA78B, 0xA7CA],
+ [0xA7D0, 0xA7D1],
+ [0xA7D3, 0xA7D3],
+ [0xA7D5, 0xA7D9],
+ [0xA7F2, 0xA801],
+ [0xA803, 0xA805],
+ [0xA807, 0xA80A],
+ [0xA80C, 0xA822],
+ [0xA840, 0xA873],
+ [0xA882, 0xA8B3],
+ [0xA8F2, 0xA8F7],
+ [0xA8FB, 0xA8FB],
+ [0xA8FD, 0xA8FE],
+ [0xA90A, 0xA925],
+ [0xA930, 0xA946],
+ [0xA960, 0xA97C],
+ [0xA984, 0xA9B2],
+ [0xA9CF, 0xA9CF],
+ [0xA9E0, 0xA9E4],
+ [0xA9E6, 0xA9EF],
+ [0xA9FA, 0xA9FE],
+ [0xAA00, 0xAA28],
+ [0xAA40, 0xAA42],
+ [0xAA44, 0xAA4B],
+ [0xAA60, 0xAA76],
+ [0xAA7A, 0xAA7A],
+ [0xAA7E, 0xAAAF],
+ [0xAAB1, 0xAAB1],
+ [0xAAB5, 0xAAB6],
+ [0xAAB9, 0xAABD],
+ [0xAAC0, 0xAAC0],
+ [0xAAC2, 0xAAC2],
+ [0xAADB, 0xAADD],
+ [0xAAE0, 0xAAEA],
+ [0xAAF2, 0xAAF4],
+ [0xAB01, 0xAB06],
+ [0xAB09, 0xAB0E],
+ [0xAB11, 0xAB16],
+ [0xAB20, 0xAB26],
+ [0xAB28, 0xAB2E],
+ [0xAB30, 0xAB5A],
+ [0xAB5C, 0xAB69],
+ [0xAB70, 0xABE2],
+ [0xAC00, 0xD7A3],
+ [0xD7B0, 0xD7C6],
+ [0xD7CB, 0xD7FB],
+ [0xF900, 0xFA6D],
+ [0xFA70, 0xFAD9],
+ [0xFB00, 0xFB06],
+ [0xFB13, 0xFB17],
+ [0xFB1D, 0xFB1D],
+ [0xFB1F, 0xFB28],
+ [0xFB2A, 0xFB36],
+ [0xFB38, 0xFB3C],
+ [0xFB3E, 0xFB3E],
+ [0xFB40, 0xFB41],
+ [0xFB43, 0xFB44],
+ [0xFB46, 0xFBB1],
+ [0xFBD3, 0xFC5D],
+ [0xFC64, 0xFD3D],
+ [0xFD50, 0xFD8F],
+ [0xFD92, 0xFDC7],
+ [0xFDF0, 0xFDF9],
+ [0xFE71, 0xFE71],
+ [0xFE73, 0xFE73],
+ [0xFE77, 0xFE77],
+ [0xFE79, 0xFE79],
+ [0xFE7B, 0xFE7B],
+ [0xFE7D, 0xFE7D],
+ [0xFE7F, 0xFEFC],
+ [0xFF21, 0xFF3A],
+ [0xFF41, 0xFF5A],
+ [0xFF66, 0xFF9D],
+ [0xFFA0, 0xFFBE],
+ [0xFFC2, 0xFFC7],
+ [0xFFCA, 0xFFCF],
+ [0xFFD2, 0xFFD7],
+ [0xFFDA, 0xFFDC],
+ [0x10000, 0x1000B],
+ [0x1000D, 0x10026],
+ [0x10028, 0x1003A],
+ [0x1003C, 0x1003D],
+ [0x1003F, 0x1004D],
+ [0x10050, 0x1005D],
+ [0x10080, 0x100FA],
+ [0x10140, 0x10174],
+ [0x10280, 0x1029C],
+ [0x102A0, 0x102D0],
+ [0x10300, 0x1031F],
+ [0x1032D, 0x1034A],
+ [0x10350, 0x10375],
+ [0x10380, 0x1039D],
+ [0x103A0, 0x103C3],
+ [0x103C8, 0x103CF],
+ [0x103D1, 0x103D5],
+ [0x10400, 0x1049D],
+ [0x104B0, 0x104D3],
+ [0x104D8, 0x104FB],
+ [0x10500, 0x10527],
+ [0x10530, 0x10563],
+ [0x10570, 0x1057A],
+ [0x1057C, 0x1058A],
+ [0x1058C, 0x10592],
+ [0x10594, 0x10595],
+ [0x10597, 0x105A1],
+ [0x105A3, 0x105B1],
+ [0x105B3, 0x105B9],
+ [0x105BB, 0x105BC],
+ [0x10600, 0x10736],
+ [0x10740, 0x10755],
+ [0x10760, 0x10767],
+ [0x10780, 0x10785],
+ [0x10787, 0x107B0],
+ [0x107B2, 0x107BA],
+ [0x10800, 0x10805],
+ [0x10808, 0x10808],
+ [0x1080A, 0x10835],
+ [0x10837, 0x10838],
+ [0x1083C, 0x1083C],
+ [0x1083F, 0x10855],
+ [0x10860, 0x10876],
+ [0x10880, 0x1089E],
+ [0x108E0, 0x108F2],
+ [0x108F4, 0x108F5],
+ [0x10900, 0x10915],
+ [0x10920, 0x10939],
+ [0x10980, 0x109B7],
+ [0x109BE, 0x109BF],
+ [0x10A00, 0x10A00],
+ [0x10A10, 0x10A13],
+ [0x10A15, 0x10A17],
+ [0x10A19, 0x10A35],
+ [0x10A60, 0x10A7C],
+ [0x10A80, 0x10A9C],
+ [0x10AC0, 0x10AC7],
+ [0x10AC9, 0x10AE4],
+ [0x10B00, 0x10B35],
+ [0x10B40, 0x10B55],
+ [0x10B60, 0x10B72],
+ [0x10B80, 0x10B91],
+ [0x10C00, 0x10C48],
+ [0x10C80, 0x10CB2],
+ [0x10CC0, 0x10CF2],
+ [0x10D00, 0x10D23],
+ [0x10E80, 0x10EA9],
+ [0x10EB0, 0x10EB1],
+ [0x10F00, 0x10F1C],
+ [0x10F27, 0x10F27],
+ [0x10F30, 0x10F45],
+ [0x10F70, 0x10F81],
+ [0x10FB0, 0x10FC4],
+ [0x10FE0, 0x10FF6],
+ [0x11003, 0x11037],
+ [0x11071, 0x11072],
+ [0x11075, 0x11075],
+ [0x11083, 0x110AF],
+ [0x110D0, 0x110E8],
+ [0x11103, 0x11126],
+ [0x11144, 0x11144],
+ [0x11147, 0x11147],
+ [0x11150, 0x11172],
+ [0x11176, 0x11176],
+ [0x11183, 0x111B2],
+ [0x111C1, 0x111C4],
+ [0x111DA, 0x111DA],
+ [0x111DC, 0x111DC],
+ [0x11200, 0x11211],
+ [0x11213, 0x1122B],
+ [0x1123F, 0x11240],
+ [0x11280, 0x11286],
+ [0x11288, 0x11288],
+ [0x1128A, 0x1128D],
+ [0x1128F, 0x1129D],
+ [0x1129F, 0x112A8],
+ [0x112B0, 0x112DE],
+ [0x11305, 0x1130C],
+ [0x1130F, 0x11310],
+ [0x11313, 0x11328],
+ [0x1132A, 0x11330],
+ [0x11332, 0x11333],
+ [0x11335, 0x11339],
+ [0x1133D, 0x1133D],
+ [0x11350, 0x11350],
+ [0x1135D, 0x11361],
+ [0x11400, 0x11434],
+ [0x11447, 0x1144A],
+ [0x1145F, 0x11461],
+ [0x11480, 0x114AF],
+ [0x114C4, 0x114C5],
+ [0x114C7, 0x114C7],
+ [0x11580, 0x115AE],
+ [0x115D8, 0x115DB],
+ [0x11600, 0x1162F],
+ [0x11644, 0x11644],
+ [0x11680, 0x116AA],
+ [0x116B8, 0x116B8],
+ [0x11700, 0x1171A],
+ [0x11740, 0x11746],
+ [0x11800, 0x1182B],
+ [0x118A0, 0x118DF],
+ [0x118FF, 0x11906],
+ [0x11909, 0x11909],
+ [0x1190C, 0x11913],
+ [0x11915, 0x11916],
+ [0x11918, 0x1192F],
+ [0x1193F, 0x1193F],
+ [0x11941, 0x11941],
+ [0x119A0, 0x119A7],
+ [0x119AA, 0x119D0],
+ [0x119E1, 0x119E1],
+ [0x119E3, 0x119E3],
+ [0x11A00, 0x11A00],
+ [0x11A0B, 0x11A32],
+ [0x11A3A, 0x11A3A],
+ [0x11A50, 0x11A50],
+ [0x11A5C, 0x11A89],
+ [0x11A9D, 0x11A9D],
+ [0x11AB0, 0x11AF8],
+ [0x11C00, 0x11C08],
+ [0x11C0A, 0x11C2E],
+ [0x11C40, 0x11C40],
+ [0x11C72, 0x11C8F],
+ [0x11D00, 0x11D06],
+ [0x11D08, 0x11D09],
+ [0x11D0B, 0x11D30],
+ [0x11D46, 0x11D46],
+ [0x11D60, 0x11D65],
+ [0x11D67, 0x11D68],
+ [0x11D6A, 0x11D89],
+ [0x11D98, 0x11D98],
+ [0x11EE0, 0x11EF2],
+ [0x11F02, 0x11F02],
+ [0x11F04, 0x11F10],
+ [0x11F12, 0x11F33],
+ [0x11FB0, 0x11FB0],
+ [0x12000, 0x12399],
+ [0x12400, 0x1246E],
+ [0x12480, 0x12543],
+ [0x12F90, 0x12FF0],
+ [0x13000, 0x1342F],
+ [0x13441, 0x13446],
+ [0x14400, 0x14646],
+ [0x16800, 0x16A38],
+ [0x16A40, 0x16A5E],
+ [0x16A70, 0x16ABE],
+ [0x16AD0, 0x16AED],
+ [0x16B00, 0x16B2F],
+ [0x16B40, 0x16B43],
+ [0x16B63, 0x16B77],
+ [0x16B7D, 0x16B8F],
+ [0x16E40, 0x16E7F],
+ [0x16F00, 0x16F4A],
+ [0x16F50, 0x16F50],
+ [0x16F93, 0x16F9F],
+ [0x16FE0, 0x16FE1],
+ [0x16FE3, 0x16FE3],
+ [0x17000, 0x187F7],
+ [0x18800, 0x18CD5],
+ [0x18D00, 0x18D08],
+ [0x1AFF0, 0x1AFF3],
+ [0x1AFF5, 0x1AFFB],
+ [0x1AFFD, 0x1AFFE],
+ [0x1B000, 0x1B122],
+ [0x1B132, 0x1B132],
+ [0x1B150, 0x1B152],
+ [0x1B155, 0x1B155],
+ [0x1B164, 0x1B167],
+ [0x1B170, 0x1B2FB],
+ [0x1BC00, 0x1BC6A],
+ [0x1BC70, 0x1BC7C],
+ [0x1BC80, 0x1BC88],
+ [0x1BC90, 0x1BC99],
+ [0x1D400, 0x1D454],
+ [0x1D456, 0x1D49C],
+ [0x1D49E, 0x1D49F],
+ [0x1D4A2, 0x1D4A2],
+ [0x1D4A5, 0x1D4A6],
+ [0x1D4A9, 0x1D4AC],
+ [0x1D4AE, 0x1D4B9],
+ [0x1D4BB, 0x1D4BB],
+ [0x1D4BD, 0x1D4C3],
+ [0x1D4C5, 0x1D505],
+ [0x1D507, 0x1D50A],
+ [0x1D50D, 0x1D514],
+ [0x1D516, 0x1D51C],
+ [0x1D51E, 0x1D539],
+ [0x1D53B, 0x1D53E],
+ [0x1D540, 0x1D544],
+ [0x1D546, 0x1D546],
+ [0x1D54A, 0x1D550],
+ [0x1D552, 0x1D6A5],
+ [0x1D6A8, 0x1D6C0],
+ [0x1D6C2, 0x1D6DA],
+ [0x1D6DC, 0x1D6FA],
+ [0x1D6FC, 0x1D714],
+ [0x1D716, 0x1D734],
+ [0x1D736, 0x1D74E],
+ [0x1D750, 0x1D76E],
+ [0x1D770, 0x1D788],
+ [0x1D78A, 0x1D7A8],
+ [0x1D7AA, 0x1D7C2],
+ [0x1D7C4, 0x1D7CB],
+ [0x1DF00, 0x1DF1E],
+ [0x1DF25, 0x1DF2A],
+ [0x1E030, 0x1E06D],
+ [0x1E100, 0x1E12C],
+ [0x1E137, 0x1E13D],
+ [0x1E14E, 0x1E14E],
+ [0x1E290, 0x1E2AD],
+ [0x1E2C0, 0x1E2EB],
+ [0x1E4D0, 0x1E4EB],
+ [0x1E7E0, 0x1E7E6],
+ [0x1E7E8, 0x1E7EB],
+ [0x1E7ED, 0x1E7EE],
+ [0x1E7F0, 0x1E7FE],
+ [0x1E800, 0x1E8C4],
+ [0x1E900, 0x1E943],
+ [0x1E94B, 0x1E94B],
+ [0x1EE00, 0x1EE03],
+ [0x1EE05, 0x1EE1F],
+ [0x1EE21, 0x1EE22],
+ [0x1EE24, 0x1EE24],
+ [0x1EE27, 0x1EE27],
+ [0x1EE29, 0x1EE32],
+ [0x1EE34, 0x1EE37],
+ [0x1EE39, 0x1EE39],
+ [0x1EE3B, 0x1EE3B],
+ [0x1EE42, 0x1EE42],
+ [0x1EE47, 0x1EE47],
+ [0x1EE49, 0x1EE49],
+ [0x1EE4B, 0x1EE4B],
+ [0x1EE4D, 0x1EE4F],
+ [0x1EE51, 0x1EE52],
+ [0x1EE54, 0x1EE54],
+ [0x1EE57, 0x1EE57],
+ [0x1EE59, 0x1EE59],
+ [0x1EE5B, 0x1EE5B],
+ [0x1EE5D, 0x1EE5D],
+ [0x1EE5F, 0x1EE5F],
+ [0x1EE61, 0x1EE62],
+ [0x1EE64, 0x1EE64],
+ [0x1EE67, 0x1EE6A],
+ [0x1EE6C, 0x1EE72],
+ [0x1EE74, 0x1EE77],
+ [0x1EE79, 0x1EE7C],
+ [0x1EE7E, 0x1EE7E],
+ [0x1EE80, 0x1EE89],
+ [0x1EE8B, 0x1EE9B],
+ [0x1EEA1, 0x1EEA3],
+ [0x1EEA5, 0x1EEA9],
+ [0x1EEAB, 0x1EEBB],
+ [0x20000, 0x2A6DF],
+ [0x2A700, 0x2B739],
+ [0x2B740, 0x2B81D],
+ [0x2B820, 0x2CEA1],
+ [0x2CEB0, 0x2EBE0],
+ [0x2EBF0, 0x2EE5D],
+ [0x2F800, 0x2FA1D],
+ [0x30000, 0x3134A],
+ [0x31350, 0x323AF],
+];
+
+/**
+UAX31 profile Continue
+Entries: 140026
+*/
+static immutable dchar[2][] UAX31_Continue = [
+ [0xAA, 0xAA],
+ [0xB5, 0xB5],
+ [0xB7, 0xB7],
+ [0xBA, 0xBA],
+ [0xC0, 0xD6],
+ [0xD8, 0xF6],
+ [0xF8, 0x2C1],
+ [0x2C6, 0x2D1],
+ [0x2E0, 0x2E4],
+ [0x2EC, 0x2EC],
+ [0x2EE, 0x2EE],
+ [0x300, 0x374],
+ [0x376, 0x377],
+ [0x37B, 0x37D],
+ [0x37F, 0x37F],
+ [0x386, 0x38A],
+ [0x38C, 0x38C],
+ [0x38E, 0x3A1],
+ [0x3A3, 0x3F5],
+ [0x3F7, 0x481],
+ [0x483, 0x487],
+ [0x48A, 0x52F],
+ [0x531, 0x556],
+ [0x559, 0x559],
+ [0x560, 0x588],
+ [0x591, 0x5BD],
+ [0x5BF, 0x5BF],
+ [0x5C1, 0x5C2],
+ [0x5C4, 0x5C5],
+ [0x5C7, 0x5C7],
+ [0x5D0, 0x5EA],
+ [0x5EF, 0x5F2],
+ [0x610, 0x61A],
+ [0x620, 0x669],
+ [0x66E, 0x6D3],
+ [0x6D5, 0x6DC],
+ [0x6DF, 0x6E8],
+ [0x6EA, 0x6FC],
+ [0x6FF, 0x6FF],
+ [0x710, 0x74A],
+ [0x74D, 0x7B1],
+ [0x7C0, 0x7F5],
+ [0x7FA, 0x7FA],
+ [0x7FD, 0x7FD],
+ [0x800, 0x82D],
+ [0x840, 0x85B],
+ [0x860, 0x86A],
+ [0x870, 0x887],
+ [0x889, 0x88E],
+ [0x898, 0x8E1],
+ [0x8E3, 0x963],
+ [0x966, 0x96F],
+ [0x971, 0x983],
+ [0x985, 0x98C],
+ [0x98F, 0x990],
+ [0x993, 0x9A8],
+ [0x9AA, 0x9B0],
+ [0x9B2, 0x9B2],
+ [0x9B6, 0x9B9],
+ [0x9BC, 0x9C4],
+ [0x9C7, 0x9C8],
+ [0x9CB, 0x9CE],
+ [0x9D7, 0x9D7],
+ [0x9DC, 0x9DD],
+ [0x9DF, 0x9E3],
+ [0x9E6, 0x9F1],
+ [0x9FC, 0x9FC],
+ [0x9FE, 0x9FE],
+ [0xA01, 0xA03],
+ [0xA05, 0xA0A],
+ [0xA0F, 0xA10],
+ [0xA13, 0xA28],
+ [0xA2A, 0xA30],
+ [0xA32, 0xA33],
+ [0xA35, 0xA36],
+ [0xA38, 0xA39],
+ [0xA3C, 0xA3C],
+ [0xA3E, 0xA42],
+ [0xA47, 0xA48],
+ [0xA4B, 0xA4D],
+ [0xA51, 0xA51],
+ [0xA59, 0xA5C],
+ [0xA5E, 0xA5E],
+ [0xA66, 0xA75],
+ [0xA81, 0xA83],
+ [0xA85, 0xA8D],
+ [0xA8F, 0xA91],
+ [0xA93, 0xAA8],
+ [0xAAA, 0xAB0],
+ [0xAB2, 0xAB3],
+ [0xAB5, 0xAB9],
+ [0xABC, 0xAC5],
+ [0xAC7, 0xAC9],
+ [0xACB, 0xACD],
+ [0xAD0, 0xAD0],
+ [0xAE0, 0xAE3],
+ [0xAE6, 0xAEF],
+ [0xAF9, 0xAFF],
+ [0xB01, 0xB03],
+ [0xB05, 0xB0C],
+ [0xB0F, 0xB10],
+ [0xB13, 0xB28],
+ [0xB2A, 0xB30],
+ [0xB32, 0xB33],
+ [0xB35, 0xB39],
+ [0xB3C, 0xB44],
+ [0xB47, 0xB48],
+ [0xB4B, 0xB4D],
+ [0xB55, 0xB57],
+ [0xB5C, 0xB5D],
+ [0xB5F, 0xB63],
+ [0xB66, 0xB6F],
+ [0xB71, 0xB71],
+ [0xB82, 0xB83],
+ [0xB85, 0xB8A],
+ [0xB8E, 0xB90],
+ [0xB92, 0xB95],
+ [0xB99, 0xB9A],
+ [0xB9C, 0xB9C],
+ [0xB9E, 0xB9F],
+ [0xBA3, 0xBA4],
+ [0xBA8, 0xBAA],
+ [0xBAE, 0xBB9],
+ [0xBBE, 0xBC2],
+ [0xBC6, 0xBC8],
+ [0xBCA, 0xBCD],
+ [0xBD0, 0xBD0],
+ [0xBD7, 0xBD7],
+ [0xBE6, 0xBEF],
+ [0xC00, 0xC0C],
+ [0xC0E, 0xC10],
+ [0xC12, 0xC28],
+ [0xC2A, 0xC39],
+ [0xC3C, 0xC44],
+ [0xC46, 0xC48],
+ [0xC4A, 0xC4D],
+ [0xC55, 0xC56],
+ [0xC58, 0xC5A],
+ [0xC5D, 0xC5D],
+ [0xC60, 0xC63],
+ [0xC66, 0xC6F],
+ [0xC80, 0xC83],
+ [0xC85, 0xC8C],
+ [0xC8E, 0xC90],
+ [0xC92, 0xCA8],
+ [0xCAA, 0xCB3],
+ [0xCB5, 0xCB9],
+ [0xCBC, 0xCC4],
+ [0xCC6, 0xCC8],
+ [0xCCA, 0xCCD],
+ [0xCD5, 0xCD6],
+ [0xCDD, 0xCDE],
+ [0xCE0, 0xCE3],
+ [0xCE6, 0xCEF],
+ [0xCF1, 0xCF3],
+ [0xD00, 0xD0C],
+ [0xD0E, 0xD10],
+ [0xD12, 0xD44],
+ [0xD46, 0xD48],
+ [0xD4A, 0xD4E],
+ [0xD54, 0xD57],
+ [0xD5F, 0xD63],
+ [0xD66, 0xD6F],
+ [0xD7A, 0xD7F],
+ [0xD81, 0xD83],
+ [0xD85, 0xD96],
+ [0xD9A, 0xDB1],
+ [0xDB3, 0xDBB],
+ [0xDBD, 0xDBD],
+ [0xDC0, 0xDC6],
+ [0xDCA, 0xDCA],
+ [0xDCF, 0xDD4],
+ [0xDD6, 0xDD6],
+ [0xDD8, 0xDDF],
+ [0xDE6, 0xDEF],
+ [0xDF2, 0xDF3],
+ [0xE01, 0xE3A],
+ [0xE40, 0xE4E],
+ [0xE50, 0xE59],
+ [0xE81, 0xE82],
+ [0xE84, 0xE84],
+ [0xE86, 0xE8A],
+ [0xE8C, 0xEA3],
+ [0xEA5, 0xEA5],
+ [0xEA7, 0xEBD],
+ [0xEC0, 0xEC4],
+ [0xEC6, 0xEC6],
+ [0xEC8, 0xECE],
+ [0xED0, 0xED9],
+ [0xEDC, 0xEDF],
+ [0xF00, 0xF00],
+ [0xF18, 0xF19],
+ [0xF20, 0xF29],
+ [0xF35, 0xF35],
+ [0xF37, 0xF37],
+ [0xF39, 0xF39],
+ [0xF3E, 0xF47],
+ [0xF49, 0xF6C],
+ [0xF71, 0xF84],
+ [0xF86, 0xF97],
+ [0xF99, 0xFBC],
+ [0xFC6, 0xFC6],
+ [0x1000, 0x1049],
+ [0x1050, 0x109D],
+ [0x10A0, 0x10C5],
+ [0x10C7, 0x10C7],
+ [0x10CD, 0x10CD],
+ [0x10D0, 0x10FA],
+ [0x10FC, 0x1248],
+ [0x124A, 0x124D],
+ [0x1250, 0x1256],
+ [0x1258, 0x1258],
+ [0x125A, 0x125D],
+ [0x1260, 0x1288],
+ [0x128A, 0x128D],
+ [0x1290, 0x12B0],
+ [0x12B2, 0x12B5],
+ [0x12B8, 0x12BE],
+ [0x12C0, 0x12C0],
+ [0x12C2, 0x12C5],
+ [0x12C8, 0x12D6],
+ [0x12D8, 0x1310],
+ [0x1312, 0x1315],
+ [0x1318, 0x135A],
+ [0x135D, 0x135F],
+ [0x1369, 0x1371],
+ [0x1380, 0x138F],
+ [0x13A0, 0x13F5],
+ [0x13F8, 0x13FD],
+ [0x1401, 0x166C],
+ [0x166F, 0x167F],
+ [0x1681, 0x169A],
+ [0x16A0, 0x16EA],
+ [0x16EE, 0x16F8],
+ [0x1700, 0x1715],
+ [0x171F, 0x1734],
+ [0x1740, 0x1753],
+ [0x1760, 0x176C],
+ [0x176E, 0x1770],
+ [0x1772, 0x1773],
+ [0x1780, 0x17D3],
+ [0x17D7, 0x17D7],
+ [0x17DC, 0x17DD],
+ [0x17E0, 0x17E9],
+ [0x180B, 0x180D],
+ [0x180F, 0x1819],
+ [0x1820, 0x1878],
+ [0x1880, 0x18AA],
+ [0x18B0, 0x18F5],
+ [0x1900, 0x191E],
+ [0x1920, 0x192B],
+ [0x1930, 0x193B],
+ [0x1946, 0x196D],
+ [0x1970, 0x1974],
+ [0x1980, 0x19AB],
+ [0x19B0, 0x19C9],
+ [0x19D0, 0x19DA],
+ [0x1A00, 0x1A1B],
+ [0x1A20, 0x1A5E],
+ [0x1A60, 0x1A7C],
+ [0x1A7F, 0x1A89],
+ [0x1A90, 0x1A99],
+ [0x1AA7, 0x1AA7],
+ [0x1AB0, 0x1ABD],
+ [0x1ABF, 0x1ACE],
+ [0x1B00, 0x1B4C],
+ [0x1B50, 0x1B59],
+ [0x1B6B, 0x1B73],
+ [0x1B80, 0x1BF3],
+ [0x1C00, 0x1C37],
+ [0x1C40, 0x1C49],
+ [0x1C4D, 0x1C7D],
+ [0x1C80, 0x1C88],
+ [0x1C90, 0x1CBA],
+ [0x1CBD, 0x1CBF],
+ [0x1CD0, 0x1CD2],
+ [0x1CD4, 0x1CFA],
+ [0x1D00, 0x1F15],
+ [0x1F18, 0x1F1D],
+ [0x1F20, 0x1F45],
+ [0x1F48, 0x1F4D],
+ [0x1F50, 0x1F57],
+ [0x1F59, 0x1F59],
+ [0x1F5B, 0x1F5B],
+ [0x1F5D, 0x1F5D],
+ [0x1F5F, 0x1F7D],
+ [0x1F80, 0x1FB4],
+ [0x1FB6, 0x1FBC],
+ [0x1FBE, 0x1FBE],
+ [0x1FC2, 0x1FC4],
+ [0x1FC6, 0x1FCC],
+ [0x1FD0, 0x1FD3],
+ [0x1FD6, 0x1FDB],
+ [0x1FE0, 0x1FEC],
+ [0x1FF2, 0x1FF4],
+ [0x1FF6, 0x1FFC],
+ [0x200C, 0x200D],
+ [0x203F, 0x2040],
+ [0x2054, 0x2054],
+ [0x2071, 0x2071],
+ [0x207F, 0x207F],
+ [0x2090, 0x209C],
+ [0x20D0, 0x20DC],
+ [0x20E1, 0x20E1],
+ [0x20E5, 0x20F0],
+ [0x2102, 0x2102],
+ [0x2107, 0x2107],
+ [0x210A, 0x2113],
+ [0x2115, 0x2115],
+ [0x2118, 0x211D],
+ [0x2124, 0x2124],
+ [0x2126, 0x2126],
+ [0x2128, 0x2128],
+ [0x212A, 0x2139],
+ [0x213C, 0x213F],
+ [0x2145, 0x2149],
+ [0x214E, 0x214E],
+ [0x2160, 0x2188],
+ [0x2C00, 0x2CE4],
+ [0x2CEB, 0x2CF3],
+ [0x2D00, 0x2D25],
+ [0x2D27, 0x2D27],
+ [0x2D2D, 0x2D2D],
+ [0x2D30, 0x2D67],
+ [0x2D6F, 0x2D6F],
+ [0x2D7F, 0x2D96],
+ [0x2DA0, 0x2DA6],
+ [0x2DA8, 0x2DAE],
+ [0x2DB0, 0x2DB6],
+ [0x2DB8, 0x2DBE],
+ [0x2DC0, 0x2DC6],
+ [0x2DC8, 0x2DCE],
+ [0x2DD0, 0x2DD6],
+ [0x2DD8, 0x2DDE],
+ [0x2DE0, 0x2DFF],
+ [0x3005, 0x3007],
+ [0x3021, 0x302F],
+ [0x3031, 0x3035],
+ [0x3038, 0x303C],
+ [0x3041, 0x3096],
+ [0x3099, 0x309A],
+ [0x309D, 0x309F],
+ [0x30A1, 0x30FF],
+ [0x3105, 0x312F],
+ [0x3131, 0x318E],
+ [0x31A0, 0x31BF],
+ [0x31F0, 0x31FF],
+ [0x3400, 0x4DBF],
+ [0x4E00, 0xA48C],
+ [0xA4D0, 0xA4FD],
+ [0xA500, 0xA60C],
+ [0xA610, 0xA62B],
+ [0xA640, 0xA66F],
+ [0xA674, 0xA67D],
+ [0xA67F, 0xA6F1],
+ [0xA717, 0xA71F],
+ [0xA722, 0xA788],
+ [0xA78B, 0xA7CA],
+ [0xA7D0, 0xA7D1],
+ [0xA7D3, 0xA7D3],
+ [0xA7D5, 0xA7D9],
+ [0xA7F2, 0xA827],
+ [0xA82C, 0xA82C],
+ [0xA840, 0xA873],
+ [0xA880, 0xA8C5],
+ [0xA8D0, 0xA8D9],
+ [0xA8E0, 0xA8F7],
+ [0xA8FB, 0xA8FB],
+ [0xA8FD, 0xA92D],
+ [0xA930, 0xA953],
+ [0xA960, 0xA97C],
+ [0xA980, 0xA9C0],
+ [0xA9CF, 0xA9D9],
+ [0xA9E0, 0xA9FE],
+ [0xAA00, 0xAA36],
+ [0xAA40, 0xAA4D],
+ [0xAA50, 0xAA59],
+ [0xAA60, 0xAA76],
+ [0xAA7A, 0xAAC2],
+ [0xAADB, 0xAADD],
+ [0xAAE0, 0xAAEF],
+ [0xAAF2, 0xAAF6],
+ [0xAB01, 0xAB06],
+ [0xAB09, 0xAB0E],
+ [0xAB11, 0xAB16],
+ [0xAB20, 0xAB26],
+ [0xAB28, 0xAB2E],
+ [0xAB30, 0xAB5A],
+ [0xAB5C, 0xAB69],
+ [0xAB70, 0xABEA],
+ [0xABEC, 0xABED],
+ [0xABF0, 0xABF9],
+ [0xAC00, 0xD7A3],
+ [0xD7B0, 0xD7C6],
+ [0xD7CB, 0xD7FB],
+ [0xF900, 0xFA6D],
+ [0xFA70, 0xFAD9],
+ [0xFB00, 0xFB06],
+ [0xFB13, 0xFB17],
+ [0xFB1D, 0xFB28],
+ [0xFB2A, 0xFB36],
+ [0xFB38, 0xFB3C],
+ [0xFB3E, 0xFB3E],
+ [0xFB40, 0xFB41],
+ [0xFB43, 0xFB44],
+ [0xFB46, 0xFBB1],
+ [0xFBD3, 0xFC5D],
+ [0xFC64, 0xFD3D],
+ [0xFD50, 0xFD8F],
+ [0xFD92, 0xFDC7],
+ [0xFDF0, 0xFDF9],
+ [0xFE00, 0xFE0F],
+ [0xFE20, 0xFE2F],
+ [0xFE33, 0xFE34],
+ [0xFE4D, 0xFE4F],
+ [0xFE71, 0xFE71],
+ [0xFE73, 0xFE73],
+ [0xFE77, 0xFE77],
+ [0xFE79, 0xFE79],
+ [0xFE7B, 0xFE7B],
+ [0xFE7D, 0xFE7D],
+ [0xFE7F, 0xFEFC],
+ [0xFF10, 0xFF19],
+ [0xFF21, 0xFF3A],
+ [0xFF3F, 0xFF3F],
+ [0xFF41, 0xFF5A],
+ [0xFF65, 0xFFBE],
+ [0xFFC2, 0xFFC7],
+ [0xFFCA, 0xFFCF],
+ [0xFFD2, 0xFFD7],
+ [0xFFDA, 0xFFDC],
+ [0x10000, 0x1000B],
+ [0x1000D, 0x10026],
+ [0x10028, 0x1003A],
+ [0x1003C, 0x1003D],
+ [0x1003F, 0x1004D],
+ [0x10050, 0x1005D],
+ [0x10080, 0x100FA],
+ [0x10140, 0x10174],
+ [0x101FD, 0x101FD],
+ [0x10280, 0x1029C],
+ [0x102A0, 0x102D0],
+ [0x102E0, 0x102E0],
+ [0x10300, 0x1031F],
+ [0x1032D, 0x1034A],
+ [0x10350, 0x1037A],
+ [0x10380, 0x1039D],
+ [0x103A0, 0x103C3],
+ [0x103C8, 0x103CF],
+ [0x103D1, 0x103D5],
+ [0x10400, 0x1049D],
+ [0x104A0, 0x104A9],
+ [0x104B0, 0x104D3],
+ [0x104D8, 0x104FB],
+ [0x10500, 0x10527],
+ [0x10530, 0x10563],
+ [0x10570, 0x1057A],
+ [0x1057C, 0x1058A],
+ [0x1058C, 0x10592],
+ [0x10594, 0x10595],
+ [0x10597, 0x105A1],
+ [0x105A3, 0x105B1],
+ [0x105B3, 0x105B9],
+ [0x105BB, 0x105BC],
+ [0x10600, 0x10736],
+ [0x10740, 0x10755],
+ [0x10760, 0x10767],
+ [0x10780, 0x10785],
+ [0x10787, 0x107B0],
+ [0x107B2, 0x107BA],
+ [0x10800, 0x10805],
+ [0x10808, 0x10808],
+ [0x1080A, 0x10835],
+ [0x10837, 0x10838],
+ [0x1083C, 0x1083C],
+ [0x1083F, 0x10855],
+ [0x10860, 0x10876],
+ [0x10880, 0x1089E],
+ [0x108E0, 0x108F2],
+ [0x108F4, 0x108F5],
+ [0x10900, 0x10915],
+ [0x10920, 0x10939],
+ [0x10980, 0x109B7],
+ [0x109BE, 0x109BF],
+ [0x10A00, 0x10A03],
+ [0x10A05, 0x10A06],
+ [0x10A0C, 0x10A13],
+ [0x10A15, 0x10A17],
+ [0x10A19, 0x10A35],
+ [0x10A38, 0x10A3A],
+ [0x10A3F, 0x10A3F],
+ [0x10A60, 0x10A7C],
+ [0x10A80, 0x10A9C],
+ [0x10AC0, 0x10AC7],
+ [0x10AC9, 0x10AE6],
+ [0x10B00, 0x10B35],
+ [0x10B40, 0x10B55],
+ [0x10B60, 0x10B72],
+ [0x10B80, 0x10B91],
+ [0x10C00, 0x10C48],
+ [0x10C80, 0x10CB2],
+ [0x10CC0, 0x10CF2],
+ [0x10D00, 0x10D27],
+ [0x10D30, 0x10D39],
+ [0x10E80, 0x10EA9],
+ [0x10EAB, 0x10EAC],
+ [0x10EB0, 0x10EB1],
+ [0x10EFD, 0x10F1C],
+ [0x10F27, 0x10F27],
+ [0x10F30, 0x10F50],
+ [0x10F70, 0x10F85],
+ [0x10FB0, 0x10FC4],
+ [0x10FE0, 0x10FF6],
+ [0x11000, 0x11046],
+ [0x11066, 0x11075],
+ [0x1107F, 0x110BA],
+ [0x110C2, 0x110C2],
+ [0x110D0, 0x110E8],
+ [0x110F0, 0x110F9],
+ [0x11100, 0x11134],
+ [0x11136, 0x1113F],
+ [0x11144, 0x11147],
+ [0x11150, 0x11173],
+ [0x11176, 0x11176],
+ [0x11180, 0x111C4],
+ [0x111C9, 0x111CC],
+ [0x111CE, 0x111DA],
+ [0x111DC, 0x111DC],
+ [0x11200, 0x11211],
+ [0x11213, 0x11237],
+ [0x1123E, 0x11241],
+ [0x11280, 0x11286],
+ [0x11288, 0x11288],
+ [0x1128A, 0x1128D],
+ [0x1128F, 0x1129D],
+ [0x1129F, 0x112A8],
+ [0x112B0, 0x112EA],
+ [0x112F0, 0x112F9],
+ [0x11300, 0x11303],
+ [0x11305, 0x1130C],
+ [0x1130F, 0x11310],
+ [0x11313, 0x11328],
+ [0x1132A, 0x11330],
+ [0x11332, 0x11333],
+ [0x11335, 0x11339],
+ [0x1133B, 0x11344],
+ [0x11347, 0x11348],
+ [0x1134B, 0x1134D],
+ [0x11350, 0x11350],
+ [0x11357, 0x11357],
+ [0x1135D, 0x11363],
+ [0x11366, 0x1136C],
+ [0x11370, 0x11374],
+ [0x11400, 0x1144A],
+ [0x11450, 0x11459],
+ [0x1145E, 0x11461],
+ [0x11480, 0x114C5],
+ [0x114C7, 0x114C7],
+ [0x114D0, 0x114D9],
+ [0x11580, 0x115B5],
+ [0x115B8, 0x115C0],
+ [0x115D8, 0x115DD],
+ [0x11600, 0x11640],
+ [0x11644, 0x11644],
+ [0x11650, 0x11659],
+ [0x11680, 0x116B8],
+ [0x116C0, 0x116C9],
+ [0x11700, 0x1171A],
+ [0x1171D, 0x1172B],
+ [0x11730, 0x11739],
+ [0x11740, 0x11746],
+ [0x11800, 0x1183A],
+ [0x118A0, 0x118E9],
+ [0x118FF, 0x11906],
+ [0x11909, 0x11909],
+ [0x1190C, 0x11913],
+ [0x11915, 0x11916],
+ [0x11918, 0x11935],
+ [0x11937, 0x11938],
+ [0x1193B, 0x11943],
+ [0x11950, 0x11959],
+ [0x119A0, 0x119A7],
+ [0x119AA, 0x119D7],
+ [0x119DA, 0x119E1],
+ [0x119E3, 0x119E4],
+ [0x11A00, 0x11A3E],
+ [0x11A47, 0x11A47],
+ [0x11A50, 0x11A99],
+ [0x11A9D, 0x11A9D],
+ [0x11AB0, 0x11AF8],
+ [0x11C00, 0x11C08],
+ [0x11C0A, 0x11C36],
+ [0x11C38, 0x11C40],
+ [0x11C50, 0x11C59],
+ [0x11C72, 0x11C8F],
+ [0x11C92, 0x11CA7],
+ [0x11CA9, 0x11CB6],
+ [0x11D00, 0x11D06],
+ [0x11D08, 0x11D09],
+ [0x11D0B, 0x11D36],
+ [0x11D3A, 0x11D3A],
+ [0x11D3C, 0x11D3D],
+ [0x11D3F, 0x11D47],
+ [0x11D50, 0x11D59],
+ [0x11D60, 0x11D65],
+ [0x11D67, 0x11D68],
+ [0x11D6A, 0x11D8E],
+ [0x11D90, 0x11D91],
+ [0x11D93, 0x11D98],
+ [0x11DA0, 0x11DA9],
+ [0x11EE0, 0x11EF6],
+ [0x11F00, 0x11F10],
+ [0x11F12, 0x11F3A],
+ [0x11F3E, 0x11F42],
+ [0x11F50, 0x11F59],
+ [0x11FB0, 0x11FB0],
+ [0x12000, 0x12399],
+ [0x12400, 0x1246E],
+ [0x12480, 0x12543],
+ [0x12F90, 0x12FF0],
+ [0x13000, 0x1342F],
+ [0x13440, 0x13455],
+ [0x14400, 0x14646],
+ [0x16800, 0x16A38],
+ [0x16A40, 0x16A5E],
+ [0x16A60, 0x16A69],
+ [0x16A70, 0x16ABE],
+ [0x16AC0, 0x16AC9],
+ [0x16AD0, 0x16AED],
+ [0x16AF0, 0x16AF4],
+ [0x16B00, 0x16B36],
+ [0x16B40, 0x16B43],
+ [0x16B50, 0x16B59],
+ [0x16B63, 0x16B77],
+ [0x16B7D, 0x16B8F],
+ [0x16E40, 0x16E7F],
+ [0x16F00, 0x16F4A],
+ [0x16F4F, 0x16F87],
+ [0x16F8F, 0x16F9F],
+ [0x16FE0, 0x16FE1],
+ [0x16FE3, 0x16FE4],
+ [0x16FF0, 0x16FF1],
+ [0x17000, 0x187F7],
+ [0x18800, 0x18CD5],
+ [0x18D00, 0x18D08],
+ [0x1AFF0, 0x1AFF3],
+ [0x1AFF5, 0x1AFFB],
+ [0x1AFFD, 0x1AFFE],
+ [0x1B000, 0x1B122],
+ [0x1B132, 0x1B132],
+ [0x1B150, 0x1B152],
+ [0x1B155, 0x1B155],
+ [0x1B164, 0x1B167],
+ [0x1B170, 0x1B2FB],
+ [0x1BC00, 0x1BC6A],
+ [0x1BC70, 0x1BC7C],
+ [0x1BC80, 0x1BC88],
+ [0x1BC90, 0x1BC99],
+ [0x1BC9D, 0x1BC9E],
+ [0x1CF00, 0x1CF2D],
+ [0x1CF30, 0x1CF46],
+ [0x1D165, 0x1D169],
+ [0x1D16D, 0x1D172],
+ [0x1D17B, 0x1D182],
+ [0x1D185, 0x1D18B],
+ [0x1D1AA, 0x1D1AD],
+ [0x1D242, 0x1D244],
+ [0x1D400, 0x1D454],
+ [0x1D456, 0x1D49C],
+ [0x1D49E, 0x1D49F],
+ [0x1D4A2, 0x1D4A2],
+ [0x1D4A5, 0x1D4A6],
+ [0x1D4A9, 0x1D4AC],
+ [0x1D4AE, 0x1D4B9],
+ [0x1D4BB, 0x1D4BB],
+ [0x1D4BD, 0x1D4C3],
+ [0x1D4C5, 0x1D505],
+ [0x1D507, 0x1D50A],
+ [0x1D50D, 0x1D514],
+ [0x1D516, 0x1D51C],
+ [0x1D51E, 0x1D539],
+ [0x1D53B, 0x1D53E],
+ [0x1D540, 0x1D544],
+ [0x1D546, 0x1D546],
+ [0x1D54A, 0x1D550],
+ [0x1D552, 0x1D6A5],
+ [0x1D6A8, 0x1D6C0],
+ [0x1D6C2, 0x1D6DA],
+ [0x1D6DC, 0x1D6FA],
+ [0x1D6FC, 0x1D714],
+ [0x1D716, 0x1D734],
+ [0x1D736, 0x1D74E],
+ [0x1D750, 0x1D76E],
+ [0x1D770, 0x1D788],
+ [0x1D78A, 0x1D7A8],
+ [0x1D7AA, 0x1D7C2],
+ [0x1D7C4, 0x1D7CB],
+ [0x1D7CE, 0x1D7FF],
+ [0x1DA00, 0x1DA36],
+ [0x1DA3B, 0x1DA6C],
+ [0x1DA75, 0x1DA75],
+ [0x1DA84, 0x1DA84],
+ [0x1DA9B, 0x1DA9F],
+ [0x1DAA1, 0x1DAAF],
+ [0x1DF00, 0x1DF1E],
+ [0x1DF25, 0x1DF2A],
+ [0x1E000, 0x1E006],
+ [0x1E008, 0x1E018],
+ [0x1E01B, 0x1E021],
+ [0x1E023, 0x1E024],
+ [0x1E026, 0x1E02A],
+ [0x1E030, 0x1E06D],
+ [0x1E08F, 0x1E08F],
+ [0x1E100, 0x1E12C],
+ [0x1E130, 0x1E13D],
+ [0x1E140, 0x1E149],
+ [0x1E14E, 0x1E14E],
+ [0x1E290, 0x1E2AE],
+ [0x1E2C0, 0x1E2F9],
+ [0x1E4D0, 0x1E4F9],
+ [0x1E7E0, 0x1E7E6],
+ [0x1E7E8, 0x1E7EB],
+ [0x1E7ED, 0x1E7EE],
+ [0x1E7F0, 0x1E7FE],
+ [0x1E800, 0x1E8C4],
+ [0x1E8D0, 0x1E8D6],
+ [0x1E900, 0x1E94B],
+ [0x1E950, 0x1E959],
+ [0x1EE00, 0x1EE03],
+ [0x1EE05, 0x1EE1F],
+ [0x1EE21, 0x1EE22],
+ [0x1EE24, 0x1EE24],
+ [0x1EE27, 0x1EE27],
+ [0x1EE29, 0x1EE32],
+ [0x1EE34, 0x1EE37],
+ [0x1EE39, 0x1EE39],
+ [0x1EE3B, 0x1EE3B],
+ [0x1EE42, 0x1EE42],
+ [0x1EE47, 0x1EE47],
+ [0x1EE49, 0x1EE49],
+ [0x1EE4B, 0x1EE4B],
+ [0x1EE4D, 0x1EE4F],
+ [0x1EE51, 0x1EE52],
+ [0x1EE54, 0x1EE54],
+ [0x1EE57, 0x1EE57],
+ [0x1EE59, 0x1EE59],
+ [0x1EE5B, 0x1EE5B],
+ [0x1EE5D, 0x1EE5D],
+ [0x1EE5F, 0x1EE5F],
+ [0x1EE61, 0x1EE62],
+ [0x1EE64, 0x1EE64],
+ [0x1EE67, 0x1EE6A],
+ [0x1EE6C, 0x1EE72],
+ [0x1EE74, 0x1EE77],
+ [0x1EE79, 0x1EE7C],
+ [0x1EE7E, 0x1EE7E],
+ [0x1EE80, 0x1EE89],
+ [0x1EE8B, 0x1EE9B],
+ [0x1EEA1, 0x1EEA3],
+ [0x1EEA5, 0x1EEA9],
+ [0x1EEAB, 0x1EEBB],
+ [0x1FBF0, 0x1FBF9],
+ [0x20000, 0x2A6DF],
+ [0x2A700, 0x2B739],
+ [0x2B740, 0x2B81D],
+ [0x2B820, 0x2CEA1],
+ [0x2CEB0, 0x2EBE0],
+ [0x2EBF0, 0x2EE5D],
+ [0x2F800, 0x2FA1D],
+ [0x30000, 0x3134A],
+ [0x31350, 0x323AF],
+ [0xE0100, 0xE01EF],
+];
+
+/**
+C99 Start
+Entries: 34958
+*/
+alias FixedTable_C99_Start = FixedTable_C99_Continue;
+
+/**
+C99 Continue
+Entries: 34958
+*/
+static immutable dchar[2][] FixedTable_C99_Continue = [
+ [0xAA, 0xAA],
+ [0xB5, 0xB5],
+ [0xB7, 0xB7],
+ [0xBA, 0xBA],
+ [0xC0, 0xD6],
+ [0xD8, 0xF6],
+ [0xF8, 0x1F5],
+ [0x1FA, 0x217],
+ [0x250, 0x2A8],
+ [0x2B0, 0x2B8],
+ [0x2BB, 0x2BB],
+ [0x2BD, 0x2C1],
+ [0x2D0, 0x2D1],
+ [0x2E0, 0x2E4],
+ [0x37A, 0x37A],
+ [0x386, 0x386],
+ [0x388, 0x38A],
+ [0x38C, 0x38C],
+ [0x38E, 0x3A1],
+ [0x3A3, 0x3CE],
+ [0x3D0, 0x3D6],
+ [0x3DA, 0x3DA],
+ [0x3DC, 0x3DC],
+ [0x3DE, 0x3DE],
+ [0x3E0, 0x3E0],
+ [0x3E2, 0x3F3],
+ [0x401, 0x40C],
+ [0x40E, 0x44F],
+ [0x451, 0x45C],
+ [0x45E, 0x481],
+ [0x490, 0x4C4],
+ [0x4C7, 0x4C8],
+ [0x4CB, 0x4CC],
+ [0x4D0, 0x4EB],
+ [0x4EE, 0x4F5],
+ [0x4F8, 0x4F9],
+ [0x531, 0x556],
+ [0x559, 0x559],
+ [0x561, 0x587],
+ [0x5B0, 0x5B9],
+ [0x5BB, 0x5BD],
+ [0x5BF, 0x5BF],
+ [0x5C1, 0x5C2],
+ [0x5D0, 0x5EA],
+ [0x5F0, 0x5F2],
+ [0x621, 0x63A],
+ [0x640, 0x652],
+ [0x660, 0x669],
+ [0x670, 0x6B7],
+ [0x6BA, 0x6BE],
+ [0x6C0, 0x6CE],
+ [0x6D0, 0x6DC],
+ [0x6E5, 0x6E8],
+ [0x6EA, 0x6ED],
+ [0x6F0, 0x6F9],
+ [0x901, 0x903],
+ [0x905, 0x939],
+ [0x93D, 0x94D],
+ [0x950, 0x952],
+ [0x958, 0x963],
+ [0x966, 0x96F],
+ [0x981, 0x983],
+ [0x985, 0x98C],
+ [0x98F, 0x990],
+ [0x993, 0x9A8],
+ [0x9AA, 0x9B0],
+ [0x9B2, 0x9B2],
+ [0x9B6, 0x9B9],
+ [0x9BE, 0x9C4],
+ [0x9C7, 0x9C8],
+ [0x9CB, 0x9CD],
+ [0x9DC, 0x9DD],
+ [0x9DF, 0x9E3],
+ [0x9E6, 0x9F1],
+ [0xA02, 0xA02],
+ [0xA05, 0xA0A],
+ [0xA0F, 0xA10],
+ [0xA13, 0xA28],
+ [0xA2A, 0xA30],
+ [0xA32, 0xA33],
+ [0xA35, 0xA36],
+ [0xA38, 0xA39],
+ [0xA3E, 0xA42],
+ [0xA47, 0xA48],
+ [0xA4B, 0xA4D],
+ [0xA59, 0xA5C],
+ [0xA5E, 0xA5E],
+ [0xA66, 0xA6F],
+ [0xA74, 0xA74],
+ [0xA81, 0xA83],
+ [0xA85, 0xA8B],
+ [0xA8D, 0xA8D],
+ [0xA8F, 0xA91],
+ [0xA93, 0xAA8],
+ [0xAAA, 0xAB0],
+ [0xAB2, 0xAB3],
+ [0xAB5, 0xAB9],
+ [0xABD, 0xAC5],
+ [0xAC7, 0xAC9],
+ [0xACB, 0xACD],
+ [0xAD0, 0xAD0],
+ [0xAE0, 0xAE0],
+ [0xAE6, 0xAEF],
+ [0xB01, 0xB03],
+ [0xB05, 0xB0C],
+ [0xB0F, 0xB10],
+ [0xB13, 0xB28],
+ [0xB2A, 0xB30],
+ [0xB32, 0xB33],
+ [0xB36, 0xB39],
+ [0xB3D, 0xB43],
+ [0xB47, 0xB48],
+ [0xB4B, 0xB4D],
+ [0xB5C, 0xB5D],
+ [0xB5F, 0xB61],
+ [0xB66, 0xB6F],
+ [0xB82, 0xB83],
+ [0xB85, 0xB8A],
+ [0xB8E, 0xB90],
+ [0xB92, 0xB95],
+ [0xB99, 0xB9A],
+ [0xB9C, 0xB9C],
+ [0xB9E, 0xB9F],
+ [0xBA3, 0xBA4],
+ [0xBA8, 0xBAA],
+ [0xBAE, 0xBB5],
+ [0xBB7, 0xBB9],
+ [0xBBE, 0xBC2],
+ [0xBC6, 0xBC8],
+ [0xBCA, 0xBCD],
+ [0xBE7, 0xBEF],
+ [0xC01, 0xC03],
+ [0xC05, 0xC0C],
+ [0xC0E, 0xC10],
+ [0xC12, 0xC28],
+ [0xC2A, 0xC33],
+ [0xC35, 0xC39],
+ [0xC3E, 0xC44],
+ [0xC46, 0xC48],
+ [0xC4A, 0xC4D],
+ [0xC60, 0xC61],
+ [0xC66, 0xC6F],
+ [0xC82, 0xC83],
+ [0xC85, 0xC8C],
+ [0xC8E, 0xC90],
+ [0xC92, 0xCA8],
+ [0xCAA, 0xCB3],
+ [0xCB5, 0xCB9],
+ [0xCBE, 0xCC4],
+ [0xCC6, 0xCC8],
+ [0xCCA, 0xCCD],
+ [0xCDE, 0xCDE],
+ [0xCE0, 0xCE1],
+ [0xCE6, 0xCEF],
+ [0xD02, 0xD03],
+ [0xD05, 0xD0C],
+ [0xD0E, 0xD10],
+ [0xD12, 0xD28],
+ [0xD2A, 0xD39],
+ [0xD3E, 0xD43],
+ [0xD46, 0xD48],
+ [0xD4A, 0xD4D],
+ [0xD60, 0xD61],
+ [0xD66, 0xD6F],
+ [0xE01, 0xE3A],
+ [0xE40, 0xE5B],
+ [0xE81, 0xE82],
+ [0xE84, 0xE84],
+ [0xE87, 0xE88],
+ [0xE8A, 0xE8A],
+ [0xE8D, 0xE8D],
+ [0xE94, 0xE97],
+ [0xE99, 0xE9F],
+ [0xEA1, 0xEA3],
+ [0xEA5, 0xEA5],
+ [0xEA7, 0xEA7],
+ [0xEAA, 0xEAB],
+ [0xEAD, 0xEAE],
+ [0xEB0, 0xEB9],
+ [0xEBB, 0xEBD],
+ [0xEC0, 0xEC4],
+ [0xEC6, 0xEC6],
+ [0xEC8, 0xECD],
+ [0xED0, 0xED9],
+ [0xEDC, 0xEDD],
+ [0xF00, 0xF00],
+ [0xF18, 0xF19],
+ [0xF20, 0xF33],
+ [0xF35, 0xF35],
+ [0xF37, 0xF37],
+ [0xF39, 0xF39],
+ [0xF3E, 0xF47],
+ [0xF49, 0xF69],
+ [0xF71, 0xF84],
+ [0xF86, 0xF8B],
+ [0xF90, 0xF95],
+ [0xF97, 0xF97],
+ [0xF99, 0xFAD],
+ [0xFB1, 0xFB7],
+ [0xFB9, 0xFB9],
+ [0x10A0, 0x10C5],
+ [0x10D0, 0x10F6],
+ [0x1E00, 0x1E9B],
+ [0x1EA0, 0x1EF9],
+ [0x1F00, 0x1F15],
+ [0x1F18, 0x1F1D],
+ [0x1F20, 0x1F45],
+ [0x1F48, 0x1F4D],
+ [0x1F50, 0x1F57],
+ [0x1F59, 0x1F59],
+ [0x1F5B, 0x1F5B],
+ [0x1F5D, 0x1F5D],
+ [0x1F5F, 0x1F7D],
+ [0x1F80, 0x1FB4],
+ [0x1FB6, 0x1FBC],
+ [0x1FBE, 0x1FBE],
+ [0x1FC2, 0x1FC4],
+ [0x1FC6, 0x1FCC],
+ [0x1FD0, 0x1FD3],
+ [0x1FD6, 0x1FDB],
+ [0x1FE0, 0x1FEC],
+ [0x1FF2, 0x1FF4],
+ [0x1FF6, 0x1FFC],
+ [0x203F, 0x2040],
+ [0x207F, 0x207F],
+ [0x2102, 0x2102],
+ [0x2107, 0x2107],
+ [0x210A, 0x2113],
+ [0x2115, 0x2115],
+ [0x2118, 0x211D],
+ [0x2124, 0x2124],
+ [0x2126, 0x2126],
+ [0x2128, 0x2128],
+ [0x212A, 0x2131],
+ [0x2133, 0x2138],
+ [0x2160, 0x2182],
+ [0x3005, 0x3007],
+ [0x3021, 0x3029],
+ [0x3041, 0x3093],
+ [0x309B, 0x309C],
+ [0x30A1, 0x30F6],
+ [0x30FB, 0x30FC],
+ [0x3105, 0x312C],
+ [0x4E00, 0x9FA5],
+ [0xAC00, 0xD7A3],
+];
+
+/**
+C11 Start
+Entries: 971620
+*/
+alias FixedTable_C11_Start = FixedTable_C11_Continue;
+
+/**
+C11 Continue
+Entries: 971620
+*/
+static immutable dchar[2][] FixedTable_C11_Continue = [
+ [0xA8, 0xA8],
+ [0xAA, 0xAA],
+ [0xAD, 0xAD],
+ [0xAF, 0xAF],
+ [0xB2, 0xB5],
+ [0xB7, 0xBA],
+ [0xBC, 0xBE],
+ [0xC0, 0xD6],
+ [0xD8, 0xF6],
+ [0xF8, 0xFF],
+ [0x100, 0x167F],
+ [0x1681, 0x180D],
+ [0x180F, 0x1FFF],
+ [0x200B, 0x200D],
+ [0x202A, 0x202E],
+ [0x203F, 0x2040],
+ [0x2054, 0x2054],
+ [0x2060, 0x206F],
+ [0x2070, 0x218F],
+ [0x2460, 0x24FF],
+ [0x2776, 0x2793],
+ [0x2C00, 0x2DFF],
+ [0x2E80, 0x2FFF],
+ [0x3004, 0x3007],
+ [0x3021, 0x302F],
+ [0x3031, 0x303F],
+ [0x3040, 0xD7FF],
+ [0xF900, 0xFD3D],
+ [0xFD40, 0xFDCF],
+ [0xFDF0, 0xFE44],
+ [0xFE47, 0xFFFD],
+ [0x10000, 0x1FFFD],
+ [0x20000, 0x2FFFD],
+ [0x30000, 0x3FFFD],
+ [0x40000, 0x4FFFD],
+ [0x50000, 0x5FFFD],
+ [0x60000, 0x6FFFD],
+ [0x70000, 0x7FFFD],
+ [0x80000, 0x8FFFD],
+ [0x90000, 0x9FFFD],
+ [0xA0000, 0xAFFFD],
+ [0xB0000, 0xBFFFD],
+ [0xC0000, 0xCFFFD],
+ [0xD0000, 0xDFFFD],
+ [0xE0000, 0xEFFFD],
+];
+
+/**
+Least restrictive with both Start and Continue
+Entries: 860486
+*/
+static immutable dchar[2][] LeastRestrictive_OfAll = [
+ [0xA8, 0xA8],
+ [0xAA, 0xAA],
+ [0xAD, 0xAD],
+ [0xAF, 0xAF],
+ [0xB2, 0xB5],
+ [0xB7, 0xBA],
+ [0xBC, 0xBE],
+ [0xC0, 0xD6],
+ [0xD8, 0xF6],
+ [0xF8, 0x217],
+ [0x250, 0x2A8],
+ [0x2B0, 0x2B8],
+ [0x2BB, 0x2BB],
+ [0x2BD, 0x2C1],
+ [0x2C6, 0x2D1],
+ [0x2E0, 0x2E4],
+ [0x2EC, 0x2EC],
+ [0x2EE, 0x2EE],
+ [0x300, 0x374],
+ [0x376, 0x377],
+ [0x37A, 0x37D],
+ [0x37F, 0x37F],
+ [0x386, 0x386],
+ [0x388, 0x38A],
+ [0x38C, 0x38C],
+ [0x38E, 0x3A1],
+ [0x3A3, 0x3D6],
+ [0x3DA, 0x3DA],
+ [0x3DC, 0x3DC],
+ [0x3DE, 0x3DE],
+ [0x3E0, 0x3E0],
+ [0x3E2, 0x3F3],
+ [0x3F7, 0x40C],
+ [0x40E, 0x44F],
+ [0x451, 0x45C],
+ [0x45E, 0x481],
+ [0x483, 0x487],
+ [0x48A, 0x4C4],
+ [0x4C7, 0x4C8],
+ [0x4CB, 0x4CC],
+ [0x4D0, 0x4EB],
+ [0x4EE, 0x4F5],
+ [0x4F8, 0x4F9],
+ [0x531, 0x556],
+ [0x559, 0x559],
+ [0x560, 0x587],
+ [0x591, 0x5B9],
+ [0x5BB, 0x5BD],
+ [0x5BF, 0x5BF],
+ [0x5C1, 0x5C2],
+ [0x5C4, 0x5C5],
+ [0x5C7, 0x5C7],
+ [0x5D0, 0x5EA],
+ [0x5EF, 0x5F2],
+ [0x610, 0x61A],
+ [0x620, 0x63A],
+ [0x640, 0x652],
+ [0x660, 0x669],
+ [0x66E, 0x6BE],
+ [0x6C0, 0x6CE],
+ [0x6D0, 0x6D5],
+ [0x6DF, 0x6E8],
+ [0x6EA, 0x6F9],
+ [0x6FF, 0x6FF],
+ [0x710, 0x710],
+ [0x712, 0x72F],
+ [0x74D, 0x7A5],
+ [0x7B1, 0x7B1],
+ [0x7C0, 0x7EA],
+ [0x7F4, 0x7F5],
+ [0x7FA, 0x7FA],
+ [0x7FD, 0x7FD],
+ [0x800, 0x815],
+ [0x81A, 0x81A],
+ [0x824, 0x824],
+ [0x828, 0x828],
+ [0x840, 0x858],
+ [0x860, 0x86A],
+ [0x870, 0x887],
+ [0x889, 0x88E],
+ [0x898, 0x8C9],
+ [0x8E3, 0x939],
+ [0x93D, 0x94D],
+ [0x950, 0x952],
+ [0x958, 0x963],
+ [0x966, 0x96F],
+ [0x971, 0x983],
+ [0x985, 0x98C],
+ [0x98F, 0x990],
+ [0x993, 0x9A8],
+ [0x9AA, 0x9B0],
+ [0x9B2, 0x9B2],
+ [0x9B6, 0x9B9],
+ [0x9BC, 0x9C4],
+ [0x9C7, 0x9C8],
+ [0x9CB, 0x9CE],
+ [0x9D7, 0x9D7],
+ [0x9DC, 0x9DD],
+ [0x9DF, 0x9E3],
+ [0x9E6, 0x9F1],
+ [0x9FC, 0x9FC],
+ [0x9FE, 0x9FE],
+ [0xA01, 0xA02],
+ [0xA05, 0xA0A],
+ [0xA0F, 0xA10],
+ [0xA13, 0xA28],
+ [0xA2A, 0xA30],
+ [0xA32, 0xA33],
+ [0xA35, 0xA36],
+ [0xA38, 0xA39],
+ [0xA3C, 0xA3C],
+ [0xA3E, 0xA42],
+ [0xA47, 0xA48],
+ [0xA4B, 0xA4D],
+ [0xA51, 0xA51],
+ [0xA59, 0xA5C],
+ [0xA5E, 0xA5E],
+ [0xA66, 0xA6F],
+ [0xA72, 0xA74],
+ [0xA81, 0xA83],
+ [0xA85, 0xA8B],
+ [0xA8D, 0xA8D],
+ [0xA8F, 0xA91],
+ [0xA93, 0xAA8],
+ [0xAAA, 0xAB0],
+ [0xAB2, 0xAB3],
+ [0xAB5, 0xAB9],
+ [0xABC, 0xABD],
+ [0xAC7, 0xAC9],
+ [0xACB, 0xACD],
+ [0xAD0, 0xAD0],
+ [0xAE0, 0xAE0],
+ [0xAE6, 0xAEF],
+ [0xAF9, 0xAFF],
+ [0xB01, 0xB03],
+ [0xB05, 0xB0C],
+ [0xB0F, 0xB10],
+ [0xB13, 0xB28],
+ [0xB2A, 0xB30],
+ [0xB32, 0xB33],
+ [0xB35, 0xB39],
+ [0xB3C, 0xB43],
+ [0xB47, 0xB48],
+ [0xB4B, 0xB4D],
+ [0xB55, 0xB57],
+ [0xB5C, 0xB5D],
+ [0xB5F, 0xB61],
+ [0xB66, 0xB6F],
+ [0xB71, 0xB71],
+ [0xB82, 0xB83],
+ [0xB85, 0xB8A],
+ [0xB8E, 0xB90],
+ [0xB92, 0xB95],
+ [0xB99, 0xB9A],
+ [0xB9C, 0xB9C],
+ [0xB9E, 0xB9F],
+ [0xBA3, 0xBA4],
+ [0xBA8, 0xBAA],
+ [0xBAE, 0xBB5],
+ [0xBB7, 0xBB9],
+ [0xBBE, 0xBC2],
+ [0xBC6, 0xBC8],
+ [0xBCA, 0xBCD],
+ [0xBD0, 0xBD0],
+ [0xBD7, 0xBD7],
+ [0xBE6, 0xBEF],
+ [0xC00, 0xC03],
+ [0xC05, 0xC0C],
+ [0xC0E, 0xC10],
+ [0xC12, 0xC28],
+ [0xC2A, 0xC33],
+ [0xC35, 0xC39],
+ [0xC3C, 0xC44],
+ [0xC46, 0xC48],
+ [0xC4A, 0xC4D],
+ [0xC55, 0xC56],
+ [0xC58, 0xC5A],
+ [0xC5D, 0xC5D],
+ [0xC60, 0xC61],
+ [0xC66, 0xC6F],
+ [0xC80, 0xC83],
+ [0xC85, 0xC8C],
+ [0xC8E, 0xC90],
+ [0xC92, 0xCA8],
+ [0xCAA, 0xCB3],
+ [0xCB5, 0xCB9],
+ [0xCBC, 0xCC4],
+ [0xCC6, 0xCC8],
+ [0xCCA, 0xCCD],
+ [0xCD5, 0xCD6],
+ [0xCDD, 0xCDE],
+ [0xCE0, 0xCE1],
+ [0xCE6, 0xCEF],
+ [0xCF1, 0xCF2],
+ [0xD00, 0xD0C],
+ [0xD0E, 0xD10],
+ [0xD12, 0xD39],
+ [0xD3D, 0xD43],
+ [0xD46, 0xD48],
+ [0xD4A, 0xD4E],
+ [0xD54, 0xD57],
+ [0xD5F, 0xD61],
+ [0xD66, 0xD6F],
+ [0xD7A, 0xD7F],
+ [0xD81, 0xD83],
+ [0xD85, 0xD96],
+ [0xD9A, 0xDB1],
+ [0xDB3, 0xDBB],
+ [0xDBD, 0xDBD],
+ [0xDC0, 0xDC6],
+ [0xDCA, 0xDCA],
+ [0xDCF, 0xDD4],
+ [0xDD6, 0xDD6],
+ [0xDD8, 0xDDF],
+ [0xDE6, 0xDEF],
+ [0xDF2, 0xDF3],
+ [0xE01, 0xE32],
+ [0xE40, 0xE4E],
+ [0xE50, 0xE59],
+ [0xE81, 0xE82],
+ [0xE84, 0xE84],
+ [0xE86, 0xE88],
+ [0xE8A, 0xE8A],
+ [0xE8C, 0xE8D],
+ [0xE94, 0xE97],
+ [0xE99, 0xE9F],
+ [0xEA1, 0xEA3],
+ [0xEA5, 0xEA5],
+ [0xEA7, 0xEAB],
+ [0xEAD, 0xEAE],
+ [0xEB0, 0xEB9],
+ [0xEBB, 0xEBD],
+ [0xEC0, 0xEC4],
+ [0xEC6, 0xEC6],
+ [0xEC8, 0xECE],
+ [0xED0, 0xED9],
+ [0xEDC, 0xEDF],
+ [0xF00, 0xF00],
+ [0xF18, 0xF19],
+ [0xF20, 0xF29],
+ [0xF35, 0xF35],
+ [0xF37, 0xF37],
+ [0xF39, 0xF39],
+ [0xF3E, 0xF47],
+ [0xF49, 0xF6C],
+ [0xF71, 0xF84],
+ [0xF86, 0xF95],
+ [0xF97, 0xF97],
+ [0xF99, 0xFB7],
+ [0xFB9, 0xFB9],
+ [0xFC6, 0xFC6],
+ [0x1000, 0x103F],
+ [0x1050, 0x105D],
+ [0x1061, 0x1061],
+ [0x1065, 0x1066],
+ [0x106E, 0x1070],
+ [0x1075, 0x1081],
+ [0x108E, 0x108E],
+ [0x10A0, 0x10C5],
+ [0x10C7, 0x10C7],
+ [0x10CD, 0x10CD],
+ [0x10D0, 0x10FA],
+ [0x10FC, 0x1248],
+ [0x124A, 0x124D],
+ [0x1250, 0x1256],
+ [0x1258, 0x1258],
+ [0x125A, 0x125D],
+ [0x1260, 0x1288],
+ [0x128A, 0x128D],
+ [0x1290, 0x12B0],
+ [0x12B2, 0x12B5],
+ [0x12B8, 0x12BE],
+ [0x12C0, 0x12C0],
+ [0x12C2, 0x12C5],
+ [0x12C8, 0x12D6],
+ [0x12D8, 0x1310],
+ [0x1312, 0x1315],
+ [0x1318, 0x135A],
+ [0x135D, 0x135F],
+ [0x1369, 0x1371],
+ [0x1380, 0x138F],
+ [0x13A0, 0x13F5],
+ [0x13F8, 0x13FD],
+ [0x1401, 0x166C],
+ [0x166F, 0x167F],
+ [0x1681, 0x169A],
+ [0x16A0, 0x16EA],
+ [0x16EE, 0x16F8],
+ [0x1700, 0x1711],
+ [0x171F, 0x1731],
+ [0x1740, 0x1751],
+ [0x1760, 0x176C],
+ [0x176E, 0x1770],
+ [0x1772, 0x1773],
+ [0x1780, 0x17B3],
+ [0x17D7, 0x17D7],
+ [0x17DC, 0x17DC],
+ [0x17E0, 0x17E9],
+ [0x180B, 0x180D],
+ [0x180F, 0x1878],
+ [0x1880, 0x18A8],
+ [0x18AA, 0x18AA],
+ [0x18B0, 0x18F5],
+ [0x1900, 0x191E],
+ [0x1920, 0x192B],
+ [0x1930, 0x193B],
+ [0x1946, 0x196D],
+ [0x1970, 0x1974],
+ [0x1980, 0x19AB],
+ [0x19B0, 0x19C9],
+ [0x19D0, 0x19DA],
+ [0x1A00, 0x1A16],
+ [0x1A20, 0x1A54],
+ [0x1A60, 0x1A7C],
+ [0x1A7F, 0x1A89],
+ [0x1A90, 0x1A99],
+ [0x1AA7, 0x1AA7],
+ [0x1AB0, 0x1ABD],
+ [0x1ABF, 0x1ACE],
+ [0x1B00, 0x1B33],
+ [0x1B45, 0x1B4C],
+ [0x1B50, 0x1B59],
+ [0x1B6B, 0x1B73],
+ [0x1B80, 0x1BA0],
+ [0x1BAE, 0x1BAF],
+ [0x1BBA, 0x1BE5],
+ [0x1C00, 0x1C37],
+ [0x1C40, 0x1C49],
+ [0x1C4D, 0x1C7D],
+ [0x1C80, 0x1C88],
+ [0x1C90, 0x1CBA],
+ [0x1CBD, 0x1CBF],
+ [0x1CD0, 0x1CD2],
+ [0x1CD4, 0x1CEC],
+ [0x1CEE, 0x1CF3],
+ [0x1CF5, 0x1CF6],
+ [0x1CFA, 0x1CFA],
+ [0x1D00, 0x1EF9],
+ [0x1F00, 0x1F15],
+ [0x1F18, 0x1F1D],
+ [0x1F20, 0x1F45],
+ [0x1F48, 0x1F4D],
+ [0x1F50, 0x1F57],
+ [0x1F59, 0x1F59],
+ [0x1F5B, 0x1F5B],
+ [0x1F5D, 0x1F5D],
+ [0x1F5F, 0x1F7D],
+ [0x1F80, 0x1FB4],
+ [0x1FB6, 0x1FBC],
+ [0x1FBE, 0x1FBE],
+ [0x1FC2, 0x1FC4],
+ [0x1FC6, 0x1FCC],
+ [0x1FD0, 0x1FD3],
+ [0x1FD6, 0x1FDB],
+ [0x1FE0, 0x1FEC],
+ [0x1FF2, 0x1FF4],
+ [0x1FF6, 0x1FFC],
+ [0x200B, 0x200D],
+ [0x202A, 0x202E],
+ [0x203F, 0x2040],
+ [0x2054, 0x2054],
+ [0x2060, 0x2071],
+ [0x207F, 0x207F],
+ [0x2090, 0x209C],
+ [0x20D0, 0x20DC],
+ [0x20E1, 0x20E1],
+ [0x20E5, 0x20F0],
+ [0x2102, 0x2102],
+ [0x2107, 0x2107],
+ [0x210A, 0x2113],
+ [0x2115, 0x2115],
+ [0x2118, 0x211D],
+ [0x2124, 0x2124],
+ [0x2126, 0x2126],
+ [0x2128, 0x2128],
+ [0x212A, 0x2138],
+ [0x213C, 0x213F],
+ [0x2145, 0x2149],
+ [0x214E, 0x214E],
+ [0x2160, 0x2188],
+ [0x2460, 0x24FF],
+ [0x2776, 0x2793],
+ [0x2C00, 0x2CE4],
+ [0x2CEB, 0x2CF3],
+ [0x2D00, 0x2D25],
+ [0x2D27, 0x2D27],
+ [0x2D2D, 0x2D2D],
+ [0x2D30, 0x2D67],
+ [0x2D6F, 0x2D6F],
+ [0x2D7F, 0x2D96],
+ [0x2DA0, 0x2DA6],
+ [0x2DA8, 0x2DAE],
+ [0x2DB0, 0x2DB6],
+ [0x2DB8, 0x2DBE],
+ [0x2DC0, 0x2DC6],
+ [0x2DC8, 0x2DCE],
+ [0x2DD0, 0x2DD6],
+ [0x2DD8, 0x2DDE],
+ [0x2DE0, 0x2DFF],
+ [0x2E80, 0x2FFF],
+ [0x3004, 0x3007],
+ [0x3021, 0x302F],
+ [0x3031, 0x303C],
+ [0x3041, 0x3096],
+ [0x3099, 0x309F],
+ [0x30A1, 0x30FC],
+ [0x3105, 0x312F],
+ [0x3131, 0x318E],
+ [0x31A0, 0x31BF],
+ [0x31F0, 0x31FF],
+ [0x3400, 0x4DBF],
+ [0x4E00, 0xA48C],
+ [0xA4D0, 0xA4FD],
+ [0xA500, 0xA60C],
+ [0xA610, 0xA61F],
+ [0xA62A, 0xA62B],
+ [0xA640, 0xA66F],
+ [0xA674, 0xA67D],
+ [0xA67F, 0xA6EF],
+ [0xA717, 0xA71F],
+ [0xA722, 0xA788],
+ [0xA78B, 0xA7CA],
+ [0xA7D0, 0xA7D1],
+ [0xA7D3, 0xA7D3],
+ [0xA7D5, 0xA7D9],
+ [0xA7F2, 0xA805],
+ [0xA807, 0xA80A],
+ [0xA80C, 0xA822],
+ [0xA82C, 0xA82C],
+ [0xA840, 0xA873],
+ [0xA880, 0xA8B3],
+ [0xA8D0, 0xA8D9],
+ [0xA8E0, 0xA8F7],
+ [0xA8FB, 0xA8FB],
+ [0xA8FD, 0xA8FE],
+ [0xA90A, 0xA925],
+ [0xA930, 0xA946],
+ [0xA960, 0xA97C],
+ [0xA980, 0xA9B2],
+ [0xA9CF, 0xA9CF],
+ [0xA9E0, 0xA9E4],
+ [0xA9E6, 0xA9EF],
+ [0xA9FA, 0xA9FE],
+ [0xAA00, 0xAA28],
+ [0xAA40, 0xAA42],
+ [0xAA44, 0xAA4B],
+ [0xAA50, 0xAA59],
+ [0xAA60, 0xAA76],
+ [0xAA7A, 0xAA7A],
+ [0xAA7E, 0xAAAF],
+ [0xAAB1, 0xAAB1],
+ [0xAAB5, 0xAAB6],
+ [0xAAB9, 0xAABD],
+ [0xAAC0, 0xAAC0],
+ [0xAAC2, 0xAAC2],
+ [0xAADB, 0xAADD],
+ [0xAAE0, 0xAAEA],
+ [0xAAF2, 0xAAF4],
+ [0xAB01, 0xAB06],
+ [0xAB09, 0xAB0E],
+ [0xAB11, 0xAB16],
+ [0xAB20, 0xAB26],
+ [0xAB28, 0xAB2E],
+ [0xAB30, 0xAB5A],
+ [0xAB5C, 0xAB69],
+ [0xAB70, 0xABE2],
+ [0xABEC, 0xABED],
+ [0xABF0, 0xABF9],
+ [0xAC00, 0xD7A3],
+ [0xD7B0, 0xD7C6],
+ [0xD7CB, 0xD7FB],
+ [0xF900, 0xFA6D],
+ [0xFA70, 0xFAD9],
+ [0xFB00, 0xFB06],
+ [0xFB13, 0xFB17],
+ [0xFB1D, 0xFB1D],
+ [0xFB1F, 0xFB28],
+ [0xFB2A, 0xFB36],
+ [0xFB38, 0xFB3C],
+ [0xFB3E, 0xFB3E],
+ [0xFB40, 0xFB41],
+ [0xFB43, 0xFB44],
+ [0xFB46, 0xFBB1],
+ [0xFBD3, 0xFC5D],
+ [0xFC64, 0xFD3D],
+ [0xFD40, 0xFD8F],
+ [0xFD92, 0xFDC7],
+ [0xFDF0, 0xFDF9],
+ [0xFE00, 0xFE0F],
+ [0xFE20, 0xFE2F],
+ [0xFE33, 0xFE34],
+ [0xFE47, 0xFE71],
+ [0xFE73, 0xFE73],
+ [0xFE77, 0xFE77],
+ [0xFE79, 0xFE79],
+ [0xFE7B, 0xFE7B],
+ [0xFE7D, 0xFE7D],
+ [0xFE7F, 0xFEFC],
+ [0xFF10, 0xFF19],
+ [0xFF21, 0xFF3A],
+ [0xFF3F, 0xFF3F],
+ [0xFF41, 0xFF5A],
+ [0xFF65, 0xFF9D],
+ [0xFFA0, 0xFFBE],
+ [0xFFC2, 0xFFC7],
+ [0xFFCA, 0xFFCF],
+ [0xFFD2, 0xFFD7],
+ [0xFFDA, 0xFFDC],
+ [0x10000, 0x1000B],
+ [0x1000D, 0x10026],
+ [0x10028, 0x1003A],
+ [0x1003C, 0x1003D],
+ [0x1003F, 0x1004D],
+ [0x10050, 0x1005D],
+ [0x10080, 0x100FA],
+ [0x10140, 0x10174],
+ [0x101FD, 0x101FD],
+ [0x10280, 0x1029C],
+ [0x102A0, 0x102D0],
+ [0x102E0, 0x102E0],
+ [0x10300, 0x1031F],
+ [0x1032D, 0x1034A],
+ [0x10350, 0x10375],
+ [0x10380, 0x1039D],
+ [0x103A0, 0x103C3],
+ [0x103C8, 0x103CF],
+ [0x103D1, 0x103D5],
+ [0x10400, 0x1049D],
+ [0x104A0, 0x104A9],
+ [0x104B0, 0x104D3],
+ [0x104D8, 0x104FB],
+ [0x10500, 0x10527],
+ [0x10530, 0x10563],
+ [0x10570, 0x1057A],
+ [0x1057C, 0x1058A],
+ [0x1058C, 0x10592],
+ [0x10594, 0x10595],
+ [0x10597, 0x105A1],
+ [0x105A3, 0x105B1],
+ [0x105B3, 0x105B9],
+ [0x105BB, 0x105BC],
+ [0x10600, 0x10736],
+ [0x10740, 0x10755],
+ [0x10760, 0x10767],
+ [0x10780, 0x10785],
+ [0x10787, 0x107B0],
+ [0x107B2, 0x107BA],
+ [0x10800, 0x10805],
+ [0x10808, 0x10808],
+ [0x1080A, 0x10835],
+ [0x10837, 0x10838],
+ [0x1083C, 0x1083C],
+ [0x1083F, 0x10855],
+ [0x10860, 0x10876],
+ [0x10880, 0x1089E],
+ [0x108E0, 0x108F2],
+ [0x108F4, 0x108F5],
+ [0x10900, 0x10915],
+ [0x10920, 0x10939],
+ [0x10980, 0x109B7],
+ [0x109BE, 0x109BF],
+ [0x10A00, 0x10A03],
+ [0x10A05, 0x10A06],
+ [0x10A0C, 0x10A13],
+ [0x10A15, 0x10A17],
+ [0x10A19, 0x10A35],
+ [0x10A38, 0x10A3A],
+ [0x10A3F, 0x10A3F],
+ [0x10A60, 0x10A7C],
+ [0x10A80, 0x10A9C],
+ [0x10AC0, 0x10AC7],
+ [0x10AC9, 0x10AE6],
+ [0x10B00, 0x10B35],
+ [0x10B40, 0x10B55],
+ [0x10B60, 0x10B72],
+ [0x10B80, 0x10B91],
+ [0x10C00, 0x10C48],
+ [0x10C80, 0x10CB2],
+ [0x10CC0, 0x10CF2],
+ [0x10D00, 0x10D23],
+ [0x10D30, 0x10D39],
+ [0x10E80, 0x10EA9],
+ [0x10EAB, 0x10EAC],
+ [0x10EB0, 0x10EB1],
+ [0x10EFD, 0x10F1C],
+ [0x10F27, 0x10F27],
+ [0x10F30, 0x10F45],
+ [0x10F70, 0x10F81],
+ [0x10FB0, 0x10FC4],
+ [0x10FE0, 0x10FF6],
+ [0x11000, 0x11037],
+ [0x11066, 0x11072],
+ [0x11075, 0x11075],
+ [0x1107F, 0x110AF],
+ [0x110C2, 0x110C2],
+ [0x110D0, 0x110E8],
+ [0x110F0, 0x110F9],
+ [0x11100, 0x11126],
+ [0x11136, 0x1113F],
+ [0x11144, 0x11147],
+ [0x11150, 0x11173],
+ [0x11176, 0x11176],
+ [0x11180, 0x111B2],
+ [0x111C1, 0x111C4],
+ [0x111C9, 0x111CC],
+ [0x111CE, 0x111DA],
+ [0x111DC, 0x111DC],
+ [0x11200, 0x11211],
+ [0x11213, 0x11237],
+ [0x1123E, 0x11240],
+ [0x11280, 0x11286],
+ [0x11288, 0x11288],
+ [0x1128A, 0x1128D],
+ [0x1128F, 0x1129D],
+ [0x1129F, 0x112A8],
+ [0x112B0, 0x112EA],
+ [0x112F0, 0x112F9],
+ [0x11300, 0x11303],
+ [0x11305, 0x1130C],
+ [0x1130F, 0x11310],
+ [0x11313, 0x11328],
+ [0x1132A, 0x11330],
+ [0x11332, 0x11333],
+ [0x11335, 0x11339],
+ [0x1133B, 0x1133D],
+ [0x11347, 0x11348],
+ [0x1134B, 0x1134D],
+ [0x11350, 0x11350],
+ [0x11357, 0x11357],
+ [0x1135D, 0x11363],
+ [0x11366, 0x1136C],
+ [0x11370, 0x11374],
+ [0x11400, 0x1144A],
+ [0x11450, 0x11459],
+ [0x1145E, 0x11461],
+ [0x11480, 0x114C5],
+ [0x114C7, 0x114C7],
+ [0x114D0, 0x114D9],
+ [0x11580, 0x115B5],
+ [0x115B8, 0x115C0],
+ [0x115D8, 0x115DD],
+ [0x11600, 0x11640],
+ [0x11644, 0x11644],
+ [0x11650, 0x11659],
+ [0x11680, 0x116B8],
+ [0x116C0, 0x116C9],
+ [0x11700, 0x1171A],
+ [0x1171D, 0x1172B],
+ [0x11730, 0x11739],
+ [0x11740, 0x11746],
+ [0x11800, 0x1183A],
+ [0x118A0, 0x118E9],
+ [0x118FF, 0x11906],
+ [0x11909, 0x11909],
+ [0x1190C, 0x11913],
+ [0x11915, 0x11916],
+ [0x11918, 0x11935],
+ [0x11937, 0x11938],
+ [0x1193B, 0x1193F],
+ [0x11941, 0x11941],
+ [0x11950, 0x11959],
+ [0x119A0, 0x119A7],
+ [0x119AA, 0x119D7],
+ [0x119DA, 0x119E1],
+ [0x119E3, 0x119E3],
+ [0x11A00, 0x11A32],
+ [0x11A3A, 0x11A3A],
+ [0x11A47, 0x11A47],
+ [0x11A50, 0x11A89],
+ [0x11A9D, 0x11A9D],
+ [0x11AB0, 0x11AF8],
+ [0x11C00, 0x11C08],
+ [0x11C0A, 0x11C36],
+ [0x11C38, 0x11C40],
+ [0x11C50, 0x11C59],
+ [0x11C72, 0x11C8F],
+ [0x11C92, 0x11CA7],
+ [0x11CA9, 0x11CB6],
+ [0x11D00, 0x11D06],
+ [0x11D08, 0x11D09],
+ [0x11D0B, 0x11D36],
+ [0x11D3A, 0x11D3A],
+ [0x11D3C, 0x11D3D],
+ [0x11D3F, 0x11D46],
+ [0x11D50, 0x11D59],
+ [0x11D60, 0x11D65],
+ [0x11D67, 0x11D68],
+ [0x11D6A, 0x11D89],
+ [0x11D90, 0x11D91],
+ [0x11D93, 0x11D98],
+ [0x11DA0, 0x11DA9],
+ [0x11EE0, 0x11EF2],
+ [0x11F00, 0x11F02],
+ [0x11F04, 0x11F10],
+ [0x11F12, 0x11F33],
+ [0x11F3E, 0x11F42],
+ [0x11F50, 0x11F59],
+ [0x11FB0, 0x11FB0],
+ [0x12000, 0x12399],
+ [0x12400, 0x1246E],
+ [0x12480, 0x12543],
+ [0x12F90, 0x12FF0],
+ [0x13000, 0x1342F],
+ [0x13440, 0x13446],
+ [0x14400, 0x14646],
+ [0x16800, 0x16A38],
+ [0x16A40, 0x16A5E],
+ [0x16A60, 0x16A69],
+ [0x16A70, 0x16ABE],
+ [0x16AC0, 0x16AC9],
+ [0x16AD0, 0x16AED],
+ [0x16AF0, 0x16AF4],
+ [0x16B00, 0x16B2F],
+ [0x16B40, 0x16B43],
+ [0x16B50, 0x16B59],
+ [0x16B63, 0x16B77],
+ [0x16B7D, 0x16B8F],
+ [0x16E40, 0x16E7F],
+ [0x16F00, 0x16F4A],
+ [0x16F4F, 0x16F50],
+ [0x16F8F, 0x16F9F],
+ [0x16FE0, 0x16FE1],
+ [0x16FE3, 0x16FE3],
+ [0x16FF0, 0x16FF1],
+ [0x17000, 0x187F7],
+ [0x18800, 0x18CD5],
+ [0x18D00, 0x18D08],
+ [0x1AFF0, 0x1AFF3],
+ [0x1AFF5, 0x1AFFB],
+ [0x1AFFD, 0x1AFFE],
+ [0x1B000, 0x1B122],
+ [0x1B132, 0x1B132],
+ [0x1B150, 0x1B152],
+ [0x1B155, 0x1B155],
+ [0x1B164, 0x1B167],
+ [0x1B170, 0x1B2FB],
+ [0x1BC00, 0x1BC6A],
+ [0x1BC70, 0x1BC7C],
+ [0x1BC80, 0x1BC88],
+ [0x1BC90, 0x1BC99],
+ [0x1BC9D, 0x1BC9E],
+ [0x1CF00, 0x1CF2D],
+ [0x1CF30, 0x1CF46],
+ [0x1D165, 0x1D169],
+ [0x1D16D, 0x1D172],
+ [0x1D17B, 0x1D182],
+ [0x1D185, 0x1D18B],
+ [0x1D1AA, 0x1D1AD],
+ [0x1D242, 0x1D244],
+ [0x1D400, 0x1D454],
+ [0x1D456, 0x1D49C],
+ [0x1D49E, 0x1D49F],
+ [0x1D4A2, 0x1D4A2],
+ [0x1D4A5, 0x1D4A6],
+ [0x1D4A9, 0x1D4AC],
+ [0x1D4AE, 0x1D4B9],
+ [0x1D4BB, 0x1D4BB],
+ [0x1D4BD, 0x1D4C3],
+ [0x1D4C5, 0x1D505],
+ [0x1D507, 0x1D50A],
+ [0x1D50D, 0x1D514],
+ [0x1D516, 0x1D51C],
+ [0x1D51E, 0x1D539],
+ [0x1D53B, 0x1D53E],
+ [0x1D540, 0x1D544],
+ [0x1D546, 0x1D546],
+ [0x1D54A, 0x1D550],
+ [0x1D552, 0x1D6A5],
+ [0x1D6A8, 0x1D6C0],
+ [0x1D6C2, 0x1D6DA],
+ [0x1D6DC, 0x1D6FA],
+ [0x1D6FC, 0x1D714],
+ [0x1D716, 0x1D734],
+ [0x1D736, 0x1D74E],
+ [0x1D750, 0x1D76E],
+ [0x1D770, 0x1D788],
+ [0x1D78A, 0x1D7A8],
+ [0x1D7AA, 0x1D7C2],
+ [0x1D7C4, 0x1D7CB],
+ [0x1D7CE, 0x1D7FF],
+ [0x1DA00, 0x1DA36],
+ [0x1DA3B, 0x1DA6C],
+ [0x1DA75, 0x1DA75],
+ [0x1DA84, 0x1DA84],
+ [0x1DA9B, 0x1DA9F],
+ [0x1DAA1, 0x1DAAF],
+ [0x1DF00, 0x1DF1E],
+ [0x1DF25, 0x1DF2A],
+ [0x1E000, 0x1E006],
+ [0x1E008, 0x1E018],
+ [0x1E01B, 0x1E021],
+ [0x1E023, 0x1E024],
+ [0x1E026, 0x1E02A],
+ [0x1E030, 0x1E06D],
+ [0x1E08F, 0x1E08F],
+ [0x1E100, 0x1E12C],
+ [0x1E130, 0x1E13D],
+ [0x1E140, 0x1E149],
+ [0x1E14E, 0x1E14E],
+ [0x1E290, 0x1E2AE],
+ [0x1E2C0, 0x1E2F9],
+ [0x1E4D0, 0x1E4F9],
+ [0x1E7E0, 0x1E7E6],
+ [0x1E7E8, 0x1E7EB],
+ [0x1E7ED, 0x1E7EE],
+ [0x1E7F0, 0x1E7FE],
+ [0x1E800, 0x1E8C4],
+ [0x1E8D0, 0x1E8D6],
+ [0x1E900, 0x1E94B],
+ [0x1E950, 0x1E959],
+ [0x1EE00, 0x1EE03],
+ [0x1EE05, 0x1EE1F],
+ [0x1EE21, 0x1EE22],
+ [0x1EE24, 0x1EE24],
+ [0x1EE27, 0x1EE27],
+ [0x1EE29, 0x1EE32],
+ [0x1EE34, 0x1EE37],
+ [0x1EE39, 0x1EE39],
+ [0x1EE3B, 0x1EE3B],
+ [0x1EE42, 0x1EE42],
+ [0x1EE47, 0x1EE47],
+ [0x1EE49, 0x1EE49],
+ [0x1EE4B, 0x1EE4B],
+ [0x1EE4D, 0x1EE4F],
+ [0x1EE51, 0x1EE52],
+ [0x1EE54, 0x1EE54],
+ [0x1EE57, 0x1EE57],
+ [0x1EE59, 0x1EE59],
+ [0x1EE5B, 0x1EE5B],
+ [0x1EE5D, 0x1EE5D],
+ [0x1EE5F, 0x1EE5F],
+ [0x1EE61, 0x1EE62],
+ [0x1EE64, 0x1EE64],
+ [0x1EE67, 0x1EE6A],
+ [0x1EE6C, 0x1EE72],
+ [0x1EE74, 0x1EE77],
+ [0x1EE79, 0x1EE7C],
+ [0x1EE7E, 0x1EE7E],
+ [0x1EE80, 0x1EE89],
+ [0x1EE8B, 0x1EE9B],
+ [0x1EEA1, 0x1EEA3],
+ [0x1EEA5, 0x1EEA9],
+ [0x1EEAB, 0x1EEBB],
+ [0x1FBF0, 0x1FBF9],
+ [0x20000, 0x2B739],
+ [0x2B740, 0x2B81D],
+ [0x2B820, 0x2CEA1],
+ [0x2CEB0, 0x2EBE0],
+ [0x2EBF0, 0x2EE5D],
+ [0x2F800, 0x2FA1D],
+ [0x30000, 0x323AF],
+ [0x40000, 0x4FFFD],
+ [0x50000, 0x5FFFD],
+ [0x60000, 0x6FFFD],
+ [0x70000, 0x7FFFD],
+ [0x80000, 0x8FFFD],
+ [0x90000, 0x9FFFD],
+ [0xA0000, 0xAFFFD],
+ [0xB0000, 0xBFFFD],
+ [0xC0000, 0xCFFFD],
+ [0xD0000, 0xDFFFD],
+ [0xE0000, 0xEFFFD],
+];
+
+/**
+Least restrictive Start
+Entries: 858717
+*/
+static immutable dchar[2][] LeastRestrictive_Start = [
+ [0xA8, 0xA8],
+ [0xAA, 0xAA],
+ [0xAD, 0xAD],
+ [0xAF, 0xAF],
+ [0xB2, 0xB5],
+ [0xB7, 0xBA],
+ [0xBC, 0xBE],
+ [0xC0, 0xD6],
+ [0xD8, 0xF6],
+ [0xF8, 0x217],
+ [0x250, 0x2A8],
+ [0x2B0, 0x2B8],
+ [0x2BB, 0x2BB],
+ [0x2BD, 0x2C1],
+ [0x2C6, 0x2D1],
+ [0x2E0, 0x2E4],
+ [0x2EC, 0x2EC],
+ [0x2EE, 0x2EE],
+ [0x370, 0x374],
+ [0x376, 0x377],
+ [0x37A, 0x37D],
+ [0x37F, 0x37F],
+ [0x386, 0x386],
+ [0x388, 0x38A],
+ [0x38C, 0x38C],
+ [0x38E, 0x3A1],
+ [0x3A3, 0x3CE],
+ [0x3D0, 0x3D6],
+ [0x3DA, 0x3DA],
+ [0x3DC, 0x3DC],
+ [0x3DE, 0x3DE],
+ [0x3E0, 0x3E0],
+ [0x3E2, 0x3F3],
+ [0x3F7, 0x40C],
+ [0x40E, 0x44F],
+ [0x451, 0x45C],
+ [0x45E, 0x481],
+ [0x48A, 0x4C4],
+ [0x4C7, 0x4C8],
+ [0x4CB, 0x4CC],
+ [0x4D0, 0x4EB],
+ [0x4EE, 0x4F5],
+ [0x4F8, 0x4F9],
+ [0x531, 0x556],
+ [0x559, 0x559],
+ [0x560, 0x587],
+ [0x5B0, 0x5B9],
+ [0x5BB, 0x5BD],
+ [0x5BF, 0x5BF],
+ [0x5C1, 0x5C2],
+ [0x5D0, 0x5EA],
+ [0x5EF, 0x5F2],
+ [0x620, 0x63A],
+ [0x640, 0x652],
+ [0x660, 0x669],
+ [0x66E, 0x6BE],
+ [0x6C0, 0x6CE],
+ [0x6D0, 0x6D5],
+ [0x6E5, 0x6E8],
+ [0x6EA, 0x6FC],
+ [0x6FF, 0x6FF],
+ [0x710, 0x710],
+ [0x712, 0x72F],
+ [0x74D, 0x7A5],
+ [0x7B1, 0x7B1],
+ [0x7CA, 0x7EA],
+ [0x7F4, 0x7F5],
+ [0x7FA, 0x7FA],
+ [0x800, 0x815],
+ [0x81A, 0x81A],
+ [0x824, 0x824],
+ [0x828, 0x828],
+ [0x840, 0x858],
+ [0x860, 0x86A],
+ [0x870, 0x887],
+ [0x889, 0x88E],
+ [0x8A0, 0x8C9],
+ [0x901, 0x939],
+ [0x93D, 0x94D],
+ [0x950, 0x952],
+ [0x958, 0x963],
+ [0x966, 0x96F],
+ [0x971, 0x983],
+ [0x985, 0x98C],
+ [0x98F, 0x990],
+ [0x993, 0x9A8],
+ [0x9AA, 0x9B0],
+ [0x9B2, 0x9B2],
+ [0x9B6, 0x9B9],
+ [0x9BD, 0x9C4],
+ [0x9C7, 0x9C8],
+ [0x9CB, 0x9CE],
+ [0x9DC, 0x9DD],
+ [0x9DF, 0x9E3],
+ [0x9E6, 0x9F1],
+ [0x9FC, 0x9FC],
+ [0xA02, 0xA02],
+ [0xA05, 0xA0A],
+ [0xA0F, 0xA10],
+ [0xA13, 0xA28],
+ [0xA2A, 0xA30],
+ [0xA32, 0xA33],
+ [0xA35, 0xA36],
+ [0xA38, 0xA39],
+ [0xA3E, 0xA42],
+ [0xA47, 0xA48],
+ [0xA4B, 0xA4D],
+ [0xA59, 0xA5C],
+ [0xA5E, 0xA5E],
+ [0xA66, 0xA6F],
+ [0xA72, 0xA74],
+ [0xA81, 0xA83],
+ [0xA85, 0xA8B],
+ [0xA8D, 0xA8D],
+ [0xA8F, 0xA91],
+ [0xA93, 0xAA8],
+ [0xAAA, 0xAB0],
+ [0xAB2, 0xAB3],
+ [0xAB5, 0xAB9],
+ [0xABD, 0xABD],
+ [0xAC7, 0xAC9],
+ [0xACB, 0xACD],
+ [0xAD0, 0xAD0],
+ [0xAE0, 0xAE0],
+ [0xAE6, 0xAEF],
+ [0xAF9, 0xAF9],
+ [0xB01, 0xB03],
+ [0xB05, 0xB0C],
+ [0xB0F, 0xB10],
+ [0xB13, 0xB28],
+ [0xB2A, 0xB30],
+ [0xB32, 0xB33],
+ [0xB35, 0xB39],
+ [0xB3D, 0xB43],
+ [0xB47, 0xB48],
+ [0xB4B, 0xB4D],
+ [0xB5C, 0xB5D],
+ [0xB5F, 0xB61],
+ [0xB66, 0xB6F],
+ [0xB71, 0xB71],
+ [0xB82, 0xB83],
+ [0xB85, 0xB8A],
+ [0xB8E, 0xB90],
+ [0xB92, 0xB95],
+ [0xB99, 0xB9A],
+ [0xB9C, 0xB9C],
+ [0xB9E, 0xB9F],
+ [0xBA3, 0xBA4],
+ [0xBA8, 0xBAA],
+ [0xBAE, 0xBB5],
+ [0xBB7, 0xBB9],
+ [0xBBE, 0xBC2],
+ [0xBC6, 0xBC8],
+ [0xBCA, 0xBCD],
+ [0xBD0, 0xBD0],
+ [0xBE7, 0xBEF],
+ [0xC01, 0xC03],
+ [0xC05, 0xC0C],
+ [0xC0E, 0xC10],
+ [0xC12, 0xC28],
+ [0xC2A, 0xC33],
+ [0xC35, 0xC39],
+ [0xC3D, 0xC44],
+ [0xC46, 0xC48],
+ [0xC4A, 0xC4D],
+ [0xC58, 0xC5A],
+ [0xC5D, 0xC5D],
+ [0xC60, 0xC61],
+ [0xC66, 0xC6F],
+ [0xC80, 0xC80],
+ [0xC82, 0xC83],
+ [0xC85, 0xC8C],
+ [0xC8E, 0xC90],
+ [0xC92, 0xCA8],
+ [0xCAA, 0xCB3],
+ [0xCB5, 0xCB9],
+ [0xCBD, 0xCC4],
+ [0xCC6, 0xCC8],
+ [0xCCA, 0xCCD],
+ [0xCDD, 0xCDE],
+ [0xCE0, 0xCE1],
+ [0xCE6, 0xCEF],
+ [0xCF1, 0xCF2],
+ [0xD02, 0xD0C],
+ [0xD0E, 0xD10],
+ [0xD12, 0xD28],
+ [0xD2A, 0xD39],
+ [0xD3D, 0xD43],
+ [0xD46, 0xD48],
+ [0xD4A, 0xD4E],
+ [0xD54, 0xD56],
+ [0xD5F, 0xD61],
+ [0xD66, 0xD6F],
+ [0xD7A, 0xD7F],
+ [0xD85, 0xD96],
+ [0xD9A, 0xDB1],
+ [0xDB3, 0xDBB],
+ [0xDBD, 0xDBD],
+ [0xDC0, 0xDC6],
+ [0xE01, 0xE30],
+ [0xE32, 0xE32],
+ [0xE40, 0xE5B],
+ [0xE81, 0xE82],
+ [0xE84, 0xE84],
+ [0xE86, 0xE88],
+ [0xE8A, 0xE8A],
+ [0xE8C, 0xE8D],
+ [0xE94, 0xE97],
+ [0xE99, 0xE9F],
+ [0xEA1, 0xEA3],
+ [0xEA5, 0xEA5],
+ [0xEA7, 0xEAB],
+ [0xEAD, 0xEAE],
+ [0xEB0, 0xEB2],
+ [0xEBB, 0xEBD],
+ [0xEC0, 0xEC4],
+ [0xEC6, 0xEC6],
+ [0xEC8, 0xECD],
+ [0xED0, 0xED9],
+ [0xEDC, 0xEDD],
+ [0xF00, 0xF00],
+ [0xF18, 0xF19],
+ [0xF20, 0xF33],
+ [0xF35, 0xF35],
+ [0xF37, 0xF37],
+ [0xF39, 0xF39],
+ [0xF3E, 0xF47],
+ [0xF49, 0xF69],
+ [0xF71, 0xF84],
+ [0xF86, 0xF8C],
+ [0xF90, 0xF95],
+ [0xF97, 0xF97],
+ [0xF99, 0xFAD],
+ [0xFB1, 0xFB7],
+ [0xFB9, 0xFB9],
+ [0x1000, 0x102A],
+ [0x103F, 0x103F],
+ [0x1050, 0x1055],
+ [0x105A, 0x105D],
+ [0x1061, 0x1061],
+ [0x1065, 0x1066],
+ [0x106E, 0x1070],
+ [0x1075, 0x1081],
+ [0x108E, 0x108E],
+ [0x10A0, 0x10C5],
+ [0x10C7, 0x10C7],
+ [0x10CD, 0x10CD],
+ [0x10D0, 0x10FA],
+ [0x10FC, 0x1248],
+ [0x124A, 0x124D],
+ [0x1250, 0x1256],
+ [0x1258, 0x1258],
+ [0x125A, 0x125D],
+ [0x1260, 0x1288],
+ [0x128A, 0x128D],
+ [0x1290, 0x12B0],
+ [0x12B2, 0x12B5],
+ [0x12B8, 0x12BE],
+ [0x12C0, 0x12C0],
+ [0x12C2, 0x12C5],
+ [0x12C8, 0x12D6],
+ [0x12D8, 0x1310],
+ [0x1312, 0x1315],
+ [0x1318, 0x135A],
+ [0x1380, 0x138F],
+ [0x13A0, 0x13F5],
+ [0x13F8, 0x13FD],
+ [0x1401, 0x166C],
+ [0x166F, 0x167F],
+ [0x1681, 0x169A],
+ [0x16A0, 0x16EA],
+ [0x16EE, 0x16F8],
+ [0x1700, 0x1711],
+ [0x171F, 0x1731],
+ [0x1740, 0x1751],
+ [0x1760, 0x176C],
+ [0x176E, 0x1770],
+ [0x1780, 0x17B3],
+ [0x17D7, 0x17D7],
+ [0x17DC, 0x17DC],
+ [0x180F, 0x1878],
+ [0x1880, 0x18A8],
+ [0x18AA, 0x18AA],
+ [0x18B0, 0x18F5],
+ [0x1900, 0x191E],
+ [0x1950, 0x196D],
+ [0x1970, 0x1974],
+ [0x1980, 0x19AB],
+ [0x19B0, 0x19C9],
+ [0x1A00, 0x1A16],
+ [0x1A20, 0x1A54],
+ [0x1AA7, 0x1AA7],
+ [0x1B05, 0x1B33],
+ [0x1B45, 0x1B4C],
+ [0x1B83, 0x1BA0],
+ [0x1BAE, 0x1BAF],
+ [0x1BBA, 0x1BE5],
+ [0x1C00, 0x1C23],
+ [0x1C4D, 0x1C4F],
+ [0x1C5A, 0x1C7D],
+ [0x1C80, 0x1C88],
+ [0x1C90, 0x1CBA],
+ [0x1CBD, 0x1CBF],
+ [0x1CE9, 0x1CEC],
+ [0x1CEE, 0x1CF3],
+ [0x1CF5, 0x1CF6],
+ [0x1CFA, 0x1CFA],
+ [0x1D00, 0x1DBF],
+ [0x1E00, 0x1EF9],
+ [0x1F00, 0x1F15],
+ [0x1F18, 0x1F1D],
+ [0x1F20, 0x1F45],
+ [0x1F48, 0x1F4D],
+ [0x1F50, 0x1F57],
+ [0x1F59, 0x1F59],
+ [0x1F5B, 0x1F5B],
+ [0x1F5D, 0x1F5D],
+ [0x1F5F, 0x1F7D],
+ [0x1F80, 0x1FB4],
+ [0x1FB6, 0x1FBC],
+ [0x1FBE, 0x1FBE],
+ [0x1FC2, 0x1FC4],
+ [0x1FC6, 0x1FCC],
+ [0x1FD0, 0x1FD3],
+ [0x1FD6, 0x1FDB],
+ [0x1FE0, 0x1FEC],
+ [0x1FF2, 0x1FF4],
+ [0x1FF6, 0x1FFC],
+ [0x200B, 0x200D],
+ [0x202A, 0x202E],
+ [0x203F, 0x2040],
+ [0x2054, 0x2054],
+ [0x2060, 0x2071],
+ [0x207F, 0x207F],
+ [0x2090, 0x209C],
+ [0x2102, 0x2102],
+ [0x2107, 0x2107],
+ [0x210A, 0x2113],
+ [0x2115, 0x2115],
+ [0x2118, 0x211D],
+ [0x2124, 0x2124],
+ [0x2126, 0x2126],
+ [0x2128, 0x2128],
+ [0x212A, 0x2138],
+ [0x213C, 0x213F],
+ [0x2145, 0x2149],
+ [0x214E, 0x214E],
+ [0x2160, 0x2188],
+ [0x2460, 0x24FF],
+ [0x2776, 0x2793],
+ [0x2C00, 0x2CE4],
+ [0x2CEB, 0x2CEE],
+ [0x2CF2, 0x2CF3],
+ [0x2D00, 0x2D25],
+ [0x2D27, 0x2D27],
+ [0x2D2D, 0x2D2D],
+ [0x2D30, 0x2D67],
+ [0x2D6F, 0x2D6F],
+ [0x2D80, 0x2D96],
+ [0x2DA0, 0x2DA6],
+ [0x2DA8, 0x2DAE],
+ [0x2DB0, 0x2DB6],
+ [0x2DB8, 0x2DBE],
+ [0x2DC0, 0x2DC6],
+ [0x2DC8, 0x2DCE],
+ [0x2DD0, 0x2DD6],
+ [0x2DD8, 0x2DDE],
+ [0x2E80, 0x2FFF],
+ [0x3004, 0x3007],
+ [0x3021, 0x3029],
+ [0x3031, 0x3035],
+ [0x3038, 0x303C],
+ [0x3041, 0x3096],
+ [0x309B, 0x309F],
+ [0x30A1, 0x30FF],
+ [0x3105, 0x312F],
+ [0x3131, 0x318E],
+ [0x31A0, 0x31BF],
+ [0x31F0, 0x31FF],
+ [0x3400, 0x4DBF],
+ [0x4E00, 0xA48C],
+ [0xA4D0, 0xA4FD],
+ [0xA500, 0xA60C],
+ [0xA610, 0xA61F],
+ [0xA62A, 0xA62B],
+ [0xA640, 0xA66E],
+ [0xA67F, 0xA69D],
+ [0xA6A0, 0xA6EF],
+ [0xA717, 0xA71F],
+ [0xA722, 0xA788],
+ [0xA78B, 0xA7CA],
+ [0xA7D0, 0xA7D1],
+ [0xA7D3, 0xA7D3],
+ [0xA7D5, 0xA7D9],
+ [0xA7F2, 0xA801],
+ [0xA803, 0xA805],
+ [0xA807, 0xA80A],
+ [0xA80C, 0xA822],
+ [0xA840, 0xA873],
+ [0xA882, 0xA8B3],
+ [0xA8F2, 0xA8F7],
+ [0xA8FB, 0xA8FB],
+ [0xA8FD, 0xA8FE],
+ [0xA90A, 0xA925],
+ [0xA930, 0xA946],
+ [0xA960, 0xA97C],
+ [0xA984, 0xA9B2],
+ [0xA9CF, 0xA9CF],
+ [0xA9E0, 0xA9E4],
+ [0xA9E6, 0xA9EF],
+ [0xA9FA, 0xA9FE],
+ [0xAA00, 0xAA28],
+ [0xAA40, 0xAA42],
+ [0xAA44, 0xAA4B],
+ [0xAA60, 0xAA76],
+ [0xAA7A, 0xAA7A],
+ [0xAA7E, 0xAAAF],
+ [0xAAB1, 0xAAB1],
+ [0xAAB5, 0xAAB6],
+ [0xAAB9, 0xAABD],
+ [0xAAC0, 0xAAC0],
+ [0xAAC2, 0xAAC2],
+ [0xAADB, 0xAADD],
+ [0xAAE0, 0xAAEA],
+ [0xAAF2, 0xAAF4],
+ [0xAB01, 0xAB06],
+ [0xAB09, 0xAB0E],
+ [0xAB11, 0xAB16],
+ [0xAB20, 0xAB26],
+ [0xAB28, 0xAB2E],
+ [0xAB30, 0xAB5A],
+ [0xAB5C, 0xAB69],
+ [0xAB70, 0xABE2],
+ [0xAC00, 0xD7A3],
+ [0xD7B0, 0xD7C6],
+ [0xD7CB, 0xD7FB],
+ [0xF900, 0xFA6D],
+ [0xFA70, 0xFAD9],
+ [0xFB00, 0xFB06],
+ [0xFB13, 0xFB17],
+ [0xFB1D, 0xFB1D],
+ [0xFB1F, 0xFB28],
+ [0xFB2A, 0xFB36],
+ [0xFB38, 0xFB3C],
+ [0xFB3E, 0xFB3E],
+ [0xFB40, 0xFB41],
+ [0xFB43, 0xFB44],
+ [0xFB46, 0xFBB1],
+ [0xFBD3, 0xFC5D],
+ [0xFC64, 0xFD3D],
+ [0xFD40, 0xFD8F],
+ [0xFD92, 0xFDC7],
+ [0xFDF0, 0xFDF9],
+ [0xFE47, 0xFE71],
+ [0xFE73, 0xFE73],
+ [0xFE77, 0xFE77],
+ [0xFE79, 0xFE79],
+ [0xFE7B, 0xFE7B],
+ [0xFE7D, 0xFE7D],
+ [0xFE7F, 0xFEFC],
+ [0xFF21, 0xFF3A],
+ [0xFF41, 0xFF5A],
+ [0xFF66, 0xFF9D],
+ [0xFFA0, 0xFFBE],
+ [0xFFC2, 0xFFC7],
+ [0xFFCA, 0xFFCF],
+ [0xFFD2, 0xFFD7],
+ [0xFFDA, 0xFFDC],
+ [0x10000, 0x1000B],
+ [0x1000D, 0x10026],
+ [0x10028, 0x1003A],
+ [0x1003C, 0x1003D],
+ [0x1003F, 0x1004D],
+ [0x10050, 0x1005D],
+ [0x10080, 0x100FA],
+ [0x10140, 0x10174],
+ [0x10280, 0x1029C],
+ [0x102A0, 0x102D0],
+ [0x10300, 0x1031F],
+ [0x1032D, 0x1034A],
+ [0x10350, 0x10375],
+ [0x10380, 0x1039D],
+ [0x103A0, 0x103C3],
+ [0x103C8, 0x103CF],
+ [0x103D1, 0x103D5],
+ [0x10400, 0x1049D],
+ [0x104B0, 0x104D3],
+ [0x104D8, 0x104FB],
+ [0x10500, 0x10527],
+ [0x10530, 0x10563],
+ [0x10570, 0x1057A],
+ [0x1057C, 0x1058A],
+ [0x1058C, 0x10592],
+ [0x10594, 0x10595],
+ [0x10597, 0x105A1],
+ [0x105A3, 0x105B1],
+ [0x105B3, 0x105B9],
+ [0x105BB, 0x105BC],
+ [0x10600, 0x10736],
+ [0x10740, 0x10755],
+ [0x10760, 0x10767],
+ [0x10780, 0x10785],
+ [0x10787, 0x107B0],
+ [0x107B2, 0x107BA],
+ [0x10800, 0x10805],
+ [0x10808, 0x10808],
+ [0x1080A, 0x10835],
+ [0x10837, 0x10838],
+ [0x1083C, 0x1083C],
+ [0x1083F, 0x10855],
+ [0x10860, 0x10876],
+ [0x10880, 0x1089E],
+ [0x108E0, 0x108F2],
+ [0x108F4, 0x108F5],
+ [0x10900, 0x10915],
+ [0x10920, 0x10939],
+ [0x10980, 0x109B7],
+ [0x109BE, 0x109BF],
+ [0x10A00, 0x10A00],
+ [0x10A10, 0x10A13],
+ [0x10A15, 0x10A17],
+ [0x10A19, 0x10A35],
+ [0x10A60, 0x10A7C],
+ [0x10A80, 0x10A9C],
+ [0x10AC0, 0x10AC7],
+ [0x10AC9, 0x10AE4],
+ [0x10B00, 0x10B35],
+ [0x10B40, 0x10B55],
+ [0x10B60, 0x10B72],
+ [0x10B80, 0x10B91],
+ [0x10C00, 0x10C48],
+ [0x10C80, 0x10CB2],
+ [0x10CC0, 0x10CF2],
+ [0x10D00, 0x10D23],
+ [0x10E80, 0x10EA9],
+ [0x10EB0, 0x10EB1],
+ [0x10F00, 0x10F1C],
+ [0x10F27, 0x10F27],
+ [0x10F30, 0x10F45],
+ [0x10F70, 0x10F81],
+ [0x10FB0, 0x10FC4],
+ [0x10FE0, 0x10FF6],
+ [0x11003, 0x11037],
+ [0x11071, 0x11072],
+ [0x11075, 0x11075],
+ [0x11083, 0x110AF],
+ [0x110D0, 0x110E8],
+ [0x11103, 0x11126],
+ [0x11144, 0x11144],
+ [0x11147, 0x11147],
+ [0x11150, 0x11172],
+ [0x11176, 0x11176],
+ [0x11183, 0x111B2],
+ [0x111C1, 0x111C4],
+ [0x111DA, 0x111DA],
+ [0x111DC, 0x111DC],
+ [0x11200, 0x11211],
+ [0x11213, 0x1122B],
+ [0x1123F, 0x11240],
+ [0x11280, 0x11286],
+ [0x11288, 0x11288],
+ [0x1128A, 0x1128D],
+ [0x1128F, 0x1129D],
+ [0x1129F, 0x112A8],
+ [0x112B0, 0x112DE],
+ [0x11305, 0x1130C],
+ [0x1130F, 0x11310],
+ [0x11313, 0x11328],
+ [0x1132A, 0x11330],
+ [0x11332, 0x11333],
+ [0x11335, 0x11339],
+ [0x1133D, 0x1133D],
+ [0x11350, 0x11350],
+ [0x1135D, 0x11361],
+ [0x11400, 0x11434],
+ [0x11447, 0x1144A],
+ [0x1145F, 0x11461],
+ [0x11480, 0x114AF],
+ [0x114C4, 0x114C5],
+ [0x114C7, 0x114C7],
+ [0x11580, 0x115AE],
+ [0x115D8, 0x115DB],
+ [0x11600, 0x1162F],
+ [0x11644, 0x11644],
+ [0x11680, 0x116AA],
+ [0x116B8, 0x116B8],
+ [0x11700, 0x1171A],
+ [0x11740, 0x11746],
+ [0x11800, 0x1182B],
+ [0x118A0, 0x118DF],
+ [0x118FF, 0x11906],
+ [0x11909, 0x11909],
+ [0x1190C, 0x11913],
+ [0x11915, 0x11916],
+ [0x11918, 0x1192F],
+ [0x1193F, 0x1193F],
+ [0x11941, 0x11941],
+ [0x119A0, 0x119A7],
+ [0x119AA, 0x119D0],
+ [0x119E1, 0x119E1],
+ [0x119E3, 0x119E3],
+ [0x11A00, 0x11A00],
+ [0x11A0B, 0x11A32],
+ [0x11A3A, 0x11A3A],
+ [0x11A50, 0x11A50],
+ [0x11A5C, 0x11A89],
+ [0x11A9D, 0x11A9D],
+ [0x11AB0, 0x11AF8],
+ [0x11C00, 0x11C08],
+ [0x11C0A, 0x11C2E],
+ [0x11C40, 0x11C40],
+ [0x11C72, 0x11C8F],
+ [0x11D00, 0x11D06],
+ [0x11D08, 0x11D09],
+ [0x11D0B, 0x11D30],
+ [0x11D46, 0x11D46],
+ [0x11D60, 0x11D65],
+ [0x11D67, 0x11D68],
+ [0x11D6A, 0x11D89],
+ [0x11D98, 0x11D98],
+ [0x11EE0, 0x11EF2],
+ [0x11F02, 0x11F02],
+ [0x11F04, 0x11F10],
+ [0x11F12, 0x11F33],
+ [0x11FB0, 0x11FB0],
+ [0x12000, 0x12399],
+ [0x12400, 0x1246E],
+ [0x12480, 0x12543],
+ [0x12F90, 0x12FF0],
+ [0x13000, 0x1342F],
+ [0x13441, 0x13446],
+ [0x14400, 0x14646],
+ [0x16800, 0x16A38],
+ [0x16A40, 0x16A5E],
+ [0x16A70, 0x16ABE],
+ [0x16AD0, 0x16AED],
+ [0x16B00, 0x16B2F],
+ [0x16B40, 0x16B43],
+ [0x16B63, 0x16B77],
+ [0x16B7D, 0x16B8F],
+ [0x16E40, 0x16E7F],
+ [0x16F00, 0x16F4A],
+ [0x16F50, 0x16F50],
+ [0x16F93, 0x16F9F],
+ [0x16FE0, 0x16FE1],
+ [0x16FE3, 0x16FE3],
+ [0x17000, 0x187F7],
+ [0x18800, 0x18CD5],
+ [0x18D00, 0x18D08],
+ [0x1AFF0, 0x1AFF3],
+ [0x1AFF5, 0x1AFFB],
+ [0x1AFFD, 0x1AFFE],
+ [0x1B000, 0x1B122],
+ [0x1B132, 0x1B132],
+ [0x1B150, 0x1B152],
+ [0x1B155, 0x1B155],
+ [0x1B164, 0x1B167],
+ [0x1B170, 0x1B2FB],
+ [0x1BC00, 0x1BC6A],
+ [0x1BC70, 0x1BC7C],
+ [0x1BC80, 0x1BC88],
+ [0x1BC90, 0x1BC99],
+ [0x1D400, 0x1D454],
+ [0x1D456, 0x1D49C],
+ [0x1D49E, 0x1D49F],
+ [0x1D4A2, 0x1D4A2],
+ [0x1D4A5, 0x1D4A6],
+ [0x1D4A9, 0x1D4AC],
+ [0x1D4AE, 0x1D4B9],
+ [0x1D4BB, 0x1D4BB],
+ [0x1D4BD, 0x1D4C3],
+ [0x1D4C5, 0x1D505],
+ [0x1D507, 0x1D50A],
+ [0x1D50D, 0x1D514],
+ [0x1D516, 0x1D51C],
+ [0x1D51E, 0x1D539],
+ [0x1D53B, 0x1D53E],
+ [0x1D540, 0x1D544],
+ [0x1D546, 0x1D546],
+ [0x1D54A, 0x1D550],
+ [0x1D552, 0x1D6A5],
+ [0x1D6A8, 0x1D6C0],
+ [0x1D6C2, 0x1D6DA],
+ [0x1D6DC, 0x1D6FA],
+ [0x1D6FC, 0x1D714],
+ [0x1D716, 0x1D734],
+ [0x1D736, 0x1D74E],
+ [0x1D750, 0x1D76E],
+ [0x1D770, 0x1D788],
+ [0x1D78A, 0x1D7A8],
+ [0x1D7AA, 0x1D7C2],
+ [0x1D7C4, 0x1D7CB],
+ [0x1DF00, 0x1DF1E],
+ [0x1DF25, 0x1DF2A],
+ [0x1E030, 0x1E06D],
+ [0x1E100, 0x1E12C],
+ [0x1E137, 0x1E13D],
+ [0x1E14E, 0x1E14E],
+ [0x1E290, 0x1E2AD],
+ [0x1E2C0, 0x1E2EB],
+ [0x1E4D0, 0x1E4EB],
+ [0x1E7E0, 0x1E7E6],
+ [0x1E7E8, 0x1E7EB],
+ [0x1E7ED, 0x1E7EE],
+ [0x1E7F0, 0x1E7FE],
+ [0x1E800, 0x1E8C4],
+ [0x1E900, 0x1E943],
+ [0x1E94B, 0x1E94B],
+ [0x1EE00, 0x1EE03],
+ [0x1EE05, 0x1EE1F],
+ [0x1EE21, 0x1EE22],
+ [0x1EE24, 0x1EE24],
+ [0x1EE27, 0x1EE27],
+ [0x1EE29, 0x1EE32],
+ [0x1EE34, 0x1EE37],
+ [0x1EE39, 0x1EE39],
+ [0x1EE3B, 0x1EE3B],
+ [0x1EE42, 0x1EE42],
+ [0x1EE47, 0x1EE47],
+ [0x1EE49, 0x1EE49],
+ [0x1EE4B, 0x1EE4B],
+ [0x1EE4D, 0x1EE4F],
+ [0x1EE51, 0x1EE52],
+ [0x1EE54, 0x1EE54],
+ [0x1EE57, 0x1EE57],
+ [0x1EE59, 0x1EE59],
+ [0x1EE5B, 0x1EE5B],
+ [0x1EE5D, 0x1EE5D],
+ [0x1EE5F, 0x1EE5F],
+ [0x1EE61, 0x1EE62],
+ [0x1EE64, 0x1EE64],
+ [0x1EE67, 0x1EE6A],
+ [0x1EE6C, 0x1EE72],
+ [0x1EE74, 0x1EE77],
+ [0x1EE79, 0x1EE7C],
+ [0x1EE7E, 0x1EE7E],
+ [0x1EE80, 0x1EE89],
+ [0x1EE8B, 0x1EE9B],
+ [0x1EEA1, 0x1EEA3],
+ [0x1EEA5, 0x1EEA9],
+ [0x1EEAB, 0x1EEBB],
+ [0x20000, 0x2B739],
+ [0x2B740, 0x2B81D],
+ [0x2B820, 0x2CEA1],
+ [0x2CEB0, 0x2EBE0],
+ [0x2EBF0, 0x2EE5D],
+ [0x2F800, 0x2FA1D],
+ [0x30000, 0x323AF],
+ [0x40000, 0x4FFFD],
+ [0x50000, 0x5FFFD],
+ [0x60000, 0x6FFFD],
+ [0x70000, 0x7FFFD],
+ [0x80000, 0x8FFFD],
+ [0x90000, 0x9FFFD],
+ [0xA0000, 0xAFFFD],
+ [0xB0000, 0xBFFFD],
+ [0xC0000, 0xCFFFD],
+ [0xD0000, 0xDFFFD],
+ [0xE0000, 0xEFFFD],
+];
+
+/**
+Least restrictive Continue
+Entries: 796056
+*/
+static immutable dchar[2][] LeastRestrictive_Continue = [
+ [0xA8, 0xA8],
+ [0xAA, 0xAA],
+ [0xAD, 0xAD],
+ [0xAF, 0xAF],
+ [0xB2, 0xB5],
+ [0xB7, 0xBA],
+ [0xBC, 0xBE],
+ [0xC0, 0xD6],
+ [0xD8, 0xF6],
+ [0xF8, 0x217],
+ [0x250, 0x2A8],
+ [0x2B0, 0x2B8],
+ [0x2BB, 0x2BB],
+ [0x2BD, 0x2C1],
+ [0x2C6, 0x2D1],
+ [0x2E0, 0x2E4],
+ [0x2EC, 0x2EC],
+ [0x2EE, 0x2EE],
+ [0x300, 0x374],
+ [0x376, 0x377],
+ [0x37A, 0x37D],
+ [0x37F, 0x37F],
+ [0x386, 0x386],
+ [0x388, 0x38A],
+ [0x38C, 0x38C],
+ [0x38E, 0x3A1],
+ [0x3A3, 0x3D6],
+ [0x3DA, 0x3DA],
+ [0x3DC, 0x3DC],
+ [0x3DE, 0x3DE],
+ [0x3E0, 0x3E0],
+ [0x3E2, 0x3F3],
+ [0x3F7, 0x40C],
+ [0x40E, 0x44F],
+ [0x451, 0x45C],
+ [0x45E, 0x481],
+ [0x483, 0x487],
+ [0x48A, 0x4C4],
+ [0x4C7, 0x4C8],
+ [0x4CB, 0x4CC],
+ [0x4D0, 0x4EB],
+ [0x4EE, 0x4F5],
+ [0x4F8, 0x4F9],
+ [0x531, 0x556],
+ [0x559, 0x559],
+ [0x560, 0x587],
+ [0x591, 0x5B9],
+ [0x5BB, 0x5BD],
+ [0x5BF, 0x5BF],
+ [0x5C1, 0x5C2],
+ [0x5C4, 0x5C5],
+ [0x5C7, 0x5C7],
+ [0x5D0, 0x5EA],
+ [0x5EF, 0x5F2],
+ [0x610, 0x61A],
+ [0x620, 0x63A],
+ [0x640, 0x652],
+ [0x660, 0x669],
+ [0x66E, 0x6B7],
+ [0x6BA, 0x6BE],
+ [0x6C0, 0x6CE],
+ [0x6D0, 0x6DC],
+ [0x6DF, 0x6E8],
+ [0x6EA, 0x6ED],
+ [0x6F0, 0x6F9],
+ [0x6FF, 0x6FF],
+ [0x710, 0x74A],
+ [0x74D, 0x7B1],
+ [0x7C0, 0x7F5],
+ [0x7FA, 0x7FA],
+ [0x7FD, 0x7FD],
+ [0x800, 0x82D],
+ [0x840, 0x85B],
+ [0x860, 0x86A],
+ [0x870, 0x887],
+ [0x889, 0x88E],
+ [0x898, 0x8E1],
+ [0x8E3, 0x903],
+ [0x905, 0x939],
+ [0x93D, 0x94D],
+ [0x950, 0x952],
+ [0x958, 0x963],
+ [0x966, 0x96F],
+ [0x971, 0x983],
+ [0x985, 0x98C],
+ [0x98F, 0x990],
+ [0x993, 0x9A8],
+ [0x9AA, 0x9B0],
+ [0x9B2, 0x9B2],
+ [0x9B6, 0x9B9],
+ [0x9BC, 0x9C4],
+ [0x9C7, 0x9C8],
+ [0x9CB, 0x9CD],
+ [0x9D7, 0x9D7],
+ [0x9DC, 0x9DD],
+ [0x9DF, 0x9E3],
+ [0x9E6, 0x9F1],
+ [0x9FC, 0x9FC],
+ [0x9FE, 0x9FE],
+ [0xA01, 0xA02],
+ [0xA05, 0xA0A],
+ [0xA0F, 0xA10],
+ [0xA13, 0xA28],
+ [0xA2A, 0xA30],
+ [0xA32, 0xA33],
+ [0xA35, 0xA36],
+ [0xA38, 0xA39],
+ [0xA3C, 0xA3C],
+ [0xA3E, 0xA42],
+ [0xA47, 0xA48],
+ [0xA4B, 0xA4D],
+ [0xA51, 0xA51],
+ [0xA59, 0xA5C],
+ [0xA5E, 0xA5E],
+ [0xA66, 0xA6F],
+ [0xA74, 0xA74],
+ [0xA81, 0xA83],
+ [0xA85, 0xA8B],
+ [0xA8D, 0xA8D],
+ [0xA8F, 0xA91],
+ [0xA93, 0xAA8],
+ [0xAAA, 0xAB0],
+ [0xAB2, 0xAB3],
+ [0xAB5, 0xAB9],
+ [0xABC, 0xAC5],
+ [0xAC7, 0xAC9],
+ [0xACB, 0xACD],
+ [0xAD0, 0xAD0],
+ [0xAE0, 0xAE0],
+ [0xAE6, 0xAEF],
+ [0xAF9, 0xAFF],
+ [0xB01, 0xB03],
+ [0xB05, 0xB0C],
+ [0xB0F, 0xB10],
+ [0xB13, 0xB28],
+ [0xB2A, 0xB30],
+ [0xB32, 0xB33],
+ [0xB35, 0xB39],
+ [0xB3C, 0xB43],
+ [0xB47, 0xB48],
+ [0xB4B, 0xB4D],
+ [0xB55, 0xB57],
+ [0xB5C, 0xB5D],
+ [0xB5F, 0xB61],
+ [0xB66, 0xB6F],
+ [0xB71, 0xB71],
+ [0xB82, 0xB83],
+ [0xB85, 0xB8A],
+ [0xB8E, 0xB90],
+ [0xB92, 0xB95],
+ [0xB99, 0xB9A],
+ [0xB9C, 0xB9C],
+ [0xB9E, 0xB9F],
+ [0xBA3, 0xBA4],
+ [0xBA8, 0xBAA],
+ [0xBAE, 0xBB5],
+ [0xBB7, 0xBB9],
+ [0xBBE, 0xBC2],
+ [0xBC6, 0xBC8],
+ [0xBCA, 0xBCD],
+ [0xBD0, 0xBD0],
+ [0xBD7, 0xBD7],
+ [0xBE6, 0xBEF],
+ [0xC00, 0xC03],
+ [0xC05, 0xC0C],
+ [0xC0E, 0xC10],
+ [0xC12, 0xC28],
+ [0xC2A, 0xC33],
+ [0xC35, 0xC39],
+ [0xC3C, 0xC44],
+ [0xC46, 0xC48],
+ [0xC4A, 0xC4D],
+ [0xC55, 0xC56],
+ [0xC58, 0xC5A],
+ [0xC5D, 0xC5D],
+ [0xC60, 0xC61],
+ [0xC66, 0xC6F],
+ [0xC80, 0xC83],
+ [0xC85, 0xC8C],
+ [0xC8E, 0xC90],
+ [0xC92, 0xCA8],
+ [0xCAA, 0xCB3],
+ [0xCB5, 0xCB9],
+ [0xCBC, 0xCC4],
+ [0xCC6, 0xCC8],
+ [0xCCA, 0xCCD],
+ [0xCD5, 0xCD6],
+ [0xCDD, 0xCDE],
+ [0xCE0, 0xCE1],
+ [0xCE6, 0xCEF],
+ [0xCF1, 0xCF3],
+ [0xD00, 0xD03],
+ [0xD05, 0xD0C],
+ [0xD0E, 0xD10],
+ [0xD12, 0xD39],
+ [0xD3E, 0xD43],
+ [0xD46, 0xD48],
+ [0xD4A, 0xD4E],
+ [0xD54, 0xD57],
+ [0xD5F, 0xD61],
+ [0xD66, 0xD6F],
+ [0xD7A, 0xD7F],
+ [0xD81, 0xD83],
+ [0xD85, 0xD96],
+ [0xD9A, 0xDB1],
+ [0xDB3, 0xDBB],
+ [0xDBD, 0xDBD],
+ [0xDC0, 0xDC6],
+ [0xDCA, 0xDCA],
+ [0xDCF, 0xDD4],
+ [0xDD6, 0xDD6],
+ [0xDD8, 0xDDF],
+ [0xDE6, 0xDEF],
+ [0xDF2, 0xDF3],
+ [0xE01, 0xE3A],
+ [0xE40, 0xE4E],
+ [0xE50, 0xE59],
+ [0xE81, 0xE82],
+ [0xE84, 0xE84],
+ [0xE86, 0xE88],
+ [0xE8A, 0xE8A],
+ [0xE8C, 0xE8D],
+ [0xE94, 0xE97],
+ [0xE99, 0xE9F],
+ [0xEA1, 0xEA3],
+ [0xEA5, 0xEA5],
+ [0xEA7, 0xEAB],
+ [0xEAD, 0xEAE],
+ [0xEB0, 0xEB9],
+ [0xEBB, 0xEBD],
+ [0xEC0, 0xEC4],
+ [0xEC6, 0xEC6],
+ [0xEC8, 0xECE],
+ [0xED0, 0xED9],
+ [0xEDC, 0xEDF],
+ [0xF00, 0xF00],
+ [0xF18, 0xF19],
+ [0xF20, 0xF29],
+ [0xF35, 0xF35],
+ [0xF37, 0xF37],
+ [0xF39, 0xF39],
+ [0xF3E, 0xF47],
+ [0xF49, 0xF6C],
+ [0xF71, 0xF84],
+ [0xF86, 0xF95],
+ [0xF97, 0xF97],
+ [0xF99, 0xFB7],
+ [0xFB9, 0xFB9],
+ [0xFC6, 0xFC6],
+ [0x1000, 0x1049],
+ [0x1050, 0x109D],
+ [0x10A0, 0x10C5],
+ [0x10C7, 0x10C7],
+ [0x10CD, 0x10CD],
+ [0x10D0, 0x10FA],
+ [0x10FC, 0x1248],
+ [0x124A, 0x124D],
+ [0x1250, 0x1256],
+ [0x1258, 0x1258],
+ [0x125A, 0x125D],
+ [0x1260, 0x1288],
+ [0x128A, 0x128D],
+ [0x1290, 0x12B0],
+ [0x12B2, 0x12B5],
+ [0x12B8, 0x12BE],
+ [0x12C0, 0x12C0],
+ [0x12C2, 0x12C5],
+ [0x12C8, 0x12D6],
+ [0x12D8, 0x1310],
+ [0x1312, 0x1315],
+ [0x1318, 0x135A],
+ [0x135D, 0x135F],
+ [0x1369, 0x1371],
+ [0x1380, 0x138F],
+ [0x13A0, 0x13F5],
+ [0x13F8, 0x13FD],
+ [0x1401, 0x166C],
+ [0x166F, 0x167F],
+ [0x1681, 0x169A],
+ [0x16A0, 0x16EA],
+ [0x16EE, 0x16F8],
+ [0x1700, 0x1715],
+ [0x171F, 0x1734],
+ [0x1740, 0x1753],
+ [0x1760, 0x176C],
+ [0x176E, 0x1770],
+ [0x1772, 0x1773],
+ [0x1780, 0x17D3],
+ [0x17D7, 0x17D7],
+ [0x17DC, 0x17DD],
+ [0x17E0, 0x17E9],
+ [0x180B, 0x180D],
+ [0x180F, 0x1819],
+ [0x1820, 0x1878],
+ [0x1880, 0x18AA],
+ [0x18B0, 0x18F5],
+ [0x1900, 0x191E],
+ [0x1920, 0x192B],
+ [0x1930, 0x193B],
+ [0x1946, 0x196D],
+ [0x1970, 0x1974],
+ [0x1980, 0x19AB],
+ [0x19B0, 0x19C9],
+ [0x19D0, 0x19DA],
+ [0x1A00, 0x1A1B],
+ [0x1A20, 0x1A5E],
+ [0x1A60, 0x1A7C],
+ [0x1A7F, 0x1A89],
+ [0x1A90, 0x1A99],
+ [0x1AA7, 0x1AA7],
+ [0x1AB0, 0x1ABD],
+ [0x1ABF, 0x1ACE],
+ [0x1B00, 0x1B4C],
+ [0x1B50, 0x1B59],
+ [0x1B6B, 0x1B73],
+ [0x1B80, 0x1BF3],
+ [0x1C00, 0x1C37],
+ [0x1C40, 0x1C49],
+ [0x1C4D, 0x1C7D],
+ [0x1C80, 0x1C88],
+ [0x1C90, 0x1CBA],
+ [0x1CBD, 0x1CBF],
+ [0x1CD0, 0x1CD2],
+ [0x1CD4, 0x1CFA],
+ [0x1D00, 0x1EF9],
+ [0x1F00, 0x1F15],
+ [0x1F18, 0x1F1D],
+ [0x1F20, 0x1F45],
+ [0x1F48, 0x1F4D],
+ [0x1F50, 0x1F57],
+ [0x1F59, 0x1F59],
+ [0x1F5B, 0x1F5B],
+ [0x1F5D, 0x1F5D],
+ [0x1F5F, 0x1F7D],
+ [0x1F80, 0x1FB4],
+ [0x1FB6, 0x1FBC],
+ [0x1FBE, 0x1FBE],
+ [0x1FC2, 0x1FC4],
+ [0x1FC6, 0x1FCC],
+ [0x1FD0, 0x1FD3],
+ [0x1FD6, 0x1FDB],
+ [0x1FE0, 0x1FEC],
+ [0x1FF2, 0x1FF4],
+ [0x1FF6, 0x1FFC],
+ [0x200B, 0x200D],
+ [0x202A, 0x202E],
+ [0x203F, 0x2040],
+ [0x2054, 0x2054],
+ [0x2060, 0x2071],
+ [0x207F, 0x207F],
+ [0x2090, 0x209C],
+ [0x20D0, 0x20DC],
+ [0x20E1, 0x20E1],
+ [0x20E5, 0x20F0],
+ [0x2102, 0x2102],
+ [0x2107, 0x2107],
+ [0x210A, 0x2113],
+ [0x2115, 0x2115],
+ [0x2118, 0x211D],
+ [0x2124, 0x2124],
+ [0x2126, 0x2126],
+ [0x2128, 0x2128],
+ [0x212A, 0x2138],
+ [0x213C, 0x213F],
+ [0x2145, 0x2149],
+ [0x214E, 0x214E],
+ [0x2160, 0x2188],
+ [0x2460, 0x24FF],
+ [0x2776, 0x2793],
+ [0x2C00, 0x2CE4],
+ [0x2CEB, 0x2CF3],
+ [0x2D00, 0x2D25],
+ [0x2D27, 0x2D27],
+ [0x2D2D, 0x2D2D],
+ [0x2D30, 0x2D67],
+ [0x2D6F, 0x2D6F],
+ [0x2D7F, 0x2D96],
+ [0x2DA0, 0x2DA6],
+ [0x2DA8, 0x2DAE],
+ [0x2DB0, 0x2DB6],
+ [0x2DB8, 0x2DBE],
+ [0x2DC0, 0x2DC6],
+ [0x2DC8, 0x2DCE],
+ [0x2DD0, 0x2DD6],
+ [0x2DD8, 0x2DDE],
+ [0x2DE0, 0x2DFF],
+ [0x2E80, 0x2FFF],
+ [0x3004, 0x3007],
+ [0x3021, 0x302F],
+ [0x3031, 0x303C],
+ [0x3041, 0x3096],
+ [0x3099, 0x309F],
+ [0x30A1, 0x30FC],
+ [0x3105, 0x312F],
+ [0x3131, 0x318E],
+ [0x31A0, 0x31BF],
+ [0x31F0, 0x31FF],
+ [0x3400, 0x4DBF],
+ [0x4E00, 0xA48C],
+ [0xA4D0, 0xA4FD],
+ [0xA500, 0xA60C],
+ [0xA610, 0xA62B],
+ [0xA640, 0xA66F],
+ [0xA674, 0xA67D],
+ [0xA67F, 0xA6F1],
+ [0xA717, 0xA71F],
+ [0xA722, 0xA788],
+ [0xA78B, 0xA7CA],
+ [0xA7D0, 0xA7D1],
+ [0xA7D3, 0xA7D3],
+ [0xA7D5, 0xA7D9],
+ [0xA7F2, 0xA827],
+ [0xA82C, 0xA82C],
+ [0xA840, 0xA873],
+ [0xA880, 0xA8C5],
+ [0xA8D0, 0xA8D9],
+ [0xA8E0, 0xA8F7],
+ [0xA8FB, 0xA8FB],
+ [0xA8FD, 0xA92D],
+ [0xA930, 0xA953],
+ [0xA960, 0xA97C],
+ [0xA980, 0xA9C0],
+ [0xA9CF, 0xA9D9],
+ [0xA9E0, 0xA9FE],
+ [0xAA00, 0xAA36],
+ [0xAA40, 0xAA4D],
+ [0xAA50, 0xAA59],
+ [0xAA60, 0xAA76],
+ [0xAA7A, 0xAAC2],
+ [0xAADB, 0xAADD],
+ [0xAAE0, 0xAAEF],
+ [0xAAF2, 0xAAF6],
+ [0xAB01, 0xAB06],
+ [0xAB09, 0xAB0E],
+ [0xAB11, 0xAB16],
+ [0xAB20, 0xAB26],
+ [0xAB28, 0xAB2E],
+ [0xAB30, 0xAB5A],
+ [0xAB5C, 0xAB69],
+ [0xAB70, 0xABEA],
+ [0xABEC, 0xABED],
+ [0xABF0, 0xABF9],
+ [0xAC00, 0xD7A3],
+ [0xD7B0, 0xD7C6],
+ [0xD7CB, 0xD7FB],
+ [0xF900, 0xFA6D],
+ [0xFA70, 0xFAD9],
+ [0xFB00, 0xFB06],
+ [0xFB13, 0xFB17],
+ [0xFB1D, 0xFB28],
+ [0xFB2A, 0xFB36],
+ [0xFB38, 0xFB3C],
+ [0xFB3E, 0xFB3E],
+ [0xFB40, 0xFB41],
+ [0xFB43, 0xFB44],
+ [0xFB46, 0xFBB1],
+ [0xFBD3, 0xFC5D],
+ [0xFC64, 0xFD3D],
+ [0xFD40, 0xFD8F],
+ [0xFD92, 0xFDC7],
+ [0xFDF0, 0xFDF9],
+ [0xFE00, 0xFE0F],
+ [0xFE20, 0xFE2F],
+ [0xFE33, 0xFE34],
+ [0xFE47, 0xFE4F],
+ [0xFE71, 0xFE71],
+ [0xFE73, 0xFE73],
+ [0xFE77, 0xFE77],
+ [0xFE79, 0xFE79],
+ [0xFE7B, 0xFE7B],
+ [0xFE7D, 0xFE7D],
+ [0xFE7F, 0xFEFC],
+ [0xFF10, 0xFF19],
+ [0xFF21, 0xFF3A],
+ [0xFF3F, 0xFF3F],
+ [0xFF41, 0xFF5A],
+ [0xFF65, 0xFFBE],
+ [0xFFC2, 0xFFC7],
+ [0xFFCA, 0xFFCF],
+ [0xFFD2, 0xFFD7],
+ [0xFFDA, 0xFFDC],
+ [0x10000, 0x1000B],
+ [0x1000D, 0x10026],
+ [0x10028, 0x1003A],
+ [0x1003C, 0x1003D],
+ [0x1003F, 0x1004D],
+ [0x10050, 0x1005D],
+ [0x10080, 0x100FA],
+ [0x10140, 0x10174],
+ [0x101FD, 0x101FD],
+ [0x10280, 0x1029C],
+ [0x102A0, 0x102D0],
+ [0x102E0, 0x102E0],
+ [0x10300, 0x1031F],
+ [0x1032D, 0x1034A],
+ [0x10350, 0x1037A],
+ [0x10380, 0x1039D],
+ [0x103A0, 0x103C3],
+ [0x103C8, 0x103CF],
+ [0x103D1, 0x103D5],
+ [0x10400, 0x1049D],
+ [0x104A0, 0x104A9],
+ [0x104B0, 0x104D3],
+ [0x104D8, 0x104FB],
+ [0x10500, 0x10527],
+ [0x10530, 0x10563],
+ [0x10570, 0x1057A],
+ [0x1057C, 0x1058A],
+ [0x1058C, 0x10592],
+ [0x10594, 0x10595],
+ [0x10597, 0x105A1],
+ [0x105A3, 0x105B1],
+ [0x105B3, 0x105B9],
+ [0x105BB, 0x105BC],
+ [0x10600, 0x10736],
+ [0x10740, 0x10755],
+ [0x10760, 0x10767],
+ [0x10780, 0x10785],
+ [0x10787, 0x107B0],
+ [0x107B2, 0x107BA],
+ [0x10800, 0x10805],
+ [0x10808, 0x10808],
+ [0x1080A, 0x10835],
+ [0x10837, 0x10838],
+ [0x1083C, 0x1083C],
+ [0x1083F, 0x10855],
+ [0x10860, 0x10876],
+ [0x10880, 0x1089E],
+ [0x108E0, 0x108F2],
+ [0x108F4, 0x108F5],
+ [0x10900, 0x10915],
+ [0x10920, 0x10939],
+ [0x10980, 0x109B7],
+ [0x109BE, 0x109BF],
+ [0x10A00, 0x10A03],
+ [0x10A05, 0x10A06],
+ [0x10A0C, 0x10A13],
+ [0x10A15, 0x10A17],
+ [0x10A19, 0x10A35],
+ [0x10A38, 0x10A3A],
+ [0x10A3F, 0x10A3F],
+ [0x10A60, 0x10A7C],
+ [0x10A80, 0x10A9C],
+ [0x10AC0, 0x10AC7],
+ [0x10AC9, 0x10AE6],
+ [0x10B00, 0x10B35],
+ [0x10B40, 0x10B55],
+ [0x10B60, 0x10B72],
+ [0x10B80, 0x10B91],
+ [0x10C00, 0x10C48],
+ [0x10C80, 0x10CB2],
+ [0x10CC0, 0x10CF2],
+ [0x10D00, 0x10D27],
+ [0x10D30, 0x10D39],
+ [0x10E80, 0x10EA9],
+ [0x10EAB, 0x10EAC],
+ [0x10EB0, 0x10EB1],
+ [0x10EFD, 0x10F1C],
+ [0x10F27, 0x10F27],
+ [0x10F30, 0x10F50],
+ [0x10F70, 0x10F85],
+ [0x10FB0, 0x10FC4],
+ [0x10FE0, 0x10FF6],
+ [0x11000, 0x11046],
+ [0x11066, 0x11075],
+ [0x1107F, 0x110BA],
+ [0x110C2, 0x110C2],
+ [0x110D0, 0x110E8],
+ [0x110F0, 0x110F9],
+ [0x11100, 0x11134],
+ [0x11136, 0x1113F],
+ [0x11144, 0x11147],
+ [0x11150, 0x11173],
+ [0x11176, 0x11176],
+ [0x11180, 0x111C4],
+ [0x111C9, 0x111CC],
+ [0x111CE, 0x111DA],
+ [0x111DC, 0x111DC],
+ [0x11200, 0x11211],
+ [0x11213, 0x11237],
+ [0x1123E, 0x11241],
+ [0x11280, 0x11286],
+ [0x11288, 0x11288],
+ [0x1128A, 0x1128D],
+ [0x1128F, 0x1129D],
+ [0x1129F, 0x112A8],
+ [0x112B0, 0x112EA],
+ [0x112F0, 0x112F9],
+ [0x11300, 0x11303],
+ [0x11305, 0x1130C],
+ [0x1130F, 0x11310],
+ [0x11313, 0x11328],
+ [0x1132A, 0x11330],
+ [0x11332, 0x11333],
+ [0x11335, 0x11339],
+ [0x1133B, 0x11344],
+ [0x11347, 0x11348],
+ [0x1134B, 0x1134D],
+ [0x11350, 0x11350],
+ [0x11357, 0x11357],
+ [0x1135D, 0x11363],
+ [0x11366, 0x1136C],
+ [0x11370, 0x11374],
+ [0x11400, 0x1144A],
+ [0x11450, 0x11459],
+ [0x1145E, 0x11461],
+ [0x11480, 0x114C5],
+ [0x114C7, 0x114C7],
+ [0x114D0, 0x114D9],
+ [0x11580, 0x115B5],
+ [0x115B8, 0x115C0],
+ [0x115D8, 0x115DD],
+ [0x11600, 0x11640],
+ [0x11644, 0x11644],
+ [0x11650, 0x11659],
+ [0x11680, 0x116B8],
+ [0x116C0, 0x116C9],
+ [0x11700, 0x1171A],
+ [0x1171D, 0x1172B],
+ [0x11730, 0x11739],
+ [0x11740, 0x11746],
+ [0x11800, 0x1183A],
+ [0x118A0, 0x118E9],
+ [0x118FF, 0x11906],
+ [0x11909, 0x11909],
+ [0x1190C, 0x11913],
+ [0x11915, 0x11916],
+ [0x11918, 0x11935],
+ [0x11937, 0x11938],
+ [0x1193B, 0x11943],
+ [0x11950, 0x11959],
+ [0x119A0, 0x119A7],
+ [0x119AA, 0x119D7],
+ [0x119DA, 0x119E1],
+ [0x119E3, 0x119E4],
+ [0x11A00, 0x11A3E],
+ [0x11A47, 0x11A47],
+ [0x11A50, 0x11A99],
+ [0x11A9D, 0x11A9D],
+ [0x11AB0, 0x11AF8],
+ [0x11C00, 0x11C08],
+ [0x11C0A, 0x11C36],
+ [0x11C38, 0x11C40],
+ [0x11C50, 0x11C59],
+ [0x11C72, 0x11C8F],
+ [0x11C92, 0x11CA7],
+ [0x11CA9, 0x11CB6],
+ [0x11D00, 0x11D06],
+ [0x11D08, 0x11D09],
+ [0x11D0B, 0x11D36],
+ [0x11D3A, 0x11D3A],
+ [0x11D3C, 0x11D3D],
+ [0x11D3F, 0x11D47],
+ [0x11D50, 0x11D59],
+ [0x11D60, 0x11D65],
+ [0x11D67, 0x11D68],
+ [0x11D6A, 0x11D8E],
+ [0x11D90, 0x11D91],
+ [0x11D93, 0x11D98],
+ [0x11DA0, 0x11DA9],
+ [0x11EE0, 0x11EF6],
+ [0x11F00, 0x11F10],
+ [0x11F12, 0x11F3A],
+ [0x11F3E, 0x11F42],
+ [0x11F50, 0x11F59],
+ [0x11FB0, 0x11FB0],
+ [0x12000, 0x12399],
+ [0x12400, 0x1246E],
+ [0x12480, 0x12543],
+ [0x12F90, 0x12FF0],
+ [0x13000, 0x1342F],
+ [0x13440, 0x13455],
+ [0x14400, 0x14646],
+ [0x16800, 0x16A38],
+ [0x16A40, 0x16A5E],
+ [0x16A60, 0x16A69],
+ [0x16A70, 0x16ABE],
+ [0x16AC0, 0x16AC9],
+ [0x16AD0, 0x16AED],
+ [0x16AF0, 0x16AF4],
+ [0x16B00, 0x16B36],
+ [0x16B40, 0x16B43],
+ [0x16B50, 0x16B59],
+ [0x16B63, 0x16B77],
+ [0x16B7D, 0x16B8F],
+ [0x16E40, 0x16E7F],
+ [0x16F00, 0x16F4A],
+ [0x16F4F, 0x16F87],
+ [0x16F8F, 0x16F9F],
+ [0x16FE0, 0x16FE1],
+ [0x16FE3, 0x16FE4],
+ [0x16FF0, 0x16FF1],
+ [0x17000, 0x187F7],
+ [0x18800, 0x18CD5],
+ [0x18D00, 0x18D08],
+ [0x1AFF0, 0x1AFF3],
+ [0x1AFF5, 0x1AFFB],
+ [0x1AFFD, 0x1AFFE],
+ [0x1B000, 0x1B122],
+ [0x1B132, 0x1B132],
+ [0x1B150, 0x1B152],
+ [0x1B155, 0x1B155],
+ [0x1B164, 0x1B167],
+ [0x1B170, 0x1B2FB],
+ [0x1BC00, 0x1BC6A],
+ [0x1BC70, 0x1BC7C],
+ [0x1BC80, 0x1BC88],
+ [0x1BC90, 0x1BC99],
+ [0x1BC9D, 0x1BC9E],
+ [0x1CF00, 0x1CF2D],
+ [0x1CF30, 0x1CF46],
+ [0x1D165, 0x1D169],
+ [0x1D16D, 0x1D172],
+ [0x1D17B, 0x1D182],
+ [0x1D185, 0x1D18B],
+ [0x1D1AA, 0x1D1AD],
+ [0x1D242, 0x1D244],
+ [0x1D400, 0x1D454],
+ [0x1D456, 0x1D49C],
+ [0x1D49E, 0x1D49F],
+ [0x1D4A2, 0x1D4A2],
+ [0x1D4A5, 0x1D4A6],
+ [0x1D4A9, 0x1D4AC],
+ [0x1D4AE, 0x1D4B9],
+ [0x1D4BB, 0x1D4BB],
+ [0x1D4BD, 0x1D4C3],
+ [0x1D4C5, 0x1D505],
+ [0x1D507, 0x1D50A],
+ [0x1D50D, 0x1D514],
+ [0x1D516, 0x1D51C],
+ [0x1D51E, 0x1D539],
+ [0x1D53B, 0x1D53E],
+ [0x1D540, 0x1D544],
+ [0x1D546, 0x1D546],
+ [0x1D54A, 0x1D550],
+ [0x1D552, 0x1D6A5],
+ [0x1D6A8, 0x1D6C0],
+ [0x1D6C2, 0x1D6DA],
+ [0x1D6DC, 0x1D6FA],
+ [0x1D6FC, 0x1D714],
+ [0x1D716, 0x1D734],
+ [0x1D736, 0x1D74E],
+ [0x1D750, 0x1D76E],
+ [0x1D770, 0x1D788],
+ [0x1D78A, 0x1D7A8],
+ [0x1D7AA, 0x1D7C2],
+ [0x1D7C4, 0x1D7CB],
+ [0x1D7CE, 0x1D7FF],
+ [0x1DA00, 0x1DA36],
+ [0x1DA3B, 0x1DA6C],
+ [0x1DA75, 0x1DA75],
+ [0x1DA84, 0x1DA84],
+ [0x1DA9B, 0x1DA9F],
+ [0x1DAA1, 0x1DAAF],
+ [0x1DF00, 0x1DF1E],
+ [0x1DF25, 0x1DF2A],
+ [0x1E000, 0x1E006],
+ [0x1E008, 0x1E018],
+ [0x1E01B, 0x1E021],
+ [0x1E023, 0x1E024],
+ [0x1E026, 0x1E02A],
+ [0x1E030, 0x1E06D],
+ [0x1E08F, 0x1E08F],
+ [0x1E100, 0x1E12C],
+ [0x1E130, 0x1E13D],
+ [0x1E140, 0x1E149],
+ [0x1E14E, 0x1E14E],
+ [0x1E290, 0x1E2AE],
+ [0x1E2C0, 0x1E2F9],
+ [0x1E4D0, 0x1E4F9],
+ [0x1E7E0, 0x1E7E6],
+ [0x1E7E8, 0x1E7EB],
+ [0x1E7ED, 0x1E7EE],
+ [0x1E7F0, 0x1E7FE],
+ [0x1E800, 0x1E8C4],
+ [0x1E8D0, 0x1E8D6],
+ [0x1E900, 0x1E94B],
+ [0x1E950, 0x1E959],
+ [0x1EE00, 0x1EE03],
+ [0x1EE05, 0x1EE1F],
+ [0x1EE21, 0x1EE22],
+ [0x1EE24, 0x1EE24],
+ [0x1EE27, 0x1EE27],
+ [0x1EE29, 0x1EE32],
+ [0x1EE34, 0x1EE37],
+ [0x1EE39, 0x1EE39],
+ [0x1EE3B, 0x1EE3B],
+ [0x1EE42, 0x1EE42],
+ [0x1EE47, 0x1EE47],
+ [0x1EE49, 0x1EE49],
+ [0x1EE4B, 0x1EE4B],
+ [0x1EE4D, 0x1EE4F],
+ [0x1EE51, 0x1EE52],
+ [0x1EE54, 0x1EE54],
+ [0x1EE57, 0x1EE57],
+ [0x1EE59, 0x1EE59],
+ [0x1EE5B, 0x1EE5B],
+ [0x1EE5D, 0x1EE5D],
+ [0x1EE5F, 0x1EE5F],
+ [0x1EE61, 0x1EE62],
+ [0x1EE64, 0x1EE64],
+ [0x1EE67, 0x1EE6A],
+ [0x1EE6C, 0x1EE72],
+ [0x1EE74, 0x1EE77],
+ [0x1EE79, 0x1EE7C],
+ [0x1EE7E, 0x1EE7E],
+ [0x1EE80, 0x1EE89],
+ [0x1EE8B, 0x1EE9B],
+ [0x1EEA1, 0x1EEA3],
+ [0x1EEA5, 0x1EEA9],
+ [0x1EEAB, 0x1EEBB],
+ [0x1FBF0, 0x1FBF9],
+ [0x20000, 0x2B739],
+ [0x2B740, 0x2B81D],
+ [0x2B820, 0x2CEA1],
+ [0x2CEB0, 0x2EBE0],
+ [0x2EBF0, 0x2EE5D],
+ [0x2F800, 0x2FA1D],
+ [0x30000, 0x323AF],
+ [0x40000, 0x4FFFD],
+ [0x50000, 0x5FFFD],
+ [0x60000, 0x6FFFD],
+ [0x70000, 0x7FFFD],
+ [0x80000, 0x8FFFD],
+ [0x90000, 0x9FFFD],
+ [0xA0000, 0xAFFFD],
+ [0xB0000, 0xBFFFD],
+ [0xC0000, 0xCFFFD],
+ [0xD0000, 0xDFFFD],
+ [0xE0000, 0xE01EF],
+];
diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
index cb2439f..01fc377 100644
--- a/gcc/d/dmd/common/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -1,12 +1,12 @@
/**
* An expandable buffer in which you can write text or binary data.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d, root/_outbuffer.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/outbuffer.d, root/_outbuffer.d)
* Documentation: https://dlang.org/phobos/dmd_root_outbuffer.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/outbuffer.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/common/outbuffer.d
*/
module dmd.common.outbuffer;
@@ -141,7 +141,7 @@ struct OutBuffer
memory buffer. The config variables `notlinehead`, `doindent` etc. are
not changed.
*/
- extern (C++) void destroy() pure nothrow @trusted
+ extern (C++) void destroy() pure nothrow
{
dtor();
fileMapping = null;
@@ -247,7 +247,7 @@ struct OutBuffer
/**
* Writes a 16 bit value, no reserve check.
*/
- @trusted nothrow
+ nothrow @safe
void write16n(int v)
{
auto x = cast(ushort) v;
@@ -367,8 +367,7 @@ struct OutBuffer
}
// Position buffer to accept the specified number of bytes at offset
- @trusted
- void position(size_t where, size_t nbytes) nothrow
+ void position(size_t where, size_t nbytes) nothrow @safe
{
if (where + nbytes > data.length)
{
@@ -382,7 +381,7 @@ struct OutBuffer
/**
* Writes an 8 bit byte, no reserve check.
*/
- extern (C++) @trusted nothrow
+ extern (C++) nothrow @safe
void writeByten(int b)
{
this.data[offset++] = cast(ubyte) b;
@@ -786,10 +785,11 @@ struct OutBuffer
Returns: `true` iff the operation succeeded.
*/
- extern(D) bool moveToFile(const char* filename) @system
+ extern(D) bool moveToFile(const char[] filename) @system
{
bool result = true;
- const bool identical = this[] == FileMapping!(const ubyte)(filename)[];
+ const filenameZ = (filename ~ "\0").ptr;
+ const bool identical = this[] == FileMapping!(const ubyte)(filenameZ)[];
if (fileMapping && fileMapping.active)
{
@@ -802,7 +802,7 @@ struct OutBuffer
{
// Resize to fit to get rid of the slack bytes at the end
fileMapping.resize(offset);
- result = fileMapping.moveToFile(filename);
+ result = fileMapping.moveToFile(filenameZ);
}
// Can't call destroy() here because the file mapping is already closed.
data = null;
@@ -811,12 +811,12 @@ struct OutBuffer
else
{
if (!identical)
- writeFile(filename, this[]);
+ writeFile(filenameZ, this[]);
destroy();
}
return identical
- ? result && touchFile(filename)
+ ? result && touchFile(filenameZ)
: result;
}
}
diff --git a/gcc/d/dmd/common/outbuffer.h b/gcc/d/dmd/common/outbuffer.h
index 2250497..62aca7a 100644
--- a/gcc/d/dmd/common/outbuffer.h
+++ b/gcc/d/dmd/common/outbuffer.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/common/smallbuffer.d b/gcc/d/dmd/common/smallbuffer.d
index 608ecc8..65adec6 100644
--- a/gcc/d/dmd/common/smallbuffer.d
+++ b/gcc/d/dmd/common/smallbuffer.d
@@ -1,12 +1,12 @@
/**
* Common string functions including filename manipulation.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/smallbuffer.d, common/_smallbuffer.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/smallbuffer.d, common/_smallbuffer.d)
* Documentation: https://dlang.org/phobos/dmd_common_smallbuffer.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/smallbuffer
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/common/smallbuffer.d
*/
module dmd.common.smallbuffer;
diff --git a/gcc/d/dmd/compiler.d b/gcc/d/dmd/compiler.d
index 65330cf..8203e0c 100644
--- a/gcc/d/dmd/compiler.d
+++ b/gcc/d/dmd/compiler.d
@@ -1,12 +1,12 @@
/**
* Describes a back-end compiler and implements compiler-specific actions.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d, _compiler.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/compiler.d, _compiler.d)
* Documentation: https://dlang.org/phobos/dmd_compiler.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/compiler.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/compiler.d
*/
module dmd.compiler;
@@ -16,6 +16,7 @@ import dmd.ctfeexpr;
import dmd.dmodule;
import dmd.expression;
import dmd.mtype;
+import dmd.typesem;
import dmd.root.array;
extern (C++) __gshared
diff --git a/gcc/d/dmd/compiler.h b/gcc/d/dmd/compiler.h
index 74351ed..ca085c6 100644
--- a/gcc/d/dmd/compiler.h
+++ b/gcc/d/dmd/compiler.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index e194664..1b11a9f 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/version.html, Conditional Compilation)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cond.d, _cond.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cond.d, _cond.d)
* Documentation: https://dlang.org/phobos/dmd_cond.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cond.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/cond.d
*/
module dmd.cond;
@@ -24,7 +24,7 @@ import dmd.dscope;
import dmd.dsymbol;
import dmd.errors;
import dmd.expression;
-import dmd.expressionsem;
+import dmd.expressionsem : evalStaticCondition;
import dmd.globals;
import dmd.identifier;
import dmd.location;
@@ -64,7 +64,7 @@ extern (C++) abstract class Condition : ASTNode
return DYNCAST.condition;
}
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
this.loc = loc;
}
@@ -126,7 +126,7 @@ extern (C++) final class StaticForeach : RootObject
*/
bool needExpansion = false;
- extern (D) this(const ref Loc loc, ForeachStatement aggrfe, ForeachRangeStatement rangefe) @safe
+ extern (D) this(Loc loc, ForeachStatement aggrfe, ForeachRangeStatement rangefe) @safe
{
assert(!!aggrfe ^ !!rangefe);
@@ -145,52 +145,6 @@ extern (C++) final class StaticForeach : RootObject
}
/*****************************************
- * Turn an aggregate which is an array into an expression tuple
- * of its elements. I.e., lower
- * static foreach (x; [1, 2, 3, 4]) { ... }
- * to
- * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
- */
- private extern(D) void lowerArrayAggregate(Scope* sc)
- {
- auto aggr = aggrfe.aggr;
- Expression el = new ArrayLengthExp(aggr.loc, aggr);
- sc = sc.startCTFE();
- el = el.expressionSemantic(sc);
- sc = sc.endCTFE();
- el = el.optimize(WANTvalue);
- el = el.ctfeInterpret();
- if (el.op == EXP.int64)
- {
- Expressions *es = void;
- if (auto ale = aggr.isArrayLiteralExp())
- {
- // Directly use the elements of the array for the TupleExp creation
- es = ale.elements;
- }
- else
- {
- const length = cast(size_t)el.toInteger();
- es = new Expressions(length);
- foreach (i; 0 .. length)
- {
- auto index = new IntegerExp(loc, i, Type.tsize_t);
- auto value = new IndexExp(aggr.loc, aggr, index);
- (*es)[i] = value;
- }
- }
- aggrfe.aggr = new TupleExp(aggr.loc, es);
- aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
- aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
- aggrfe.aggr = aggrfe.aggr.ctfeInterpret();
- }
- else
- {
- aggrfe.aggr = ErrorExp.get();
- }
- }
-
- /*****************************************
* Wrap a statement into a function literal and call it.
*
* Params:
@@ -199,9 +153,9 @@ extern (C++) final class StaticForeach : RootObject
* Returns:
* AST of the expression `(){ s; }()` with location loc.
*/
- private extern(D) Expression wrapAndCall(const ref Loc loc, Statement s)
+ extern(D) Expression wrapAndCall(Loc loc, Statement s)
{
- auto tf = new TypeFunction(ParameterList(), null, LINK.default_, 0);
+ auto tf = new TypeFunction(ParameterList(), null, LINK.default_, STC.none);
auto fd = new FuncLiteralDeclaration(loc, loc, tf, TOK.reserved, null);
fd.fbody = s;
auto fe = new FuncExp(loc, fd);
@@ -222,7 +176,7 @@ extern (C++) final class StaticForeach : RootObject
* `foreach (parameters; lower .. upper) s;`
* Where aggregate/lower, upper are as for the current StaticForeach.
*/
- private extern(D) Statement createForeach(const ref Loc loc, Parameters* parameters, Statement s)
+ extern(D) Statement createForeach(Loc loc, Parameters* parameters, Statement s)
{
if (aggrfe)
{
@@ -255,7 +209,7 @@ extern (C++) final class StaticForeach : RootObject
* }
*/
- private extern(D) TypeStruct createTupleType(const ref Loc loc, Expressions* e, Scope* sc)
+ extern(D) TypeStruct createTupleType(Loc loc, Expressions* e, Scope* sc)
{ // TODO: move to druntime?
auto sid = Identifier.generateId("Tuple");
auto sdecl = new StructDeclaration(loc, sid, false);
@@ -263,7 +217,7 @@ extern (C++) final class StaticForeach : RootObject
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, 0));
+ sdecl.members.push(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
@@ -281,205 +235,11 @@ extern (C++) final class StaticForeach : RootObject
* An AST for the expression `Tuple(e)`.
*/
- private extern(D) Expression createTuple(const ref Loc loc, TypeStruct type, Expressions* e) @safe
+ extern(D) Expression createTuple(Loc loc, TypeStruct type, Expressions* e) @safe
{ // TODO: move to druntime?
return new CallExp(loc, new TypeExp(loc, type), e);
}
-
- /*****************************************
- * Lower any aggregate that is not an array to an array using a
- * regular foreach loop within CTFE. If there are multiple
- * `static foreach` loop variables, an array of tuples is
- * generated. In thise case, the field `needExpansion` is set to
- * true to indicate that the static foreach loop expansion will
- * need to expand the tuples into multiple variables.
- *
- * For example, `static foreach (x; range) { ... }` is lowered to:
- *
- * static foreach (x; {
- * typeof({
- * foreach (x; range) return x;
- * }())[] __res;
- * foreach (x; range) __res ~= x;
- * return __res;
- * }()) { ... }
- *
- * Finally, call `lowerArrayAggregate` to turn the produced
- * array into an expression tuple.
- *
- * Params:
- * sc = The current scope.
- */
-
- private void lowerNonArrayAggregate(Scope* sc)
- {
- auto nvars = aggrfe ? aggrfe.parameters.length : 1;
- auto aloc = aggrfe ? aggrfe.aggr.loc : rangefe.lwr.loc;
- // We need three sets of foreach loop variables because the
- // lowering contains three foreach loops.
- Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()];
- foreach (i; 0 .. nvars)
- {
- foreach (params; pparams)
- {
- auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm;
- params.push(new Parameter(aloc, p.storageClass, p.type, p.ident, null, null));
- }
- }
- Expression[2] res;
- TypeStruct tplty = null;
- if (nvars == 1) // only one `static foreach` variable, generate identifiers.
- {
- foreach (i; 0 .. 2)
- {
- res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident);
- }
- }
- else // multiple `static foreach` variables, generate tuples.
- {
- foreach (i; 0 .. 2)
- {
- auto e = new Expressions(pparams[0].length);
- foreach (j, ref elem; *e)
- {
- auto p = (*pparams[i])[j];
- elem = new IdentifierExp(aloc, p.ident);
- }
- if (!tplty)
- {
- tplty = createTupleType(aloc, e, sc);
- }
- res[i] = createTuple(aloc, tplty, e);
- }
- needExpansion = true; // need to expand the tuples later
- }
- // generate remaining code for the new aggregate which is an
- // array (see documentation comment).
- if (rangefe)
- {
- sc = sc.startCTFE();
- rangefe.lwr = rangefe.lwr.expressionSemantic(sc);
- rangefe.lwr = resolveProperties(sc, rangefe.lwr);
- rangefe.upr = rangefe.upr.expressionSemantic(sc);
- rangefe.upr = resolveProperties(sc, rangefe.upr);
- sc = sc.endCTFE();
- rangefe.lwr = rangefe.lwr.optimize(WANTvalue);
- rangefe.lwr = rangefe.lwr.ctfeInterpret();
- rangefe.upr = rangefe.upr.optimize(WANTvalue);
- rangefe.upr = rangefe.upr.ctfeInterpret();
- }
- auto s1 = new Statements();
- auto sfe = new Statements();
- if (tplty) sfe.push(new ExpStatement(loc, tplty.sym));
- sfe.push(new ReturnStatement(aloc, res[0]));
- s1.push(createForeach(aloc, pparams[0], new CompoundStatement(aloc, sfe)));
- s1.push(new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0)));
- Type ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
- auto aty = ety.arrayOf();
- auto idres = Identifier.generateId("__res");
- auto vard = new VarDeclaration(aloc, aty, idres, null, STC.temp);
- auto s2 = new Statements();
-
- // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
- // an empty foreach to expose them.
- uint olderrors = global.startGagging();
- ety = ety.typeSemantic(aloc, sc);
- if (global.endGagging(olderrors))
- s2.push(createForeach(aloc, pparams[1], null));
- else
- {
- s2.push(new ExpStatement(aloc, vard));
- auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
- s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass)));
- s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
- }
-
- Expression aggr = void;
- Type indexty = void;
-
- if (rangefe && (indexty = ety).isintegral())
- {
- rangefe.lwr.type = indexty;
- rangefe.upr.type = indexty;
- auto lwrRange = getIntRange(rangefe.lwr);
- auto uprRange = getIntRange(rangefe.upr);
-
- const lwr = rangefe.lwr.toInteger();
- auto upr = rangefe.upr.toInteger();
- size_t length = 0;
-
- if (lwrRange.imin <= uprRange.imax)
- length = cast(size_t) (upr - lwr);
-
- auto exps = new Expressions(length);
-
- if (rangefe.op == TOK.foreach_)
- {
- foreach (i; 0 .. length)
- (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
- }
- else
- {
- --upr;
- foreach (i; 0 .. length)
- (*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
- }
- aggr = new ArrayLiteralExp(aloc, indexty.arrayOf(), exps);
- }
- else
- {
- aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
- sc = sc.startCTFE();
- aggr = aggr.expressionSemantic(sc);
- aggr = resolveProperties(sc, aggr);
- sc = sc.endCTFE();
- aggr = aggr.optimize(WANTvalue);
- aggr = aggr.ctfeInterpret();
- }
-
- assert(!!aggrfe ^ !!rangefe);
- aggrfe = new ForeachStatement(loc, TOK.foreach_, pparams[2], aggr,
- aggrfe ? aggrfe._body : rangefe._body,
- aggrfe ? aggrfe.endloc : rangefe.endloc);
- rangefe = null;
- lowerArrayAggregate(sc); // finally, turn generated array into expression tuple
- }
-
- /*****************************************
- * Perform `static foreach` lowerings that are necessary in order
- * to finally expand the `static foreach` using
- * `dmd.statementsem.makeTupleForeach`.
- */
- extern(D) void prepare(Scope* sc)
- {
- assert(sc);
-
- if (aggrfe)
- {
- sc = sc.startCTFE();
- aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
- sc = sc.endCTFE();
- }
-
- if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror)
- {
- return;
- }
-
- if (!ready())
- {
- if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray)
- {
- lowerArrayAggregate(sc);
- }
- else
- {
- lowerNonArrayAggregate(sc);
- }
- }
- }
-
/*****************************************
* Returns:
* `true` iff ready to call `dmd.statementsem.makeTupleForeach`.
@@ -494,15 +254,13 @@ extern (C++) final class StaticForeach : RootObject
*/
extern (C++) class DVCondition : Condition
{
- uint level;
Identifier ident;
Module mod;
- extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) @safe
+ extern (D) this(Loc loc, Module mod, Identifier ident) @safe
{
super(loc);
this.mod = mod;
- this.level = level;
this.ident = ident;
}
@@ -557,45 +315,45 @@ extern (C++) final class DebugCondition : DVCondition
*
* Params:
* mod = Module this node belongs to
- * level = Minimum global level this condition needs to pass.
- * Only used if `ident` is `null`.
* ident = Identifier required for this condition to pass.
* If `null`, this conditiion will use an integer level.
* loc = Location in the source file
*/
- extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) @safe
+ extern (D) this(Loc loc, Module mod, Identifier ident) @safe
{
- super(loc, mod, level, ident);
+ super(loc, mod, ident);
}
override int include(Scope* sc)
{
//printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
- if (inc == Include.notComputed)
+ if (inc != Include.notComputed)
{
- inc = Include.no;
- bool definedInModule = false;
- if (ident)
+ return inc == Include.yes;
+ }
+ inc = Include.no;
+ bool definedInModule = false;
+ if (ident)
+ {
+ if (mod.debugids && findCondition(*mod.debugids, ident))
{
- if (mod.debugids && findCondition(*mod.debugids, ident))
- {
- inc = Include.yes;
- definedInModule = true;
- }
- else if (findCondition(global.debugids, ident))
- inc = Include.yes;
- else
- {
- if (!mod.debugidsNot)
- mod.debugidsNot = new Identifiers();
- mod.debugidsNot.push(ident);
- }
+ inc = Include.yes;
+ definedInModule = true;
}
- else if (level <= global.params.debuglevel || level <= mod.debuglevel)
+ else if (findCondition(global.debugids, ident))
inc = Include.yes;
- if (!definedInModule)
- printDepsConditional(sc, this, "depsDebug ");
+ else
+ {
+ if (!mod.debugidsNot)
+ mod.debugidsNot = new Identifiers();
+ mod.debugidsNot.push(ident);
+ }
}
+ else if (global.params.debugEnabled)
+ inc = Include.yes;
+
+ if (!definedInModule)
+ printDepsConditional(sc, this, "depsDebug ");
return (inc == Include.yes);
}
@@ -608,11 +366,6 @@ extern (C++) final class DebugCondition : DVCondition
{
v.visit(this);
}
-
- override const(char)* toChars() const
- {
- return ident ? ident.toChars() : "debug".ptr;
- }
}
/**
@@ -659,9 +412,9 @@ extern (C++) final class VersionCondition : DVCondition
case "AVR":
case "BigEndian":
case "BSD":
- case "CppRuntime_Clang":
+ case "CppRuntime_LLVM":
case "CppRuntime_DigitalMars":
- case "CppRuntime_Gcc":
+ case "CppRuntime_GNU":
case "CppRuntime_Microsoft":
case "CppRuntime_Sun":
case "CRuntime_Bionic":
@@ -744,6 +497,7 @@ extern (C++) final class VersionCondition : DVCondition
case "Win32":
case "Win64":
case "Windows":
+ case "Xtensa":
case "X86":
case "X86_64":
return true;
@@ -764,7 +518,7 @@ extern (C++) final class VersionCondition : DVCondition
* loc = Where the identifier is set
* ident = identifier being checked (ident[$] must be '\0')
*/
- extern(D) static void checkReserved(const ref Loc loc, const(char)[] ident)
+ extern(D) static void checkReserved(Loc loc, const(char)[] ident)
{
if (isReserved(ident))
error(loc, "version identifier `%s` is reserved and cannot be set",
@@ -836,49 +590,47 @@ extern (C++) final class VersionCondition : DVCondition
*
* Params:
* mod = Module this node belongs to
- * level = Minimum global level this condition needs to pass.
- * Only used if `ident` is `null`.
* ident = Identifier required for this condition to pass.
* If `null`, this conditiion will use an integer level.
* loc = Location in the source file
*/
- extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) @safe
+ extern (D) this(Loc loc, Module mod, Identifier ident) @safe
{
- super(loc, mod, level, ident);
+ super(loc, mod, ident);
}
override int include(Scope* sc)
{
//printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
//if (ident) printf("\tident = '%s'\n", ident.toChars());
- if (inc == Include.notComputed)
+ if (inc != Include.notComputed)
{
- inc = Include.no;
- bool definedInModule = false;
- if (ident)
+ return inc == Include.yes;
+ }
+
+ inc = Include.no;
+ bool definedInModule = false;
+ if (ident)
+ {
+ if (mod.versionids && findCondition(*mod.versionids, ident))
{
- if (mod.versionids && findCondition(*mod.versionids, ident))
- {
- inc = Include.yes;
- definedInModule = true;
- }
- else if (findCondition(global.versionids, ident))
- inc = Include.yes;
- else
- {
- if (!mod.versionidsNot)
- mod.versionidsNot = new Identifiers();
- mod.versionidsNot.push(ident);
- }
+ inc = Include.yes;
+ definedInModule = true;
}
- else if (level <= global.params.versionlevel || level <= mod.versionlevel)
+ else if (findCondition(global.versionids, ident))
inc = Include.yes;
- if (!definedInModule &&
- (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert)))
+ else
{
- printDepsConditional(sc, this, "depsVersion ");
+ if (!mod.versionidsNot)
+ mod.versionidsNot = new Identifiers();
+ mod.versionidsNot.push(ident);
}
}
+ if (!definedInModule &&
+ (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert)))
+ {
+ printDepsConditional(sc, this, "depsVersion ");
+ }
return (inc == Include.yes);
}
@@ -891,11 +643,6 @@ extern (C++) final class VersionCondition : DVCondition
{
v.visit(this);
}
-
- override const(char)* toChars() const
- {
- return ident ? ident.toChars() : "version".ptr;
- }
}
/***********************************************************
@@ -904,7 +651,7 @@ extern (C++) final class StaticIfCondition : Condition
{
Expression exp;
- extern (D) this(const ref Loc loc, Expression exp) @safe
+ extern (D) this(Loc loc, Expression exp) @safe
{
super(loc);
this.exp = exp;
@@ -926,31 +673,33 @@ extern (C++) final class StaticIfCondition : Condition
return 0;
}
- if (inc == Include.notComputed)
+ if (inc != Include.notComputed)
{
- if (!sc)
- {
- error(loc, "`static if` conditional cannot be at global scope");
- inc = Include.no;
- return 0;
- }
+ return inc == Include.yes;
+ }
- import dmd.staticcond;
- bool errors;
+ if (!sc)
+ {
+ error(loc, "`static if` conditional cannot be at global scope");
+ inc = Include.no;
+ return 0;
+ }
- bool result = evalStaticCondition(sc, exp, exp, errors);
+ import dmd.staticcond;
+ bool errors;
- // Prevent repeated condition evaluation.
- // See: fail_compilation/fail7815.d
- if (inc != Include.notComputed)
- return (inc == Include.yes);
- if (errors)
- return errorReturn();
- if (result)
- inc = Include.yes;
- else
- inc = Include.no;
- }
+ bool result = evalStaticCondition(sc, exp, exp, errors);
+
+ // Prevent repeated condition evaluation.
+ // See: fail_compilation/fail7815.d
+ if (inc != Include.notComputed)
+ return (inc == Include.yes);
+ if (errors)
+ return errorReturn();
+ if (result)
+ inc = Include.yes;
+ else
+ inc = Include.no;
return (inc == Include.yes);
}
@@ -963,11 +712,6 @@ extern (C++) final class StaticIfCondition : Condition
{
return this;
}
-
- override const(char)* toChars() const
- {
- return exp ? exp.toChars() : "static if".ptr;
- }
}
@@ -1005,7 +749,5 @@ private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[
ob.writestring(") : ");
if (condition.ident)
ob.writestring(condition.ident.toString());
- else
- ob.print(condition.level);
ob.writeByte('\n');
}
diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h
index fe497c2d..174a8fb 100644
--- a/gcc/d/dmd/cond.h
+++ b/gcc/d/dmd/cond.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -39,8 +39,8 @@ public:
virtual Condition *syntaxCopy() = 0;
virtual int include(Scope *sc) = 0;
- virtual DebugCondition *isDebugCondition() { return NULL; }
- virtual VersionCondition *isVersionCondition() { return NULL; }
+ virtual DebugCondition *isDebugCondition() { return nullptr; }
+ virtual VersionCondition *isVersionCondition() { return nullptr; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -58,7 +58,6 @@ public:
class DVCondition : public Condition
{
public:
- unsigned level;
Identifier *ident;
Module *mod;
@@ -72,7 +71,6 @@ public:
static void addGlobalIdent(const char *ident);
int include(Scope *sc) override;
- DebugCondition *isDebugCondition() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -83,7 +81,6 @@ public:
static void addPredefinedGlobalIdent(const char *ident);
int include(Scope *sc) override;
- VersionCondition *isVersionCondition() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index 6ec31d5..fad9c9a 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -5,12 +5,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/constfold.d, _constfold.d)
* Documentation: https://dlang.org/phobos/dmd_constfold.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/constfold.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/constfold.d
*/
module dmd.constfold;
@@ -36,7 +36,7 @@ import dmd.root.utf;
import dmd.sideeffect;
import dmd.target;
import dmd.tokens;
-import dmd.typesem : toDsymbol, equivalent, sarrayOf;
+import dmd.typesem : toDsymbol, equivalent, sarrayOf, size;
private enum LOG = false;
@@ -69,15 +69,15 @@ UnionExp Neg(Type type, Expression e1)
{
UnionExp ue = void;
Loc loc = e1.loc;
- if (e1.type.isreal())
+ if (e1.type.isReal())
{
emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type);
}
- else if (e1.type.isimaginary())
+ else if (e1.type.isImaginary())
{
emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type);
}
- else if (e1.type.iscomplex())
+ else if (e1.type.isComplex())
{
emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type);
}
@@ -107,22 +107,22 @@ UnionExp Not(Type type, Expression e1)
return ue;
}
-UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Add(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
static if (LOG)
{
printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
}
- if (type.isreal())
+ if (type.isReal())
{
emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type);
}
- else if (type.isimaginary())
+ else if (type.isImaginary())
{
emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type);
}
- else if (type.iscomplex())
+ else if (type.isComplex())
{
// This rigamarole is necessary so that -0.0 doesn't get
// converted to +0.0 by doing an extraneous add with +0.0
@@ -134,12 +134,12 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
real_t i2 = CTFloat.zero;
auto v = complex_t(CTFloat.zero);
int x;
- if (e1.type.isreal())
+ if (e1.type.isReal())
{
r1 = e1.toReal();
x = 0;
}
- else if (e1.type.isimaginary())
+ else if (e1.type.isImaginary())
{
i1 = e1.toImaginary();
x = 3;
@@ -149,11 +149,11 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
c1 = e1.toComplex();
x = 6;
}
- if (e2.type.isreal())
+ if (e2.type.isReal())
{
r2 = e2.toReal();
}
- else if (e2.type.isimaginary())
+ else if (e2.type.isImaginary())
{
i2 = e2.toImaginary();
x += 1;
@@ -212,7 +212,7 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
-UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Min(Loc loc, Type type, Expression e1, Expression e2)
{
// Compute e1-e2 as e1+(-e2)
UnionExp neg = Neg(e2.type, e2);
@@ -220,32 +220,32 @@ UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
-UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Mul(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
- if (type.isfloating())
+ if (type.isFloating())
{
auto c = complex_t(CTFloat.zero);
real_t r = CTFloat.zero;
- if (e1.type.isreal())
+ if (e1.type.isReal())
{
r = e1.toReal();
c = e2.toComplex();
c = complex_t(r * creall(c), r * cimagl(c));
}
- else if (e1.type.isimaginary())
+ else if (e1.type.isImaginary())
{
r = e1.toImaginary();
c = e2.toComplex();
c = complex_t(-r * cimagl(c), r * creall(c));
}
- else if (e2.type.isreal())
+ else if (e2.type.isReal())
{
r = e2.toReal();
c = e1.toComplex();
c = complex_t(r * creall(c), r * cimagl(c));
}
- else if (e2.type.isimaginary())
+ else if (e2.type.isImaginary())
{
r = e2.toImaginary();
c = e1.toComplex();
@@ -253,11 +253,11 @@ UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
}
else
c = e1.toComplex() * e2.toComplex();
- if (type.isreal())
+ if (type.isReal())
emplaceExp!(RealExp)(&ue, loc, creall(c), type);
- else if (type.isimaginary())
+ else if (type.isImaginary())
emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
- else if (type.iscomplex())
+ else if (type.isComplex())
emplaceExp!(ComplexExp)(&ue, loc, c, type);
else
assert(0);
@@ -269,15 +269,15 @@ UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
-UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Div(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
- if (type.isfloating())
+ if (type.isFloating())
{
auto c = complex_t(CTFloat.zero);
- if (e2.type.isreal())
+ if (e2.type.isReal())
{
- if (e1.type.isreal())
+ if (e1.type.isReal())
{
emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type);
return ue;
@@ -286,7 +286,7 @@ UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
c = e1.toComplex();
c = complex_t(creall(c) / r, cimagl(c) / r);
}
- else if (e2.type.isimaginary())
+ else if (e2.type.isImaginary())
{
const r = e2.toImaginary();
c = e1.toComplex();
@@ -297,11 +297,11 @@ UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
c = e1.toComplex() / e2.toComplex();
}
- if (type.isreal())
+ if (type.isReal())
emplaceExp!(RealExp)(&ue, loc, creall(c), type);
- else if (type.isimaginary())
+ else if (type.isImaginary())
emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
- else if (type.iscomplex())
+ else if (type.isComplex())
emplaceExp!(ComplexExp)(&ue, loc, c, type);
else
assert(0);
@@ -319,7 +319,7 @@ UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
emplaceExp!(ErrorExp)(&ue);
return ue;
}
- if (n2 == -1 && !type.isunsigned())
+ if (n2 == -1 && !type.isUnsigned())
{
// Check for int.min / -1
if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
@@ -335,7 +335,7 @@ UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
}
- if (e1.type.isunsigned() || e2.type.isunsigned())
+ if (e1.type.isUnsigned() || e2.type.isUnsigned())
n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2);
else
n = n1 / n2;
@@ -344,29 +344,29 @@ UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
-UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Mod(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
- if (type.isfloating())
+ if (type.isFloating())
{
auto c = complex_t(CTFloat.zero);
- if (e2.type.isreal())
+ if (e2.type.isReal())
{
const r2 = e2.toReal();
c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
}
- else if (e2.type.isimaginary())
+ else if (e2.type.isImaginary())
{
const i2 = e2.toImaginary();
c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
}
else
assert(0);
- if (type.isreal())
+ if (type.isReal())
emplaceExp!(RealExp)(&ue, loc, creall(c), type);
- else if (type.isimaginary())
+ else if (type.isImaginary())
emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
- else if (type.iscomplex())
+ else if (type.isComplex())
emplaceExp!(ComplexExp)(&ue, loc, c, type);
else
assert(0);
@@ -384,7 +384,7 @@ UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
emplaceExp!(ErrorExp)(&ue);
return ue;
}
- if (n2 == -1 && !type.isunsigned())
+ if (n2 == -1 && !type.isUnsigned())
{
// Check for int.min % -1
if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
@@ -400,7 +400,7 @@ UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
}
- if (e1.type.isunsigned() || e2.type.isunsigned())
+ if (e1.type.isUnsigned() || e2.type.isUnsigned())
n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2);
else
n = n1 % n2;
@@ -409,18 +409,18 @@ UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
-UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Pow(Loc loc, Type type, Expression e1, Expression e2)
{
//printf("Pow()\n");
UnionExp ue;
// Handle integer power operations.
- if (e2.type.isintegral())
+ if (e2.type.isIntegral())
{
dinteger_t n = e2.toInteger();
bool neg;
- if (!e2.type.isunsigned() && cast(sinteger_t)n < 0)
+ if (!e2.type.isUnsigned() && cast(sinteger_t)n < 0)
{
- if (e1.type.isintegral())
+ if (e1.type.isIntegral())
{
cantExp(ue);
return ue;
@@ -432,12 +432,12 @@ UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
else
neg = false;
UnionExp ur, uv;
- if (e1.type.iscomplex())
+ if (e1.type.isComplex())
{
emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type);
}
- else if (e1.type.isfloating())
+ else if (e1.type.isFloating())
{
emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type);
@@ -467,14 +467,14 @@ UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type);
uv = Div(loc, v.type, one.exp(), v);
}
- if (type.iscomplex())
+ if (type.isComplex())
emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type);
- else if (type.isintegral())
+ else if (type.isIntegral())
emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type);
else
emplaceExp!(RealExp)(&ue, loc, v.toReal(), type);
}
- else if (e2.type.isfloating())
+ else if (e2.type.isFloating())
{
// x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
if (e1.toReal() < CTFloat.zero)
@@ -489,14 +489,14 @@ UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
-UnionExp Shl(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Shl(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type);
return ue;
}
-UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Shr(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
dinteger_t value = e1.toInteger();
@@ -542,7 +542,7 @@ UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
-UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Ushr(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
dinteger_t value = e1.toInteger();
@@ -582,21 +582,21 @@ UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2)
return ue;
}
-UnionExp And(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp And(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type);
return ue;
}
-UnionExp Or(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Or(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type);
return ue;
}
-UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Xor(Loc loc, Type type, Expression e1, Expression e2)
{
//printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
UnionExp ue = void;
@@ -606,7 +606,7 @@ UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
/* Also returns EXP.cantExpression if cannot be computed.
*/
-UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Equal(EXP op, Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
int cmp = 0;
@@ -765,13 +765,13 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
cantExp(ue);
return ue;
}
- else if (e1.type.isreal())
+ else if (e1.type.isReal())
{
r1 = e1.toReal();
r2 = e2.toReal();
goto L1;
}
- else if (e1.type.isimaginary())
+ else if (e1.type.isImaginary())
{
r1 = e1.toImaginary();
r2 = e2.toImaginary();
@@ -785,11 +785,11 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
cmp = (r1 == r2);
}
}
- else if (e1.type.iscomplex())
+ else if (e1.type.isComplex())
{
cmp = e1.toComplex() == e2.toComplex();
}
- else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer)
+ else if (e1.type.isIntegral() || e1.type.toBasetype().ty == Tpointer)
{
cmp = (e1.toInteger() == e2.toInteger());
}
@@ -804,8 +804,9 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
return ue;
}
-UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Identity(EXP op, Loc loc, Type type, Expression e1, Expression e2)
{
+ //printf("Identity %s %s\n", e1.toChars(), e2.toChars());
UnionExp ue = void;
int cmp;
if (e1.op == EXP.null_)
@@ -820,11 +821,21 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
{
SymOffExp es1 = e1.isSymOffExp();
SymOffExp es2 = e2.isSymOffExp();
- cmp = (es1.var == es2.var && es1.offset == es2.offset);
+ cmp = es1.offset == es2.offset;
+ if (cmp)
+ {
+ cmp = es1.var == es2.var;
+ if (!cmp && (es1.var.isParameter() || es2.var.isParameter()))
+ {
+ // because of ref's, they may still be the same, we cannot tell
+ cantExp(ue);
+ return ue;
+ }
+ }
}
else
{
- if (e1.type.isfloating())
+ if (e1.type.isFloating())
cmp = e1.isIdentical(e2);
else
{
@@ -838,7 +849,7 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
return ue;
}
-UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Cmp(EXP op, Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
dinteger_t n;
@@ -866,20 +877,20 @@ UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
cantExp(ue);
return ue;
}
- else if (e1.type.isreal())
+ else if (e1.type.isReal())
{
r1 = e1.toReal();
r2 = e2.toReal();
goto L1;
}
- else if (e1.type.isimaginary())
+ else if (e1.type.isImaginary())
{
r1 = e1.toImaginary();
r2 = e2.toImaginary();
L1:
n = realCmp(op, r1, r2);
}
- else if (e1.type.iscomplex())
+ else if (e1.type.isComplex())
{
assert(0);
}
@@ -889,7 +900,7 @@ UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
sinteger_t n2;
n1 = e1.toInteger();
n2 = e2.toInteger();
- if (e1.type.isunsigned() || e2.type.isunsigned())
+ if (e1.type.isUnsigned() || e2.type.isUnsigned())
n = intUnsignedCmp(op, n1, n2);
else
n = intSignedCmp(op, n1, n2);
@@ -902,7 +913,7 @@ UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
* to: type to cast to
* type: type to paint the result
*/
-UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
+UnionExp Cast(Loc loc, Type type, Type to, Expression e1)
{
UnionExp ue = void;
Type tb = to.toBasetype();
@@ -968,9 +979,9 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
emplaceExp!(IntegerExp)(&ue, loc, opt.get(), type);
}
- else if (type.isintegral())
+ else if (type.isIntegral())
{
- if (e1.type.isfloating())
+ if (e1.type.isFloating())
{
dinteger_t result;
real_t r = e1.toReal();
@@ -1008,27 +1019,27 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
}
emplaceExp!(IntegerExp)(&ue, loc, result, type);
}
- else if (type.isunsigned())
+ else if (type.isUnsigned())
emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type);
else
emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
}
- else if (tb.isreal())
+ else if (tb.isReal())
{
real_t value = e1.toReal();
emplaceExp!(RealExp)(&ue, loc, value, type);
}
- else if (tb.isimaginary())
+ else if (tb.isImaginary())
{
real_t value = e1.toImaginary();
emplaceExp!(RealExp)(&ue, loc, value, type);
}
- else if (tb.iscomplex())
+ else if (tb.isComplex())
{
complex_t value = e1.toComplex();
emplaceExp!(ComplexExp)(&ue, loc, value, type);
}
- else if (tb.isscalar())
+ else if (tb.isScalar())
{
emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
}
@@ -1385,7 +1396,7 @@ private Expressions* copyElements(Expression e1, Expression e2 = null)
/* Also return EXP.cantExpression if this fails
*/
-UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Cat(Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
Expression e = CTFEExp.cantexp;
@@ -1494,7 +1505,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
assert(ue.exp().type);
return ue;
}
- else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
+ else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isIntegral())
{
// [chars] ~ string --> [chars]
StringExp es = e2.isStringExp();
@@ -1511,7 +1522,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
assert(ue.exp().type);
return ue;
}
- else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
+ else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isIntegral())
{
// string ~ [chars] --> [chars]
StringExp es = e1.isStringExp();
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index aeedb49..1a2a1e9 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -3,12 +3,12 @@
*
* Specification: C11
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d, _cparse.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cparse.d, _cparse.d)
* Documentation: https://dlang.org/phobos/dmd_cparse.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cparse.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/cparse.d
*/
module dmd.cparse;
@@ -27,6 +27,7 @@ import dmd.root.array;
import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.tokens;
+import dmd.typesem : size;
/***********************************************************
*/
@@ -35,7 +36,7 @@ final class CParser(AST) : Parser!AST
AST.Dsymbols* symbols; // symbols declared in current scope
bool addFuncName; /// add declaration of __func__ to function symbol table
- bool importBuiltins; /// seen use of C compiler builtins, so import __builtins;
+ bool importBuiltins; /// seen use of C compiler builtins, so import __importc_builtins;
private
{
@@ -44,6 +45,9 @@ final class CParser(AST) : Parser!AST
// #pragma pack stack
Array!Identifier* records; // identifers (or null)
Array!structalign_t* packs; // parallel alignment values
+
+ STC defaultStorageClasses;
+ Array!STC* defaultStorageClassesStack;
}
/* C cannot be parsed without determining if an identifier is a type or a variable.
@@ -89,6 +93,9 @@ final class CParser(AST) : Parser!AST
this.wchar_tsize = target.wchar_tsize;
// C `char` is always unsigned in ImportC
+
+ // We know that we are parsing out C, due the parent not knowing this, we have to setup tables here.
+ charLookup = compileEnv.cCharLookupTable;
}
/********************************************
@@ -125,7 +132,7 @@ final class CParser(AST) : Parser!AST
/* Seen references to C builtin functions.
* Import their definitions
*/
- auto s = new AST.Import(Loc.initial, null, Id.builtins, null, false);
+ auto s = new AST.Import(Loc.initial, null, Id.importc_builtins, null, false);
wrap.push(s);
}
@@ -1116,75 +1123,74 @@ final class CParser(AST) : Parser!AST
*/
private AST.Expression cparseCastExp()
{
- if (token.value == TOK.leftParenthesis)
+ if (token.value != TOK.leftParenthesis)
+ return cparseUnaryExp();
+
+ //printf("cparseCastExp()\n");
+ auto tk = peek(&token);
+ bool iscast;
+ bool isexp;
+ if (tk.value == TOK.identifier)
{
- //printf("cparseCastExp()\n");
- auto tk = peek(&token);
- bool iscast;
- bool isexp;
- if (tk.value == TOK.identifier)
- {
- iscast = isTypedef(tk.ident);
- isexp = !iscast;
- }
- if (isexp)
- {
- // ( identifier ) is an expression
- return cparseUnaryExp();
- }
+ iscast = isTypedef(tk.ident);
+ isexp = !iscast;
+ }
+ if (isexp)
+ {
+ // ( identifier ) is an expression
+ return cparseUnaryExp();
+ }
- // If ( type-name )
- auto pt = &token;
+ // If ( type-name )
+ auto pt = &token;
- if (isCastExpression(pt))
- {
- // Expression may be either a cast or a compound literal, which
- // requires checking whether the next token is leftCurly
- const loc = token.loc;
- nextToken();
- auto t = cparseTypeName();
- check(TOK.rightParenthesis);
- pt = &token;
+ if (!isCastExpression(pt))
+ return cparseUnaryExp();
- if (token.value == TOK.leftCurly)
- {
- // C11 6.5.2.5 ( type-name ) { initializer-list }
- auto ci = cparseInitializer();
- auto ce = new AST.CompoundLiteralExp(loc, t, ci);
- return cparsePostfixOperators(ce);
- }
+ // Expression may be either a cast or a compound literal, which
+ // requires checking whether the next token is leftCurly
+ const loc = token.loc;
+ nextToken();
+ auto t = cparseTypeName();
+ check(TOK.rightParenthesis);
+ pt = &token;
- if (iscast)
- {
- // ( type-name ) cast-expression
- auto ce = cparseCastExp();
- return new AST.CastExp(loc, ce, t);
- }
+ if (token.value == TOK.leftCurly)
+ {
+ // C11 6.5.2.5 ( type-name ) { initializer-list }
+ auto ci = cparseInitializer();
+ auto ce = new AST.CompoundLiteralExp(loc, t, ci);
+ return cparsePostfixOperators(ce);
+ }
- if (t.isTypeIdentifier() &&
- isexp &&
- token.value == TOK.leftParenthesis &&
- !isCastExpression(pt))
- {
- /* (t)(...)... might be a cast expression or a function call,
- * with different grammars: a cast would be cparseCastExp(),
- * a function call would be cparsePostfixExp(CallExp(cparseArguments())).
- * We can't know until t is known. So, parse it as a function call
- * and let semantic() rewrite the AST as a CastExp if it turns out
- * to be a type.
- */
- auto ie = new AST.IdentifierExp(loc, t.isTypeIdentifier().ident);
- ie.parens = true; // let semantic know it might be a CastExp
- AST.Expression e = new AST.CallExp(loc, ie, cparseArguments());
- return cparsePostfixOperators(e);
- }
+ if (iscast)
+ {
+ // ( type-name ) cast-expression
+ auto ce = cparseCastExp();
+ return new AST.CastExp(loc, ce, t);
+ }
- // ( type-name ) cast-expression
- auto ce = cparseCastExp();
- return new AST.CastExp(loc, ce, t);
- }
+ if (t.isTypeIdentifier() &&
+ isexp &&
+ token.value == TOK.leftParenthesis &&
+ !isCastExpression(pt))
+ {
+ /* (t)(...)... might be a cast expression or a function call,
+ * with different grammars: a cast would be cparseCastExp(),
+ * a function call would be cparsePostfixExp(CallExp(cparseArguments())).
+ * We can't know until t is known. So, parse it as a function call
+ * and let semantic() rewrite the AST as a CastExp if it turns out
+ * to be a type.
+ */
+ auto ie = new AST.IdentifierExp(loc, t.isTypeIdentifier().ident);
+ ie.parens = true; // let semantic know it might be a CastExp
+ AST.Expression e = new AST.CallExp(loc, ie, cparseArguments());
+ return cparsePostfixOperators(e);
}
- return cparseUnaryExp();
+
+ // ( type-name ) cast-expression
+ auto ce = cparseCastExp();
+ return new AST.CastExp(loc, ce, t);
}
/**************
@@ -1439,8 +1445,10 @@ final class CParser(AST) : Parser!AST
auto e = cparseOrExp();
while (token.value == TOK.andAnd)
{
+ e = new AST.CastExp(loc, e, AST.Type.tbool);
nextToken();
auto e2 = cparseOrExp();
+ e2 = new AST.CastExp(loc, e2, AST.Type.tbool);
e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
}
return e;
@@ -1459,8 +1467,10 @@ final class CParser(AST) : Parser!AST
auto e = cparseAndAndExp();
while (token.value == TOK.orOr)
{
+ e = new AST.CastExp(loc, e, AST.Type.tbool);
nextToken();
auto e2 = cparseAndAndExp();
+ e2 = new AST.CastExp(loc, e2, AST.Type.tbool);
e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
}
return e;
@@ -1680,7 +1690,7 @@ final class CParser(AST) : Parser!AST
private AST.Expression cparseStatementExpression()
{
AST.ParameterList parameterList;
- StorageClass stc = 0;
+ STC stc = STC.none;
const loc = token.loc;
auto symbolsSave = symbols;
symbols = new AST.Dsymbols();
@@ -1704,7 +1714,7 @@ final class CParser(AST) : Parser!AST
}
auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
- auto fd = new AST.FuncLiteralDeclaration(loc, token.loc, tf, TOK.delegate_, null, null, 0);
+ auto fd = new AST.FuncLiteralDeclaration(loc, token.loc, tf, TOK.delegate_, null, null, STC.none);
fd.fbody = fbody;
auto fe = new AST.FuncExp(loc, fd);
@@ -1869,22 +1879,30 @@ final class CParser(AST) : Parser!AST
* init-declarator:
* declarator simple-asm-expr (opt) gnu-attributes (opt)
* declarator simple-asm-expr (opt) gnu-attributes (opt) = initializer
+ *
+ * Clang also allows simple-asm-expr after gnu-attributes.
*/
+ while (1)
+ {
+ if (token.value == TOK.asm_)
+ {
+ asmName = cparseGnuAsmLabel();
+ /* This is a data definition, there cannot now be a
+ * function definition.
+ */
+ first = false;
+ }
+ else if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
+ else
+ break;
+ }
+
switch (token.value)
{
case TOK.assign:
case TOK.comma:
case TOK.semicolon:
- case TOK.asm_:
- case TOK.__attribute__:
- if (token.value == TOK.asm_)
- asmName = cparseGnuAsmLabel();
- if (token.value == TOK.__attribute__)
- {
- cparseGnuAttributes(specifier);
- if (token.value == TOK.leftCurly)
- break; // function definition
- }
/* This is a data definition, there cannot now be a
* function definition.
*/
@@ -1919,6 +1937,14 @@ final class CParser(AST) : Parser!AST
auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
typedefTab.setDim(typedefTabLengthSave);
symbols = symbolsSave;
+ if (specifier.mod & MOD.x__stdcall)
+ {
+ // If this function is __stdcall, wrap it in a LinkDeclaration so that
+ // it's extern(Windows) when imported in D.
+ auto decls = new AST.Dsymbols(1);
+ (*decls)[0] = s;
+ s = new AST.LinkDeclaration(s.loc, LINK.windows, decls);
+ }
symbols.push(s);
return;
}
@@ -1984,7 +2010,7 @@ final class CParser(AST) : Parser!AST
//printf("AliasDeclaration %s %s\n", id.toChars(), dt.toChars());
auto ad = new AST.AliasDeclaration(token.loc, id, dt);
if (id == idt)
- ad.adFlags |= ad.hidden; // do not print when generating .di files
+ ad.hidden = true; // do not print when generating .di files
s = ad;
}
@@ -2024,7 +2050,7 @@ final class CParser(AST) : Parser!AST
error("no initializer for function declaration");
if (specifier.scw & SCW.x_Thread_local)
error("functions cannot be `_Thread_local`"); // C11 6.7.1-4
- StorageClass stc = specifiersToSTC(level, specifier);
+ STC stc = specifiersToSTC(level, specifier);
stc &= ~STC.gshared; // no gshared functions
auto fd = new AST.FuncDeclaration(token.loc, Loc.initial, id, stc, dt, specifier.noreturn);
specifiersToFuncDeclaration(fd, specifier);
@@ -2066,18 +2092,18 @@ final class CParser(AST) : Parser!AST
{
auto str = asmName.peekString();
p.mangleOverride = str;
-// p.adFlags |= AST.VarDeclaration.nounderscore;
- p.adFlags |= 4; // cannot get above line to compile on Ubuntu
+ p.noUnderscore = true;
}
}
s = applySpecifier(s, specifier);
- if (level == LVL.local)
+ if (level == LVL.local || (specifier.mod & MOD.x__stdcall))
{
- // Wrap the declaration in `extern (C) { declaration }`
+ // Wrap the declaration in `extern (C/Windows) { declaration }`
// Necessary for function pointers, but harmless to apply to all.
auto decls = new AST.Dsymbols(1);
(*decls)[0] = s;
- s = new AST.LinkDeclaration(s.loc, linkage, decls);
+ const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
+ s = new AST.LinkDeclaration(s.loc, lkg, decls);
}
symbols.push(s);
}
@@ -2211,7 +2237,7 @@ final class CParser(AST) : Parser!AST
auto body = cparseStatement(ParseStatementFlags.curly); // don't start a new scope; continue with parameter scope
typedefTab.pop(); // end of function scope
- StorageClass stc = specifiersToSTC(LVL.global, specifier);
+ STC stc = specifiersToSTC(LVL.global, specifier);
stc &= ~STC.gshared; // no gshared functions
auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, stc, ft, specifier.noreturn);
specifiersToFuncDeclaration(fd, specifier);
@@ -2967,7 +2993,7 @@ final class CParser(AST) : Parser!AST
if (isStatic || mod)
error("static or type qualifier used outside of function prototype");
}
- if (ts.isTypeSArray() || ts.isTypeDArray())
+ if (ts.isStaticOrDynamicArray())
{
/* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
* in the outermost array type derivation.
@@ -2996,9 +3022,10 @@ final class CParser(AST) : Parser!AST
auto parameterList = cparseParameterList();
const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
- StorageClass stc = specifier._nothrow ? STC.nothrow_ : 0;
+ STC stc = specifier._nothrow ? STC.nothrow_ : STC.none;
if (specifier._pure)
stc |= STC.pure_;
+ stc |= defaultStorageClasses;
AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, stc);
//tf = tf.addSTC(storageClass); // TODO
insertTx(ts, tf, t); // ts -> ... -> tf -> t
@@ -3151,7 +3178,7 @@ final class CParser(AST) : Parser!AST
{
auto parameters = new AST.Parameters();
AST.VarArg varargs = AST.VarArg.none;
- StorageClass varargsStc;
+ STC varargsStc;
check(TOK.leftParenthesis);
if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis) // func(void)
@@ -3514,7 +3541,7 @@ final class CParser(AST) : Parser!AST
break;
}
nextToken();
- auto s = new AST.CompoundAsmStatement(loc, statements, 0);
+ auto s = new AST.CompoundAsmStatement(loc, statements, STC.none);
return s;
}
@@ -3614,6 +3641,12 @@ final class CParser(AST) : Parser!AST
* type on the target machine. It's the opposite of __attribute__((packed))
*/
}
+ else if (token.ident == Id.packed)
+ {
+ specifier.packalign.set(1);
+ specifier.packalign.setPack(true);
+ nextToken();
+ }
else if (token.ident == Id.always_inline) // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
{
specifier.scw |= SCW.xinline;
@@ -3893,7 +3926,7 @@ final class CParser(AST) : Parser!AST
cparseGnuAttributes(specifierx);
}
- auto em = new AST.EnumMember(mloc, ident, value, null, 0, null, null);
+ auto em = new AST.EnumMember(mloc, ident, value, null, STC.none, null, null);
members.push(em);
if (token.value == TOK.comma)
@@ -3962,7 +3995,7 @@ final class CParser(AST) : Parser!AST
members = new AST.Dsymbols(); // so `members` will be non-null even with 0 members
while (token.value != TOK.rightCurly)
{
- cparseStructDeclaration(members);
+ cparseStructDeclaration(members, packalign);
if (token.value == TOK.endOfFile)
break;
@@ -3976,6 +4009,24 @@ final class CParser(AST) : Parser!AST
* struct-declarator (opt)
*/
}
+
+ /* GNU Extensions
+ * Parse the postfix gnu-attributes (opt)
+ */
+ Specifier specifier;
+ if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
+ if (!specifier.packalign.isUnknown)
+ {
+ packalign.set(specifier.packalign.get());
+ packalign.setPack(specifier.packalign.isPack());
+ foreach (ref d; (*members)[])
+ {
+ auto decls = new AST.Dsymbols(1);
+ (*decls)[0] = d;
+ d = new AST.AlignDeclaration(d.loc, specifier.packalign, decls);
+ }
+ }
}
else if (!tag)
error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
@@ -4007,8 +4058,9 @@ final class CParser(AST) : Parser!AST
* declarator (opt) : constant-expression
* Params:
* members = where to put the fields (members)
+ * packalign = alignment to use for struct members
*/
- void cparseStructDeclaration(AST.Dsymbols* members)
+ void cparseStructDeclaration(AST.Dsymbols* members, structalign_t packalign)
{
//printf("cparseStructDeclaration()\n");
if (token.value == TOK._Static_assert)
@@ -4019,7 +4071,7 @@ final class CParser(AST) : Parser!AST
}
Specifier specifier;
- specifier.packalign = this.packalign;
+ specifier.packalign = packalign.isUnknown ? this.packalign : packalign;
auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
if (!tspec)
{
@@ -5114,9 +5166,9 @@ final class CParser(AST) : Parser!AST
* Returns:
* corresponding D storage class
*/
- StorageClass specifiersToSTC(LVL level, const ref Specifier specifier)
+ STC specifiersToSTC(LVL level, const ref Specifier specifier)
{
- StorageClass stc;
+ STC stc;
if (specifier.scw & SCW.x_Thread_local)
{
if (level == LVL.global)
@@ -5478,6 +5530,12 @@ final class CParser(AST) : Parser!AST
if (pt && *pt)
t = *pt;
}
+ if (t.mcache && t.mcache.typedefIdent)
+ {
+ t = t.copy();
+ t.mcache = null;
+ }
+ t.getMcache().typedefIdent = id;
auto tab = cast(void*[void*])(typedefTab[$ - 1]);
tab[cast(void*)id] = cast(void*)t;
typedefTab[$ - 1] = cast(void*)tab;
@@ -5571,7 +5629,7 @@ final class CParser(AST) : Parser!AST
* Params:
* startloc = location to use for error messages
*/
- private void uupragmaDirective(const ref Loc startloc)
+ private void uupragmaDirective(Loc startloc)
{
const loc = startloc;
nextToken(); // move past __pragma
@@ -5619,12 +5677,14 @@ final class CParser(AST) : Parser!AST
* the preprocessed output. Ignore them.
* Upon return, p is at start of next line.
*/
- private void pragmaDirective(const ref Loc loc)
+ private void pragmaDirective(Loc loc)
{
Token n;
scan(&n);
if (n.value == TOK.identifier && n.ident == Id.pack)
return pragmaPack(loc, true);
+ if (n.value == TOK.identifier && n.ident == Id.attribute)
+ return pragmaAttribute(loc);
if (n.value != TOK.endOfLine)
skipToNextLine();
}
@@ -5638,7 +5698,7 @@ final class CParser(AST) : Parser!AST
* startloc = location to use for error messages
* useScan = use scan() to retrieve next token, instead of nextToken()
*/
- private void pragmaPack(const ref Loc startloc, bool useScan)
+ private void pragmaPack(Loc startloc, bool useScan)
{
const loc = startloc;
@@ -5768,7 +5828,7 @@ final class CParser(AST) : Parser!AST
if (len == 1) // stack is now empty
packalign.setDefault();
else
- packalign = (*this.packs)[len - 1];
+ packalign = (*this.packs)[len - 2];
return closingParen();
}
while (n.value == TOK.comma) // #pragma pack ( pop ,
@@ -5832,6 +5892,125 @@ final class CParser(AST) : Parser!AST
skipToNextLine();
}
+ /*********
+ * # pragma attribute(...)
+ * Sets default storage classes
+ * Params:
+ * startloc = location to use for error messages
+ */
+ private void pragmaAttribute(Loc startloc)
+ {
+ const loc = startloc;
+
+ if (!defaultStorageClassesStack)
+ {
+ defaultStorageClassesStack = new Array!STC;
+ }
+
+ Token n;
+ Lexer.scan(&n);
+ if (n.value != TOK.leftParenthesis)
+ {
+ error(loc, "left parenthesis expected to follow `#pragma attribute`");
+ if (n.value != TOK.endOfLine)
+ skipToNextLine();
+ return;
+ }
+
+ void closingParen()
+ {
+ if (n.value != TOK.rightParenthesis)
+ {
+ error(loc, "right parenthesis expected to close `#pragma attribute(`");
+ }
+ if (n.value != TOK.endOfLine)
+ skipToNextLine();
+ }
+
+ Lexer.scan(&n);
+
+ /* # pragma attribute (push, ...)
+ */
+ if (n.value == TOK.identifier && n.ident == Id.push)
+ {
+ Lexer.scan(&n);
+ if (n.value != TOK.comma)
+ {
+ error(loc, "comma expected to follow `#pragma attribute(push`");
+ if (n.value != TOK.endOfLine)
+ skipToNextLine();
+ return;
+ }
+
+ while (1)
+ {
+ Lexer.scan(&n);
+ if (n.value == TOK.endOfLine)
+ {
+ error(loc, "right parenthesis expected to close `#pragma attribute(push, `");
+ break;
+ }
+
+ if (n.value == TOK.rightParenthesis)
+ break;
+
+ if (n.value == TOK.identifier)
+ {
+ if (n.ident == Id._nothrow)
+ defaultStorageClasses |= STC.nothrow_;
+ else if (n.ident == Id.nogc)
+ defaultStorageClasses |= STC.nogc;
+ else if (n.ident == Id._pure)
+ defaultStorageClasses |= STC.pure_;
+ // Ignore unknown identifiers
+ }
+ else
+ {
+ error(loc, "unrecognized `#pragma attribute(push, %s)`", n.toChars());
+ break;
+ }
+
+ Lexer.scan(&n);
+
+ if (n.value == TOK.rightParenthesis)
+ break;
+
+ if (n.value != TOK.comma)
+ {
+ error(loc, "unrecognized `#pragma attribute(push, %s)`", n.toChars());
+ break;
+ }
+ }
+
+ this.defaultStorageClassesStack.push(defaultStorageClasses);
+
+ return closingParen();
+ }
+
+ /* # pragma attribute(pop)
+ */
+ if (n.value == TOK.identifier && n.ident == Id.pop)
+ {
+ scan(&n);
+ size_t len = this.defaultStorageClassesStack.length;
+
+ if (len)
+ {
+ this.defaultStorageClassesStack.setDim(len - 1);
+ if (len == 1) // stack is now empty
+ defaultStorageClasses = STC.init;
+ else
+ defaultStorageClasses = (*this.defaultStorageClassesStack)[len - 2];
+ }
+
+ return closingParen();
+ }
+
+ error(loc, "unrecognized `#pragma attribute(%s)`", n.toChars());
+ if (n.value != TOK.endOfLine)
+ skipToNextLine();
+ }
+
//}
/******************************************************************************/
@@ -5860,13 +6039,15 @@ final class CParser(AST) : Parser!AST
const(char)* endp = &slice[length - 7];
+ AST.Dsymbols newSymbols;
+
size_t[void*] defineTab; // hash table of #define's turned into Symbol's
- // indexed by Identifier, returns index into symbols[]
+ // indexed by Identifier, returns index into newSymbols[]
// The memory for this is leaked
- void addVar(AST.Dsymbol s)
+ void addSym(AST.Dsymbol s)
{
- //printf("addVar() %s\n", s.toChars());
+ //printf("addSym() %s\n", s.toChars());
if (auto v = s.isVarDeclaration())
v.isCmacro(true); // mark it as coming from a C #define
/* If it's already defined, replace the earlier
@@ -5874,13 +6055,22 @@ final class CParser(AST) : Parser!AST
*/
if (size_t* pd = cast(void*)s.ident in defineTab)
{
- //printf("replacing %s\n", v.toChars());
- (*symbols)[*pd] = s;
+ //printf("replacing %s\n", s.toChars());
+ newSymbols[*pd] = s;
return;
}
- assert(symbols, "symbols is null");
- defineTab[cast(void*)s.ident] = symbols.length;
- symbols.push(s);
+ defineTab[cast(void*)s.ident] = newSymbols.length;
+ newSymbols.push(s);
+ }
+
+ void removeSym(Identifier ident)
+ {
+ //printf("removeSym() %s\n", ident.toChars());
+ if (size_t* pd = cast(void*)ident in defineTab)
+ {
+ //printf("removing %s\n", ident.toChars());
+ newSymbols[*pd] = null;
+ }
}
while (p < endp)
@@ -5899,6 +6089,30 @@ final class CParser(AST) : Parser!AST
AST.Type t;
+ bool hasMinus;
+ if (token.value == TOK.min)
+ {
+ nextToken();
+ // Only allow integer and float literals after minus.
+ switch (token.value)
+ {
+ case TOK.int32Literal:
+ case TOK.uns32Literal:
+ case TOK.int64Literal:
+ case TOK.uns64Literal:
+ case TOK.float32Literal:
+ case TOK.float64Literal:
+ case TOK.float80Literal:
+ case TOK.imaginary32Literal:
+ case TOK.imaginary64Literal:
+ case TOK.imaginary80Literal:
+ hasMinus = true;
+ break;
+ default:
+ continue;
+ }
+ }
+
Lswitch:
switch (token.value)
{
@@ -5923,8 +6137,10 @@ final class CParser(AST) : Parser!AST
* enum id = intvalue;
*/
AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
+ if (hasMinus)
+ e = new AST.NegExp(scanloc, e);
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
- addVar(v);
+ addSym(v);
++p;
continue;
}
@@ -5946,8 +6162,10 @@ final class CParser(AST) : Parser!AST
* enum id = floatvalue;
*/
AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
+ if (hasMinus)
+ e = new AST.NegExp(scanloc, e);
auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
- addVar(v);
+ addSym(v);
++p;
continue;
}
@@ -5965,7 +6183,7 @@ final class CParser(AST) : Parser!AST
*/
AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
- addVar(v);
+ addSym(v);
++p;
continue;
}
@@ -5991,8 +6209,8 @@ final class CParser(AST) : Parser!AST
if (token.value != TOK.endOfFile)
break;
auto ret = new AST.ReturnStatement(exp.loc, exp);
- auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0);
- StorageClass stc = STC.auto_;
+ auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, STC.none);
+ STC stc = STC.auto_;
auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0);
fd.fbody = ret;
@@ -6001,7 +6219,7 @@ final class CParser(AST) : Parser!AST
AST.TemplateParameters* tpl = new AST.TemplateParameters();
AST.Expression constraint = null;
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
- addVar(tempdecl);
+ addSym(tempdecl);
++p;
continue;
}
@@ -6037,7 +6255,7 @@ final class CParser(AST) : Parser!AST
if (token.value != TOK.identifier)
break Lswitch;
- auto param = new AST.Parameter(token.loc, 0, null, token.ident, null, null);
+ auto param = new AST.Parameter(token.loc, STC.none, null, token.ident, null, null);
parameters.push(param);
nextToken();
if (token.value == TOK.comma)
@@ -6052,7 +6270,7 @@ final class CParser(AST) : Parser!AST
//auto pstart = p;
nextToken();
- auto parameterList = AST.ParameterList(parameters, varargs, 0);
+ auto parameterList = AST.ParameterList(parameters, varargs, STC.none);
/* Create a type for each parameter. Add it to the template parameter list,
* and the parameter list.
*/
@@ -6083,7 +6301,7 @@ final class CParser(AST) : Parser!AST
// Generate function
auto ret = new AST.ReturnStatement(exp.loc, exp);
- StorageClass stc = STC.auto_;
+ STC stc = STC.auto_;
auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0);
fd.fbody = ret;
@@ -6092,7 +6310,7 @@ final class CParser(AST) : Parser!AST
AST.Dsymbols* decldefs = new AST.Dsymbols();
decldefs.push(fd);
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false);
- addVar(tempdecl);
+ addSym(tempdecl);
++p;
continue;
@@ -6103,11 +6321,28 @@ final class CParser(AST) : Parser!AST
}
}
}
+ else if (p[0 .. 6] == "#undef")
+ {
+ p += 6;
+ nextToken();
+ //printf("undef %s\n", token.toChars());
+ if (token.value == TOK.identifier)
+ removeSym(token.ident);
+ }
// scan to end of line
while (*p)
++p;
++p; // advance to start of next line
- scanloc.linnum = scanloc.linnum + 1;
+ }
+
+ if (newSymbols.length)
+ {
+ assert(symbols, "symbols is null");
+ symbols.reserve(newSymbols.length);
+
+ foreach (sym; newSymbols)
+ if (sym) // undefined entries are null
+ symbols.push(sym);
}
scanloc = scanlocSave;
diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h
index 72d895c..e022d7c 100644
--- a/gcc/d/dmd/ctfe.h
+++ b/gcc/d/dmd/ctfe.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -48,7 +48,6 @@ class ThrownExceptionExp final : public Expression
{
public:
ClassReferenceExp *thrown; // the thing being tossed
- const char *toChars() const override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -58,6 +57,4 @@ public:
class CTFEExp final : public Expression
{
-public:
- const char *toChars() const override;
};
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index d2fcf5f..2f577ce 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -1,12 +1,12 @@
/**
* CTFE for expressions involving pointers, slices, array concatenation etc.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ctfeexpr.d, _ctfeexpr.d)
* Documentation: https://dlang.org/phobos/dmd_ctfeexpr.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctfeexpr.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/ctfeexpr.d
*/
module dmd.ctfeexpr;
@@ -17,6 +17,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.constfold;
import dmd.compiler;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dinterpret;
@@ -464,8 +465,7 @@ Expression resolveSlice(Expression e, UnionExp* pue = null)
*pue = Slice(e.type, se.e1, se.lwr, se.upr);
return pue.exp();
}
- else
- return Slice(e.type, se.e1, se.lwr, se.upr).copy();
+ return Slice(e.type, se.e1, se.lwr, se.upr).copy();
}
/* Determine the array length, without interpreting it.
@@ -522,7 +522,7 @@ uinteger_t resolveArrayLength(Expression e)
* Returns:
* Constructed ArrayLiteralExp
*/
-ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, const ref Loc loc, Type type, Expression elem, size_t dim)
+ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, Loc loc, Type type, Expression elem, size_t dim)
{
if (type.ty == Tsarray && type.nextOf().ty == Tsarray && elem.type.ty != Tsarray)
{
@@ -553,7 +553,7 @@ ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, const ref Loc l
* Helper for NewExp
* Create a string literal consisting of 'value' duplicated 'dim' times.
*/
-StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, Type type, dchar value, size_t dim, ubyte sz)
+StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, Loc loc, Type type, dchar value, size_t dim, ubyte sz)
{
auto s = cast(char*)mem.xcalloc(dim, sz);
foreach (elemi; 0 .. dim)
@@ -660,7 +660,7 @@ bool isSafePointerCast(Type srcPointee, Type destPointee)
srcPointee = srcPointee.baseElemOf();
destPointee = destPointee.baseElemOf();
}
- return srcPointee.isintegral() && destPointee.isintegral() && srcPointee.size() == destPointee.size();
+ return srcPointee.isIntegral() && destPointee.isIntegral() && srcPointee.size() == destPointee.size();
}
Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
@@ -688,7 +688,7 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
if (auto ie = e.isIndexExp())
{
// Note that each AA element is part of its own memory block
- if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64)
+ if ((ie.e1.type.isStaticOrDynamicArray() || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64)
{
*ofs = ie.e2.toInteger();
return ie.e1;
@@ -697,7 +697,7 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
if (auto se = e.isSliceExp())
{
if (se && e.type.toBasetype().ty == Tsarray &&
- (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64)
+ (se.e1.type.isStaticOrDynamicArray() || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64)
{
*ofs = se.lwr.toInteger();
return se.e1;
@@ -741,7 +741,7 @@ bool pointToSameMemoryBlock(Expression agg1, Expression agg2)
}
// return e1 - e2 as an integer, or error if not possible
-Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expression e1, Expression e2)
+Expression pointerDifference(UnionExp* pue, Loc loc, Type type, Expression e1, Expression e2)
{
dinteger_t ofs1, ofs2;
Expression agg1 = getAggregateFromPointer(e1, &ofs1);
@@ -774,7 +774,7 @@ Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expres
// Return eptr op e2, where eptr is a pointer, e2 is an integer,
// and op is EXP.add or EXP.min
-Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2)
+Expression pointerArithmetic(UnionExp* pue, Loc loc, EXP op, Type type, Expression eptr, Expression e2)
{
if (eptr.type.nextOf().ty == Tvoid)
{
@@ -950,7 +950,7 @@ int comparePointers(EXP op, Expression agg1, dinteger_t ofs1, Expression agg2, d
// floating point -> integer or integer -> floating point
bool isFloatIntPaint(Type to, Type from)
{
- return from.size() == to.size() && (from.isintegral() && to.isfloating() || from.isfloating() && to.isintegral());
+ return from.size() == to.size() && (from.isIntegral() && to.isFloating() || from.isFloating() && to.isIntegral());
}
// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
@@ -1052,7 +1052,7 @@ bool realCmp(EXP op, real_t r1, real_t r2) @safe nothrow
* Returns:
* -1,0,1
*/
-private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinteger_t len)
+private int ctfeCmpArrays(Loc loc, Expression e1, Expression e2, uinteger_t len)
{
// Resolve slices, if necessary
uinteger_t lo1 = 0;
@@ -1087,7 +1087,7 @@ private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinte
// Comparing two array literals. This case is potentially recursive.
// If they aren't strings, we just need an equality check rather than
// a full cmp.
- const bool needCmp = ae1.type.nextOf().isintegral();
+ const bool needCmp = ae1.type.nextOf().isIntegral();
foreach (size_t i; 0 .. cast(size_t)len)
{
Expression ee1 = (*ae1.elements)[cast(size_t)(lo1 + i)];
@@ -1138,7 +1138,7 @@ private bool isArray(const Expression e) @safe nothrow
* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
* For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
*/
-private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool identity = false)
+private int ctfeRawCmp(Loc loc, Expression e1, Expression e2, bool identity = false)
{
if (e1.op == EXP.classReference || e2.op == EXP.classReference)
{
@@ -1212,26 +1212,23 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
}
return cast(int)(len1 - len2);
}
- if (e1.type.isintegral())
+ if (e1.type.isIntegral())
{
return e1.toInteger() != e2.toInteger();
}
- if (identity && e1.type.isfloating())
+ if (identity && e1.type.isFloating())
return !e1.isIdentical(e2);
- if (e1.type.isreal() || e1.type.isimaginary())
+ if (e1.type.isReal() || e1.type.isImaginary())
{
- real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary();
- real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary();
+ real_t r1 = e1.type.isReal() ? e1.toReal() : e1.toImaginary();
+ real_t r2 = e1.type.isReal() ? e2.toReal() : e2.toImaginary();
if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
{
return 1; // they are not equal
}
- else
- {
- return (r1 != r2);
- }
+ return (r1 != r2);
}
- else if (e1.type.iscomplex())
+ else if (e1.type.isComplex())
{
return e1.toComplex() != e2.toComplex();
}
@@ -1242,33 +1239,30 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
// For structs, we only need to return 0 or 1 (< and > aren't legal).
if (es1.sd != es2.sd)
return 1;
- else if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
+ if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
return 0; // both arrays are empty
- else if (!es1.elements || !es2.elements)
+ if (!es1.elements || !es2.elements)
return 1;
- else if (es1.elements.length != es2.elements.length)
+ if (es1.elements.length != es2.elements.length)
return 1;
- else
+ foreach (size_t i; 0 .. es1.elements.length)
{
- foreach (size_t i; 0 .. es1.elements.length)
- {
- Expression ee1 = (*es1.elements)[i];
- Expression ee2 = (*es2.elements)[i];
+ Expression ee1 = (*es1.elements)[i];
+ Expression ee2 = (*es2.elements)[i];
- // https://issues.dlang.org/show_bug.cgi?id=16284
- if (ee1.op == EXP.void_ && ee2.op == EXP.void_) // if both are VoidInitExp
- continue;
+ // https://issues.dlang.org/show_bug.cgi?id=16284
+ if (ee1.op == EXP.void_ && ee2.op == EXP.void_) // if both are VoidInitExp
+ continue;
- if (ee1 == ee2)
- continue;
- if (!ee1 || !ee2)
- return 1;
- const int cmp = ctfeRawCmp(loc, ee1, ee2, identity);
- if (cmp)
- return 1;
- }
- return 0; // All elements are equal
+ if (ee1 == ee2)
+ continue;
+ if (!ee1 || !ee2)
+ return 1;
+ const int cmp = ctfeRawCmp(loc, ee1, ee2, identity);
+ if (cmp)
+ return 1;
}
+ return 0; // All elements are equal
}
if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral)
{
@@ -1316,13 +1310,13 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
}
/// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
-bool ctfeEqual(const ref Loc loc, EXP op, Expression e1, Expression e2)
+bool ctfeEqual(Loc loc, EXP op, Expression e1, Expression e2)
{
return !ctfeRawCmp(loc, e1, e2) ^ (op == EXP.notEqual);
}
/// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
-bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
+bool ctfeIdentity(Loc loc, EXP op, Expression e1, Expression e2)
{
//printf("ctfeIdentity %s %s\n", e1.toChars(), e2.toChars());
//printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", EXPtoString(op).ptr,
@@ -1342,7 +1336,7 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
SymOffExp es2 = e2.isSymOffExp();
cmp = (es1.var == es2.var && es1.offset == es2.offset);
}
- else if (e1.type.isfloating())
+ else if (e1.type.isFloating())
cmp = e1.isIdentical(e2);
else
{
@@ -1354,29 +1348,29 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
}
/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
-bool ctfeCmp(const ref Loc loc, EXP op, Expression e1, Expression e2)
+bool ctfeCmp(Loc loc, EXP op, Expression e1, Expression e2)
{
Type t1 = e1.type.toBasetype();
Type t2 = e2.type.toBasetype();
if (t1.isString() && t2.isString())
return specificCmp(op, ctfeRawCmp(loc, e1, e2));
- else if (t1.isreal())
+ if (t1.isReal())
return realCmp(op, e1.toReal(), e2.toReal());
- else if (t1.isimaginary())
+ if (t1.isImaginary())
return realCmp(op, e1.toImaginary(), e2.toImaginary());
- else if (t1.isunsigned() || t2.isunsigned())
+ if (t1.isUnsigned() || t2.isUnsigned())
return intUnsignedCmp(op, e1.toInteger(), e2.toInteger());
else
return intSignedCmp(op, e1.toInteger(), e2.toInteger());
}
-UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp ctfeCat(Loc loc, Type type, Expression e1, Expression e2)
{
Type t1 = e1.type.toBasetype();
Type t2 = e2.type.toBasetype();
UnionExp ue;
- if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
+ if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isIntegral())
{
// [chars] ~ string => string (only valid for CTFE)
StringExp es1 = e2.isStringExp();
@@ -1405,7 +1399,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
es.type = type;
return ue;
}
- if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
+ if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isIntegral())
{
// string ~ [chars] => string (only valid for CTFE)
// Concatenate the strings
@@ -1465,7 +1459,7 @@ UnionExp ctfeCat(const ref 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(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2)
+Expression findKeyInAA(Loc loc, AssocArrayLiteralExp ae, Expression e2)
{
/* Search the keys backwards, in case there are duplicate keys
*/
@@ -1486,7 +1480,7 @@ Expression findKeyInAA(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2
* dynamic arrays, and strings. We know that e1 is an
* interpreted CTFE expression, so it cannot have side-effects.
*/
-Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, uinteger_t indx)
+Expression ctfeIndex(UnionExp* pue, Loc loc, Type type, Expression e1, uinteger_t indx)
{
//printf("ctfeIndex(e1 = %s)\n", e1.toChars());
assert(e1.type);
@@ -1515,7 +1509,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1,
assert(0);
}
-Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expression e, bool explicitCast = false)
+Expression ctfeCast(UnionExp* pue, Loc loc, Type type, Type to, Expression e, bool explicitCast = false)
{
Expression paint()
{
@@ -1535,11 +1529,9 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres
: tclass.implicitConvTo(to.mutableOf());
if (match)
return paint();
- else
- {
- emplaceExp!(NullExp)(pue, loc, to);
- return pue.exp();
- }
+
+ emplaceExp!(NullExp)(pue, loc, to);
+ return pue.exp();
}
// Allow TypeInfo type painting
@@ -1657,7 +1649,7 @@ void assignInPlace(Expression dest, Expression src)
}
// Given an AA literal aae, set aae[index] = newval and return newval.
-Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae, Expression index, Expression newval)
+Expression assignAssocArrayElement(Loc loc, AssocArrayLiteralExp aae, Expression index, Expression newval)
{
/* Create new associative array literal reflecting updated key/value
*/
@@ -1687,7 +1679,7 @@ Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae,
/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
/// all new elements will be set to the default initializer for the element type.
-Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen)
+Expression changeArrayLiteralLength(UnionExp* pue, Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen)
{
Type elemType = arrayType.next;
assert(elemType);
@@ -1774,7 +1766,7 @@ bool isCtfeValueValid(Expression newval)
case EXP.int64:
case EXP.float64:
case EXP.complex80:
- return tb.isscalar();
+ return tb.isScalar();
case EXP.null_:
return tb.ty == Tnull ||
@@ -1849,7 +1841,7 @@ bool isCtfeValueValid(Expression newval)
const SliceExp se = newval.isSliceExp();
assert(se.lwr && se.lwr.op == EXP.int64);
assert(se.upr && se.upr.op == EXP.int64);
- return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral);
+ return tb.isStaticOrDynamicArray() && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral);
}
case EXP.void_:
diff --git a/gcc/d/dmd/ctorflow.d b/gcc/d/dmd/ctorflow.d
index ba5240e..e604700 100644
--- a/gcc/d/dmd/ctorflow.d
+++ b/gcc/d/dmd/ctorflow.d
@@ -1,12 +1,12 @@
/**
* Manage flow analysis for constructors.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d, _ctorflow.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ctorflow.d, _ctorflow.d)
* Documentation: https://dlang.org/phobos/dmd_ctorflow.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctorflow.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/ctorflow.d
*/
module dmd.ctorflow;
diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d
index a0432d2..234b652 100644
--- a/gcc/d/dmd/cxxfrontend.d
+++ b/gcc/d/dmd/cxxfrontend.d
@@ -1,19 +1,22 @@
/**
* Contains C++ interfaces for interacting with DMD as a library.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cxxfrontend.d, _cxxfrontend.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cxxfrontend.d, _cxxfrontend.d)
* Documentation: https://dlang.org/phobos/dmd_cxxfrontend.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cxxfrontend.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/cxxfrontend.d
*/
module dmd.cxxfrontend;
import dmd.aggregate : AggregateDeclaration;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.attrib;
import dmd.common.outbuffer : OutBuffer;
+import dmd.dclass : ClassDeclaration;
+import dmd.declaration : TypeInfoDeclaration;
import dmd.denum : EnumDeclaration;
import dmd.dmodule /*: Module*/;
import dmd.dscope : Scope;
@@ -35,24 +38,33 @@ import dmd.statement : Statement, AsmStatement, GccAsmStatement;
extern (C++, "dmd"):
/***********************************************************
- * cppmangle.d
+ * atrtibsem.d
+ */
+Expressions* getAttributes(UserAttributeDeclaration a)
+{
+ import dmd.attribsem;
+ return dmd.attribsem.getAttributes(a);
+}
+
+/***********************************************************
+ * mangle/cpp.d
*/
const(char)* toCppMangleItanium(Dsymbol s)
{
- import dmd.cppmangle;
- return dmd.cppmangle.toCppMangleItanium(s);
+ import dmd.mangle.cpp;
+ return dmd.mangle.cpp.toCppMangleItanium(s);
}
const(char)* cppTypeInfoMangleItanium(Dsymbol s)
{
- import dmd.cppmangle;
- return dmd.cppmangle.cppTypeInfoMangleItanium(s);
+ import dmd.mangle.cpp;
+ return dmd.mangle.cpp.cppTypeInfoMangleItanium(s);
}
const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
{
- import dmd.cppmangle;
- return dmd.cppmangle.cppThunkMangleItanium(fd, offset);
+ import dmd.mangle.cpp;
+ return dmd.mangle.cpp.cppThunkMangleItanium(fd, offset);
}
/***********************************************************
@@ -65,36 +77,36 @@ Expression ctfeInterpret(Expression e)
}
/***********************************************************
- * dmangle.d
+ * mangle/package.d
*/
const(char)* mangleExact(FuncDeclaration fd)
{
- import dmd.dmangle;
- return dmd.dmangle.mangleExact(fd);
+ import dmd.mangle;
+ return dmd.mangle.mangleExact(fd);
}
void mangleToBuffer(Type t, ref OutBuffer buf)
{
- import dmd.dmangle;
- return dmd.dmangle.mangleToBuffer(t, buf);
+ import dmd.mangle;
+ return dmd.mangle.mangleToBuffer(t, buf);
}
void mangleToBuffer(Expression e, ref OutBuffer buf)
{
- import dmd.dmangle;
- return dmd.dmangle.mangleToBuffer(e, buf);
+ import dmd.mangle;
+ return dmd.mangle.mangleToBuffer(e, buf);
}
void mangleToBuffer(Dsymbol s, ref OutBuffer buf)
{
- import dmd.dmangle;
- return dmd.dmangle.mangleToBuffer(s, buf);
+ import dmd.mangle;
+ return dmd.mangle.mangleToBuffer(s, buf);
}
void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
{
- import dmd.dmangle;
- return dmd.dmangle.mangleToBuffer(ti, buf);
+ import dmd.mangle;
+ return dmd.mangle.mangleToBuffer(ti, buf);
}
/***********************************************************
@@ -143,7 +155,7 @@ void addMember(Dsymbol dsym, Scope* sc, ScopeDsymbol sds)
return dmd.dsymbolsem.addMember(dsym, sc, sds);
}
-Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags
+Dsymbol search(Dsymbol d, Loc loc, Identifier ident, SearchOptFlags
flags = SearchOpt.all)
{
import dmd.dsymbolsem;
@@ -162,6 +174,24 @@ void importAll(Dsymbol d, Scope* sc)
return dmd.dsymbolsem.importAll(d, sc);
}
+Dsymbols* include(Dsymbol d, Scope* sc)
+{
+ import dmd.dsymbolsem;
+ return dmd.dsymbolsem.include(d, sc);
+}
+
+bool isFuncHidden(ClassDeclaration cd, FuncDeclaration fd)
+{
+ import dmd.dsymbolsem;
+ return dmd.dsymbolsem.isFuncHidden(cd, fd);
+}
+
+Dsymbol vtblSymbol(ClassDeclaration cd)
+{
+ import dmd.dsymbolsem;
+ return dmd.dsymbolsem.vtblSymbol(cd);
+}
+
/***********************************************************
* dtemplate.d
*/
@@ -217,7 +247,7 @@ void genCppHdrFiles(ref Modules ms)
/***********************************************************
* enumsem.d
*/
-Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc)
+Expression getDefaultValue(EnumDeclaration ed, Loc loc)
{
import dmd.enumsem;
return dmd.enumsem.getDefaultValue(ed, loc);
@@ -240,6 +270,26 @@ Expression expressionSemantic(Expression e, Scope* sc)
return dmd.expressionsem.expressionSemantic(e, sc);
}
+bool fill(StructDeclaration sd, Loc loc,
+ ref Expressions elements, bool ctorinit)
+{
+ import dmd.expressionsem;
+ return dmd.expressionsem.fill(sd, loc, elements, ctorinit);
+}
+
+/***********************************************************
+ * func.d
+ */
+FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = STC.none)
+{
+ return FuncDeclaration.genCfunc(fparams, treturn, name, cast(STC) stc);
+}
+
+FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = STC.none)
+{
+ return FuncDeclaration.genCfunc(fparams, treturn, id, cast(STC) stc);
+}
+
/***********************************************************
* funcsem.d
*/
@@ -255,6 +305,18 @@ bool functionSemantic3(FuncDeclaration fd)
return dmd.funcsem.functionSemantic3(fd);
}
+MATCH leastAsSpecialized(FuncDeclaration fd, FuncDeclaration g, Identifiers* names)
+{
+ import dmd.funcsem;
+ return dmd.funcsem.leastAsSpecialized(fd, g, names);
+}
+
+PURE isPure(FuncDeclaration fd)
+{
+ import dmd.funcsem;
+ return dmd.funcsem.isPure(fd);
+}
+
/***********************************************************
* hdrgen.d
*/
@@ -303,13 +365,13 @@ const(char)* parametersTypeToChars(ParameterList pl)
/***********************************************************
* iasm.d
*/
-Statement asmSemantic(AsmStatement s, Scope *sc)
+Statement asmSemantic(AsmStatement s, Scope* sc)
{
import dmd.iasm;
return dmd.iasm.asmSemantic(s, sc);
}
-void asmSemantic(CAsmDeclaration d, Scope *sc)
+void asmSemantic(CAsmDeclaration d, Scope* sc)
{
import dmd.iasm;
return dmd.iasm.asmSemantic(d, sc);
@@ -318,13 +380,13 @@ void asmSemantic(CAsmDeclaration d, Scope *sc)
/***********************************************************
* iasmgcc.d
*/
-Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
+Statement gccAsmSemantic(GccAsmStatement s, Scope* sc)
{
import dmd.iasmgcc;
return dmd.iasmgcc.gccAsmSemantic(s, sc);
}
-void gccAsmSemantic(CAsmDeclaration d, Scope *sc)
+void gccAsmSemantic(CAsmDeclaration d, Scope* sc)
{
import dmd.iasmgcc;
return dmd.iasmgcc.gccAsmSemantic(d, sc);
@@ -403,6 +465,11 @@ void semanticTypeInfoMembers(StructDeclaration sd)
return dmd.semantic3.semanticTypeInfoMembers(sd);
}
+bool checkClosure(FuncDeclaration fd)
+{
+ import dmd.semantic3;
+ return dmd.semantic3.checkClosure(fd);
+}
/***********************************************************
* statementsem.d
*/
@@ -430,13 +497,13 @@ bool hasPointers(Type t)
return dmd.typesem.hasPointers(t);
}
-Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
+Type typeSemantic(Type type, Loc loc, Scope* sc)
{
import dmd.typesem;
return dmd.typesem.typeSemantic(type, loc, sc);
}
-Type trySemantic(Type type, const ref Loc loc, Scope* sc)
+Type trySemantic(Type type, Loc loc, Scope* sc)
{
import dmd.typesem;
return dmd.typesem.trySemantic(type, loc, sc);
@@ -454,7 +521,7 @@ Type merge2(Type type)
return dmd.typesem.merge2(type);
}
-Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
+Expression defaultInit(Type mt, Loc loc, const bool isCfile = false)
{
import dmd.typesem;
return dmd.typesem.defaultInit(mt, loc, isCfile);
@@ -470,7 +537,13 @@ Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool
cppCovariant = false)
{
import dmd.typesem;
- return dmd.typesem.covariant(src, t, pstc, cppCovariant);
+ return dmd.typesem.covariant(src, t, cast(STC*) pstc, cppCovariant);
+}
+
+bool isZeroInit(Type t, Loc loc)
+{
+ import dmd.typesem;
+ return dmd.typesem.isZeroInit(t, loc);
}
bool isBaseOf(Type tthis, Type t, int* poffset)
@@ -596,7 +669,7 @@ Type addMod(Type type, MOD mod)
Type addStorageClass(Type type, StorageClass stc)
{
import dmd.typesem;
- return dmd.typesem.addStorageClass(type, stc);
+ return dmd.typesem.addStorageClass(type, cast(STC) stc);
}
Type pointerTo(Type type)
@@ -611,10 +684,34 @@ Type referenceTo(Type type)
return dmd.typesem.referenceTo(type);
}
+uinteger_t size(Type type)
+{
+ import dmd.typesem;
+ return dmd.typesem.size(type);
+}
+
+uinteger_t size(Type type, Loc loc)
+{
+ import dmd.typesem;
+ return dmd.typesem.size(type, loc);
+}
+
+MATCH implicitConvTo(Type from, Type to)
+{
+ import dmd.dcast;
+ return dmd.dcast.implicitConvTo(from, to);
+}
+
+MATCH constConv(Type from, Type to)
+{
+ import dmd.typesem;
+ return dmd.typesem.constConv(from, to);
+}
+
/***********************************************************
* typinf.d
*/
-bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
+bool genTypeInfo(Expression e, Loc loc, Type torig, Scope* sc)
{
import dmd.typinf;
return dmd.typinf.genTypeInfo(e, loc, torig, sc);
@@ -632,6 +729,18 @@ bool builtinTypeInfo(Type t)
return dmd.typinf.builtinTypeInfo(t);
}
+Type makeNakedAssociativeArray(TypeAArray t)
+{
+ import dmd.typinf;
+ return dmd.typinf.makeNakedAssociativeArray(t);
+}
+
+TypeInfoDeclaration getTypeInfoAssocArrayDeclaration(TypeAArray t, Scope* sc)
+{
+ import dmd.typinf;
+ return dmd.typinf.getTypeInfoAssocArrayDeclaration(t, sc);
+}
+
version (IN_LLVM)
{
/***********************************************************
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 8a713f4..86d2f0f 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -1,12 +1,12 @@
/**
* Semantic analysis for cast-expressions.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dcast.d, _dcast.d)
* Documentation: https://dlang.org/phobos/dmd_dcast.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dcast.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dcast.d
*/
module dmd.dcast;
@@ -20,6 +20,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.dclass;
import dmd.declaration;
+import dmd.denum;
import dmd.dinterpret;
import dmd.dscope;
import dmd.dstruct;
@@ -45,6 +46,7 @@ import dmd.root.ctfloat;
import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.root.utf;
+import dmd.safe : setUnsafe;
import dmd.tokens;
import dmd.typesem;
@@ -69,8 +71,8 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
{
Expression visit(Expression e)
{
- // printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
- if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
+ //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
+ if (const match = (sc && sc.inCfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
{
// no need for an extra cast when matching is exact
@@ -148,7 +150,7 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
//printf("type %s t %s\n", type.deco, t.deco);
auto ts = toAutoQualChars(e.type, t);
error(e.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
- e.toChars(), ts[0], ts[1]);
+ e.toErrMsg(), ts[0], ts[1]);
}
}
return ErrorExp.get();
@@ -271,7 +273,7 @@ MATCH implicitConvTo(Expression e, Type t)
/* See if we can do integral narrowing conversions
*/
- if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic())
+ if (e.type.isIntegral() && t.isIntegral() && e.type.isTypeBasic() && t.isTypeBasic())
{
IntRange src = getIntRange(e);
IntRange target = IntRange.fromType(t);
@@ -320,14 +322,14 @@ MATCH implicitConvTo(Expression e, Type t)
Type t1b = e.e1.type.toBasetype();
Type t2b = e.e2.type.toBasetype();
- if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb))
+ if (t1b.ty == Tpointer && t2b.isIntegral() && t1b.equivalent(tb))
{
// ptr + offset
// ptr - offset
MATCH m = e.e1.implicitConvTo(t);
return (m > MATCH.constant) ? MATCH.constant : m;
}
- if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb))
+ if (t2b.ty == Tpointer && t1b.isIntegral() && t2b.equivalent(tb))
{
// offset + ptr
MATCH m = e.e2.implicitConvTo(t);
@@ -452,7 +454,7 @@ MATCH implicitConvTo(Expression e, Type t)
bool isLosslesslyConvertibleToFP(T)()
{
- if (e.type.isunsigned())
+ if (e.type.isUnsigned())
{
const f = cast(T) value;
return cast(dinteger_t) f == value;
@@ -472,7 +474,7 @@ MATCH implicitConvTo(Expression e, Type t)
case Tint8:
if (ty == Tuns64 && value & ~0x7FU)
return MATCH.nomatch;
- else if (cast(byte)value != value)
+ if (cast(byte)value != value)
return MATCH.nomatch;
break;
@@ -489,7 +491,7 @@ MATCH implicitConvTo(Expression e, Type t)
case Tint16:
if (ty == Tuns64 && value & ~0x7FFFU)
return MATCH.nomatch;
- else if (cast(short)value != value)
+ if (cast(short)value != value)
return MATCH.nomatch;
break;
@@ -624,7 +626,7 @@ MATCH implicitConvTo(Expression e, Type t)
if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid)
return MATCH.nomatch;
- if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer))
+ if (!(e.type.isStaticOrDynamicArray() || e.type.ty == Tpointer))
return visit(e);
TY tyn = e.type.nextOf().ty;
@@ -702,8 +704,14 @@ MATCH implicitConvTo(Expression e, Type t)
if (!tn.isConst() && !tn.isImmutable())
return MATCH.nomatch;
m = MATCH.constant;
+
+ // After converting e.g. ubyte[] to const(ubyte)[], don't change
+ // to MATCH.convert, return MATCH.constant
+ // https://github.com/dlang/dmd/issues/20635
+ if (e.type.ty == t.ty && e.type.nextOf().ty == tn.ty)
+ return m;
}
- if (e.hexString && tn.isintegral && (tn.size == e.sz || (!e.committed && (e.len % tn.size) == 0)))
+ if (e.type != t && e.hexString && tn.isIntegral && (tn.size == e.sz || (!e.committed && (e.len % tn.size) == 0)))
{
m = MATCH.convert;
return m;
@@ -756,8 +764,7 @@ MATCH implicitConvTo(Expression e, Type t)
Type typeb = e.type.toBasetype();
auto result = MATCH.nomatch;
- if ((tb.ty == Tarray || tb.ty == Tsarray) &&
- (typeb.ty == Tarray || typeb.ty == Tsarray))
+ if (tb.isStaticOrDynamicArray() && typeb.isStaticOrDynamicArray())
{
result = MATCH.exact;
Type typen = typeb.nextOf().toBasetype();
@@ -800,7 +807,7 @@ MATCH implicitConvTo(Expression e, Type t)
return result;
}
- else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer))
+ else if (tb.ty == Tvector && (typeb.isStaticOrDynamicArray() || typeb.ty == Tpointer))
{ // Tpointer because ImportC eagerly converts Tsarray to Tpointer
result = MATCH.exact;
// Convert array literal to vector type
@@ -930,7 +937,7 @@ MATCH implicitConvTo(Expression e, Type t)
*/
Type tb = t.toBasetype();
MOD mod = tb.mod;
- if (tf.isref)
+ if (tf.isRef)
{
}
else
@@ -1162,7 +1169,7 @@ MATCH implicitConvTo(Expression e, Type t)
if (result != MATCH.nomatch)
return result;
- if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch)
+ if (t.isIntegral() && e.e1.type.isIntegral() && e.e1.implicitConvTo(t) != MATCH.nomatch)
result = MATCH.convert;
else
result = visit(e);
@@ -1468,6 +1475,462 @@ MATCH implicitConvTo(Expression e, Type t)
}
}
+/********************************
+ * Determine if 'from' can be implicitly converted
+ * to type 'to'.
+ * Returns:
+ * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
+ */
+MATCH implicitConvTo(Type from, Type to)
+{
+ MATCH visitType(Type from)
+ {
+ //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", from.toChars());
+ //printf("to : %s\n", to.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+ return MATCH.nomatch;
+
+ }
+
+ MATCH visitBasic(TypeBasic from)
+ {
+ //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), from.toChars());
+ if (from == to)
+ return MATCH.exact;
+
+ if (from.ty == to.ty)
+ {
+ if (from.mod == to.mod)
+ return MATCH.exact;
+ if (MODimplicitConv(from.mod, to.mod))
+ return MATCH.constant;
+ if (!((from.mod ^ to.mod) & MODFlags.shared_)) // for wild matching
+ return MATCH.constant;
+ return MATCH.convert;
+ }
+
+ if (from.ty == Tvoid || to.ty == Tvoid)
+ return MATCH.nomatch;
+ if (to.ty == Tbool)
+ return MATCH.nomatch;
+
+ TypeBasic tob;
+ if (to.ty == Tvector && to.deco)
+ {
+ TypeVector tv = cast(TypeVector)to;
+ tob = tv.elementType();
+ }
+ else if (auto te = to.isTypeEnum())
+ {
+ EnumDeclaration ed = te.sym;
+ if (ed.isSpecial())
+ {
+ /* Special enums that allow implicit conversions to them
+ * with a MATCH.convert
+ */
+ tob = to.toBasetype().isTypeBasic();
+ }
+ else
+ return MATCH.nomatch;
+ }
+ else
+ tob = to.isTypeBasic();
+ if (!tob)
+ return MATCH.nomatch;
+
+ if (from.flags & TFlags.integral)
+ {
+ // Disallow implicit conversion of integers to imaginary or complex
+ if (tob.flags & (TFlags.imaginary | TFlags.complex))
+ return MATCH.nomatch;
+
+ // If converting from integral to integral
+ if (tob.flags & TFlags.integral)
+ {
+ const sz = size(from, Loc.initial);
+ const tosz = tob.size(Loc.initial);
+
+ /* Can't convert to smaller size
+ */
+ if (sz > tosz)
+ return MATCH.nomatch;
+ /* Can't change sign if same size
+ */
+ //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
+ // return MATCH.nomatch;
+ }
+ }
+ else if (from.flags & TFlags.floating)
+ {
+ // Disallow implicit conversion of floating point to integer
+ if (tob.flags & TFlags.integral)
+ return MATCH.nomatch;
+
+ assert(tob.flags & TFlags.floating || to.ty == Tvector);
+
+ // Disallow implicit conversion from complex to non-complex
+ if (from.flags & TFlags.complex && !(tob.flags & TFlags.complex))
+ return MATCH.nomatch;
+
+ // Disallow implicit conversion of real or imaginary to complex
+ if (from.flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex)
+ return MATCH.nomatch;
+
+ // Disallow implicit conversion to-from real and imaginary
+ if ((from.flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary)))
+ return MATCH.nomatch;
+ }
+ return MATCH.convert;
+
+ }
+
+ MATCH visitVector(TypeVector from)
+ {
+ //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), from.toChars());
+ if (from == to)
+ return MATCH.exact;
+ if (to.ty != Tvector)
+ return MATCH.nomatch;
+
+ TypeVector tv = cast(TypeVector)to;
+ assert(from.basetype.ty == Tsarray && tv.basetype.ty == Tsarray);
+
+ // Can't convert to a vector which has different size.
+ if (from.basetype.size() != tv.basetype.size())
+ return MATCH.nomatch;
+
+ // Allow conversion to void[]
+ if (tv.basetype.nextOf().ty == Tvoid)
+ return MATCH.convert;
+
+ // Otherwise implicitly convertible only if basetypes are.
+ return from.basetype.implicitConvTo(tv.basetype);
+ }
+
+ MATCH visitSArray(TypeSArray from)
+ {
+ //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+ if (auto ta = to.isTypeDArray())
+ {
+ if (!MODimplicitConv(from.next.mod, ta.next.mod))
+ return MATCH.nomatch;
+
+ /* Allow conversion to void[]
+ */
+ if (ta.next.ty == Tvoid)
+ {
+ return MATCH.convert;
+ }
+
+ MATCH m = from.next.constConv(ta.next);
+ if (m > MATCH.nomatch)
+ {
+ return MATCH.convert;
+ }
+ return MATCH.nomatch;
+ }
+ if (auto tsa = to.isTypeSArray())
+ {
+ if (from == to)
+ return MATCH.exact;
+
+ if (from.dim.equals(tsa.dim))
+ {
+ MATCH m = from.next.implicitConvTo(tsa.next);
+
+ /* Allow conversion to non-interface base class.
+ */
+ if (m == MATCH.convert &&
+ from.next.ty == Tclass)
+ {
+ if (auto toc = tsa.next.isTypeClass)
+ {
+ if (!toc.sym.isInterfaceDeclaration)
+ return MATCH.convert;
+ }
+ }
+
+ /* Since static arrays are value types, allow
+ * conversions from const elements to non-const
+ * ones, just like we allow conversion from const int
+ * to int.
+ */
+ if (m >= MATCH.constant)
+ {
+ if (from.mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+ }
+ }
+ return MATCH.nomatch;
+ }
+
+ MATCH visitDArray(TypeDArray from)
+ {
+ //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ if (auto ta = to.isTypeDArray())
+ {
+ if (!MODimplicitConv(from.next.mod, ta.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ /* Allow conversion to void[]
+ */
+ if (from.next.ty != Tvoid && ta.next.ty == Tvoid)
+ {
+ return MATCH.convert;
+ }
+
+ MATCH m = from.next.constConv(ta.next);
+ if (m > MATCH.nomatch)
+ {
+ if (m == MATCH.exact && from.mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+ }
+
+ return visitType(from);
+ }
+
+ MATCH visitAArray(TypeAArray from)
+ {
+ //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ if (auto ta = to.isTypeAArray())
+ {
+ if (!MODimplicitConv(from.next.mod, ta.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ if (!MODimplicitConv(from.index.mod, ta.index.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ MATCH m = from.next.constConv(ta.next);
+ MATCH mi = from.index.constConv(ta.index);
+ if (m > MATCH.nomatch && mi > MATCH.nomatch)
+ {
+ return MODimplicitConv(from.mod, to.mod) ? MATCH.constant : MATCH.nomatch;
+ }
+ }
+ return visitType(from);
+ }
+
+ /+
+ + Checks whether this function type is convertible to ` to`
+ + when used in a function pointer / delegate.
+ +
+ + Params:
+ + to = target type
+ +
+ + Returns:
+ + MATCH.nomatch: `to` is not a covaraint function
+ + MATCH.convert: `to` is a covaraint function
+ + MATCH.exact: `to` is identical to this function
+ +/
+ MATCH implicitPointerConv(TypeFunction tf, Type to)
+ {
+ assert(to);
+
+ if (tf.equals(to))
+ return MATCH.constant;
+
+ if (tf.covariant(to) == Covariant.yes)
+ {
+ Type tret = tf.nextOf();
+ Type toret = to.nextOf();
+ if (tret.ty == Tclass && toret.ty == Tclass)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=10219
+ * Check covariant interface return with offset tweaking.
+ * interface I {}
+ * class C : Object, I {}
+ * I function() dg = function C() {} // should be error
+ */
+ int offset = 0;
+ if (toret.isBaseOf(tret, &offset) && offset != 0)
+ return MATCH.nomatch;
+ }
+ return MATCH.convert;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ MATCH visitPointer(TypePointer from)
+ {
+ //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), from.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ // Only convert between pointers
+ auto tp = to.isTypePointer();
+ if (!tp)
+ return MATCH.nomatch;
+
+ assert(from.next);
+ assert(tp.next);
+
+ // Conversion to void*
+ if (tp.next.ty == Tvoid)
+ {
+ // Function pointer conversion doesn't check constness?
+ if (from.next.ty == Tfunction)
+ return MATCH.convert;
+
+ if (!MODimplicitConv(from.next.mod, tp.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ return from.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
+ }
+
+ // Conversion between function pointers
+ if (auto thisTf = from.next.isTypeFunction())
+ return implicitPointerConv(thisTf, tp.next);
+
+ // Default, no implicit conversion between the pointer targets
+ MATCH m = from.next.constConv(tp.next);
+
+ if (m == MATCH.exact && from.mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+
+ MATCH visitDelegate(TypeDelegate from)
+ {
+ //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", from, to);
+ //printf("from: %s\n", from.toChars());
+ //printf("to : %s\n", to.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ if (auto toDg = to.isTypeDelegate())
+ {
+ MATCH m = implicitPointerConv(from.next.isTypeFunction(), toDg.next);
+
+ // Retain the old behaviour for this refactoring
+ // Should probably be changed to constant to match function pointers
+ if (m > MATCH.convert)
+ m = MATCH.convert;
+
+ return m;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ MATCH visitStruct(TypeStruct from)
+ {
+ //printf("TypeStruct::implicitConvTo(%s => %s)\n", from.toChars(), to.toChars());
+ MATCH m = from.implicitConvToWithoutAliasThis(to);
+ return m == MATCH.nomatch ? from.implicitConvToThroughAliasThis(to) : m;
+ }
+
+ MATCH visitEnum(TypeEnum from)
+ {
+ import dmd.enumsem : getMemtype;
+
+ MATCH m;
+ //printf("TypeEnum::implicitConvTo() %s to %s\n", from.toChars(), to.toChars());
+ if (from.ty == to.ty && from.sym == (cast(TypeEnum)to).sym)
+ m = (from.mod == to.mod) ? MATCH.exact : MATCH.constant;
+ else if (from.sym.getMemtype(Loc.initial).implicitConvTo(to))
+ m = MATCH.convert; // match with conversions
+ else
+ m = MATCH.nomatch; // no match
+ return m;
+ }
+
+ MATCH visitClass(TypeClass from)
+ {
+ //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), from.toChars());
+ MATCH m = from.implicitConvToWithoutAliasThis(to);
+ return m ? m : from.implicitConvToThroughAliasThis(to);
+ }
+
+ MATCH visitTuple(TypeTuple from)
+ {
+ if (from == to)
+ return MATCH.exact;
+ if (auto tt = to.isTypeTuple())
+ {
+ if (from.arguments.length == tt.arguments.length)
+ {
+ MATCH m = MATCH.exact;
+ for (size_t i = 0; i < tt.arguments.length; i++)
+ {
+ Parameter arg1 = (*from.arguments)[i];
+ Parameter arg2 = (*tt.arguments)[i];
+ MATCH mi = arg1.type.implicitConvTo(arg2.type);
+ if (mi < m)
+ m = mi;
+ }
+ return m;
+ }
+ }
+ return MATCH.nomatch;
+ }
+
+ MATCH visitNull(TypeNull from)
+ {
+ //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", from, to);
+ //printf("from: %s\n", from.toChars());
+ //printf("to : %s\n", to.toChars());
+ MATCH m = visitType(cast(Type)from);
+ if (m != MATCH.nomatch)
+ return m;
+
+ //NULL implicitly converts to any pointer type or dynamic array
+ //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
+ {
+ Type tb = to.toBasetype();
+ if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate)
+ return MATCH.constant;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ MATCH visitNoreturn(TypeNoreturn from)
+ {
+ //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", from, to);
+ //printf("from: %s\n", from.toChars());
+ //printf("to : %s\n", to.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ // Different qualifiers?
+ if (to.ty == Tnoreturn)
+ return MATCH.constant;
+
+ // Implicitly convertible to any type
+ return MATCH.convert;
+ }
+
+ switch(from.ty)
+ {
+ default: return from.isTypeBasic() ? visitBasic(from.isTypeBasic()) : visitType(from);
+ case Tvector: return visitVector(from.isTypeVector());
+ case Tsarray: return visitSArray(from.isTypeSArray());
+ case Tarray: return visitDArray(from.isTypeDArray());
+ case Taarray: return visitAArray(from.isTypeAArray());
+ case Tpointer: return visitPointer(from.isTypePointer());
+ case Tdelegate: return visitDelegate(from.isTypeDelegate());
+ case Tstruct: return visitStruct(from.isTypeStruct());
+ case Tenum: return visitEnum(from.isTypeEnum());
+ case Tclass: return visitClass(from.isTypeClass());
+ case Ttuple: return visitTuple(from.isTypeTuple());
+ case Tnull: return visitNull(from.isTypeNull());
+ case Tnoreturn: return visitNoreturn(from.isTypeNoreturn());
+ }
+}
+
/**
* Same as implicitConvTo(); except follow C11 rules, which are quite a bit
* more permissive than D.
@@ -1489,12 +1952,12 @@ MATCH cimplicitConvTo(Expression e, Type t)
if (tb.isTypeVector() || typeb.isTypeVector())
return implicitConvTo(e, t); // permissive checking doesn't apply to vectors
- if ((typeb.isintegral() || typeb.isfloating()) &&
- (tb.isintegral() || tb.isfloating()))
+ if ((typeb.isIntegral() || typeb.isFloating()) &&
+ (tb.isIntegral() || tb.isFloating()))
return MATCH.convert;
- if (tb.ty == Tpointer && typeb.isintegral()) // C11 6.3.2.3-5
+ if (tb.ty == Tpointer && typeb.isIntegral()) // C11 6.3.2.3-5
return MATCH.convert;
- if (tb.isintegral() && typeb.ty == Tpointer) // C11 6.3.2.3-6
+ if (tb.isIntegral() && typeb.ty == Tpointer) // C11 6.3.2.3-6
return MATCH.convert;
if (tb.ty == Tpointer && typeb.ty == Tpointer) // C11 6.3.2.3-7
return MATCH.convert;
@@ -1595,8 +2058,8 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass);
// Arithmetic types (== valueable basic types)
- const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector);
- const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector);
+ const(bool) tob_isA = ((tob.isIntegral() || tob.isFloating()) && tob.ty != Tvector);
+ const(bool) t1b_isA = ((t1b.isIntegral() || t1b.isFloating()) && t1b.ty != Tvector);
// Try casting the alias this member.
// Return the expression if it succeeds, null otherwise.
@@ -1682,8 +2145,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
if (hasAliasThis)
{
- auto result = tryAliasThisCast();
- if (result)
+ if (auto result = tryAliasThisCast())
return result;
}
@@ -1777,8 +2239,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
*/
if (hasAliasThis)
{
- auto result = tryAliasThisCast();
- if (result)
+ if (auto result = tryAliasThisCast())
return result;
}
error(e.loc, "cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars());
@@ -1801,7 +2262,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
if (!e.type.equals(t))
{
- if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary()))
+ if ((e.type.isReal() && t.isReal()) || (e.type.isImaginary() && t.isImaginary()))
{
auto result = e.copy();
result.type = t;
@@ -1817,7 +2278,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
if (!e.type.equals(t))
{
- if (e.type.iscomplex() && t.iscomplex())
+ if (e.type.isComplex() && t.isComplex())
{
auto result = e.copy();
result.type = t;
@@ -1848,7 +2309,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
//printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid &&
- (!sc || !(sc.flags & SCOPE.Cfile)))
+ (!sc || !sc.inCfile))
{
error(e.loc, "cannot convert string literal to `void*`");
return ErrorExp.get();
@@ -1878,7 +2339,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
Type tb = t.toBasetype();
Type typeb = e.type.toBasetype();
- if (e.hexString && !e.committed)
+ if (e.hexString && !e.committed && tb.nextOf().isIntegral)
{
const szx = cast(ubyte) tb.nextOf().size();
if (szx != se.sz && (e.len % szx) == 0)
@@ -1979,9 +2440,9 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
if (e.committed)
goto Lcast;
- auto X(T, U)(T tf, U tt)
+ static auto X(T, U)(T tf, U tt)
{
- return (cast(int)tf * 256 + cast(int)tt);
+ return cast(int)tf * 256 + cast(int)tt;
}
{
@@ -2099,7 +2560,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
// See if need to truncate or extend the literal
if (auto tsa = tb.isTypeSArray())
{
- size_t dim2 = cast(size_t)tsa.dim.toInteger();
+ const dim2 = cast(size_t)tsa.dim.toInteger();
//printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2);
// Changing dimensions
@@ -2179,8 +2640,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
{
auto ve = e.e1.isVarExp();
- auto f = ve.var.isFuncDeclaration();
- if (f)
+ if (auto f = ve.var.isFuncDeclaration())
{
assert(f.isImportedSymbol());
f = f.overloadExactMatch(tb.nextOf());
@@ -2257,7 +2717,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
Type tb = t.toBasetype();
if (tb.ty == Tarray)
{
- if (checkArrayLiteralEscape(sc, ae, false))
+ if (checkArrayLiteralEscape(*sc, ae, false))
{
return ErrorExp.get();
}
@@ -2269,8 +2729,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
}
Type typeb = e.type.toBasetype();
- if ((tb.ty == Tarray || tb.ty == Tsarray) &&
- (typeb.ty == Tarray || typeb.ty == Tsarray))
+ if (tb.isStaticOrDynamicArray() && typeb.isStaticOrDynamicArray())
{
if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid)
{
@@ -2285,7 +2744,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
if (auto tsa = tb.isTypeSArray())
{
if (e.elements.length != tsa.dim.toInteger())
- goto L1;
+ return visit(ae);
}
ae = e.copy().isArrayLiteralExp();
@@ -2313,7 +2772,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
ae.type = tp;
}
}
- else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer))
+ else if (tb.ty == Tvector && (typeb.isStaticOrDynamicArray() || typeb.ty == Tpointer))
{
// Convert array literal to vector type
// The Tpointer case comes from C eagerly converting Tsarray to Tpointer
@@ -2323,7 +2782,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
const edim = e.elements.length;
const tbasedim = tbase.dim.toInteger();
if (edim > tbasedim)
- goto L1;
+ return visit(ae);
ae = e.copy().isArrayLiteralExp();
ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642
@@ -2347,7 +2806,6 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
ev = ev.expressionSemantic(sc);
return ev;
}
- L1:
return visit(ae);
}
@@ -2380,6 +2838,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
(*ae.keys)[i] = ex;
}
ae.type = t;
+ semanticTypeInfo(sc, ae.type);
return ae;
}
return visit(e);
@@ -2467,7 +2926,10 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
}
- static immutable msg = "cannot form delegate due to covariant return type";
+ void errorCovariantReturnType()
+ {
+ error(e.loc, "cannot form delegate due to covariant return type");
+ }
Type tb = t.toBasetype();
Type typeb = e.type.toBasetype();
@@ -2477,7 +2939,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
int offset;
e.func.tookAddressOf++;
if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset)
- error(e.loc, "%s", msg.ptr);
+ errorCovariantReturnType();
auto result = e.copy();
result.type = t;
return result;
@@ -2488,12 +2950,11 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
{
if (e.func)
{
- auto f = e.func.overloadExactMatch(tb.nextOf());
- if (f)
+ if (auto f = e.func.overloadExactMatch(tb.nextOf()))
{
int offset;
if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset)
- error(e.loc, "%s", msg.ptr);
+ errorCovariantReturnType();
if (f != e.func) // if address not already marked as taken
f.tookAddressOf++;
auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2);
@@ -2501,7 +2962,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
return result;
}
if (e.func.tintro)
- error(e.loc, "%s", msg.ptr);
+ errorCovariantReturnType();
}
}
@@ -2683,7 +3144,7 @@ Expression inferType(Expression e, Type t, int flag = 0)
Expression visitAle(ArrayLiteralExp ale)
{
Type tb = t.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
Type tn = tb.nextOf();
if (ale.basis)
@@ -2765,7 +3226,7 @@ Expression scaleFactor(BinExp be, Scope* sc)
Type t2b = be.e2.type.toBasetype();
Expression eoff;
- if (t1b.ty == Tpointer && t2b.isintegral())
+ if (t1b.ty == Tpointer && t2b.isIntegral())
{
// Need to adjust operator by the stride
// Replace (ptr + int) with (ptr + (int * stride))
@@ -2779,7 +3240,7 @@ Expression scaleFactor(BinExp be, Scope* sc)
be.e2.type = t;
be.type = be.e1.type;
}
- else if (t2b.ty == Tpointer && t1b.isintegral())
+ else if (t2b.ty == Tpointer && t1b.isIntegral())
{
// Need to adjust operator by the stride
// Replace (int + ptr) with (ptr + (int * stride))
@@ -2806,7 +3267,7 @@ Expression scaleFactor(BinExp be, Scope* sc)
if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
{
}
- else if (sc.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions"))
+ else if (sc.setUnsafe(false, be.loc, "pointer arithmetic"))
{
return ErrorExp.get();
}
@@ -2827,7 +3288,7 @@ private bool isVoidArrayLiteral(Expression e, Type other)
{
auto ale = e.isArrayLiteralExp();
e = ale[0];
- if (other.ty == Tsarray || other.ty == Tarray)
+ if (other.isStaticOrDynamicArray())
other = other.nextOf();
else
return false;
@@ -2902,16 +3363,16 @@ Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2)
Type t1b = e1.type.toBasetype();
Type t2b = e2.type.toBasetype();
- if (sc && sc.flags & SCOPE.Cfile)
+ if (sc && sc.inCfile)
{
// Integral types can be implicitly converted to pointers
if ((t1b.ty == Tpointer) != (t2b.ty == Tpointer))
{
- if (t1b.isintegral())
+ if (t1b.isIntegral())
{
return convert(e1, t2b);
}
- else if (t2b.isintegral())
+ else if (t2b.isIntegral())
{
return convert(e2, t1b);
}
@@ -3033,8 +3494,8 @@ Lagain:
d.purity = PURE.impure;
assert(d.purity != PURE.fwdref);
- d.isnothrow = (tf1.isnothrow && tf2.isnothrow);
- d.isnogc = (tf1.isnogc && tf2.isnogc);
+ d.isNothrow = (tf1.isNothrow && tf2.isNothrow);
+ d.isNogc = (tf1.isNogc && tf2.isNogc);
if (tf1.trust == tf2.trust)
d.trust = tf1.trust;
@@ -3093,7 +3554,7 @@ Lagain:
return null;
}
- if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
+ if (t1.isStaticOrDynamicArray() && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
{
/* (T[n] op void*) => T[]
* (T[] op void*) => T[]
@@ -3105,7 +3566,9 @@ Lagain:
return coerce(t1.nextOf().arrayOf());
}
- if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
+ if (t2.isStaticOrDynamicArray() &&
+ (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.arrayLiteral
+ && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
{
/* (void* op T[n]) => T[]
* (void* op T[]) => T[]
@@ -3117,7 +3580,7 @@ Lagain:
return coerce(t2.nextOf().arrayOf());
}
- if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch)
+ if (t1.isStaticOrDynamicArray() && (m = t1.implicitConvTo(t2)) != MATCH.nomatch)
{
// https://issues.dlang.org/show_bug.cgi?id=7285
// Tsarray op [x, y, ...] should to be Tsarray
@@ -3133,7 +3596,7 @@ Lagain:
return convert(e1, t2);
}
- if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1))
+ if (t2.isStaticOrDynamicArray() && t2.implicitConvTo(t1))
{
// https://issues.dlang.org/show_bug.cgi?id=7285
// https://issues.dlang.org/show_bug.cgi?id=14737
@@ -3142,7 +3605,8 @@ Lagain:
return convert(e2, t1);
}
- if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod)
+ if ((t1.isStaticOrDynamicArray() || t1.ty == Tpointer) && (t2.isStaticOrDynamicArray() || t2.ty == Tpointer)
+ && t1.nextOf().mod != t2.nextOf().mod)
{
/* If one is mutable and the other immutable, then retry
* with both of them as const
@@ -3424,7 +3888,7 @@ LmergeClassTypes:
goto Lagain;
}
- if (t1.isintegral() && t2.isintegral())
+ if (t1.isIntegral() && t2.isIntegral())
{
if (t1.ty != t2.ty)
{
@@ -3462,7 +3926,7 @@ LmodCompare:
return convert(e1, t2);
/// Covers array operations for user-defined types
- Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope *sc)
+ Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope* sc)
{
// scalar op scalar - we shouldn't be here
if (e1.type.ty != Tarray && e1.type.ty != Tsarray && e2.type.ty != Tarray && e2.type.ty != Tsarray)
@@ -3681,26 +4145,12 @@ Expression typeCombine(BinExp be, Scope* sc)
{
Expression errorReturn()
{
- Expression ex = be.incompatibleTypes();
+ Expression ex = be.incompatibleTypes(sc);
if (ex.op == EXP.error)
return ex;
return ErrorExp.get();
}
- Type t1 = be.e1.type.toBasetype();
- Type t2 = be.e2.type.toBasetype();
-
- if (be.op == EXP.min || be.op == EXP.add)
- {
- // struct+struct, and class+class are errors
- if (t1.ty == Tstruct && t2.ty == Tstruct)
- return errorReturn();
- else if (t1.ty == Tclass && t2.ty == Tclass)
- return errorReturn();
- else if (t1.ty == Taarray && t2.ty == Taarray)
- return errorReturn();
- }
-
if (auto result = typeMerge(sc, be.op, be.e1, be.e2))
{
if (be.type is null)
@@ -3762,7 +4212,7 @@ Expression integralPromotions(Expression e, Scope* sc)
void fix16997(Scope* sc, UnaExp ue)
{
- if (global.params.fix16997 || sc.flags & SCOPE.Cfile)
+ if (global.params.fix16997 || sc.inCfile)
ue.e1 = integralPromotions(ue.e1, sc); // desired C-like behavor
else
{
@@ -3797,7 +4247,7 @@ extern (D) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2)
t1 = t1.toBasetype();
t2 = t2.toBasetype();
- if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && t2.ty == t1.ty)
+ if ((t1.isStaticOrDynamicArray() || t1.ty == Tpointer) && t2.ty == t1.ty)
{
if (t1.nextOf().implicitConvTo(t2.nextOf()) >= MATCH.constant || t2.nextOf().implicitConvTo(t1.nextOf()) >= MATCH.constant)
return true;
@@ -3944,10 +4394,9 @@ IntRange getIntRange(Expression e)
VarDeclaration vd = e.var.isVarDeclaration();
if (vd && vd.range)
return vd.range._cast(e.type);
- else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null)
+ if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null)
return getIntRange(ie);
- else
- return visit(e);
+ return visit(e);
}
IntRange visitComma(CommaExp e)
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 8bac1f4..80d39fa 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/class.html, Classes)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dclass.d, _dclass.d)
* Documentation: https://dlang.org/phobos/dmd_dclass.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dclass.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dclass.d
*/
module dmd.dclass;
@@ -23,7 +23,7 @@ import dmd.gluelayer;
import dmd.declaration;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, addMember, setFieldOffset;
import dmd.errors;
import dmd.func;
import dmd.id;
@@ -33,7 +33,7 @@ import dmd.mtype;
import dmd.objc;
import dmd.root.rmem;
import dmd.target;
-import dmd.typesem;
+import dmd.typesem : covariant, immutableOf, sarrayOf;
import dmd.visitor;
/***********************************************************
@@ -198,7 +198,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
- final extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
+ final extern (D) this(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
{
objc = ObjcClassDeclaration(this);
@@ -206,6 +206,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
id = Identifier.generateAnonymousId("class");
super(loc, id);
+ this.dsym = DSYM.classDeclaration;
static immutable msg = "only object.d can define this reserved class name";
@@ -375,7 +376,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
.error(loc, fmt, kind, toPrettyChars, arg);
}
- static ClassDeclaration create(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
+ static ClassDeclaration create(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
{
return new ClassDeclaration(loc, id, baseclasses, members, inObject);
}
@@ -489,8 +490,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
return null;
if (cdb.ident.equals(ident))
return cdb;
- auto result = cdb.searchBase(ident);
- if (result)
+ if (auto result = cdb.searchBase(ident))
return result;
}
return null;
@@ -614,39 +614,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
return classKind == ClassKind.d;
}
- final bool isFuncHidden(FuncDeclaration fd)
- {
- //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
- Dsymbol s = this.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors);
- if (!s)
- {
- //printf("not found\n");
- /* Because, due to a hack, if there are multiple definitions
- * of fd.ident, NULL is returned.
- */
- return false;
- }
- s = s.toAlias();
- if (auto os = s.isOverloadSet())
- {
- foreach (sm; os.a)
- {
- auto fm = sm.isFuncDeclaration();
- if (overloadApply(fm, s => fd == s.isFuncDeclaration()))
- return false;
- }
- return true;
- }
- else
- {
- auto f = s.isFuncDeclaration();
- //printf("%s fdstart = %p\n", s.kind(), fdstart);
- if (overloadApply(f, s => fd == s.isFuncDeclaration()))
- return false;
- return !fd.parent.isTemplateMixin();
- }
- }
-
/****************
* Find virtual function matching identifier and type.
* Used to build virtual function tables for interface implementations.
@@ -921,31 +888,11 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
// Back end
Dsymbol vtblsym;
- final Dsymbol vtblSymbol()
- {
- if (!vtblsym)
- {
- auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.length);
- auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_);
- var.addMember(null, this);
- var.isdataseg = 1;
- var._linkage = LINK.d;
- var.semanticRun = PASS.semanticdone; // no more semantic wanted
- vtblsym = var;
- }
- return vtblsym;
- }
-
extern (D) final bool isErrorException()
{
return errorException && (this == errorException || errorException.isBaseOf(this, null));
}
- override final inout(ClassDeclaration) isClassDeclaration() inout @nogc nothrow pure @safe
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -956,9 +903,10 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
*/
extern (C++) final class InterfaceDeclaration : ClassDeclaration
{
- extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses)
+ extern (D) this(Loc loc, Identifier id, BaseClasses* baseclasses)
{
super(loc, id, baseclasses, null, false);
+ this.dsym = DSYM.interfaceDeclaration;
if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces
{
com = true;
@@ -1058,11 +1006,6 @@ extern (C++) final class InterfaceDeclaration : ClassDeclaration
return com;
}
- override inout(InterfaceDeclaration) isInterfaceDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 3f9769d..4510927 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -2,12 +2,12 @@
* Miscellaneous declarations, including typedef, alias, variable declarations including the
* implicit this declaration, type tuples, ClassInfo, ModuleInfo and various TypeInfos.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d, _declaration.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/declaration.d, _declaration.d)
* Documentation: https://dlang.org/phobos/dmd_declaration.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/declaration.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/declaration.d
*/
module dmd.declaration;
@@ -22,200 +22,52 @@ import dmd.delegatize;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, aliasSemantic;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
import dmd.func;
+import dmd.funcsem : overloadApply, getLevelAndCheck;
import dmd.globals;
import dmd.gluelayer;
+import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.init;
-import dmd.initsem;
+import dmd.initsem : initializerToExpression, initializerSemantic;
import dmd.intrange;
import dmd.location;
import dmd.mtype;
import dmd.common.outbuffer;
import dmd.rootobject;
+import dmd.root.filename;
import dmd.target;
import dmd.tokens;
-import dmd.typesem;
+import dmd.typesem : toDsymbol, typeSemantic, size, hasPointers;
import dmd.visitor;
version (IN_GCC) {}
else version (IN_LLVM) {}
else version = MARS;
-/************************************
- * Check to see the aggregate type is nested and its context pointer is
- * accessible from the current scope.
- * Returns true if error occurs.
+/******************************************
*/
-bool checkFrameAccess(Loc loc, Scope* sc, AggregateDeclaration ad, size_t iStart = 0)
+void ObjectNotFound(Loc loc, Identifier id)
{
- Dsymbol sparent = ad.toParentLocal();
- Dsymbol sparent2 = ad.toParent2();
- Dsymbol s = sc.func;
- if (ad.isNested() && s)
- {
- //printf("ad = %p %s [%s], parent:%p\n", ad, ad.toChars(), ad.loc.toChars(), ad.parent);
- //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent.toChars(), sparent.loc.toChars(), sparent.parent,toChars());
- //printf("sparent2 = %p %s [%s], parent: %s\n", sparent2, sparent2.toChars(), sparent2.loc.toChars(), sparent2.parent,toChars());
- if (!ensureStaticLinkTo(s, sparent) || sparent != sparent2 && !ensureStaticLinkTo(s, sparent2))
- {
- error(loc, "cannot access frame pointer of `%s`", ad.toPrettyChars());
- return true;
- }
- }
-
- bool result = false;
- for (size_t i = iStart; i < ad.fields.length; i++)
+ global.gag = 0; // never gag the fatal error
+ error(loc, "`%s` not found. object.d may be incorrectly installed or corrupt.", id.toChars());
+ version (IN_LLVM)
{
- VarDeclaration vd = ad.fields[i];
- Type tb = vd.type.baseElemOf();
- if (tb.ty == Tstruct)
- {
- result |= checkFrameAccess(loc, sc, (cast(TypeStruct)tb).sym);
- }
+ errorSupplemental(loc, "ldc2 might not be correctly installed.");
+ errorSupplemental(loc, "Please check your ldc2.conf configuration file.");
+ errorSupplemental(loc, "Installation instructions can be found at http://wiki.dlang.org/LDC.");
}
- return result;
-}
-
-/***********************************************
- * Mark variable v as modified if it is inside a constructor that var
- * is a field in.
- * Also used to allow immutable globals to be initialized inside a static constructor.
- * Returns:
- * true if it's an initialization of v
- */
-bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
-{
- //printf("modifyFieldVar(var = %s)\n", var.toChars());
- Dsymbol s = sc.func;
- while (1)
- {
- FuncDeclaration fd = null;
- if (s)
- fd = s.isFuncDeclaration();
- if (fd &&
- ((fd.isCtorDeclaration() && var.isField()) ||
- ((fd.isStaticCtorDeclaration() || fd.isCrtCtor) && !var.isField())) &&
- fd.toParentDecl() == var.toParent2() &&
- (!e1 || e1.op == EXP.this_))
- {
- bool result = true;
-
- var.ctorinit = true;
- //printf("setting ctorinit\n");
-
- if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof)
- {
- assert(e1);
- auto mustInit = ((var.storage_class & STC.nodefaultctor) != 0 ||
- var.type.needsNested());
-
- const dim = sc.ctorflow.fieldinit.length;
- auto ad = fd.isMemberDecl();
- assert(ad);
- size_t i;
- for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ?
- {
- if (ad.fields[i] == var)
- break;
- }
- assert(i < dim);
- auto fieldInit = &sc.ctorflow.fieldinit[i];
- const fi = fieldInit.csx;
-
- if (fi & CSX.this_ctor)
- {
- if (var.type.isMutable() && e1.type.isMutable())
- result = false;
- else
- {
- const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
- .error(loc, "%s field `%s` initialized multiple times", modStr, var.toChars());
- .errorSupplemental(fieldInit.loc, "Previous initialization is here.");
- }
- }
- else if (sc.inLoop || (fi & CSX.label))
- {
- if (!mustInit && var.type.isMutable() && e1.type.isMutable())
- result = false;
- else
- {
- const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
- .error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var.toChars());
- }
- }
-
- fieldInit.csx |= CSX.this_ctor;
- fieldInit.loc = e1.loc;
- if (var.overlapped) // https://issues.dlang.org/show_bug.cgi?id=15258
- {
- foreach (j, v; ad.fields)
- {
- if (v is var || !var.isOverlappedWith(v))
- continue;
- v.ctorinit = true;
- sc.ctorflow.fieldinit[j].csx = CSX.this_ctor;
- }
- }
- }
- else if (fd != sc.func)
- {
- if (var.type.isMutable())
- result = false;
- else if (sc.func.fes)
- {
- const(char)* p = var.isField() ? "field" : var.kind();
- .error(loc, "%s %s `%s` initialization is not allowed in foreach loop",
- MODtoChars(var.type.mod), p, var.toChars());
- }
- else
- {
- const(char)* p = var.isField() ? "field" : var.kind();
- .error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`",
- MODtoChars(var.type.mod), p, var.toChars(), sc.func.toChars());
- }
- }
- else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
- var.type.isImmutable())
- {
- .error(loc, "%s %s `%s` initialization is not allowed in `static this`",
- MODtoChars(var.type.mod), var.kind(), var.toChars());
- errorSupplemental(loc, "Use `shared static this` instead.");
- }
- else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
- var.type.isConst())
- {
- // @@@DEPRECATED_2.116@@@
- // Turn this into an error, merging with the branch above
- .deprecation(loc, "%s %s `%s` initialization is not allowed in `static this`",
- MODtoChars(var.type.mod), var.kind(), var.toChars());
- deprecationSupplemental(loc, "Use `shared static this` instead.");
- }
- return result;
- }
- else
- {
- if (s)
- {
- s = s.toParentP(var.toParent2());
- continue;
- }
- }
- break;
+ else version (MARS)
+ {
+ errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
+ const dmdConfFile = global.inifilename.length ? FileName.canonicalName(global.inifilename) : "not found";
+ errorSupplemental(loc, "config file: %.*s", cast(int)dmdConfFile.length, dmdConfFile.ptr);
}
- return false;
-}
-
-/******************************************
- */
-void ObjectNotFound(Identifier id)
-{
- error(Loc.initial, "`%s` not found. object.d may be incorrectly installed or corrupt.", id.toChars());
fatal();
}
@@ -235,29 +87,34 @@ extern (C++) abstract class Declaration : Dsymbol
{
Type type;
Type originalType; // before semantic analysis
- StorageClass storage_class = STC.undefined_;
+ STC storage_class = STC.none;
+ // overridden symbol with pragma(mangle, "...")
+ const(char)[] mangleOverride;
Visibility visibility;
- LINK _linkage = LINK.default_; // may be `LINK.system`; use `resolvedLinkage()` to resolve it
short inuse; // used to detect cycles
- ubyte adFlags; // control re-assignment of AliasDeclaration (put here for packing reasons)
- enum wasRead = 1; // set if AliasDeclaration was read
- enum ignoreRead = 2; // ignore any reads of AliasDeclaration
- enum nounderscore = 4; // don't prepend _ to mangled name
- enum hidden = 8; // don't print this in .di files
+ private extern (D) static struct BitFields
+ {
+ LINK _linkage = LINK.default_; // may be `LINK.system`; use `resolvedLinkage()` to resolve it
+ bool wasRead; // set if AliasDeclaration was read
+ bool ignoreRead; // ignore any reads of AliasDeclaration
+ bool noUnderscore; // don't prepend _ to mangled name
+ bool hidden; // don't print this in .di files
+ bool nrvo; /// forward to fd.nrvo_var when generating code
+ }
- // overridden symbol with pragma(mangle, "...")
- const(char)[] mangleOverride;
+ import dmd.common.bitfields;
+ mixin(generateBitFields!(BitFields, ubyte));
- final extern (D) this(Identifier ident) @safe
+ final extern (D) this(DSYM tag, Identifier ident) @safe
{
- super(ident);
+ super(tag, ident);
visibility = Visibility(Visibility.Kind.undefined);
}
- final extern (D) this(const ref Loc loc, Identifier ident) @safe
+ final extern (D) this(DSYM tag, Loc loc, Identifier ident) @safe
{
- super(loc, ident);
+ super(tag, loc, ident);
visibility = Visibility(Visibility.Kind.undefined);
}
@@ -266,7 +123,7 @@ extern (C++) abstract class Declaration : Dsymbol
return "declaration";
}
- override final uinteger_t size(const ref Loc loc)
+ override final uinteger_t size(Loc loc)
{
assert(type);
const sz = type.size();
@@ -275,150 +132,6 @@ extern (C++) abstract class Declaration : Dsymbol
return sz;
}
- /**
- * Issue an error if an attempt to call a disabled method is made
- *
- * If the declaration is disabled but inside a disabled function,
- * returns `true` but do not issue an error message.
- *
- * Params:
- * loc = Location information of the call
- * sc = Scope in which the call occurs
- * isAliasedDeclaration = if `true` searches overload set
- *
- * Returns:
- * `true` if this `Declaration` is `@disable`d, `false` otherwise.
- */
- extern (D) final bool checkDisabled(Loc loc, Scope* sc, bool isAliasedDeclaration = false)
- {
- if (!(storage_class & STC.disable))
- return false;
-
- if (sc.func && sc.func.storage_class & STC.disable)
- return true;
-
- if (auto p = toParent())
- {
- if (auto postblit = isPostBlitDeclaration())
- {
- /* https://issues.dlang.org/show_bug.cgi?id=21885
- *
- * If the generated postblit is disabled, it
- * means that one of the fields has a disabled
- * postblit. Print the first field that has
- * a disabled postblit.
- */
- if (postblit.isGenerated())
- {
- auto sd = p.isStructDeclaration();
- assert(sd);
- for (size_t i = 0; i < sd.fields.length; i++)
- {
- auto structField = sd.fields[i];
- if (structField.overlapped)
- continue;
- Type tv = structField.type.baseElemOf();
- if (tv.ty != Tstruct)
- continue;
- auto sdv = (cast(TypeStruct)tv).sym;
- if (!sdv.postblit)
- continue;
- if (sdv.postblit.isDisabled())
- {
- .error(loc, "%s `%s` is not copyable because field `%s` is not copyable", p.kind, p.toPrettyChars, structField.toChars());
- return true;
- }
- }
- }
- .error(loc, "%s `%s` is not copyable because it has a disabled postblit", p.kind, p.toPrettyChars);
- return true;
- }
- }
-
- // if the function is @disabled, maybe there
- // is an overload in the overload set that isn't
- if (isAliasedDeclaration)
- {
- FuncDeclaration fd = isFuncDeclaration();
- if (fd)
- {
- for (FuncDeclaration ovl = fd; ovl; ovl = cast(FuncDeclaration)ovl.overnext)
- if (!(ovl.storage_class & STC.disable))
- return false;
- }
- }
-
- if (auto ctor = isCtorDeclaration())
- {
- if (ctor.isCpCtor && ctor.isGenerated())
- {
- .error(loc, "generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars());
- return true;
- }
- }
- .error(loc, "%s `%s` cannot be used because it is annotated with `@disable`", kind, toPrettyChars);
- return true;
- }
-
- /*************************************
- * Check to see if declaration can be modified in this context (sc).
- * Issue error if not.
- * Params:
- * loc = location for error messages
- * e1 = `null` or `this` expression when this declaration is a field
- * sc = context
- * flag = if the first bit is set it means do not issue error message for
- * invalid modification; if the second bit is set, it means that
- this declaration is a field and a subfield of it is modified.
- * Returns:
- * Modifiable.yes or Modifiable.initialization
- */
- extern (D) final Modifiable checkModify(Loc loc, Scope* sc, Expression e1, ModifyFlags flag)
- {
- VarDeclaration v = isVarDeclaration();
- if (v && v.canassign)
- return Modifiable.initialization;
-
- if (isParameter() || isResult())
- {
- for (Scope* scx = sc; scx; scx = scx.enclosing)
- {
- if (scx.func == parent && (scx.flags & SCOPE.contract))
- {
- const(char)* s = isParameter() && parent.ident != Id.ensure ? "parameter" : "result";
- if (!(flag & ModifyFlags.noError))
- error(loc, "%s `%s` cannot modify %s `%s` in contract", kind, toPrettyChars, s, toChars());
- return Modifiable.initialization; // do not report type related errors
- }
- }
- }
-
- if (e1 && e1.op == EXP.this_ && isField())
- {
- VarDeclaration vthis = e1.isThisExp().var;
- for (Scope* scx = sc; scx; scx = scx.enclosing)
- {
- if (scx.func == vthis.parent && (scx.flags & SCOPE.contract))
- {
- if (!(flag & ModifyFlags.noError))
- error(loc, "%s `%s` cannot modify parameter `this` in contract", kind, toPrettyChars);
- return Modifiable.initialization; // do not report type related errors
- }
- }
- }
-
- if (v && (v.isCtorinit() || isField()))
- {
- // It's only modifiable if inside the right constructor
- if ((storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_))
- return Modifiable.initialization;
- if (flag & ModifyFlags.fieldAssign)
- return Modifiable.yes;
- return modifyFieldVar(loc, sc, v, e1) ? Modifiable.initialization : Modifiable.yes;
- }
- return Modifiable.yes;
- }
-
final bool isStatic() const pure nothrow @nogc @safe
{
return (storage_class & STC.static_) != 0;
@@ -561,11 +274,6 @@ extern (C++) abstract class Declaration : Dsymbol
return visibility;
}
- override final inout(Declaration) isDeclaration() inout pure nothrow @nogc @safe
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -581,9 +289,9 @@ extern (C++) final class TupleDeclaration : Declaration
bool isexp; // true: expression tuple
bool building; // it's growing in AliasAssign semantic
- extern (D) this(const ref Loc loc, Identifier ident, Objects* objects) @safe
+ extern (D) this(Loc loc, Identifier ident, Objects* objects) @safe
{
- super(loc, ident);
+ super(DSYM.tupleDeclaration, loc, ident);
this.objects = objects;
}
@@ -637,7 +345,7 @@ extern (C++) final class TupleDeclaration : Declaration
}
else
{
- auto arg = new Parameter(Loc.initial, 0, t, null, null, null);
+ auto arg = new Parameter(Loc.initial, STC.none, t, null, null, null);
}
(*args)[i] = arg;
if (!t.deco)
@@ -711,11 +419,6 @@ extern (C++) final class TupleDeclaration : Declaration
return 0;
}
- override inout(TupleDeclaration) isTupleDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -732,25 +435,24 @@ extern (C++) final class AliasDeclaration : Declaration
Dsymbol overnext; // next in overload list
Dsymbol _import; // !=null if unresolved internal alias for selective import
- extern (D) this(const ref Loc loc, Identifier ident, Type type) @safe
+ extern (D) this(Loc loc, Identifier ident, Type type) @safe
{
- super(loc, ident);
- //printf("AliasDeclaration(id = '%s', type = %p)\n", ident.toChars(), type);
- //printf("type = '%s'\n", type.toChars());
+ super(DSYM.aliasDeclaration, loc, ident);
+ //debug printf("AliasDeclaration(id = '%s', type = `%s`, %p)\n", ident.toChars(), dmd.hdrgen.toChars(type), type.isTypeIdentifier());
this.type = type;
assert(type);
}
- extern (D) this(const ref Loc loc, Identifier ident, Dsymbol s) @safe
+ extern (D) this(Loc loc, Identifier ident, Dsymbol s) @safe
{
- super(loc, ident);
- //printf("AliasDeclaration(id = '%s', s = %p)\n", ident.toChars(), s);
+ super(DSYM.aliasDeclaration, loc, ident);
+ //debug printf("AliasDeclaration(id = '%s', s = `%s`)\n", ident.toChars(), s.toChars());
assert(s != this);
this.aliassym = s;
assert(s);
}
- static AliasDeclaration create(const ref Loc loc, Identifier id, Type type) @safe
+ static AliasDeclaration create(Loc loc, Identifier id, Type type) @safe
{
return new AliasDeclaration(loc, id, type);
}
@@ -905,28 +607,38 @@ extern (C++) final class AliasDeclaration : Declaration
override Dsymbol toAlias()
{
- //printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s', inuse = %d)\n",
- // loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym.kind() : "", inuse);
+ 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 (!(adFlags & ignoreRead))
- adFlags |= wasRead; // can never assign to this AliasDeclaration again
+ if (!this.ignoreRead)
+ this.wasRead = true; // can never assign to this AliasDeclaration again
if (inuse == 1 && type && _scope)
{
inuse = 2;
- uint olderrors = global.errors;
+ 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)
- goto Lerr;
+ return err();
if (s)
{
s = s.toAlias();
if (global.errors != olderrors)
- goto Lerr;
+ return err();
aliassym = s;
inuse = 0;
}
@@ -934,9 +646,9 @@ extern (C++) final class AliasDeclaration : Declaration
{
Type t = type.typeSemantic(loc, _scope);
if (t.ty == Terror)
- goto Lerr;
+ return err();
if (global.errors != olderrors)
- goto Lerr;
+ return err();
//printf("t = %s\n", t.toChars());
inuse = 0;
}
@@ -944,14 +656,7 @@ extern (C++) final class AliasDeclaration : Declaration
if (inuse)
{
.error(loc, "%s `%s` recursive alias declaration", kind, toPrettyChars);
-
- Lerr:
- // 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;
+ return err();
}
if (semanticRun >= PASS.semanticdone)
@@ -1017,11 +722,6 @@ extern (C++) final class AliasDeclaration : Declaration
aliassym && aliassym.isOverloadable();
}
- override inout(AliasDeclaration) isAliasDeclaration() inout
- {
- return this;
- }
-
/** Returns: `true` if this instance was created to make a template parameter
visible in the scope of a template body, `false` otherwise */
extern (D) bool isAliasedTemplateParameter() const
@@ -1044,7 +744,7 @@ extern (C++) final class OverDeclaration : Declaration
extern (D) this(Identifier ident, Dsymbol s) @safe
{
- super(ident);
+ super(DSYM.overDeclaration, ident);
this.aliassym = s;
}
@@ -1102,11 +802,6 @@ extern (C++) final class OverDeclaration : Declaration
return result;
}
- override inout(OverDeclaration) isOverDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1123,7 +818,6 @@ extern (C++) class VarDeclaration : Declaration
VarDeclaration lastVar; // Linked list of variables for goto-skips-init detection
Expression edtor; // if !=null, does the destruction of the variable
IntRange* range; // if !=null, the variable is known to be within the range
- VarDeclarations* maybes; // maybeScope variables that are assigned to this maybeScope variable
uint endlinnum; // line number of end of scope that this var lives in
uint offset;
@@ -1173,7 +867,7 @@ extern (C++) class VarDeclaration : Declaration
byte canassign; // it can be assigned to
ubyte isdataseg; // private data for isDataseg 0 unset, 1 true, 2 false
- final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
+ final extern (D) this(Loc loc, Type type, Identifier ident, Initializer _init, STC storage_class = STC.none)
in
{
assert(ident);
@@ -1181,7 +875,7 @@ extern (C++) class VarDeclaration : Declaration
do
{
//printf("VarDeclaration('%s')\n", ident.toChars());
- super(loc, ident);
+ super(DSYM.varDeclaration, loc, ident);
debug
{
if (!type && !_init)
@@ -1198,9 +892,9 @@ extern (C++) class VarDeclaration : Declaration
this.storage_class = storage_class;
}
- static VarDeclaration create(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
+ static VarDeclaration create(Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.none)
{
- return new VarDeclaration(loc, type, ident, _init, storage_class);
+ return new VarDeclaration(loc, type, ident, _init, cast(STC) storage_class);
}
override VarDeclaration syntaxCopy(Dsymbol s)
@@ -1225,8 +919,7 @@ extern (C++) class VarDeclaration : Declaration
*/
for (auto s = cast(Dsymbol)this; s; s = s.parent)
{
- auto ad = (cast(inout)s).isMember();
- if (ad)
+ if (auto ad = (cast(inout)s).isMember())
return ad;
if (!s.parent || !s.parent.isTemplateMixin())
break;
@@ -1339,7 +1032,7 @@ extern (C++) class VarDeclaration : Declaration
auto vbitoffset = v.offset * 8;
// Bitsize of types are overridden by any bit-field widths.
- ulong tbitsize = void;
+ ulong tbitsize;
if (auto bf = isBitFieldDeclaration())
{
bitoffset += bf.bitOffset;
@@ -1348,7 +1041,7 @@ extern (C++) class VarDeclaration : Declaration
else
tbitsize = tsz * 8;
- ulong vbitsize = void;
+ ulong vbitsize;
if (auto vbf = v.isBitFieldDeclaration())
{
vbitoffset += vbf.bitOffset;
@@ -1370,7 +1063,7 @@ extern (C++) class VarDeclaration : Declaration
/*************************************
* Return true if we can take the address of this variable.
*/
- final bool canTakeAddressOf()
+ final bool canTakeAddressOf() @safe
{
return !(storage_class & STC.manifest);
}
@@ -1378,124 +1071,12 @@ extern (C++) class VarDeclaration : Declaration
/******************************************
* Return true if variable needs to call the destructor.
*/
- final bool needsScopeDtor()
+ final bool needsScopeDtor() @safe
{
//printf("VarDeclaration::needsScopeDtor() %s %d\n", toChars(), edtor && !(storage_class & STC.nodtor));
return edtor && !(storage_class & STC.nodtor);
}
- /******************************************
- * If a variable has a scope destructor call, return call for it.
- * Otherwise, return NULL.
- */
- extern (D) final Expression callScopeDtor(Scope* sc)
- {
- //printf("VarDeclaration::callScopeDtor() %s\n", toChars());
-
- // Destruction of STC.field's is handled by buildDtor()
- if (storage_class & (STC.nodtor | STC.ref_ | STC.out_ | STC.field))
- {
- return null;
- }
-
- if (iscatchvar)
- return null; // destructor is built by `void semantic(Catch c, Scope* sc)`, not here
-
- Expression e = null;
- // Destructors for structs and arrays of structs
- Type tv = type.baseElemOf();
- if (tv.ty == Tstruct)
- {
- StructDeclaration sd = (cast(TypeStruct)tv).sym;
- if (!sd.dtor || sd.errors)
- return null;
-
- const sz = type.size();
- assert(sz != SIZE_INVALID);
- if (!sz)
- return null;
-
- if (type.toBasetype().ty == Tstruct)
- {
- // v.__xdtor()
- e = new VarExp(loc, this);
-
- /* This is a hack so we can call destructors on const/immutable objects.
- * Need to add things like "const ~this()" and "immutable ~this()" to
- * fix properly.
- */
- e.type = e.type.mutableOf();
-
- // Enable calling destructors on shared objects.
- // The destructor is always a single, non-overloaded function,
- // and must serve both shared and non-shared objects.
- e.type = e.type.unSharedOf;
-
- e = new DotVarExp(loc, e, sd.dtor, false);
- e = new CallExp(loc, e);
- }
- else
- {
- // __ArrayDtor(v[0 .. n])
- e = new VarExp(loc, this);
-
- const sdsz = sd.type.size();
- assert(sdsz != SIZE_INVALID && sdsz != 0);
- const n = sz / sdsz;
- SliceExp se = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t),
- new IntegerExp(loc, n, Type.tsize_t));
-
- // Prevent redundant bounds check
- se.upperIsInBounds = true;
- se.lowerIsLessThanUpper = true;
-
- // This is a hack so we can call destructors on const/immutable objects.
- se.type = sd.type.arrayOf();
-
- e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
- }
- return e;
- }
- // Destructors for classes
- if (storage_class & (STC.auto_ | STC.scope_) && !(storage_class & STC.parameter))
- {
- for (ClassDeclaration cd = type.isClassHandle(); cd; cd = cd.baseClass)
- {
- /* We can do better if there's a way with onstack
- * classes to determine if there's no way the monitor
- * could be set.
- */
- //if (cd.isInterfaceDeclaration())
- // error("interface `%s` cannot be scope", cd.toChars());
-
- if (onstack) // if any destructors
- {
- // delete'ing C++ classes crashes (and delete is deprecated anyway)
- if (cd.classKind == ClassKind.cpp)
- {
- // Don't call non-existant dtor
- if (!cd.dtor)
- break;
-
- e = new VarExp(loc, this);
- e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances
- e = new DotVarExp(loc, e, cd.dtor, false);
- e = new CallExp(loc, e);
- break;
- }
-
- // delete this;
- Expression ec;
- ec = new VarExp(loc, this);
- e = new DeleteExp(loc, ec, true);
- e.type = Type.tvoid;
- break;
- }
- }
- }
- return e;
- }
-
/*******************************************
* If variable has a constant expression initializer, get it.
* Otherwise, return null.
@@ -1505,7 +1086,7 @@ extern (C++) class VarDeclaration : Declaration
assert(type && _init);
// Ungag errors when not speculative
- uint oldgag = global.gag;
+ const oldgag = global.gag;
if (global.gag)
{
Dsymbol sym = isMember();
@@ -1528,35 +1109,6 @@ extern (C++) class VarDeclaration : Declaration
return e;
}
- /*******************************************
- * Helper function for the expansion of manifest constant.
- */
- extern (D) final Expression expandInitializer(Loc loc)
- {
- assert((storage_class & STC.manifest) && _init);
-
- auto e = getConstInitializer();
- if (!e)
- {
- .error(loc, "cannot make expression out of initializer for `%s`", toChars());
- return ErrorExp.get();
- }
-
- e = e.copy();
- e.loc = loc; // for better error message
- return e;
- }
-
- override final void checkCtorConstInit()
- {
- version (none)
- {
- /* doesn't work if more than one static ctor */
- if (ctorinit == 0 && isCtorinit() && !isField())
- error("missing initializer in static constructor for const variable");
- }
- }
-
/************************************
* Check to see if this variable is actually in an enclosing function
* rather than the current one.
@@ -1566,7 +1118,7 @@ extern (C++) class VarDeclaration : Declaration
extern (D) final bool checkNestedReference(Scope* sc, Loc loc)
{
//printf("VarDeclaration::checkNestedReference() %s\n", toChars());
- if (sc.intypeof == 1 || (sc.flags & SCOPE.ctfe))
+ if (sc.intypeof == 1 || sc.ctfe)
return false;
if (!parent || parent == sc.parent)
return false;
@@ -1601,7 +1153,7 @@ extern (C++) class VarDeclaration : Declaration
}
// Add this VarDeclaration to fdv.closureVars[] if not already there
- if (!sc.intypeof && !(sc.flags & SCOPE.compile) &&
+ if (!sc.intypeof && !sc.traitsCompiles &&
// https://issues.dlang.org/show_bug.cgi?id=17605
(fdv.skipCodegen || !fdthis.skipCodegen))
{
@@ -1645,12 +1197,6 @@ extern (C++) class VarDeclaration : Declaration
return s;
}
- // Eliminate need for dynamic_cast
- override final inout(VarDeclaration) isVarDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1667,10 +1213,10 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
uint fieldWidth;
uint bitOffset;
- final extern (D) this(const ref Loc loc, Type type, Identifier ident, Expression width)
+ final extern (D) this(Loc loc, Type type, Identifier ident, Expression width)
{
super(loc, type, ident, null);
-
+ this.dsym = DSYM.bitFieldDeclaration;
this.width = width;
this.storage_class |= STC.field;
}
@@ -1684,11 +1230,6 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
return bf;
}
- override final inout(BitFieldDeclaration) isBitFieldDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1705,7 +1246,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
final ulong getMinMax(Identifier id)
{
const width = fieldWidth;
- const uns = type.isunsigned();
+ const uns = type.isUnsigned();
const min = id == Id.min;
ulong v;
assert(width != 0); // should have been rejected in semantic pass
@@ -1728,19 +1269,13 @@ extern (C++) final class SymbolDeclaration : Declaration
{
AggregateDeclaration dsym;
- extern (D) this(const ref Loc loc, AggregateDeclaration dsym) @safe
+ extern (D) this(Loc loc, AggregateDeclaration dsym) @safe
{
- super(loc, dsym.ident);
+ super(DSYM.symbolDeclaration, loc, dsym.ident);
this.dsym = dsym;
storage_class |= STC.const_;
}
- // Eliminate need for dynamic_cast
- override inout(SymbolDeclaration) isSymbolDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1751,7 +1286,7 @@ extern (C++) final class SymbolDeclaration : Declaration
*/
private Identifier getTypeInfoIdent(Type t)
{
- import dmd.dmangle;
+ import dmd.mangle;
import core.stdc.stdlib;
import dmd.root.rmem;
// _init_10TypeInfo_%s
@@ -1785,6 +1320,7 @@ extern (C++) class TypeInfoDeclaration : VarDeclaration
final extern (D) this(Type tinfo)
{
super(Loc.initial, Type.dtypeinfo.type, tinfo.getTypeInfoIdent(), null);
+ this.dsym = DSYM.typeInfoDeclaration;
this.tinfo = tinfo;
storage_class = STC.static_ | STC.gshared;
visibility = Visibility(Visibility.Kind.public_);
@@ -1802,21 +1338,6 @@ extern (C++) class TypeInfoDeclaration : VarDeclaration
assert(0); // should never be produced by syntax
}
- override final const(char)* toChars() const
- {
- //printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo.toChars());
- OutBuffer buf;
- buf.writestring("typeid(");
- buf.writestring(tinfo.toChars());
- buf.writeByte(')');
- return buf.extractChars();
- }
-
- override final inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout @nogc nothrow pure @safe
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1832,7 +1353,7 @@ extern (C++) final class TypeInfoStructDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfostruct)
{
- ObjectNotFound(Id.TypeInfo_Struct);
+ ObjectNotFound(loc, Id.TypeInfo_Struct);
}
type = Type.typeinfostruct.type;
}
@@ -1857,7 +1378,7 @@ extern (C++) final class TypeInfoClassDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfoclass)
{
- ObjectNotFound(Id.TypeInfo_Class);
+ ObjectNotFound(loc, Id.TypeInfo_Class);
}
type = Type.typeinfoclass.type;
}
@@ -1882,7 +1403,7 @@ extern (C++) final class TypeInfoInterfaceDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfointerface)
{
- ObjectNotFound(Id.TypeInfo_Interface);
+ ObjectNotFound(loc, Id.TypeInfo_Interface);
}
type = Type.typeinfointerface.type;
}
@@ -1907,7 +1428,7 @@ extern (C++) final class TypeInfoPointerDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfopointer)
{
- ObjectNotFound(Id.TypeInfo_Pointer);
+ ObjectNotFound(loc, Id.TypeInfo_Pointer);
}
type = Type.typeinfopointer.type;
}
@@ -1932,7 +1453,7 @@ extern (C++) final class TypeInfoArrayDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfoarray)
{
- ObjectNotFound(Id.TypeInfo_Array);
+ ObjectNotFound(loc, Id.TypeInfo_Array);
}
type = Type.typeinfoarray.type;
}
@@ -1957,7 +1478,7 @@ extern (C++) final class TypeInfoStaticArrayDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfostaticarray)
{
- ObjectNotFound(Id.TypeInfo_StaticArray);
+ ObjectNotFound(loc, Id.TypeInfo_StaticArray);
}
type = Type.typeinfostaticarray.type;
}
@@ -1977,12 +1498,14 @@ extern (C++) final class TypeInfoStaticArrayDeclaration : TypeInfoDeclaration
*/
extern (C++) final class TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration
{
+ Type entry; // type of TypeInfo_AssociativeArray.Entry!(t.index, t.next)
+
extern (D) this(Type tinfo)
{
super(tinfo);
if (!Type.typeinfoassociativearray)
{
- ObjectNotFound(Id.TypeInfo_AssociativeArray);
+ ObjectNotFound(loc, Id.TypeInfo_AssociativeArray);
}
type = Type.typeinfoassociativearray.type;
}
@@ -2007,7 +1530,7 @@ extern (C++) final class TypeInfoEnumDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfoenum)
{
- ObjectNotFound(Id.TypeInfo_Enum);
+ ObjectNotFound(loc, Id.TypeInfo_Enum);
}
type = Type.typeinfoenum.type;
}
@@ -2032,7 +1555,7 @@ extern (C++) final class TypeInfoFunctionDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfofunction)
{
- ObjectNotFound(Id.TypeInfo_Function);
+ ObjectNotFound(loc, Id.TypeInfo_Function);
}
type = Type.typeinfofunction.type;
}
@@ -2057,7 +1580,7 @@ extern (C++) final class TypeInfoDelegateDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfodelegate)
{
- ObjectNotFound(Id.TypeInfo_Delegate);
+ ObjectNotFound(loc, Id.TypeInfo_Delegate);
}
type = Type.typeinfodelegate.type;
}
@@ -2082,7 +1605,7 @@ extern (C++) final class TypeInfoTupleDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfotypelist)
{
- ObjectNotFound(Id.TypeInfo_Tuple);
+ ObjectNotFound(loc, Id.TypeInfo_Tuple);
}
type = Type.typeinfotypelist.type;
}
@@ -2107,7 +1630,7 @@ extern (C++) final class TypeInfoConstDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfoconst)
{
- ObjectNotFound(Id.TypeInfo_Const);
+ ObjectNotFound(loc, Id.TypeInfo_Const);
}
type = Type.typeinfoconst.type;
}
@@ -2132,7 +1655,7 @@ extern (C++) final class TypeInfoInvariantDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfoinvariant)
{
- ObjectNotFound(Id.TypeInfo_Invariant);
+ ObjectNotFound(loc, Id.TypeInfo_Invariant);
}
type = Type.typeinfoinvariant.type;
}
@@ -2157,7 +1680,7 @@ extern (C++) final class TypeInfoSharedDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfoshared)
{
- ObjectNotFound(Id.TypeInfo_Shared);
+ ObjectNotFound(loc, Id.TypeInfo_Shared);
}
type = Type.typeinfoshared.type;
}
@@ -2182,7 +1705,7 @@ extern (C++) final class TypeInfoWildDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfowild)
{
- ObjectNotFound(Id.TypeInfo_Wild);
+ ObjectNotFound(loc, Id.TypeInfo_Wild);
}
type = Type.typeinfowild.type;
}
@@ -2207,7 +1730,7 @@ extern (C++) final class TypeInfoVectorDeclaration : TypeInfoDeclaration
super(tinfo);
if (!Type.typeinfovector)
{
- ObjectNotFound(Id.TypeInfo_Vector);
+ ObjectNotFound(loc, Id.TypeInfo_Vector);
}
type = Type.typeinfovector.type;
}
@@ -2228,9 +1751,10 @@ extern (C++) final class TypeInfoVectorDeclaration : TypeInfoDeclaration
*/
extern (C++) final class ThisDeclaration : VarDeclaration
{
- extern (D) this(const ref Loc loc, Type t)
+ extern (D) this(Loc loc, Type t)
{
super(loc, t, Id.This, null);
+ this.dsym = DSYM.thisDeclaration;
storage_class |= STC.nodtor;
}
@@ -2239,11 +1763,6 @@ extern (C++) final class ThisDeclaration : VarDeclaration
assert(0); // should never be produced by syntax
}
- override inout(ThisDeclaration) isThisDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 998beba9..c7e4552 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -34,6 +34,11 @@ namespace dmd
{
bool functionSemantic(FuncDeclaration* fd);
bool functionSemantic3(FuncDeclaration* fd);
+ bool checkClosure(FuncDeclaration* fd);
+ MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names);
+ PURE isPure(FuncDeclaration *f);
+ FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
+ FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
}
//enum STC : ulong from astenums.d:
@@ -118,14 +123,17 @@ public:
Type *type;
Type *originalType; // before semantic analysis
StorageClass storage_class;
+ DString mangleOverride; // overridden symbol with pragma(mangle, "...")
Visibility visibility;
- LINK _linkage; // may be `LINK::system`; use `resolvedLinkage()` to resolve it
short inuse; // used to detect cycles
- uint8_t adFlags;
- DString mangleOverride; // overridden symbol with pragma(mangle, "...")
+ uint8_t bitFields;
+
+ LINK _linkage() const;
+ LINK _linkage(LINK v);
+ bool noUnderscore() const;
const char *kind() const override;
- uinteger_t size(const Loc &loc) override final;
+ uinteger_t size(Loc loc) override final;
bool isStatic() const { return (storage_class & STCstatic) != 0; }
@@ -158,7 +166,6 @@ public:
Visibility visible() override final;
- Declaration *isDeclaration() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -178,7 +185,6 @@ public:
Dsymbol *toAlias2() override;
bool needThis() override;
- TupleDeclaration *isTupleDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -191,7 +197,7 @@ public:
Dsymbol *overnext; // next in overload list
Dsymbol *_import; // !=NULL if unresolved internal alias for selective import
- static AliasDeclaration *create(const Loc &loc, Identifier *id, Type *type);
+ static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
AliasDeclaration *syntaxCopy(Dsymbol *) override;
bool overloadInsert(Dsymbol *s) override;
const char *kind() const override;
@@ -200,7 +206,6 @@ public:
Dsymbol *toAlias2() override;
bool isOverloadable() const override;
- AliasDeclaration *isAliasDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -220,7 +225,6 @@ public:
Dsymbol *isUnique();
bool isOverloadable() const override;
- OverDeclaration *isOverDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -235,7 +239,6 @@ public:
VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection
Expression *edtor; // if !=NULL, does the destruction of the variable
IntRange *range; // if !NULL, the variable is known to be within the range
- VarDeclarations *maybes; // STCmaybescope variables that are assigned to this STCmaybescope variable
unsigned endlinnum; // line number of end of scope that this var lives in
unsigned offset;
@@ -282,7 +285,7 @@ public:
#endif
bool systemInferred() const;
bool systemInferred(bool v);
- static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
+ static VarDeclaration *create(Loc loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
VarDeclaration *syntaxCopy(Dsymbol *) override;
const char *kind() const override;
AggregateDeclaration *isThis() override final;
@@ -297,10 +300,8 @@ public:
bool hasPointers() override final;
bool canTakeAddressOf();
bool needsScopeDtor();
- void checkCtorConstInit() override final;
Dsymbol *toAlias() override final;
// Eliminate need for dynamic_cast
- VarDeclaration *isVarDeclaration() override final { return (VarDeclaration *)this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -315,7 +316,6 @@ public:
unsigned bitOffset;
BitFieldDeclaration *syntaxCopy(Dsymbol *) override;
- BitFieldDeclaration *isBitFieldDeclaration() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -329,7 +329,6 @@ public:
AggregateDeclaration *dsym;
// Eliminate need for dynamic_cast
- SymbolDeclaration *isSymbolDeclaration() override { return (SymbolDeclaration *)this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -340,9 +339,7 @@ public:
static TypeInfoDeclaration *create(Type *tinfo);
TypeInfoDeclaration *syntaxCopy(Dsymbol *) override final;
- const char *toChars() const override final;
- TypeInfoDeclaration *isTypeInfoDeclaration() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -397,6 +394,8 @@ public:
class TypeInfoAssociativeArrayDeclaration final : public TypeInfoDeclaration
{
public:
+ Type* entry;
+
static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo);
void accept(Visitor *v) override { v->visit(this); }
@@ -480,7 +479,6 @@ class ThisDeclaration final : public VarDeclaration
{
public:
ThisDeclaration *syntaxCopy(Dsymbol *) override;
- ThisDeclaration *isThisDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -534,7 +532,7 @@ enum class BUILTIN : unsigned char
toPrecReal
};
-Expression *eval_builtin(const Loc &loc, FuncDeclaration *fd, Expressions *arguments);
+Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments);
BUILTIN isBuiltin(FuncDeclaration *fd);
struct ContractInfo;
@@ -588,13 +586,6 @@ public:
// Things that should really go into Scope
- // 1 if there's a return exp; statement
- // 2 if there's a throw statement
- // 4 if there's an assert(0)
- // 8 if there's inline asm
- // 16 if there are multiple return statements
- int hasReturnExp;
-
VarDeclaration *nrvo_var; // variable to replace with shidden
Symbol *shidden; // hidden pointer passed to function
@@ -637,12 +628,12 @@ public:
bool nothrowInprocess(bool v);
bool nogcInprocess() const;
bool nogcInprocess(bool v);
- bool returnInprocess() const;
- bool returnInprocess(bool v);
+ bool saferD() const;
+ bool saferD(bool v);
+ bool scopeInprocess() const;
+ bool scopeInprocess(bool v);
bool inlineScanned() const;
bool inlineScanned(bool v);
- bool inferScope() const;
- bool inferScope(bool v);
bool hasCatches() const;
bool hasCatches(bool v);
bool skipCodegen() const;
@@ -679,12 +670,18 @@ public:
bool dllImport(bool v);
bool dllExport() const;
bool dllExport(bool v);
+ bool hasReturnExp() const;
+ bool hasReturnExp(bool v);
+ bool hasInlineAsm() const;
+ bool hasInlineAsm(bool v);
+ bool hasMultipleReturnExp() const;
+ bool hasMultipleReturnExp(bool v);
// Data for a function declaration that is needed for the Objective-C
// integration.
ObjcFuncDeclaration objc;
- static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type, bool noreturn = false);
+ static FuncDeclaration *create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type, bool noreturn = false);
FuncDeclaration *syntaxCopy(Dsymbol *) override;
Statements *frequires();
Ensures *fensures();
@@ -706,8 +703,7 @@ public:
bool overloadInsert(Dsymbol *s) override;
bool inUnittest();
- static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names);
- LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc);
+ LabelDsymbol *searchLabel(Identifier *ident, Loc loc);
const char *toPrettyChars(bool QualifyTypes = false) override;
const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure'
bool isMain() const;
@@ -719,10 +715,8 @@ public:
bool isCodeseg() const override final;
bool isOverloadable() const override final;
bool isAbstract() override final;
- PURE isPure();
bool isSafe();
bool isTrusted();
- bool isNogc();
virtual bool isNested() const;
AggregateDeclaration *isThis() override;
@@ -735,15 +729,9 @@ public:
const char *kind() const override;
bool isUnique();
bool needsClosure();
- bool checkClosure();
bool hasNestedFrameRefs();
ParameterList getParameterList();
- static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
- static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
-
- FuncDeclaration *isFuncDeclaration() override final { return this; }
-
virtual FuncDeclaration *toAliasFunc() { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -754,7 +742,6 @@ public:
FuncDeclaration *funcalias;
d_bool hasOverloads;
- FuncAliasDeclaration *isFuncAliasDeclaration() override { return this; }
const char *kind() const override;
FuncDeclaration *toAliasFunc() override;
@@ -777,7 +764,6 @@ public:
bool addPreInvariant() override;
bool addPostInvariant() override;
- FuncLiteralDeclaration *isFuncLiteralDeclaration() override { return this; }
const char *kind() const override;
const char *toPrettyChars(bool QualifyTypes = false) override;
void accept(Visitor *v) override { v->visit(this); }
@@ -787,14 +773,13 @@ class CtorDeclaration final : public FuncDeclaration
{
public:
d_bool isCpCtor;
+ d_bool isMoveCtor;
CtorDeclaration *syntaxCopy(Dsymbol *) override;
const char *kind() const override;
- const char *toChars() const override;
bool isVirtual() const override;
bool addPreInvariant() override;
bool addPostInvariant() override;
- CtorDeclaration *isCtorDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -807,7 +792,6 @@ public:
bool addPostInvariant() override;
bool overloadInsert(Dsymbol *s) override;
- PostBlitDeclaration *isPostBlitDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -816,13 +800,11 @@ class DtorDeclaration final : public FuncDeclaration
public:
DtorDeclaration *syntaxCopy(Dsymbol *) override;
const char *kind() const override;
- const char *toChars() const override;
bool isVirtual() const override;
bool addPreInvariant() override;
bool addPostInvariant() override;
bool overloadInsert(Dsymbol *s) override;
- DtorDeclaration *isDtorDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -834,9 +816,7 @@ public:
bool isVirtual() const override final;
bool addPreInvariant() override final;
bool addPostInvariant() override final;
- bool hasStaticCtorOrDtor() override final;
- StaticCtorDeclaration *isStaticCtorDeclaration() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -846,7 +826,6 @@ public:
bool standalone;
SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *) override;
- SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -858,11 +837,9 @@ public:
StaticDtorDeclaration *syntaxCopy(Dsymbol *) override;
AggregateDeclaration *isThis() override final;
bool isVirtual() const override final;
- bool hasStaticCtorOrDtor() override final;
bool addPreInvariant() override final;
bool addPostInvariant() override final;
- StaticDtorDeclaration *isStaticDtorDeclaration() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -871,7 +848,6 @@ class SharedStaticDtorDeclaration final : public StaticDtorDeclaration
public:
SharedStaticDtorDeclaration *syntaxCopy(Dsymbol *) override;
- SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -883,7 +859,6 @@ public:
bool addPreInvariant() override;
bool addPostInvariant() override;
- InvariantDeclaration *isInvariantDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -901,7 +876,6 @@ public:
bool addPreInvariant() override;
bool addPostInvariant() override;
- UnitTestDeclaration *isUnitTestDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -914,6 +888,5 @@ public:
bool addPreInvariant() override;
bool addPostInvariant() override;
- NewDeclaration *isNewDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d
index 62800d3..344130b 100644
--- a/gcc/d/dmd/delegatize.d
+++ b/gcc/d/dmd/delegatize.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/function.html#lazy-params, Lazy Parameters)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d, _delegatize.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/delegatize.d, _delegatize.d)
* Documentation: https://dlang.org/phobos/dmd_delegatize.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/delegatize.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/delegatize.d
*/
module dmd.delegatize;
@@ -25,10 +25,10 @@ import dmd.init;
import dmd.initsem;
import dmd.location;
import dmd.mtype;
-import dmd.postordervisitor;
import dmd.statement;
import dmd.tokens;
import dmd.visitor;
+import dmd.visitor.postorder;
/*********************************
@@ -215,15 +215,13 @@ bool lambdaCheckForNestedRef(Expression e, Scope* sc)
override void visit(SymOffExp e)
{
- VarDeclaration v = e.var.isVarDeclaration();
- if (v)
+ if (VarDeclaration v = e.var.isVarDeclaration())
result = v.checkNestedReference(sc, Loc.initial);
}
override void visit(VarExp e)
{
- VarDeclaration v = e.var.isVarDeclaration();
- if (v)
+ if (VarDeclaration v = e.var.isVarDeclaration())
result = v.checkNestedReference(sc, Loc.initial);
}
@@ -235,8 +233,7 @@ bool lambdaCheckForNestedRef(Expression e, Scope* sc)
override void visit(DeclarationExp e)
{
- VarDeclaration v = e.declaration.isVarDeclaration();
- if (v)
+ if (VarDeclaration v = e.declaration.isVarDeclaration())
{
result = v.checkNestedReference(sc, Loc.initial);
if (result)
diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d
index 5c739ee..e1a4ab6 100644
--- a/gcc/d/dmd/denum.d
+++ b/gcc/d/dmd/denum.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/denum.d, _denum.d)
* Documentation: https://dlang.org/phobos/dmd_denum.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/denum.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/denum.d
* References: https://dlang.org/spec/enum.html
*/
@@ -64,12 +64,13 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
Symbol* sinit;
- extern (D) this(const ref Loc loc, Identifier ident, Type memtype)
+ extern (D) this(Loc loc, Identifier ident, Type memtype)
{
super(loc, ident);
//printf("EnumDeclaration() %p %s : %s\n", this, toChars(), memtype.toChars());
type = new TypeEnum(this);
this.memtype = memtype;
+ this.dsym = DSYM.enumDeclaration;
visibility = Visibility(Visibility.Kind.undefined);
}
@@ -81,13 +82,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
return ed;
}
- override bool oneMember(out Dsymbol ps, Identifier ident)
- {
- if (isAnonymous())
- return Dsymbol.oneMembers(members, ps, ident);
- return Dsymbol.oneMember(ps, ident);
- }
-
override Type getType()
{
return type;
@@ -120,11 +114,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
return isSpecialEnumIdent(ident) && memtype;
}
- override inout(EnumDeclaration) isEnumDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -154,15 +143,16 @@ extern (C++) final class EnumMember : VarDeclaration
EnumDeclaration ed;
- extern (D) this(const ref Loc loc, Identifier id, Expression value, Type origType)
+ extern (D) this(Loc loc, Identifier id, Expression value, Type origType)
{
super(loc, null, id ? id : Id.empty, new ExpInitializer(loc, value));
this.origValue = value;
this.origType = origType;
+ this.dsym = DSYM.enumMember;
}
extern(D) this(Loc loc, Identifier id, Expression value, Type memtype,
- StorageClass stc, UserAttributeDeclaration uad, DeprecatedDeclaration dd)
+ STC stc, UserAttributeDeclaration uad, DeprecatedDeclaration dd)
{
this(loc, id, value, memtype);
storage_class = stc;
@@ -187,11 +177,6 @@ extern (C++) final class EnumMember : VarDeclaration
return "enum member";
}
- override inout(EnumMember) isEnumMember() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/deps.d b/gcc/d/dmd/deps.d
new file mode 100644
index 0000000..f586a84
--- /dev/null
+++ b/gcc/d/dmd/deps.d
@@ -0,0 +1,141 @@
+/**
+ * Implement the `-deps` and `-makedeps` switches, which output dependencies of modules for build tools.
+ *
+ * The grammar of the `-deps` output is:
+ * ---
+ * ImportDeclaration
+ * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
+ * ModuleAliasIdentifier ] "\n"
+ *
+ * BasicImportDeclaration
+ * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
+ * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
+ *
+ * FilePath
+ * - any string with '(', ')' and '\' escaped with the '\' character
+ * ---
+ *
+ * Make dependencies as generated by `-makedeps` look like this:
+ * ---
+ * source/app.d:
+ * source/importa.d \
+ * source/importb.d
+ * ---
+ *
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/deps.d, makedeps.d)
+ * Documentation: https://dlang.org/phobos/dmd_deps.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/deps.d
+ */
+module dmd.deps;
+
+import core.stdc.stdio : printf;
+import core.stdc.string : strcmp;
+import dmd.common.outbuffer;
+import dmd.dimport : Import;
+import dmd.dmodule : Module;
+import dmd.globals : Param, Output;
+import dmd.hdrgen : visibilityToBuffer;
+import dmd.id : Id;
+import dmd.utils : escapePath;
+
+/**
+ * Add an import expression to module dependencies
+ * Params:
+ * moduleDeps = output settings for `-deps`
+ * makeDeps = output settings for `-makedeps`
+ * fileNameZ = 0-termminated string containing the import expression's resolved filename
+ * importString = raw string passed to import exp
+ * imod = module import exp is in
+ */
+void addImportExpDep(ref Output moduleDeps, ref Output makeDeps, const(char)[] fileNameZ, const(char)[] importString, Module imod)
+{
+ if (moduleDeps.buffer !is null)
+ {
+ OutBuffer* ob = moduleDeps.buffer;
+
+ if (!moduleDeps.name)
+ ob.writestring("depsFile ");
+ ob.writestring(imod.toPrettyChars());
+ ob.writestring(" (");
+ escapePath(ob, imod.srcfile.toChars());
+ ob.writestring(") : ");
+ if (moduleDeps.name)
+ ob.writestring("string : ");
+ ob.write(importString);
+ ob.writestring(" (");
+ escapePath(ob, fileNameZ.ptr);
+ ob.writestring(")");
+ ob.writenl();
+ }
+ if (makeDeps.doOutput)
+ {
+ makeDeps.files.push(fileNameZ.ptr);
+ }
+}
+
+/**
+ * Add an import statement to module dependencies
+ * Params:
+ * moduleDeps = output settings
+ * imp = import to add
+ * imod = module that the import is in
+ */
+void addImportDep(ref Output moduleDeps, Import imp, Module imod)
+{
+ // object self-imports itself, so skip that
+ // https://issues.dlang.org/show_bug.cgi?id=7547
+ // don't list pseudo modules __entrypoint.d, __main.d
+ // https://issues.dlang.org/show_bug.cgi?id=11117
+ // https://issues.dlang.org/show_bug.cgi?id=11164
+ if (moduleDeps.buffer is null || (imp.id == Id.object && imod.ident == Id.object) ||
+ strcmp(imod.ident.toChars(), "__main") == 0)
+ return;
+
+ OutBuffer* ob = moduleDeps.buffer;
+ if (!moduleDeps.name)
+ ob.writestring("depsImport ");
+ ob.writestring(imod.toPrettyChars());
+ ob.writestring(" (");
+ escapePath(ob, imod.srcfile.toChars());
+ ob.writestring(") : ");
+ // use visibility instead of sc.visibility because it couldn't be
+ // resolved yet, see the comment above
+ visibilityToBuffer(*ob, imp.visibility);
+ ob.writeByte(' ');
+ if (imp.isstatic)
+ {
+ ob.writestring("static ");
+ }
+ ob.writestring(": ");
+ foreach (pid; imp.packages)
+ {
+ ob.printf("%s.", pid.toChars());
+ }
+ ob.writestring(imp.id.toString());
+ ob.writestring(" (");
+ if (imp.mod)
+ escapePath(ob, imp.mod.srcfile.toChars());
+ else
+ ob.writestring("???");
+ ob.writeByte(')');
+ foreach (i, name; imp.names)
+ {
+ if (i == 0)
+ ob.writeByte(':');
+ else
+ ob.writeByte(',');
+ auto _alias = imp.aliases[i];
+ if (!_alias)
+ {
+ ob.printf("%s", name.toChars());
+ _alias = name;
+ }
+ else
+ ob.printf("%s=%s", _alias.toChars(), name.toChars());
+ }
+ if (imp.aliasId)
+ ob.printf(" -> %s", imp.aliasId.toChars());
+ ob.writenl();
+}
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index 2efdd31..bbd74a4 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -1,12 +1,12 @@
/**
* A `Dsymbol` representing a renamed import.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dimport.d, _dimport.d)
* Documentation: https://dlang.org/phobos/dmd_dimport.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dimport.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dimport.d
*/
module dmd.dimport;
@@ -14,7 +14,6 @@ module dmd.dimport;
import dmd.arraytypes;
import dmd.dmodule;
import dmd.dsymbol;
-import dmd.errors;
import dmd.identifier;
import dmd.location;
import dmd.visitor;
@@ -41,7 +40,7 @@ extern (C++) final class Import : Dsymbol
// corresponding AliasDeclarations for alias=name pairs
AliasDeclarations aliasdecls;
- extern (D) this(const ref Loc loc, Identifier[] packages, Identifier id, Identifier aliasId, int isstatic)
+ extern (D) this(Loc loc, Identifier[] packages, Identifier id, Identifier aliasId, int isstatic)
{
Identifier selectIdent()
{
@@ -51,19 +50,16 @@ extern (C++) final class Import : Dsymbol
// import [aliasId] = std.stdio;
return aliasId;
}
- else if (packages.length > 0)
+ if (packages.length > 0)
{
// import [std].stdio;
return packages[0];
}
- else
- {
- // import [id];
- return id;
- }
+ // import [id];
+ return id;
}
- super(loc, selectIdent());
+ super(DSYM.import_, loc, selectIdent());
assert(id);
version (none)
@@ -84,16 +80,6 @@ extern (C++) final class Import : Dsymbol
this.visibility = Visibility.Kind.private_; // default to private
}
- extern (D) void addAlias(Identifier name, Identifier _alias)
- {
- if (isstatic)
- .error(loc, "%s `%s` cannot have an import bind list", kind, toPrettyChars);
- if (!aliasId)
- this.ident = null; // make it an anonymous import
- names.push(name);
- aliases.push(_alias);
- }
-
override const(char)* kind() const
{
return isstatic ? "static import" : "import";
@@ -110,9 +96,13 @@ extern (C++) final class Import : Dsymbol
assert(!s);
auto si = new Import(loc, packages, id, aliasId, isstatic);
si.comment = comment;
+ assert(!(isstatic && names.length));
+ if (names.length && !si.aliasId)
+ si.ident = null;
for (size_t i = 0; i < names.length; i++)
{
- si.addAlias(names[i], aliases[i]);
+ si.names.push(names[i]);
+ si.aliases.push(aliases[i]);
}
return si;
}
@@ -165,16 +155,10 @@ extern (C++) final class Import : Dsymbol
* https://issues.dlang.org/show_bug.cgi?id=5412
*/
assert(ident && ident == s.ident);
- Import imp;
- if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId)
- return true;
- else
+ if (aliasId)
return false;
- }
-
- override inout(Import) isImport() inout
- {
- return this;
+ const imp = s.isImport();
+ return imp && !imp.aliasId;
}
override void accept(Visitor v)
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 5493fc1..13051db 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -3,12 +3,12 @@
*
* Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE))
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dinterpret.d, _dinterpret.d)
* Documentation: https://dlang.org/phobos/dmd_dinterpret.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dinterpret.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dinterpret.d
*/
module dmd.dinterpret;
@@ -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;
+import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf, size;
import dmd.utils : arrayCastBigEndian;
import dmd.visitor;
@@ -100,6 +100,10 @@ public Expression ctfeInterpret(Expression e)
auto rgnpos = ctfeGlobals.region.savePos();
+ import dmd.timetrace;
+ timeTraceBeginEvent(TimeTraceEventType.ctfe);
+ scope (exit) timeTraceEndEvent(TimeTraceEventType.ctfe, e);
+
Expression result = interpret(e, null);
// Report an error if the expression contained a `ThrowException` and
@@ -432,6 +436,27 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
}
+ scope dlg = () {
+ import dmd.common.outbuffer;
+ auto strbuf = OutBuffer(20);
+ strbuf.writestring(fd.toPrettyChars());
+ strbuf.write("(");
+ if (arguments)
+ {
+ foreach (i, arg; *arguments)
+ {
+ if (i > 0)
+ strbuf.write(", ");
+ strbuf.writestring(arg.toChars());
+ }
+ }
+ strbuf.write(")");
+ return strbuf.extractSlice();
+ };
+ import dmd.timetrace;
+ timeTraceBeginEvent(TimeTraceEventType.ctfeCall);
+ scope (exit) timeTraceEndEvent(TimeTraceEventType.ctfeCall, fd, dlg);
+
void fdError(const(char)* msg)
{
error(fd.loc, "%s `%s` %s", fd.kind, fd.toPrettyChars, msg);
@@ -695,9 +720,9 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
}
}
- if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
+ 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();
@@ -733,7 +758,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
}
/// used to collect coverage information in ctfe
-void incUsageCtfe(InterState* istate, const ref Loc loc)
+void incUsageCtfe(InterState* istate, Loc loc)
{
if (global.params.ctfe_cov && istate)
{
@@ -974,7 +999,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate)
/* If the function returns a ref AND it's been called from an assignment,
* we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
*/
- if (tf.isref)
+ if (tf.isRef)
{
result = interpret(pue, s.exp, istate, CTFEGoal.LValue);
return;
@@ -1860,7 +1885,7 @@ public:
// Check for taking an address of a shared variable.
// If the shared variable is an array, the offset might not be zero.
Type fromType = null;
- if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray)
+ if (e.var.type.isStaticOrDynamicArray())
{
fromType = (cast(TypeArray)e.var.type).next;
}
@@ -1875,7 +1900,7 @@ public:
Expression val = getVarExp(e.loc, istate, e.var, goal);
if (exceptionOrCant(val))
return;
- if (val.type.ty == Tarray || val.type.ty == Tsarray)
+ if (val.type.isStaticOrDynamicArray())
{
// Check for unsupported type painting operations
Type elemtype = (cast(TypeArray)val.type).next;
@@ -1964,13 +1989,15 @@ public:
Declaration decl = ve.var;
// We cannot take the address of an imported symbol at compile time
- if (decl.isImportedSymbol()) {
+ if (decl.isImportedSymbol())
+ {
error(e.loc, "cannot take address of imported symbol `%s` at compile time", decl.toChars());
result = CTFEExp.cantexp;
return;
}
- if (decl.isDataseg()) {
+ if (decl.isDataseg())
+ {
// Normally this is already done by optimize()
// Do it here in case optimize(WANTvalue) wasn't run before CTFE
emplaceExp!(SymOffExp)(pue, e.loc, e.e1.isVarExp().var, 0);
@@ -2027,7 +2054,7 @@ public:
}
}
- static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
+ static Expression getVarExp(Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
{
Expression e = CTFEExp.cantexp;
if (VarDeclaration v = d.isVarDeclaration())
@@ -2727,7 +2754,7 @@ public:
// Create an array literal of type 'newtype' with dimensions given by
// 'arguments'[argnum..$]
- static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
+ static Expression recursivelyCreateArrayLiteral(UnionExp* pue, Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
{
Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
if (exceptionOrCantInterpret(lenExpr))
@@ -2769,6 +2796,13 @@ public:
printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
}
+ if (e.placement)
+ {
+ error(e.placement.loc, "`new ( %s )` PlacementExpression cannot be evaluated at compile time", e.placement.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
if (exceptionOrCant(epre))
return;
@@ -2903,7 +2937,7 @@ public:
result = eref;
return;
}
- if (e.newtype.toBasetype().isscalar())
+ if (e.newtype.toBasetype().isScalar())
{
Expression newval;
if (e.arguments && e.arguments.length)
@@ -2980,8 +3014,8 @@ public:
}
}
- private alias fp_t = extern (D) UnionExp function(const ref Loc loc, Type, Expression, Expression);
- private alias fp2_t = extern (D) bool function(const ref Loc loc, EXP, Expression, Expression);
+ private alias fp_t = extern (D) UnionExp function(Loc loc, Type, Expression, Expression);
+ private alias fp2_t = extern (D) bool function(Loc loc, EXP, Expression, Expression);
extern (D) private void interpretCommon(BinExp e, fp_t fp)
{
@@ -3002,7 +3036,7 @@ public:
result = pointerDifference(pue, e.loc, e.type, e1, e2);
return;
}
- if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
+ if (e.e1.type.ty == Tpointer && e.e2.type.isIntegral())
{
UnionExp ue1 = void;
Expression e1 = interpret(&ue1, e.e1, istate);
@@ -3015,7 +3049,7 @@ public:
result = pointerArithmetic(pue, e.loc, e.op, e.type, e1, e2);
return;
}
- if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
+ if (e.e2.type.ty == Tpointer && e.e1.type.isIntegral() && e.op == EXP.add)
{
UnionExp ue1 = void;
Expression e1 = interpret(&ue1, e.e1, istate);
@@ -3329,7 +3363,7 @@ public:
// a[] = e can have const e. So we compare the naked types.
Type tdst = e1.type.toBasetype();
Type tsrc = e.e2.type.toBasetype();
- while (tdst.ty == Tsarray || tdst.ty == Tarray)
+ while (tdst.isStaticOrDynamicArray())
{
tdst = (cast(TypeArray)tdst).next.toBasetype();
if (tsrc.equivalent(tdst))
@@ -3611,7 +3645,7 @@ public:
newval = (*fp)(e.loc, e.type, oldval, newval).copy();
}
- else if (e.e2.type.isintegral() &&
+ else if (e.e2.type.isIntegral() &&
(e.op == EXP.addAssign ||
e.op == EXP.minAssign ||
e.op == EXP.plusPlus ||
@@ -3844,7 +3878,7 @@ public:
if (auto bf = v.isBitFieldDeclaration())
{
sinteger_t value = ival.toInteger();
- if (bf.type.isunsigned())
+ if (bf.type.isUnsigned())
value &= (1L << bf.fieldWidth) - 1; // zero extra bits
else
{ // sign extend extra bits
@@ -4277,7 +4311,7 @@ public:
Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
{
Expressions* w = ae.elements;
- assert(ae.type.ty == Tsarray || ae.type.ty == Tarray || ae.type.ty == Tpointer);
+ assert(ae.type.isStaticOrDynamicArray() || ae.type.ty == Tpointer);
bool directblk = (cast(TypeNext)ae.type).next.equivalent(newval.type);
for (size_t k = lwr; k < upr; k++)
{
@@ -4830,33 +4864,6 @@ public:
return;
}
- else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendTTrace)
- {
- // In expressionsem.d `ea ~= eb` was lowered to `_d_arrayappendT{,Trace}({file, line, funcname}, ea, eb);`.
- // The following code will rewrite it back to `ea ~= eb` and then interpret that expression.
- Expression lhs, rhs;
-
- if (fd.ident == Id._d_arrayappendT)
- {
- assert(e.arguments.length == 2);
- lhs = (*e.arguments)[0];
- rhs = (*e.arguments)[1];
- }
- else
- {
- assert(e.arguments.length == 5);
- lhs = (*e.arguments)[3];
- rhs = (*e.arguments)[4];
- }
-
- auto cae = new CatAssignExp(e.loc, lhs, rhs);
- cae.type = e.type;
-
- result = interpretRegion(cae, istate, CTFEGoal.LValue);
- return;
- }
- else if (fd.ident == Id._d_arrayappendcTX)
- assert(0, "CTFE cannot interpret _d_arrayappendcTX!");
}
else if (auto soe = ecall.isSymOffExp())
{
@@ -5042,7 +5049,7 @@ public:
auto ce = e.e2.isCallExp();
assert(ce);
- auto ne = new NewExp(e.loc, null, e.type, ce.arguments);
+ auto ne = new NewExp(e.loc, null, null, e.type, ce.arguments);
ne.type = e.e1.type;
result = interpret(ne, istate);
@@ -5806,8 +5813,7 @@ public:
auto expTb = exp.type.toBasetype();
if (exp.type.implicitConvTo(tbNext) >= MATCH.convert &&
- (tb.ty == Tarray || tb.ty == Tsarray) &&
- (expTb.ty == Tarray || expTb.ty == Tsarray))
+ tb.isStaticOrDynamicArray() && expTb.isStaticOrDynamicArray())
return new ArrayLiteralExp(exp.loc, e.type, exp);
return exp;
}
@@ -5923,7 +5929,7 @@ public:
bool castToSarrayPointer = false;
bool castBackFromVoid = false;
- if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
+ if (e1.type.isStaticOrDynamicArray() || e1.type.ty == Tpointer)
{
// Check for unsupported type painting operations
// For slices, we need the type being sliced,
@@ -6103,11 +6109,11 @@ public:
// Disallow array type painting, except for conversions between built-in
// types of identical size.
- if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
+ if (e.to.isStaticOrDynamicArray() && e1.type.isStaticOrDynamicArray() && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
{
auto se = e1.isStringExp();
// Allow casting a hex string literal to short[], int[] or long[]
- if (se && se.hexString && se.postfix == StringExp.NoPostfix)
+ if (se && se.hexString && se.postfix == StringExp.NoPostfix && e.to.nextOf().isIntegral)
{
const sz = cast(size_t) e.to.nextOf().size;
if ((se.len % sz) != 0)
@@ -6126,8 +6132,7 @@ public:
}
error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
if (se && se.hexString && se.postfix != StringExp.NoPostfix)
- errorSupplemental(e.loc, "perhaps remove postfix `%s` from hex string",
- (cast(char) se.postfix ~ "\0").ptr);
+ errorSupplemental(e.loc, "perhaps remove postfix `%.*s` from hex string", 1, &se.postfix);
result = CTFEExp.cantexp;
return;
@@ -6144,9 +6149,9 @@ public:
}
else if (tobt.isTypeBasic() && e1.op == EXP.null_)
{
- if (tobt.isintegral())
+ if (tobt.isIntegral())
emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
- else if (tobt.isreal())
+ else if (tobt.isReal())
emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
result = pue.exp();
return;
@@ -6534,7 +6539,7 @@ public:
/// Interpret `throw <exp>` found at the specified location `loc`
private
-void interpretThrow(ref Expression result, Expression exp, const ref Loc loc, InterState* istate)
+void interpretThrow(ref Expression result, Expression exp, Loc loc, InterState* istate)
{
incUsageCtfe(istate, loc);
@@ -6675,7 +6680,7 @@ Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
true if it is safe to return, false if an error was generated.
*/
private
-bool stopPointersEscaping(const ref Loc loc, Expression e)
+bool stopPointersEscaping(Loc loc, Expression e)
{
import dmd.typesem : hasPointers;
if (!e.type.hasPointers())
@@ -6725,7 +6730,7 @@ bool stopPointersEscaping(const ref Loc loc, Expression e)
// Check all elements of an array for escaping local variables. Return false if error
private
-bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
+bool stopPointersEscapingFromArray(Loc loc, Expressions* elems)
{
foreach (e; *elems)
{
@@ -6789,7 +6794,7 @@ ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp
* 1. all slices must be resolved.
* 2. all .ownedByCtfe set to OwnedBy.code
*/
-private Expression scrubReturnValue(const ref Loc loc, Expression e)
+private Expression scrubReturnValue(Loc loc, Expression e)
{
/* Returns: true if e is void,
* or is an array literal or struct literal of void elements.
@@ -6855,10 +6860,10 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e)
Expression scrubSE(StructLiteralExp sle)
{
sle.ownedByCtfe = OwnedBy.code;
- if (!(sle.stageflags & stageScrub))
+ if (!(sle.stageflags & StructLiteralExp.StageFlags.scrub))
{
const old = sle.stageflags;
- sle.stageflags |= stageScrub; // prevent infinite recursion
+ sle.stageflags |= StructLiteralExp.StageFlags.scrub; // prevent infinite recursion
if (auto ex = scrubArray(sle.elements, true))
return ex;
sle.stageflags = old;
@@ -6935,10 +6940,10 @@ private Expression scrubCacheValue(Expression e)
Expression scrubSE(StructLiteralExp sle)
{
sle.ownedByCtfe = OwnedBy.cache;
- if (!(sle.stageflags & stageScrub))
+ if (!(sle.stageflags & StructLiteralExp.StageFlags.scrub))
{
const old = sle.stageflags;
- sle.stageflags |= stageScrub; // prevent infinite recursion
+ sle.stageflags |= StructLiteralExp.StageFlags.scrub; // prevent infinite recursion
if (auto ex = scrubArrayCache(sle.elements))
return ex;
sle.stageflags = old;
@@ -7012,10 +7017,10 @@ private Expression copyRegionExp(Expression e)
static void copySE(StructLiteralExp sle)
{
- if (1 || !(sle.stageflags & stageScrub))
+ if (1 || !(sle.stageflags & StructLiteralExp.StageFlags.scrub))
{
const old = sle.stageflags;
- sle.stageflags |= stageScrub; // prevent infinite recursion
+ sle.stageflags |= StructLiteralExp.StageFlags.scrub; // prevent infinite recursion
copyArray(sle.elements);
sle.stageflags = old;
}
@@ -7509,7 +7514,7 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
/* If this is a built-in function, return the interpreted result,
* Otherwise, return NULL.
*/
-private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
+private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
{
Expression e = null;
size_t nargs = arguments ? arguments.length : 0;
diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d
index c04fbec..307b43f 100644
--- a/gcc/d/dmd/dmacro.d
+++ b/gcc/d/dmd/dmacro.d
@@ -1,12 +1,12 @@
/**
* Text macro processor for Ddoc.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d, _dmacro.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmacro.d, _dmacro.d)
* Documentation: https://dlang.org/phobos/dmd_dmacro.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmacro.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dmacro.d
*/
module dmd.dmacro;
@@ -16,8 +16,6 @@ import core.stdc.string;
import dmd.common.outbuffer;
import dmd.root.rmem;
-@trusted:
-
struct MacroTable
{
/**********************************
@@ -303,7 +301,7 @@ struct Macro
* copy allocated with mem.xmalloc()
*/
-char[] memdup(const(char)[] p) nothrow pure
+char[] memdup(const(char)[] p) nothrow pure @trusted
{
size_t len = p.length;
return (cast(char*)memcpy(mem.xmalloc(len), p.ptr, len))[0 .. len];
@@ -318,7 +316,7 @@ char[] memdup(const(char)[] p) nothrow pure
* 1..9: get nth argument
* -1: get 2nd through end
*/
-size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) @nogc nothrow pure
+size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) @nogc nothrow pure @safe
{
/* Scan forward for matching right parenthesis.
* Nest parentheses.
@@ -334,7 +332,7 @@ size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) @nogc nothr
uint inexp = 0;
uint argn = 0;
size_t v = 0;
- const p = buf.ptr;
+ const p = buf;
const end = buf.length;
Largstart:
// Skip first space, if any, to find the start of the macro argument
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 58bf3fd..0e0070a 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/module.html, Modules)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d, _dmodule.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmodule.d, _dmodule.d)
* Documentation: https://dlang.org/phobos/dmd_dmodule.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmodule.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dmodule.d
*/
module dmd.dmodule;
@@ -24,12 +24,13 @@ import dmd.astenums;
import dmd.common.outbuffer;
import dmd.compiler;
import dmd.cparse;
+import dmd.declaration;
import dmd.dimport;
import dmd.dmacro;
import dmd.doc;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, importAll, load, include;
import dmd.errors;
import dmd.errorsink;
import dmd.expression;
@@ -57,12 +58,10 @@ import dmd.visitor;
version (Windows)
{
- import core.sys.windows.winbase : getpid = GetCurrentProcessId;
enum PathSeparator = '\\';
}
else version (Posix)
{
- import core.sys.posix.unistd : getpid;
enum PathSeparator = '/';
}
else
@@ -174,11 +173,12 @@ extern (C++) class Package : ScopeDsymbol
uint tag; // auto incremented tag, used to mask package tree in scopes
Module mod; // !=null if isPkgMod == PKG.module_
- final extern (D) this(const ref Loc loc, Identifier ident) nothrow
+ final extern (D) this(Loc loc, Identifier ident) nothrow
{
super(loc, ident);
__gshared uint packageTag;
this.tag = packageTag++;
+ this.dsym = DSYM.package_;
}
override const(char)* kind() const nothrow
@@ -252,11 +252,6 @@ extern (C++) class Package : ScopeDsymbol
return dst;
}
- override final inout(Package) isPackage() inout
- {
- return this;
- }
-
/**
* Checks if pkg is a sub-package of this
*
@@ -309,8 +304,9 @@ extern (C++) class Package : ScopeDsymbol
packages ~= s.ident;
reverse(packages);
- if (Module.find(getFilename(packages, ident)))
- Module.load(Loc.initial, packages, this.ident);
+ ImportPathInfo pathThatFoundThis;
+ if (Module.find(getFilename(packages, ident), pathThatFoundThis))
+ Module.load(Loc.initial, packages, this.ident, pathThatFoundThis);
else
isPkgMod = PKG.package_;
}
@@ -348,8 +344,8 @@ extern (C++) final class Module : Package
const(char)[] arg; // original argument name
ModuleDeclaration* md; // if !=null, the contents of the ModuleDeclaration declaration
const FileName srcfile; // input source file
- const FileName objfile; // output .obj file
- const FileName hdrfile; // 'header' file
+ FileName objfile; // output .obj file
+ FileName hdrfile; // 'header' file
FileName docfile; // output documentation file
const(ubyte)[] src; /// Raw content of the file
uint errors; // if any errors in file
@@ -357,6 +353,7 @@ extern (C++) final class Module : Package
FileType filetype; // source file type
bool hasAlwaysInlines; // contains references to functions that must be inlined
bool isPackageFile; // if it is a package.d
+ Edition edition; // language edition that this module is compiled with
Package pkg; // if isPackageFile is true, the Package that contains this package.d
Strings contentImportedFiles; // array of files whose content was imported
int needmoduleinfo;
@@ -427,11 +424,9 @@ extern (C++) final class Module : Package
Modules aimports; // all imported modules
- uint debuglevel; // debug level
Identifiers* debugids; // debug identifiers
Identifiers* debugidsNot; // forward referenced debug identifiers
- uint versionlevel; // version level
Identifiers* versionids; // version identifiers
Identifiers* versionidsNot; // forward referenced version identifiers
@@ -441,9 +436,10 @@ extern (C++) final class Module : Package
size_t nameoffset; // offset of module name from start of ModuleInfo
size_t namelen; // length of module name in characters
- extern (D) this(const ref Loc loc, const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen)
+ extern (D) this(Loc loc, const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen)
{
super(loc, ident);
+ this.dsym = DSYM.module_;
const(char)[] srcfilename;
//printf("Module::Module(filename = '%.*s', ident = '%s')\n", cast(int)filename.length, filename.ptr, ident.toChars());
this.arg = filename;
@@ -454,7 +450,7 @@ extern (C++) final class Module : Package
FileName.exists(filename) == 1)
{
FileName.free(srcfilename.ptr);
- srcfilename = FileName.removeExt(filename); // just does a mem.strdup(filename)
+ srcfilename = FileName.sansExt(filename);
}
else if (!FileName.equalsExt(srcfilename, mars_ext) &&
!FileName.equalsExt(srcfilename, hdr_ext) &&
@@ -476,6 +472,8 @@ extern (C++) final class Module : Package
setDocfile();
if (doHdrGen)
hdrfile = setOutfilename(global.params.dihdr.name, global.params.dihdr.dir, arg, hdr_ext);
+
+ this.edition = Edition.legacy;
}
extern (D) this(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen)
@@ -495,20 +493,26 @@ extern (C++) final class Module : Package
static const(char)* find(const(char)* filename)
{
- return find(filename.toDString).ptr;
+ 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)
+ extern (D) static const(char)[] find(const(char)[] filename, out ImportPathInfo pathThatFoundThis)
{
- return global.fileManager.lookForSourceFile(filename, global.path[]);
+ ptrdiff_t whichPathFoundThis;
+ const(char)[] ret = global.fileManager.lookForSourceFile(filename, global.path[], whichPathFoundThis);
+
+ if (whichPathFoundThis >= 0)
+ pathThatFoundThis = global.path[whichPathFoundThis];
+ return ret;
}
- extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident)
+ extern (C++) static Module load(Loc loc, Identifiers* packages, Identifier ident)
{
return load(loc, packages ? (*packages)[] : null, ident);
}
- extern (D) static Module load(const ref Loc loc, Identifier[] packages, Identifier ident)
+ extern (D) static Module load(Loc loc, Identifier[] packages, Identifier ident, ImportPathInfo pathInfo = ImportPathInfo.init)
{
//printf("Module::load(ident = '%s')\n", ident.toChars());
// Build module filename by turning:
@@ -517,11 +521,17 @@ extern (C++) final class Module : Package
// foo\bar\baz
const(char)[] filename = getFilename(packages, ident);
// Look for the source file
- if (const result = find(filename))
+ ImportPathInfo importPathThatFindUs;
+ if (const result = find(filename, importPathThatFindUs))
+ {
filename = result; // leaks
+ pathInfo = importPathThatFindUs;
+ }
auto m = new Module(loc, filename, ident, 0, 0);
+ // TODO: apply import path information (pathInfo) on to module
+
if (!m.read(loc))
return null;
if (global.params.v.verbose)
@@ -565,16 +575,26 @@ extern (C++) final class Module : Package
else
{
const(char)[] argdoc;
- OutBuffer buf;
- if (arg == "__stdin.d")
- {
- buf.printf("__stdin_%d.d", getpid());
- arg = buf[];
- }
if (global.params.preservePaths)
argdoc = arg;
else
argdoc = FileName.name(arg);
+
+ if (global.params.fullyQualifiedObjectFiles)
+ {
+ const fqn = md ? md.toString() : toString();
+ argdoc = FileName.replaceName(argdoc, fqn);
+
+ // add ext, otherwise forceExt will make nested.module into nested.<ext>
+ const bufferLength = argdoc.length + 1 + ext.length + /* null terminator */ 1;
+ char[] s = new char[bufferLength];
+ s[0 .. argdoc.length] = argdoc[];
+ s[argdoc.length] = '.';
+ s[$-1-ext.length .. $-1] = ext[];
+ s[$-1] = 0;
+ argdoc = s;
+ }
+
// If argdoc doesn't have an absolute path, make it relative to dir
if (!FileName.absolute(argdoc))
{
@@ -607,43 +627,32 @@ extern (C++) final class Module : Package
* Params:
* loc = The location at which the file read originated (e.g. import)
*/
- private void onFileReadError(const ref Loc loc)
+ private void onFileReadError(Loc loc)
{
- if (FileName.equals(srcfile.toString(), "object.d"))
+ const name = srcfile.toString();
+ if (FileName.equals(name, "object.d"))
{
- .error(loc, "cannot find source code for runtime library file 'object.d'");
- version (IN_LLVM)
- {
- errorSupplemental(loc, "ldc2 might not be correctly installed.");
- errorSupplemental(loc, "Please check your ldc2.conf configuration file.");
- errorSupplemental(loc, "Installation instructions can be found at http://wiki.dlang.org/LDC.");
- }
- version (MARS)
- {
- errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
- const dmdConfFile = global.inifilename.length ? FileName.canonicalName(global.inifilename) : "not found";
- errorSupplemental(loc, "config file: %.*s", cast(int)dmdConfFile.length, dmdConfFile.ptr);
- }
+ ObjectNotFound(Loc.initial, ident);
}
else if (FileName.ext(this.arg) || !loc.isValid())
{
// Modules whose original argument name has an extension, or do not
// have a valid location come from the command-line.
// Error that their file cannot be found and return early.
- .error(loc, "cannot find input file `%s`", srcfile.toChars());
+ .error(loc, "cannot find input file `%.*s`", cast(int)name.length, name.ptr);
}
else
{
// if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module
bool isPackageMod = (strcmp(toChars(), "package") != 0) && isPackageFileName(srcfile);
if (isPackageMod)
- .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars());
+ .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%.*s'", toChars(), cast(int)name.length, name.ptr);
else
{
.error(loc, "unable to read module `%s`", toChars());
- const pkgfile = FileName.combine(FileName.removeExt(srcfile.toString()), package_d);
- .errorSupplemental(loc, "Expected '%s' or '%s' in one of the following import paths:",
- srcfile.toChars(), pkgfile.ptr);
+ const pkgfile = FileName.combine(FileName.sansExt(name), package_d);
+ .errorSupplemental(loc, "Expected '%.*s' or '%.*s' in one of the following import paths:",
+ cast(int)name.length, name.ptr, cast(int)pkgfile.length, pkgfile.ptr);
}
}
if (!global.gag)
@@ -653,11 +662,11 @@ extern (C++) final class Module : Package
if (global.path.length)
{
foreach (i, p; global.path[])
- fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p);
+ fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p.path);
}
else
{
- fprintf(stderr, "Specify path to file '%s' with -I switch\n", srcfile.toChars());
+ fprintf(stderr, "Specify path to file '%.*s' with -I switch\n", cast(int)name.length, name.ptr);
}
removeHdrFilesAndFail(global.params, Module.amodules);
@@ -675,7 +684,7 @@ extern (C++) final class Module : Package
*
* Returns: `true` if successful
*/
- bool read(const ref Loc loc)
+ bool read(Loc loc)
{
if (this.src)
return true; // already read
@@ -722,6 +731,11 @@ extern (C++) final class Module : Package
{
const(char)* srcname = srcfile.toChars();
//printf("Module::parse(srcname = '%s')\n", srcname);
+
+ import dmd.timetrace;
+ timeTraceBeginEvent(TimeTraceEventType.parse);
+ scope (exit) timeTraceEndEvent(TimeTraceEventType.parse, this);
+
isPackageFile = isPackageFileName(srcfile);
const(char)[] buf = processSource(src, this);
// an error happened on UTF conversion
@@ -773,20 +787,19 @@ extern (C++) final class Module : Package
{
filetype = FileType.c;
- global.compileEnv.masm = target.os == Target.OS.Windows && !target.omfobj; // Microsoft inline assembler format
+ global.compileEnv.masm = target.os == Target.OS.Windows; // Microsoft inline assembler format
scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines, &global.compileEnv);
global.compileEnv.masm = false;
p.nextToken();
checkCompiledImport();
members = p.parseModule();
assert(!p.md); // C doesn't have module declarations
- numlines = p.scanloc.linnum;
+ numlines = p.linnum;
}
else
{
const bool doUnittests = global.params.parsingUnittestsRequired();
scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink, &global.compileEnv, doUnittests);
- p.transitionIn = global.params.v.vin;
p.nextToken();
p.parseModuleDeclaration();
md = p.md;
@@ -805,7 +818,7 @@ extern (C++) final class Module : Package
checkCompiledImport();
members = p.parseModuleContent();
- numlines = p.scanloc.linnum;
+ numlines = p.linnum;
}
/* The symbol table into which the module is to be inserted.
@@ -945,7 +958,7 @@ extern (C++) final class Module : Package
* sc = the scope into which we are imported
* loc = the location of the import statement
*/
- void checkImportDeprecation(const ref Loc loc, Scope* sc)
+ void checkImportDeprecation(Loc loc, Scope* sc)
{
if (md && md.isdeprecated && !sc.isDeprecated)
{
@@ -1154,11 +1167,6 @@ extern (C++) final class Module : Package
uint[uint] ctfe_cov; /// coverage information from ctfe execution_count[line]
- override inout(Module) isModule() inout nothrow
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1270,7 +1278,7 @@ extern (C++) struct ModuleDeclaration
bool isdeprecated; // if it is a deprecated module
Expression msg;
- extern (D) this(const ref Loc loc, Identifier[] packages, Identifier id, Expression msg, bool isdeprecated) @safe
+ extern (D) this(Loc loc, Identifier[] packages, Identifier id, Expression msg, bool isdeprecated) @safe
{
this.loc = loc;
this.packages = packages;
@@ -1394,7 +1402,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
{
enum SourceEncoding { utf16, utf32}
enum Endian { little, big}
- immutable loc = mod.getLoc();
+ immutable loc = mod.loc;
/*
* Convert a buffer from UTF32 to UTF8
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index c00c1cc..dc4a0b9 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/ddoc.html, Documentation Generator)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/doc.d, _doc.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/doc.d, _doc.d)
* Documentation: https://dlang.org/phobos/dmd_doc.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/doc.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/doc.d
*/
module dmd.doc;
@@ -433,10 +433,7 @@ void gendocfile(Module m, const char[] ddoctext, const char* datetime, ErrorSink
OutBuffer buf;
if (m.filetype == FileType.ddoc)
{
- const ploc = m.md ? &m.md.loc : &m.loc;
- Loc loc = *ploc;
- if (!loc.filename)
- loc.filename = srcfilename.ptr;
+ Loc loc = m.md ? m.md.loc : m.loc;
size_t commentlen = m.comment ? strlen(cast(char*)m.comment) : 0;
Dsymbols a;
@@ -477,7 +474,7 @@ void gendocfile(Module m, const char[] ddoctext, const char* datetime, ErrorSink
auto p = slice.ptr;
for (size_t j = 0; j < slice.length; j++)
{
- char c = p[j];
+ const c = p[j];
if (c == 0xFF && j + 1 < slice.length)
{
j++;
@@ -510,7 +507,7 @@ void escapeDdocString(ref OutBuffer buf, size_t start)
{
for (size_t u = start; u < buf.length; u++)
{
- char c = buf[u];
+ const c = buf[u];
switch (c)
{
case '$':
@@ -637,7 +634,7 @@ private void escapeStrayParenthesis(Loc loc, ref OutBuffer buf, size_t start, bo
for (size_t u = buf.length; u > start;)
{
u--;
- char c = buf[u];
+ const c = buf[u];
switch (c)
{
case ')':
@@ -694,9 +691,7 @@ bool emitAnchorName(ref OutBuffer buf, Dsymbol s, Scope* sc, bool includeParent)
}
else
{
- /* We just want the identifier, not overloads like TemplateDeclaration::toChars.
- * We don't want the template parameter list and constraints. */
- buf.writestring(s.Dsymbol.toChars());
+ buf.writestring(s.ident ? s.ident.toString : "__anonymous");
}
return true;
}
@@ -799,7 +794,11 @@ void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false)
}
else
{
- auto symbolName = ident.toString();
+ // buf.writestring("<<<");
+ // buf.writestring(typeof(ident).stringof);
+ // buf.writestring(">>>");
+ // auto symbolName = ident.toString();
+ auto symbolName = ident.toChars().toDString();
buf.printf("$(%.*s %.*s", cast(int) macroName.length, macroName.ptr,
cast(int) symbolName.length, symbolName.ptr);
@@ -2062,9 +2061,9 @@ string toLowercase(string s) pure @safe
// TODO: maybe unicode lowercase, somehow
if (c >= 'A' && c <= 'Z')
{
- if (!lower.length) {
+ if (!lower.length)
lower.reserve(s.length);
- }
+
lower ~= s[lower.length..i];
c += 'a' - 'A';
lower ~= c;
@@ -2107,42 +2106,12 @@ int getMarkdownIndent(ref OutBuffer buf, size_t from, size_t to) @safe
}
/************************************************
- * Scan forward to one of:
- * start of identifier
- * beginning of next line
- * end of buf
- */
-size_t skiptoident(ref OutBuffer buf, size_t i) @safe
-{
- const slice = buf[];
- while (i < slice.length)
- {
- dchar c;
- size_t oi = i;
- if (utf_decodeChar(slice, i, c))
- {
- /* Ignore UTF errors, but still consume input
- */
- break;
- }
- if (c >= 0x80)
- {
- if (!isUniAlpha(c))
- continue;
- }
- else if (!(isalpha(c) || c == '_' || c == '\n'))
- continue;
- i = oi;
- break;
- }
- return i;
-}
-
-/************************************************
* Scan forward past end of identifier.
*/
size_t skippastident(ref OutBuffer buf, size_t i) @safe
{
+ import dmd.common.charactertables;
+
const slice = buf[];
while (i < slice.length)
{
@@ -2156,7 +2125,8 @@ size_t skippastident(ref OutBuffer buf, size_t i) @safe
}
if (c >= 0x80)
{
- if (isUniAlpha(c))
+ // we don't care if it is start/continue here
+ if (isAnyIdentifierCharacter(c))
continue;
}
else if (isalnum(c) || c == '_')
@@ -2173,6 +2143,8 @@ size_t skippastident(ref OutBuffer buf, size_t i) @safe
*/
size_t skipPastIdentWithDots(ref OutBuffer buf, size_t i) @safe
{
+ import dmd.common.charactertables;
+
const slice = buf[];
bool lastCharWasDot;
while (i < slice.length)
@@ -2203,7 +2175,8 @@ size_t skipPastIdentWithDots(ref OutBuffer buf, size_t i) @safe
{
if (c >= 0x80)
{
- if (isUniAlpha(c))
+ // we don't care if it is start/continue here
+ if (isAnyIdentifierCharacter(c))
{
lastCharWasDot = false;
continue;
@@ -2300,10 +2273,9 @@ void removeBlankLineMacro(ref OutBuffer buf, ref size_t iAt, ref size_t i)
* thematic break. If the replacement is made `i` changes to
* point to the closing parenthesis of the `$(HR)` macro.
* iLineStart = the index within `buf` that the thematic break's line starts at
- * loc = the current location within the file
* Returns: whether a thematic break was replaced
*/
-bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_t iLineStart, const ref Loc loc)
+bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_t iLineStart)
{
const slice = buf[];
@@ -2404,11 +2376,10 @@ void removeAnyAtxHeadingSuffix(ref OutBuffer buf, size_t i)
* iEnd = the index within `buf` of the character after the last
* heading character. Is incremented by the length of the
* inserted heading macro when this function ends.
- * loc = the location of the Ddoc within the file
* headingLevel = the level (1-6) of heading to end. Is set to `0` when this
* function ends.
*/
-void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEnd, const ref Loc loc, ref int headingLevel)
+void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEnd, ref int headingLevel)
{
char[5] heading = "$(H0 ";
heading[3] = cast(char) ('0' + headingLevel);
@@ -2465,12 +2436,11 @@ size_t endAllListsAndQuotes(ref OutBuffer buf, ref size_t i, ref MarkdownList[]
* e.g. `*very* **nice**` becomes `$(EM very) $(STRONG nice)`.
* Params:
* buf = an OutBuffer containing the DDoc
- * loc = the current location within the file
* inlineDelimiters = the collection of delimiters found within a paragraph. When this function returns its length will be reduced to `downToLevel`.
* downToLevel = the length within `inlineDelimiters`` to reduce emphasis to
* Returns: the number of characters added to the buffer by the replacements
*/
-size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int downToLevel = 0)
+size_t replaceMarkdownEmphasis(ref OutBuffer buf, ref MarkdownDelimiter[] inlineDelimiters, int downToLevel = 0)
{
size_t replaceEmphasisPair(ref MarkdownDelimiter start, ref MarkdownDelimiter end)
{
@@ -2613,7 +2583,7 @@ TypeFunction isTypeFunction(Dsymbol s) @safe
{
Type t = f.originalType ? f.originalType : f.type;
if (t.ty == Tfunction)
- return cast(TypeFunction)t;
+ return (() @trusted => cast(TypeFunction)t)();
}
return null;
}
@@ -2653,7 +2623,7 @@ Parameter isFunctionParameter(Dsymbols* a, const(char)[] p) @safe
/****************************************************
*/
-Parameter isEponymousFunctionParameter(Dsymbols *a, const(char)[] p) @safe
+Parameter isEponymousFunctionParameter(Dsymbols* a, const(char)[] p) @safe
{
foreach (Dsymbol dsym; *a)
{
@@ -2849,10 +2819,9 @@ struct MarkdownList
* i = the index within `buf` of the list item. If this function succeeds `i` will be adjusted to fit the inserted macro.
* iPrecedingBlankLine = the index within `buf` of the preceeding blank line. If non-zero and a new list was started, the preceeding blank line is removed and this value is set to `0`.
* nestedLists = a set of nested lists. If this function succeeds it may contain a new nested list.
- * loc = the location of the Ddoc within the file
* Returns: `true` if a list was created
*/
- bool startItem(ref OutBuffer buf, ref size_t iLineStart, ref size_t i, ref size_t iPrecedingBlankLine, ref MarkdownList[] nestedLists, const ref Loc loc)
+ bool startItem(ref OutBuffer buf, ref size_t iLineStart, ref size_t i, ref size_t iPrecedingBlankLine, ref MarkdownList[] nestedLists)
{
buf.remove(iStart, iContentStart - iStart);
@@ -3027,14 +2996,13 @@ struct MarkdownLink
* buf = an OutBuffer containing the DDoc
* i = the index within `buf` that points to the `]` character of the potential link.
* If this function succeeds it will be adjusted to fit the inserted link macro.
- * loc = the current location within the file
* inlineDelimiters = previously parsed Markdown delimiters, including emphasis and link/image starts
* delimiterIndex = the index within `inlineDelimiters` of the nearest link/image starting delimiter
* linkReferences = previously parsed link references. When this function returns it may contain
* additional previously unparsed references.
* Returns: whether a reference link was found and replaced at `i`
*/
- static bool replaceLink(ref OutBuffer buf, ref size_t i, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences)
+ static bool replaceLink(ref OutBuffer buf, ref size_t i, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences)
{
const delimiter = inlineDelimiters[delimiterIndex];
MarkdownLink link;
@@ -3043,7 +3011,7 @@ struct MarkdownLink
if (iEnd > i)
{
i = delimiter.iStart;
- link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences, loc);
+ link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences);
inlineDelimiters.length = delimiterIndex;
return true;
}
@@ -3055,7 +3023,7 @@ struct MarkdownLink
if (iEnd > i)
{
const label = link.label;
- link = linkReferences.lookupReference(label, buf, i, loc);
+ link = linkReferences.lookupReference(label, buf, i);
// check rightFlanking to avoid replacing things like int[string]
if (!link.href.length && !delimiter.rightFlanking)
link = linkReferences.lookupSymbol(label);
@@ -3067,7 +3035,7 @@ struct MarkdownLink
if (iEnd == i)
return false;
- immutable delta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, delimiterIndex);
+ immutable delta = replaceMarkdownEmphasis(buf, inlineDelimiters, delimiterIndex);
iEnd += delta;
i += delta;
link.replaceLink(buf, i, iEnd, delimiter);
@@ -3084,10 +3052,9 @@ struct MarkdownLink
* delimiterIndex = the index within `inlineDelimiters` of the nearest link/image starting delimiter
* linkReferences = previously parsed link references. When this function returns it may contain
* additional previously unparsed references.
- * loc = the current location in the file
* Returns: whether a reference link was found and replaced at `i`
*/
- static bool replaceReferenceDefinition(ref OutBuffer buf, ref size_t i, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences, const ref Loc loc)
+ static bool replaceReferenceDefinition(ref OutBuffer buf, ref size_t i, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences)
{
const delimiter = inlineDelimiters[delimiterIndex];
MarkdownLink link;
@@ -3096,7 +3063,7 @@ struct MarkdownLink
return false;
i = delimiter.iStart;
- link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences, loc);
+ link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences);
inlineDelimiters.length = delimiterIndex;
return true;
}
@@ -3469,9 +3436,8 @@ struct MarkdownLink
* iEnd = the index within `buf` that points just after the end of the definition
* linkReferences = previously parsed link references. When this function returns it may contain
* an additional reference.
- * loc = the current location in the file
*/
- private void storeAndReplaceDefinition(ref OutBuffer buf, ref size_t i, size_t iEnd, ref MarkdownLinkReferences linkReferences, const ref Loc loc)
+ private void storeAndReplaceDefinition(ref OutBuffer buf, ref size_t i, size_t iEnd, ref MarkdownLinkReferences linkReferences)
{
// Remove the definition and trailing whitespace
iEnd = skipChars(buf, iEnd, " \t\r\n");
@@ -3604,14 +3570,13 @@ struct MarkdownLinkReferences
* label = the label to find the reference for
* buf = an OutBuffer containing the DDoc
* i = the index within `buf` to start searching for references at
- * loc = the current location in the file
* Returns: a link. If the `href` member has a value then the reference is valid.
*/
- MarkdownLink lookupReference(string label, ref OutBuffer buf, size_t i, const ref Loc loc)
+ MarkdownLink lookupReference(string label, ref OutBuffer buf, size_t i)
{
const lowercaseLabel = label.toLowercase();
if (lowercaseLabel !in references)
- extractReferences(buf, i, loc);
+ extractReferences(buf, i);
if (lowercaseLabel in references)
return references[lowercaseLabel];
@@ -3637,7 +3602,7 @@ struct MarkdownLinkReferences
auto id = Identifier.lookup(ids[0].ptr, ids[0].length);
if (id)
{
- auto loc = Loc();
+ auto loc = Loc.initial;
Dsymbol pscopesym;
auto symbol = _scope.search(loc, id, pscopesym, SearchOpt.ignoreErrors);
for (size_t i = 1; symbol && i < ids.length; ++i)
@@ -3659,10 +3624,9 @@ struct MarkdownLinkReferences
* Params:
* buf = an OutBuffer containing the DDoc
* i = the index within `buf` to start looking at
- * loc = the current location in the file
* Returns: whether a reference was extracted
*/
- private void extractReferences(ref OutBuffer buf, size_t i, const ref Loc loc)
+ private void extractReferences(ref OutBuffer buf, size_t i)
{
static bool isFollowedBySpace(ref OutBuffer buf, size_t i)
{
@@ -3750,7 +3714,7 @@ struct MarkdownLinkReferences
break;
case ']':
if (delimiters.length && !inCode &&
- MarkdownLink.replaceReferenceDefinition(buf, i, delimiters, cast(int) delimiters.length - 1, this, loc))
+ MarkdownLink.replaceReferenceDefinition(buf, i, delimiters, cast(int) delimiters.length - 1, this))
--i;
break;
default:
@@ -3923,19 +3887,18 @@ size_t parseTableDelimiterRow(ref OutBuffer buf, const size_t iStart, bool inQuo
* buf = an OutBuffer containing the DDoc
* iStart = the index within `buf` that the table header row starts at, inclusive
* iEnd = the index within `buf` that the table header row ends at, exclusive
- * loc = the current location in the file
* inQuote = whether the table is inside a quote
* inlineDelimiters = delimiters containing columns separators and any inline emphasis
* columnAlignments = the parsed alignments for each column
* Returns: the number of characters added by starting the table, or `0` if unchanged
*/
-size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, bool inQuote, ref MarkdownDelimiter[] inlineDelimiters, out TableColumnAlignment[] columnAlignments)
+size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, bool inQuote, ref MarkdownDelimiter[] inlineDelimiters, out TableColumnAlignment[] columnAlignments)
{
const iDelimiterRowEnd = parseTableDelimiterRow(buf, iEnd + 1, inQuote, columnAlignments);
if (iDelimiterRowEnd)
{
size_t delta;
- if (replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, true, delta))
+ if (replaceTableRow(buf, iStart, iEnd, inlineDelimiters, columnAlignments, true, delta))
{
buf.remove(iEnd + delta, iDelimiterRowEnd - iEnd);
buf.insert(iEnd + delta, "$(TBODY ");
@@ -3956,7 +3919,6 @@ size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc l
* buf = an OutBuffer containing the DDoc
* iStart = the index within `buf` that the table row starts at, inclusive
* iEnd = the index within `buf` that the table row ends at, exclusive
- * loc = the current location in the file
* inlineDelimiters = delimiters containing columns separators and any inline emphasis
* columnAlignments = alignments for each column
* headerRow = if `true` then the number of columns will be enforced to match
@@ -3965,7 +3927,7 @@ size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc l
* delta = the number of characters added by replacing the row, or `0` if unchanged
* Returns: `true` if a table row was found and replaced
*/
-bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow, out size_t delta)
+bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow, out size_t delta)
{
delta = 0;
@@ -3991,7 +3953,7 @@ bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Lo
void replaceTableCell(size_t iCellStart, size_t iCellEnd, int cellIndex, int di)
{
- const eDelta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, di);
+ const eDelta = replaceMarkdownEmphasis(buf, inlineDelimiters, di);
delta += eDelta;
iCellEnd += eDelta;
@@ -4109,15 +4071,14 @@ size_t endTable(ref OutBuffer buf, size_t i, ref TableColumnAlignment[] columnAl
* buf = an OutBuffer containing the DDoc
* iStart = the index within `buf` that the table row starts at, inclusive
* iEnd = the index within `buf` that the table row ends at, exclusive
- * loc = the current location in the file
* inlineDelimiters = delimiters containing columns separators and any inline emphasis
* columnAlignments = alignments for each column; upon return is set to length `0`
* Returns: the number of characters added by replacing the row, or `0` if unchanged
*/
-size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments)
+size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments)
{
size_t delta;
- replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, false, delta);
+ replaceTableRow(buf, iStart, iEnd, inlineDelimiters, columnAlignments, false, delta);
delta += endTable(buf, iEnd + delta, columnAlignments);
return delta;
}
@@ -4134,9 +4095,8 @@ size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref L
*/
void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t offset)
{
- const incrementLoc = loc.linnum == 0 ? 1 : 0;
- loc.linnum = loc.linnum + incrementLoc;
- loc.charnum = 0;
+ loc.nextLine();
+
//printf("highlightText()\n");
bool leadingBlank = true;
size_t iParagraphStart = offset;
@@ -4187,19 +4147,19 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
}
if (headingLevel)
{
- i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
- endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+ i += replaceMarkdownEmphasis(buf, inlineDelimiters);
+ endMarkdownHeading(buf, iParagraphStart, i, headingLevel);
removeBlankLineMacro(buf, iPrecedingBlankLine, i);
++i;
iParagraphStart = skipChars(buf, i, " \t\r\n");
}
if (tableRowDetected && !columnAlignments.length)
- i += startTable(buf, iLineStart, i, loc, lineQuoted, inlineDelimiters, columnAlignments);
+ i += startTable(buf, iLineStart, i, lineQuoted, inlineDelimiters, columnAlignments);
else if (columnAlignments.length)
{
size_t delta;
- if (replaceTableRow(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments, false, delta))
+ if (replaceTableRow(buf, iLineStart, i, inlineDelimiters, columnAlignments, false, delta))
i += delta;
else
i += endTable(buf, i, columnAlignments);
@@ -4214,7 +4174,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
i += endTable(buf, i, columnAlignments);
if (!lineQuoted && quoteLevel)
endAllListsAndQuotes(buf, i, nestedLists, quoteLevel, quoteMacroLevel);
- i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
+ i += replaceMarkdownEmphasis(buf, inlineDelimiters);
// if we don't already know about this paragraph break then
// insert a blank line and record the paragraph break
@@ -4240,7 +4200,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
lineQuoted = false;
tableRowDetected = false;
iLineStart = i + 1;
- loc.linnum = loc.linnum + incrementLoc;
+ loc.nextLine();
// update the paragraph start if we just entered a macro
if (previousMacroLevel < macroLevel && iParagraphStart < iLineStart)
@@ -4330,7 +4290,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
if (quoteLevel < lineQuoteLevel)
{
- i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
if (nestedLists.length)
{
const indent = getMarkdownIndent(buf, iLineStart, i);
@@ -4453,7 +4413,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
if (!headingLevel)
break;
- i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
if (!lineQuoted && quoteLevel)
i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
@@ -4494,7 +4454,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
const list = MarkdownList.parseItem(buf, iLineStart, i);
if (list.isValid)
{
- if (replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+ if (replaceMarkdownThematicBreak(buf, i, iLineStart))
{
removeBlankLineMacro(buf, iPrecedingBlankLine, i);
iParagraphStart = skipChars(buf, i+1, " \t\r\n");
@@ -4618,7 +4578,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
}
else
{
- i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
if (!lineQuoted && quoteLevel)
{
const delta = endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
@@ -4650,9 +4610,9 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
case '_':
{
- if (leadingBlank && !inCode && replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+ if (leadingBlank && !inCode && replaceMarkdownThematicBreak(buf, i, iLineStart))
{
- i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
if (!lineQuoted && quoteLevel)
i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
removeBlankLineMacro(buf, iPrecedingBlankLine, i);
@@ -4680,7 +4640,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
break;
}
- i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
if (!lineQuoted && quoteLevel)
{
const delta = endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
@@ -4690,7 +4650,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
}
list.macroLevel = macroLevel;
- list.startItem(buf, iLineStart, i, iPrecedingBlankLine, nestedLists, loc);
+ list.startItem(buf, iLineStart, i, iPrecedingBlankLine, nestedLists);
break;
}
}
@@ -4709,9 +4669,9 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
if (leadingBlank)
{
// Check for a thematic break
- if (replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+ if (replaceMarkdownThematicBreak(buf, i, iLineStart))
{
- i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
if (!lineQuoted && quoteLevel)
i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
removeBlankLineMacro(buf, iPrecedingBlankLine, i);
@@ -4790,7 +4750,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
if (delimiter.type == '[' || delimiter.type == '!')
{
if (delimiter.isValid &&
- MarkdownLink.replaceLink(buf, i, loc, inlineDelimiters, d, linkReferences))
+ MarkdownLink.replaceLink(buf, i, inlineDelimiters, d, linkReferences))
{
// if we removed a reference link then we're at line start
if (i <= delimiter.iStart)
@@ -4888,10 +4848,10 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
--downToLevel;
if (headingLevel && headingMacroLevel >= macroLevel)
{
- endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+ endMarkdownHeading(buf, iParagraphStart, i, headingLevel);
removeBlankLineMacro(buf, iPrecedingBlankLine, i);
}
- i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
while (nestedLists.length && nestedLists[$-1].macroLevel >= macroLevel)
{
i = buf.insert(i, ")\n)");
@@ -4899,7 +4859,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
}
if (quoteLevel && quoteMacroLevel >= macroLevel)
i += endAllMarkdownQuotes(buf, i, quoteLevel);
- i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters, downToLevel);
+ i += replaceMarkdownEmphasis(buf, inlineDelimiters, downToLevel);
--macroLevel;
quoteMacroLevel = 0;
@@ -4975,11 +4935,11 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
size_t i = buf.length;
if (headingLevel)
{
- endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+ endMarkdownHeading(buf, iParagraphStart, i, headingLevel);
removeBlankLineMacro(buf, iPrecedingBlankLine, i);
}
- i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
- i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
+ i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
+ i += replaceMarkdownEmphasis(buf, inlineDelimiters);
endAllListsAndQuotes(buf, i, nestedLists, quoteLevel, quoteMacroLevel);
}
@@ -5249,6 +5209,8 @@ bool isCVariadicArg(const(char)[] p) @nogc nothrow pure @safe
@trusted
bool isIdStart(const(char)* p) @nogc nothrow pure
{
+ import dmd.common.charactertables;
+
dchar c = *p;
if (isalpha(c) || c == '_')
return true;
@@ -5257,7 +5219,7 @@ bool isIdStart(const(char)* p) @nogc nothrow pure
size_t i = 0;
if (utf_decodeChar(p[0 .. 4], i, c))
return false; // ignore errors
- if (isUniAlpha(c))
+ if (isAnyStart(c))
return true;
}
return false;
@@ -5269,6 +5231,8 @@ bool isIdStart(const(char)* p) @nogc nothrow pure
@trusted
bool isIdTail(const(char)* p) @nogc nothrow pure
{
+ import dmd.common.charactertables;
+
dchar c = *p;
if (isalnum(c) || c == '_')
return true;
@@ -5277,7 +5241,7 @@ bool isIdTail(const(char)* p) @nogc nothrow pure
size_t i = 0;
if (utf_decodeChar(p[0 .. 4], i, c))
return false; // ignore errors
- if (isUniAlpha(c))
+ if (isAnyContinue(c))
return true;
}
return false;
diff --git a/gcc/d/dmd/doc.h b/gcc/d/dmd/doc.h
index 1775e35..61a51a0 100644
--- a/gcc/d/dmd/doc.h
+++ b/gcc/d/dmd/doc.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 76a26a2..725a55e 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -3,12 +3,12 @@
*
* Not to be confused with the `scope` storage class.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dscope.d, _dscope.d)
* Documentation: https://dlang.org/phobos/dmd_dscope.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dscope.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dscope.d
*/
module dmd.dscope;
@@ -24,6 +24,7 @@ import dmd.dclass;
import dmd.declaration;
import dmd.dmodule;
import dmd.doc;
+import dmd.dstruct;
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.dtemplate;
@@ -45,37 +46,80 @@ import dmd.tokens;
//version=LOGSEARCH;
+/// What kind of contract function we're in, if any
+enum Contract : ubyte
+{
+ none = 0,
+ invariant_ = 1,
+ require = 2, // in contract
+ ensure = 3, // out contract
+}
-// List of flags that can be applied to this `Scope`
-enum SCOPE
+private extern (D) struct BitFields
{
- ctor = 0x0001, /// constructor type
- noaccesscheck = 0x0002, /// don't do access checks
- condition = 0x0004, /// inside static if/assert condition
- debug_ = 0x0008, /// inside debug conditional
- constraint = 0x0010, /// inside template constraint
- invariant_ = 0x0020, /// inside invariant code
- require = 0x0040, /// inside in contract code
- ensure = 0x0060, /// inside out contract code
- contract = 0x0060, /// [mask] we're inside contract code
- ctfe = 0x0080, /// inside a ctfe-only expression
- compile = 0x0100, /// inside __traits(compile)
- ignoresymbolvisibility = 0x0200, /// ignore symbol visibility
- /// https://issues.dlang.org/show_bug.cgi?id=15907
- Cfile = 0x0800, /// C semantics apply
- free = 0x8000, /// is on free list
-
- fullinst = 0x10000, /// fully instantiate templates
- ctfeBlock = 0x20000, /// inside a `if (__ctfe)` block
- dip1000 = 0x40000, /// dip1000 errors enabled for this scope
- dip25 = 0x80000, /// dip25 errors enabled for this scope
+ bool ctor; /// constructor type
+ bool noAccessCheck; /// don't do access checks
+ bool condition; /// inside static if/assert condition
+ bool debug_; /// inside debug conditional
+ bool inTemplateConstraint; /// inside template constraint
+ Contract contract;
+ bool ctfe; /// inside a ctfe-only expression
+ bool traitsCompiles; /// inside __traits(compile)
+ /// ignore symbol visibility
+ /// https://issues.dlang.org/show_bug.cgi?id=15907
+ bool ignoresymbolvisibility;
+ bool inCfile; /// C semantics apply
+ bool canFree; /// is on free list
+ bool fullinst; /// fully instantiate templates
+ bool ctfeBlock; /// inside a `if (__ctfe)` block
}
-/// Flags that are carried along with a scope push()
-private enum PersistentFlags =
- SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
- SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility |
- SCOPE.Cfile | SCOPE.ctfeBlock | SCOPE.dip1000 | SCOPE.dip25;
+/// State of -preview switches
+///
+/// By making them part of a Scope, we reduce reliance on dmd.globals,
+/// and can enable/disable them per module / edition.
+private struct Previews
+{
+ // Run `dmd -preview=h` for the meaning of these switches
+ private extern (D) static struct BitFields
+ {
+ bool bitfields;
+ bool dip1000;
+ bool dip1008;
+ bool dip1021;
+ bool dip25;
+ bool fieldwise;
+ bool fixAliasThis;
+ bool fixImmutableConv;
+ bool in_;
+ bool inclusiveInContracts;
+ bool noSharedAccess;
+ bool rvalueRefParam;
+ bool safer;
+ FeatureState systemVariables;
+ }
+
+ import dmd.common.bitfields : generateBitFields;
+ mixin(generateBitFields!(BitFields, ushort));
+
+ void setFromParams(ref Param params) @nogc nothrow pure @safe
+ {
+ this.bitfields = params.bitfields;
+ this.dip1000 = params.useDIP1000 == FeatureState.enabled;
+ this.dip1008 = params.ehnogc;
+ this.dip1021 = params.useDIP1021; // == FeatureState.enabled;
+ this.dip25 = params.useDIP25 == FeatureState.enabled;
+ this.fixAliasThis = params.fixAliasThis;
+ this.fixImmutableConv = params.fixImmutableConv;
+ this.in_ = params.previewIn;
+ this.inclusiveInContracts = params.inclusiveInContracts;
+ this.noSharedAccess = params.noSharedAccess == FeatureState.enabled;
+ this.rvalueRefParam = params.rvalueRefParam == FeatureState.enabled;
+ this.safer = params.safer == FeatureState.enabled;
+ this.systemVariables = params.systemVariables;
+ this.fieldwise = params.fieldwise == FeatureState.enabled;
+ }
+}
extern (C++) struct Scope
{
@@ -87,10 +131,10 @@ extern (C++) struct Scope
VarDeclaration varDecl; /// variable we are in during semantic2
Dsymbol parent; /// parent to use
LabelStatement slabel; /// enclosing labelled statement
- SwitchStatement sw; /// enclosing switch statement
+ SwitchStatement switchStatement;/// enclosing switch statement
Statement tryBody; /// enclosing _body of TryCatchStatement or TryFinallyStatement
- TryFinallyStatement tf; /// enclosing try finally statement
- ScopeGuardStatement os; /// enclosing scope(xxx) statement
+ TryFinallyStatement tryFinally; /// enclosing try finally statement
+ ScopeGuardStatement scopeGuard; /// enclosing scope(xxx) statement
Statement sbreak; /// enclosing statement that supports "break"
Statement scontinue; /// enclosing statement that supports "continue"
ForeachStatement fes; /// if nested function for ForeachStatement, this is it
@@ -132,11 +176,14 @@ extern (C++) struct Scope
Visibility visibility = Visibility(Visibility.Kind.public_);
int explicitVisibility; /// set if in an explicit visibility attribute
- StorageClass stc; /// storage class
+ STC stc; /// storage class
DeprecatedDeclaration depdecl; /// customized deprecation message
- uint flags;
+ import dmd.common.bitfields : generateBitFields;
+ mixin(generateBitFields!(BitFields, ushort));
+
+ Previews previews;
// user defined attributes
UserAttributeDeclaration userAttribDecl;
@@ -147,6 +194,7 @@ extern (C++) struct Scope
AliasDeclaration aliasAsg; /// if set, then aliasAsg is being assigned a new value,
/// do not set wasRead for it
+ StructDeclaration argStruct; /// elimiate recursion when looking for rvalue construction
extern (D) __gshared Scope* freelist;
@@ -157,8 +205,8 @@ extern (C++) struct Scope
Scope* s = freelist;
freelist = s.enclosing;
//printf("freelist %p\n", s);
- assert(s.flags & SCOPE.free);
- s.flags &= ~SCOPE.free;
+ assert(s.canFree);
+ s.canFree = false;
return s;
}
return new Scope();
@@ -180,12 +228,10 @@ extern (C++) struct Scope
m = m.parent;
m.addMember(null, sc.scopesym);
m.parent = null; // got changed by addMember()
- if (global.params.useDIP1000 == FeatureState.enabled)
- sc.flags |= SCOPE.dip1000;
- if (global.params.useDIP25 == FeatureState.enabled)
- sc.flags |= SCOPE.dip25;
+ sc.previews.setFromParams(global.params);
+
if (_module.filetype == FileType.c)
- sc.flags |= SCOPE.Cfile;
+ sc.inCfile = true;
// Create the module scope underneath the global scope
sc = sc.push(_module);
sc.parent = _module;
@@ -207,13 +253,13 @@ extern (C++) struct Scope
{
Scope* s = copy();
//printf("Scope::push(this = %p) new = %p\n", this, s);
- assert(!(flags & SCOPE.free));
+ assert(!this.canFree);
s.scopesym = null;
s.enclosing = &this;
debug
{
if (enclosing)
- assert(!(enclosing.flags & SCOPE.free));
+ assert(!enclosing.canFree);
if (s == enclosing)
{
printf("this = %p, enclosing = %p, enclosing.enclosing = %p\n", s, &this, enclosing);
@@ -223,12 +269,36 @@ extern (C++) struct Scope
s.slabel = null;
s.nofree = false;
s.ctorflow.fieldinit = ctorflow.fieldinit.arraydup;
- s.flags = (flags & PersistentFlags);
+
+ // Only keep persistent flags
+ s.resetAllFlags();
+ s.contract = this.contract;
+ s.debug_ = this.debug_;
+ s.ctfe = this.ctfe;
+ s.traitsCompiles = this.traitsCompiles;
+ s.inTemplateConstraint = this.inTemplateConstraint;
+ s.noAccessCheck = this.noAccessCheck;
+ s.ignoresymbolvisibility = this.ignoresymbolvisibility;
+ s.inCfile = this.inCfile;
+ s.ctfeBlock = this.ctfeBlock;
+ s.previews = this.previews;
s.lastdc = null;
assert(&this != s);
return s;
}
+ /// Copy flags from scope `other`
+ extern(D) void copyFlagsFrom(Scope* other) @safe
+ {
+ this.bitFields = other.bitFields;
+ }
+
+ /// Set all scope flags to their initial value
+ extern(D) void resetAllFlags() @safe
+ {
+ this.bitFields = 0;
+ }
+
extern (D) Scope* push(ScopeDsymbol ss)
{
//printf("Scope::push(%s)\n", ss.toChars());
@@ -251,7 +321,7 @@ extern (C++) struct Scope
this = this.init;
enclosing = freelist;
freelist = &this;
- flags |= SCOPE.free;
+ this.canFree = true;
}
return enc;
}
@@ -270,7 +340,8 @@ extern (C++) struct Scope
extern (D) Scope* startCTFE()
{
Scope* sc = this.push();
- sc.flags = this.flags | SCOPE.ctfe;
+ sc.copyFlagsFrom(&this);
+ sc.ctfe = true;
version (none)
{
/* TODO: Currently this is not possible, because we need to
@@ -300,7 +371,7 @@ extern (C++) struct Scope
extern (D) Scope* endCTFE()
{
- assert(flags & SCOPE.ctfe);
+ assert(this.ctfe);
return pop();
}
@@ -311,30 +382,29 @@ extern (C++) struct Scope
* loc = for error messages
* ctorflow = flow results to merge in
*/
- extern (D) void merge(const ref Loc loc, const ref CtorFlow ctorflow)
+ extern (D) void merge(Loc loc, const ref CtorFlow ctorflow)
{
if (!mergeCallSuper(this.ctorflow.callSuper, ctorflow.callSuper))
error(loc, "one path skips constructor");
const fies = ctorflow.fieldinit;
- if (this.ctorflow.fieldinit.length && fies.length)
+ if (!this.ctorflow.fieldinit.length || !fies.length)
+ return;
+ FuncDeclaration f = func;
+ if (fes)
+ f = fes.func;
+ auto ad = f.isMemberDecl();
+ assert(ad);
+ foreach (i, v; ad.fields)
{
- FuncDeclaration f = func;
- if (fes)
- f = fes.func;
- auto ad = f.isMemberDecl();
- assert(ad);
- foreach (i, v; ad.fields)
+ bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
+ auto fieldInit = &this.ctorflow.fieldinit[i];
+ const fiesCurrent = fies[i];
+ if (fieldInit.loc is Loc.init)
+ fieldInit.loc = fiesCurrent.loc;
+ if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit)
{
- bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
- auto fieldInit = &this.ctorflow.fieldinit[i];
- const fiesCurrent = fies[i];
- if (fieldInit.loc is Loc.init)
- fieldInit.loc = fiesCurrent.loc;
- if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit)
- {
- error(loc, "one path skips field `%s`", v.toChars());
- }
+ error(loc, "one path skips field `%s`", v.toChars());
}
}
}
@@ -352,7 +422,7 @@ extern (C++) struct Scope
* Returns:
* symbol if found, null if not
*/
- extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, out Dsymbol pscopesym, SearchOptFlags flags = SearchOpt.all)
+ extern (C++) Dsymbol search(Loc loc, Identifier ident, out Dsymbol pscopesym, SearchOptFlags flags = SearchOpt.all)
{
version (LOGSEARCH)
{
@@ -470,7 +540,7 @@ extern (C++) struct Scope
if (sc.scopesym.isModule())
flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed
- else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration())
+ else if (sc.inCfile && sc.scopesym.isStructDeclaration())
continue; // C doesn't have struct scope
if (Dsymbol s = sc.scopesym.search(loc, ident, flags))
@@ -492,11 +562,10 @@ extern (C++) struct Scope
}
NotFound:
- if (global.params.fixAliasThis)
+ if (sc.previews.fixAliasThis)
{
Expression exp = new ThisExp(loc);
- Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp);
- if (aliasSym)
+ if (Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp))
{
//printf("found aliassym: %s\n", aliasSym.toChars());
pscopesym = new ExpressionDsymbol(exp);
@@ -511,7 +580,7 @@ extern (C++) struct Scope
return null;
}
- if (this.flags & SCOPE.ignoresymbolvisibility)
+ if (this.ignoresymbolvisibility)
flags |= SearchOpt.ignoreVisibility;
// First look in local scopes
@@ -658,7 +727,7 @@ extern (C++) struct Scope
//printf("\t\tscopesym = %p\n", scopesym);
if (!scopesym.symtab)
scopesym.symtab = new DsymbolTable();
- if (!(flags & SCOPE.Cfile))
+ if (!this.inCfile)
return scopesym.symtabInsert(s);
// ImportC insert
@@ -753,7 +822,7 @@ extern (C++) struct Scope
{
//printf("\tsc = %p\n", sc);
sc.nofree = true;
- assert(!(flags & SCOPE.free));
+ assert(!this.canFree);
//assert(sc != sc.enclosing);
//assert(!sc.enclosing || sc != sc.enclosing.enclosing);
//if (++i == 10)
@@ -814,7 +883,7 @@ extern (C++) struct Scope
*/
extern (D) bool isFromSpeculativeSemanticContext() scope
{
- return this.intypeof || this.flags & SCOPE.compile;
+ return this.intypeof || this.traitsCompiles;
}
@@ -824,18 +893,24 @@ extern (C++) struct Scope
*/
extern (D) bool needsCodegen()
{
- return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0;
+ return !this.ctfe && !this.ctfeBlock && !this.traitsCompiles;
}
/// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
extern (D) FeatureState useDIP1000()
{
- return (flags & SCOPE.dip1000) ? FeatureState.enabled : FeatureState.disabled;
+ return (this.previews.dip1000 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
}
/// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
extern (D) FeatureState useDIP25()
{
- return (flags & SCOPE.dip25) ? FeatureState.enabled : FeatureState.disabled;
+ return (this.previews.dip25 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
+ }
+
+ /// Returns: whether this scope compiles with `edition` or later
+ extern (D) bool hasEdition(Edition edition)
+ {
+ return _module && _module.edition >= edition;
}
}
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index df4d07a..d07be2f 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d, _dstruct.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dstruct.d, _dstruct.d)
* Documentation: https://dlang.org/phobos/dmd_dstruct.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dstruct.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dstruct.d
*/
module dmd.dstruct;
@@ -23,11 +23,12 @@ import dmd.declaration;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem;
+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;
@@ -36,7 +37,7 @@ import dmd.mtype;
import dmd.opover;
import dmd.target;
import dmd.tokens;
-import dmd.typesem;
+import dmd.typesem : isZeroInit, merge, size, hasPointers;
import dmd.typinf;
import dmd.visitor;
@@ -65,126 +66,6 @@ FuncDeclaration search_toString(StructDeclaration sd)
return fd;
}
-/***************************************
- * Request additional semantic analysis for TypeInfo generation.
- * Params:
- * sc = context
- * t = type that TypeInfo is being generated for
- */
-extern (D) void semanticTypeInfo(Scope* sc, Type t)
-{
- if (sc)
- {
- if (sc.intypeof)
- return;
- if (!sc.needsCodegen())
- return;
- }
-
- if (!t)
- return;
-
- void visitVector(TypeVector t)
- {
- semanticTypeInfo(sc, t.basetype);
- }
-
- void visitAArray(TypeAArray t)
- {
- semanticTypeInfo(sc, t.index);
- semanticTypeInfo(sc, t.next);
- }
-
- void visitStruct(TypeStruct t)
- {
- //printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars());
- StructDeclaration sd = t.sym;
-
- /* Step 1: create TypeInfoDeclaration
- */
- if (!sc) // inline may request TypeInfo.
- {
- Scope scx;
- scx.eSink = global.errorSink;
- scx._module = sd.getModule();
- getTypeInfoType(sd.loc, t, &scx);
- sd.requestTypeInfo = true;
- }
- else if (!sc.minst)
- {
- // don't yet have to generate TypeInfo instance if
- // the typeid(T) expression exists in speculative scope.
- }
- else
- {
- getTypeInfoType(sd.loc, t, sc);
- sd.requestTypeInfo = true;
-
- // https://issues.dlang.org/show_bug.cgi?id=15149
- // if the typeid operand type comes from a
- // result of auto function, it may be yet speculative.
- // unSpeculative(sc, sd);
- }
-
- /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
- * This should be done even if typeid(T) exists in speculative scope.
- * Because it may appear later in non-speculative scope.
- */
- if (!sd.members)
- return; // opaque struct
- if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.tidtor && !sd.xhash && !search_toString(sd))
- return; // none of TypeInfo-specific members
-
- // If the struct is in a non-root module, run semantic3 to get
- // correct symbols for the member function.
- if (sd.semanticRun >= PASS.semantic3)
- {
- // semantic3 is already done
- }
- else if (TemplateInstance ti = sd.isInstantiated())
- {
- if (ti.minst && !ti.minst.isRoot())
- Module.addDeferredSemantic3(sd);
- }
- else
- {
- if (sd.inNonRoot())
- {
- //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot());
- Module.addDeferredSemantic3(sd);
- }
- }
- }
-
- void visitTuple(TypeTuple t)
- {
- if (t.arguments)
- {
- foreach (arg; *t.arguments)
- {
- semanticTypeInfo(sc, arg.type);
- }
- }
- }
-
- /* Note structural similarity of this Type walker to that in isSpeculativeType()
- */
-
- Type tb = t.toBasetype();
- switch (tb.ty)
- {
- case Tvector: visitVector(tb.isTypeVector()); break;
- case Taarray: visitAArray(tb.isTypeAArray()); break;
- case Tstruct: visitStruct(tb.isTypeStruct()); break;
- case Ttuple: visitTuple (tb.isTypeTuple()); break;
-
- case Tclass:
- case Tenum: break;
-
- default: semanticTypeInfo(sc, tb.nextOf()); break;
- }
-}
-
enum StructFlags : int
{
none = 0x0,
@@ -220,9 +101,10 @@ extern (C++) class StructDeclaration : AggregateDeclaration
bool hasIdentityEquals; // true if has identity opEquals
bool hasNoFields; // has no fields
bool hasCopyCtor; // copy constructor
+ bool hasMoveCtor; // move constructor
bool hasPointerField; // members with indirections
bool hasVoidInitPointers; // void-initialized unsafe fields
- bool hasSystemFields; // @system members
+ bool hasUnsafeBitpatterns; // @system members, pointers, bool
bool hasFieldWithInvariant; // invariants
bool computedTypeProperties;// the above 3 fields are computed
// Even if struct is defined as non-root symbol, some built-in operations
@@ -234,9 +116,10 @@ extern (C++) class StructDeclaration : AggregateDeclaration
import dmd.common.bitfields : generateBitFields;
mixin(generateBitFields!(BitFields, ushort));
- extern (D) this(const ref Loc loc, Identifier id, bool inObject)
+ extern (D) this(Loc loc, Identifier id, bool inObject)
{
super(loc, id);
+ this.dsym = DSYM.structDeclaration;
zeroInit = false; // assume false until we do semantic processing
ispod = ThreeState.none;
// For forward references
@@ -249,7 +132,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
}
}
- static StructDeclaration create(const ref Loc loc, Identifier id, bool inObject)
+ static StructDeclaration create(Loc loc, Identifier id, bool inObject)
{
return new StructDeclaration(loc, id, inObject);
}
@@ -290,11 +173,12 @@ extern (C++) class StructDeclaration : AggregateDeclaration
{
Dsymbol s = (*members)[i];
s.setFieldOffset(this, &fieldState, isunion);
- }
- if (type.ty == Terror)
- {
- errors = true;
- return;
+ if (type.ty == Terror)
+ {
+ errorSupplemental(s.loc, "error on member `%s`", s.toPrettyChars);
+ errors = true;
+ return;
+ }
}
if (structsize == 0)
@@ -319,11 +203,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
*/
structsize = 4;
}
- else if (target.c.bitFieldStyle == TargetC.BitFieldStyle.DM)
- {
- structsize = 0;
- alignsize = 0;
- }
else
structsize = 0;
break;
@@ -354,8 +233,18 @@ extern (C++) class StructDeclaration : AggregateDeclaration
// Determine if struct is all zeros or not
zeroInit = true;
+ auto lastOffset = -1;
foreach (vd; fields)
{
+ // First skip zero sized fields
+ if (vd.type.size(vd.loc) == 0)
+ continue;
+
+ // only consider first sized member of an (anonymous) union
+ if (vd.overlapped && vd.offset == lastOffset)
+ continue;
+ lastOffset = vd.offset;
+
if (vd._init)
{
if (vd._init.isVoidInitializer())
@@ -364,10 +253,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
*/
continue;
- // Zero size fields are zero initialized
- if (vd.type.size(vd.loc) == 0)
- continue;
-
// Examine init to see if it is all 0s.
auto exp = vd.getConstInitializer();
if (!exp || !_isZeroInit(exp))
@@ -395,13 +280,16 @@ extern (C++) class StructDeclaration : AggregateDeclaration
foreach (vd; fields)
{
if (vd.storage_class & STC.ref_ || vd.hasPointers())
+ {
hasPointerField = true;
+ hasUnsafeBitpatterns = true;
+ }
if (vd._init && vd._init.isVoidInitializer() && vd.type.hasPointers())
hasVoidInitPointers = true;
- if (vd.storage_class & STC.system || vd.type.hasSystemFields())
- hasSystemFields = true;
+ if (vd.storage_class & STC.system || vd.type.hasUnsafeBitpatterns())
+ hasUnsafeBitpatterns = true;
if (!vd._init && vd.type.hasVoidInitPointers())
hasVoidInitPointers = true;
@@ -432,13 +320,22 @@ extern (C++) class StructDeclaration : AggregateDeclaration
if (ispod != ThreeState.none)
return (ispod == ThreeState.yes);
- ispod = ThreeState.yes;
-
import dmd.clone;
- bool hasCpCtorLocal;
- needCopyCtor(this, hasCpCtorLocal);
- if (enclosing || search(this, loc, Id.postblit) || search(this, loc, Id.dtor) || hasCpCtorLocal)
+ 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;
@@ -454,12 +351,9 @@ extern (C++) class StructDeclaration : AggregateDeclaration
return false;
}
- Type tv = v.type.baseElemOf();
- if (tv.ty == Tstruct)
+ if (auto ts = v.type.baseElemOf().isTypeStruct())
{
- TypeStruct ts = cast(TypeStruct)tv;
- StructDeclaration sd = ts.sym;
- if (!sd.isPOD())
+ if (!ts.sym.isPOD())
{
ispod = ThreeState.no;
return false;
@@ -467,7 +361,8 @@ extern (C++) class StructDeclaration : AggregateDeclaration
}
}
- return (ispod == ThreeState.yes);
+ ispod = ThreeState.yes;
+ return true;
}
/***************************************
@@ -480,11 +375,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
return postblit || hasCopyCtor;
}
- override final inout(StructDeclaration) isStructDeclaration() inout @nogc nothrow pure @safe
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -609,7 +499,7 @@ bool _isZeroInit(Expression exp)
case EXP.string_:
{
- StringExp se = cast(StringExp)exp;
+ auto se = cast(StringExp)exp;
if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array
return se.len == 0;
@@ -646,9 +536,10 @@ bool _isZeroInit(Expression exp)
*/
extern (C++) final class UnionDeclaration : StructDeclaration
{
- extern (D) this(const ref Loc loc, Identifier id)
+ extern (D) this(Loc loc, Identifier id)
{
super(loc, id, false);
+ this.dsym = DSYM.unionDeclaration;
}
override UnionDeclaration syntaxCopy(Dsymbol s)
@@ -664,11 +555,6 @@ extern (C++) final class UnionDeclaration : StructDeclaration
return "union";
}
- override inout(UnionDeclaration) isUnionDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index b831c32..74ca9cb 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -1,12 +1,12 @@
/**
* The base class for a D symbol, which can be a module, variable, function, enum, etc.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbol.d, _dsymbol.d)
* Documentation: https://dlang.org/phobos/dmd_dsymbol.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbol.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dsymbol.d
*/
module dmd.dsymbol;
@@ -51,11 +51,12 @@ import dmd.statement;
import dmd.staticassert;
import dmd.tokens;
import dmd.visitor;
+import dmd.dsymbolsem;
import dmd.common.outbuffer;
/***************************************
- * Calls dg(Dsymbol *sym) for each Dsymbol.
+ * Calls dg(Dsymbol* sym) for each Dsymbol.
* If dg returns !=0, stops and returns that value else returns 0.
* Params:
* symbols = Dsymbols
@@ -84,7 +85,7 @@ int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg)
}
/***************************************
- * Calls dg(Dsymbol *sym) for each Dsymbol.
+ * Calls dg(Dsymbol* sym) for each Dsymbol.
* Params:
* symbols = Dsymbols
* dg = delegate to call for each Dsymbol
@@ -258,6 +259,76 @@ private struct DsymbolAttributes
UserAttributeDeclaration userAttribDecl;
}
+enum DSYM : ubyte
+{
+ none,
+ dsymbol,
+ linkDeclaration,
+ cppMangleDeclaration,
+ alignDeclaration,
+ pragmaDeclaration,
+ conditionalDeclaration,
+ staticForeachDeclaration,
+ userAttributeDeclaration,
+ labelDsymbol,
+ aliasThis,
+ package_,
+ module_,
+ enumMember,
+ templateDeclaration,
+ templateInstance,
+ templateMixin,
+ forwardingAttribDeclaration,
+ nspace,
+ declaration,
+ storageClassDeclaration,
+ expressionDsymbol,
+ aliasAssign,
+ thisDeclaration,
+ bitFieldDeclaration,
+ typeInfoDeclaration,
+ tupleDeclaration,
+ aliasDeclaration,
+ aggregateDeclaration,
+ funcDeclaration,
+ funcAliasDeclaration,
+ overDeclaration,
+ funcLiteralDeclaration,
+ ctorDeclaration,
+ postBlitDeclaration,
+ dtorDeclaration,
+ staticCtorDeclaration,
+ staticDtorDeclaration,
+ sharedStaticCtorDeclaration,
+ sharedStaticDtorDeclaration,
+ invariantDeclaration,
+ unitTestDeclaration,
+ newDeclaration,
+ varDeclaration,
+ versionSymbol,
+ debugSymbol,
+ classDeclaration,
+ structDeclaration,
+ unionDeclaration,
+ interfaceDeclaration,
+ scopeDsymbol,
+ forwardingScopeDsymbol,
+ withScopeSymbol,
+ arrayScopeSymbol,
+ import_,
+ enumDeclaration,
+ symbolDeclaration,
+ attribDeclaration,
+ anonDeclaration,
+ cppNamespaceDeclaration,
+ visibilityDeclaration,
+ overloadSet,
+ mixinDeclaration,
+ staticAssert,
+ staticIfDeclaration,
+ cAsmDeclaration
+}
+
/***********************************************************
*/
extern (C++) class Dsymbol : ASTNode
@@ -265,42 +336,51 @@ extern (C++) class Dsymbol : ASTNode
Identifier ident;
Dsymbol parent;
Symbol* csym; // symbol for code generator
- const Loc loc; // where defined
Scope* _scope; // !=null means context to use for semantic()
- const(char)* prettystring; // cached value of toPrettyChars()
private DsymbolAttributes* atts; /// attached attribute declarations
- bool errors; // this symbol failed to pass semantic()
- PASS semanticRun = PASS.initial;
+ const Loc loc; // where defined
ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
+ static struct BitFields
+ {
+ bool errors; // this symbol failed to pass semantic()
+ PASS semanticRun = PASS.initial;
+ }
+ import dmd.common.bitfields;
+ mixin(generateBitFields!(BitFields, ubyte));
+ DSYM dsym;
- final extern (D) this() nothrow @safe
+ final extern (D) this(DSYM tag) nothrow @safe
{
//printf("Dsymbol::Dsymbol(%p)\n", this);
- loc = Loc(null, 0, 0);
+ this.dsym = tag;
+ loc = Loc.initial;
}
- final extern (D) this(Identifier ident) nothrow @safe
+ final extern (D) this(DSYM tag, Identifier ident) nothrow @safe
{
//printf("Dsymbol::Dsymbol(%p, ident)\n", this);
- this.loc = Loc(null, 0, 0);
+ this.dsym = tag;
+ this.loc = Loc.initial;
this.ident = ident;
}
- final extern (D) this(const ref Loc loc, Identifier ident) nothrow @safe
+ final extern (D) this(DSYM tag, Loc loc, Identifier ident) nothrow @safe
{
//printf("Dsymbol::Dsymbol(%p, ident)\n", this);
+ this.dsym = tag;
this.loc = loc;
this.ident = ident;
}
static Dsymbol create(Identifier ident) nothrow @safe
{
- return new Dsymbol(ident);
+ return new Dsymbol(DSYM.dsymbol, ident);
}
- override const(char)* toChars() const
+ final override const(char)* toChars() const
{
- return ident ? ident.toChars() : "__anonymous";
+ import dmd.hdrgen : toChars;
+ return toChars(this);
}
// Getters / setters for fields stored in `DsymbolAttributes`
@@ -345,19 +425,6 @@ extern (C++) class Dsymbol : ASTNode
return toChars();
}
- final const(Loc) getLoc()
- {
- if (!loc.isValid()) // avoid bug 5861.
- if (const m = getModule())
- return Loc(m.srcfile.toChars(), 0, 0);
- return loc;
- }
-
- final const(char)* locToChars()
- {
- return getLoc().toChars();
- }
-
override bool equals(const RootObject o) const
{
if (this == o)
@@ -396,8 +463,7 @@ extern (C++) class Dsymbol : ASTNode
while (s)
{
//printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
- Module m = s.isModule();
- if (m)
+ if (Module m = s.isModule())
return m;
s = s.parent;
}
@@ -428,8 +494,7 @@ extern (C++) class Dsymbol : ASTNode
while (s)
{
//printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
- Module m = s.isModule();
- if (m)
+ if (Module m = s.isModule())
return m;
TemplateInstance ti = s.isTemplateInstance();
if (ti && ti.enclosing)
@@ -453,7 +518,7 @@ extern (C++) class Dsymbol : ASTNode
*
* See also `parent`, `toParent` and `toParent2`.
*/
- final inout(Dsymbol) pastMixin() inout
+ final inout(Dsymbol) pastMixin() inout @safe
{
//printf("Dsymbol::pastMixin() %s\n", toChars());
if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
@@ -503,13 +568,13 @@ extern (C++) class Dsymbol : ASTNode
* // s.toParentLocal() == FuncDeclaration('mod.test')
* ---
*/
- final inout(Dsymbol) toParent() inout
+ final inout(Dsymbol) toParent() inout @safe
{
return parent ? parent.pastMixin() : null;
}
/// ditto
- final inout(Dsymbol) toParent2() inout
+ final inout(Dsymbol) toParent2() inout @safe
{
if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol())
return parent;
@@ -593,7 +658,7 @@ extern (C++) class Dsymbol : ASTNode
continue;
if (sa == p1)
return true;
- else if (p2 && sa == p2)
+ if (p2 && sa == p2)
return true;
}
outer = ti.tempdecl.toParent();
@@ -621,7 +686,7 @@ extern (C++) class Dsymbol : ASTNode
final Ungag ungagSpeculative() const
{
- uint oldgag = global.gag;
+ const oldgag = global.gag;
if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
global.gag = 0;
return Ungag(oldgag);
@@ -657,15 +722,10 @@ extern (C++) class Dsymbol : ASTNode
const(char)* toPrettyChars(bool QualifyTypes = false)
{
- if (prettystring && !QualifyTypes)
- return prettystring; // value cached for speed
-
//printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
if (!parent)
{
auto s = toChars();
- if (!QualifyTypes)
- prettystring = s;
return s;
}
@@ -685,8 +745,6 @@ extern (C++) class Dsymbol : ASTNode
addQualifiers(this);
auto s = buf.extractSlice(true).ptr;
- if (!QualifyTypes)
- prettystring = s;
return s;
}
@@ -723,7 +781,7 @@ extern (C++) class Dsymbol : ASTNode
* Returns:
* SIZE_INVALID when the size cannot be determined
*/
- uinteger_t size(const ref Loc loc)
+ uinteger_t size(Loc loc)
{
.error(loc, "%s `%s` symbol `%s` has no size", kind, toPrettyChars, toChars());
return SIZE_INVALID;
@@ -842,20 +900,6 @@ extern (C++) class Dsymbol : ASTNode
assert(0);
}
- /**************************************
- * Determine if this symbol is only one.
- * Returns:
- * false, ps = null: There are 2 or more symbols
- * true, ps = null: There are zero symbols
- * true, ps = symbol: The one and only one symbol
- */
- bool oneMember(out Dsymbol ps, Identifier ident)
- {
- //printf("Dsymbol::oneMember()\n");
- ps = this;
- return true;
- }
-
/*****************************************
* Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
*/
@@ -872,7 +916,7 @@ extern (C++) class Dsymbol : ASTNode
for (size_t i = 0; i < members.length; i++)
{
Dsymbol sx = (*members)[i];
- bool x = sx.oneMember(ps, ident);
+ bool x = sx.oneMember(ps, ident); //MYTODO: this temporarily creates a new dependency to dsymbolsem, will need to extract oneMembers() later
//printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
if (!x)
{
@@ -928,42 +972,18 @@ extern (C++) class Dsymbol : ASTNode
return false;
}
- bool hasStaticCtorOrDtor()
- {
- //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
- return false;
- }
-
void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
{
}
- void checkCtorConstInit()
- {
- }
-
/****************************************
* Add documentation comment to Dsymbol.
* Ignore NULL comments.
*/
void addComment(const(char)* comment)
{
- if (!comment || !*comment)
- return;
-
- //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
- void* h = cast(void*)this; // just the pointer is the key
- auto p = h in commentHashTable;
- if (!p)
- {
- commentHashTable[h] = comment;
- return;
- }
- if (strcmp(*p, comment) != 0)
- {
- // Concatenate the two
- *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
- }
+ import dmd.dsymbolsem;
+ dmd.dsymbolsem.addComment(this, comment);
}
/// get documentation comment for this Dsymbol
@@ -981,7 +1001,7 @@ extern (C++) class Dsymbol : ASTNode
/* Shell around addComment() to avoid disruption for the moment */
final void comment(const(char)* comment) { addComment(comment); }
- private extern (D) __gshared const(char)*[void*] commentHashTable;
+ extern (D) __gshared const(char)*[void*] commentHashTable;
/**********************************
@@ -1048,64 +1068,181 @@ extern (C++) class Dsymbol : ASTNode
v.visit(this);
}
- pure nothrow @safe @nogc:
-
- // Eliminate need for dynamic_cast
- inout(Package) isPackage() inout { return null; }
- inout(Module) isModule() inout { return null; }
- inout(EnumMember) isEnumMember() inout { return null; }
- inout(TemplateDeclaration) isTemplateDeclaration() inout { return null; }
- inout(TemplateInstance) isTemplateInstance() inout { return null; }
- inout(TemplateMixin) isTemplateMixin() inout { return null; }
- inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
- inout(Nspace) isNspace() inout { return null; }
- inout(Declaration) isDeclaration() inout { return null; }
- inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; }
- inout(ExpressionDsymbol) isExpressionDsymbol() inout { return null; }
- inout(AliasAssign) isAliasAssign() inout { return null; }
- inout(ThisDeclaration) isThisDeclaration() inout { return null; }
- inout(BitFieldDeclaration) isBitFieldDeclaration() inout { return null; }
- inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; }
- inout(TupleDeclaration) isTupleDeclaration() inout { return null; }
- inout(AliasDeclaration) isAliasDeclaration() inout { return null; }
- inout(AggregateDeclaration) isAggregateDeclaration() inout { return null; }
- inout(FuncDeclaration) isFuncDeclaration() inout { return null; }
- inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return null; }
- inout(OverDeclaration) isOverDeclaration() inout { return null; }
- inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return null; }
- inout(CtorDeclaration) isCtorDeclaration() inout { return null; }
- inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return null; }
- inout(DtorDeclaration) isDtorDeclaration() inout { return null; }
- inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return null; }
- inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return null; }
- inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
- inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
- inout(InvariantDeclaration) isInvariantDeclaration() inout { return null; }
- inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return null; }
- inout(NewDeclaration) isNewDeclaration() inout { return null; }
- inout(VarDeclaration) isVarDeclaration() inout { return null; }
- inout(VersionSymbol) isVersionSymbol() inout { return null; }
- inout(DebugSymbol) isDebugSymbol() inout { return null; }
- inout(ClassDeclaration) isClassDeclaration() inout { return null; }
- inout(StructDeclaration) isStructDeclaration() inout { return null; }
- inout(UnionDeclaration) isUnionDeclaration() inout { return null; }
- inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return null; }
- inout(ScopeDsymbol) isScopeDsymbol() inout { return null; }
- inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return null; }
- inout(WithScopeSymbol) isWithScopeSymbol() inout { return null; }
- inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; }
- inout(Import) isImport() inout { return null; }
- inout(EnumDeclaration) isEnumDeclaration() inout { return null; }
- inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; }
- inout(AttribDeclaration) isAttribDeclaration() inout { return null; }
- inout(AnonDeclaration) isAnonDeclaration() inout { return null; }
- inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; }
- inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
- inout(OverloadSet) isOverloadSet() inout { return null; }
- inout(MixinDeclaration) isMixinDeclaration() inout { return null; }
- inout(StaticAssert) isStaticAssert() inout { return null; }
- inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; }
- inout(CAsmDeclaration) isCAsmDeclaration() inout { return null; }
+ pure nothrow @trusted @nogc final:
+
+ inout(Package) isPackage() inout { return (dsym == DSYM.package_ || dsym == DSYM.module_) ? cast(inout(Package)) cast(void*) this : null; }
+ inout(Module) isModule() inout { return dsym == DSYM.module_ ? cast(inout(Module)) cast(void*) this : null; }
+ inout(EnumMember) isEnumMember() inout { return dsym == DSYM.enumMember ? cast(inout(EnumMember)) cast(void*) this : null; }
+ inout(TemplateDeclaration) isTemplateDeclaration() inout { return dsym == DSYM.templateDeclaration ? cast(inout(TemplateDeclaration)) cast(void*) this : null; }
+ inout(TemplateInstance) isTemplateInstance() inout { return (dsym == DSYM.templateInstance || dsym == DSYM.templateMixin) ? cast(inout(TemplateInstance)) cast(void*) this : null; }
+ inout(TemplateMixin) isTemplateMixin() inout { return dsym == DSYM.templateMixin ? cast(inout(TemplateMixin)) cast(void*) this : null; }
+ inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return dsym == DSYM.forwardingAttribDeclaration ? cast(inout(ForwardingAttribDeclaration)) cast(void*) this : null; }
+ inout(Nspace) isNspace() inout { return dsym == DSYM.nspace ? cast(inout(Nspace)) cast(void*) this : null; }
+ inout(Declaration) isDeclaration() inout {
+ switch (dsym)
+ {
+ case DSYM.tupleDeclaration:
+ case DSYM.aliasDeclaration:
+ case DSYM.overDeclaration:
+ case DSYM.varDeclaration:
+ case DSYM.bitFieldDeclaration:
+ case DSYM.typeInfoDeclaration:
+ case DSYM.thisDeclaration:
+ case DSYM.enumMember:
+ case DSYM.symbolDeclaration:
+ case DSYM.funcDeclaration:
+ case DSYM.funcAliasDeclaration:
+ case DSYM.funcLiteralDeclaration:
+ case DSYM.ctorDeclaration:
+ case DSYM.postBlitDeclaration:
+ case DSYM.dtorDeclaration:
+ case DSYM.staticCtorDeclaration:
+ case DSYM.sharedStaticCtorDeclaration:
+ case DSYM.staticDtorDeclaration:
+ case DSYM.sharedStaticDtorDeclaration:
+ case DSYM.invariantDeclaration:
+ case DSYM.unitTestDeclaration:
+ case DSYM.newDeclaration:
+ return cast(inout(Declaration)) cast(void*) this;
+ default:
+ return null;
+ }
+ }
+ inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return dsym == DSYM.storageClassDeclaration ? cast(inout(StorageClassDeclaration)) cast(void*) this : null; }
+ inout(ExpressionDsymbol) isExpressionDsymbol() inout { return dsym == DSYM.expressionDsymbol ? cast(inout(ExpressionDsymbol)) cast(void*) this : null; }
+ inout(AliasAssign) isAliasAssign() inout { return dsym == DSYM.aliasAssign ? cast(inout(AliasAssign)) cast(void*) this : null; }
+ inout(ThisDeclaration) isThisDeclaration() inout { return dsym == DSYM.thisDeclaration ? cast(inout(ThisDeclaration)) cast(void*) this : null; }
+ inout(BitFieldDeclaration) isBitFieldDeclaration() inout { return dsym == DSYM.bitFieldDeclaration ? cast(inout(BitFieldDeclaration)) cast(void*) this : null; }
+ inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return dsym == DSYM.typeInfoDeclaration ? cast(inout(TypeInfoDeclaration)) cast(void*) this : null; }
+ inout(TupleDeclaration) isTupleDeclaration() inout { return dsym == DSYM.tupleDeclaration ? cast(inout(TupleDeclaration)) cast(void*) this : null; }
+ inout(AliasDeclaration) isAliasDeclaration() inout { return dsym == DSYM.aliasDeclaration ? cast(inout(AliasDeclaration)) cast(void*) this : null; }
+ inout(AggregateDeclaration) isAggregateDeclaration() inout {
+ switch (dsym)
+ {
+ case DSYM.aggregateDeclaration:
+ case DSYM.structDeclaration:
+ case DSYM.unionDeclaration:
+ case DSYM.classDeclaration:
+ case DSYM.interfaceDeclaration:
+ return cast(inout(AggregateDeclaration)) cast(void*) this;
+ default:
+ return null;
+ }
+ }
+ inout(FuncDeclaration) isFuncDeclaration() inout {
+ switch (dsym)
+ {
+ case DSYM.funcDeclaration:
+ case DSYM.funcAliasDeclaration:
+ case DSYM.funcLiteralDeclaration:
+ case DSYM.ctorDeclaration:
+ case DSYM.postBlitDeclaration:
+ case DSYM.dtorDeclaration:
+ case DSYM.staticCtorDeclaration:
+ case DSYM.sharedStaticCtorDeclaration:
+ case DSYM.staticDtorDeclaration:
+ case DSYM.sharedStaticDtorDeclaration:
+ case DSYM.invariantDeclaration:
+ case DSYM.unitTestDeclaration:
+ case DSYM.newDeclaration:
+ return cast(inout(FuncDeclaration)) cast(void*) this;
+ default:
+ return null;
+ }
+ }
+ inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return dsym == DSYM.funcAliasDeclaration ? cast(inout(FuncAliasDeclaration)) cast(void*) this : null; }
+ inout(OverDeclaration) isOverDeclaration() inout { return dsym == DSYM.overDeclaration ? cast(inout(OverDeclaration)) cast(void*) this : null; }
+ inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return dsym == DSYM.funcLiteralDeclaration ? cast(inout(FuncLiteralDeclaration)) cast(void*) this : null; }
+ inout(CtorDeclaration) isCtorDeclaration() inout { return dsym == DSYM.ctorDeclaration ? cast(inout(CtorDeclaration)) cast(void*) this : null; }
+ inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return dsym == DSYM.postBlitDeclaration ? cast(inout(PostBlitDeclaration)) cast(void*) this : null; }
+ inout(DtorDeclaration) isDtorDeclaration() inout { return dsym == DSYM.dtorDeclaration ? cast(inout(DtorDeclaration)) cast(void*) this : null; }
+ inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return (dsym == DSYM.staticCtorDeclaration || dsym == DSYM.sharedStaticCtorDeclaration) ? cast(inout(StaticCtorDeclaration)) cast(void*) this : null; }
+ inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return (dsym == DSYM.staticDtorDeclaration || dsym == DSYM.sharedStaticDtorDeclaration) ? cast(inout(StaticDtorDeclaration)) cast(void*) this : null; }
+ inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return dsym == DSYM.sharedStaticCtorDeclaration ? cast(inout(SharedStaticCtorDeclaration)) cast(void*) this : null; }
+ inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return dsym == DSYM.sharedStaticDtorDeclaration ? cast(inout(SharedStaticDtorDeclaration)) cast(void*) this : null; }
+ inout(InvariantDeclaration) isInvariantDeclaration() inout { return dsym == DSYM.invariantDeclaration ? cast(inout(InvariantDeclaration)) cast(void*) this : null; }
+ inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return dsym == DSYM.unitTestDeclaration ? cast(inout(UnitTestDeclaration)) cast(void*) this : null; }
+ inout(NewDeclaration) isNewDeclaration() inout { return dsym == DSYM.newDeclaration ? cast(inout(NewDeclaration)) cast(void*) this : null; }
+ inout(VarDeclaration) isVarDeclaration() inout {
+ switch (dsym)
+ {
+ case DSYM.varDeclaration:
+ case DSYM.bitFieldDeclaration:
+ case DSYM.typeInfoDeclaration:
+ case DSYM.thisDeclaration:
+ case DSYM.enumMember:
+ return cast(inout(VarDeclaration)) cast(void*) this;
+ default:
+ return null;
+ }
+ }
+ inout(VersionSymbol) isVersionSymbol() inout { return dsym == DSYM.versionSymbol ? cast(inout(VersionSymbol)) cast(void*) this : null; }
+ inout(DebugSymbol) isDebugSymbol() inout { return dsym == DSYM.debugSymbol ? cast(inout(DebugSymbol)) cast(void*) this : null; }
+ inout(ClassDeclaration) isClassDeclaration() inout { return (dsym == DSYM.classDeclaration || dsym == DSYM.interfaceDeclaration) ? cast(inout(ClassDeclaration)) cast(void*) this : null; }
+ inout(StructDeclaration) isStructDeclaration() inout { return (dsym == DSYM.structDeclaration || dsym == DSYM.unionDeclaration) ? cast(inout(StructDeclaration)) cast(void*) this : null; }
+ inout(UnionDeclaration) isUnionDeclaration() inout { return dsym == DSYM.unionDeclaration ? cast(inout(UnionDeclaration)) cast(void*) this : null; }
+ inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return dsym == DSYM.interfaceDeclaration ? cast(inout(InterfaceDeclaration)) cast(void*) this : null; }
+ inout(ScopeDsymbol) isScopeDsymbol() inout {
+ switch (dsym)
+ {
+ case DSYM.enumDeclaration:
+ case DSYM.scopeDsymbol:
+ case DSYM.package_:
+ case DSYM.module_:
+ case DSYM.nspace:
+ case DSYM.templateInstance:
+ case DSYM.templateMixin:
+ case DSYM.templateDeclaration:
+ case DSYM.aggregateDeclaration:
+ case DSYM.structDeclaration:
+ case DSYM.unionDeclaration:
+ case DSYM.classDeclaration:
+ case DSYM.interfaceDeclaration:
+ case DSYM.withScopeSymbol:
+ case DSYM.arrayScopeSymbol:
+ case DSYM.forwardingScopeDsymbol:
+ return cast(inout(ScopeDsymbol)) cast(void*) this;
+ default:
+ return null;
+ }
+ }
+ inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return dsym == DSYM.forwardingScopeDsymbol ? cast(inout(ForwardingScopeDsymbol)) cast(void*) this : null; }
+ inout(WithScopeSymbol) isWithScopeSymbol() inout { return dsym == DSYM.withScopeSymbol ? cast(inout(WithScopeSymbol)) cast(void*) this : null; }
+ inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return dsym == DSYM.arrayScopeSymbol ? cast(inout(ArrayScopeSymbol)) cast(void*) this : null; }
+ inout(Import) isImport() inout { return dsym == DSYM.import_ ? cast(inout(Import)) cast(void*) this : null; }
+ inout(EnumDeclaration) isEnumDeclaration() inout { return dsym == DSYM.enumDeclaration ? cast(inout(EnumDeclaration)) cast(void*) this : null; }
+ inout(SymbolDeclaration) isSymbolDeclaration() inout { return dsym == DSYM.symbolDeclaration ? cast(inout(SymbolDeclaration)) cast(void*) this : null; }
+ inout(AttribDeclaration) isAttribDeclaration() inout {
+ switch (dsym)
+ {
+ case DSYM.attribDeclaration:
+ case DSYM.storageClassDeclaration:
+ case DSYM.linkDeclaration:
+ case DSYM.cppMangleDeclaration:
+ case DSYM.cppNamespaceDeclaration:
+ case DSYM.visibilityDeclaration:
+ case DSYM.alignDeclaration:
+ case DSYM.anonDeclaration:
+ case DSYM.pragmaDeclaration:
+ case DSYM.conditionalDeclaration:
+ case DSYM.staticIfDeclaration:
+ case DSYM.staticForeachDeclaration:
+ case DSYM.forwardingAttribDeclaration:
+ case DSYM.mixinDeclaration:
+ case DSYM.userAttributeDeclaration:
+ return cast(inout(AttribDeclaration)) cast(void*) this;
+ default:
+ return null;
+ }
+ }
+ inout(AnonDeclaration) isAnonDeclaration() inout { return dsym == DSYM.anonDeclaration ? cast(inout(AnonDeclaration)) cast(void*) this : null; }
+ inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return dsym == DSYM.cppNamespaceDeclaration ? cast(inout(CPPNamespaceDeclaration)) cast(void*) this : null; }
+ inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return dsym == DSYM.visibilityDeclaration ? cast(inout(VisibilityDeclaration)) cast(void*) this : null; }
+ inout(OverloadSet) isOverloadSet() inout { return dsym == DSYM.overloadSet ? cast(inout(OverloadSet)) cast(void*) this : null; }
+ inout(MixinDeclaration) isMixinDeclaration() inout { return dsym == DSYM.mixinDeclaration ? cast(inout(MixinDeclaration)) cast(void*) this : null; }
+ inout(StaticAssert) isStaticAssert() inout { return dsym == DSYM.staticAssert ? cast(inout(StaticAssert)) cast(void*) this : null; }
+ inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return dsym == DSYM.staticIfDeclaration ? cast(inout(StaticIfDeclaration)) cast(void*) this : null; }
+ inout(CAsmDeclaration) isCAsmDeclaration() inout { return dsym == DSYM.cAsmDeclaration ? cast(inout(CAsmDeclaration)) cast(void*) this : null; }
}
/***********************************************************
@@ -1128,16 +1265,17 @@ private:
public:
final extern (D) this() nothrow @safe
{
+ super(DSYM.scopeDsymbol);
}
final extern (D) this(Identifier ident) nothrow @safe
{
- super(ident);
+ super(DSYM.scopeDsymbol, ident);
}
- final extern (D) this(const ref Loc loc, Identifier ident) nothrow @safe
+ final extern (D) this(Loc loc, Identifier ident) nothrow @safe
{
- super(loc, ident);
+ super(DSYM.scopeDsymbol, loc, ident);
}
override ScopeDsymbol syntaxCopy(Dsymbol s)
@@ -1277,7 +1415,7 @@ public:
return (members is null);
}
- static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2)
+ static void multiplyDefined(Loc loc, Dsymbol s1, Dsymbol s2)
{
version (none)
{
@@ -1313,7 +1451,7 @@ public:
}
else
{
- .error(s1.loc, "%s `%s` conflicts with %s `%s` at %s", s1.kind, s1.toPrettyChars, s2.kind(), s2.toPrettyChars(), s2.locToChars());
+ .error(s1.loc, "%s `%s` conflicts with %s `%s` at %s", s1.kind, s1.toPrettyChars, s2.kind(), s2.toPrettyChars(), s2.loc.toChars());
}
}
@@ -1347,29 +1485,6 @@ public:
return symtab.lookup(id);
}
- /****************************************
- * Return true if any of the members are static ctors or static dtors, or if
- * any members have members that are.
- */
- override bool hasStaticCtorOrDtor()
- {
- if (members)
- {
- for (size_t i = 0; i < members.length; i++)
- {
- Dsymbol member = (*members)[i];
- if (member.hasStaticCtorOrDtor())
- return true;
- }
- }
- return false;
- }
-
- override final inout(ScopeDsymbol) isScopeDsymbol() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1386,11 +1501,7 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol
extern (D) this(WithStatement withstate) nothrow @safe
{
this.withstate = withstate;
- }
-
- override inout(WithScopeSymbol) isWithScopeSymbol() inout
- {
- return this;
+ this.dsym = DSYM.withScopeSymbol;
}
override void accept(Visitor v)
@@ -1414,6 +1525,7 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
this._scope = sc;
this.arrayContent = exp;
+ this.dsym = DSYM.arrayScopeSymbol;
}
extern (D) this(Scope* sc, TypeTuple type) nothrow @safe
@@ -1428,11 +1540,6 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
this.arrayContent = td;
}
- override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -1448,7 +1555,7 @@ extern (C++) final class OverloadSet : Dsymbol
extern (D) this(Identifier ident, OverloadSet os = null) nothrow
{
- super(ident);
+ super(DSYM.overloadSet, ident);
if (os)
{
a.pushSlice(os.a[]);
@@ -1460,11 +1567,6 @@ extern (C++) final class OverloadSet : Dsymbol
a.push(s);
}
- override inout(OverloadSet) isOverloadSet() inout
- {
- return this;
- }
-
override const(char)* kind() const
{
return "overloadset";
@@ -1487,6 +1589,7 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
extern (D) this() nothrow @safe
{
super();
+ this.dsym = DSYM.forwardingScopeDsymbol;
}
override Dsymbol symtabInsert(Dsymbol s) nothrow
@@ -1555,11 +1658,6 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
override const(char)* kind()const{ return "local scope"; }
- override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow
- {
- return this;
- }
-
}
/**
@@ -1572,14 +1670,9 @@ extern (C++) final class ExpressionDsymbol : Dsymbol
Expression exp;
this(Expression exp) nothrow @safe
{
- super();
+ super(DSYM.expressionDsymbol);
this.exp = exp;
}
-
- override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow
- {
- return this;
- }
}
/**********************************************
@@ -1595,9 +1688,9 @@ extern (C++) final class AliasAssign : Dsymbol
Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
/// only one of type and aliassym can be != null
- extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow @safe
+ extern (D) this(Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow @safe
{
- super(loc, null);
+ super(DSYM.aliasAssign, loc, null);
this.ident = ident;
this.type = type;
this.aliassym = aliassym;
@@ -1612,11 +1705,6 @@ extern (C++) final class AliasAssign : Dsymbol
return aa;
}
- override inout(AliasAssign) isAliasAssign() inout
- {
- return this;
- }
-
override const(char)* kind() const
{
return "alias assignment";
@@ -1709,15 +1797,10 @@ extern (C++) final class CAsmDeclaration : Dsymbol
Expression code;
extern (D) this(Expression e) nothrow @safe
{
- super();
+ super(DSYM.cAsmDeclaration);
this.code = e;
}
- override inout(CAsmDeclaration) isCAsmDeclaration() inout nothrow
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index f845435..558d156 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -139,20 +139,6 @@ enum class PASS : uint8_t
obj // toObjFile() run
};
-enum
-{
- PASSinit, // initial state
- PASSsemantic, // semantic() started
- PASSsemanticdone, // semantic() done
- PASSsemantic2, // semantic2() started
- PASSsemantic2done, // semantic2() done
- PASSsemantic3, // semantic3() started
- PASSsemantic3done, // semantic3() done
- PASSinline, // inline started
- PASSinlinedone, // inline done
- PASSobj // toObjFile() run
-};
-
/* Flags for symbol search
*/
typedef unsigned SearchOptFlags;
@@ -192,17 +178,22 @@ public:
Identifier *ident;
Dsymbol *parent;
Symbol *csym; // symbol for code generator
- Loc loc; // where defined
Scope *_scope; // !=NULL means context to use for semantic()
- const utf8_t *prettystring;
private:
DsymbolAttributes* atts;
public:
- d_bool errors; // this symbol failed to pass semantic()
- PASS semanticRun;
+ Loc loc; // where defined
unsigned short localNum; // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
+
+ bool errors() const;
+ PASS semanticRun() const;
+ PASS semanticRun(PASS v);
+private:
+ unsigned char bitfields;
+ unsigned char dsym;
+public:
static Dsymbol *create(Identifier *);
- const char *toChars() const override;
+ const char *toChars() const final override;
DeprecatedDeclaration* depdecl();
CPPNamespaceDeclaration* cppnamespace();
UserAttributeDeclaration* userAttribDecl();
@@ -210,8 +201,6 @@ public:
CPPNamespaceDeclaration* cppnamespace(CPPNamespaceDeclaration* ns);
UserAttributeDeclaration* userAttribDecl(UserAttributeDeclaration* uad);
virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments
- Loc getLoc();
- const char *locToChars();
bool equals(const RootObject * const o) const override;
bool isAnonymous() const;
Module *getModule();
@@ -222,9 +211,9 @@ public:
Dsymbol *toParent2();
Dsymbol *toParentDecl();
Dsymbol *toParentLocal();
- Dsymbol *toParentP(Dsymbol *p1, Dsymbol *p2 = NULL);
+ Dsymbol *toParentP(Dsymbol *p1, Dsymbol *p2 = nullptr);
TemplateInstance *isInstantiated();
- bool followInstantiationContext(Dsymbol *p1, Dsymbol *p2 = NULL);
+ bool followInstantiationContext(Dsymbol *p1, Dsymbol *p2 = nullptr);
TemplateInstance *isSpeculative();
Ungag ungagSpeculative();
@@ -237,7 +226,7 @@ public:
virtual Dsymbol *toAlias(); // resolve real symbol
virtual Dsymbol *toAlias2();
virtual bool overloadInsert(Dsymbol *s);
- virtual uinteger_t size(const Loc &loc);
+ virtual uinteger_t size(Loc loc);
virtual bool isforwardRef();
virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member
virtual bool isExport() const; // is Dsymbol exported?
@@ -254,11 +243,8 @@ public:
virtual bool needThis(); // need a 'this' pointer?
virtual Visibility visible();
virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
- virtual bool oneMember(Dsymbol *&ps, Identifier *ident);
virtual bool hasPointers();
- virtual bool hasStaticCtorOrDtor();
virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { }
- virtual void checkCtorConstInit() { }
virtual void addComment(const utf8_t *comment);
const utf8_t *comment(); // current value of comment
@@ -269,61 +255,61 @@ public:
bool inNonRoot();
// Eliminate need for dynamic_cast
- virtual Package *isPackage() { return NULL; }
- virtual Module *isModule() { return NULL; }
- virtual EnumMember *isEnumMember() { return NULL; }
- virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; }
- virtual TemplateInstance *isTemplateInstance() { return NULL; }
- virtual TemplateMixin *isTemplateMixin() { return NULL; }
- virtual ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return NULL; }
- virtual Nspace *isNspace() { return NULL; }
- virtual Declaration *isDeclaration() { return NULL; }
- virtual StorageClassDeclaration *isStorageClassDeclaration(){ return NULL; }
- virtual ExpressionDsymbol *isExpressionDsymbol() { return NULL; }
- virtual AliasAssign *isAliasAssign() { return NULL; }
- virtual ThisDeclaration *isThisDeclaration() { return NULL; }
- virtual BitFieldDeclaration *isBitFieldDeclaration() { return NULL; }
- virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; }
- virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
- virtual AliasDeclaration *isAliasDeclaration() { return NULL; }
- virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; }
- virtual FuncDeclaration *isFuncDeclaration() { return NULL; }
- virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; }
- virtual OverDeclaration *isOverDeclaration() { return NULL; }
- virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; }
- virtual CtorDeclaration *isCtorDeclaration() { return NULL; }
- virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; }
- virtual DtorDeclaration *isDtorDeclaration() { return NULL; }
- virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; }
- virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; }
- virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; }
- virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; }
- virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; }
- virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; }
- virtual NewDeclaration *isNewDeclaration() { return NULL; }
- virtual VarDeclaration *isVarDeclaration() { return NULL; }
- virtual VersionSymbol *isVersionSymbol() { return NULL; }
- virtual DebugSymbol *isDebugSymbol() { return NULL; }
- virtual ClassDeclaration *isClassDeclaration() { return NULL; }
- virtual StructDeclaration *isStructDeclaration() { return NULL; }
- virtual UnionDeclaration *isUnionDeclaration() { return NULL; }
- virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; }
- virtual ScopeDsymbol *isScopeDsymbol() { return NULL; }
- virtual ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return NULL; }
- virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; }
- virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
- virtual Import *isImport() { return NULL; }
- virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
- virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; }
- virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
- virtual AnonDeclaration *isAnonDeclaration() { return NULL; }
- virtual CPPNamespaceDeclaration *isCPPNamespaceDeclaration() { return NULL; }
- virtual VisibilityDeclaration *isVisibilityDeclaration() { return NULL; }
- virtual OverloadSet *isOverloadSet() { return NULL; }
- virtual MixinDeclaration *isMixinDeclaration() { return NULL; }
- virtual StaticAssert *isStaticAssert() { return NULL; }
- virtual StaticIfDeclaration *isStaticIfDeclaration() { return NULL; }
- virtual CAsmDeclaration *isCAsmDeclaration() { return NULL; }
+ Package *isPackage();
+ Module *isModule();
+ EnumMember *isEnumMember();
+ TemplateDeclaration *isTemplateDeclaration();
+ TemplateInstance *isTemplateInstance();
+ TemplateMixin *isTemplateMixin();
+ ForwardingAttribDeclaration *isForwardingAttribDeclaration();
+ Nspace *isNspace();
+ Declaration *isDeclaration();
+ StorageClassDeclaration *isStorageClassDeclaration();
+ ExpressionDsymbol *isExpressionDsymbol();
+ AliasAssign *isAliasAssign();
+ ThisDeclaration *isThisDeclaration();
+ BitFieldDeclaration *isBitFieldDeclaration();
+ TypeInfoDeclaration *isTypeInfoDeclaration();
+ TupleDeclaration *isTupleDeclaration();
+ AliasDeclaration *isAliasDeclaration();
+ AggregateDeclaration *isAggregateDeclaration();
+ FuncDeclaration *isFuncDeclaration();
+ FuncAliasDeclaration *isFuncAliasDeclaration();
+ OverDeclaration *isOverDeclaration();
+ FuncLiteralDeclaration *isFuncLiteralDeclaration();
+ CtorDeclaration *isCtorDeclaration();
+ PostBlitDeclaration *isPostBlitDeclaration();
+ DtorDeclaration *isDtorDeclaration();
+ StaticCtorDeclaration *isStaticCtorDeclaration();
+ StaticDtorDeclaration *isStaticDtorDeclaration();
+ SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration();
+ SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration();
+ InvariantDeclaration *isInvariantDeclaration();
+ UnitTestDeclaration *isUnitTestDeclaration();
+ NewDeclaration *isNewDeclaration();
+ VarDeclaration *isVarDeclaration();
+ VersionSymbol *isVersionSymbol();
+ DebugSymbol *isDebugSymbol();
+ ClassDeclaration *isClassDeclaration();
+ StructDeclaration *isStructDeclaration();
+ UnionDeclaration *isUnionDeclaration();
+ InterfaceDeclaration *isInterfaceDeclaration();
+ ScopeDsymbol *isScopeDsymbol();
+ ForwardingScopeDsymbol *isForwardingScopeDsymbol();
+ WithScopeSymbol *isWithScopeSymbol();
+ ArrayScopeSymbol *isArrayScopeSymbol();
+ Import *isImport();
+ EnumDeclaration *isEnumDeclaration();
+ SymbolDeclaration *isSymbolDeclaration();
+ AttribDeclaration *isAttribDeclaration();
+ AnonDeclaration *isAnonDeclaration();
+ CPPNamespaceDeclaration *isCPPNamespaceDeclaration();
+ VisibilityDeclaration *isVisibilityDeclaration();
+ OverloadSet *isOverloadSet();
+ MixinDeclaration *isMixinDeclaration();
+ StaticAssert *isStaticAssert();
+ StaticIfDeclaration *isStaticIfDeclaration();
+ CAsmDeclaration *isCAsmDeclaration();
void accept(Visitor *v) override { v->visit(this); }
};
@@ -346,13 +332,11 @@ public:
virtual void importScope(Dsymbol *s, Visibility visibility);
virtual bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
bool isforwardRef() override final;
- static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2);
+ static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2);
const char *kind() const override;
virtual Dsymbol *symtabInsert(Dsymbol *s);
virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
- bool hasStaticCtorOrDtor() override;
- ScopeDsymbol *isScopeDsymbol() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -364,7 +348,6 @@ public:
WithStatement *withstate;
- WithScopeSymbol *isWithScopeSymbol() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -375,7 +358,6 @@ class ArrayScopeSymbol final : public ScopeDsymbol
public:
RootObject *arrayContent;
- ArrayScopeSymbol *isArrayScopeSymbol() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -387,7 +369,6 @@ public:
Dsymbols a; // array of Dsymbols
void push(Dsymbol *s);
- OverloadSet *isOverloadSet() override { return this; }
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -402,7 +383,6 @@ public:
void importScope(Dsymbol *s, Visibility visibility) override;
const char *kind() const override;
- ForwardingScopeDsymbol *isForwardingScopeDsymbol() override { return this; }
};
class ExpressionDsymbol final : public Dsymbol
@@ -410,7 +390,6 @@ class ExpressionDsymbol final : public Dsymbol
public:
Expression *exp;
- ExpressionDsymbol *isExpressionDsymbol() override { return this; }
};
class CAsmDeclaration final : public Dsymbol
@@ -418,7 +397,6 @@ class CAsmDeclaration final : public Dsymbol
public:
Expression *code; // string expression
- CAsmDeclaration *isCAsmDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -446,7 +424,11 @@ public:
namespace dmd
{
void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
- Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
+ Dsymbol *search(Dsymbol *d, Loc loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
+ Dsymbols *include(Dsymbol *d, Scope *sc);
void setScope(Dsymbol *d, Scope *sc);
void importAll(Dsymbol *d, Scope *sc);
+ void addComment(Dsymbol *d, const char *comment);
+ bool oneMember(Dsymbol *d, Dsymbol *&ps, Identifier *ident);
+ bool hasStaticCtorOrDtor(Dsymbol *d);
}
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index b13f98a..acbac7a 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -2,12 +2,12 @@
* Does the semantic 1 pass on the AST, which looks at symbol declarations but not initializers
* or function bodies.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d, _dsymbolsem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d, _dsymbolsem.d)
* Documentation: https://dlang.org/phobos/dmd_dsymbolsem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbolsem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dsymbolsem.d
*/
module dmd.dsymbolsem;
@@ -21,12 +21,15 @@ import dmd.arraytypes;
import dmd.astcodegen;
import dmd.astenums;
import dmd.attrib;
+import dmd.attribsem;
import dmd.clone;
import dmd.cond;
+import dmd.timetrace;
import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
import dmd.denum;
+import dmd.deps;
import dmd.dimport;
import dmd.dinterpret;
import dmd.dmodule;
@@ -50,6 +53,7 @@ import dmd.init;
import dmd.initsem;
import dmd.intrange;
import dmd.hdrgen;
+import dmd.lexer;
import dmd.location;
import dmd.mtype;
import dmd.mustuse;
@@ -58,11 +62,14 @@ import dmd.objc;
import dmd.opover;
import dmd.optimize;
import dmd.parse;
+debug import dmd.printast;
import dmd.root.array;
import dmd.root.filename;
+import dmd.root.string;
import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.rootobject;
+import dmd.safe;
import dmd.semantic2;
import dmd.semantic3;
import dmd.sideeffect;
@@ -126,10 +133,10 @@ AlignDeclaration getAlignment(AlignDeclaration ad, Scope* sc)
else
{
auto n = e.toInteger();
- if (sc.flags & SCOPE.Cfile && n == 0) // C11 6.7.5-6 allows 0 for alignment
+ if (sc.inCfile && n == 0) // C11 6.7.5-6 allows 0 for alignment
continue;
- if (n < 1 || n & (n - 1) || ushort.max < n || !e.type.isintegral())
+ if (n < 1 || n & (n - 1) || ushort.max < n || !e.type.isIntegral())
{
error(ad.loc, "alignment must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
errors = true;
@@ -167,7 +174,7 @@ const(char)* getMessage(DeprecatedDeclaration dd)
return dd.msgstr;
}
-bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc)
+bool checkDeprecated(Dsymbol d, Loc loc, Scope* sc)
{
if (global.params.useDeprecated == DiagnosticReporting.off)
return false;
@@ -178,7 +185,7 @@ bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc)
return false;
// Don't complain if we're inside a template constraint
// https://issues.dlang.org/show_bug.cgi?id=21831
- if (sc.flags & SCOPE.constraint)
+ if (sc.inTemplateConstraint)
return false;
const(char)* message = null;
@@ -204,7 +211,7 @@ bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc)
/*********************************
* Check type to see if it is based on a deprecated symbol.
*/
-private void checkDeprecated(Type type, const ref Loc loc, Scope* sc)
+private void checkDeprecated(Type type, Loc loc, Scope* sc)
{
if (Dsymbol s = type.toDsymbol(sc))
{
@@ -238,38 +245,58 @@ package bool allowsContractWithoutBody(FuncDeclaration funcdecl)
}
/*
-Tests whether the `ctor` that is part of `ti` is an rvalue constructor
-(i.e. a constructor that receives a single parameter of the same type as
-`Unqual!typeof(this)`). If that is the case and `sd` contains a copy
-constructor, than an error is issued.
+If sd has a copy constructor and ctor is an rvalue constructor,
+issue an error.
Params:
- sd = struct declaration that may contin both an rvalue and copy constructor
- ctor = constructor that will be checked if it is an evalue constructor
+ sd = struct declaration that may contain both an rvalue and copy constructor
+ ctor = constructor that will be checked if it is an rvalue constructor
ti = template instance the ctor is part of
Return:
- `false` if ctor is not an rvalue constructor or if `sd` does not contain a
- copy constructor. `true` otherwise
+ `true` if sd has a copy constructor and ctor is an rvalue constructor
*/
bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, TemplateInstance ti)
{
- auto loc = ctor.loc;
- auto tf = cast(TypeFunction)ctor.type;
- auto dim = tf.parameterList.length;
- if (sd && sd.hasCopyCtor && (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)))
+ //printf("checkHasBothRvalueAndCpCtor() sd: %s ctor: %s ti: %s\n", sd.toChars(), ctor.toChars(), ti.toChars());
+ /* cannot use ctor.isMoveCtor because semantic pass may not have been run yet,
+ * so use isRvalueConstructor()
+ */
+ if (sd && sd.hasCopyCtor && isRvalueConstructor(sd, ctor))
+ {
+ .error(ctor.loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars());
+ .errorSupplemental(ti.loc, "Template instance `%s` creates an rvalue constructor for `struct %s`",
+ ti.toPrettyChars(), sd.toChars());
+
+ return true;
+ }
+
+ return false;
+}
+
+/************************************************
+ * Check if ctor is an rvalue constructor.
+ * A constructor that receives a single parameter of the same type as
+ * `Unqual!typeof(this)` is an rvalue constructor.
+ * Params:
+ * sd = struct that ctor is a member of
+ * ctor = constructor to test
+ * Returns:
+ * true if it is an rvalue constructor
+ */
+bool isRvalueConstructor(StructDeclaration sd, CtorDeclaration ctor)
+{
+ // note commonality with setting isMoveCtor in the semantic code for CtorDeclaration
+ auto tf = ctor.type.isTypeFunction();
+ const dim = tf.parameterList.length;
+ if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))
{
auto param = tf.parameterList[0];
if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
{
- .error(loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars());
- .errorSupplemental(ti.loc, "Template instance `%s` creates an rvalue constructor for `struct %s`",
- ti.toPrettyChars(), sd.toChars());
-
return true;
}
}
-
return false;
}
@@ -286,6 +313,7 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem
*/
Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
{
+ //printf("resolveAliasThis() %s\n", toChars(e));
import dmd.typesem : dotExp;
for (AggregateDeclaration ad = isAggregate(e.type); ad;)
{
@@ -294,7 +322,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
Loc loc = e.loc;
Type tthis = (e.op == EXP.type ? e.type : null);
const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag));
- uint olderrors = gag ? global.startGagging() : 0;
+ const olderrors = gag ? global.startGagging() : 0;
e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags);
if (!e || findOnly)
return gag && global.endGagging(olderrors) ? null : e;
@@ -368,7 +396,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
* Returns:
* Whether the alias this was reported as deprecated.
*/
-private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
+private bool checkDeprecatedAliasThis(AliasThis at, Loc loc, Scope* sc)
{
if (global.params.useDeprecated != DiagnosticReporting.off
&& at.isDeprecated() && !sc.isDeprecated())
@@ -396,7 +424,7 @@ private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc
}
// Save the scope and defer semantic analysis on the Dsymbol.
-void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope *scx)
+void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope* scx)
{
s._scope = scx ? scx : sc.copy();
s._scope.setNoFree();
@@ -595,12 +623,31 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
if (dsym.storage_class & STC.extern_ && dsym._init)
- .error(dsym.loc, "%s `%s` extern symbols cannot have initializers", dsym.kind, dsym.toPrettyChars);
+ {
+ if (sc.inCfile)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=24447
+ // extern int x = 3; is allowed in C
+ dsym.storage_class &= ~STC.extern_;
+ }
+ else
+ .error(dsym.loc, "%s `%s` extern symbols cannot have initializers", dsym.kind, dsym.toPrettyChars);
+
+ }
AggregateDeclaration ad = dsym.isThis();
if (ad)
dsym.storage_class |= ad.storage_class & STC.TYPECTOR;
+ if ((dsym.storage_class & STC.auto_) && (dsym.storage_class & STC.ref_))
+ {
+ if (!(dsym.storage_class & STC.autoref))
+ {
+ .error(dsym.loc, "%s `%s` - `auto ref` variable must have `auto` and `ref` adjacent", dsym.kind, dsym.toChars());
+ dsym.storage_class |= STC.autoref;
+ }
+ }
+
/* If auto type inference, do the inference
*/
int inferred = 0;
@@ -613,12 +660,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
bool needctfe = (dsym.storage_class & (STC.manifest | STC.static_)) != 0 || !sc.func;
if (needctfe)
{
- sc.flags |= SCOPE.condition;
+ sc.condition = true;
sc = sc.startCTFE();
}
//printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars());
dsym._init = dsym._init.inferType(sc);
- dsym.type = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0).type;
+ dsym.type = dsym._init.initializerToExpression(null, sc.inCfile).type;
if (needctfe)
sc = sc.endCTFE();
@@ -670,7 +717,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// Calculate type size + safety checks
if (dsym.storage_class & STC.gshared && !dsym.isMember())
{
- sc.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared");
+ sc.setUnsafe(false, dsym.loc, "using `__gshared` instead of `shared`");
}
Dsymbol parent = dsym.toParent();
@@ -718,7 +765,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
dsym.type = Type.terror;
}
}
- if ((dsym.storage_class & STC.auto_) && !inferred)
+ if ((dsym.storage_class & STC.auto_) && !inferred && !(dsym.storage_class & STC.autoref))
.error(dsym.loc, "%s `%s` - storage class `auto` has no effect if type is not inferred, did you mean `scope`?", dsym.kind, dsym.toPrettyChars);
if (auto tt = tb.isTypeTuple())
@@ -727,7 +774,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
* and add those.
*/
size_t nelems = Parameter.dim(tt.arguments);
- Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0) : null;
+ Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, sc.inCfile) : null;
if (ie)
ie = ie.expressionSemantic(sc);
if (nelems > 0 && ie)
@@ -765,7 +812,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
else if (isAliasThisTuple(e))
{
- auto v = copyToTemp(0, "__tup", e);
+ auto v = copyToTemp(STC.none, "__tup", e);
v.dsymbolSemantic(sc);
auto ve = new VarExp(dsym.loc, v);
ve.type = e.type;
@@ -849,7 +896,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
else
ti = dsym._init ? dsym._init.syntaxCopy() : null;
- StorageClass storage_class = STC.temp | dsym.storage_class;
+ STC storage_class = STC.temp | dsym.storage_class;
if ((dsym.storage_class & STC.parameter) && (arg.storageClass & STC.parameter))
storage_class |= arg.storageClass;
auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class);
@@ -888,7 +935,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
else if (dsym.type.isWild())
dsym.storage_class |= STC.wild;
- if (StorageClass stc = dsym.storage_class & (STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_))
+ if (STC stc = dsym.storage_class & (STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_))
{
if (stc == STC.final_)
.error(dsym.loc, "%s `%s` cannot be `final`, perhaps you meant `const`?", dsym.kind, dsym.toPrettyChars);
@@ -908,7 +955,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (dsym.storage_class & STC.scope_)
{
- StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.gshared);
+ STC stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.gshared);
if (stc)
{
OutBuffer buf;
@@ -977,7 +1024,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
// If it's a member template
AggregateDeclaration ad2 = ti.tempdecl.isMember();
- if (ad2 && dsym.storage_class != STC.undefined_)
+ if (ad2 && dsym.storage_class != STC.none)
{
.error(dsym.loc, "%s `%s` - cannot use template to add field to aggregate `%s`", dsym.kind, dsym.toPrettyChars, ad2.toChars());
}
@@ -1000,9 +1047,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
- if ((dsym.storage_class & (STC.ref_ | STC.parameter | STC.foreach_ | STC.temp | STC.result)) == STC.ref_ && dsym.ident != Id.This)
+ if ((dsym.storage_class & (STC.ref_ | STC.field)) == (STC.ref_ | STC.field) && dsym.ident != Id.This)
{
- .error(dsym.loc, "%s `%s` - only parameters, functions and `foreach` declarations can be `ref`", dsym.kind, dsym.toPrettyChars);
+ .error(dsym.loc, "%s `%s` - field declarations cannot be `ref`", dsym.kind, dsym.toPrettyChars);
}
if (dsym.type.hasWild())
@@ -1051,8 +1098,27 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
+ bool dsymIsRef = (dsym.storage_class & (STC.ref_ | STC.field | STC.parameter | STC.temp | STC.foreach_)) == STC.ref_;
+ if (dsymIsRef)
+ {
+ if (!dsym._init && dsym.ident != Id.This)
+ {
+ if (dsym.storage_class & STC.autoref)
+ {
+ dsymIsRef = false;
+ dsym.storage_class &= ~STC.ref_;
+ }
+ else
+ .error(dsym.loc, "%s `%s` - initializer is required for `ref` variable", dsym.kind, dsym.toPrettyChars);
+ }
+ else if (dsym._init.isVoidInitializer())
+ {
+ .error(dsym.loc, "%s `%s` - void initializer not allowed for `ref` variable", dsym.kind, dsym.toPrettyChars);
+ }
+ }
+
FuncDeclaration fd = parent.isFuncDeclaration();
- if (dsym.type.isscope() && !(dsym.storage_class & STC.nodtor))
+ if (dsym.type.isScopeClass() && !(dsym.storage_class & STC.nodtor))
{
if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.gshared) || !fd)
{
@@ -1072,24 +1138,30 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// Calculate type size + safety checks
if (sc && sc.func)
{
- if (dsym._init && dsym._init.isVoidInitializer())
+ if (dsym._init && dsym._init.isVoidInitializer() && !(dsym.storage_class & STC.temp))
{
+ // Don't do these checks for STC.temp vars because the generated `opAssign`
+ // for a struct with postblit and destructor void initializes a temporary
+ // __swap variable, which can be trusted
if (dsym.type.hasPointers()) // also computes type size
sc.setUnsafe(false, dsym.loc,
- "`void` initializers for pointers not allowed in safe functions");
+ "`void` initializing a pointer");
else if (dsym.type.hasInvariant())
sc.setUnsafe(false, dsym.loc,
- "`void` initializers for structs with invariants are not allowed in safe functions");
- else if (dsym.type.hasSystemFields())
+ "`void` initializing a struct with an invariant");
+ else if (dsym.type.toBasetype().ty == Tbool)
+ sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
+ "void intializing a bool (which must always be 0 or 1)");
+ else if (dsym.type.hasUnsafeBitpatterns())
sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
- "`void` initializers for `@system` variables not allowed in safe functions");
+ "`void` initializing a type with unsafe bit patterns");
}
else if (!dsym._init &&
!(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
dsym.type.hasVoidInitPointers())
{
- sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions");
+ sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers");
}
}
@@ -1115,7 +1187,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
bool isBlit = false;
uinteger_t sz;
- if (sc.flags & SCOPE.Cfile && !dsym._init)
+ if (sc.inCfile && !dsym._init)
{
addDefaultCInitializer(dsym);
}
@@ -1180,7 +1252,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc = sc.push();
sc.stc &= ~(STC.TYPECTOR | STC.pure_ | STC.nothrow_ | STC.nogc | STC.ref_ | STC.disable);
- if (sc.flags & SCOPE.Cfile &&
+ if (sc.inCfile &&
dsym.type.isTypeSArray() &&
dsym.type.isTypeSArray().isIncomplete() &&
dsym._init.isVoidInitializer() &&
@@ -1210,12 +1282,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (ai && tb.ty == Taarray)
e = ai.toAssocArrayLiteral();
else
- e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
+ e = dsym._init.initializerToExpression(null, sc.inCfile);
if (!e)
{
// Run semantic, but don't need to interpret
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret);
- e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
+ e = dsym._init.initializerToExpression(null, sc.inCfile);
if (!e)
{
.error(dsym.loc, "%s `%s` is not a static and cannot have static initializer", dsym.kind, dsym.toPrettyChars);
@@ -1225,7 +1297,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ei = new ExpInitializer(dsym._init.loc, e);
dsym._init = ei;
}
- else if (sc.flags & SCOPE.Cfile && dsym.type.isTypeSArray() &&
+ else if (sc.inCfile && dsym.type.isTypeSArray() &&
dsym.type.isTypeSArray().isIncomplete())
{
// C11 6.7.9-22 determine the size of the incomplete array,
@@ -1240,9 +1312,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ex = (cast(AssignExp)ex).e2;
if (auto ne = ex.isNewExp())
{
+ if (ne.placement)
+ {
+ }
/* See if initializer is a NewExp that can be allocated on the stack.
*/
- if (dsym.type.toBasetype().ty == Tclass)
+ else if (dsym.type.toBasetype().ty == Tclass)
{
/* Unsafe to allocate on stack if constructor is not `scope` because the `this` can leak.
* https://issues.dlang.org/show_bug.cgi?id=23145
@@ -1251,7 +1326,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
import dmd.escape : setUnsafeDIP1000;
const inSafeFunc = sc.func && sc.func.isSafeBypassingInference(); // isSafeBypassingInference may call setUnsafe().
- if (sc.setUnsafeDIP1000(false, dsym.loc, "`scope` allocation of `%s` requires that constructor be annotated with `scope`", dsym))
+ if (setUnsafeDIP1000(*sc, false, dsym.loc, "`scope` allocation of `%s` with a non-`scope` constructor", dsym))
errorSupplemental(ne.member.loc, "is the location of the constructor");
}
ne.onstack = 1;
@@ -1276,21 +1351,67 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
Expression exp = ei.exp;
Expression e1 = new VarExp(dsym.loc, dsym);
- if (isBlit)
- exp = new BlitExp(dsym.loc, e1, exp);
+
+ void constructInit(bool isBlit)
+ {
+ if (isBlit)
+ exp = new BlitExp(dsym.loc, e1, exp);
+ else
+ exp = new ConstructExp(dsym.loc, e1, exp);
+ dsym.canassign++;
+ exp = exp.expressionSemantic(sc);
+ dsym.canassign--;
+ }
+
+ if (dsymIsRef) // follow logic similar to typesem.argumentMatchParameter() and statementsem.visitForeach()
+ {
+ dsym.storage_class |= STC.nodtor;
+ exp = exp.expressionSemantic(sc);
+ Type tp = dsym.type;
+ Type ta = exp.type;
+ if (!exp.isLvalue())
+ {
+ if (dsym.storage_class & STC.autoref)
+ {
+ dsym.storage_class &= ~STC.ref_;
+ constructInit(isBlit);
+ }
+ else
+ {
+ .error(dsym.loc, "rvalue `%s` cannot be assigned to `ref %s`", exp.toChars(), dsym.toChars());
+ exp = ErrorExp.get();
+ }
+ }
+ else if (!ta.constConv(tp))
+ {
+ if (dsym.storage_class & STC.autoref)
+ {
+ dsym.storage_class &= ~STC.ref_;
+ constructInit(false);
+ }
+ else
+ {
+ .error(dsym.loc, "type `%s` cannot be assigned to `ref %s %s`", ta.toChars(), tp.toChars(), dsym.toChars());
+ exp = ErrorExp.get();
+ }
+ }
+ else
+ {
+ constructInit(false);
+ }
+ }
else
- exp = new ConstructExp(dsym.loc, e1, exp);
- dsym.canassign++;
- exp = exp.expressionSemantic(sc);
- dsym.canassign--;
- exp = exp.optimize(WANTvalue);
+ {
+ constructInit(isBlit);
+ }
+
if (exp.op == EXP.error)
{
dsym._init = new ErrorInitializer();
ei = null;
}
else
- ei.exp = exp;
+ ei.exp = exp.optimize(WANTvalue);
}
else
{
@@ -1314,7 +1435,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
else if (dsym.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
dsym.type.isConst() || dsym.type.isImmutable() ||
- sc.flags & SCOPE.Cfile)
+ sc.inCfile)
{
/* Because we may need the results of a const declaration in a
* subsequent type, such as an array dimension, before semantic2()
@@ -1325,7 +1446,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
*/
if (!inferred)
{
- uint errors = global.errors;
+ const errors = global.errors;
dsym.inuse++;
// Bug 20549. Don't try this on modules or packages, syntaxCopy
// could crash (inf. recursion) on a mod/pkg referencing itself
@@ -1459,7 +1580,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (dsym.errors)
return;
- if (!(global.params.bitfields || sc.flags & SCOPE.Cfile))
+ if (!(sc.previews.bitfields || sc.inCfile))
{
version (IN_GCC)
.error(dsym.loc, "%s `%s` use `-fpreview=bitfields` for bitfield support", dsym.kind, dsym.toPrettyChars);
@@ -1476,7 +1597,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
auto width = dsym.width.expressionSemantic(sc);
sc = sc.endCTFE();
width = width.ctfeInterpret();
- if (!dsym.type.isintegral())
+ 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());
@@ -1507,6 +1628,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(Import imp)
{
+ timeTraceBeginEvent(TimeTraceEventType.sema1Import);
+ scope (exit) timeTraceEndEvent(TimeTraceEventType.sema1Import, imp);
static if (LOG)
{
printf("Import::semantic('%s') %s\n", imp.toPrettyChars(), imp.id.toChars());
@@ -1547,156 +1670,91 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
imp.mod.checkImportDeprecation(imp.loc, sc);
}
}
- if (imp.mod)
+ if (!imp.mod)
{
- // Modules need a list of each imported module
-
- // if inside a template instantiation, the instantianting
- // module gets the import.
- // https://issues.dlang.org/show_bug.cgi?id=17181
- Module importer = sc._module;
- if (sc.minst && sc.tinst)
- {
- importer = sc.minst;
- if (!sc.tinst.importedModules.contains(imp.mod))
- sc.tinst.importedModules.push(imp.mod);
- }
- //printf("%s imports %s\n", importer.toChars(), imp.mod.toChars());
- if (!importer.aimports.contains(imp.mod))
- importer.aimports.push(imp.mod);
-
- if (sc.explicitVisibility)
- imp.visibility = sc.visibility;
-
- if (!imp.aliasId && !imp.names.length) // neither a selective nor a renamed import
- {
- ScopeDsymbol scopesym = sc.getScopesym();
+ imp.semanticRun = PASS.semanticdone;
+ addImportDep(global.params.moduleDeps, imp, sc._module);
+ }
- if (!imp.isstatic)
- {
- scopesym.importScope(imp.mod, imp.visibility);
- }
+ // Modules need a list of each imported module
+ // if inside a template instantiation, the instantianting
+ // module gets the import.
+ // https://issues.dlang.org/show_bug.cgi?id=17181
+ Module importer = sc._module;
+ if (sc.minst && sc.tinst)
+ {
+ importer = sc.minst;
+ if (!sc.tinst.importedModules.contains(imp.mod))
+ sc.tinst.importedModules.push(imp.mod);
+ }
+ //printf("%s imports %s\n", importer.toChars(), imp.mod.toChars());
+ if (!importer.aimports.contains(imp.mod))
+ importer.aimports.push(imp.mod);
- imp.addPackageAccess(scopesym);
- }
+ if (sc.explicitVisibility)
+ imp.visibility = sc.visibility;
- // if a module has errors it means that parsing has failed.
- if (!imp.mod.errors)
- imp.mod.dsymbolSemantic(null);
+ if (!imp.aliasId && !imp.names.length) // neither a selective nor a renamed import
+ {
+ ScopeDsymbol scopesym = sc.getScopesym();
- if (imp.mod.needmoduleinfo)
+ if (!imp.isstatic)
{
- //printf("module4 %s because of %s\n", importer.toChars(), imp.mod.toChars());
- importer.needmoduleinfo = 1;
+ scopesym.importScope(imp.mod, imp.visibility);
}
- sc = sc.push(imp.mod);
- sc.visibility = imp.visibility;
- for (size_t i = 0; i < imp.aliasdecls.length; i++)
- {
- AliasDeclaration ad = imp.aliasdecls[i];
- //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope);
- Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], SearchOpt.ignorePrivateImports);
- if (sym)
- {
- import dmd.access : symbolIsVisible;
- if (!symbolIsVisible(sc, sym) && !sym.errors)
- {
- .error(imp.loc, "%s `%s` member `%s` is not visible from module `%s`", imp.mod.kind, imp.mod.toPrettyChars,
- imp.names[i].toChars(), sc._module.toChars());
- sym.errors = true;
- }
- ad.dsymbolSemantic(sc);
- // If the import declaration is in non-root module,
- // analysis of the aliased symbol is deferred.
- // Therefore, don't see the ad.aliassym or ad.type here.
- }
- else
- {
- Dsymbol s = imp.mod.search_correct(imp.names[i]);
- // https://issues.dlang.org/show_bug.cgi?id=23908
- // Don't suggest symbols from the importer's module
- if (s && s.parent != importer)
- .error(imp.loc, "%s `%s` import `%s` not found, did you mean %s `%s`?", imp.mod.kind, imp.mod.toPrettyChars, imp.names[i].toChars(), s.kind(), s.toPrettyChars());
- else
- .error(imp.loc, "%s `%s` import `%s` not found", imp.mod.kind, imp.mod.toPrettyChars, imp.names[i].toChars());
- ad.type = Type.terror;
- }
- }
- sc = sc.pop();
+
+ imp.addPackageAccess(scopesym);
}
- imp.semanticRun = PASS.semanticdone;
+ // if a module has errors it means that parsing has failed.
+ if (!imp.mod.errors)
+ imp.mod.dsymbolSemantic(null);
- // object self-imports itself, so skip that
- // https://issues.dlang.org/show_bug.cgi?id=7547
- // don't list pseudo modules __entrypoint.d, __main.d
- // https://issues.dlang.org/show_bug.cgi?id=11117
- // https://issues.dlang.org/show_bug.cgi?id=11164
- if (global.params.moduleDeps.buffer is null || (imp.id == Id.object && sc._module.ident == Id.object) ||
- strcmp(sc._module.ident.toChars(), "__main") == 0)
- return;
+ if (imp.mod.needmoduleinfo)
+ {
+ //printf("module4 %s because of %s\n", importer.toChars(), imp.mod.toChars());
+ importer.needmoduleinfo = 1;
+ }
- /* The grammar of the file is:
- * ImportDeclaration
- * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
- * ModuleAliasIdentifier ] "\n"
- *
- * BasicImportDeclaration
- * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
- * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
- *
- * FilePath
- * - any string with '(', ')' and '\' escaped with the '\' character
- */
- OutBuffer* ob = global.params.moduleDeps.buffer;
- Module imod = sc._module;
- if (!global.params.moduleDeps.name)
- ob.writestring("depsImport ");
- ob.writestring(imod.toPrettyChars());
- ob.writestring(" (");
- escapePath(ob, imod.srcfile.toChars());
- ob.writestring(") : ");
- // use visibility instead of sc.visibility because it couldn't be
- // resolved yet, see the comment above
- visibilityToBuffer(*ob, imp.visibility);
- ob.writeByte(' ');
- if (imp.isstatic)
- {
- stcToBuffer(*ob, STC.static_);
- ob.writeByte(' ');
- }
- ob.writestring(": ");
- foreach (pid; imp.packages)
- {
- ob.printf("%s.", pid.toChars());
- }
- ob.writestring(imp.id.toString());
- ob.writestring(" (");
- if (imp.mod)
- escapePath(ob, imp.mod.srcfile.toChars());
- else
- ob.writestring("???");
- ob.writeByte(')');
- foreach (i, name; imp.names)
+ sc = sc.push(imp.mod);
+ sc.visibility = imp.visibility;
+ for (size_t i = 0; i < imp.aliasdecls.length; i++)
{
- if (i == 0)
- ob.writeByte(':');
- else
- ob.writeByte(',');
- Identifier _alias = imp.aliases[i];
- if (!_alias)
+ AliasDeclaration ad = imp.aliasdecls[i];
+ //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope);
+ Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], SearchOpt.ignorePrivateImports);
+ if (sym)
{
- ob.printf("%s", name.toChars());
- _alias = name;
+ import dmd.access : symbolIsVisible;
+ if (!symbolIsVisible(sc, sym) && !sym.errors)
+ {
+ .error(imp.loc, "%s `%s` member `%s` is not visible from module `%s`", imp.mod.kind, imp.mod.toPrettyChars,
+ imp.names[i].toChars(), sc._module.toChars());
+ sym.errors = true;
+ }
+ ad.dsymbolSemantic(sc);
+ // If the import declaration is in non-root module,
+ // analysis of the aliased symbol is deferred.
+ // Therefore, don't see the ad.aliassym or ad.type here.
}
else
- ob.printf("%s=%s", _alias.toChars(), name.toChars());
+ {
+ Dsymbol s = imp.mod.search_correct(imp.names[i]);
+ // https://issues.dlang.org/show_bug.cgi?id=23908
+ // Don't suggest symbols from the importer's module
+ if (s && s.parent != importer)
+ .error(imp.loc, "%s `%s` import `%s` not found, did you mean %s `%s`?", imp.mod.kind, imp.mod.toPrettyChars, imp.names[i].toChars(), s.kind(), s.toPrettyChars());
+ else
+ .error(imp.loc, "%s `%s` import `%s` not found", imp.mod.kind, imp.mod.toPrettyChars, imp.names[i].toChars());
+ ad.type = Type.terror;
+ }
}
- if (imp.aliasId)
- ob.printf(" -> %s", imp.aliasId.toChars());
- ob.writenl();
+ sc = sc.pop();
+
+ imp.semanticRun = PASS.semanticdone;
+ addImportDep(global.params.moduleDeps, imp, sc._module);
}
void attribSemantic(AttribDeclaration ad)
@@ -1706,20 +1764,25 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ad.semanticRun = PASS.semantic;
Dsymbols* d = ad.include(sc);
//printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
- if (d)
+ if (!d)
{
- Scope* sc2 = ad.newScope(sc);
- bool errors;
- for (size_t i = 0; i < d.length; i++)
- {
- Dsymbol s = (*d)[i];
- s.dsymbolSemantic(sc2);
- errors |= s.errors;
- }
- ad.errors |= errors;
- if (sc2 != sc)
- sc2.pop();
+ ad.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ Scope* sc2 = ad.newScope(sc);
+ bool errors;
+ for (size_t i = 0; i < d.length; i++)
+ {
+ Dsymbol s = (*d)[i];
+ s.dsymbolSemantic(sc2);
+ errors |= s.errors;
}
+ if (errors)
+ ad.errors = true;
+ if (sc2 != sc)
+ sc2.pop();
+
ad.semanticRun = PASS.semanticdone;
}
@@ -1747,7 +1810,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc = sc.push();
sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.gshared);
sc.inunion = scd.isunion ? scd : null;
- sc.flags = 0;
+ sc.resetAllFlags();
for (size_t i = 0; i < scd.decl.length; i++)
{
Dsymbol s = (*scd.decl)[i];
@@ -1781,7 +1844,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
//printf("MixinDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars());
OutBuffer buf;
- if (expressionsToString(buf, sc, cd.exps))
+ if (expressionsToString(buf, sc, cd.exps, cd.loc, null, true))
return null;
const errors = global.errors;
@@ -1789,9 +1852,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
const bool doUnittests = global.params.parsingUnittestsRequired();
- auto loc = adjustLocForMixin(str, cd.loc, global.params.mixinOut);
- scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
- p.transitionIn = global.params.v.vin;
+ scope p = new Parser!ASTCodegen(sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
+ adjustLocForMixin(str, cd.loc, *p.baseLoc, global.params.mixinOut);
+ p.linnum = p.baseLoc.startLine;
p.nextToken();
auto d = p.parseDeclDefs(0);
@@ -1837,8 +1900,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
const sident = se.toStringz();
if (!sident.length || !Identifier.isValidIdentifier(sident))
{
- error(ns.exp.loc, "expected valid identifier for C++ namespace but got `%.*s`",
- cast(int)sident.length, sident.ptr);
+ error(ns.exp.loc, "expected valid identifier for C++ namespace but got `%s`", se.toErrMsg());
return null;
}
else
@@ -1904,6 +1966,25 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
if (sa.semanticRun < PASS.semanticdone)
sa.semanticRun = PASS.semanticdone;
+ else
+ return;
+
+ // https://issues.dlang.org/show_bug.cgi?id=24645
+ // This is a short-circuit. Usually, static assert conditions are evaluated
+ // in semantic2, but it's not uncommon to use this pattern:
+ // ---
+ // version(X)
+ // {}
+ // else
+ // static assert(false, "unsupported platform");
+ // ---
+ // However, without this short-circuit, the static assert error may get drowned
+ // out by subsequent semantic1 (import) errors. Only short-circuit at module scope though,
+ // inside mixin templates you want an instantiation trace (which you don't get here).
+ if (sc.parent && sc.parent.isModule())
+ if (auto i = sa.exp.isIntegerExp())
+ if (i.toInteger() == 0)
+ staticAssertFail(sa, sc);
}
override void visit(DebugSymbol ds)
@@ -1929,6 +2010,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
if (m.semanticRun != PASS.initial)
return;
+
+ timeTraceBeginEvent(TimeTraceEventType.sema1Module);
+ scope (exit) timeTraceEndEvent(TimeTraceEventType.sema1Module, m);
+
//printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
m.semanticRun = PASS.semantic;
// Note that modules get their own scope, from scratch.
@@ -2141,7 +2226,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
tm.argsym.parent = scy.parent;
Scope* argscope = scy.push(tm.argsym);
- uint errorsave = global.errors;
+ const errorsave = global.errors;
// Declare each template parameter as an alias for the argument type
tm.declareParameters(argscope);
@@ -2286,7 +2371,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ns.semanticRun = PASS.semantic;
ns.parent = sc.parent;
// Link does not matter here, if the UDA is present it will error
- UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
+ checkGNUABITag(ns, LINK.cpp);
if (!ns.members)
{
@@ -2326,7 +2411,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(CtorDeclaration ctd)
{
- //printf("CtorDeclaration::semantic() %s\n", toChars());
+ //printf("CtorDeclaration::semantic() %p %s\n", ctd, ctd.toChars());
if (ctd.semanticRun >= PASS.semanticdone)
return;
if (ctd._scope)
@@ -2359,6 +2444,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc.stc &= ~STC.static_; // not a static constructor
funcDeclarationSemantic(sc, ctd);
+ // Check short constructor: this() => expr;
+ if (ctd.fbody)
+ {
+ if (auto s = ctd.fbody.isExpStatement())
+ {
+ if (s.exp)
+ {
+ auto ce = s.exp.isCallExp();
+ // check this/super before semantic
+ if (!ce || (!ce.e1.isThisExp() && !ce.e1.isSuperExp()))
+ {
+ s.exp = s.exp.expressionSemantic(sc);
+ if (s.exp.type.ty != Tvoid)
+ error(s.loc, "can only return void expression, `this` call or `super` call from constructor");
+ }
+ }
+ }
+ }
sc.pop();
@@ -2409,12 +2512,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
else if ((dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)))
{
- //printf("tf: %s\n", tf.toChars());
+ //printf("tf: %s\n", toChars(tf));
auto param = tf.parameterList[0];
- if (param.storageClass & STC.ref_ && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
+ if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
{
- //printf("copy constructor\n");
- ctd.isCpCtor = true;
+ //printf("copy constructor %p\n", ctd);
+ assert(!ctd.isCpCtor && !ctd.isMoveCtor);
+ if (param.storageClass & STC.ref_)
+ ctd.isCpCtor = true; // copy constructor
+ else
+ ctd.isMoveCtor = true; // move constructor
+ assert(!(ctd.isCpCtor && ctd.isMoveCtor));
}
}
}
@@ -2528,50 +2636,53 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc.pop();
}
- override void visit(StaticCtorDeclaration scd)
+ void visitStaticCDtorDeclaration(FuncDeclaration sd, bool isDestructor)
{
- //printf("StaticCtorDeclaration::semantic()\n");
- if (scd.semanticRun >= PASS.semanticdone)
+ if (sd.semanticRun >= PASS.semanticdone)
return;
- if (scd._scope)
+ if (sd._scope)
{
- sc = scd._scope;
- scd._scope = null;
+ sc = sd._scope;
+ sd._scope = null;
}
-
- scd.parent = sc.parent;
- Dsymbol p = scd.parent.pastMixin();
+ sd.parent = sc.parent;
+ Dsymbol p = sd.parent.pastMixin();
+ const bool isShared = !!(sd.isSharedStaticDtorDeclaration() || sd.isSharedStaticCtorDeclaration());
+ const(char)* what = isDestructor ? "destructor" : "constructor";
if (!p.isScopeDsymbol())
{
- const(char)* s = (scd.isSharedStaticCtorDeclaration() ? "shared " : "");
- error(scd.loc, "`%sstatic` constructor can only be member of module/aggregate/template, not %s `%s`", s, p.kind(), p.toChars());
- scd.type = Type.terror;
- scd.errors = true;
+ const(char)* s = isShared ? "shared " : "";
+ error(sd.loc, "`%sstatic` %s can only be member of module/aggregate/template, not %s `%s`", s, what, p.kind(), p.toChars());
+ sd.type = Type.terror;
+ sd.errors = true;
return;
}
- if (!scd.type)
- scd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, scd.storage_class);
- /* If the static ctor appears within a template instantiation,
+ if (!sd.type)
+ sd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, sd.storage_class);
+
+ /* If the static [dc]tor appears within a template instantiation,
* it could get called multiple times by the module constructors
* for different modules. Thus, protect it with a gate.
*/
- if (scd.isInstantiated() && scd.semanticRun < PASS.semantic)
+ if (sd.isInstantiated() && sd.semanticRun < PASS.semantic)
{
/* Add this prefix to the constructor:
* ```
* static int gate;
- * if (++gate != 1) return;
+ * if ([--|++]gate != [0|1]) return; // dependant on ctor/dtor
* ```
* or, for shared constructor:
* ```
* shared int gate;
- * if (core.atomic.atomicOp!"+="(gate, 1) != 1) return;
+ * enum op = isDestructor ? "-=" : "+=";
+ * enum cmp = isDestructor ? 0 : 1;
+ * if (core.atomic.atomicOp!op(gate, 1) != cmp) return;
* ```
*/
- const bool isShared = !!scd.isSharedStaticCtorDeclaration();
+
auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null);
- v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : 0);
+ v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : STC.none);
auto sa = new Statements();
Statement s = new ExpStatement(Loc.initial, v);
@@ -2580,49 +2691,56 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
Expression e;
if (isShared)
{
- e = doAtomicOp("+=", v.ident, IntegerExp.literal!(1));
+ e = doAtomicOp(isDestructor ? "-=" : "+=", v.ident, IntegerExp.literal!(1));
if (e is null)
{
- .error(scd.loc, "%s `%s` shared static constructor within a template require `core.atomic : atomicOp` to be present", scd.kind, scd.toPrettyChars);
+ .error(sd.loc, "%s `%s` shared static %s within a template require `core.atomic : atomicOp` to be present", sd.kind, sd.toPrettyChars, what);
return;
}
}
else
{
+ IntegerExp one = isDestructor ? IntegerExp.literal!(-1) : IntegerExp.literal!(1);
e = new AddAssignExp(
- Loc.initial, new IdentifierExp(Loc.initial, v.ident), IntegerExp.literal!1);
+ Loc.initial, new IdentifierExp(Loc.initial, v.ident), one);
}
-
- e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!1);
+ IntegerExp cmp = isDestructor ? IntegerExp.literal!0 : IntegerExp.literal!1;
+ e = new EqualExp(EXP.notEqual, Loc.initial, e, cmp);
s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
sa.push(s);
- if (scd.fbody)
- sa.push(scd.fbody);
+ if (sd.fbody)
+ sa.push(sd.fbody);
- scd.fbody = new CompoundStatement(Loc.initial, sa);
+ sd.fbody = new CompoundStatement(Loc.initial, sa);
+ if (isDestructor)
+ (cast(StaticDtorDeclaration)sd).vgate = v;
}
-
const LINK save = sc.linkage;
if (save != LINK.d)
{
- const(char)* s = (scd.isSharedStaticCtorDeclaration() ? "shared " : "");
- deprecation(scd.loc, "`%sstatic` constructor can only be of D linkage", s);
+ const(char)* s = isShared ? "shared " : "";
+ deprecation(sd.loc, "`%sstatic` %s can only be of D linkage", s, what);
// Just correct it
sc.linkage = LINK.d;
}
- funcDeclarationSemantic(sc, scd);
+ funcDeclarationSemantic(sc, sd);
sc.linkage = save;
// We're going to need ModuleInfo
- Module m = scd.getModule();
+ Module m = sd.getModule();
if (!m)
m = sc._module;
if (m)
{
m.needmoduleinfo = 1;
- //printf("module1 %s needs moduleinfo\n", m.toChars());
+ //printf("module2 %s needs moduleinfo\n", m.toChars());
}
+ }
+ override void visit(StaticCtorDeclaration scd)
+ {
+ //printf("StaticCtorDeclaration::semantic()\n");
+ visitStaticCDtorDeclaration(scd, false);
foreachUda(scd, sc, (Expression e) {
import dmd.attrib : isEnumAttribute;
@@ -2645,100 +2763,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(StaticDtorDeclaration sdd)
{
- if (sdd.semanticRun >= PASS.semanticdone)
- return;
- if (sdd._scope)
- {
- sc = sdd._scope;
- sdd._scope = null;
- }
-
- sdd.parent = sc.parent;
- Dsymbol p = sdd.parent.pastMixin();
- if (!p.isScopeDsymbol())
- {
- const(char)* s = (sdd.isSharedStaticDtorDeclaration() ? "shared " : "");
- error(sdd.loc, "`%sstatic` destructor can only be member of module/aggregate/template, not %s `%s`", s, p.kind(), p.toChars());
- sdd.type = Type.terror;
- sdd.errors = true;
- return;
- }
- if (!sdd.type)
- sdd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, sdd.storage_class);
-
- /* If the static ctor appears within a template instantiation,
- * it could get called multiple times by the module constructors
- * for different modules. Thus, protect it with a gate.
- */
- if (sdd.isInstantiated() && sdd.semanticRun < PASS.semantic)
- {
- /* Add this prefix to the constructor:
- * ```
- * static int gate;
- * if (--gate != 0) return;
- * ```
- * or, for shared constructor:
- * ```
- * shared int gate;
- * if (core.atomic.atomicOp!"-="(gate, 1) != 0) return;
- * ```
- */
- const bool isShared = !!sdd.isSharedStaticDtorDeclaration();
- auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null);
- v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : 0);
-
- auto sa = new Statements();
- Statement s = new ExpStatement(Loc.initial, v);
- sa.push(s);
-
- Expression e;
- if (isShared)
- {
- e = doAtomicOp("-=", v.ident, IntegerExp.literal!(1));
- if (e is null)
- {
- .error(sdd.loc, "%s `%s` shared static destructo within a template require `core.atomic : atomicOp` to be present", sdd.kind, sdd.toPrettyChars);
- return;
- }
- }
- else
- {
- e = new AddAssignExp(
- Loc.initial, new IdentifierExp(Loc.initial, v.ident), IntegerExp.literal!(-1));
- }
-
- e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!0);
- s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
-
- sa.push(s);
- if (sdd.fbody)
- sa.push(sdd.fbody);
-
- sdd.fbody = new CompoundStatement(Loc.initial, sa);
-
- sdd.vgate = v;
- }
-
- const LINK save = sc.linkage;
- if (save != LINK.d)
- {
- const(char)* s = (sdd.isSharedStaticDtorDeclaration() ? "shared " : "");
- deprecation(sdd.loc, "`%sstatic` destructor can only be of D linkage", s);
- // Just correct it
- sc.linkage = LINK.d;
- }
- funcDeclarationSemantic(sc, sdd);
- sc.linkage = save;
-
- // We're going to need ModuleInfo
- Module m = sdd.getModule();
- if (!m)
- m = sc._module;
- if (m)
- {
- m.needmoduleinfo = 1;
- //printf("module2 %s needs moduleinfo\n", m.toChars());
- }
+ visitStaticCDtorDeclaration(sdd, true);
}
override void visit(InvariantDeclaration invd)
@@ -2775,7 +2800,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc = sc.push();
sc.stc &= ~STC.static_; // not a static invariant
sc.stc |= STC.const_; // invariant() is always const
- sc.flags = (sc.flags & ~SCOPE.contract) | SCOPE.invariant_;
+ sc.contract = Contract.invariant_;
sc.linkage = LINK.d;
funcDeclarationSemantic(sc, invd);
@@ -2852,7 +2877,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (sd.semanticRun >= PASS.semanticdone)
return;
- int errors = global.errors;
+ const errors = global.errors;
//printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
Scope* scx = null;
@@ -2919,7 +2944,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
return;
sd.semanticRun = PASS.semantic;
- UserAttributeDeclaration.checkGNUABITag(sd, sc.linkage);
+ checkGNUABITag(sd, sc.linkage);
if (!sd.members) // if opaque declaration
{
@@ -2941,7 +2966,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
*/
sd.members.foreachDsymbol( s => s.setScope(sc2) );
sd.members.foreachDsymbol( s => s.importAll(sc2) );
- sd.members.foreachDsymbol( (s) { s.dsymbolSemantic(sc2); sd.errors |= s.errors; } );
+ sd.members.foreachDsymbol( (s) { s.dsymbolSemantic(sc2); if (sd.errors) s.errors = true; } );
if (sd.errors)
sd.type = Type.terror;
@@ -2988,13 +3013,42 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
buildDtors(sd, sc2);
- sd.hasCopyCtor = buildCopyCtor(sd, sc2);
+ bool hasCopyCtor;
+ bool hasMoveCtor;
+ bool needCopyCtor;
+ bool needMoveCtor;
+ needCopyOrMoveCtor(sd, hasCopyCtor, hasMoveCtor, needCopyCtor, needMoveCtor);
+ //printf("%s hasCopy %d hasMove %d needCopy %d needMove %d\n", sd.toChars(), hasCopyCtor, hasMoveCtor, needCopyCtor, needMoveCtor);
+
+ /* When generating a move ctor, generate a copy ctor too, otherwise
+ * https://github.com/s-ludwig/taggedalgebraic/issues/75
+ */
+ if (0 && needMoveCtor && !hasCopyCtor)
+ {
+ needCopyCtor = true;
+ }
+
+ if (needCopyCtor)
+ {
+ assert(hasCopyCtor == false);
+ buildCopyOrMoveCtor(sd, sc2, false); // build copy constructor
+ hasCopyCtor = true;
+ }
+ if (needMoveCtor)
+ {
+ assert(hasMoveCtor == false);
+ buildCopyOrMoveCtor(sd, sc2, true); // build move constructor
+ hasMoveCtor = true;
+ }
+ sd.hasCopyCtor = hasCopyCtor;
+ sd.hasMoveCtor = hasMoveCtor;
+
sd.postblit = buildPostBlit(sd, sc2);
buildOpAssign(sd, sc2);
buildOpEquals(sd, sc2);
- if (!(sc2.flags & SCOPE.Cfile) &&
+ if (!sc2.inCfile &&
global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo
{
sd.xeq = buildXopEquals(sd, sc2);
@@ -3011,10 +3065,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (sd.ctor)
{
- Dsymbol scall = sd.search(Loc.initial, Id.call);
+ Dsymbol scall = sd.search(Loc.initial, Id.opCall);
if (scall)
{
- uint xerrors = global.startGagging();
+ const xerrors = global.startGagging();
sc = sc.push();
sc.tinst = null;
sc.minst = null;
@@ -3099,7 +3153,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (cldec.semanticRun >= PASS.semanticdone)
return;
- int errors = global.errors;
+ const errors = global.errors;
//printf("+ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
@@ -3159,7 +3213,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
return;
}
cldec.semanticRun = PASS.semantic;
- UserAttributeDeclaration.checkGNUABITag(cldec, sc.linkage);
+ checkGNUABITag(cldec, sc.linkage);
checkMustUseReserved(cldec);
if (cldec.baseok < Baseok.done)
@@ -3379,8 +3433,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
void badObjectDotD()
{
- .error(cldec.loc, "%s `%s` missing or corrupt object.d", cldec.kind, cldec.toPrettyChars);
- fatal();
+ ObjectNotFound(cldec.loc, cldec.ident);
}
if (!cldec.object || cldec.object.errors)
@@ -3634,7 +3687,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// This is required if other lowerings add code to the generated constructor which
// is less strict (e.g. `preview=dtorfields` might introduce a call to a less qualified dtor)
- auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf);
+ auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, STC.none, tf);
ctor.storage_class |= STC.inference | (fd.storage_class & STC.scope_);
ctor.isGenerated = true;
ctor.fbody = new CompoundStatement(Loc.initial, new Statements());
@@ -3763,7 +3816,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
//printf("InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);
if (idec.semanticRun >= PASS.semanticdone)
return;
- int errors = global.errors;
+ const errors = global.errors;
//printf("+InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);
@@ -3872,7 +3925,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (!idec.baseclasses.length && sc.linkage == LINK.cpp)
idec.classKind = ClassKind.cpp;
idec.cppnamespace = sc.namespace;
- UserAttributeDeclaration.checkGNUABITag(idec, sc.linkage);
+ checkGNUABITag(idec, sc.linkage);
checkMustUseReserved(idec);
if (sc.linkage == LINK.objc)
@@ -4093,7 +4146,7 @@ private extern(C++) class AddMemberVisitor : Visitor
Scope* sc;
ScopeDsymbol sds;
- this(Scope* sc, ScopeDsymbol sds)
+ this(Scope* sc, ScopeDsymbol sds) @safe
{
this.sc = sc;
this.sds = sds;
@@ -4131,7 +4184,8 @@ private extern(C++) class AddMemberVisitor : Visitor
}
// If using C tag/prototype/forward declaration rules
- if (sc.flags & SCOPE.Cfile && !dsym.isImport())
+ if (sc && sc.inCfile && !dsym.isImport())
+ // When merging master, replace with: if (sc && sc.inCfile && !dsym.isImport())
{
if (handleTagSymbols(*sc, dsym, s2, sds))
return;
@@ -4152,7 +4206,7 @@ private extern(C++) class AddMemberVisitor : Visitor
if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
{
if (dsym.ident == Id.__sizeof ||
- !(sc && sc.flags & SCOPE.Cfile) && (dsym.ident == Id.__xalignof || dsym.ident == Id._mangleof))
+ !(sc && sc.inCfile) && (dsym.ident == Id.__xalignof || dsym.ident == Id._mangleof))
{
.error(dsym.loc, "%s `%s` `.%s` property cannot be redefined", dsym.kind, dsym.toPrettyChars, dsym.ident.toChars());
dsym.errors = true;
@@ -4303,34 +4357,21 @@ private extern(C++) class AddMemberVisitor : Visitor
Module m = sds.isModule();
// Do not add the member to the symbol table,
// just make sure subsequent debug declarations work.
- if (ds.ident)
+ if (!m)
{
- if (!m)
- {
- .error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars);
- ds.errors = true;
- }
- else
- {
- if (m.debugidsNot && findCondition(*m.debugidsNot, ds.ident))
- {
- .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars);
- ds.errors = true;
- }
- if (!m.debugids)
- m.debugids = new Identifiers();
- m.debugids.push(ds.ident);
- }
+ .error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars);
+ ds.errors = true;
}
else
{
- if (!m)
+ if (m.debugidsNot && findCondition(*m.debugidsNot, ds.ident))
{
- .error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars);
+ .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars);
ds.errors = true;
}
- else
- m.debuglevel = ds.level;
+ if (!m.debugids)
+ m.debugids = new Identifiers();
+ m.debugids.push(ds.ident);
}
}
@@ -4340,36 +4381,24 @@ private extern(C++) class AddMemberVisitor : Visitor
Module m = sds.isModule();
// Do not add the member to the symbol table,
// just make sure subsequent debug declarations work.
- if (vs.ident)
+ VersionCondition.checkReserved(vs.loc, vs.ident.toString());
+ if (!m)
{
- VersionCondition.checkReserved(vs.loc, vs.ident.toString());
- if (!m)
- {
- .error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars);
- vs.errors = true;
- }
- else
- {
- if (m.versionidsNot && findCondition(*m.versionidsNot, vs.ident))
- {
- .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars);
- vs.errors = true;
- }
- if (!m.versionids)
- m.versionids = new Identifiers();
- m.versionids.push(vs.ident);
- }
+ .error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars);
+ vs.errors = true;
}
else
{
- if (!m)
+ if (m.versionidsNot && findCondition(*m.versionidsNot, vs.ident))
{
- .error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars);
+ .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars);
vs.errors = true;
}
- else
- m.versionlevel = vs.level;
+ if (!m.versionids)
+ m.versionids = new Identifiers();
+ m.versionids.push(vs.ident);
}
+
}
override void visit(Nspace ns)
@@ -4428,7 +4457,7 @@ private extern(C++) class AddMemberVisitor : Visitor
*/
void addEnumMembersToSymtab(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds)
{
- const bool isCEnum = (sc.flags & SCOPE.Cfile) != 0; // it's an ImportC enum
+ const bool isCEnum = sc.inCfile; // it's an ImportC enum
//printf("addEnumMembersToSymtab(ed: %s added: %d Cfile: %d)\n", ed.toChars(), ed.added, isCEnum);
if (ed.added)
return;
@@ -4459,6 +4488,8 @@ void addEnumMembersToSymtab(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds)
* the enum members to both symbol tables.
*/
em.addMember(sc, ed); // add em to ed's symbol table
+ if (em.errors)
+ return;
em.addMember(sc, sds); // add em to symbol table that ed is in
em.parent = ed; // restore it after previous addMember() changed it
}
@@ -4724,6 +4755,15 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
visit(cast(Dsymbol)sds);
}
+ override void visit(StructDeclaration sd)
+ {
+ // need to visit auto-generated methods as well
+ if (sd.xeq) visit(sd.xeq);
+ if (sd.xcmp) visit(sd.xcmp);
+ if (sd.xhash) visit(sd.xhash);
+ visit(cast(ScopeDsymbol)sd);
+ }
+
override void visit(AttribDeclaration ad)
{
ad.include(null).foreachDsymbol( s => s.accept(this) );
@@ -4771,7 +4811,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
printf("\timplement template instance %s '%s'\n", tempdecl.parent.toChars(), tempinst.toChars());
printf("\ttempdecl %s\n", tempdecl.toChars());
}
- uint errorsave = global.errors;
+ const errorsave = global.errors;
tempinst.inst = tempinst;
tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent;
@@ -4799,7 +4839,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
continue;
Type t = isType((*tempinst.tiargs)[i]);
assert(t);
- if (StorageClass stc = ModToStc(t.mod))
+ if (STC stc = ModToStc(t.mod))
{
//printf("t = %s, stc = x%llx\n", t.toChars(), stc);
auto s = new Dsymbols();
@@ -4827,11 +4867,11 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
_scope = _scope.push(tempinst.argsym);
_scope.tinst = tempinst;
_scope.minst = tempinst.minst;
- //scope.stc = 0;
+ //scope.stc = STC.none;
// Declare each template parameter as an alias for the argument type
Scope* paramscope = _scope.push();
- paramscope.stc = 0;
+ paramscope.stc = STC.none;
paramscope.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=14169
// template parameters should be public
tempinst.declareParameters(paramscope);
@@ -4964,7 +5004,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
if (global.errors != errorsave)
goto Laftersemantic;
- if ((sc.func || (sc.flags & SCOPE.fullinst)) && !tempinst.tinst)
+ if ((sc.func || sc.fullinst) && !tempinst.tinst)
{
/* If a template is instantiated inside function, the whole instantiation
* should be done at that position. But, immediate running semantic3 of
@@ -5164,7 +5204,7 @@ void aliasSeqInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDecl
{
//printf("[%s] aliasSeqInstance.dsymbolSemantic('%s')\n", tempinst.loc.toChars(), tempinst.toChars());
Scope* paramscope = sc.push();
- paramscope.stc = 0;
+ paramscope.stc = STC.none;
paramscope.visibility = Visibility(Visibility.Kind.public_);
TemplateTupleParameter ttp = (*tempdecl.parameters)[0].isTemplateTupleParameter();
@@ -5189,7 +5229,7 @@ void aliasInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDeclara
{
//printf("[%s] aliasInstance.dsymbolSemantic('%s')\n", tempinst.loc.toChars(), tempinst.toChars());
Scope* paramscope = sc.push();
- paramscope.stc = 0;
+ paramscope.stc = STC.none;
paramscope.visibility = Visibility(Visibility.Kind.public_);
TemplateTypeParameter ttp = (*tempdecl.parameters)[0].isTemplateTypeParameter();
@@ -5211,7 +5251,7 @@ void aliasInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDeclara
// function used to perform semantic on AliasDeclaration
void aliasSemantic(AliasDeclaration ds, Scope* sc)
{
- //printf("AliasDeclaration::semantic() %s\n", ds.toChars());
+ //printf("AliasDeclaration::semantic() %s %p\n", ds.toChars(), ds.aliassym);
// as DsymbolSemanticVisitor::visit(AliasDeclaration), in case we're called first.
// see https://issues.dlang.org/show_bug.cgi?id=21001
@@ -5295,6 +5335,27 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
// Detect `alias sym = sym;` to prevent creating loops in overload overnext lists.
if (auto tident = ds.type.isTypeIdentifier())
{
+ if (sc.hasEdition(Edition.v2024) && tident.idents.length)
+ {
+ alias mt = tident;
+ Dsymbol pscopesym;
+ Dsymbol s = sc.search(ds.loc, mt.ident, pscopesym);
+ // detect `alias a = var1.member_var;` which confusingly resolves to
+ // `typeof(var1).member_var`, which can be valid inside the aggregate type
+ if (s && s.isVarDeclaration() &&
+ mt.ident != Id.This && mt.ident != Id._super)
+ {
+ s = tident.toDsymbol(sc);
+ // don't error for `var1.static_symbol`
+ if (s && s.needThis())
+ {
+ error(ds.loc, "cannot alias %s member `%s` of variable `%s`",
+ s.kind(), s.toChars(), mt.ident.toChars());
+ errorSupplemental(ds.loc, "Use `typeof(%s)` instead to preserve behaviour",
+ mt.ident.toChars());
+ }
+ }
+ }
// Selective imports are allowed to alias to the same name `import mod : sym=sym`.
if (!ds._import)
{
@@ -5444,7 +5505,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
if (!aliassym)
return errorRet();
- if (aliassym.adFlags & Declaration.wasRead)
+ if (aliassym.wasRead)
{
if (!aliassym.errors)
error(ds.loc, "%s was read, so cannot reassign", aliassym.toChars());
@@ -5452,7 +5513,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
return errorRet();
}
- aliassym.adFlags |= Declaration.ignoreRead; // temporarilly allow reads of aliassym
+ aliassym.ignoreRead = true; // temporarilly allow reads of aliassym
const storage_class = sc.stc & (STC.deprecated_ | STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable);
@@ -5576,8 +5637,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
aliassym.aliassym = null;
}
-
- aliassym.adFlags &= ~Declaration.ignoreRead;
+ aliassym.ignoreRead = false;
if (aliassym.type && aliassym.type.ty == Terror ||
global.gag && errors != global.errors)
@@ -5840,34 +5900,40 @@ private CallExp doAtomicOp (string op, Identifier var, Expression arg)
* Set up loc for a parse of a mixin. Append the input text to the mixin.
* Params:
* input = mixin text
- * loc = location to adjust
+ * loc = location of expansion
+ * baseLoc = location to adjust
* mixinOut = sink for mixin text data
* Returns:
* adjusted loc suitable for Parser
*/
-Loc adjustLocForMixin(const(char)[] input, ref const Loc loc, ref Output mixinOut)
+void adjustLocForMixin(const(char)[] input, Loc loc, ref BaseLoc baseLoc, ref Output mixinOut)
{
- Loc result;
if (mixinOut.doOutput)
{
const lines = mixinOut.bufferLines;
writeMixin(input, loc, mixinOut.bufferLines, *mixinOut.buffer);
- result = Loc(mixinOut.name.ptr, lines + 2, loc.charnum);
+ baseLoc.startLine = lines + 2;
+ baseLoc.filename = mixinOut.name;
+ return;
}
- else if (loc.filename)
+
+ SourceLoc sl = SourceLoc(loc);
+ if (sl.filename.length == 0)
{
- /* Create a pseudo-filename for the mixin string, as it may not even exist
- * in the source file.
- */
- auto len = strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1;
- char* filename = cast(char*)mem.xmalloc(len);
- snprintf(filename, len, "%s-mixin-%d", loc.filename, cast(int)loc.linnum);
- result = Loc(filename, loc.linnum, loc.charnum);
+ // Rare case of compiler-generated mixin exp, e.g. __xtoHash
+ baseLoc.filename = "";
+ return;
}
- else
- result = loc;
- return result;
+
+ /* Create a pseudo-filename for the mixin string, as it may not even exist
+ * in the source file.
+ */
+ auto len = sl.filename.length + 7 + (sl.linnum).sizeof * 3 + 1;
+ char* filename = cast(char*) mem.xmalloc(len);
+ snprintf(filename, len, "%.*s-mixin-%d", cast(int) sl.filename.length, sl.filename.ptr, cast(int) sl.linnum);
+ baseLoc.startLine = sl.line;
+ baseLoc.filename = filename.toDString;
}
/**************************************
@@ -5879,7 +5945,7 @@ Loc adjustLocForMixin(const(char)[] input, ref const Loc loc, ref Output mixinOu
* lines = line count to update
* output = sink for output
*/
-private void writeMixin(const(char)[] s, ref const Loc loc, ref int lines, ref OutBuffer buf)
+private void writeMixin(const(char)[] s, Loc loc, ref int lines, ref OutBuffer buf)
{
buf.writestring("// expansion at ");
buf.writestring(loc.toChars());
@@ -5916,67 +5982,6 @@ private void writeMixin(const(char)[] s, ref const Loc loc, ref int lines, ref O
++lines;
}
-/**
- * Check signature of `pragma(printf)` function, print error if invalid.
- *
- * printf/scanf-like functions must be of the form:
- * extern (C/C++) T printf([parameters...], const(char)* format, ...);
- * or:
- * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
- *
- * Params:
- * funcdecl = function to check
- * f = function type
- * sc = scope
- */
-void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* sc)
-{
- static bool isPointerToChar(Parameter p)
- {
- if (auto tptr = p.type.isTypePointer())
- {
- return tptr.next.ty == Tchar;
- }
- return false;
- }
-
- bool isVa_list(Parameter p)
- {
- return p.type.equals(target.va_listType(funcdecl.loc, sc));
- }
-
- const nparams = f.parameterList.length;
- const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars();
- if (!(f.linkage == LINK.c || f.linkage == LINK.cpp))
- {
- .error(funcdecl.loc, "`pragma(%s)` function `%s` must have `extern(C)` or `extern(C++)` linkage,"
- ~" not `extern(%s)`",
- p, funcdecl.toChars(), f.linkage.linkageToChars());
- }
- if (f.parameterList.varargs == VarArg.variadic)
- {
- if (!(nparams >= 1 && isPointerToChar(f.parameterList[nparams - 1])))
- {
- .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"
- ~ " signature `%s %s([parameters...], const(char)*, ...)` not `%s`",
- p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars());
- }
- }
- else if (f.parameterList.varargs == VarArg.none)
- {
- if(!(nparams >= 2 && isPointerToChar(f.parameterList[nparams - 2]) &&
- isVa_list(f.parameterList[nparams - 1])))
- .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"~
- " signature `%s %s([parameters...], const(char)*, va_list)`",
- p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars());
- }
- else
- {
- .error(funcdecl.loc, "`pragma(%s)` function `%s` must have C-style variadic `...` or `va_list` parameter",
- p, funcdecl.toChars());
- }
-}
-
/*********************************************
* Search for ident as member of d.
* Params:
@@ -5987,7 +5992,7 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope*
* Returns:
* null if not found
*/
-Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all)
+Dsymbol search(Dsymbol d, Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all)
{
scope v = new SearchVisitor(loc, ident, flags);
d.accept(v);
@@ -6034,7 +6039,7 @@ private extern(C++) class SearchVisitor : Visitor
SearchOptFlags flags;
Dsymbol result;
- this(const ref Loc loc, Identifier ident, SearchOptFlags flags)
+ this(Loc loc, Identifier ident, SearchOptFlags flags) @safe
{
this.loc = loc;
this.ident = ident;
@@ -6250,7 +6255,7 @@ private extern(C++) class SearchVisitor : Visitor
VarDeclaration* pvar;
Expression ce;
- static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
+ static Dsymbol dollarFromTypeTuple(Loc loc, TypeTuple tt, Scope* sc)
{
/* $ gives the number of type entries in the type tuple
@@ -6511,7 +6516,7 @@ private extern(C++) class SearchVisitor : Visitor
return setResult(m.searchCacheSymbol);
}
- uint errors = global.errors;
+ const errors = global.errors;
m.insearch = true;
visit(cast(ScopeDsymbol)m);
@@ -6610,7 +6615,7 @@ private extern(C++) class SearchVisitor : Visitor
s = b.sym.search(loc, ident, flags);
if (!s)
continue;
- else if (s == cd) // happens if s is nested in this and derives from this
+ if (s == cd) // happens if s is nested in this and derives from this
s = null;
else if (!(flags & SearchOpt.ignoreVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s))
s = null;
@@ -6640,7 +6645,7 @@ private extern(C++) class SetScopeVisitor : Visitor
alias visit = typeof(super).visit;
Scope* sc;
- this(Scope* sc)
+ this(Scope* sc) @safe
{
this.sc = sc;
}
@@ -6783,7 +6788,7 @@ extern(C++) class ImportAllVisitor : Visitor
alias visit = typeof(super).visit;
Scope* sc;
- this(Scope* sc)
+ this(Scope* sc) @safe
{
this.sc = sc;
}
@@ -6862,7 +6867,7 @@ extern(C++) class ImportAllVisitor : Visitor
(*m.members)[0].ident != Id.object ||
(*m.members)[0].isImport() is null))
{
- auto im = new Import(Loc.initial, null, Id.object, null, 0);
+ auto im = new Import(m.loc, null, Id.object, null, 0);
m.members.shift(im);
}
if (!m.symtab)
@@ -6949,7 +6954,7 @@ extern (D) bool load(Import imp, Scope* sc)
{
if (p.isPkgMod == PKG.unknown)
{
- uint preverrors = global.errors;
+ const preverrors = global.errors;
imp.mod = Module.load(imp.loc, imp.packages, imp.id);
if (!imp.mod)
p.isPkgMod = PKG.package_;
@@ -7026,7 +7031,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
FieldState* fieldState;
bool isunion;
- this(AggregateDeclaration ad, FieldState* fieldState, bool isunion)
+ this(AggregateDeclaration ad, FieldState* fieldState, bool isunion) @safe
{
this.ad = ad;
this.fieldState = fieldState;
@@ -7115,7 +7120,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
assert(sz != SIZE_INVALID && sz < uint.max);
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
- vd.offset = placeField(
+ vd.offset = placeField(vd.loc,
fieldState.offset,
memsize, memalignsize, vd.alignment,
ad.structsize, ad.alignsize,
@@ -7162,12 +7167,19 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth);
const style = target.c.bitFieldStyle;
+ if (style != TargetC.BitFieldStyle.MS && style != TargetC.BitFieldStyle.Gcc_Clang)
+ assert(0, "unsupported bit-field style");
+
+ const isMicrosoftStyle = style == TargetC.BitFieldStyle.MS;
+ const contributesToAggregateAlignment = target.c.contributesToAggregateAlignment(bfd);
void startNewField()
{
if (log) printf("startNewField()\n");
uint alignsize;
- if (style == TargetC.BitFieldStyle.Gcc_Clang)
+ if (isMicrosoftStyle)
+ alignsize = memsize; // not memalignsize
+ else
{
if (bfd.fieldWidth > 32)
alignsize = memalignsize;
@@ -7178,15 +7190,13 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
else
alignsize = 1;
}
- else
- alignsize = memsize; // not memalignsize
uint dummy;
- bfd.offset = placeField(
+ bfd.offset = placeField(bfd.loc,
fieldState.offset,
memsize, alignsize, bfd.alignment,
ad.structsize,
- (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
+ contributesToAggregateAlignment ? ad.alignsize : dummy,
isunion);
fieldState.inFlight = true;
@@ -7195,64 +7205,30 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
fieldState.fieldSize = memsize;
}
- if (style == TargetC.BitFieldStyle.Gcc_Clang)
- {
- if (bfd.fieldWidth == 0)
- {
- if (!isunion)
- {
- // Use type of zero width field to align to next field
- fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
- ad.structsize = fieldState.offset;
- }
-
- fieldState.inFlight = false;
- return;
- }
+ if (ad.alignsize == 0)
+ ad.alignsize = 1;
+ if (!isMicrosoftStyle && contributesToAggregateAlignment && ad.alignsize < memalignsize)
+ ad.alignsize = memalignsize;
- if (ad.alignsize == 0)
- ad.alignsize = 1;
- if (!anon &&
- ad.alignsize < memalignsize)
- ad.alignsize = memalignsize;
- }
- else if (style == TargetC.BitFieldStyle.MS)
+ if (bfd.fieldWidth == 0)
{
- if (ad.alignsize == 0)
- ad.alignsize = 1;
- if (bfd.fieldWidth == 0)
+ if (!isMicrosoftStyle && !isunion)
{
- if (fieldState.inFlight && !isunion)
- {
- // documentation says align to next int
- //const alsz = cast(uint)Type.tint32.size();
- const alsz = memsize; // but it really does this
- fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
- ad.structsize = fieldState.offset;
- }
-
- fieldState.inFlight = false;
- return;
+ // Use type of zero width field to align to next field
+ fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
+ ad.structsize = fieldState.offset;
}
- }
- else if (style == TargetC.BitFieldStyle.DM)
- {
- if (anon && bfd.fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
- return; // this probably should be a bug in DMC
- if (ad.alignsize == 0)
- ad.alignsize = 1;
- if (bfd.fieldWidth == 0)
+ else if (isMicrosoftStyle && fieldState.inFlight && !isunion)
{
- if (fieldState.inFlight && !isunion)
- {
- const alsz = memsize;
- fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
- ad.structsize = fieldState.offset;
- }
-
- fieldState.inFlight = false;
- return;
+ // documentation says align to next int
+ //const alsz = cast(uint)Type.tint32.size();
+ const alsz = memsize; // but it really does this
+ fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+ ad.structsize = fieldState.offset;
}
+
+ fieldState.inFlight = false;
+ return;
}
if (!fieldState.inFlight)
@@ -7260,12 +7236,14 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
//printf("not in flight\n");
startNewField();
}
- else if (style == TargetC.BitFieldStyle.Gcc_Clang)
+ else if (!isMicrosoftStyle)
{
- // If the bit-field spans more units of alignment than its type,
- // start a new field at the next alignment boundary.
- if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
- fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8)
+ // If the bit-field 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.
+ if (fieldState.bitOffset % (memalignsize * 8) == 0 &&
+ fieldState.bitOffset + bfd.fieldWidth > memsize * 8)
{
if (log) printf("more units of alignment than its type\n");
startNewField(); // the bit field is full
@@ -7273,18 +7251,17 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
else
{
// if alignment boundary is crossed
- uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
+ uint start = (fieldState.fieldOffset * 8 + fieldState.bitOffset) % (memalignsize * 8);
uint end = start + bfd.fieldWidth;
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
- if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
+ if (start / (memsize * 8) != (end - 1) / (memsize * 8))
{
if (log) printf("alignment is crossed\n");
startNewField();
}
}
}
- else if (style == TargetC.BitFieldStyle.DM ||
- style == TargetC.BitFieldStyle.MS)
+ else
{
if (memsize != fieldState.fieldSize ||
fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8)
@@ -7293,16 +7270,16 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
startNewField();
}
}
- else
- assert(0);
bfd.offset = fieldState.fieldOffset;
bfd.bitOffset = fieldState.bitOffset;
const pastField = bfd.bitOffset + bfd.fieldWidth;
- if (style == TargetC.BitFieldStyle.Gcc_Clang)
+ if (isMicrosoftStyle)
+ fieldState.fieldSize = memsize;
+ else
{
- auto size = (pastField + 7) / 8;
+ const size = (pastField + 7) / 8;
fieldState.fieldSize = size;
//printf(" offset: %d, size: %d\n", offset, size);
if (isunion)
@@ -7314,8 +7291,6 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
else
ad.structsize = bfd.offset + size;
}
- else
- fieldState.fieldSize = memsize;
//printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
//print(fieldState);
@@ -7402,7 +7377,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
/* Given the anon 'member's size and alignment,
* go ahead and place it.
*/
- anond.anonoffset = placeField(
+ anond.anonoffset = placeField(anond.loc,
fieldState.offset,
anond.anonstructsize, anond.anonalignsize, alignment,
ad.structsize, ad.alignsize,
@@ -7419,3 +7394,819 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
}
}
}
+
+extern(D) Scope* newScope(Dsymbol d, Scope* sc)
+{
+ scope nsv = new NewScopeVisitor(sc);
+ d.accept(nsv);
+ return nsv.sc;
+}
+
+private extern(C++) class NewScopeVisitor : Visitor
+{
+ alias visit = typeof(super).visit;
+ Scope* sc;
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ /****************************************
+ * A hook point to supply scope for members.
+ * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
+ */
+ override void visit(AttribDeclaration dc){}
+
+ override void visit(StorageClassDeclaration swt)
+ {
+ STC scstc = sc.stc;
+ /* These sets of storage classes are mutually exclusive,
+ * so choose the innermost or most recent one.
+ */
+ if (swt.stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
+ scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
+ if (swt.stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared))
+ scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared);
+ if (swt.stc & (STC.const_ | STC.immutable_ | STC.manifest))
+ scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
+ if (swt.stc & (STC.gshared | STC.shared_))
+ scstc &= ~(STC.gshared | STC.shared_);
+ if (swt.stc & (STC.safe | STC.trusted | STC.system))
+ scstc &= ~(STC.safe | STC.trusted | STC.system);
+ scstc |= swt.stc;
+ //printf("scstc = x%llx\n", scstc);
+ sc = swt.createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
+ sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);
+ }
+
+ /**
+ * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
+ *
+ * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
+ * in any function overriding `newScope`), then set the `Scope`'s depdecl.
+ *
+ * Returns:
+ * Always a new scope, to use for this `DeprecatedDeclaration`'s members.
+ */
+ override void visit(DeprecatedDeclaration dpd)
+ {
+ auto oldsc = sc;
+ visit((cast(StorageClassDeclaration)dpd));
+ auto scx = sc;
+ sc = oldsc;
+ // The enclosing scope is deprecated as well
+ if (scx == sc)
+ scx = sc.push();
+ scx.depdecl = dpd;
+ sc = scx;
+ }
+
+ override void visit(LinkDeclaration lid)
+ {
+ sc= lid.createNewScope(sc, sc.stc, lid.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
+ sc.aligndecl, sc.inlining);
+ }
+
+ override void visit(CPPMangleDeclaration cpmd)
+ {
+ sc = cpmd.createNewScope(sc, sc.stc, LINK.cpp, cpmd.cppmangle, sc.visibility, sc.explicitVisibility,
+ sc.aligndecl, sc.inlining);
+ }
+
+ /**
+ * Returns:
+ * A copy of the parent scope, with `this` as `namespace` and C++ linkage
+ *///override Scope* visit(Scope* sc)
+ override void visit(CPPNamespaceDeclaration scd)
+ {
+ auto scx = sc.copy();
+ scx.linkage = LINK.cpp;
+ scx.namespace = scd;
+ sc = scx;
+ }
+
+ override void visit(VisibilityDeclaration atbd)
+ {
+ if (atbd.pkg_identifiers)
+ dsymbolSemantic(atbd, sc);
+
+ sc = atbd.createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, atbd.visibility, 1, sc.aligndecl, sc.inlining);
+ }
+
+ override void visit(AlignDeclaration visd)
+ {
+ sc = visd.createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility,
+ sc.explicitVisibility, visd, sc.inlining);
+ }
+
+ override void visit(PragmaDeclaration prd)
+ {
+ if (prd.ident == Id.Pinline)
+ {
+ // We keep track of this pragma inside scopes,
+ // then it's evaluated on demand in function semantic
+ sc = prd.createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, prd); // @suppress(dscanner.style.long_line)
+ }
+ }
+
+ /**************************************
+ * Use the ForwardingScopeDsymbol as the parent symbol for members.
+ */
+ override void visit(ForwardingAttribDeclaration fad)
+ {
+ sc = sc.push(fad.sym);
+ }
+
+ override void visit(UserAttributeDeclaration uac)
+ {
+ Scope* sc2 = sc;
+ if (uac.atts && uac.atts.length)
+ {
+ // create new one for changes
+ sc2 = sc.copy();
+ sc2.userAttribDecl = uac;
+ }
+ sc = sc2;
+ }
+}
+
+
+extern(C++) Dsymbols* include(Dsymbol d, Scope* sc)
+{
+ scope icv = new IncludeVisitor(sc);
+ d.accept(icv);
+ return icv.symbols;
+}
+
+extern(C++) class IncludeVisitor : Visitor
+{
+ alias visit = typeof(super).visit;
+ Scope* sc;
+ Dsymbols* symbols;
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ override void visit(AttribDeclaration ad)
+ {
+ if (ad.errors)
+ {
+ symbols = null;
+ return;
+ }
+ symbols = ad.decl;
+ return;
+ }
+
+// Decide if 'then' or 'else' code should be included
+ override void visit(ConditionalDeclaration cdc)
+ {
+ //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
+
+ if (cdc.errors)
+ {
+ symbols = null;
+ return;
+ }
+ assert(cdc.condition);
+ symbols = cdc.condition.include(cdc._scope ? cdc._scope : sc) ? cdc.decl : cdc.elsedecl;
+ }
+
+ override void visit(StaticIfDeclaration sif)
+ {
+ /****************************************
+ * Different from other AttribDeclaration subclasses, include() call requires
+ * the completion of addMember and setScope phases.
+ */
+ //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
+ if (sif.errors || sif.onStack)
+ {
+ symbols = null;
+ return;
+ }
+ sif.onStack = true;
+ scope(exit) sif.onStack = false;
+
+ if (sc && sif.condition.inc == Include.notComputed)
+ {
+ assert(sif.scopesym); // addMember is already done
+ assert(sif._scope); // setScope is already done
+
+ Scope* saved_scope = sc;
+ sc = sif._scope;
+ visit(cast(ConditionalDeclaration) sif);
+ Dsymbols* d = symbols;
+ sc = saved_scope;
+
+ if (d && !sif.addisdone)
+ {
+ // Add members lazily.
+ d.foreachDsymbol( s => s.addMember(sif._scope, sif.scopesym) );
+
+ // Set the member scopes lazily.
+ d.foreachDsymbol( s => s.setScope(sif._scope) );
+
+ sif.addisdone = true;
+ }
+ symbols = d;
+ return;
+ }
+ else
+ {
+ visit(cast(ConditionalDeclaration)sif);
+ }
+ }
+
+ override void visit(StaticForeachDeclaration sfd)
+ {
+ if (sfd.errors || sfd.onStack)
+ {
+ symbols = null;
+ return;
+ }
+ if (sfd.cached)
+ {
+ assert(!sfd.onStack);
+ symbols = sfd.cache;
+ return;
+ }
+ sfd.onStack = true;
+ scope(exit) sfd.onStack = false;
+
+ if (sfd._scope)
+ {
+ sfd.sfe.prepare(sfd._scope); // lower static foreach aggregate
+ }
+ if (!sfd.sfe.ready())
+ {
+ symbols = null;// TODO: ok?
+ return;
+ }
+
+ // expand static foreach
+ import dmd.statementsem: makeTupleForeach;
+ Dsymbols* d = makeTupleForeach(sfd._scope, true, true, sfd.sfe.aggrfe, sfd.decl, sfd.sfe.needExpansion).decl;
+ if (d) // process generated declarations
+ {
+ // Add members lazily.
+ d.foreachDsymbol( s => s.addMember(sfd._scope, sfd.scopesym) );
+
+ // Set the member scopes lazily.
+ d.foreachDsymbol( s => s.setScope(sfd._scope) );
+ }
+ sfd.cached = true;
+ sfd.cache = d;
+ symbols = d;
+ }
+}
+
+/**
+ * Called from a symbol's semantic to check if `gnuAbiTag` UDA
+ * can be applied to them
+ *
+ * Directly emits an error if the UDA doesn't work with this symbol
+ *
+ * Params:
+ * sym = symbol to check for `gnuAbiTag`
+ * linkage = Linkage of the symbol (Declaration.link or sc.link)
+ */
+void checkGNUABITag(Dsymbol sym, LINK linkage)
+{
+ if (global.params.cplusplus < CppStdRevision.cpp11)
+ return;
+
+ foreachUdaNoSemantic(sym, (exp) {
+ if (!isGNUABITag(exp))
+ return 0; // continue
+ if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
+ {
+ .error(exp.loc, "`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
+ sym.errors = true;
+ }
+ else if (linkage != LINK.cpp)
+ {
+ .error(exp.loc, "`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
+ sym.errors = true;
+ }
+ // Only one `@gnuAbiTag` is allowed by semantic2
+ return 1; // break
+ });
+}
+
+/**
+ * Check if the provided expression references `core.attribute.gnuAbiTag`
+ *
+ * This should be called after semantic has been run on the expression.
+ * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
+ *
+ * Params:
+ * e = Expression to check (usually from `UserAttributeDeclaration.atts`)
+ *
+ * Returns:
+ * `true` if the expression references the compiler-recognized `gnuAbiTag`
+ */
+bool isGNUABITag(Expression e)
+{
+ if (global.params.cplusplus < CppStdRevision.cpp11)
+ return false;
+
+ auto ts = e.type ? e.type.isTypeStruct() : null;
+ if (!ts)
+ return false;
+ if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
+ return false;
+ // Can only be defined in druntime
+ Module m = ts.sym.parent.isModule();
+ if (!m || !m.isCoreModule(Id.attribute))
+ return false;
+ return true;
+}
+
+/******************************************
+ * If a variable has a scope destructor call, return call for it.
+ * Otherwise, return NULL.
+ */
+private Expression callScopeDtor(VarDeclaration vd, Scope* sc)
+{
+ //printf("VarDeclaration::callScopeDtor() %s\n", toChars());
+
+ // Destruction of STC.field's is handled by buildDtor()
+ if (vd.storage_class & (STC.nodtor | STC.ref_ | STC.out_ | STC.field))
+ {
+ return null;
+ }
+
+ if (vd.iscatchvar)
+ return null; // destructor is built by `void semantic(Catch c, Scope* sc)`, not here
+
+ Expression e = null;
+ // Destructors for structs and arrays of structs
+ Type tv = vd.type.baseElemOf();
+ if (tv.ty == Tstruct)
+ {
+ StructDeclaration sd = (cast(TypeStruct)tv).sym;
+ if (!sd.dtor || sd.errors)
+ return null;
+
+ const sz = vd.type.size();
+ assert(sz != SIZE_INVALID);
+ if (!sz)
+ return null;
+
+ if (vd.type.toBasetype().ty == Tstruct)
+ {
+ // v.__xdtor()
+ e = new VarExp(vd.loc, vd);
+
+ /* This is a hack so we can call destructors on const/immutable objects.
+ * Need to add things like "const ~this()" and "immutable ~this()" to
+ * fix properly.
+ */
+ e.type = e.type.mutableOf();
+
+ // Enable calling destructors on shared objects.
+ // The destructor is always a single, non-overloaded function,
+ // and must serve both shared and non-shared objects.
+ e.type = e.type.unSharedOf;
+
+ e = new DotVarExp(vd.loc, e, sd.dtor, false);
+ e = new CallExp(vd.loc, e);
+ }
+ else
+ {
+ // __ArrayDtor(v[0 .. n])
+ e = new VarExp(vd.loc, vd);
+
+ const sdsz = sd.type.size();
+ assert(sdsz != SIZE_INVALID && sdsz != 0);
+ const n = sz / sdsz;
+ SliceExp se = new SliceExp(vd.loc, e, new IntegerExp(vd.loc, 0, Type.tsize_t),
+ new IntegerExp(vd.loc, n, Type.tsize_t));
+
+ // Prevent redundant bounds check
+ se.upperIsInBounds = true;
+ se.lowerIsLessThanUpper = true;
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ se.type = sd.type.arrayOf();
+
+ e = new CallExp(vd.loc, new IdentifierExp(vd.loc, Id.__ArrayDtor), se);
+ }
+ return e;
+ }
+ // Destructors for classes
+ if (!(vd.storage_class & (STC.auto_ | STC.scope_) && !(vd.storage_class & STC.parameter)))
+ return null;
+
+ for (ClassDeclaration cd = vd.type.isClassHandle(); cd; cd = cd.baseClass)
+ {
+ /* We can do better if there's a way with onstack
+ * classes to determine if there's no way the monitor
+ * could be set.
+ */
+ //if (cd.isInterfaceDeclaration())
+ // error("interface `%s` cannot be scope", cd.toChars());
+
+ if (!vd.onstack) // if any destructors
+ continue;
+ // delete'ing C++ classes crashes (and delete is deprecated anyway)
+ if (cd.classKind == ClassKind.cpp)
+ {
+ // Don't call non-existant dtor
+ if (!cd.dtor)
+ break;
+
+ e = new VarExp(vd.loc, vd);
+ e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances
+ e = new DotVarExp(vd.loc, e, cd.dtor, false);
+ e = new CallExp(vd.loc, e);
+ break;
+ }
+
+ // delete this;
+ Expression ec;
+ ec = new VarExp(vd.loc, vd);
+ e = new DeleteExp(vd.loc, ec, true);
+ break;
+ }
+ return e;
+}
+
+/***************************************
+ * Collect all instance fields, then determine instance size.
+ * Returns:
+ * false if failed to determine the size.
+ */
+bool determineSize(AggregateDeclaration ad, Loc loc)
+{
+ //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
+
+ // The previous instance size finalizing had:
+ if (ad.type.ty == Terror || ad.errors)
+ return false; // failed already
+ if (ad.sizeok == Sizeok.done)
+ return true; // succeeded
+
+ if (!ad.members)
+ {
+ .error(loc, "%s `%s` unknown size", ad.kind, ad.toPrettyChars);
+ return false;
+ }
+
+ if (ad._scope)
+ dsymbolSemantic(ad, null);
+
+ // Determine the instance size of base class first.
+ if (auto cd = ad.isClassDeclaration())
+ {
+ cd = cd.baseClass;
+ if (cd && !cd.determineSize(loc))
+ goto Lfail;
+ }
+
+ // Determine instance fields when sizeok == Sizeok.none
+ if (!ad.determineFields())
+ goto Lfail;
+ if (ad.sizeok != Sizeok.done)
+ ad.finalizeSize();
+
+ // this aggregate type has:
+ if (ad.type.ty == Terror)
+ return false; // marked as invalid during the finalizing.
+ if (ad.sizeok == Sizeok.done)
+ return true; // succeeded to calculate instance size.
+
+Lfail:
+ // There's unresolvable forward reference.
+ if (ad.type != Type.terror)
+ error(loc, "%s `%s` no size because of forward reference", ad.kind, ad.toPrettyChars);
+ // Don't cache errors from speculative semantic, might be resolvable later.
+ // https://issues.dlang.org/show_bug.cgi?id=16574
+ if (!global.gag)
+ {
+ ad.type = Type.terror;
+ ad.errors = true;
+ }
+ return false;
+}
+
+extern (C++) void addComment(Dsymbol d, const(char)* comment)
+{
+ scope v = new AddCommentVisitor(comment);
+ d.accept(v);
+}
+
+extern (C++) class AddCommentVisitor: Visitor
+{
+ alias visit = Visitor.visit;
+
+ const(char)* comment;
+
+ this(const(char)* comment)
+ {
+ this.comment = comment;
+ }
+
+ override void visit(Dsymbol d)
+ {
+ if (!comment || !*comment)
+ return;
+
+ //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
+ void* h = cast(void*)d; // just the pointer is the key
+ auto p = h in d.commentHashTable;
+ if (!p)
+ {
+ d.commentHashTable[h] = comment;
+ return;
+ }
+ if (strcmp(*p, comment) != 0)
+ {
+ // Concatenate the two
+ *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
+ }
+ }
+ override void visit(AttribDeclaration atd)
+ {
+ if (comment)
+ {
+ atd.include(null).foreachDsymbol( s => s.addComment(comment) );
+ }
+ }
+ override void visit(ConditionalDeclaration cd)
+ {
+ if (comment)
+ {
+ cd.decl .foreachDsymbol( s => s.addComment(comment) );
+ cd.elsedecl.foreachDsymbol( s => s.addComment(comment) );
+ }
+ }
+ override void visit(StaticForeachDeclaration sfd) {}
+}
+
+void checkCtorConstInit(Dsymbol d)
+{
+ scope v = new CheckCtorConstInitVisitor();
+ d.accept(v);
+}
+
+private extern(C++) class CheckCtorConstInitVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ override void visit(AttribDeclaration ad)
+ {
+ ad.include(null).foreachDsymbol( s => s.checkCtorConstInit() );
+ }
+
+ override void visit(VarDeclaration vd)
+ {
+ version (none)
+ {
+ /* doesn't work if more than one static ctor */
+ if (vd.ctorinit == 0 && vd.isCtorinit() && !vd.isField())
+ error("missing initializer in static constructor for const variable");
+ }
+ }
+
+ override void visit(Dsymbol d){}
+}
+
+/**************************************
+* Determine if this symbol is only one.
+* Returns:
+* false, ps = null: There are 2 or more symbols
+* true, ps = null: There are zero symbols
+* true, ps = symbol: The one and only one symbol
+*/
+bool oneMember(Dsymbol d, out Dsymbol ps, Identifier ident)
+{
+ scope v = new OneMemberVisitor(ps, ident);
+ d.accept(v);
+ return v.result;
+}
+
+private extern(C++) class OneMemberVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ Dsymbol* ps;
+ Identifier ident;
+ bool result;
+
+ this(out Dsymbol ps, Identifier ident)
+ {
+ this.ps = &ps;
+ this.ident = ident;
+ }
+
+ override void visit(AttribDeclaration atb)
+ {
+ Dsymbols* d = atb.include(null);
+ result = Dsymbol.oneMembers(d, *ps, ident);
+ }
+
+ override void visit(StaticForeachDeclaration sfd)
+ {
+ // Required to support IFTI on a template that contains a
+ // `static foreach` declaration. `super.oneMember` calls
+ // include with a `null` scope. As `static foreach` requires
+ // the scope for expansion, `oneMember` can only return a
+ // precise result once `static foreach` has been expanded.
+ if (sfd.cached)
+ {
+ this.visit(cast(AttribDeclaration) sfd);
+ }
+ else
+ {
+ *ps = null; // a `static foreach` declaration may in general expand to multiple symbols
+ result = false;
+ }
+ }
+
+ override void visit(StorageClassDeclaration scd)
+ {
+ bool t = Dsymbol.oneMembers(scd.decl, *ps, ident);
+ if (t && *ps)
+ {
+ /* This is to deal with the following case:
+ * struct Tick {
+ * template to(T) { const T to() { ... } }
+ * }
+ * For eponymous function templates, the 'const' needs to get attached to 'to'
+ * before the semantic analysis of 'to', so that template overloading based on the
+ * 'this' pointer can be successful.
+ */
+ if (FuncDeclaration fd = (*ps).isFuncDeclaration())
+ {
+ /* Use storage_class2 instead of storage_class otherwise when we do .di generation
+ * we'll wind up with 'const const' rather than 'const'.
+ */
+ /* Don't think we need to worry about mutually exclusive storage classes here
+ */
+ fd.storage_class2 |= scd.stc;
+ }
+ }
+ result = t;
+ }
+
+ override void visit(ConditionalDeclaration cd)
+ {
+ //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
+ if (cd.condition.inc != Include.notComputed)
+ {
+ Dsymbols* d = cd.condition.include(null) ? cd.decl : cd.elsedecl;
+ result = Dsymbol.oneMembers(d, *ps, ident);
+ }
+ else
+ {
+ bool res = (Dsymbol.oneMembers(cd.decl, *ps, ident) && *ps is null && Dsymbol.oneMembers(cd.elsedecl, *ps, ident) && *ps is null);
+ *ps = null;
+ result = res;
+ }
+ }
+
+ override void visit(ScopeDsymbol sd)
+ {
+ if (sd.isAnonymous())
+ result = Dsymbol.oneMembers(sd.members, *ps, ident);
+ else {
+ // visit(Dsymbol dsym)
+ *ps = sd;
+ result = true;
+ }
+ }
+
+ override void visit(StaticAssert sa)
+ {
+ //printf("StaticAssert::oneMember())\n");
+ *ps = null;
+ result = true;
+ }
+
+ override void visit(TemplateInstance ti)
+ {
+ *ps = null;
+ result = true;
+ }
+
+ override void visit(TemplateMixin tm)
+ {
+ *ps = tm;
+ result = true;
+ }
+
+ override void visit(Dsymbol dsym)
+ {
+ *ps = dsym;
+ result = true;
+ }
+}
+
+/****************************************
+* Return true if any of the members are static ctors or static dtors, or if
+* any members have members that are.
+*/
+extern(C++) bool hasStaticCtorOrDtor(Dsymbol d)
+{
+ scope v = new HasStaticCtorOrDtor();
+ d.accept(v);
+ return v.result;
+}
+
+private extern(C++) class HasStaticCtorOrDtor : Visitor
+{
+ import dmd.mtype : Type;
+
+ alias visit = Visitor.visit;
+ bool result;
+
+ // attrib.d
+ override void visit(AttribDeclaration ad){
+ result = ad.include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
+ }
+
+ // dsymbol.d
+ override void visit(Dsymbol d){
+ //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
+ result = false;
+ }
+
+ override void visit(ScopeDsymbol sd) {
+ if (sd.members)
+ {
+ for (size_t i = 0; i < sd.members.length; i++)
+ {
+ Dsymbol member = (*(sd.members))[i];
+ if (member.hasStaticCtorOrDtor())
+ result = true;
+ return;
+ }
+ }
+ result = false;
+ }
+
+ // dtemplate.d
+ override void visit(TemplateDeclaration td) {
+ result = false; // don't scan uninstantiated templates
+ }
+
+ // func.d
+ override void visit(StaticCtorDeclaration scd) {
+ result = true;
+ }
+
+ override void visit(StaticDtorDeclaration sdd) @nogc nothrow pure @safe {
+ result = true;
+ }
+}
+
+extern(C++) bool isFuncHidden(ClassDeclaration cd, FuncDeclaration fd)
+{
+ import dmd.funcsem : overloadApply;
+ //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
+ Dsymbol s = cd.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors);
+ if (!s)
+ {
+ //printf("not found\n");
+ /* Because, due to a hack, if there are multiple definitions
+ * of fd.ident, NULL is returned.
+ */
+ return false;
+ }
+ s = s.toAlias();
+ if (auto os = s.isOverloadSet())
+ {
+ foreach (sm; os.a)
+ {
+ auto fm = sm.isFuncDeclaration();
+ if (overloadApply(fm, s => fd == s.isFuncDeclaration()))
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ auto f = s.isFuncDeclaration();
+ //printf("%s fdstart = %p\n", s.kind(), fdstart);
+ if (overloadApply(f, s => fd == s.isFuncDeclaration()))
+ return false;
+ return !fd.parent.isTemplateMixin();
+ }
+}
+
+Dsymbol vtblSymbol(ClassDeclaration cd)
+{
+ if (!cd.vtblsym)
+ {
+ auto vtype = Type.tvoidptr.immutableOf().sarrayOf(cd.vtbl.length);
+ auto var = new VarDeclaration(cd.loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_);
+ var.addMember(null, cd);
+ var.isdataseg = 1;
+ var._linkage = LINK.d;
+ var.semanticRun = PASS.semanticdone; // no more semantic wanted
+ cd.vtblsym = var;
+ }
+ return cd.vtblsym;
+}
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index d181fac..2158895 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -28,12 +28,12 @@
* arguments, and uses it if found.
* - Otherwise, the rest of semantic is run on the `TemplateInstance`.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dtemplate.d, _dtemplate.d)
* Documentation: https://dlang.org/phobos/dmd_dtemplate.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtemplate.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dtemplate.d
*/
module dmd.dtemplate;
@@ -50,36 +50,36 @@ import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
import dmd.dinterpret;
-import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, checkDeprecated, aliasSemantic, search, search_correct, setScope, importAll, include, hasStaticCtorOrDtor;
import dmd.errors;
import dmd.errorsink;
import dmd.expression;
-import dmd.expressionsem;
+import dmd.expressionsem : resolveLoc, expressionSemantic, resolveProperties, checkValue;
import dmd.func;
-import dmd.funcsem;
+import dmd.funcsem : functionSemantic, leastAsSpecialized, overloadApply;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.impcnvtab;
import dmd.init;
-import dmd.initsem;
import dmd.location;
+import dmd.mangle;
import dmd.mtype;
import dmd.opover;
import dmd.optimize;
import dmd.root.array;
import dmd.common.outbuffer;
import dmd.rootobject;
-import dmd.semantic2;
-import dmd.semantic3;
-import dmd.templatesem;
+import dmd.semantic3 : semantic3;
+import dmd.templatesem : matchWithInstance, formatParamsWithTiargs, leastAsSpecialized, declareParameter;
import dmd.tokens;
-import dmd.typesem;
+import dmd.typesem : hasPointers, typeSemantic, merge, merge2, resolve, toDsymbol,
+ addStorageClass, isBaseOf, equivalent, sarrayOf, constOf, mutableOf, unSharedOf,
+ unqualify, aliasthisOf, castMod, substWildTo, addMod;
import dmd.visitor;
import dmd.templateparamsem;
@@ -89,7 +89,7 @@ private enum LOG = false;
enum IDX_NOTFOUND = 0x12345678;
-pure nothrow @nogc @safe
+pure nothrow @nogc @trusted
{
/********************************************
@@ -136,6 +136,13 @@ inout(Parameter) isParameter(inout RootObject o)
return cast(inout(Parameter))o;
}
+inout(Identifier) isIdentifier(inout RootObject o)
+{
+ if (!o || o.dyncast() != DYNCAST.identifier)
+ return null;
+ return cast(inout(Identifier))o;
+}
+
inout(TemplateParameter) isTemplateParameter(inout RootObject o)
{
if (!o || o.dyncast() != DYNCAST.templateparameter)
@@ -143,6 +150,11 @@ inout(TemplateParameter) isTemplateParameter(inout RootObject o)
return cast(inout(TemplateParameter))o;
}
+} // end @trusted casts
+
+pure nothrow @nogc @safe
+{
+
/**************************************
* Is this Object an error?
*/
@@ -206,23 +218,18 @@ Dsymbol getDsymbol(RootObject oarg)
// Try to convert Expression to symbol
if (auto ve = ea.isVarExp())
return ve.var;
- else if (auto fe = ea.isFuncExp())
+ if (auto fe = ea.isFuncExp())
return fe.td ? fe.td : fe.fd;
- else if (auto te = ea.isTemplateExp())
+ if (auto te = ea.isTemplateExp())
return te.td;
- else if (auto te = ea.isScopeExp())
+ if (auto te = ea.isScopeExp())
return te.sds;
- else
- return null;
- }
- else
- {
- // Try to convert Type to symbol
- if (auto ta = isType(oarg))
- return ta.toDsymbol(null);
- else
- return isDsymbol(oarg); // if already a symbol
+ return null;
}
+ // Try to convert Type to symbol
+ if (auto ta = isType(oarg))
+ return ta.toDsymbol(null);
+ return isDsymbol(oarg); // if already a symbol
}
@@ -282,6 +289,18 @@ private bool match(RootObject o1, RootObject o2)
o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast());
}
+ bool yes()
+ {
+ static if (log)
+ printf("\t. match\n");
+ return true;
+ }
+ bool no()
+ {
+ static if (log)
+ printf("\t. nomatch\n");
+ return false;
+ }
/* A proper implementation of the various equals() overrides
* should make it possible to just do o1.equals(o2), but
* we'll do that another day.
@@ -294,7 +313,7 @@ private bool match(RootObject o1, RootObject o2)
{
auto t2 = isType(o2);
if (!t2)
- goto Lnomatch;
+ return no();
static if (log)
{
@@ -302,15 +321,15 @@ private bool match(RootObject o1, RootObject o2)
printf("\tt2 = %s\n", t2.toChars());
}
if (!t1.equals(t2))
- goto Lnomatch;
+ return no();
- goto Lmatch;
+ return yes();
}
if (auto e1 = getExpression(o1))
{
auto e2 = getExpression(o2);
if (!e2)
- goto Lnomatch;
+ return no();
static if (log)
{
@@ -323,15 +342,15 @@ private bool match(RootObject o1, RootObject o2)
// as well as expression equality to ensure templates are properly
// matched.
if (!(e1.type && e2.type && e1.type.equals(e2.type)) || !e1.equals(e2))
- goto Lnomatch;
+ return no();
- goto Lmatch;
+ return yes();
}
if (auto s1 = isDsymbol(o1))
{
auto s2 = isDsymbol(o2);
if (!s2)
- goto Lnomatch;
+ return no();
static if (log)
{
@@ -339,17 +358,17 @@ private bool match(RootObject o1, RootObject o2)
printf("\ts2 = %s \n", s2.kind(), s2.toChars());
}
if (!s1.equals(s2))
- goto Lnomatch;
+ return no();
if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration())
- goto Lnomatch;
+ return no();
- goto Lmatch;
+ return yes();
}
if (auto u1 = isTuple(o1))
{
auto u2 = isTuple(o2);
if (!u2)
- goto Lnomatch;
+ return no();
static if (log)
{
@@ -357,19 +376,11 @@ private bool match(RootObject o1, RootObject o2)
printf("\tu2 = %s\n", u2.toChars());
}
if (!arrayObjectMatch(u1.objects, u2.objects))
- goto Lnomatch;
+ return no();
- goto Lmatch;
+ return yes();
}
-Lmatch:
- static if (log)
- printf("\t. match\n");
- return true;
-
-Lnomatch:
- static if (log)
- printf("\t. nomatch\n");
- return false;
+ return yes();
}
/************************************
@@ -414,8 +425,7 @@ private size_t arrayObjectHash(ref Objects oa1)
hash = mixHash(hash, expressionHash(e1));
else if (auto s1 = isDsymbol(o1))
{
- auto fa1 = s1.isFuncAliasDeclaration();
- if (fa1)
+ if (auto fa1 = s1.isFuncAliasDeclaration())
s1 = fa1.toAliasFunc();
hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent));
}
@@ -592,9 +602,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
Array!Expression lastConstraintNegs; /// its negative parts
Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint`
- extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false)
+ extern (D) this(Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false)
{
super(loc, ident);
+ this.dsym = DSYM.templateDeclaration;
static if (LOG)
{
printf("TemplateDeclaration(this = %p, id = '%s')\n", this, ident.toChars());
@@ -733,19 +744,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
return true;
}
- override bool hasStaticCtorOrDtor()
- {
- return false; // don't scan uninstantiated templates
- }
-
override const(char)* kind() const
{
return (onemember && onemember.isAggregateDeclaration()) ? onemember.kind() : "template";
}
- override const(char)* toChars() const
+ /****************************
+ * Similar to `toChars`, but does not print the template constraints
+ */
+ const(char)* toCharsNoConstraints() const
{
- HdrGenState hgs;
+ HdrGenState hgs = { skipConstraints: true };
OutBuffer buf;
toCharsMaybeConstraints(this, buf, hgs);
return buf.extractChars();
@@ -877,11 +886,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
instances.remove(tibox);
}
- override inout(TemplateDeclaration) isTemplateDeclaration() inout
- {
- return this;
- }
-
/**
* Check if the last template parameter is a tuple one,
* and returns it if so, else returns `null`.
@@ -891,7 +895,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
*/
extern (D) TemplateTupleParameter isVariadic()
{
- size_t dim = parameters.length;
+ const dim = parameters.length;
if (dim == 0)
return null;
return (*parameters)[dim - 1].isTemplateTupleParameter();
@@ -992,6 +996,11 @@ size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
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)
@@ -999,11 +1008,6 @@ ubyte deduceWildHelper(Type t, Type* at, Type tparam)
*at = null;
- auto X(T, U)(T U, U T)
- {
- return (U << 4) | T;
- }
-
switch (X(tparam.mod, t.mod))
{
case X(MODFlags.wild, 0):
@@ -1078,12 +1082,6 @@ private Type rawTypeMerge(Type t1, Type t2)
MATCH deduceTypeHelper(Type t, out Type at, Type tparam)
{
// 9*9 == 81 cases
-
- auto X(T, U)(T U, U T)
- {
- return (U << 4) | T;
- }
-
switch (X(tparam.mod, t.mod))
{
case X(0, 0):
@@ -1630,60 +1628,66 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa
override void visit(TypeSArray t)
{
// Extra check that array dimensions must match
- if (tparam)
+ if (!tparam)
{
- if (tparam.ty == Tarray)
- {
- MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
- result = (m >= MATCH.constant) ? MATCH.convert : MATCH.nomatch;
- return;
- }
+ visit(cast(Type)t);
+ return;
+ }
- TemplateParameter tp = null;
- Expression edim = null;
- size_t i;
- if (auto tsa = tparam.isTypeSArray())
+ 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())
+ {
+ if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter)
{
- if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter)
- {
- Identifier id = tsa.dim.isVarExp().var.ident;
- i = templateIdentifierLookup(id, &parameters);
- assert(i != IDX_NOTFOUND);
- tp = parameters[i];
- }
- else
- edim = tsa.dim;
+ Identifier id = tsa.dim.isVarExp().var.ident;
+ i = templateIdentifierLookup(id, &parameters);
+ assert(i != IDX_NOTFOUND);
+ tp = parameters[i];
}
- else if (auto taa = tparam.isTypeAArray())
+ else
+ edim = tsa.dim;
+ }
+ else if (auto taa = tparam.isTypeAArray())
+ {
+ i = templateParameterLookup(taa.index, &parameters);
+ if (i != IDX_NOTFOUND)
+ tp = parameters[i];
+ else
{
- i = templateParameterLookup(taa.index, &parameters);
- 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)
{
- 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);
+ 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, &parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
- {
- result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
- return;
- }
}
+ if ((tp && tp.matchArg(sc, t.dim, i, &parameters, dedtypes, null)) ||
+ (edim && edim.isIntegerExp() && edim.toInteger() == t.dim.toInteger())
+ )
+ {
+ result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
+ return;
+ }
+
visit(cast(Type)t);
}
@@ -1708,132 +1712,137 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa
if (!tparam)
return visit(cast(Type)t);
- if (auto tp = tparam.isTypeFunction())
+ auto tp = tparam.isTypeFunction();
+ if (!tp)
{
- if (t.parameterList.varargs != tp.parameterList.varargs || t.linkage != tp.linkage)
- {
- result = MATCH.nomatch;
- return;
- }
+ visit(cast(Type)t);
+ return;
+ }
+
+ if (t.parameterList.varargs != tp.parameterList.varargs || t.linkage != tp.linkage)
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+
+ foreach (fparam; *tp.parameterList.parameters)
+ {
+ // 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;
- foreach (fparam; *tp.parameterList.parameters)
+ // 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]))
{
- // 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]))
+ auto tx = fparam.type.typeSemantic(Loc.initial, sc);
+ if (tx.ty == Terror)
{
- auto tx = fparam.type.typeSemantic(Loc.initial, sc);
- if (tx.ty == Terror)
- {
- result = MATCH.nomatch;
- return;
- }
- fparam.type = tx;
+ result = MATCH.nomatch;
+ return;
}
+ fparam.type = tx;
}
+ }
- const size_t nfargs = t.parameterList.length;
- size_t nfparams = tp.parameterList.length;
+ const size_t nfargs = t.parameterList.length;
+ size_t nfparams = tp.parameterList.length;
- /* See if tuple match
+ /* See if tuple match
+ */
+ if (nfparams > 0 && nfargs >= nfparams - 1)
+ {
+ /* See if 'A' of the template parameter matches 'A'
+ * of the type of the last function parameter.
*/
- if (nfparams > 0 && nfargs >= nfparams - 1)
+ 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++)
{
- /* 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)
+ if (tupi == parameters.length)
goto L1;
+ TemplateParameter tx = parameters[tupi];
+ TemplateTupleParameter tup = tx.isTemplateTupleParameter();
+ if (tup && tup.ident.equals(tid.ident))
+ break;
+ }
- /* Look through parameters to find tuple matching tid.ident
- */
- size_t tupi = 0;
- for (; 1; tupi++)
+ /* 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)
+ {
+ // Existing deduced argument must be a tuple, and must match
+ Tuple tup = isTuple(o);
+ if (!tup || tup.objects.length != tuple_dim)
{
- if (tupi == parameters.length)
- goto L1;
- TemplateParameter tx = parameters[tupi];
- TemplateTupleParameter tup = tx.isTemplateTupleParameter();
- if (tup && tup.ident.equals(tid.ident))
- break;
+ result = MATCH.nomatch;
+ return;
}
-
- /* 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)
+ for (size_t i = 0; i < tuple_dim; i++)
{
- // Existing deduced argument must be a tuple, and must match
- Tuple tup = isTuple(o);
- if (!tup || tup.objects.length != tuple_dim)
+ Parameter arg = t.parameterList[nfparams - 1 + i];
+ if (!arg.type.equals(tup.objects[i]))
{
result = MATCH.nomatch;
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
+ }
+ else
+ {
+ // Create new tuple
+ auto tup = new Tuple(tuple_dim);
+ for (size_t i = 0; i < tuple_dim; i++)
{
- // 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;
+ Parameter arg = t.parameterList[nfparams - 1 + i];
+ tup.objects[i] = arg.type;
}
- nfparams--; // don't consider the last parameter for type deduction
- goto L2;
+ dedtypes[tupi] = tup;
}
+ nfparams--; // don't consider the last parameter for type deduction
+ goto L2;
+ }
- L1:
- if (nfargs != nfparams)
+ 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;
}
- 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;
- }
- }
}
+
visit(cast(Type)t);
}
@@ -1860,78 +1869,82 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa
override void visit(TypeInstance t)
{
// Extra check
- if (tparam && tparam.ty == Tinstance && t.tempinst.tempdecl)
+ if (!tparam || tparam.ty != Tinstance || !t.tempinst.tempdecl)
{
- TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
- assert(tempdecl);
+ visit(cast(Type)t);
+ return;
+ }
- TypeInstance tp = tparam.isTypeInstance();
+ TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
- //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());
+ TypeInstance tp = tparam.isTypeInstance();
- /* Handle case of:
- * template Foo(T : sa!(T), alias sa)
+ //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, &parameters);
+ 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
*/
- size_t i = templateIdentifierLookup(tp.tempinst.name, &parameters);
- if (i == IDX_NOTFOUND)
+ 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)
{
- /* 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)
{
- 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;
- }
+ // 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)
+ }
+ if (s)
+ {
+ s = s.toAlias();
+ TemplateDeclaration td = s.isTemplateDeclaration();
+ if (td)
{
- s = s.toAlias();
- TemplateDeclaration td = s.isTemplateDeclaration();
- if (td)
+ if (td.overroot)
+ td = td.overroot;
+ for (; td; td = td.overnext)
{
- if (td.overroot)
- td = td.overroot;
- for (; td; td = td.overnext)
- {
- if (td == tempdecl)
- goto L2;
- }
+ if (td == tempdecl)
+ goto L2;
}
}
- goto Lnomatch;
}
-
- TemplateParameter tpx = parameters[i];
- if (!tpx.matchArg(sc, tempdecl, i, &parameters, dedtypes, null))
- goto Lnomatch;
- }
- else if (tempdecl != tp.tempinst.tempdecl)
goto Lnomatch;
+ }
- L2:
- if (!resolveTemplateInstantiation(sc, &parameters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes))
+ TemplateParameter tpx = parameters[i];
+ if (!tpx.matchArg(sc, tempdecl, i, &parameters, dedtypes, null))
goto Lnomatch;
}
+ else if (tempdecl != tp.tempinst.tempdecl)
+ goto Lnomatch;
+
+ L2:
+ if (!resolveTemplateInstantiation(sc, &parameters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes))
+ goto Lnomatch;
+
visit(cast(Type)t);
return;
@@ -2537,8 +2550,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa
*/
private void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, ref Objects best, ref int numBaseClassMatches)
{
- TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
- if (parti)
+ if (TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null)
{
// Make a temporary copy of dedtypes so we don't destroy it
auto tmpdedtypes = new Objects(dedtypes.length);
@@ -2981,6 +2993,8 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
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);
@@ -3157,7 +3171,7 @@ extern (C++) class TemplateParameter : ASTNode
bool dependent;
/* ======================== TemplateParameter =============================== */
- extern (D) this(const ref Loc loc, Identifier ident) @safe
+ extern (D) this(Loc loc, Identifier ident) @safe
{
this.loc = loc;
this.ident = ident;
@@ -3196,7 +3210,7 @@ extern (C++) class TemplateParameter : ASTNode
abstract RootObject specialization();
- abstract RootObject defaultArg(const ref Loc instLoc, Scope* sc);
+ abstract RootObject defaultArg(Loc instLoc, Scope* sc);
abstract bool hasDefaultArg();
@@ -3210,10 +3224,6 @@ extern (C++) class TemplateParameter : ASTNode
return DYNCAST.templateparameter;
}
- /* Create dummy argument based on parameter.
- */
- abstract RootObject dummyArg();
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3232,7 +3242,7 @@ extern (C++) class TemplateTypeParameter : TemplateParameter
extern (D) __gshared Type tdummy = null;
- extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType) @safe
+ extern (D) this(Loc loc, Identifier ident, Type specType, Type defaultType) @safe
{
super(loc, ident);
this.specType = specType;
@@ -3278,7 +3288,7 @@ extern (C++) class TemplateTypeParameter : TemplateParameter
return specType;
}
- override final RootObject defaultArg(const ref Loc instLoc, Scope* sc)
+ override final RootObject defaultArg(Loc instLoc, Scope* sc)
{
Type t = defaultType;
if (t)
@@ -3294,19 +3304,6 @@ extern (C++) class TemplateTypeParameter : TemplateParameter
return defaultType !is null;
}
- override final RootObject dummyArg()
- {
- Type t = specType;
- if (!t)
- {
- // Use this for alias-parameter's too (?)
- if (!tdummy)
- tdummy = new TypeIdentifier(loc, ident);
- t = tdummy;
- }
- return t;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3320,7 +3317,7 @@ extern (C++) class TemplateTypeParameter : TemplateParameter
*/
extern (C++) final class TemplateThisParameter : TemplateTypeParameter
{
- extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType) @safe
+ extern (D) this(Loc loc, Identifier ident, Type specType, Type defaultType) @safe
{
super(loc, ident, specType, defaultType);
}
@@ -3354,7 +3351,7 @@ extern (C++) final class TemplateValueParameter : TemplateParameter
extern (D) __gshared Expression[void*] edummies;
- extern (D) this(const ref Loc loc, Identifier ident, Type valType,
+ extern (D) this(Loc loc, Identifier ident, Type valType,
Expression specValue, Expression defaultValue) @safe
{
super(loc, ident);
@@ -3411,37 +3408,38 @@ extern (C++) final class TemplateValueParameter : TemplateParameter
return specValue;
}
- override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
+ override RootObject defaultArg(Loc instLoc, Scope* sc)
{
Expression e = defaultValue;
- if (e)
- {
- 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)
+ 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);
}
+ if ((e = resolveProperties(sc, e)) is null)
+ return null;
+ e = e.resolveLoc(instLoc, sc); // use the instantiated loc
+ e = e.optimize(WANTvalue);
+
return e;
}
@@ -3450,24 +3448,6 @@ extern (C++) final class TemplateValueParameter : TemplateParameter
return defaultValue !is null;
}
- override RootObject dummyArg()
- {
- Expression e = specValue;
- if (!e)
- {
- // Create a dummy value
- auto pe = cast(void*)valType in edummies;
- if (!pe)
- {
- e = valType.defaultInit(Loc.initial);
- edummies[cast(void*)valType] = e;
- }
- else
- e = *pe;
- }
- return e;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3487,7 +3467,7 @@ extern (C++) final class TemplateAliasParameter : TemplateParameter
extern (D) __gshared Dsymbol sdummy = null;
- extern (D) this(const ref Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias) @safe
+ extern (D) this(Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias) @safe
{
super(loc, ident);
this.specType = specType;
@@ -3525,7 +3505,7 @@ extern (C++) final class TemplateAliasParameter : TemplateParameter
return specAlias;
}
- override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
+ override RootObject defaultArg(Loc instLoc, Scope* sc)
{
RootObject da = defaultAlias;
if (auto ta = isType(defaultAlias))
@@ -3553,18 +3533,6 @@ extern (C++) final class TemplateAliasParameter : TemplateParameter
return defaultAlias !is null;
}
- override RootObject dummyArg()
- {
- RootObject s = specAlias;
- if (!s)
- {
- if (!sdummy)
- sdummy = new Dsymbol();
- s = sdummy;
- }
- return s;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3578,7 +3546,7 @@ extern (C++) final class TemplateAliasParameter : TemplateParameter
*/
extern (C++) final class TemplateTupleParameter : TemplateParameter
{
- extern (D) this(const ref Loc loc, Identifier ident) @safe
+ extern (D) this(Loc loc, Identifier ident) @safe
{
super(loc, ident);
}
@@ -3632,7 +3600,7 @@ extern (C++) final class TemplateTupleParameter : TemplateParameter
return null;
}
- override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
+ override RootObject defaultArg(Loc instLoc, Scope* sc)
{
return null;
}
@@ -3642,11 +3610,6 @@ extern (C++) final class TemplateTupleParameter : TemplateParameter
return false;
}
- override RootObject dummyArg()
- {
- return null;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3679,7 +3642,22 @@ extern (C++) class TemplateInstance : ScopeDsymbol
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
- TemplateInstance inst; // refer to existing instance
+
+ /**
+ 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()
@@ -3691,7 +3669,15 @@ extern (C++) class TemplateInstance : ScopeDsymbol
TemplateInstances* deferred;
- Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[]
+ /**
+ 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.
@@ -3738,13 +3724,14 @@ extern (C++) class TemplateInstance : ScopeDsymbol
}
}
- extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs) scope
+ 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;
}
@@ -3753,13 +3740,14 @@ extern (C++) class TemplateInstance : ScopeDsymbol
* This constructor is only called when we figured out which function
* template to instantiate.
*/
- extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs) scope
+ 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;
@@ -3830,19 +3818,6 @@ extern (C++) class TemplateInstance : ScopeDsymbol
return "template instance";
}
- override bool oneMember(out Dsymbol ps, Identifier ident)
- {
- ps = null;
- return true;
- }
-
- override const(char)* toChars() const
- {
- OutBuffer buf;
- toCBufferInstance(this, buf);
- return buf.extractChars();
- }
-
override final const(char)* toPrettyCharsHelper()
{
OutBuffer buf;
@@ -3889,7 +3864,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
// 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.warnings == DiagnosticReporting.error) ||
+ (cl == Classification.warning && global.params.useWarnings == DiagnosticReporting.error) ||
(cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
cur.errors = true;
@@ -3905,7 +3880,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
if (n_instantiations <= max_shown)
{
for (TemplateInstance cur = this; cur; cur = cur.tinst)
- printFn(cur.loc, format, cur.toChars());
+ printFn(cur.loc, format, cur.toErrMsg());
}
else if (n_instantiations - n_totalrecursions <= max_shown)
{
@@ -3973,66 +3948,63 @@ extern (C++) class TemplateInstance : ScopeDsymbol
if (enclosing != ti.enclosing)
{
//printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
- goto Lnotequals;
+ return false;
}
//printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
if (!arrayObjectMatch(tdtypes, ti.tdtypes))
- goto Lnotequals;
+ return false;
/* Template functions may have different instantiations based on
* "auto ref" parameters.
*/
- if (auto fd = ti.toAlias().isFuncDeclaration())
- {
- if (!fd.errors)
- {
- auto resolvedArgs = fd.type.isTypeFunction().resolveNamedArgs(
- ArgumentList(this.fargs, this.fnames), null);
+ auto fd = ti.toAlias().isFuncDeclaration();
+ if (!fd)
+ return true;
+ if (fd.errors)
+ return true;
- // 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 resolvedArgs = fd.type.isTypeFunction().resolveNamedArgs(
+ ArgumentList(this.fargs, this.fnames), null);
- Expression[] args = resolvedArgs ? (*resolvedArgs)[] : [];
+ // 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 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"
- {
- 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)
- goto Lnotequals;
- if (farg.isLvalue())
- {
- if (!(fparam.storageClass & STC.ref_))
- goto Lnotequals; // auto ref's don't match
- }
- else
- {
- if (fparam.storageClass & STC.ref_)
- goto Lnotequals; // auto ref's don't match
- }
- }
- }
+ 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;
-
- Lnotequals:
- return false;
}
extern (D) final size_t toHash()
@@ -4184,77 +4156,75 @@ extern (C++) class TemplateInstance : ScopeDsymbol
// Elide codegen because there's no instantiation from any root modules.
return false;
}
- else
- {
- // 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)
+ // 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)
{
- // 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
{
- 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;
- }
+ 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;
+ // Elide codegen if `this` doesn't need it.
+ if (tithis.minst && !tithis.minst.isRoot() && !tithis.minst.rootImports())
+ return ThreeState.no;
- return ThreeState.none;
- }
+ return ThreeState.none;
+ }
- if (const needsCodegen = needsCodegenRootOnly(this, tinst))
- return needsCodegen == ThreeState.yes ? true : false;
+ 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)
+ // 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
{
- const needsCodegen = needsCodegenRootOnly(tnext, tnext.tinst); // sets tnext.minst
- if (tnext.minst) // not speculative
+ if (needsCodegen == ThreeState.no)
{
- 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;
+ 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;
}
+
+ // 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;
}
/**********************************************
@@ -4503,7 +4473,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
* Returns:
* false if one or more arguments have errors.
*/
- extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags, TupleDeclaration atd = null)
+ 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");
@@ -4513,9 +4483,13 @@ extern (C++) class TemplateInstance : ScopeDsymbol
// 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++)
{
RootObject o = (*tiargs)[j];
@@ -4609,7 +4583,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
{
if (ea.checkValue()) // check void expression
ea = ErrorExp.get();
- uint olderrs = global.errors;
+ const olderrs = global.errors;
ea = ea.ctfeInterpret();
if (global.errors != olderrs)
ea = ErrorExp.get();
@@ -4821,7 +4795,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
printf("TemplateInstance.findBestMatch()\n");
}
- uint errs = global.errors;
+ const errs = global.errors;
TemplateDeclaration td_last = null;
Objects dedtypes;
@@ -5036,135 +5010,6 @@ extern (C++) class TemplateInstance : ScopeDsymbol
return (errs == global.errors);
}
- /*****************************************************
- * Determine if template instance is really a template function,
- * and that template function needs to infer types from the function
- * arguments.
- *
- * Like findBestMatch, iterate possible template candidates,
- * but just looks only the necessity of type inference.
- */
- extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
- {
- //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
- if (semanticRun != PASS.initial)
- return false;
-
- uint olderrs = global.errors;
- Objects dedtypes;
- size_t count = 0;
-
- 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 any of the overloaded template declarations need inference,
- * then return true
- */
- if (!td.onemember)
- return 0;
- if (auto td2 = td.onemember.isTemplateDeclaration())
- {
- if (!td2.onemember || !td2.onemember.isFuncDeclaration())
- return 0;
- if (tiargs.length >= td.parameters.length - (td.isVariadic() ? 1 : 0))
- return 0;
- return 1;
- }
- auto fd = td.onemember.isFuncDeclaration();
- if (!fd || fd.type.ty != Tfunction)
- return 0;
-
- foreach (tp; *td.parameters)
- {
- if (tp.isTemplateThisParameter())
- return 1;
- }
-
- /* Determine if the instance arguments, tiargs, are all that is necessary
- * to instantiate the template.
- */
- //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
- auto tf = fd.type.isTypeFunction();
- if (tf.parameterList.length)
- {
- auto tp = td.isVariadic();
- if (tp && td.parameters.length > 1)
- return 1;
-
- if (!tp && tiargs.length < td.parameters.length)
- {
- // Can remain tiargs be filled by default arguments?
- foreach (size_t i; tiargs.length .. td.parameters.length)
- {
- if (!(*td.parameters)[i].hasDefaultArg())
- return 1;
- }
- }
-
- foreach (i, fparam; tf.parameterList)
- {
- // 'auto ref' needs inference.
- if (fparam.storageClass & STC.auto_)
- return 1;
- }
- }
-
- if (!flag)
- {
- /* Calculate the need for overload resolution.
- * When only one template can match with tiargs, inference is not necessary.
- */
- dedtypes.setDim(td.parameters.length);
- dedtypes.zero();
- 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;
- }
- }
- MATCH m = matchWithInstance(sc, td, this, dedtypes, ArgumentList(), 0);
- if (m == MATCH.nomatch)
- return 0;
- }
-
- /* If there is more than one function template which matches, we may
- * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
- */
- return ++count > 1 ? 1 : 0;
- });
- if (r)
- return true;
- }
-
- if (olderrs != global.errors)
- {
- if (!global.gag)
- {
- errorSupplemental(loc, "while looking for match for `%s`", toChars());
- semanticRun = PASS.semanticdone;
- inst = this;
- }
- errors = true;
- }
- //printf("false\n");
- return false;
- }
-
/*****************************************
* Determines if a TemplateInstance will need a nested
* generation of the TemplateDeclaration.
@@ -5486,11 +5331,6 @@ extern (C++) class TemplateInstance : ScopeDsymbol
--nest;
}
- override final inout(TemplateInstance) isTemplateInstance() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -5628,12 +5468,13 @@ extern (C++) final class TemplateMixin : TemplateInstance
{
TypeQualified tqual;
- extern (D) this(const ref Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs)
+ extern (D) this(Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs)
{
super(loc,
tqual.idents.length ? cast(Identifier)tqual.idents[tqual.idents.length - 1] : (cast(TypeIdentifier)tqual).ident,
tiargs ? tiargs : new Objects());
//printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
+ this.dsym = DSYM.templateMixin;
this.ident = ident;
this.tqual = tqual;
}
@@ -5649,24 +5490,12 @@ extern (C++) final class TemplateMixin : TemplateInstance
return "mixin";
}
- override bool oneMember(out Dsymbol ps, Identifier ident)
- {
- return Dsymbol.oneMember(ps, ident);
- }
-
override bool hasPointers()
{
//printf("TemplateMixin.hasPointers() %s\n", toChars());
return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
}
- override const(char)* toChars() const
- {
- OutBuffer buf;
- toCBufferInstance(this, buf);
- return buf.extractChars();
- }
-
extern (D) bool findTempDecl(Scope* sc)
{
// Follow qualifications to find the TemplateDeclaration
@@ -5741,11 +5570,6 @@ extern (C++) final class TemplateMixin : TemplateInstance
return true;
}
- override inout(TemplateMixin) isTemplateMixin() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -5767,7 +5591,7 @@ struct TemplateInstanceBox
assert(this.ti.hash);
}
- size_t toHash() const @trusted pure nothrow
+ size_t toHash() const @safe pure nothrow
{
assert(ti.hash);
return ti.hash;
@@ -5883,8 +5707,8 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si
if (auto ttp = tp.isTemplateTupleParameter())
return matchArgTuple(ttp);
- else
- return matchArgParameter();
+
+ return matchArgParameter();
}
MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam)
@@ -5987,7 +5811,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
/* If a function is really property-like, and then
* it's CTFEable, ei will be a literal expression.
*/
- uint olderrors = global.startGagging();
+ const olderrors = global.startGagging();
ei = resolveProperties(sc, ei);
ei = ei.ctfeInterpret();
if (global.endGagging(olderrors) || ei.op == EXP.error)
@@ -6260,14 +6084,13 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
if (auto ttp = tp.isTemplateTypeParameter())
return matchArgType(ttp);
- else if (auto tvp = tp.isTemplateValueParameter())
+ if (auto tvp = tp.isTemplateValueParameter())
return matchArgValue(tvp);
- else if (auto tap = tp.isTemplateAliasParameter())
+ if (auto tap = tp.isTemplateAliasParameter())
return matchArgAlias(tap);
- else if (auto ttp = tp.isTemplateTupleParameter())
+ if (auto ttp = tp.isTemplateTupleParameter())
return matchArgTuple(ttp);
- else
- assert(0);
+ assert(0);
}
@@ -6353,8 +6176,8 @@ void printTemplateStats(bool listInstances, ErrorSink eSink)
auto diff = b.ts.uniqueInstantiations - a.ts.uniqueInstantiations;
if (diff)
return diff;
- else
- return b.ts.numInstantiations - a.ts.numInstantiations;
+
+ return b.ts.numInstantiations - a.ts.numInstantiations;
}
}
@@ -6424,6 +6247,9 @@ void write(ref OutBuffer buf, RootObject obj)
{
if (obj)
{
- buf.writestring(obj.toChars());
+ if (auto e = isExpression(obj))
+ buf.writestring(e.toErrMsg());
+ else
+ buf.writestring(obj.toChars());
}
}
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 2e2ced4..3946c25 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -2,12 +2,12 @@
* This module contains the implementation of the C++ header generation available through
* the command line switch -Hc.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dtoh.d, _dtoh.d)
* Documentation: https://dlang.org/phobos/dmd_dtoh.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtoh.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dtoh.d
*/
module dmd.dtoh;
@@ -104,7 +104,8 @@ void genCppHdrFiles(ref Modules ms)
// Emit array compatibility because extern(C++) types may have slices
// as members (as opposed to function parameters)
- buf.writestring(`
+ if (v.hasDArray)
+ buf.writestring(`
#ifdef CUSTOM_D_ARRAY_TYPE
#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
#else
@@ -133,6 +134,17 @@ struct _d_dynamicArray final
#endif
`);
+ if (v.hasExternSystem)
+ buf.writestring(`
+#ifndef _WIN32
+#define EXTERN_SYSTEM_AFTER __stdcall
+#define EXTERN_SYSTEM_BEFORE
+#else
+#define EXTERN_SYSTEM_AFTER
+#define EXTERN_SYSTEM_BEFORE extern "C"
+#endif
+`);
+
if (v.hasReal)
{
hashIf(buf, "!defined(_d_real)");
@@ -248,7 +260,14 @@ public:
OutBuffer* buf;
/// The generated header uses `real` emitted as `_d_real`?
- bool hasReal;
+ bool hasReal = false;
+
+ /// The generated header has extern(System) functions,
+ /// which needs support macros in the header
+ bool hasExternSystem = false;
+
+ /// There are functions taking slices, which need a compatibility struct for C++
+ bool hasDArray = false;
/// The generated header should contain comments for skipped declarations?
const bool printIgnored;
@@ -493,7 +512,7 @@ public:
}
}
- if (global.params.warnings != DiagnosticReporting.off || canFix)
+ if (global.params.useWarnings != DiagnosticReporting.off || canFix)
{
// Warn about identifiers that are keywords in C++.
if (auto kc = keywordClass(ident))
@@ -745,7 +764,7 @@ public:
// Note that tf might be null for templated (member) functions
auto tf = cast(AST.TypeFunction)fd.type;
- if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
+ if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp && tf.linkage != LINK.windows) || (!tf && fd.isPostBlitDeclaration()))
{
ignored("function %s because of linkage", fd.toPrettyChars());
return checkFunctionNeedsPlaceholder(fd);
@@ -793,8 +812,17 @@ public:
writeProtection(fd.visibility.kind);
- if (tf && tf.linkage == LINK.c)
+ if (fd._linkage == LINK.system)
+ {
+ hasExternSystem = true;
+ buf.writestring("EXTERN_SYSTEM_BEFORE ");
+ }
+ else if (tf && tf.linkage == LINK.c)
buf.writestring("extern \"C\" ");
+ else if (tf && tf.linkage == LINK.windows)
+ {
+ // __stdcall is printed after return type
+ }
else if (!adparent)
buf.writestring("extern ");
if (adparent && fd.isStatic())
@@ -948,7 +976,8 @@ public:
{
EnumKind kind = getEnumKind(type);
- if (vd.visibility.kind == AST.Visibility.Kind.none || vd.visibility.kind == AST.Visibility.Kind.private_) {
+ if (vd.visibility.kind == AST.Visibility.Kind.none || vd.visibility.kind == AST.Visibility.Kind.private_)
+ {
ignored("enum `%s` because it is `%s`.", vd.toPrettyChars(), AST.visibilityToChars(vd.visibility.kind));
return;
}
@@ -2058,6 +2087,8 @@ public:
{
debug (Debug_DtoH) mixin(traceVisit!t);
+ hasDArray = true;
+
if (t.isConst() || t.isImmutable())
buf.writestring("const ");
buf.writestring("_d_dynamicArray< ");
@@ -2261,8 +2292,8 @@ public:
* Writes the function signature to `buf`.
*
* Params:
- * fd = the function to print
* tf = fd's type
+ * fd = the function to print
*/
private void funcToBuffer(AST.TypeFunction tf, AST.FuncDeclaration fd)
{
@@ -2294,9 +2325,18 @@ public:
assert(tf.next, fd.loc.toChars().toDString());
tf.next == AST.Type.tsize_t ? originalType.next.accept(this) : tf.next.accept(this);
- if (tf.isref)
+ if (tf.isRef)
buf.writeByte('&');
buf.writeByte(' ');
+
+ if (fd._linkage == LINK.system)
+ {
+ buf.writestring("EXTERN_SYSTEM_AFTER ");
+ }
+ else if (tf.linkage == LINK.windows)
+ {
+ buf.writestring("__stdcall ");
+ }
writeIdentifier(fd);
}
@@ -2757,7 +2797,7 @@ public:
{
if (vd._init && !vd._init.isVoidInitializer())
return AST.initializerToExpression(vd._init);
- else if (auto ts = vd.type.isTypeStruct())
+ if (auto ts = vd.type.isTypeStruct())
{
if (!ts.sym.noDefaultCtor && !ts.sym.isUnionDeclaration())
{
diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d
index 2e3b352..26528e9 100644
--- a/gcc/d/dmd/dversion.d
+++ b/gcc/d/dmd/dversion.d
@@ -4,12 +4,12 @@
* Specification: $(LINK2 https://dlang.org/spec/version.html#version-specification, Version Specification),
* $(LINK2 https://dlang.org/spec/version.html#debug_specification, Debug Specification).
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d, _dversion.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dversion.d, _dversion.d)
* Documentation: https://dlang.org/phobos/dmd_dversion.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dversion.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/dversion.d
*/
module dmd.dversion;
@@ -20,7 +20,6 @@ import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
import dmd.dsymbolsem;
-import dmd.errors;
import dmd.globals;
import dmd.identifier;
import dmd.location;
@@ -30,21 +29,17 @@ import dmd.visitor;
/***********************************************************
* DebugSymbol's happen for statements like:
* debug = identifier;
- * debug = integer;
*/
extern (C++) final class DebugSymbol : Dsymbol
{
- uint level;
-
- extern (D) this(const ref Loc loc, Identifier ident) @safe
+ extern (D) this(Loc loc, Identifier ident) @safe
{
- super(loc, ident);
+ super(DSYM.debugSymbol, loc, ident);
}
- extern (D) this(const ref Loc loc, uint level) @safe
+ extern (D) this(Loc loc) @safe
{
- super(loc, null);
- this.level = level;
+ super(DSYM.aliasDeclaration, loc, null);
}
override DebugSymbol syntaxCopy(Dsymbol s)
@@ -52,32 +47,14 @@ extern (C++) final class DebugSymbol : Dsymbol
assert(!s);
auto ds = new DebugSymbol(loc, ident);
ds.comment = comment;
- ds.level = level;
return ds;
}
- override const(char)* toChars() const nothrow
- {
- if (ident)
- return ident.toChars();
- else
- {
- OutBuffer buf;
- buf.print(level);
- return buf.extractChars();
- }
- }
-
override const(char)* kind() const nothrow
{
return "debug";
}
- override inout(DebugSymbol) isDebugSymbol() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -87,54 +64,33 @@ extern (C++) final class DebugSymbol : Dsymbol
/***********************************************************
* VersionSymbol's happen for statements like:
* version = identifier;
- * version = integer;
*/
extern (C++) final class VersionSymbol : Dsymbol
{
- uint level;
- extern (D) this(const ref Loc loc, Identifier ident) @safe
+ extern (D) this(Loc loc, Identifier ident) @safe
{
- super(loc, ident);
+ super(DSYM.versionSymbol, loc, ident);
}
- extern (D) this(const ref Loc loc, uint level) @safe
+ extern (D) this(Loc loc) @safe
{
- super(loc, null);
- this.level = level;
+ super(DSYM.versionSymbol, loc, null);
}
override VersionSymbol syntaxCopy(Dsymbol s)
{
assert(!s);
- auto ds = ident ? new VersionSymbol(loc, ident)
- : new VersionSymbol(loc, level);
+ auto ds = new VersionSymbol(loc, ident);
ds.comment = comment;
return ds;
}
- override const(char)* toChars() const nothrow
- {
- if (ident)
- return ident.toChars();
- else
- {
- OutBuffer buf;
- buf.print(level);
- return buf.extractChars();
- }
- }
-
override const(char)* kind() const nothrow
{
return "version";
}
- override inout(VersionSymbol) isVersionSymbol() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/entity.d b/gcc/d/dmd/entity.d
index af74c3b..a70029b 100644
--- a/gcc/d/dmd/entity.d
+++ b/gcc/d/dmd/entity.d
@@ -3,12 +3,12 @@
*
* Specification $(LINK2 https://dlang.org/spec/entity.html, Named Character Entities)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/entity.d, _entity.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/entity.d, _entity.d)
* Documentation: https://dlang.org/phobos/dmd_entity.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/entity.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/entity.d
*/
module dmd.entity;
diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h
index 4e6fbe2..6d5d302 100644
--- a/gcc/d/dmd/enum.h
+++ b/gcc/d/dmd/enum.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -20,7 +20,7 @@ class Expression;
namespace dmd
{
// in enumsem.d
- Expression *getDefaultValue(EnumDeclaration *ed, const Loc &loc);
+ Expression *getDefaultValue(EnumDeclaration *ed, Loc loc);
}
class EnumDeclaration final : public ScopeDsymbol
@@ -52,14 +52,12 @@ public:
bool inuse(bool v);
EnumDeclaration *syntaxCopy(Dsymbol *s) override;
- bool oneMember(Dsymbol *&ps, Identifier *ident) override;
Type *getType() override;
const char *kind() const override;
bool isDeprecated() const override; // is Dsymbol deprecated?
Visibility visible() override;
bool isSpecial() const;
- EnumDeclaration *isEnumDeclaration() override { return this; }
Symbol *sinit;
void accept(Visitor *v) override { v->visit(this); }
@@ -87,6 +85,5 @@ public:
EnumMember *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
- EnumMember *isEnumMember() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d
index 3886ca2..4f0d4e5 100644
--- a/gcc/d/dmd/enumsem.d
+++ b/gcc/d/dmd/enumsem.d
@@ -1,12 +1,12 @@
/**
* Does the semantic passes on enums.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/enumsem.d, _enumsem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/enumsem.d, _enumsem.d)
* Documentation: https://dlang.org/phobos/dmd_enumsem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/enumsem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/enumsem.d
*/
module dmd.enumsem;
@@ -30,7 +30,6 @@ import dmd.declaration;
import dmd.denum;
import dmd.dimport;
import dmd.dinterpret;
-import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
import dmd.dstruct;
@@ -119,7 +118,7 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
ed.cppnamespace = sc.namespace;
ed.semanticRun = PASS.semantic;
- UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage);
+ checkGNUABITag(ed, sc.linkage);
checkMustUseReserved(ed);
if (!ed.members && !ed.memtype) // enum ident;
@@ -186,13 +185,13 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
if (ed.members.length == 0)
{
- .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars());
+ .error(ed.loc, "%s `%s` enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars());
ed.errors = true;
ed.semanticRun = PASS.semanticdone;
return;
}
- if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done
+ if (!sc.inCfile) // C enum remains incomplete until members are done
ed.semanticRun = PASS.semanticdone;
version (none)
@@ -219,8 +218,7 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
*/
ed.members.foreachDsymbol( (s)
{
- EnumMember em = s.isEnumMember();
- if (em)
+ if (EnumMember em = s.isEnumMember())
em._scope = sce;
});
@@ -230,7 +228,7 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
*/
addEnumMembersToSymtab(ed, sc, sc.getScopesym());
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* C11 6.7.2.2
*/
@@ -325,7 +323,10 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
if (EnumMember em = s.isEnumMember())
{
em.type = commonType;
- em.value = em.value.castTo(sc, commonType);
+ // optimize out the cast so that other parts of the compiler can
+ // assume that an integral enum's members are `IntegerExp`s.
+ // https://issues.dlang.org/show_bug.cgi?id=24504
+ em.value = em.value.castTo(sc, commonType).optimize(WANTvalue);
}
});
}
@@ -346,7 +347,7 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
//printf("members = %s\n", members.toChars());
}
-Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc)
+Expression getDefaultValue(EnumDeclaration ed, Loc loc)
{
Expression handleErrors(){
ed.defaultval = ErrorExp.get();
@@ -383,8 +384,7 @@ Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc)
foreach (const i; 0 .. ed.members.length)
{
- EnumMember em = (*ed.members)[i].isEnumMember();
- if (em)
+ if (EnumMember em = (*ed.members)[i].isEnumMember())
{
if (em.semanticRun < PASS.semanticdone)
{
@@ -399,7 +399,7 @@ Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc)
return handleErrors();
}
-Type getMemtype(EnumDeclaration ed, const ref Loc loc)
+Type getMemtype(EnumDeclaration ed, Loc loc)
{
if (ed._scope)
{
@@ -698,7 +698,7 @@ void enumMemberSemantic(Scope* sc, EnumMember em)
if (e.op == EXP.error)
return errorReturn();
- if (e.type.isfloating())
+ if (e.type.isFloating())
{
// Check that e != eprev (not always true for floats)
Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev);
diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d
index 79efc6e..90c18c3 100644
--- a/gcc/d/dmd/errors.d
+++ b/gcc/d/dmd/errors.d
@@ -1,20 +1,22 @@
/**
* Functions for raising errors.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d, _errors.d)
* Documentation: https://dlang.org/phobos/dmd_errors.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errors.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/errors.d
*/
module dmd.errors;
-import core.stdc.stdarg;
+public import core.stdc.stdarg;
+public import dmd.root.string: fTuple;
import dmd.errorsink;
import dmd.globals;
import dmd.location;
+import dmd.root.string;
nothrow:
@@ -37,60 +39,39 @@ class ErrorSinkCompiler : ErrorSink
extern (C++):
override:
- void error(const ref Loc loc, const(char)* format, ...)
+ void verror(Loc loc, const(char)* format, va_list ap)
{
- va_list ap;
- va_start(ap, format);
verrorReport(loc, format, ap, ErrorKind.error);
- va_end(ap);
}
- void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+ void verrorSupplemental(Loc loc, const(char)* format, va_list ap)
{
- va_list ap;
- va_start(ap, format);
verrorReportSupplemental(loc, format, ap, ErrorKind.error);
- va_end(ap);
}
- void warning(const ref Loc loc, const(char)* format, ...)
+ void vwarning(Loc loc, const(char)* format, va_list ap)
{
- va_list ap;
- va_start(ap, format);
verrorReport(loc, format, ap, ErrorKind.warning);
- va_end(ap);
}
- void warningSupplemental(const ref Loc loc, const(char)* format, ...)
+ void vwarningSupplemental(Loc loc, const(char)* format, va_list ap)
{
- va_list ap;
- va_start(ap, format);
verrorReportSupplemental(loc, format, ap, ErrorKind.warning);
- va_end(ap);
}
- void deprecation(const ref Loc loc, const(char)* format, ...)
+ void vdeprecation(Loc loc, const(char)* format, va_list ap)
{
- va_list ap;
- va_start(ap, format);
verrorReport(loc, format, ap, ErrorKind.deprecation);
- va_end(ap);
}
- void deprecationSupplemental(const ref Loc loc, const(char)* format, ...)
+ void vdeprecationSupplemental(Loc loc, const(char)* format, va_list ap)
{
- va_list ap;
- va_start(ap, format);
verrorReportSupplemental(loc, format, ap, ErrorKind.deprecation);
- va_end(ap);
}
- void message(const ref Loc loc, const(char)* format, ...)
+ void vmessage(Loc loc, const(char)* format, va_list ap)
{
- va_list ap;
- va_start(ap, format);
verrorReport(loc, format, ap, ErrorKind.message);
- va_end(ap);
}
}
@@ -130,9 +111,9 @@ enum Color : int
static if (__VERSION__ < 2092)
- private extern (C++) void noop(const ref Loc loc, const(char)* format, ...) {}
+ private extern (C++) void noop(Loc loc, const(char)* format, ...) {}
else
- pragma(printf) private extern (C++) void noop(const ref Loc loc, const(char)* format, ...) {}
+ pragma(printf) private extern (C++) void noop(Loc loc, const(char)* format, ...) {}
package auto previewErrorFunc(bool isDeprecated, FeatureState featureState) @safe @nogc pure nothrow
@@ -174,7 +155,7 @@ package auto previewSupplementalFunc(bool isDeprecated, FeatureState featureStat
* ... = printf-style variadic arguments
*/
static if (__VERSION__ < 2092)
- extern (C++) void error(const ref Loc loc, const(char)* format, ...)
+ extern (C++) void error(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -182,7 +163,7 @@ static if (__VERSION__ < 2092)
va_end(ap);
}
else
- pragma(printf) extern (C++) void error(const ref Loc loc, const(char)* format, ...)
+ pragma(printf) extern (C++) void error(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -202,7 +183,7 @@ else
static if (__VERSION__ < 2092)
extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...)
{
- const loc = Loc(filename, linnum, charnum);
+ const loc = SourceLoc(filename.toDString, linnum, charnum);
va_list ap;
va_start(ap, format);
verrorReport(loc, format, ap, ErrorKind.error);
@@ -211,13 +192,23 @@ static if (__VERSION__ < 2092)
else
pragma(printf) extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...)
{
- const loc = Loc(filename, linnum, charnum);
+ const loc = SourceLoc(filename.toDString, linnum, charnum);
va_list ap;
va_start(ap, format);
verrorReport(loc, format, ap, ErrorKind.error);
va_end(ap);
}
+/// Callback for when the backend wants to report an error
+extern(C++) void errorBackend(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...)
+{
+ const loc = SourceLoc(filename.toDString, linnum, charnum);
+ va_list ap;
+ va_start(ap, format);
+ verrorReport(loc, format, ap, ErrorKind.error);
+ va_end(ap);
+}
+
/**
* Print additional details about an error message.
* Doesn't increase the error count or print an additional error prefix.
@@ -227,7 +218,7 @@ else
* ... = printf-style variadic arguments
*/
static if (__VERSION__ < 2092)
- extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+ extern (C++) void errorSupplemental(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -235,7 +226,7 @@ static if (__VERSION__ < 2092)
va_end(ap);
}
else
- pragma(printf) extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+ pragma(printf) extern (C++) void errorSupplemental(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -251,7 +242,7 @@ else
* ... = printf-style variadic arguments
*/
static if (__VERSION__ < 2092)
- extern (C++) void warning(const ref Loc loc, const(char)* format, ...)
+ extern (C++) void warning(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -259,7 +250,7 @@ static if (__VERSION__ < 2092)
va_end(ap);
}
else
- pragma(printf) extern (C++) void warning(const ref Loc loc, const(char)* format, ...)
+ pragma(printf) extern (C++) void warning(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -276,7 +267,7 @@ else
* ... = printf-style variadic arguments
*/
static if (__VERSION__ < 2092)
- extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...)
+ extern (C++) void warningSupplemental(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -284,7 +275,7 @@ static if (__VERSION__ < 2092)
va_end(ap);
}
else
- pragma(printf) extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...)
+ pragma(printf) extern (C++) void warningSupplemental(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -301,7 +292,7 @@ else
* ... = printf-style variadic arguments
*/
static if (__VERSION__ < 2092)
- extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...)
+ extern (C++) void deprecation(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -309,7 +300,7 @@ static if (__VERSION__ < 2092)
va_end(ap);
}
else
- pragma(printf) extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...)
+ pragma(printf) extern (C++) void deprecation(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -326,7 +317,7 @@ else
* ... = printf-style variadic arguments
*/
static if (__VERSION__ < 2092)
- extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...)
+ extern (C++) void deprecationSupplemental(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -334,7 +325,7 @@ static if (__VERSION__ < 2092)
va_end(ap);
}
else
- pragma(printf) extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...)
+ pragma(printf) extern (C++) void deprecationSupplemental(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -351,7 +342,7 @@ else
* ... = printf-style variadic arguments
*/
static if (__VERSION__ < 2092)
- extern (C++) void message(const ref Loc loc, const(char)* format, ...)
+ extern (C++) void message(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -359,7 +350,7 @@ static if (__VERSION__ < 2092)
va_end(ap);
}
else
- pragma(printf) extern (C++) void message(const ref Loc loc, const(char)* format, ...)
+ pragma(printf) extern (C++) void message(Loc loc, const(char)* format, ...)
{
va_list ap;
va_start(ap, format);
@@ -395,7 +386,7 @@ else
* see verrorReport for arguments
* Returns: true if error handling is done, false to continue printing to stderr
*/
-alias DiagnosticHandler = bool delegate(const ref Loc location, Color headerColor, const(char)* header, const(char)* messageFormat, va_list args, const(char)* prefix1, const(char)* prefix2);
+alias DiagnosticHandler = bool delegate(const ref SourceLoc location, Color headerColor, const(char)* header, const(char)* messageFormat, va_list args, const(char)* prefix1, const(char)* prefix2);
/**
* The diagnostic handler.
@@ -441,7 +432,13 @@ else
* p1 = additional message prefix
* p2 = additional message prefix
*/
-extern (C++) void verrorReport(const ref Loc loc, const(char)* format, va_list ap, ErrorKind kind, const(char)* p1 = null, const(char)* p2 = null);
+private extern(C++) void verrorReport(Loc loc, const(char)* format, va_list ap, ErrorKind kind, const(char)* p1 = null, const(char)* p2 = null)
+{
+ return verrorReport(loc.SourceLoc, format, ap, kind, p1, p2);
+}
+
+/// ditto
+private extern(C++) void verrorReport(const SourceLoc loc, const(char)* format, va_list ap, ErrorKind kind, const(char)* p1 = null, const(char)* p2 = null);
/**
* Implements $(D errorSupplemental), $(D warningSupplemental), and
@@ -454,7 +451,13 @@ extern (C++) void verrorReport(const ref Loc loc, const(char)* format, va_list a
* ap = printf-style variadic arguments
* kind = kind of error being printed
*/
-extern (C++) void verrorReportSupplemental(const ref Loc loc, const(char)* format, va_list ap, ErrorKind kind);
+private extern(C++) void verrorReportSupplemental(Loc loc, const(char)* format, va_list ap, ErrorKind kind)
+{
+ return verrorReportSupplemental(loc.SourceLoc, format, ap, kind);
+}
+
+/// ditto
+private extern(C++) void verrorReportSupplemental(const SourceLoc loc, const(char)* format, va_list ap, ErrorKind kind);
/**
* The type of the fatal error handler
diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h
index a47b5aa..a2d0f36 100644
--- a/gcc/d/dmd/errors.h
+++ b/gcc/d/dmd/errors.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -31,20 +31,17 @@ enum class ErrorKind
#endif
// Print a warning, deprecation, or error, accepts printf-like format specifiers.
-D_ATTRIBUTE_FORMAT(2, 3) void warning(const Loc& loc, const char *format, ...);
-D_ATTRIBUTE_FORMAT(2, 3) void warningSupplemental(const Loc& loc, const char *format, ...);
-D_ATTRIBUTE_FORMAT(2, 3) void deprecation(const Loc& loc, const char *format, ...);
-D_ATTRIBUTE_FORMAT(2, 3) void deprecationSupplemental(const Loc& loc, const char *format, ...);
-D_ATTRIBUTE_FORMAT(2, 3) void error(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void warning(Loc loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void warningSupplemental(Loc loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void deprecation(Loc loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void deprecationSupplemental(Loc loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void error(Loc loc, const char *format, ...);
D_ATTRIBUTE_FORMAT(4, 5) void error(const char *filename, unsigned linnum, unsigned charnum, const char *format, ...);
-D_ATTRIBUTE_FORMAT(2, 3) void errorSupplemental(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void errorSupplemental(Loc loc, const char *format, ...);
D_ATTRIBUTE_FORMAT(1, 2) void message(const char *format, ...);
-D_ATTRIBUTE_FORMAT(2, 3) void message(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(2, 3) void message(Loc loc, const char *format, ...);
D_ATTRIBUTE_FORMAT(1, 2) void tip(const char *format, ...);
-D_ATTRIBUTE_FORMAT(2, 0) void verrorReport(const Loc& loc, const char *format, va_list ap, ErrorKind kind, const char *p1 = NULL, const char *p2 = NULL);
-D_ATTRIBUTE_FORMAT(2, 0) void verrorReportSupplemental(const Loc& loc, const char* format, va_list ap, ErrorKind kind);
-
#if defined(__GNUC__) || defined(__clang__)
#define D_ATTRIBUTE_NORETURN __attribute__((noreturn))
#elif _MSC_VER
diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d
index afea689..5793ef1 100644
--- a/gcc/d/dmd/errorsink.d
+++ b/gcc/d/dmd/errorsink.d
@@ -1,16 +1,18 @@
/**
* Provides an abstraction for what to do with error messages.
*
- * Copyright: Copyright (C) 2023-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 2023-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errorsink.d, _errorsink.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errorsink.d, _errorsink.d)
* Documentation: https://dlang.org/phobos/dmd_errorsink.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errorsink.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/errorsink.d
*/
module dmd.errorsink;
+import core.stdc.stdarg;
+
import dmd.location;
/***************************************
@@ -21,19 +23,78 @@ abstract class ErrorSink
nothrow:
extern (C++):
- void error(const ref Loc loc, const(char)* format, ...);
+ void verror(Loc loc, const(char)* format, va_list ap);
+ void verrorSupplemental(Loc loc, const(char)* format, va_list ap);
+ void vwarning(Loc loc, const(char)* format, va_list ap);
+ void vwarningSupplemental(Loc loc, const(char)* format, va_list ap);
+ void vmessage(Loc loc, const(char)* format, va_list ap);
+ void vdeprecation(Loc loc, const(char)* format, va_list ap);
+ void vdeprecationSupplemental(Loc loc, const(char)* format, va_list ap);
- void errorSupplemental(const ref Loc loc, const(char)* format, ...);
+ void error(Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ verror(loc, format, ap);
+ va_end(ap);
+ }
- void warning(const ref Loc loc, const(char)* format, ...);
+ void errorSupplemental(Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ verrorSupplemental(loc, format, ap);
+ va_end(ap);
+ }
- void warningSupplemental(const ref Loc loc, const(char)* format, ...);
+ void warning(Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vwarning(loc, format, ap);
+ va_end(ap);
+ }
+
+ void warningSupplemental(Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vwarningSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+
+ void message(Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vmessage(loc, format, ap);
+ va_end(ap);
+ }
- void message(const ref Loc loc, const(char)* format, ...);
+ void deprecation(Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vdeprecation(loc, format, ap);
+ va_end(ap);
+ }
- void deprecation(const ref Loc loc, const(char)* format, ...);
+ void deprecationSupplemental(Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vdeprecationSupplemental(loc, format, ap);
+ va_end(ap);
+ }
- void deprecationSupplemental(const ref Loc loc, const(char)* format, ...);
+ /**
+ * This will be called to indicate compilation has either
+ * finished or terminated, no more errors are possible - it's
+ * now the time to print any stored errors.
+ *
+ * The default implementation does nothing since most error sinks have no state
+ */
+ void plugSink() {}
}
/*****************************************
@@ -45,19 +106,19 @@ class ErrorSinkNull : ErrorSink
extern (C++):
override:
- void error(const ref Loc loc, const(char)* format, ...) { }
+ void verror(Loc loc, const(char)* format, va_list ap) { }
- void errorSupplemental(const ref Loc loc, const(char)* format, ...) { }
+ void verrorSupplemental(Loc loc, const(char)* format, va_list ap) { }
- void warning(const ref Loc loc, const(char)* format, ...) { }
+ void vwarning(Loc loc, const(char)* format, va_list ap) { }
- void warningSupplemental(const ref Loc loc, const(char)* format, ...) { }
+ void vwarningSupplemental(Loc loc, const(char)* format, va_list ap) { }
- void message(const ref Loc loc, const(char)* format, ...) { }
+ void vmessage(Loc loc, const(char)* format, va_list ap) { }
- void deprecation(const ref Loc loc, const(char)* format, ...) { }
+ void vdeprecation(Loc loc, const(char)* format, va_list ap) { }
- void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
+ void vdeprecationSupplemental(Loc loc, const(char)* format, va_list ap) { }
}
/*****************************************
@@ -71,7 +132,7 @@ class ErrorSinkLatch : ErrorSinkNull
bool sawErrors;
- void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; }
+ void verror(Loc loc, const(char)* format, va_list ap) { sawErrors = true; }
}
/*****************************************
@@ -87,7 +148,7 @@ class ErrorSinkStderr : ErrorSink
extern (C++):
override:
- void error(const ref Loc loc, const(char)* format, ...)
+ void verror(Loc loc, const(char)* format, va_list ap)
{
fputs("Error: ", stderr);
const p = loc.toChars();
@@ -97,16 +158,13 @@ class ErrorSinkStderr : ErrorSink
//mem.xfree(cast(void*)p); // loc should provide the free()
}
- va_list ap;
- va_start(ap, format);
vfprintf(stderr, format, ap);
fputc('\n', stderr);
- va_end(ap);
}
- void errorSupplemental(const ref Loc loc, const(char)* format, ...) { }
+ void verrorSupplemental(Loc loc, const(char)* format, va_list ap) { }
- void warning(const ref Loc loc, const(char)* format, ...)
+ void vwarning(Loc loc, const(char)* format, va_list ap)
{
fputs("Warning: ", stderr);
const p = loc.toChars();
@@ -116,16 +174,13 @@ class ErrorSinkStderr : ErrorSink
//mem.xfree(cast(void*)p); // loc should provide the free()
}
- va_list ap;
- va_start(ap, format);
vfprintf(stderr, format, ap);
fputc('\n', stderr);
- va_end(ap);
}
- void warningSupplemental(const ref Loc loc, const(char)* format, ...) { }
+ void vwarningSupplemental(Loc loc, const(char)* format, va_list ap) { }
- void deprecation(const ref Loc loc, const(char)* format, ...)
+ void vdeprecation(Loc loc, const(char)* format, va_list ap)
{
fputs("Deprecation: ", stderr);
const p = loc.toChars();
@@ -135,14 +190,11 @@ class ErrorSinkStderr : ErrorSink
//mem.xfree(cast(void*)p); // loc should provide the free()
}
- va_list ap;
- va_start(ap, format);
vfprintf(stderr, format, ap);
fputc('\n', stderr);
- va_end(ap);
}
- void message(const ref Loc loc, const(char)* format, ...)
+ void vmessage(Loc loc, const(char)* format, va_list ap)
{
const p = loc.toChars();
if (*p)
@@ -151,12 +203,9 @@ class ErrorSinkStderr : ErrorSink
//mem.xfree(cast(void*)p); // loc should provide the free()
}
- va_list ap;
- va_start(ap, format);
vfprintf(stderr, format, ap);
fputc('\n', stderr);
- va_end(ap);
}
- void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
+ void vdeprecationSupplemental(Loc loc, const(char)* format, va_list ap) { }
}
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 3e17ff4..a0c5472 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -1,12 +1,12 @@
/**
* Most of the logic to implement scoped pointers and scoped references is here.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/escape.d, _escape.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/escape.d, _escape.d)
* Documentation: https://dlang.org/phobos/dmd_escape.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/escape.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/escape.d
*/
module dmd.escape;
@@ -25,6 +25,7 @@ import dmd.dsymbol;
import dmd.errors;
import dmd.expression;
import dmd.func;
+import dmd.funcsem;
import dmd.globals : FeatureState;
import dmd.id;
import dmd.identifier;
@@ -33,6 +34,7 @@ import dmd.location;
import dmd.mtype;
import dmd.printast;
import dmd.rootobject;
+import dmd.safe;
import dmd.tokens;
import dmd.typesem : hasPointers, parameterStorageClass;
import dmd.visitor;
@@ -73,7 +75,7 @@ package(dmd) struct EscapeState
* `true` if error
*/
public
-bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
+bool checkMutableArguments(ref Scope sc, FuncDeclaration fd, TypeFunction tf,
Expression ethis, Expressions* arguments, bool gag)
{
enum log = false;
@@ -92,7 +94,8 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
struct EscapeBy
{
- EscapeByResults er;
+ VarDeclarations byref;
+ VarDeclarations byvalue;
Parameter param; // null if no Parameter for this argument
bool isMutable; // true if reference to mutable
}
@@ -150,14 +153,21 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
refs = true;
auto var = outerVars[i - (len - outerVars.length)];
eb.isMutable = var.type.isMutable();
- eb.er.pushRef(var, false);
+ eb.byref.push(var);
continue;
}
+ void onRef(VarDeclaration v, bool transition) { eb.byref.push(v); }
+ void onValue(VarDeclaration v) { eb.byvalue.push(v); }
+ void onFunc(FuncDeclaration fd, bool called) {}
+ void onExp(Expression e, bool transition) {}
+
+ scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+
if (refs)
- escapeByRef(arg, &eb.er);
+ escapeByRef(arg, er);
else
- escapeByValue(arg, &eb.er);
+ escapeByValue(arg, er);
}
void checkOnePair(size_t i, ref EscapeBy eb, ref EscapeBy eb2,
@@ -170,7 +180,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
if (!(eb.isMutable || eb2.isMutable))
return;
- if (!tf.islive && !(sc.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe()))
+ if (!tf.isLive && !(sc.useDIP1000 == FeatureState.enabled && sc.func && setFunctionToUnsafe(sc.func)))
return;
if (!gag)
@@ -193,7 +203,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
void escape(size_t i, ref EscapeBy eb, bool byval)
{
- foreach (VarDeclaration v; byval ? eb.er.byvalue : eb.er.byref)
+ foreach (VarDeclaration v; byval ? eb.byvalue : eb.byref)
{
if (log)
{
@@ -204,7 +214,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
continue;
foreach (ref eb2; escapeBy[i + 1 .. $])
{
- foreach (VarDeclaration v2; byval ? eb2.er.byvalue : eb2.er.byref)
+ foreach (VarDeclaration v2; byval ? eb2.byvalue : eb2.byref)
{
checkOnePair(i, eb, eb2, v, v2, byval);
}
@@ -231,7 +241,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
* `true` if any elements escaped
*/
public
-bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag)
+bool checkArrayLiteralEscape(ref Scope sc, ArrayLiteralExp ae, bool gag)
{
bool errors;
if (ae.basis)
@@ -255,7 +265,7 @@ bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag)
* `true` if any elements escaped
*/
public
-bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag)
+bool checkAssocArrayLiteralEscape(ref Scope sc, AssocArrayLiteralExp ae, bool gag)
{
bool errors;
foreach (ex; *ae.keys)
@@ -324,7 +334,7 @@ void printScopeFailure(E)(E printFunc, VarDeclaration v, int recursionLimit)
* `true` if pointers to the stack can escape via assignment
*/
public
-bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, VarDeclaration vPar, STC parStc, Expression arg, bool assertmsg, bool gag)
+bool checkParamArgumentEscape(ref Scope sc, FuncDeclaration fdc, Identifier parId, VarDeclaration vPar, STC parStc, Expression arg, bool assertmsg, bool gag)
{
enum log = false;
if (log) printf("checkParamArgumentEscape(arg: %s par: %s parSTC: %llx)\n",
@@ -335,22 +345,6 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
if (!arg.type.hasPointers())
return false;
- EscapeByResults er;
-
- escapeByValue(arg, &er);
-
- if (parStc & STC.scope_)
- {
- // These errors only apply to non-scope parameters
- // When the parameter is `scope`, only `checkScopeVarAddr` on `er.byref` is needed
- er.byfunc.setDim(0);
- er.byvalue.setDim(0);
- er.byexp.setDim(0);
- }
-
- if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
- return false;
-
bool result = false;
/* 'v' is assigned unsafely to 'par'
@@ -360,7 +354,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
if (assertmsg)
{
result |= sc.setUnsafeDIP1000(gag, arg.loc,
- desc ~ " `%s` assigned to non-scope parameter calling `assert()`", v);
+ "assigning" ~ desc ~ " `%s` to non-scope parameter calling `assert()`", v);
return;
}
@@ -368,9 +362,9 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
const(char)* msg =
(isThis) ? (desc ~ " `%s` calling non-scope member function `%s.%s()`") :
- (fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s` calling `%s`") :
- (fdc && !parId) ? (desc ~ " `%s` assigned to non-scope anonymous parameter calling `%s`") :
- (!fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s`") :
+ (fdc && parId) ? ("assigning " ~ desc ~ " `%s` to non-scope parameter `%s` calling `%s`") :
+ (fdc && !parId) ? ("assigning " ~ desc ~ " `%s` to non-scope anonymous parameter calling `%s`") :
+ (!fdc && parId) ? ("assigning " ~ desc ~ " `%s` to non-scope parameter `%s`") :
(desc ~ " `%s` assigned to non-scope anonymous parameter");
if (isThis ?
@@ -382,51 +376,45 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
}
}
- foreach (VarDeclaration v; er.byvalue)
+ void onValue(VarDeclaration v)
{
if (log) printf("byvalue %s\n", v.toChars());
- if (v.isDataseg())
- continue;
-
- Dsymbol p = v.toParent2();
+ if (parStc & STC.scope_)
+ return;
- notMaybeScope(v, vPar);
+ doNotInferScope(v, vPar);
if (v.isScope())
{
unsafeAssign!"scope variable"(v);
}
- else if (v.isTypesafeVariadicArray && p == sc.func)
- {
- unsafeAssign!"variadic variable"(v);
- }
}
- foreach (VarDeclaration v; er.byref)
+ void onRef(VarDeclaration v, bool retRefTransition)
{
if (log) printf("byref %s\n", v.toChars());
- if (v.isDataseg())
- continue;
Dsymbol p = v.toParent2();
- notMaybeScope(v, arg);
+ doNotInferScope(v, arg);
if (checkScopeVarAddr(v, arg, sc, gag))
{
result = true;
- continue;
+ return;
}
if (p == sc.func && !(parStc & STC.scope_))
{
unsafeAssign!"reference to local variable"(v);
- continue;
+ return;
}
}
- foreach (FuncDeclaration fd; er.byfunc)
+ void onFunc(FuncDeclaration fd, bool called)
{
//printf("fd = %s, %d\n", fd.toChars(), fd.tookAddressOf);
+ if (parStc & STC.scope_)
+ return;
VarDeclarations vars;
findAllOuterAccessedVariables(fd, &vars);
@@ -437,28 +425,29 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
Dsymbol p = v.toParent2();
- notMaybeScope(v, arg);
+ doNotInferScope(v, arg);
if ((v.isReference() || v.isScope()) && p == sc.func)
{
unsafeAssign!"reference to local"(v);
- continue;
+ return;
}
}
}
- if (!sc.func)
- return result;
-
- foreach (Expression ee; er.byexp)
+ void onExp(Expression ee, bool retRefTransition)
{
+ if (parStc & STC.scope_)
+ return;
const(char)* msg = parId ?
- "reference to stack allocated value returned by `%s` assigned to non-scope parameter `%s`" :
- "reference to stack allocated value returned by `%s` assigned to non-scope anonymous parameter";
+ "assigning reference to stack allocated value returned by `%s` to non-scope parameter `%s`" :
+ "assigning reference to stack allocated value returned by `%s` to non-scope anonymous parameter";
result |= sc.setUnsafeDIP1000(gag, ee.loc, msg, ee, parId);
}
+ scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+ escapeByValue(arg, er);
return result;
}
@@ -476,7 +465,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
* `true` if assignment to `firstArg` would cause an error
*/
public
-bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Parameter param, bool gag)
+bool checkParamArgumentReturn(ref Scope sc, Expression firstArg, Expression arg, Parameter param, bool gag)
{
enum log = false;
if (log) printf("checkParamArgumentReturn(firstArg: %s arg: %s)\n",
@@ -512,7 +501,7 @@ bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Pa
* `true` if construction would cause an escaping reference error
*/
public
-bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
+bool checkConstructorEscape(ref Scope sc, CallExp ce, bool gag)
{
enum log = false;
if (log) printf("checkConstructorEscape(%s, %s)\n", ce.toChars(), ce.type.toChars());
@@ -579,7 +568,7 @@ public
ReturnParamDest returnParamDest(TypeFunction tf, Type tthis)
{
assert(tf);
- if (tf.isctor)
+ if (tf.isCtor)
return ReturnParamDest.this_;
if (!tf.nextOf() || (tf.nextOf().ty != Tvoid))
@@ -609,7 +598,7 @@ ReturnParamDest returnParamDest(TypeFunction tf, Type tthis)
* `true` if pointers to the stack can escape via assignment
*/
public
-bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
+bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
{
enum log = false;
if (log) printf("checkAssignEscape(e: %s, byRef: %d)\n", e.toChars(), byRef);
@@ -624,17 +613,6 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
if (!e1.type.hasPointers())
return false;
- if (e1.isSliceExp())
- {
- if (VarDeclaration va = expToVariable(e1))
- {
- if (!va.type.toBasetype().isTypeSArray() || // treat static array slice same as a variable
- !va.type.hasPointers())
- return false;
- }
- else
- return false;
- }
/* The struct literal case can arise from the S(e2) constructor call:
* return S(e2);
@@ -645,17 +623,24 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
if (e1.isStructLiteralExp())
return false;
- VarDeclaration va = expToVariable(e1);
- EscapeByResults er;
-
- if (byRef)
- escapeByRef(e2, &er);
- else
- escapeByValue(e2, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
- return false;
+ int deref;
+ VarDeclaration va = expToVariable(e1, deref);
+ // transitive scope not implemented, so can't assign scope pointers to a dereferenced variable
+ if (deref > 0)
+ va = null;
+ if (e1.isSliceExp())
+ {
+ // slice-copy is not assigning a pointer, but copying array content
+ if (va)
+ {
+ if (!va.type.toBasetype().isTypeSArray() || // treat static array slice same as a variable
+ !va.type.hasPointers())
+ return false;
+ }
+ else
+ return false;
+ }
if (va && e.op == EXP.concatenateElemAssign)
{
@@ -669,23 +654,17 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
va = null;
}
- if (va && e1.isDotVarExp() && va.type.toBasetype().isTypeClass())
+ if (e.op == EXP.construct && va && (va.storage_class & STC.temp) && va._init)
{
- /* https://issues.dlang.org/show_bug.cgi?id=17949
- * Draw an equivalence between:
- * *q = p;
- * and:
- * va.field = e2;
- * since we are not assigning to va, but are assigning indirectly through class reference va.
- */
- va = null;
+ // Initializing a temporary is safe, `escapeExp` will forward such vars
+ // to their `va._init` if needed.
+ return false;
}
if (log && va) printf("va: %s\n", va.toChars());
FuncDeclaration fd = sc.func;
-
// Determine if va is a `ref` parameter, so it has a lifetime exceding the function scope
const bool vaIsRef = va && va.isParameter() && va.isReference();
if (log && vaIsRef) printf("va is ref `%s`\n", va.toChars());
@@ -701,7 +680,10 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
vaIsFirstRef = va == fd.vthis;
break;
case ReturnParamDest.firstArg:
- vaIsFirstRef = (*fd.parameters)[0] == va;
+ // While you'd expect fd.parameters[0] to exist in this case, the compiler-generated
+ // expression that initializes an `out int* p = null` is analyzed before fd.parameters
+ // is created, so we still do a null and length check
+ vaIsFirstRef = fd.parameters && 0 < fd.parameters.length && (*fd.parameters)[0] == va;
break;
case ReturnParamDest.returnVal:
break;
@@ -710,35 +692,22 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
if (log && vaIsFirstRef) printf("va is first ref `%s`\n", va.toChars());
bool result = false;
- foreach (VarDeclaration v; er.byvalue)
+ void onValue(VarDeclaration v)
{
if (log) printf("byvalue: %s\n", v.toChars());
- if (v.isDataseg())
- continue;
if (v == va)
- continue;
+ return;
Dsymbol p = v.toParent2();
- if (va && !vaIsRef && !va.isScope() && !v.isScope() &&
- !v.isTypesafeVariadicArray && !va.isTypesafeVariadicArray &&
- (va.isParameter() && va.maybeScope && v.isParameter() && v.maybeScope) &&
- p == fd)
- {
- /* Add v to va's list of dependencies
- */
- va.addMaybe(v);
- continue;
- }
-
if (vaIsFirstRef && p == fd)
{
inferReturn(fd, v, /*returnScope:*/ true);
}
if (!(va && va.isScope()) || vaIsRef)
- notMaybeScope(v, e);
+ doNotInferScope(v, e);
if (v.isScope())
{
@@ -746,7 +715,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
{
// va=v, where v is `return scope`
if (inferScope(va))
- continue;
+ return;
}
// If va's lifetime encloses v's, then error
@@ -757,25 +726,23 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
{
case EnclosedBy.none: assert(0);
case EnclosedBy.returnScope:
- msg = "scope variable `%s` assigned to return scope `%s`";
+ msg = "assigning scope variable `%s` to return scope `%s`";
break;
case EnclosedBy.longerScope:
- if (v.storage_class & STC.temp)
- continue;
- msg = "scope variable `%s` assigned to `%s` with longer lifetime";
+ msg = "assigning scope variable `%s` to `%s` with longer lifetime";
break;
case EnclosedBy.refVar:
- msg = "scope variable `%s` assigned to `ref` variable `%s` with longer lifetime";
+ msg = "assigning scope variable `%s` to `ref` variable `%s` with longer lifetime";
break;
case EnclosedBy.global:
- msg = "scope variable `%s` assigned to global variable `%s`";
+ msg = "assigning scope variable `%s` to global variable `%s`";
break;
}
if (sc.setUnsafeDIP1000(gag, ae.loc, msg, v, va))
{
result = true;
- continue;
+ return;
}
}
@@ -793,15 +760,9 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
if (isRefReturnScope(va.storage_class))
va.storage_class |= STC.returnScope;
}
- continue;
+ return;
}
- result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1);
- }
- else if (v.isTypesafeVariadicArray && p == fd)
- {
- if (inferScope(va))
- continue;
- result |= sc.setUnsafeDIP1000(gag, ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v, e1);
+ result |= sc.setUnsafeDIP1000(gag, ae.loc, "assigning scope variable `%s` to non-scope `%s`", v, e1);
}
else
{
@@ -809,20 +770,19 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
* It may escape via that assignment, therefore, v can never be 'scope'.
*/
//printf("no infer for %s in %s, %d\n", v.toChars(), fd.ident.toChars(), __LINE__);
- doNotInferScope(v, e);
+ if (!v.isParameter)
+ doNotInferScope(v, e);
}
}
- foreach (VarDeclaration v; er.byref)
+ void onRef(VarDeclaration v, bool retRefTransition)
{
if (log) printf("byref: %s\n", v.toChars());
- if (v.isDataseg())
- continue;
if (checkScopeVarAddr(v, ae, sc, gag))
{
result = true;
- continue;
+ return;
}
if (va && va.isScope() && !v.isReference())
@@ -834,7 +794,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
else
{
result |= sc.setUnsafeDIP1000(gag, ae.loc,
- "address of local variable `%s` assigned to return scope `%s`", v, va);
+ "assigning address of local variable `%s` to return scope `%s`", v, va);
}
}
@@ -849,32 +809,30 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
// If va's lifetime encloses v's, then error
if (va && !(vaIsFirstRef && v.isReturn()) && va.enclosesLifetimeOf(v))
{
- if (sc.setUnsafeDIP1000(gag, ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v, va))
+ if (sc.setUnsafeDIP1000(gag, ae.loc, "assigning address of variable `%s` to `%s` with longer lifetime", v, va))
{
result = true;
- continue;
+ return;
}
}
if (!(va && va.isScope()))
- notMaybeScope(v, e);
+ doNotInferScope(v, e);
if (p != sc.func)
- continue;
+ return;
if (inferScope(va))
{
if (v.isReturn() && !va.isReturn())
va.storage_class |= STC.return_ | STC.returninferred;
- continue;
+ return;
}
- if (e1.op == EXP.structLiteral)
- continue;
- result |= sc.setUnsafeDIP1000(gag, ae.loc, "reference to local variable `%s` assigned to non-scope `%s`", v, e1);
+ result |= sc.setUnsafeDIP1000(gag, ae.loc, "assigning reference to local variable `%s` to non-scope `%s`", v, e1);
}
- foreach (FuncDeclaration func; er.byfunc)
+ void onFunc(FuncDeclaration func, bool called)
{
if (log) printf("byfunc: %s, %d\n", func.toChars(), func.tookAddressOf);
VarDeclarations vars;
@@ -896,10 +854,10 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
Dsymbol p = v.toParent2();
if (!(va && va.isScope()))
- notMaybeScope(v, e);
+ doNotInferScope(v, e);
if (!(v.isReference() || v.isScope()) || p != fd)
- continue;
+ return;
if (va && !va.isDataseg() && (va.isScope() || va.maybeScope))
{
@@ -908,55 +866,41 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
*/
//if (!va.isScope())
//va.storage_class |= STC.scope_ | STC.scopeinferred;
- continue;
+ return;
}
result |= sc.setUnsafeDIP1000(gag, ae.loc,
- "reference to local `%s` assigned to non-scope `%s` in @safe code", v, e1);
+ "assigning reference to local `%s` to non-scope `%s`", v, e1);
}
}
- foreach (Expression ee; er.byexp)
+ void onExp(Expression ee, bool retRefTransition)
{
if (log) printf("byexp: %s\n", ee.toChars());
/* Do not allow slicing of a static array returned by a function
*/
- if (ee.op == EXP.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray() &&
- !(va && va.storage_class & STC.temp))
+ if (ee.op == EXP.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray())
{
if (!gag)
sc.eSink.deprecation(ee.loc, "slice of static array temporary returned by `%s` assigned to longer lived variable `%s`",
ee.toChars(), e1.toChars());
//result = true;
- continue;
+ return;
}
- if (ee.op == EXP.call && ee.type.toBasetype().isTypeStruct() &&
- (!va || !(va.storage_class & STC.temp) && !va.isScope()))
- {
- if (sc.setUnsafeDIP1000(gag, ee.loc, "address of struct temporary returned by `%s` assigned to longer lived variable `%s`", ee, e1))
- {
- result = true;
- continue;
- }
- }
+ const(char)* msg = (ee.op == EXP.structLiteral) ?
+ "assigning address of struct literal `%s` to `%s` with longer lifetime" :
+ "assigning address of expression temporary returned by `%s` to `%s` with longer lifetime";
- if (ee.op == EXP.structLiteral &&
- (!va || !(va.storage_class & STC.temp)))
- {
- if (sc.setUnsafeDIP1000(gag, ee.loc, "address of struct literal `%s` assigned to longer lived variable `%s`", ee, e1))
- {
- result = true;
- continue;
- }
- }
+ result |= sc.setUnsafeDIP1000(gag, ee.loc, msg, ee, e1);
+ }
- if (inferScope(va))
- continue;
+ scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
- result |= sc.setUnsafeDIP1000(gag, ee.loc,
- "reference to stack allocated value returned by `%s` assigned to non-scope `%s`", ee, e1);
- }
+ if (byRef)
+ escapeByRef(e2, er);
+ else
+ escapeByValue(e2, er);
return result;
}
@@ -973,35 +917,32 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
* `true` if pointers to the stack can escape
*/
public
-bool checkThrowEscape(Scope* sc, Expression e, bool gag)
+bool checkThrowEscape(ref Scope sc, Expression e, bool gag)
{
//printf("[%s] checkThrowEscape, e = %s\n", e.loc.toChars(), e.toChars());
- EscapeByResults er;
-
- escapeByValue(e, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
- return false;
bool result = false;
- foreach (VarDeclaration v; er.byvalue)
+ void onRef(VarDeclaration v, bool retRefTransition) {}
+ void onValue(VarDeclaration v)
{
//printf("byvalue %s\n", v.toChars());
- if (v.isDataseg())
- continue;
-
if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown
// despite being `scope`
{
// https://issues.dlang.org/show_bug.cgi?id=17029
- result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be thrown", v);
- continue;
+ result |= sc.setUnsafeDIP1000(gag, e.loc, "throwing scope variable `%s`", v);
+ return;
}
else
{
- notMaybeScope(v, new ThrowExp(e.loc, e));
+ doNotInferScope(v, new ThrowExp(e.loc, e));
}
}
+ void onFunc(FuncDeclaration fd, bool called) {}
+ void onExp(Expression exp, bool retRefTransition) {}
+
+ scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+ escapeByValue(e, er);
return result;
}
@@ -1017,7 +958,7 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag)
* `true` if pointers to the stack can escape
*/
public
-bool checkNewEscape(Scope* sc, Expression e, bool gag)
+bool checkNewEscape(ref Scope sc, Expression e, bool gag)
{
import dmd.globals: FeatureState;
import dmd.errors: previewErrorFunc;
@@ -1025,19 +966,11 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
//printf("[%s] checkNewEscape, e = %s\n", e.loc.toChars(), e.toChars());
enum log = false;
if (log) printf("[%s] checkNewEscape, e: `%s`\n", e.loc.toChars(), e.toChars());
- EscapeByResults er;
-
- escapeByValue(e, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
- return false;
bool result = false;
- foreach (VarDeclaration v; er.byvalue)
+ void onValue(VarDeclaration v)
{
if (log) printf("byvalue `%s`\n", v.toChars());
- if (v.isDataseg())
- continue;
Dsymbol p = v.toParent2();
@@ -1056,23 +989,18 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
!(p.parent == sc.func))
{
// https://issues.dlang.org/show_bug.cgi?id=20868
- result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be copied into allocated memory", v);
- continue;
+ result |= sc.setUnsafeDIP1000(gag, e.loc, "copying scope variable `%s` into allocated memory", v);
+ return;
}
}
- else if (v.isTypesafeVariadicArray && p == sc.func)
- {
- result |= sc.setUnsafeDIP1000(gag, e.loc,
- "copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e, v);
- }
else
{
//printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__);
- notMaybeScope(v, e);
+ doNotInferScope(v, e);
}
}
- foreach (VarDeclaration v; er.byref)
+ void onRef(VarDeclaration v, bool retRefTransition)
{
if (log) printf("byref `%s`\n", v.toChars());
@@ -1081,14 +1009,11 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
bool escapingRef(VarDeclaration v, FeatureState fs)
{
const(char)* msg = v.isParameter() ?
- "copying `%s` into allocated memory escapes a reference to parameter `%s`" :
- "copying `%s` into allocated memory escapes a reference to local variable `%s`";
- return sc.setUnsafePreview(fs, gag, e.loc, msg, e, v);
+ "escaping a reference to parameter `%s` by copying `%s` into allocated memory" :
+ "escaping a reference to local variable `%s` by copying `%s` into allocated memory";
+ return setUnsafePreview(&sc, fs, gag, e.loc, msg, v, e);
}
- if (v.isDataseg())
- continue;
-
Dsymbol p = v.toParent2();
if (!v.isReference())
@@ -1096,7 +1021,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
if (p == sc.func)
{
result |= escapingRef(v, sc.useDIP1000);
- continue;
+ return;
}
}
@@ -1104,7 +1029,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
* Infer the addition of 'return', or set result to be the offending expression.
*/
if (!v.isReference())
- continue;
+ return;
// https://dlang.org/spec/function.html#return-ref-parameters
if (p == sc.func)
@@ -1112,16 +1037,16 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
//printf("escaping reference to local ref variable %s\n", v.toChars());
//printf("storage class = x%llx\n", v.storage_class);
result |= escapingRef(v, sc.useDIP25);
- continue;
+ return;
}
// Don't need to be concerned if v's parent does not return a ref
FuncDeclaration func = p.isFuncDeclaration();
if (!func || !func.type)
- continue;
+ return;
if (auto tf = func.type.isTypeFunction())
{
- if (!tf.isref)
- continue;
+ if (!tf.isRef)
+ return;
const(char)* msg = "storing reference to outer local variable `%s` into allocated memory causes it to escape";
if (!gag)
@@ -1135,15 +1060,25 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
}
}
- foreach (Expression ee; er.byexp)
+ void onFunc(FuncDeclaration fd, bool called)
+ {
+ if (called)
+ result |= sc.setUnsafeDIP1000(gag, e.loc,
+ "escaping a `scope` value returned from nested function `%s` into allocated memory", fd);
+ }
+
+ void onExp(Expression ee, bool retRefTransition)
{
if (log) printf("byexp %s\n", ee.toChars());
if (!gag)
- sc.eSink.error(ee.loc, "storing reference to stack allocated value returned by `%s` into allocated memory causes it to escape",
+ sc.eSink.error(ee.loc, "escaping reference to stack allocated value returned by `%s` into allocated memory",
ee.toChars());
result = true;
}
+ scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+ escapeByValue(e, er);
+
return result;
}
@@ -1160,7 +1095,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
* `true` if pointers to the stack can escape
*/
public
-bool checkReturnEscape(Scope* sc, Expression e, bool gag)
+bool checkReturnEscape(ref Scope sc, Expression e, bool gag)
{
//printf("[%s] checkReturnEscape, e: %s\n", e.loc.toChars(), e.toChars());
return checkReturnEscapeImpl(sc, e, false, gag);
@@ -1178,7 +1113,7 @@ bool checkReturnEscape(Scope* sc, Expression e, bool gag)
* `true` if references to the stack can escape
*/
public
-bool checkReturnEscapeRef(Scope* sc, Expression e, bool gag)
+bool checkReturnEscapeRef(ref Scope sc, Expression e, bool gag)
{
version (none)
{
@@ -1200,26 +1135,15 @@ bool checkReturnEscapeRef(Scope* sc, Expression e, bool gag)
* Returns:
* `true` if references to the stack can escape
*/
-private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
+private bool checkReturnEscapeImpl(ref Scope sc, Expression e, bool refs, bool gag)
{
enum log = false;
if (log) printf("[%s] checkReturnEscapeImpl, refs: %d e: `%s`\n", e.loc.toChars(), refs, e.toChars());
- EscapeByResults er;
-
- if (refs)
- escapeByRef(e, &er);
- else
- escapeByValue(e, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
- return false;
bool result = false;
- foreach (VarDeclaration v; er.byvalue)
+ void onValue(VarDeclaration v)
{
if (log) printf("byvalue `%s`\n", v.toChars());
- if (v.isDataseg())
- continue;
const vsr = buildScopeRef(v.storage_class);
@@ -1227,17 +1151,23 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
if (p == sc.func && inferReturn(sc.func, v, /*returnScope:*/ true))
{
- continue;
+ return;
}
- if (v.isScope())
+ if (v.isTypesafeVariadicArray && p == sc.func)
+ {
+ if (!gag)
+ sc.eSink.error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars());
+ result = false;
+ }
+ else if (v.isScope())
{
/* If `return scope` applies to v.
*/
if (vsr == ScopeRef.ReturnScope ||
vsr == ScopeRef.Ref_ReturnScope)
{
- continue;
+ return;
}
auto pfunc = p.isFuncDeclaration();
@@ -1251,15 +1181,20 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
* return s; // s is inferred as 'scope' but incorrectly tested in foo()
* return null; }
*/
- !(!refs && p.parent == sc.func && pfunc.fes) &&
+ !(!refs && p.parent == sc.func && pfunc.fes)
+ )
+ {
/*
* auto p(scope string s) {
* string scfunc() { return s; }
* }
*/
- !(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0)
- )
- {
+ if (sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0 &&
+ inferReturn(sc.func, sc.func.vthis, /*returnScope*/ !refs))
+ {
+ return;
+ }
+
if (v.isParameter() && !v.isReturn())
{
// https://issues.dlang.org/show_bug.cgi?id=23191
@@ -1269,31 +1204,25 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
"scope parameter `%s` may not be returned", v.toChars()
);
result = true;
- continue;
+ return;
}
}
else
{
// https://issues.dlang.org/show_bug.cgi?id=17029
- result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be returned", v);
- continue;
+ result |= sc.setUnsafeDIP1000(gag, e.loc, "returning scope variable `%s`", v);
+ return;
}
}
}
- else if (v.isTypesafeVariadicArray && p == sc.func)
- {
- if (!gag)
- sc.eSink.error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars());
- result = false;
- }
- else
+ else if (p == sc.func || !v.isParameter())
{
//printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__);
doNotInferScope(v, e);
}
}
- foreach (i, VarDeclaration v; er.byref[])
+ void onRef(VarDeclaration v, bool retRefTransition)
{
if (log)
{
@@ -1304,13 +1233,12 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
// depending on the flag passed to the CLI for DIP25
void escapingRef(VarDeclaration v, FeatureState featureState)
{
- const(char)* msg = v.isParameter() ?
- "returning `%s` escapes a reference to parameter `%s`" :
- "returning `%s` escapes a reference to local variable `%s`";
-
+ const(char)* safeMsg = v.isParameter() ?
+ "escaping a reference to parameter `%s` by returning `%s`" :
+ "escaping a reference to local variable `%s` by returning `%s` ";
if (v.isParameter() && v.isReference())
{
- if (sc.setUnsafePreview(featureState, gag, e.loc, msg, e, v) ||
+ if (setUnsafePreview(&sc, featureState, gag, e.loc, safeMsg, v, e) ||
sc.func.isSafeBypassingInference())
{
result = true;
@@ -1329,12 +1257,15 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
}
else
{
- if (er.refRetRefTransition[i])
+ if (retRefTransition)
{
- result |= sc.setUnsafeDIP1000(gag, e.loc, msg, e, v);
+ result |= sc.setUnsafeDIP1000(gag, e.loc, safeMsg, v, e);
}
else
{
+ const(char)* msg = v.isParameter() ?
+ "returning `%s` escapes a reference to parameter `%s`" :
+ "returning `%s` escapes a reference to local variable `%s`";
if (!gag)
previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars());
result = true;
@@ -1342,24 +1273,15 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
}
}
- if (v.isDataseg())
- continue;
-
const vsr = buildScopeRef(v.storage_class);
Dsymbol p = v.toParent2();
// https://issues.dlang.org/show_bug.cgi?id=19965
- if (!refs)
+ if (!refs && checkScopeVarAddr(v, e, sc, gag))
{
- if (sc.func.vthis == v)
- notMaybeScope(v, e);
-
- if (checkScopeVarAddr(v, e, sc, gag))
- {
- result = true;
- continue;
- }
+ result = true;
+ return;
}
if (!v.isReference())
@@ -1367,10 +1289,10 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
if (p == sc.func)
{
escapingRef(v, FeatureState.enabled);
- continue;
+ return;
}
FuncDeclaration fd = p.isFuncDeclaration();
- if (fd && sc.func.returnInprocess)
+ if (fd && sc.func.scopeInprocess)
{
/* Code like:
* int x;
@@ -1386,15 +1308,14 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
/* Check for returning a ref variable by 'ref', but should be 'return ref'
* Infer the addition of 'return', or set result to be the offending expression.
*/
- if ((vsr == ScopeRef.Ref ||
+ if (vsr == ScopeRef.Ref ||
vsr == ScopeRef.RefScope ||
- vsr == ScopeRef.Ref_ReturnScope) &&
- !(v.storage_class & STC.foreach_))
+ vsr == ScopeRef.Ref_ReturnScope)
{
if (p == sc.func && (vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope) &&
inferReturn(sc.func, v, /*returnScope:*/ false))
{
- continue;
+ return;
}
else
{
@@ -1405,20 +1326,20 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
//printf("escaping reference to local ref variable %s\n", v.toChars());
//printf("storage class = x%llx\n", v.storage_class);
escapingRef(v, sc.useDIP25);
- continue;
+ return;
}
// Don't need to be concerned if v's parent does not return a ref
FuncDeclaration fd = p.isFuncDeclaration();
if (fd && fd.type && fd.type.ty == Tfunction)
{
TypeFunction tf = fd.type.isTypeFunction();
- if (tf.isref)
+ if (tf.isRef)
{
const(char)* msg = "escaping reference to outer local variable `%s`";
if (!gag)
previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars());
result = true;
- continue;
+ return;
}
}
@@ -1426,10 +1347,16 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
}
}
- foreach (i, Expression ee; er.byexp[])
+ void onFunc(FuncDeclaration fd, bool called)
+ {
+ if (called && fd.isNested())
+ result |= sc.setUnsafeDIP1000(gag, e.loc, "escaping local variable through nested function `%s`", fd);
+ }
+
+ void onExp(Expression ee, bool retRefTransition)
{
if (log) printf("byexp %s\n", ee.toChars());
- if (er.expRetRefTransition[i])
+ if (retRefTransition)
{
result |= sc.setUnsafeDIP1000(gag, ee.loc,
"escaping reference to stack allocated value returned by `%s`", ee);
@@ -1441,6 +1368,15 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
result = true;
}
}
+
+
+ scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+
+ if (refs)
+ escapeByRef(e, er);
+ else
+ escapeByValue(e, er);
+
return result;
}
@@ -1483,7 +1419,7 @@ private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
if (!v.isParameter() || v.isTypesafeVariadicArray || (returnScope && v.doNotInferReturn))
return false;
- if (!fd.returnInprocess)
+ if (!fd.scopeInprocess)
return false;
if (returnScope && !(v.isScope() || v.maybeScope))
@@ -1501,9 +1437,9 @@ private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
if (auto tf = fd.type.isTypeFunction())
{
//printf("'this' too %p %s\n", tf, sc.func.toChars());
- tf.isreturnscope = returnScope;
- tf.isreturn = true;
- tf.isreturninferred = true;
+ tf.isReturnScope = returnScope;
+ tf.isReturn = true;
+ tf.isReturnInferred = true;
}
}
else
@@ -1541,11 +1477,20 @@ private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
* Params:
* e = expression to be returned by value
* er = where to place collected data
- * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
- * retRefTransition = if `e` is returned through a `return ref scope` function call
*/
public
-void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
+void escapeByValue(Expression e, ref scope EscapeByResults er)
+{
+ escapeExp(e, er, 0);
+}
+
+// Unified implementation of `escapeByValue` and `escapeByRef`
+// deref = derference level, if `p` has deref 0, then `*p` has deref 1, `&p` has -1, and `**p` has 2 etc.
+// For escapeByValue, deref = 0
+// For escapeByRef, deref = -1
+// Currently, `scope` is not transitive, so deref > 0 means no escaping, but `@live` does do transitive checking,
+// and future enhancements might add some form of transitive scope.
+void escapeExp(Expression e, ref scope EscapeByResults er, int deref)
{
//printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars());
@@ -1559,62 +1504,99 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
* allowed, but CTFE can generate one out of a new expression,
* but it'll be placed in static data so no need to check it.
*/
- if (e.e1.op != EXP.structLiteral)
- escapeByRef(e.e1, er, live, retRefTransition);
+ if (deref == 0 && e.e1.op != EXP.structLiteral)
+ escapeExp(e.e1, er, deref - 1);
}
void visitSymOff(SymOffExp e)
{
- VarDeclaration v = e.var.isVarDeclaration();
- if (v)
- er.pushRef(v, retRefTransition);
+ if (VarDeclaration v = e.var.isVarDeclaration())
+ er.varDeref(v, deref - 1);
}
void visitVar(VarExp e)
{
if (auto v = e.var.isVarDeclaration())
{
- if (v.type.hasPointers() || // not tracking non-pointers
- v.storage_class & STC.lazy_) // lazy variables are actually pointers
- er.byvalue.push(v);
+ const refAddr = deref < 0 && v.storage_class & STC.ref_ ;
+ const tempVar = deref == 0 && v.storage_class & STC.temp;
+ if ((refAddr || tempVar) && v._init && v != er.lastTemp)
+ {
+ // If compiler generated ref temporary
+ // (ref v = ex; ex)
+ // e.g. to extract side effects of `Tuple!(int, int).modify().expand[0]`
+ // look at the initializer instead
+ if (ExpInitializer ez = v._init.isExpInitializer())
+ {
+ // Prevent endless loops. Consider:
+ // `__field0 = (S __tup1 = S(x, y);) , __field0 = __tup1.__fields_field_0`
+ // escapeExp would recurse on the lhs of the last assignment, which is __field0
+ // again. In this case, we want the rhs.
+ // Also consider appending a struct with a `return scope` constructor:
+ // __appendtmp34 = __appendtmp34.this(null)
+ // In that case we just break the cycle using `lastTemp`.
+ auto lc = ez.exp.lastComma();
+ auto restoreLastTemp = er.lastTemp;
+ er.lastTemp = v;
+ // printf("%s %s TO %s\n", e.loc.toChars, e.toChars, lc.toChars);
+ if (lc.isAssignExp || lc.isConstructExp || lc.isBlitExp)
+ escapeExp(lc.isBinExp().e2, er, deref);
+ else
+ escapeExp(ez.exp, er, deref);
+
+ er.lastTemp = restoreLastTemp;
+ return;
+ }
+ }
+
+ if (deref < 0 || e.type.hasPointers())
+ er.varDeref(v, deref);
}
}
void visitThis(ThisExp e)
{
+ // Special case because `__this2` isn't `ref` internally
+ if (deref == -1 && e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
+ {
+ escapeByValue(e, er);
+ return;
+ }
+
if (e.var)
- er.byvalue.push(e.var);
+ er.varDeref(e.var, deref);
}
void visitPtr(PtrExp e)
{
- if (live && e.type.hasPointers())
- escapeByValue(e.e1, er, live, retRefTransition);
+ if (deref < 0 || (er.live && e.type.hasPointers()))
+ escapeExp(e.e1, er, deref + 1);
}
void visitDotVar(DotVarExp e)
{
- auto t = e.e1.type.toBasetype();
- if (e.type.hasPointers() && (live || t.ty == Tstruct))
- {
- escapeByValue(e.e1, er, live, retRefTransition);
- }
+ auto t1b = e.e1.type.toBasetype();
+ // Accessing a class field dereferences the `this` pointer
+ if (t1b.isTypeClass())
+ escapeExp(e.e1, er, deref + 1);
+ else if (deref < 0 || e.type.hasPointers())
+ escapeExp(e.e1, er, deref);
}
void visitDelegate(DelegateExp e)
{
Type t = e.e1.type.toBasetype();
- if (t.ty == Tclass || t.ty == Tpointer)
- escapeByValue(e.e1, er, live, retRefTransition);
+ if (t.isTypeClass() || t.isTypePointer())
+ escapeByValue(e.e1, er);
else
- escapeByRef(e.e1, er, live, retRefTransition);
- er.byfunc.push(e.func);
+ escapeByRef(e.e1, er);
+ er.byFunc(e.func, false);
}
void visitFunc(FuncExp e)
{
if (e.fd.tok == TOK.delegate_)
- er.byfunc.push(e.fd);
+ er.byFunc(e.fd, false);
}
void visitTuple(TupleExp e)
@@ -1625,14 +1607,14 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
void visitArrayLiteral(ArrayLiteralExp e)
{
Type tb = e.type.toBasetype();
- if (tb.ty == Tsarray || tb.ty == Tarray)
+ if (tb.isStaticOrDynamicArray())
{
if (e.basis)
- escapeByValue(e.basis, er, live, retRefTransition);
+ escapeExp(e.basis, er, deref);
foreach (el; *e.elements)
{
if (el)
- escapeByValue(el, er, live, retRefTransition);
+ escapeExp(el, er, deref);
}
}
}
@@ -1644,120 +1626,130 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
foreach (ex; *e.elements)
{
if (ex)
- escapeByValue(ex, er, live, retRefTransition);
+ escapeExp(ex, er, deref);
}
}
+ if (deref == -1)
+ {
+ er.byExp(e, er.inRetRefTransition > 0); //
+ }
}
void visitNew(NewExp e)
{
+ if (e.placement)
+ escapeExp(e.placement, er, deref);
+
Type tb = e.newtype.toBasetype();
- if (tb.ty == Tstruct && !e.member && e.arguments)
+ if (tb.isTypeStruct() && !e.member && e.arguments)
{
foreach (ex; *e.arguments)
{
if (ex)
- escapeByValue(ex, er, live, retRefTransition);
+ escapeExp(ex, er, deref);
}
}
}
void visitCast(CastExp e)
{
- if (!e.type.hasPointers())
+ if (deref < 0 || !e.type.hasPointers())
return;
Type tb = e.type.toBasetype();
- if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray)
- {
- escapeByRef(e.e1, er, live, retRefTransition);
- }
+ if (tb.isTypeDArray() && e.e1.type.toBasetype().isTypeSArray())
+ escapeExp(e.e1, er, deref - 1);
else
- escapeByValue(e.e1, er, live, retRefTransition);
+ escapeExp(e.e1, er, deref);
}
void visitSlice(SliceExp e)
{
- if (auto ve = e.e1.isVarExp())
- {
- VarDeclaration v = ve.var.isVarDeclaration();
- Type tb = e.type.toBasetype();
- if (v)
- {
- if (tb.ty == Tsarray)
- return;
- if (v.isTypesafeVariadicArray)
- {
- er.byvalue.push(v);
- return;
- }
- }
- }
- Type t1b = e.e1.type.toBasetype();
- if (t1b.ty == Tsarray)
- {
- Type tb = e.type.toBasetype();
- if (tb.ty != Tsarray)
- escapeByRef(e.e1, er, live, retRefTransition);
- }
- else
- escapeByValue(e.e1, er, live, retRefTransition);
+ // Usually: slicing a static array escapes by ref, slicing a dynamic array escapes by value.
+ // However, slices with compile-time known length can implicitly converted to static arrays:
+ // int*[3] b = sa[0 .. 3];
+ // So we need to compare the type before slicing and after slicing
+ const bool staticBefore = e.e1.type.toBasetype().isTypeSArray() !is null;
+ const bool staticAfter = e.type.toBasetype().isTypeSArray() !is null;
+ escapeExp(e.e1, er, deref + staticAfter - staticBefore);
}
void visitIndex(IndexExp e)
{
- if (e.e1.type.toBasetype().ty == Tsarray ||
- live && e.type.hasPointers())
+ Type tb = e.e1.type.toBasetype();
+
+ if (tb.isTypeSArray())
{
- escapeByValue(e.e1, er, live, retRefTransition);
+ escapeExp(e.e1, er, deref);
+ }
+ else if (tb.isTypeDArray())
+ {
+ escapeExp(e.e1, er, deref + 1);
}
}
void visitBin(BinExp e)
{
- Type tb = e.type.toBasetype();
- if (tb.ty == Tpointer)
+ if (e.type.toBasetype().isTypePointer())
{
- escapeByValue(e.e1, er, live, retRefTransition);
- escapeByValue(e.e2, er, live, retRefTransition);
+ // The expression must be pointer arithmetic, e.g. `p + 1` or `1 + p`
+ escapeExp(e.e1, er, deref);
+ escapeExp(e.e2, er, deref);
}
}
void visitBinAssign(BinAssignExp e)
{
- escapeByValue(e.e1, er, live, retRefTransition);
+ escapeExp(e.e1, er, deref);
}
void visitAssign(AssignExp e)
{
- escapeByValue(e.e1, er, live, retRefTransition);
+ escapeExp(e.e1, er, deref);
}
void visitComma(CommaExp e)
{
- escapeByValue(e.e2, er, live, retRefTransition);
+ escapeExp(e.e2, er, deref);
}
void visitCond(CondExp e)
{
- escapeByValue(e.e1, er, live, retRefTransition);
- escapeByValue(e.e2, er, live, retRefTransition);
+ escapeExp(e.e1, er, deref);
+ escapeExp(e.e2, er, deref);
}
void visitCall(CallExp e)
{
//printf("CallExp(): %s\n", e.toChars());
- /* Check each argument that is
- * passed as 'return scope'.
- */
+ // Check each argument that is passed as 'return scope'.
TypeFunction tf = e.calledFunctionType();
- if (!tf || !e.type.hasPointers())
+ if (!tf)
+ return;
+
+ if (deref < 0 && !tf.isRef)
+ {
+ er.byExp(e, er.inRetRefTransition > 0);
return;
+ }
+
+ // A function may have a return scope struct parameter, but only return an `int` field of that struct
+ if (deref >= 0 && !e.type.hasPointers())
+ return;
+
+ /// Given a `scope` / `return scope` / `return ref` annotation,
+ /// get the corresponding pointer dereference level
+ static int paramDeref(ScopeRef psr)
+ {
+ return
+ (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) ? -1 :
+ (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) ? 0 :
+ +1;
+ }
if (e.arguments && e.arguments.length)
{
- /* j=1 if _arguments[] is first argument,
- * skip it because it is not passed by ref
- */
+ // j=1 if _arguments[] is first argument,
+ // skip it because it is not passed by ref
int j = tf.isDstyleVariadic();
for (size_t i = j; i < e.arguments.length; ++i)
{
@@ -1768,129 +1760,73 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
Parameter p = tf.parameterList[i - j];
const stc = tf.parameterStorageClass(null, p);
ScopeRef psr = buildScopeRef(stc);
- if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
- {
- if (tf.isref)
- {
- /* ignore `ref` on struct constructor return because
- * struct S { this(return scope int* q) { this.p = q; } int* p; }
- * is different from:
- * ref char* front(return scope char** q) { return *q; }
- * https://github.com/dlang/dmd/pull/14869
- */
- if (auto dve = e.e1.isDotVarExp())
- if (auto fd = dve.var.isFuncDeclaration())
- if (fd.isCtorDeclaration() && tf.next.toBasetype().isTypeStruct())
- {
- escapeByValue(arg, er, live, retRefTransition);
- }
- }
- else
- escapeByValue(arg, er, live, retRefTransition);
- }
- else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
- {
- if (tf.isref)
- {
- /* Treat:
- * ref P foo(return ref P p)
- * as:
- * p;
- */
- escapeByValue(arg, er, live, retRefTransition);
- }
- else
- escapeByRef(arg, er, live, retRefTransition);
- }
+
+ // For struct constructors, `tf.isRef` is true, but for escape analysis,
+ // it's as if they return `void` and escape through the first (`this`) parameter:
+ // void assign(ref S this, return scope constructorArgs...)
+ // If you then return the constructed result by value, it doesn't count
+ // as dereferencing the scope arguments, they're still escaped.
+ const isRef = tf.isRef && !(tf.isCtor && paramDeref(psr) == 0);
+ const maybeInaccurate = deref == 0 && paramDeref(psr) == 0;
+ er.inRetRefTransition += maybeInaccurate;
+ if (paramDeref(psr) <= 0)
+ escapeExp(arg, er, deref + paramDeref(psr) + isRef);
+ er.inRetRefTransition -= maybeInaccurate;
}
}
}
+
// If 'this' is returned, check it too
Type t1 = e.e1.type.toBasetype();
- if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction)
+ DotVarExp dve = e.e1.isDotVarExp();
+ if (dve && t1.ty == Tfunction)
{
- DotVarExp dve = e.e1.isDotVarExp();
FuncDeclaration fd = dve.var.isFuncDeclaration();
- if (fd && fd.isThis())
- {
- /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this`
- */
-
- /*****************************
- * Concoct storage class for member function's implicit `this` parameter.
- * Params:
- * fd = member function
- * Returns:
- * storage class for fd's `this`
- */
- StorageClass getThisStorageClass(FuncDeclaration fd)
- {
- StorageClass stc;
- auto tf = fd.type.toBasetype().isTypeFunction();
- if (tf.isreturn)
- stc |= STC.return_;
- if (tf.isreturnscope)
- stc |= STC.returnScope | STC.scope_;
- auto ad = fd.isThis();
- if (ad.isClassDeclaration() || tf.isScopeQual)
- stc |= STC.scope_;
- if (ad.isStructDeclaration())
- stc |= STC.ref_; // `this` for a struct member function is passed by `ref`
- return stc;
- }
-
- const psr = buildScopeRef(getThisStorageClass(fd));
- if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
- {
- if (!tf.isref || tf.isctor)
- escapeByValue(dve.e1, er, live, retRefTransition);
- }
- else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
- {
- if (tf.isref)
- {
- /* Treat calling:
- * struct S { ref S foo() return; }
- * as:
- * this;
- */
- escapeByValue(dve.e1, er, live, retRefTransition);
- }
- else
- escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope);
- }
- }
+ if (!fd)
+ return;
- // If it's also a nested function that is 'return scope'
- if (fd && fd.isNested())
+ // https://issues.dlang.org/show_bug.cgi?id=20149#c10
+ if (deref < 0 && dve.var.isCtorDeclaration())
{
- if (tf.isreturn && tf.isScopeQual)
- er.pushExp(e, false);
+ er.byExp(e, false);
+ return;
}
+
+ // Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this`
+ const psr = buildScopeRef(getThisStorageClass(fd));
+ er.inRetRefTransition += (psr == ScopeRef.ReturnRef_Scope);
+ if (paramDeref(psr) <= 0)
+ escapeExp(dve.e1, er, deref + paramDeref(psr) + (tf.isRef && !tf.isCtor));
+ er.inRetRefTransition -= (psr == ScopeRef.ReturnRef_Scope);
}
- /* If returning the result of a delegate call, the .ptr
- * field of the delegate must be checked.
- */
- if (t1.isTypeDelegate())
+ // The return value of a delegate call with return (scope) may point to a closure variable,
+ // so escape the delegate in case it's `scope` / stack allocated.
+ if (t1.isTypeDelegate() && tf.isReturn)
{
- if (tf.isreturn)
- escapeByValue(e.e1, er, live, retRefTransition);
+ escapeExp(e.e1, er, deref + tf.isRef);
}
- /* If it's a nested function that is 'return scope'
- */
+ // If `fd` is a nested function that's return ref / return scope, check that
+ // it doesn't escape closure vars
if (auto ve = e.e1.isVarExp())
{
- FuncDeclaration fd = ve.var.isFuncDeclaration();
- if (fd && fd.isNested())
+ if (FuncDeclaration fd = ve.var.isFuncDeclaration())
{
- if (tf.isreturn && tf.isScopeQual)
- er.pushExp(e, false);
+ if (fd.isNested() && tf.isReturn)
+ {
+ er.byFunc(fd, true);
+ }
}
}
}
+ if (deref > 0 && !er.live)
+ return; // scope is not transitive currently, so dereferencing expressions don't escape
+
+ if (deref >= 0 && er.live && !e.type.hasPointers())
+ return; // can't escape non-pointer values by value
+
switch (e.op)
{
case EXP.address: return visitAddr(e.isAddrExp());
@@ -1915,14 +1851,36 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
case EXP.question: return visitCond(e.isCondExp());
case EXP.call: return visitCall(e.isCallExp());
default:
- if (auto b = e.isBinExp())
- return visitBin(b);
if (auto ba = e.isBinAssignExp())
return visitBinAssign(ba);
+ if (auto b = e.isBinExp())
+ return visitBin(b);
return visit(e);
}
}
+/*****************************
+ * Concoct storage class for member function's implicit `this` parameter.
+ * Params:
+ * fd = member function
+ * Returns:
+ * storage class for fd's `this`
+ */
+STC getThisStorageClass(FuncDeclaration fd)
+{
+ STC stc;
+ auto tf = fd.type.toBasetype().isTypeFunction();
+ if (tf.isReturn)
+ stc |= STC.return_;
+ if (tf.isReturnScope)
+ stc |= STC.returnScope | STC.scope_;
+ auto ad = fd.isThis();
+ if ((ad && ad.isClassDeclaration()) || tf.isScopeQual)
+ stc |= STC.scope_;
+ if (ad && ad.isStructDeclaration())
+ stc |= STC.ref_; // `this` for a struct member function is passed by `ref`
+ return stc;
+}
/****************************************
* e is an expression to be returned by 'ref'.
@@ -1940,239 +1898,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
* Params:
* e = expression to be returned by 'ref'
* er = where to place collected data
- * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
- * retRefTransition = if `e` is returned through a `return ref scope` function call
*/
-private
-void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
+void escapeByRef(Expression e, ref scope EscapeByResults er)
{
- //printf("[%s] escapeByRef, e: %s, retRefTransition: %d\n", e.loc.toChars(), e.toChars(), retRefTransition);
- void visit(Expression e)
- {
- }
-
- void visitVar(VarExp e)
- {
- auto v = e.var.isVarDeclaration();
- if (v)
- {
- if (v.storage_class & STC.ref_ && v.storage_class & (STC.foreach_ | STC.temp) && v._init)
- {
- /* If compiler generated ref temporary
- * (ref v = ex; ex)
- * look at the initializer instead
- */
- if (ExpInitializer ez = v._init.isExpInitializer())
- {
- if (auto ce = ez.exp.isConstructExp())
- escapeByRef(ce.e2, er, live, retRefTransition);
- else
- escapeByRef(ez.exp, er, live, retRefTransition);
- }
- }
- else
- er.pushRef(v, retRefTransition);
- }
- }
-
- void visitThis(ThisExp e)
- {
- if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
- escapeByValue(e, er, live, retRefTransition);
- else if (e.var)
- er.pushRef(e.var, retRefTransition);
- }
-
- void visitPtr(PtrExp e)
- {
- escapeByValue(e.e1, er, live, retRefTransition);
- }
-
- void visitIndex(IndexExp e)
- {
- Type tb = e.e1.type.toBasetype();
- if (auto ve = e.e1.isVarExp())
- {
- VarDeclaration v = ve.var.isVarDeclaration();
- if (v && v.isTypesafeVariadicArray)
- {
- er.pushRef(v, retRefTransition);
- return;
- }
- }
- if (tb.ty == Tsarray)
- {
- escapeByRef(e.e1, er, live, retRefTransition);
- }
- else if (tb.ty == Tarray)
- {
- escapeByValue(e.e1, er, live, retRefTransition);
- }
- }
-
- void visitStructLiteral(StructLiteralExp e)
- {
- if (e.elements)
- {
- foreach (ex; *e.elements)
- {
- if (ex)
- escapeByRef(ex, er, live, retRefTransition);
- }
- }
- er.pushExp(e, retRefTransition);
- }
-
- void visitDotVar(DotVarExp e)
- {
- Type t1b = e.e1.type.toBasetype();
- if (t1b.ty == Tclass)
- escapeByValue(e.e1, er, live, retRefTransition);
- else
- escapeByRef(e.e1, er, live, retRefTransition);
- }
-
- void visitBinAssign(BinAssignExp e)
- {
- escapeByRef(e.e1, er, live, retRefTransition);
- }
-
- void visitAssign(AssignExp e)
- {
- escapeByRef(e.e1, er, live, retRefTransition);
- }
-
- void visitComma(CommaExp e)
- {
- escapeByRef(e.e2, er, live, retRefTransition);
- }
-
- void visitCond(CondExp e)
- {
- escapeByRef(e.e1, er, live, retRefTransition);
- escapeByRef(e.e2, er, live, retRefTransition);
- }
-
- void visitCall(CallExp e)
- {
- //printf("escapeByRef.CallExp(): %s\n", e.toChars());
- /* If the function returns by ref, check each argument that is
- * passed as 'return ref'.
- */
- TypeFunction tf = e.calledFunctionType();
- if (!tf)
- return;
- if (tf.isref)
- {
- if (e.arguments && e.arguments.length)
- {
- /* j=1 if _arguments[] is first argument,
- * skip it because it is not passed by ref
- */
- int j = tf.isDstyleVariadic();
- for (size_t i = j; i < e.arguments.length; ++i)
- {
- Expression arg = (*e.arguments)[i];
- size_t nparams = tf.parameterList.length;
- if (i - j < nparams && i >= j)
- {
- Parameter p = tf.parameterList[i - j];
- const stc = tf.parameterStorageClass(null, p);
- ScopeRef psr = buildScopeRef(stc);
- if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
- escapeByRef(arg, er, live, retRefTransition);
- else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
- {
- if (auto de = arg.isDelegateExp())
- {
- if (de.func.isNested())
- er.pushExp(de, false);
- }
- else
- escapeByValue(arg, er, live, retRefTransition);
- }
- }
- }
- }
- // If 'this' is returned by ref, check it too
- Type t1 = e.e1.type.toBasetype();
- if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction)
- {
- DotVarExp dve = e.e1.isDotVarExp();
-
- // https://issues.dlang.org/show_bug.cgi?id=20149#c10
- if (dve.var.isCtorDeclaration())
- {
- er.pushExp(e, false);
- return;
- }
-
- StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_);
- if (tf.isreturn)
- stc |= STC.return_;
- if (tf.isref)
- stc |= STC.ref_;
- if (tf.isScopeQual)
- stc |= STC.scope_;
- if (tf.isreturnscope)
- stc |= STC.returnScope;
-
- const psr = buildScopeRef(stc);
- if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
- escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope);
- else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
- escapeByValue(dve.e1, er, live, retRefTransition);
-
- // If it's also a nested function that is 'return ref'
- if (FuncDeclaration fd = dve.var.isFuncDeclaration())
- {
- if (fd.isNested() && tf.isreturn)
- {
- er.pushExp(e, false);
- }
- }
- }
- // If it's a delegate, check it too
- if (e.e1.op == EXP.variable && t1.ty == Tdelegate)
- {
- escapeByValue(e.e1, er, live, retRefTransition);
- }
-
- /* If it's a nested function that is 'return ref'
- */
- if (auto ve = e.e1.isVarExp())
- {
- FuncDeclaration fd = ve.var.isFuncDeclaration();
- if (fd && fd.isNested())
- {
- if (tf.isreturn)
- er.pushExp(e, false);
- }
- }
- }
- else
- er.pushExp(e, retRefTransition);
- }
-
- switch (e.op)
- {
- case EXP.variable: return visitVar(e.isVarExp());
- case EXP.this_: return visitThis(e.isThisExp());
- case EXP.star: return visitPtr(e.isPtrExp());
- case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
- case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
- case EXP.index: return visitIndex(e.isIndexExp());
- case EXP.blit: return visitAssign(e.isBlitExp());
- case EXP.construct: return visitAssign(e.isConstructExp());
- case EXP.assign: return visitAssign(e.isAssignExp());
- case EXP.comma: return visitComma(e.isCommaExp());
- case EXP.question: return visitCond(e.isCondExp());
- case EXP.call: return visitCall(e.isCallExp());
- default:
- if (auto ba = e.isBinAssignExp())
- return visitBinAssign(ba);
- return visit(e);
- }
+ escapeExp(e, er, -1);
}
/************************************
@@ -2181,15 +1910,8 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
public
struct EscapeByResults
{
- VarDeclarations byref; // array into which variables being returned by ref are inserted
- VarDeclarations byvalue; // array into which variables with values containing pointers are inserted
- private FuncDeclarations byfunc; // nested functions that are turned into delegates
- private Expressions byexp; // array into which temporaries being returned by ref are inserted
-
- import dmd.root.array: Array;
-
- /**
- * Whether the variable / expression went through a `return ref scope` function call
+ /*
+ * retRefTransition = Whether the variable / expression went through a `return (ref) scope` function call
*
* This is needed for the dip1000 by default transition, since the rules for
* disambiguating `return scope ref` have changed. Therefore, functions in legacy code
@@ -2197,46 +1919,48 @@ struct EscapeByResults
* are being escaped, which is an error even in `@system` code. By keeping track of this
* information, variables escaped through `return ref` can be treated as a deprecation instead
* of error, see test/fail_compilation/dip1000_deprecation.d
+ *
+ * Additionally, return scope can be inferred wrongly instead of scope, in which
+ * case the code could give false positives even without @safe or dip1000:
+ * https://issues.dlang.org/show_bug.cgi?id=23657
*/
- private Array!bool refRetRefTransition;
- private Array!bool expRetRefTransition;
-
- /** Reset arrays so the storage can be used again
- */
- void reset()
- {
- byref.setDim(0);
- byvalue.setDim(0);
- byfunc.setDim(0);
- byexp.setDim(0);
- refRetRefTransition.setDim(0);
- expRetRefTransition.setDim(0);
- }
+ /// called on variables being returned by ref / address
+ void delegate(VarDeclaration, bool retRefTransition) byRef;
+ /// called on variables with values containing pointers
+ void delegate(VarDeclaration) byValue;
- /**
- * Escape variable `v` by reference
- * Params:
- * v = variable to escape
- * retRefTransition = `v` is escaped through a `return ref scope` function call
- */
- void pushRef(VarDeclaration v, bool retRefTransition)
+ /// Switch over `byValue` and `byRef` based on `deref` level (-1 = by ref, 0 = by value, 1 = only for live currently)
+ private void varDeref(VarDeclaration var, int deref)
{
- byref.push(v);
- refRetRefTransition.push(retRefTransition);
- }
-
- /**
- * Escape a reference to expression `e`
- * Params:
- * e = expression to escape
- * retRefTransition = `e` is escaped through a `return ref scope` function call
- */
- void pushExp(Expression e, bool retRefTransition)
- {
- byexp.push(e);
- expRetRefTransition.push(retRefTransition);
- }
+ if (var.isDataseg())
+ return;
+ if (deref == -1)
+ byRef(var, inRetRefTransition > 0);
+ else if (deref == 0)
+ byValue(var);
+ else if (deref > 0 && live)
+ byValue(var);
+ }
+
+ /// called on nested functions that are turned into delegates
+ /// When `called` is true, it means the delegate escapes variables
+ /// from the closure through a call to it, while `false` means the
+ /// delegate itself escapes.
+ void delegate(FuncDeclaration, bool called) byFunc;
+ /// called when expression temporaries are being returned by ref / address
+ void delegate(Expression, bool retRefTransition) byExp;
+
+ /// if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
+ bool live = false;
+
+ /// Incremented / decremented every time an ambiguous return ref/scope parameter is checked.
+ /// See retRefTransition above.
+ private int inRetRefTransition = 0;
+
+ /// When forwarding a temp var to its initializer,
+ /// keep track of the temp var to break endless loops
+ private VarDeclaration lastTemp = null;
}
/*************************
@@ -2280,7 +2004,7 @@ public void findAllOuterAccessedVariables(FuncDeclaration fd, VarDeclarations* v
* - `VarDeclaration` of a non-scope parameter it was assigned to
* - `null` for no reason
*/
-private void notMaybeScope(VarDeclaration v, RootObject o)
+private void doNotInferScope(VarDeclaration v, RootObject o)
{
if (v.maybeScope)
{
@@ -2291,23 +2015,6 @@ private void notMaybeScope(VarDeclaration v, RootObject o)
}
/***********************************
- * Turn off `maybeScope` for variable `v` if it's not a parameter.
- *
- * This is for compatibility with the old system with both `STC.maybescope` and `VarDeclaration.doNotInferScope`,
- * which is now just `VarDeclaration.maybeScope`.
- * This function should probably be removed in future refactors.
- *
- * Params:
- * v = variable
- * o = reason for it being turned off
- */
-private void doNotInferScope(VarDeclaration v, RootObject o)
-{
- if (!v.isParameter)
- notMaybeScope(v, o);
-}
-
-/***********************************
* After semantic analysis of the function body,
* try to infer `scope` / `return` on the parameters
*
@@ -2319,48 +2026,21 @@ private void doNotInferScope(VarDeclaration v, RootObject o)
public
void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
{
-
- if (funcdecl.returnInprocess)
- {
- funcdecl.returnInprocess = false;
- if (funcdecl.storage_class & STC.return_)
- {
- if (funcdecl.type == f)
- f = cast(TypeFunction)f.copy();
- f.isreturn = true;
- f.isreturnscope = cast(bool) (funcdecl.storage_class & STC.returnScope);
- if (funcdecl.storage_class & STC.returninferred)
- f.isreturninferred = true;
- }
- }
-
- if (!funcdecl.inferScope)
+ if (!funcdecl.scopeInprocess)
return;
- funcdecl.inferScope = false;
+ funcdecl.scopeInprocess = false;
- // Eliminate maybescope's
+ if (funcdecl.storage_class & STC.return_)
{
- // Create and fill array[] with maybe candidates from the `this` and the parameters
- VarDeclaration[10] tmp = void;
- size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.length : 0);
-
- import dmd.common.smallbuffer : SmallBuffer;
- auto sb = SmallBuffer!VarDeclaration(dim, tmp[]);
- VarDeclaration[] array = sb[];
-
- size_t n = 0;
- if (funcdecl.vthis)
- array[n++] = funcdecl.vthis;
- if (funcdecl.parameters)
- {
- foreach (v; *funcdecl.parameters)
- {
- array[n++] = v;
- }
- }
- eliminateMaybeScopes(array[0 .. n]);
+ if (funcdecl.type == f)
+ f = cast(TypeFunction)f.copy();
+ f.isReturn = true;
+ f.isReturnScope = cast(bool) (funcdecl.storage_class & STC.returnScope);
+ if (funcdecl.storage_class & STC.returninferred)
+ f.isReturnInferred = true;
}
+
// Infer STC.scope_
if (funcdecl.parameters && !funcdecl.errors)
{
@@ -2380,65 +2060,10 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
{
inferScope(funcdecl.vthis);
f.isScopeQual = funcdecl.vthis.isScope();
- f.isscopeinferred = !!(funcdecl.vthis.storage_class & STC.scopeinferred);
+ f.isScopeInferred = !!(funcdecl.vthis.storage_class & STC.scopeinferred);
}
}
-/**********************************************
- * Have some variables that are maybescopes that were
- * assigned values from other maybescope variables.
- * Now that semantic analysis of the function is
- * complete, we can finalize this by turning off
- * maybescope for array elements that cannot be scope.
- *
- * $(TABLE2 Scope Table,
- * $(THEAD `va`, `v`, =>, `va` , `v` )
- * $(TROW maybe, maybe, =>, scope, scope)
- * $(TROW scope, scope, =>, scope, scope)
- * $(TROW scope, maybe, =>, scope, scope)
- * $(TROW maybe, scope, =>, scope, scope)
- * $(TROW - , - , =>, - , - )
- * $(TROW - , maybe, =>, - , - )
- * $(TROW - , scope, =>, error, error)
- * $(TROW maybe, - , =>, scope, - )
- * $(TROW scope, - , =>, scope, - )
- * )
- * Params:
- * array = array of variables that were assigned to from maybescope variables
- */
-private void eliminateMaybeScopes(VarDeclaration[] array)
-{
- enum log = false;
- if (log) printf("eliminateMaybeScopes()\n");
- bool changes;
- do
- {
- changes = false;
- foreach (va; array)
- {
- if (log) printf(" va = %s\n", va.toChars());
- if (!(va.maybeScope || va.isScope()))
- {
- if (va.maybes)
- {
- foreach (v; *va.maybes)
- {
- if (log) printf(" v = %s\n", v.toChars());
- if (v.maybeScope)
- {
- // v cannot be scope since it is assigned to a non-scope va
- notMaybeScope(v, va);
- if (!v.isReference())
- v.storage_class &= ~(STC.return_ | STC.returninferred);
- changes = true;
- }
- }
- }
- }
- }
- } while (changes);
-}
-
/************************************************
* Is type a reference to a mutable value?
*
@@ -2566,30 +2191,12 @@ private EnclosedBy enclosesLifetimeOf(VarDeclaration va, VarDeclaration v)
return EnclosedBy.none;
}
-/***************************************
- * Add variable `v` to maybes[]
- *
- * When a maybescope variable `v` is assigned to a maybescope variable `va`,
- * we cannot determine if `this` is actually scope until the semantic
- * analysis for the function is completed. Thus, we save the data
- * until then.
- * Params:
- * v = a variable with `maybeScope == true` that was assigned to `this`
- */
-private void addMaybe(VarDeclaration va, VarDeclaration v)
-{
- //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars());
- if (!va.maybes)
- va.maybes = new VarDeclarations();
- va.maybes.push(v);
-}
-
// `setUnsafePreview` partially evaluated for dip1000
public
-bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg,
- RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
+bool setUnsafeDIP1000(ref Scope sc, bool gag, Loc loc, const(char)* msg,
+ RootObject[] args...)
{
- return setUnsafePreview(sc, sc.useDIP1000, gag, loc, msg, arg0, arg1, arg2);
+ return setUnsafePreview(&sc, sc.useDIP1000, gag, loc, msg, args);
}
/***************************************
@@ -2606,14 +2213,11 @@ bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg,
* Returns:
* true if taking the address of `v` is problematic because of the lack of transitive `scope`
*/
-private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool gag)
+private bool checkScopeVarAddr(VarDeclaration v, Expression e, ref Scope sc, bool gag)
{
- if (v.storage_class & STC.temp)
- return false;
-
if (!v.isScope())
{
- notMaybeScope(v, e);
+ doNotInferScope(v, e);
return false;
}
@@ -2629,7 +2233,7 @@ private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool g
// take address of `scope` variable not allowed, requires transitive scope
return sc.setUnsafeDIP1000(gag, e.loc,
- "cannot take address of `scope` variable `%s` since `scope` applies to first indirection only", v);
+ "taking address of `scope` variable `%s` with pointers", v);
}
/****************************
@@ -2644,7 +2248,7 @@ private bool isTypesafeVariadicArray(VarDeclaration v)
if (v.storage_class & STC.variadic)
{
Type tb = v.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
return true;
}
return false;
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 479ad3a..d65b163 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -3,12 +3,12 @@
*
* Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expression.d, _expression.d)
* Documentation: https://dlang.org/phobos/dmd_expression.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/expression.d
*/
module dmd.expression;
@@ -21,6 +21,7 @@ import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dimport;
@@ -53,29 +54,6 @@ import dmd.visitor;
enum LOGSEMANTIC = false;
-/// Return value for `checkModifiable`
-enum Modifiable
-{
- /// Not modifiable
- no,
- /// Modifiable (the type is mutable)
- yes,
- /// Modifiable because it is initialization
- initialization,
-}
-/**
- * Specifies how the checkModify deals with certain situations
- */
-enum ModifyFlags
-{
- /// Issue error messages on invalid modifications of the variable
- none,
- /// No errors are emitted for invalid modifications
- noError = 0x1,
- /// The modification occurs for a subfield of the current variable
- fieldAssign = 0x2,
-}
-
/****************************************
* Find the last non-comma expression.
* Params:
@@ -225,7 +203,7 @@ TemplateDeclaration getFuncTemplateDecl(Dsymbol s) @safe
* (foo).size
* cast(foo).size
*/
-DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident) @safe
+DotIdExp typeDotIdExp(Loc loc, Type type, Identifier ident) @safe
{
return new DotIdExp(loc, new TypeExp(loc, type), ident);
}
@@ -236,45 +214,49 @@ DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident) @safe
* For example, `a[index]` is really `a`, and `s.f` is really `s`.
* Params:
* e = Expression to look at
+ * deref = number of dereferences encountered
* Returns:
* variable if there is one, null if not
*/
-VarDeclaration expToVariable(Expression e)
+VarDeclaration expToVariable(Expression e, out int deref)
{
+ deref = 0;
while (1)
{
switch (e.op)
{
case EXP.variable:
- return (cast(VarExp)e).var.isVarDeclaration();
+ return e.isVarExp().var.isVarDeclaration();
case EXP.dotVariable:
- e = (cast(DotVarExp)e).e1;
+ e = e.isDotVarExp().e1;
+ if (e.type.toBasetype().isTypeClass())
+ deref++;
+
continue;
case EXP.index:
{
- IndexExp ei = cast(IndexExp)e;
- e = ei.e1;
- Type ti = e.type.toBasetype();
- if (ti.ty == Tsarray)
- continue;
- return null;
+ e = e.isIndexExp().e1;
+ if (!e.type.toBasetype().isTypeSArray())
+ deref++;
+
+ continue;
}
case EXP.slice:
{
- SliceExp ei = cast(SliceExp)e;
- e = ei.e1;
- Type ti = e.type.toBasetype();
- if (ti.ty == Tsarray)
- continue;
- return null;
+ e = e.isSliceExp().e1;
+ if (!e.type.toBasetype().isTypeSArray())
+ deref++;
+
+ continue;
}
- case EXP.this_:
case EXP.super_:
- return (cast(ThisExp)e).var.isVarDeclaration();
+ return e.isSuperExp().var.isVarDeclaration();
+ case EXP.this_:
+ return e.isThisExp().var.isVarDeclaration();
// Temporaries for rvalues that need destruction
// are of form: (T s = rvalue, s). For these cases
@@ -311,12 +293,24 @@ enum WANTexpand = 1; // expand const/immutable variables if possible
*/
extern (C++) abstract class Expression : ASTNode
{
- Type type; // !=null means that semantic() has been run
+ /// Usually, this starts out as `null` and gets set to the final expression type by
+ /// `expressionSemantic`. However, for some expressions (such as `TypeExp`,`RealExp`,
+ /// `VarExp`), the field can get set to an assigned type before running semantic.
+ /// See `expressionSemanticDone`
+ Type type;
+
Loc loc; // file location
const EXP op; // to minimize use of dynamic_cast
+
+ static struct BitFields
+ {
bool parens; // if this is a parenthesized expression
+ bool rvalue; // true if this is considered to be an rvalue, even if it is an lvalue
+ }
+ import dmd.common.bitfields;
+ mixin(generateBitFields!(BitFields, ubyte));
- extern (D) this(const ref Loc loc, EXP op) scope @safe
+ extern (D) this(Loc loc, EXP op) scope @safe
{
//printf("Expression::Expression(op = %d) this = %p\n", op, this);
this.loc = loc;
@@ -387,8 +381,12 @@ extern (C++) abstract class Expression : ASTNode
return DYNCAST.expression;
}
- override const(char)* toChars() const
+ final override const(char)* toChars() const
{
+ // FIXME: mangling (see runnable/mangle.d) relies on toChars outputting __lambdaXXX here
+ if (auto fe = isFuncExp())
+ return fe.fd.toChars();
+
return .toChars(this);
}
@@ -426,7 +424,7 @@ extern (C++) abstract class Expression : ASTNode
* is returned via e0.
* Otherwise 'e' is directly returned and e0 is set to NULL.
*/
- extern (D) static Expression extractLast(Expression e, out Expression e0) @safe
+ extern (D) static Expression extractLast(Expression e, out Expression e0) @trusted
{
if (e.op != EXP.comma)
{
@@ -473,7 +471,7 @@ extern (C++) abstract class Expression : ASTNode
dinteger_t toInteger()
{
//printf("Expression %s\n", EXPtoString(op).ptr);
- if (!type.isTypeError())
+ if (!type || !type.isTypeError())
error(loc, "integer constant expression expected instead of `%s`", toChars());
return 0;
}
@@ -528,117 +526,6 @@ extern (C++) abstract class Expression : ASTNode
return false;
}
- /****************************************
- * Check that the expression has a valid value.
- * If not, generates an error "... has no value".
- * Returns:
- * true if the expression is not valid or has void type.
- */
- bool checkValue()
- {
- if (type && type.toBasetype().ty == Tvoid)
- {
- error(loc, "expression `%s` is `void` and has no value", toChars());
- //print(); assert(0);
- if (!global.gag)
- type = Type.terror;
- return true;
- }
- return false;
- }
-
- extern (D) final bool checkScalar()
- {
- if (op == EXP.error)
- return true;
- if (type.toBasetype().ty == Terror)
- return true;
- if (!type.isscalar())
- {
- error(loc, "`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
- return true;
- }
- return checkValue();
- }
-
- extern (D) final bool checkNoBool()
- {
- if (op == EXP.error)
- return true;
- if (type.toBasetype().ty == Terror)
- return true;
- if (type.toBasetype().ty == Tbool)
- {
- error(loc, "operation not allowed on `bool` `%s`", toChars());
- return true;
- }
- return false;
- }
-
- extern (D) final bool checkIntegral()
- {
- if (op == EXP.error)
- return true;
- if (type.toBasetype().ty == Terror)
- return true;
- if (!type.isintegral())
- {
- error(loc, "`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
- return true;
- }
- return checkValue();
- }
-
- extern (D) final bool checkArithmetic(EXP op)
- {
- if (op == EXP.error)
- return true;
- if (type.toBasetype().ty == Terror)
- return true;
- if (!type.isintegral() && !type.isfloating())
- {
- // unary aggregate ops error here
- const char* msg = type.isAggregate() ?
- "operator `%s` is not defined for `%s` of type `%s`" :
- "illegal operator `%s` for `%s` of type `%s`";
- error(loc, msg, EXPtoString(op).ptr, toChars(), type.toChars());
- return true;
- }
- return checkValue();
- }
-
- /*******************************
- * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
- * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
- * Returns true if error occurs.
- */
- extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
- {
- //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
- if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
- return false;
-
- // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
- switch (rmwOp)
- {
- case EXP.plusPlus:
- case EXP.prePlusPlus:
- rmwOp = EXP.addAssign;
- break;
- case EXP.minusMinus:
- case EXP.preMinusMinus:
- rmwOp = EXP.minAssign;
- break;
- default:
- break;
- }
-
- error(loc, "read-modify-write operations are not allowed for `shared` variables");
- errorSupplemental(loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
- EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
- return true;
- }
-
/******************************
* Take address of expression.
*/
@@ -709,7 +596,7 @@ extern (C++) abstract class Expression : ASTNode
return true;
}
- final pure inout nothrow @nogc @safe
+ final pure inout nothrow @nogc @trusted
{
inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
@@ -742,7 +629,7 @@ extern (C++) abstract class Expression : ASTNode
inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
- inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
+ inout(IsExp) isIsExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
@@ -869,12 +756,12 @@ extern (C++) final class IntegerExp : Expression
{
private dinteger_t value;
- extern (D) this(const ref Loc loc, dinteger_t value, Type type)
+ extern (D) this(Loc loc, dinteger_t value, Type type)
{
super(loc, EXP.int64);
//printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
assert(type);
- if (!type.isscalar())
+ if (!type.isScalar())
{
//printf("%s, loc = %d\n", toChars(), loc.linnum);
if (type.ty != Terror)
@@ -892,7 +779,7 @@ extern (C++) final class IntegerExp : Expression
this.value = cast(int)value;
}
- static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
+ static IntegerExp create(Loc loc, dinteger_t value, Type type)
{
return new IntegerExp(loc, value, type);
}
@@ -1086,7 +973,7 @@ extern (C++) final class ErrorExp : Expression
* and we need to set the error count to prevent bogus code
* generation. At least give a message.
*/
- .error(Loc.initial, "unknown, please file report on issues.dlang.org");
+ .error(Loc.initial, "unknown, please file report at https://github.com/dlang/dmd/issues/new");
}
return errorexp;
@@ -1133,7 +1020,7 @@ extern (C++) final class RealExp : Expression
{
real_t value;
- extern (D) this(const ref Loc loc, real_t value, Type type) @safe
+ extern (D) this(Loc loc, real_t value, Type type) @safe
{
super(loc, EXP.float64);
//printf("RealExp::RealExp(%Lg)\n", value);
@@ -1141,7 +1028,7 @@ extern (C++) final class RealExp : Expression
this.type = type;
}
- static RealExp create(const ref Loc loc, real_t value, Type type) @safe
+ static RealExp create(Loc loc, real_t value, Type type) @safe
{
return new RealExp(loc, value, type);
}
@@ -1194,12 +1081,12 @@ extern (C++) final class RealExp : Expression
override real_t toReal()
{
- return type.isreal() ? value : CTFloat.zero;
+ return type.isReal() ? value : CTFloat.zero;
}
override real_t toImaginary()
{
- return type.isreal() ? CTFloat.zero : value;
+ return type.isReal() ? CTFloat.zero : value;
}
override complex_t toComplex()
@@ -1225,7 +1112,7 @@ extern (C++) final class ComplexExp : Expression
{
complex_t value;
- extern (D) this(const ref Loc loc, complex_t value, Type type) @safe
+ extern (D) this(Loc loc, complex_t value, Type type) @safe
{
super(loc, EXP.complex80);
this.value = value;
@@ -1233,7 +1120,7 @@ extern (C++) final class ComplexExp : Expression
//printf("ComplexExp::ComplexExp(%s)\n", toChars());
}
- static ComplexExp create(const ref Loc loc, complex_t value, Type type) @safe
+ static ComplexExp create(Loc loc, complex_t value, Type type) @safe
{
return new ComplexExp(loc, value, type);
}
@@ -1312,20 +1199,20 @@ extern (C++) class IdentifierExp : Expression
{
Identifier ident;
- extern (D) this(const ref Loc loc, Identifier ident) scope @safe
+ extern (D) this(Loc loc, Identifier ident) scope @safe
{
super(loc, EXP.identifier);
this.ident = ident;
}
- static IdentifierExp create(const ref Loc loc, Identifier ident) @safe
+ static IdentifierExp create(Loc loc, Identifier ident) @safe
{
return new IdentifierExp(loc, ident);
}
override final bool isLvalue()
{
- return true;
+ return !this.rvalue;
}
override void accept(Visitor v)
@@ -1341,7 +1228,7 @@ extern (C++) class IdentifierExp : Expression
*/
extern (C++) final class DollarExp : IdentifierExp
{
- extern (D) this(const ref Loc loc)
+ extern (D) this(Loc loc)
{
super(loc, Id.dollar);
}
@@ -1360,7 +1247,7 @@ extern (C++) final class DsymbolExp : Expression
Dsymbol s;
bool hasOverloads;
- extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true) @safe
+ extern (D) this(Loc loc, Dsymbol s, bool hasOverloads = true) @safe
{
super(loc, EXP.dSymbol);
this.s = s;
@@ -1369,7 +1256,7 @@ extern (C++) final class DsymbolExp : Expression
override bool isLvalue()
{
- return true;
+ return !rvalue;
}
override void accept(Visitor v)
@@ -1385,13 +1272,13 @@ extern (C++) class ThisExp : Expression
{
VarDeclaration var;
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, EXP.this_);
//printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
}
- this(const ref Loc loc, const EXP tok) @safe
+ this(Loc loc, const EXP tok) @safe
{
super(loc, tok);
//printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
@@ -1415,7 +1302,7 @@ extern (C++) class ThisExp : Expression
override final bool isLvalue()
{
// Class `this` should be an rvalue; struct `this` should be an lvalue.
- return type.toBasetype().ty != Tclass;
+ return !rvalue && type.toBasetype().ty != Tclass;
}
override void accept(Visitor v)
@@ -1429,7 +1316,7 @@ extern (C++) class ThisExp : Expression
*/
extern (C++) final class SuperExp : ThisExp
{
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, EXP.super_);
}
@@ -1447,7 +1334,7 @@ extern (C++) final class SuperExp : ThisExp
*/
extern (C++) final class NullExp : Expression
{
- extern (D) this(const ref Loc loc, Type type = null) scope @safe
+ extern (D) this(Loc loc, Type type = null) scope @safe
{
super(loc, EXP.null_);
this.type = type;
@@ -1521,7 +1408,7 @@ extern (C++) final class StringExp : Expression
enum char NoPostfix = 0;
- extern (D) this(const ref Loc loc, const(void)[] string) scope
+ extern (D) this(Loc loc, const(void)[] string) scope
{
super(loc, EXP.string_);
this.string = cast(char*)string.ptr; // note that this.string should be const
@@ -1529,7 +1416,7 @@ extern (C++) final class StringExp : Expression
this.sz = 1; // work around LDC bug #1286
}
- extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope
+ extern (D) this(Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope
{
super(loc, EXP.string_);
this.string = cast(char*)string.ptr; // note that this.string should be const
@@ -1538,12 +1425,12 @@ extern (C++) final class StringExp : Expression
this.postfix = postfix;
}
- static StringExp create(const ref Loc loc, const(char)* s)
+ static StringExp create(Loc loc, const(char)* s)
{
return new StringExp(loc, s.toDString());
}
- static StringExp create(const ref Loc loc, const(void)* string, size_t len)
+ static StringExp create(Loc loc, const(void)* string, size_t len)
{
return new StringExp(loc, string[0 .. len]);
}
@@ -1800,7 +1687,7 @@ extern (C++) final class StringExp : Expression
/* string literal is rvalue in default, but
* conversion to reference of static array is only allowed.
*/
- return (type && type.toBasetype().ty == Tsarray);
+ return !rvalue && (type && type.toBasetype().ty == Tsarray);
}
/********************************
@@ -1875,7 +1762,7 @@ extern (C++) final class InterpExp : Expression
enum char NoPostfix = 0;
- extern (D) this(const ref Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope
+ extern (D) this(Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope @safe
{
super(loc, EXP.interpolated);
this.interpolatedSet = set;
@@ -1910,7 +1797,7 @@ extern (C++) final class TupleExp : Expression
Expressions* exps;
- extern (D) this(const ref Loc loc, Expression e0, Expressions* exps) @safe
+ extern (D) this(Loc loc, Expression e0, Expressions* exps) @safe
{
super(loc, EXP.tuple);
//printf("TupleExp(this = %p)\n", this);
@@ -1918,14 +1805,14 @@ extern (C++) final class TupleExp : Expression
this.exps = exps;
}
- extern (D) this(const ref Loc loc, Expressions* exps) @safe
+ extern (D) this(Loc loc, Expressions* exps) @safe
{
super(loc, EXP.tuple);
//printf("TupleExp(this = %p)\n", this);
this.exps = exps;
}
- extern (D) this(const ref Loc loc, TupleDeclaration tup)
+ extern (D) this(Loc loc, TupleDeclaration tup)
{
super(loc, EXP.tuple);
this.exps = new Expressions();
@@ -1959,7 +1846,7 @@ extern (C++) final class TupleExp : Expression
}
}
- static TupleExp create(const ref Loc loc, Expressions* exps) @safe
+ static TupleExp create(Loc loc, Expressions* exps) @safe
{
return new TupleExp(loc, exps);
}
@@ -2015,14 +1902,14 @@ extern (C++) final class ArrayLiteralExp : Expression
Expressions* elements;
- extern (D) this(const ref Loc loc, Type type, Expressions* elements) @safe
+ extern (D) this(Loc loc, Type type, Expressions* elements) @safe
{
super(loc, EXP.arrayLiteral);
this.type = type;
this.elements = elements;
}
- extern (D) this(const ref Loc loc, Type type, Expression e)
+ extern (D) this(Loc loc, Type type, Expression e)
{
super(loc, EXP.arrayLiteral);
this.type = type;
@@ -2030,7 +1917,7 @@ extern (C++) final class ArrayLiteralExp : Expression
elements.push(e);
}
- extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements) @safe
+ extern (D) this(Loc loc, Type type, Expression basis, Expressions* elements) @safe
{
super(loc, EXP.arrayLiteral);
this.type = type;
@@ -2038,7 +1925,7 @@ extern (C++) final class ArrayLiteralExp : Expression
this.elements = elements;
}
- static ArrayLiteralExp create(const ref Loc loc, Expressions* elements) @safe
+ static ArrayLiteralExp create(Loc loc, Expressions* elements) @safe
{
return new ArrayLiteralExp(loc, null, elements);
}
@@ -2171,7 +2058,7 @@ extern (C++) final class AssocArrayLiteralExp : Expression
/// Lower to core.internal.newaa for static initializaton
Expression lowering;
- extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) @safe
+ extern (D) this(Loc loc, Expressions* keys, Expressions* values) @safe
{
super(loc, EXP.assocArrayLiteral);
assert(keys.length == values.length);
@@ -2225,18 +2112,21 @@ extern (C++) final class AssocArrayLiteralExp : Expression
}
}
-enum stageScrub = 0x1; /// scrubReturnValue is running
-enum stageSearchPointers = 0x2; /// hasNonConstPointers is running
-enum stageOptimize = 0x4; /// optimize is running
-enum stageApply = 0x8; /// apply is running
-enum stageInlineScan = 0x10; /// inlineScan is running
-enum stageToCBuffer = 0x20; /// toCBuffer is running
-
/***********************************************************
* sd( e1, e2, e3, ... )
*/
extern (C++) final class StructLiteralExp : Expression
{
+ struct BitFields
+ {
+ bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
+ bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
+ OwnedBy ownedByCtfe = OwnedBy.code;
+ }
+ import dmd.common.bitfields;
+ mixin(generateBitFields!(BitFields, ubyte));
+ StageFlags stageflags;
+
StructDeclaration sd; /// which aggregate this is for
Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
Type stype; /// final type of result (can be different from sd's type)
@@ -2264,13 +2154,18 @@ extern (C++) final class StructLiteralExp : Expression
* 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
* (with infinite recursion) of this expression.
*/
- ubyte stageflags;
-
- bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
- bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
- OwnedBy ownedByCtfe = OwnedBy.code;
+ enum StageFlags : ubyte
+ {
+ none = 0x0,
+ scrub = 0x1, /// scrubReturnValue is running
+ searchPointers = 0x2, /// hasNonConstPointers is running
+ optimize = 0x4, /// optimize is running
+ apply = 0x8, /// apply is running
+ inlineScan = 0x10, /// inlineScan is running
+ toCBuffer = 0x20 /// toCBuffer is running
+ }
- extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) @safe
+ extern (D) this(Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) @safe
{
super(loc, EXP.structLiteral);
this.sd = sd;
@@ -2282,7 +2177,7 @@ extern (C++) final class StructLiteralExp : Expression
//printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
}
- static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
+ static StructLiteralExp create(Loc loc, StructDeclaration sd, void* elements, Type stype = null)
{
return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
}
@@ -2413,7 +2308,7 @@ extern (C++) final class CompoundLiteralExp : Expression
{
Initializer initializer; /// initializer-list
- extern (D) this(const ref Loc loc, Type type_name, Initializer initializer) @safe
+ extern (D) this(Loc loc, Type type_name, Initializer initializer) @safe
{
super(loc, EXP.compoundLiteral);
super.type = type_name;
@@ -2432,7 +2327,7 @@ extern (C++) final class CompoundLiteralExp : Expression
*/
extern (C++) final class TypeExp : Expression
{
- extern (D) this(const ref Loc loc, Type type) @safe
+ extern (D) this(Loc loc, Type type) @safe
{
super(loc, EXP.type);
//printf("TypeExp::TypeExp(%s)\n", type.toChars());
@@ -2450,12 +2345,6 @@ extern (C++) final class TypeExp : Expression
return true;
}
- override bool checkValue()
- {
- error(loc, "type `%s` has no value", toChars());
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2474,7 +2363,7 @@ extern (C++) final class ScopeExp : Expression
{
ScopeDsymbol sds;
- extern (D) this(const ref Loc loc, ScopeDsymbol sds) @safe
+ extern (D) this(Loc loc, ScopeDsymbol sds) @safe
{
super(loc, EXP.scope_);
//printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
@@ -2509,12 +2398,6 @@ extern (C++) final class ScopeExp : Expression
return false;
}
- override bool checkValue()
- {
- error(loc, "%s `%s` has no value", sds.kind(), sds.toChars());
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2529,7 +2412,7 @@ extern (C++) final class TemplateExp : Expression
TemplateDeclaration td;
FuncDeclaration fd;
- extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) @safe
+ extern (D) this(Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) @safe
{
super(loc, EXP.template_);
//printf("TemplateExp(): %s\n", td.toChars());
@@ -2548,12 +2431,6 @@ extern (C++) final class TemplateExp : Expression
return true;
}
- override bool checkValue()
- {
- error(loc, "%s `%s` has no value", td.kind(), toChars());
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2569,6 +2446,7 @@ extern (C++) final class NewExp : Expression
Type newtype;
Expressions* arguments; // Array of Expression's
Identifiers* names; // Array of names corresponding to expressions
+ Expression placement; // if !=null, then PlacementExpression
Expression argprefix; // expression to be evaluated just before arguments[]
CtorDeclaration member; // constructor function
@@ -2581,23 +2459,25 @@ extern (C++) final class NewExp : Expression
/// The fields are still separate for backwards compatibility
extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
- extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe
+ extern (D) this(Loc loc, Expression placement, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe
{
super(loc, EXP.new_);
+ this.placement = placement;
this.thisexp = thisexp;
this.newtype = newtype;
this.arguments = arguments;
this.names = names;
}
- static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) @safe
+ static NewExp create(Loc loc, Expression placement, Expression thisexp, Type newtype, Expressions* arguments) @safe
{
- return new NewExp(loc, thisexp, newtype, arguments);
+ return new NewExp(loc, placement, thisexp, newtype, arguments);
}
override NewExp syntaxCopy()
{
return new NewExp(loc,
+ placement ? placement.syntaxCopy() : null,
thisexp ? thisexp.syntaxCopy() : null,
newtype.syntaxCopy(),
arraySyntaxCopy(arguments),
@@ -2618,10 +2498,12 @@ extern (C++) final class NewAnonClassExp : Expression
Expression thisexp; // if !=null, 'this' for class being allocated
ClassDeclaration cd; // class being instantiated
Expressions* arguments; // Array of Expression's to call class constructor
+ Expression placement; // if !=null, then PlacementExpression
- extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) @safe
+ extern (D) this(Loc loc, Expression placement, Expression thisexp, ClassDeclaration cd, Expressions* arguments) @safe
{
super(loc, EXP.newAnonymousClass);
+ this.placement = placement;
this.thisexp = thisexp;
this.cd = cd;
this.arguments = arguments;
@@ -2629,7 +2511,9 @@ extern (C++) final class NewAnonClassExp : Expression
override NewAnonClassExp syntaxCopy()
{
- return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
+ return new NewAnonClassExp(loc, placement ? placement.syntaxCopy : null,
+ thisexp ? thisexp.syntaxCopy() : null,
+ cd.syntaxCopy(null), arraySyntaxCopy(arguments));
}
override void accept(Visitor v)
@@ -2646,7 +2530,7 @@ extern (C++) class SymbolExp : Expression
Dsymbol originalScope; // original scope before inlining
bool hasOverloads;
- extern (D) this(const ref Loc loc, EXP op, Declaration var, bool hasOverloads) @safe
+ extern (D) this(Loc loc, EXP op, Declaration var, bool hasOverloads) @safe
{
super(loc, op);
assert(var);
@@ -2667,7 +2551,7 @@ extern (C++) final class SymOffExp : SymbolExp
{
dinteger_t offset;
- extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
+ extern (D) this(Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
{
if (auto v = var.isVarDeclaration())
{
@@ -2702,7 +2586,7 @@ extern (C++) final class SymOffExp : SymbolExp
extern (C++) final class VarExp : SymbolExp
{
bool delegateWasExtracted;
- extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true) @safe
+ extern (D) this(Loc loc, Declaration var, bool hasOverloads = true) @safe
{
if (var.isVarDeclaration())
hasOverloads = false;
@@ -2713,7 +2597,7 @@ extern (C++) final class VarExp : SymbolExp
this.type = var.type;
}
- static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true) @safe
+ static VarExp create(Loc loc, Declaration var, bool hasOverloads = true) @safe
{
return new VarExp(loc, var, hasOverloads);
}
@@ -2734,7 +2618,7 @@ extern (C++) final class VarExp : SymbolExp
override bool isLvalue()
{
- if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
+ if (rvalue || var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
return false;
return true;
}
@@ -2752,7 +2636,7 @@ extern (C++) final class OverExp : Expression
{
OverloadSet vars;
- extern (D) this(const ref Loc loc, OverloadSet s)
+ extern (D) this(Loc loc, OverloadSet s)
{
super(loc, EXP.overloadSet);
//printf("OverExp(this = %p, '%s')\n", this, var.toChars());
@@ -2781,7 +2665,7 @@ extern (C++) final class FuncExp : Expression
TemplateDeclaration td;
TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_
- extern (D) this(const ref Loc loc, Dsymbol s)
+ extern (D) this(Loc loc, Dsymbol s)
{
super(loc, EXP.function_);
this.td = s.isTemplateDeclaration();
@@ -2814,16 +2698,11 @@ extern (C++) final class FuncExp : Expression
{
if (td)
return new FuncExp(loc, td.syntaxCopy(null));
- else if (fd.semanticRun == PASS.initial)
+ if (fd.semanticRun == PASS.initial)
return new FuncExp(loc, fd.syntaxCopy(null));
- else // https://issues.dlang.org/show_bug.cgi?id=13481
- // Prevent multiple semantic analysis of lambda body.
- return new FuncExp(loc, fd);
- }
-
- override const(char)* toChars() const
- {
- return fd.toChars();
+ // https://issues.dlang.org/show_bug.cgi?id=13481
+ // Prevent multiple semantic analysis of lambda body.
+ return new FuncExp(loc, fd);
}
override bool checkType()
@@ -2836,16 +2715,6 @@ extern (C++) final class FuncExp : Expression
return false;
}
- override bool checkValue()
- {
- if (td)
- {
- error(loc, "template lambda has no value");
- return true;
- }
- return false;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2863,7 +2732,7 @@ extern (C++) final class DeclarationExp : Expression
{
Dsymbol declaration;
- extern (D) this(const ref Loc loc, Dsymbol declaration) @safe
+ extern (D) this(Loc loc, Dsymbol declaration) @safe
{
super(loc, EXP.declaration);
this.declaration = declaration;
@@ -2896,7 +2765,7 @@ extern (C++) final class TypeidExp : Expression
{
RootObject obj;
- extern (D) this(const ref Loc loc, RootObject o) @safe
+ extern (D) this(Loc loc, RootObject o) @safe
{
super(loc, EXP.typeid_);
this.obj = o;
@@ -2921,7 +2790,7 @@ extern (C++) final class TraitsExp : Expression
Identifier ident;
Objects* args;
- extern (D) this(const ref Loc loc, Identifier ident, Objects* args) @safe
+ extern (D) this(Loc loc, Identifier ident, Objects* args) @safe
{
super(loc, EXP.traits);
this.ident = ident;
@@ -2946,7 +2815,7 @@ extern (C++) final class TraitsExp : Expression
*/
extern (C++) final class HaltExp : Expression
{
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, EXP.halt);
}
@@ -2970,7 +2839,7 @@ extern (C++) final class IsExp : Expression
TOK tok; // ':' or '=='
TOK tok2; // 'struct', 'union', etc.
- extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope @safe
+ extern (D) this(Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope @safe
{
super(loc, EXP.is_);
this.targ = targ;
@@ -3009,7 +2878,7 @@ extern (C++) abstract class UnaExp : Expression
{
Expression e1;
- extern (D) this(const ref Loc loc, EXP op, Expression e1) scope @safe
+ extern (D) this(Loc loc, EXP op, Expression e1) scope @safe
{
super(loc, op);
this.e1 = e1;
@@ -3023,28 +2892,6 @@ extern (C++) abstract class UnaExp : Expression
return e;
}
- /********************************
- * The type for a unary expression is incompatible.
- * Print error message.
- * Returns:
- * ErrorExp
- */
- extern (D) final Expression incompatibleTypes()
- {
- if (e1.type.toBasetype() == Type.terror)
- return e1;
-
- if (e1.op == EXP.type)
- {
- error(loc, "incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
- }
- else
- {
- error(loc, "incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
- }
- return ErrorExp.get();
- }
-
/*********************
* Mark the operand as will never be dereferenced,
* which is useful info for @safe checks.
@@ -3070,10 +2917,8 @@ extern (C++) abstract class BinExp : Expression
{
Expression e1;
Expression e2;
- Type att1; // Save alias this type to detect recursion
- Type att2; // Save alias this type to detect recursion
- extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe
+ extern (D) this(Loc loc, EXP op, Expression e1, Expression e2) scope @safe
{
super(loc, op);
this.e1 = e1;
@@ -3089,54 +2934,6 @@ extern (C++) abstract class BinExp : Expression
return e;
}
- /********************************
- * The types for a binary expression are incompatible.
- * Print error message.
- * Returns:
- * ErrorExp
- */
- extern (D) final Expression incompatibleTypes()
- {
- if (e1.type.toBasetype() == Type.terror)
- return e1;
- if (e2.type.toBasetype() == Type.terror)
- return e2;
-
- // CondExp uses 'a ? b : c' but we're comparing 'b : c'
- const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
- if (e1.op == EXP.type || e2.op == EXP.type)
- {
- error(loc, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
- e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
- }
- else if (e1.type.equals(e2.type))
- {
- error(loc, "incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
- e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
- }
- else
- {
- auto ts = toAutoQualChars(e1.type, e2.type);
- error(loc, "incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
- e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
- }
- return ErrorExp.get();
- }
-
- extern (D) final bool checkIntegralBin()
- {
- bool r1 = e1.checkIntegral();
- bool r2 = e2.checkIntegral();
- return (r1 || r2);
- }
-
- extern (D) final bool checkArithmeticBin()
- {
- bool r1 = e1.checkArithmetic(this.op);
- bool r2 = e2.checkArithmetic(this.op);
- return (r1 || r2);
- }
-
/*********************
* Mark the operands as will never be dereferenced,
* which is useful info for @safe checks.
@@ -3162,14 +2959,14 @@ extern (C++) abstract class BinExp : Expression
*/
extern (C++) class BinAssignExp : BinExp
{
- extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe
+ extern (D) this(Loc loc, EXP op, Expression e1, Expression e2) scope @safe
{
super(loc, op, e1, e2);
}
override final bool isLvalue()
{
- return true;
+ return !rvalue;
}
override void accept(Visitor v)
@@ -3187,7 +2984,7 @@ extern (C++) final class MixinExp : Expression
{
Expressions* exps;
- extern (D) this(const ref Loc loc, Expressions* exps) @safe
+ extern (D) this(Loc loc, Expressions* exps) @safe
{
super(loc, EXP.mixin_);
this.exps = exps;
@@ -3235,7 +3032,7 @@ extern (C++) final class MixinExp : Expression
*/
extern (C++) final class ImportExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e) @safe
+ extern (D) this(Loc loc, Expression e) @safe
{
super(loc, EXP.import_, e);
}
@@ -3255,7 +3052,7 @@ extern (C++) final class AssertExp : UnaExp
{
Expression msg;
- extern (D) this(const ref Loc loc, Expression e, Expression msg = null) @safe
+ extern (D) this(Loc loc, Expression e, Expression msg = null) @safe
{
super(loc, EXP.assert_, e);
this.msg = msg;
@@ -3280,10 +3077,9 @@ extern (C++) final class AssertExp : UnaExp
*/
extern (C++) final class ThrowExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e)
+ extern (D) this(Loc loc, Expression e)
{
super(loc, EXP.throw_, e);
- this.type = Type.tnoreturn;
}
override ThrowExp syntaxCopy()
@@ -3306,13 +3102,13 @@ extern (C++) final class DotIdExp : UnaExp
bool wantsym; // do not replace Symbol with its initializer during semantic()
bool arrow; // ImportC: if -> instead of .
- extern (D) this(const ref Loc loc, Expression e, Identifier ident) @safe
+ extern (D) this(Loc loc, Expression e, Identifier ident) @safe
{
super(loc, EXP.dotIdentifier, e);
this.ident = ident;
}
- static DotIdExp create(const ref Loc loc, Expression e, Identifier ident) @safe
+ static DotIdExp create(Loc loc, Expression e, Identifier ident) @safe
{
return new DotIdExp(loc, e, ident);
}
@@ -3330,7 +3126,7 @@ extern (C++) final class DotTemplateExp : UnaExp
{
TemplateDeclaration td;
- extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td) @safe
+ extern (D) this(Loc loc, Expression e, TemplateDeclaration td) @safe
{
super(loc, EXP.dotTemplateDeclaration, e);
this.td = td;
@@ -3342,12 +3138,6 @@ extern (C++) final class DotTemplateExp : UnaExp
return true;
}
- override bool checkValue()
- {
- error(loc, "%s `%s` has no value", td.kind(), toChars());
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3361,7 +3151,7 @@ extern (C++) final class DotVarExp : UnaExp
Declaration var;
bool hasOverloads;
- extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true) @safe
+ extern (D) this(Loc loc, Expression e, Declaration var, bool hasOverloads = true) @safe
{
if (var.isVarDeclaration())
hasOverloads = false;
@@ -3374,6 +3164,8 @@ extern (C++) final class DotVarExp : UnaExp
override bool isLvalue()
{
+ if (rvalue)
+ return false;
if (e1.op != EXP.structLiteral)
return true;
auto vd = var.isVarDeclaration();
@@ -3393,14 +3185,14 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
{
TemplateInstance ti;
- extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
+ extern (D) this(Loc loc, Expression e, Identifier name, Objects* tiargs)
{
super(loc, EXP.dotTemplateInstance, e);
//printf("DotTemplateInstanceExp()\n");
this.ti = new TemplateInstance(loc, name, tiargs);
}
- extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti) @safe
+ extern (D) this(Loc loc, Expression e, TemplateInstance ti) @safe
{
super(loc, EXP.dotTemplateInstance, e);
this.ti = ti;
@@ -3424,18 +3216,6 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp
return false;
}
- override bool checkValue()
- {
- if (ti.tempdecl &&
- ti.semantictiargsdone &&
- ti.semanticRun == PASS.initial)
-
- error(loc, "partial %s `%s` has no value", ti.kind(), toChars());
- else
- error(loc, "%s `%s` has no value", ti.kind(), ti.toChars());
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3450,7 +3230,7 @@ extern (C++) final class DelegateExp : UnaExp
bool hasOverloads;
VarDeclaration vthis2; // container for multi-context
- extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null) @safe
+ extern (D) this(Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null) @safe
{
super(loc, EXP.delegate_, e);
this.func = f;
@@ -3470,7 +3250,7 @@ extern (C++) final class DotTypeExp : UnaExp
{
Dsymbol sym; // symbol that represents a type
- extern (D) this(const ref Loc loc, Expression e, Dsymbol s) @safe
+ extern (D) this(Loc loc, Expression e, Dsymbol s) @safe
{
super(loc, EXP.dotType, e);
this.sym = s;
@@ -3525,19 +3305,19 @@ extern (C++) final class CallExp : UnaExp
/// The fields are still separate for backwards compatibility
extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
- extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null) @safe
+ extern (D) this(Loc loc, Expression e, Expressions* exps, Identifiers* names = null) @safe
{
super(loc, EXP.call, e);
this.arguments = exps;
this.names = names;
}
- extern (D) this(const ref Loc loc, Expression e) @safe
+ extern (D) this(Loc loc, Expression e) @safe
{
super(loc, EXP.call, e);
}
- extern (D) this(const ref Loc loc, Expression e, Expression earg1)
+ extern (D) this(Loc loc, Expression e, Expression earg1)
{
super(loc, EXP.call, e);
this.arguments = new Expressions();
@@ -3545,7 +3325,7 @@ extern (C++) final class CallExp : UnaExp
this.arguments.push(earg1);
}
- extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
+ extern (D) this(Loc loc, Expression e, Expression earg1, Expression earg2)
{
super(loc, EXP.call, e);
auto arguments = new Expressions(2);
@@ -3561,23 +3341,23 @@ extern (C++) final class CallExp : UnaExp
* fd = the declaration of the function to call
* earg1 = the function argument
*/
- extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
+ extern(D) this(Loc loc, FuncDeclaration fd, Expression earg1)
{
this(loc, new VarExp(loc, fd, false), earg1);
this.f = fd;
}
- static CallExp create(const ref Loc loc, Expression e, Expressions* exps) @safe
+ static CallExp create(Loc loc, Expression e, Expressions* exps) @safe
{
return new CallExp(loc, e, exps);
}
- static CallExp create(const ref Loc loc, Expression e) @safe
+ static CallExp create(Loc loc, Expression e) @safe
{
return new CallExp(loc, e);
}
- static CallExp create(const ref Loc loc, Expression e, Expression earg1)
+ static CallExp create(Loc loc, Expression e, Expression earg1)
{
return new CallExp(loc, e, earg1);
}
@@ -3589,7 +3369,7 @@ extern (C++) final class CallExp : UnaExp
* fd = the declaration of the function to call
* earg1 = the function argument
*/
- static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
+ static CallExp create(Loc loc, FuncDeclaration fd, Expression earg1)
{
return new CallExp(loc, fd, earg1);
}
@@ -3601,11 +3381,13 @@ extern (C++) final class CallExp : UnaExp
override bool isLvalue()
{
+ if (rvalue)
+ return false;
Type tb = e1.type.toBasetype();
if (tb.ty == Tdelegate || tb.ty == Tpointer)
tb = tb.nextOf();
auto tf = tb.isTypeFunction();
- if (tf && tf.isref)
+ if (tf && tf.isRef)
{
if (auto dve = e1.isDotVarExp())
if (dve.var.isCtorDeclaration())
@@ -3635,10 +3417,9 @@ TypeFunction calledFunctionType(CallExp ce)
t = t.toBasetype();
if (auto tf = t.isTypeFunction())
return tf;
- else if (auto td = t.isTypeDelegate())
+ if (auto td = t.isTypeDelegate())
return td.nextOf().isTypeFunction();
- else
- return null;
+ return null;
}
FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) @safe
@@ -3682,12 +3463,12 @@ FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) @safe
*/
extern (C++) final class AddrExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e) @safe
+ extern (D) this(Loc loc, Expression e) @safe
{
super(loc, EXP.address, e);
}
- extern (D) this(const ref Loc loc, Expression e, Type t) @safe
+ extern (D) this(Loc loc, Expression e, Type t) @safe
{
this(loc, e);
type = t;
@@ -3704,14 +3485,14 @@ extern (C++) final class AddrExp : UnaExp
*/
extern (C++) final class PtrExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e) @safe
+ extern (D) this(Loc loc, Expression e) @safe
{
super(loc, EXP.star, e);
//if (e.type)
// type = ((TypePointer *)e.type).next;
}
- extern (D) this(const ref Loc loc, Expression e, Type t) @safe
+ extern (D) this(Loc loc, Expression e, Type t) @safe
{
super(loc, EXP.star, e);
type = t;
@@ -3719,7 +3500,7 @@ extern (C++) final class PtrExp : UnaExp
override bool isLvalue()
{
- return true;
+ return !rvalue;
}
override void accept(Visitor v)
@@ -3733,7 +3514,7 @@ extern (C++) final class PtrExp : UnaExp
*/
extern (C++) final class NegExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e) @safe
+ extern (D) this(Loc loc, Expression e) @safe
{
super(loc, EXP.negate, e);
}
@@ -3749,7 +3530,7 @@ extern (C++) final class NegExp : UnaExp
*/
extern (C++) final class UAddExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e) scope @safe
+ extern (D) this(Loc loc, Expression e) scope @safe
{
super(loc, EXP.uadd, e);
}
@@ -3765,7 +3546,7 @@ extern (C++) final class UAddExp : UnaExp
*/
extern (C++) final class ComExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e) @safe
+ extern (D) this(Loc loc, Expression e) @safe
{
super(loc, EXP.tilde, e);
}
@@ -3781,7 +3562,7 @@ extern (C++) final class ComExp : UnaExp
*/
extern (C++) final class NotExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e) @safe
+ extern (D) this(Loc loc, Expression e) @safe
{
super(loc, EXP.not, e);
}
@@ -3801,7 +3582,7 @@ extern (C++) final class DeleteExp : UnaExp
{
bool isRAII; // true if called automatically as a result of scoped destruction
- extern (D) this(const ref Loc loc, Expression e, bool isRAII) @safe
+ extern (D) this(Loc loc, Expression e, bool isRAII) @safe
{
super(loc, EXP.delete_, e);
this.isRAII = isRAII;
@@ -3824,8 +3605,9 @@ extern (C++) final class CastExp : UnaExp
{
Type to; // type to cast to
ubyte mod = cast(ubyte)~0; // MODxxxxx
+ bool trusted; // assume cast is safe
- extern (D) this(const ref Loc loc, Expression e, Type t) @safe
+ extern (D) this(Loc loc, Expression e, Type t) @safe
{
super(loc, EXP.cast_, e);
this.to = t;
@@ -3833,7 +3615,7 @@ extern (C++) final class CastExp : UnaExp
/* For cast(const) and cast(immutable)
*/
- extern (D) this(const ref Loc loc, Expression e, ubyte mod) @safe
+ extern (D) this(Loc loc, Expression e, ubyte mod) @safe
{
super(loc, EXP.cast_, e);
this.mod = mod;
@@ -3847,9 +3629,10 @@ extern (C++) final class CastExp : UnaExp
override bool isLvalue()
{
//printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
- if (!e1.isLvalue())
+ if (rvalue || !e1.isLvalue())
return false;
return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
+ (to.ty == Taarray && e1.type.ty == Taarray) ||
e1.type.mutableOf.unSharedOf().equals(to.mutableOf().unSharedOf());
}
@@ -3867,14 +3650,14 @@ extern (C++) final class VectorExp : UnaExp
uint dim = ~0; // number of elements in the vector
OwnedBy ownedByCtfe = OwnedBy.code;
- extern (D) this(const ref Loc loc, Expression e, Type t) @safe
+ extern (D) this(Loc loc, Expression e, Type t) @trusted
{
super(loc, EXP.vector, e);
assert(t.ty == Tvector);
to = cast(TypeVector)t;
}
- static VectorExp create(const ref Loc loc, Expression e, Type t) @safe
+ static VectorExp create(Loc loc, Expression e, Type t) @safe
{
return new VectorExp(loc, e, t);
}
@@ -3897,14 +3680,14 @@ extern (C++) final class VectorExp : UnaExp
*/
extern (C++) final class VectorArrayExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e1) @safe
+ extern (D) this(Loc loc, Expression e1) @safe
{
super(loc, EXP.vectorArray, e1);
}
override bool isLvalue()
{
- return e1.isLvalue();
+ return !rvalue && e1.isLvalue();
}
override void accept(Visitor v)
@@ -3935,14 +3718,14 @@ extern (C++) final class SliceExp : UnaExp
mixin(generateBitFields!(BitFields, ubyte));
/************************************************************/
- extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie) @safe
+ extern (D) this(Loc loc, Expression e1, IntervalExp ie) @safe
{
super(loc, EXP.slice, e1);
this.upr = ie ? ie.upr : null;
this.lwr = ie ? ie.lwr : null;
}
- extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr) @safe
+ extern (D) this(Loc loc, Expression e1, Expression lwr, Expression upr) @safe
{
super(loc, EXP.slice, e1);
this.upr = upr;
@@ -3961,7 +3744,7 @@ extern (C++) final class SliceExp : UnaExp
/* slice expression is rvalue in default, but
* conversion to reference of static array is only allowed.
*/
- return (type && type.toBasetype().ty == Tsarray);
+ return !rvalue && (type && type.toBasetype().ty == Tsarray);
}
override Optional!bool toBool()
@@ -3980,7 +3763,7 @@ extern (C++) final class SliceExp : UnaExp
*/
extern (C++) final class ArrayLengthExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e1) @safe
+ extern (D) this(Loc loc, Expression e1) @safe
{
super(loc, EXP.arrayLength, e1);
}
@@ -4003,7 +3786,7 @@ extern (C++) final class ArrayExp : UnaExp
size_t currentDimension; // for opDollar
VarDeclaration lengthVar;
- extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
+ extern (D) this(Loc loc, Expression e1, Expression index = null)
{
super(loc, EXP.array, e1);
arguments = new Expressions();
@@ -4011,7 +3794,7 @@ extern (C++) final class ArrayExp : UnaExp
arguments.push(index);
}
- extern (D) this(const ref Loc loc, Expression e1, Expressions* args) @safe
+ extern (D) this(Loc loc, Expression e1, Expressions* args) @safe
{
super(loc, EXP.array, e1);
arguments = args;
@@ -4026,6 +3809,8 @@ extern (C++) final class ArrayExp : UnaExp
override bool isLvalue()
{
+ if (rvalue)
+ return false;
if (type && type.toBasetype().ty == Tvoid)
return false;
return true;
@@ -4041,7 +3826,7 @@ extern (C++) final class ArrayExp : UnaExp
*/
extern (C++) final class DotExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.dot, e1, e2);
}
@@ -4067,7 +3852,7 @@ extern (C++) final class CommaExp : BinExp
bool allowCommaExp;
- extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2, bool generated = true) @safe
{
super(loc, EXP.comma, e1, e2);
allowCommaExp = isGenerated = generated;
@@ -4075,7 +3860,7 @@ extern (C++) final class CommaExp : BinExp
override bool isLvalue()
{
- return e2.isLvalue();
+ return !rvalue && e2.isLvalue();
}
override Optional!bool toBool()
@@ -4118,7 +3903,7 @@ extern (C++) final class IntervalExp : Expression
Expression lwr;
Expression upr;
- extern (D) this(const ref Loc loc, Expression lwr, Expression upr) @safe
+ extern (D) this(Loc loc, Expression lwr, Expression upr) @safe
{
super(loc, EXP.interval);
this.lwr = lwr;
@@ -4143,14 +3928,14 @@ extern (C++) final class IntervalExp : Expression
*/
extern (C++) final class DelegatePtrExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e1) @safe
+ extern (D) this(Loc loc, Expression e1) @safe
{
super(loc, EXP.delegatePointer, e1);
}
override bool isLvalue()
{
- return e1.isLvalue();
+ return !rvalue && e1.isLvalue();
}
override void accept(Visitor v)
@@ -4166,14 +3951,14 @@ extern (C++) final class DelegatePtrExp : UnaExp
*/
extern (C++) final class DelegateFuncptrExp : UnaExp
{
- extern (D) this(const ref Loc loc, Expression e1) @safe
+ extern (D) this(Loc loc, Expression e1) @safe
{
super(loc, EXP.delegateFunctionPointer, e1);
}
override bool isLvalue()
{
- return e1.isLvalue();
+ return !rvalue && e1.isLvalue();
}
override void accept(Visitor v)
@@ -4191,13 +3976,13 @@ extern (C++) final class IndexExp : BinExp
bool modifiable = false; // assume it is an rvalue
bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.index, e1, e2);
//printf("IndexExp::IndexExp('%s')\n", toChars());
}
- extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2, bool indexIsInBounds) @safe
{
super(loc, EXP.index, e1, e2);
this.indexIsInBounds = indexIsInBounds;
@@ -4213,10 +3998,11 @@ extern (C++) final class IndexExp : BinExp
override bool isLvalue()
{
- if (e1.op == EXP.assocArrayLiteral)
+ if (rvalue)
return false;
- if (e1.type.ty == Tsarray ||
- (e1.op == EXP.index && e1.type.ty != Tarray))
+ auto t1b = e1.type.toBasetype();
+ if (t1b.isTypeAArray() || t1b.isTypeSArray() ||
+ (e1.isIndexExp() && t1b != t1b.isTypeDArray()))
{
return e1.isLvalue();
}
@@ -4257,7 +4043,7 @@ extern (C++) final class IndexExp : BinExp
*/
extern (C++) final class PostExp : BinExp
{
- extern (D) this(EXP op, const ref Loc loc, Expression e)
+ extern (D) this(EXP op, Loc loc, Expression e)
{
super(loc, op, e, IntegerExp.literal!1);
assert(op == EXP.minusMinus || op == EXP.plusPlus);
@@ -4274,7 +4060,7 @@ extern (C++) final class PostExp : BinExp
*/
extern (C++) final class PreExp : UnaExp
{
- extern (D) this(EXP op, const ref Loc loc, Expression e) @safe
+ extern (D) this(EXP op, Loc loc, Expression e) @safe
{
super(loc, op, e);
assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
@@ -4304,12 +4090,12 @@ extern (C++) class AssignExp : BinExp
/************************************************************/
/* op can be EXP.assign, EXP.construct, or EXP.blit */
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.assign, e1, e2);
}
- this(const ref Loc loc, EXP tok, Expression e1, Expression e2) @safe
+ this(Loc loc, EXP tok, Expression e1, Expression e2) @safe
{
super(loc, tok, e1, e2);
}
@@ -4322,7 +4108,7 @@ extern (C++) class AssignExp : BinExp
{
return false;
}
- return true;
+ return !rvalue;
}
override void accept(Visitor v)
@@ -4347,10 +4133,6 @@ extern (C++) final class LoweredAssignExp : AssignExp
this.lowering = lowering;
}
- override const(char)* toChars() const
- {
- return lowering.toChars();
- }
override void accept(Visitor v)
{
v.visit(this);
@@ -4361,14 +4143,14 @@ extern (C++) final class LoweredAssignExp : AssignExp
*/
extern (C++) final class ConstructExp : AssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.construct, e1, e2);
}
// Internal use only. If `v` is a reference variable, the assignment
// will become a reference initialization automatically.
- extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) @safe
+ extern (D) this(Loc loc, VarDeclaration v, Expression e2) @safe
{
auto ve = new VarExp(loc, v);
assert(v.type && ve.type);
@@ -4390,14 +4172,14 @@ extern (C++) final class ConstructExp : AssignExp
*/
extern (C++) final class BlitExp : AssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.blit, e1, e2);
}
// Internal use only. If `v` is a reference variable, the assinment
// will become a reference rebinding automatically.
- extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) @safe
+ extern (D) this(Loc loc, VarDeclaration v, Expression e2) @safe
{
auto ve = new VarExp(loc, v);
assert(v.type && ve.type);
@@ -4419,7 +4201,7 @@ extern (C++) final class BlitExp : AssignExp
*/
extern (C++) final class AddAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.addAssign, e1, e2);
}
@@ -4435,7 +4217,7 @@ extern (C++) final class AddAssignExp : BinAssignExp
*/
extern (C++) final class MinAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.minAssign, e1, e2);
}
@@ -4451,7 +4233,7 @@ extern (C++) final class MinAssignExp : BinAssignExp
*/
extern (C++) final class MulAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.mulAssign, e1, e2);
}
@@ -4467,7 +4249,7 @@ extern (C++) final class MulAssignExp : BinAssignExp
*/
extern (C++) final class DivAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.divAssign, e1, e2);
}
@@ -4483,7 +4265,7 @@ extern (C++) final class DivAssignExp : BinAssignExp
*/
extern (C++) final class ModAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.modAssign, e1, e2);
}
@@ -4499,7 +4281,7 @@ extern (C++) final class ModAssignExp : BinAssignExp
*/
extern (C++) final class AndAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.andAssign, e1, e2);
}
@@ -4515,7 +4297,7 @@ extern (C++) final class AndAssignExp : BinAssignExp
*/
extern (C++) final class OrAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.orAssign, e1, e2);
}
@@ -4531,7 +4313,7 @@ extern (C++) final class OrAssignExp : BinAssignExp
*/
extern (C++) final class XorAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.xorAssign, e1, e2);
}
@@ -4547,7 +4329,7 @@ extern (C++) final class XorAssignExp : BinAssignExp
*/
extern (C++) final class PowAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.powAssign, e1, e2);
}
@@ -4563,7 +4345,7 @@ extern (C++) final class PowAssignExp : BinAssignExp
*/
extern (C++) final class ShlAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.leftShiftAssign, e1, e2);
}
@@ -4579,7 +4361,7 @@ extern (C++) final class ShlAssignExp : BinAssignExp
*/
extern (C++) final class ShrAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.rightShiftAssign, e1, e2);
}
@@ -4595,7 +4377,7 @@ extern (C++) final class ShrAssignExp : BinAssignExp
*/
extern (C++) final class UshrAssignExp : BinAssignExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.unsignedRightShiftAssign, e1, e2);
}
@@ -4622,12 +4404,12 @@ extern (C++) class CatAssignExp : BinAssignExp
{
Expression lowering; // lowered druntime hook `_d_arrayappend{cTX,T}`
- extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.concatenateAssign, e1, e2);
}
- extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, EXP tok, Expression e1, Expression e2) @safe
{
super(loc, tok, e1, e2);
}
@@ -4643,7 +4425,7 @@ extern (C++) class CatAssignExp : BinAssignExp
*/
extern (C++) final class CatElemAssignExp : CatAssignExp
{
- extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Type type, Expression e1, Expression e2) @safe
{
super(loc, EXP.concatenateElemAssign, e1, e2);
this.type = type;
@@ -4660,7 +4442,7 @@ extern (C++) final class CatElemAssignExp : CatAssignExp
*/
extern (C++) final class CatDcharAssignExp : CatAssignExp
{
- extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Type type, Expression e1, Expression e2) @safe
{
super(loc, EXP.concatenateDcharAssign, e1, e2);
this.type = type;
@@ -4679,7 +4461,7 @@ extern (C++) final class CatDcharAssignExp : CatAssignExp
*/
extern (C++) final class AddExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.add, e1, e2);
}
@@ -4697,7 +4479,7 @@ extern (C++) final class AddExp : BinExp
*/
extern (C++) final class MinExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.min, e1, e2);
}
@@ -4717,7 +4499,7 @@ extern (C++) final class CatExp : BinExp
{
Expression lowering; // call to druntime hook `_d_arraycatnTX`
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) scope @safe
{
super(loc, EXP.concatenate, e1, e2);
}
@@ -4735,7 +4517,7 @@ extern (C++) final class CatExp : BinExp
*/
extern (C++) final class MulExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.mul, e1, e2);
}
@@ -4753,7 +4535,7 @@ extern (C++) final class MulExp : BinExp
*/
extern (C++) final class DivExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.div, e1, e2);
}
@@ -4771,7 +4553,7 @@ extern (C++) final class DivExp : BinExp
*/
extern (C++) final class ModExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.mod, e1, e2);
}
@@ -4789,7 +4571,7 @@ extern (C++) final class ModExp : BinExp
*/
extern (C++) final class PowExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.pow, e1, e2);
}
@@ -4807,7 +4589,7 @@ extern (C++) final class PowExp : BinExp
*/
extern (C++) final class ShlExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.leftShift, e1, e2);
}
@@ -4825,7 +4607,7 @@ extern (C++) final class ShlExp : BinExp
*/
extern (C++) final class ShrExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.rightShift, e1, e2);
}
@@ -4843,7 +4625,7 @@ extern (C++) final class ShrExp : BinExp
*/
extern (C++) final class UshrExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.unsignedRightShift, e1, e2);
}
@@ -4861,7 +4643,7 @@ extern (C++) final class UshrExp : BinExp
*/
extern (C++) final class AndExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.and, e1, e2);
}
@@ -4879,7 +4661,7 @@ extern (C++) final class AndExp : BinExp
*/
extern (C++) final class OrExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.or, e1, e2);
}
@@ -4897,7 +4679,7 @@ extern (C++) final class OrExp : BinExp
*/
extern (C++) final class XorExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.xor, e1, e2);
}
@@ -4916,7 +4698,7 @@ extern (C++) final class XorExp : BinExp
*/
extern (C++) final class LogicalExp : BinExp
{
- extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, EXP op, Expression e1, Expression e2) @safe
{
super(loc, op, e1, e2);
assert(op == EXP.andAnd || op == EXP.orOr);
@@ -4938,7 +4720,7 @@ extern (C++) final class LogicalExp : BinExp
*/
extern (C++) final class CmpExp : BinExp
{
- extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(EXP op, Loc loc, Expression e1, Expression e2) @safe
{
super(loc, op, e1, e2);
assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
@@ -4959,7 +4741,7 @@ extern (C++) final class CmpExp : BinExp
*/
extern (C++) final class InExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(Loc loc, Expression e1, Expression e2) @safe
{
super(loc, EXP.in_, e1, e2);
}
@@ -4977,7 +4759,7 @@ extern (C++) final class InExp : BinExp
*/
extern (C++) final class RemoveExp : BinExp
{
- extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ extern (D) this(Loc loc, Expression e1, Expression e2)
{
super(loc, EXP.remove, e1, e2);
type = Type.tbool;
@@ -4998,7 +4780,7 @@ extern (C++) final class RemoveExp : BinExp
*/
extern (C++) final class EqualExp : BinExp
{
- extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(EXP op, Loc loc, Expression e1, Expression e2) @safe
{
super(loc, op, e1, e2);
assert(op == EXP.equal || op == EXP.notEqual);
@@ -5019,7 +4801,7 @@ extern (C++) final class EqualExp : BinExp
*/
extern (C++) final class IdentityExp : BinExp
{
- extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
+ extern (D) this(EXP op, Loc loc, Expression e1, Expression e2) @safe
{
super(loc, op, e1, e2);
assert(op == EXP.identity || op == EXP.notIdentity);
@@ -5040,7 +4822,7 @@ extern (C++) final class CondExp : BinExp
{
Expression econd;
- extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope @safe
+ extern (D) this(Loc loc, Expression econd, Expression e1, Expression e2) scope @safe
{
super(loc, EXP.question, e1, e2);
this.econd = econd;
@@ -5053,7 +4835,7 @@ extern (C++) final class CondExp : BinExp
override bool isLvalue()
{
- return e1.isLvalue() && e2.isLvalue();
+ return !rvalue && e1.isLvalue() && e2.isLvalue();
}
override void accept(Visitor v)
@@ -5084,7 +4866,7 @@ extern (C++) class DefaultInitExp : Expression
* op = EXP.prettyFunction, EXP.functionString, EXP.moduleString,
* EXP.line, EXP.file, EXP.fileFullPath
*/
- extern (D) this(const ref Loc loc, EXP op) @safe
+ extern (D) this(Loc loc, EXP op) @safe
{
super(loc, op);
}
@@ -5100,7 +4882,7 @@ extern (C++) class DefaultInitExp : Expression
*/
extern (C++) final class FileInitExp : DefaultInitExp
{
- extern (D) this(const ref Loc loc, EXP tok) @safe
+ extern (D) this(Loc loc, EXP tok) @safe
{
super(loc, tok);
}
@@ -5116,7 +4898,7 @@ extern (C++) final class FileInitExp : DefaultInitExp
*/
extern (C++) final class LineInitExp : DefaultInitExp
{
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, EXP.line);
}
@@ -5132,7 +4914,7 @@ extern (C++) final class LineInitExp : DefaultInitExp
*/
extern (C++) final class ModuleInitExp : DefaultInitExp
{
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, EXP.moduleString);
}
@@ -5148,7 +4930,7 @@ extern (C++) final class ModuleInitExp : DefaultInitExp
*/
extern (C++) final class FuncInitExp : DefaultInitExp
{
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, EXP.functionString);
}
@@ -5164,7 +4946,7 @@ extern (C++) final class FuncInitExp : DefaultInitExp
*/
extern (C++) final class PrettyFuncInitExp : DefaultInitExp
{
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, EXP.prettyFunction);
}
@@ -5183,7 +4965,7 @@ extern (C++) final class ClassReferenceExp : Expression
{
StructLiteralExp value;
- extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) @safe
+ extern (D) this(Loc loc, StructLiteralExp lit, Type type) @safe
{
super(loc, EXP.classReference);
assert(lit && lit.sd && lit.sd.isClassDeclaration());
@@ -5256,27 +5038,6 @@ extern (C++) final class CTFEExp : Expression
type = Type.tvoid;
}
- override const(char)* toChars() const
- {
- switch (op)
- {
- case EXP.cantExpression:
- return "<cant>";
- case EXP.voidExpression:
- return "cast(void)0";
- case EXP.showCtfeContext:
- return "<error>";
- case EXP.break_:
- return "<break>";
- case EXP.continue_:
- return "<continue>";
- case EXP.goto_:
- return "<goto>";
- default:
- assert(0);
- }
- }
-
extern (D) __gshared CTFEExp cantexp;
extern (D) __gshared CTFEExp voidexp;
extern (D) __gshared CTFEExp breakexp;
@@ -5306,18 +5067,13 @@ extern (C++) final class ThrownExceptionExp : Expression
{
ClassReferenceExp thrown; // the thing being tossed
- extern (D) this(const ref Loc loc, ClassReferenceExp victim) @safe
+ extern (D) this(Loc loc, ClassReferenceExp victim) @safe
{
super(loc, EXP.thrownException);
this.thrown = victim;
this.type = victim.type;
}
- override const(char)* toChars() const
- {
- return "CTFE ThrownException";
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -5333,7 +5089,7 @@ extern (C++) final class ObjcClassReferenceExp : Expression
{
ClassDeclaration classDeclaration;
- extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
+ extern (D) this(Loc loc, ClassDeclaration classDeclaration) @safe
{
super(loc, EXP.objcClassReference);
this.classDeclaration = classDeclaration;
@@ -5355,7 +5111,7 @@ extern (C++) final class GenericExp : Expression
Types* types; /// type-names for generic associations (null entry for `default`)
Expressions* exps; /// 1:1 mapping of typeNames to exps
- extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps) @safe
+ extern (D) this(Loc loc, Expression cntlExp, Types* types, Expressions* exps) @safe
{
super(loc, EXP._Generic);
this.cntlExp = cntlExp;
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 2f6bb84..3c8d90d 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -40,6 +40,7 @@ class OverloadSet;
class StringExp;
class InterpExp;
class LoweredAssignExp;
+class StaticForeach;
#ifdef IN_GCC
typedef union tree_node Symbol;
#else
@@ -50,8 +51,9 @@ namespace dmd
{
// in expressionsem.d
Expression *expressionSemantic(Expression *e, Scope *sc);
+ void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc);
// in typesem.d
- Expression *defaultInit(Type *mt, const Loc &loc, const bool isCfile = false);
+ Expression *defaultInit(Type *mt, Loc loc, const bool isCfile = false);
// Entry point for CTFE.
// A compile-time result is required. Give an error if not possible
@@ -71,26 +73,18 @@ enum
#define WANTvalue 0 // default
#define WANTexpand 1 // expand const/immutable variables if possible
-/**
- * Specifies how the checkModify deals with certain situations
- */
-enum class ModifyFlags
-{
- /// Issue error messages on invalid modifications of the variable
- none,
- /// No errors are emitted for invalid modifications
- noError = 0x1,
- /// The modification occurs for a subfield of the current variable
- fieldAssign = 0x2,
-};
-
class Expression : public ASTNode
{
public:
Type *type; // !=NULL means that semantic() has been run
Loc loc; // file location
EXP op; // to minimize use of dynamic_cast
- d_bool parens; // if this is a parenthesized expression
+ uint8_t bitFields;
+
+ bool parens() const;
+ bool parens(bool v);
+ bool rvalue() const;
+ bool rvalue(bool v);
size_t size() const;
static void _init();
@@ -99,7 +93,7 @@ public:
// kludge for template.isExpression()
DYNCAST dyncast() const override final { return DYNCAST_EXPRESSION; }
- const char *toChars() const override;
+ const char* toChars() const final override;
virtual dinteger_t toInteger();
virtual uinteger_t toUInteger();
@@ -109,7 +103,6 @@ public:
virtual StringExp *toStringExp();
virtual bool isLvalue();
virtual bool checkType();
- virtual bool checkValue();
Expression *addressOf();
Expression *deref();
@@ -151,7 +144,7 @@ public:
TypeidExp* isTypeidExp();
TraitsExp* isTraitsExp();
HaltExp* isHaltExp();
- IsExp* isExp();
+ IsExp* isIsExp();
MixinExp* isMixinExp();
ImportExp* isImportExp();
AssertExp* isAssertExp();
@@ -242,7 +235,7 @@ class IntegerExp final : public Expression
public:
dinteger_t value;
- static IntegerExp *create(const Loc &loc, dinteger_t value, Type *type);
+ static IntegerExp *create(Loc loc, dinteger_t value, Type *type);
bool equals(const RootObject * const o) const override;
dinteger_t toInteger() override;
real_t toReal() override;
@@ -268,7 +261,7 @@ class RealExp final : public Expression
public:
real_t value;
- static RealExp *create(const Loc &loc, real_t value, Type *type);
+ static RealExp *create(Loc loc, real_t value, Type *type);
bool equals(const RootObject * const o) const override;
bool isIdentical(const Expression *e) const override;
dinteger_t toInteger() override;
@@ -285,7 +278,7 @@ class ComplexExp final : public Expression
public:
complex_t value;
- static ComplexExp *create(const Loc &loc, complex_t value, Type *type);
+ static ComplexExp *create(Loc loc, complex_t value, Type *type);
bool equals(const RootObject * const o) const override;
bool isIdentical(const Expression *e) const override;
dinteger_t toInteger() override;
@@ -302,7 +295,7 @@ class IdentifierExp : public Expression
public:
Identifier *ident;
- static IdentifierExp *create(const Loc &loc, Identifier *ident);
+ static IdentifierExp *create(Loc loc, Identifier *ident);
bool isLvalue() override final;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -362,8 +355,8 @@ public:
d_bool committed; // if type is committed
d_bool hexString; // if string is parsed from a hex string literal
- static StringExp *create(const Loc &loc, const char *s);
- static StringExp *create(const Loc &loc, const void *s, d_size_t len);
+ static StringExp *create(Loc loc, const char *s);
+ static StringExp *create(Loc loc, const void *s, d_size_t len);
bool equals(const RootObject * const o) const override;
char32_t getCodeUnit(d_size_t i) const;
dinteger_t getIndex(d_size_t i) const;
@@ -400,7 +393,7 @@ public:
*/
Expressions *exps;
- static TupleExp *create(const Loc &loc, Expressions *exps);
+ static TupleExp *create(Loc loc, Expressions *exps);
TupleExp *syntaxCopy() override;
bool equals(const RootObject * const o) const override;
@@ -415,7 +408,7 @@ public:
Expression *basis;
Expressions *elements;
- static ArrayLiteralExp *create(const Loc &loc, Expressions *elements);
+ static ArrayLiteralExp *create(Loc loc, Expressions *elements);
ArrayLiteralExp *syntaxCopy() override;
bool equals(const RootObject * const o) const override;
Expression *getElement(d_size_t i);
@@ -443,6 +436,24 @@ public:
class StructLiteralExp final : public Expression
{
public:
+ uint8_t bitFields;
+
+ // if this is true, use the StructDeclaration's init symbol
+ bool useStaticInit() const;
+ bool useStaticInit(bool v);
+ // used when moving instances to indicate `this is this.origin`
+ bool isOriginal() const;
+ bool isOriginal(bool v);
+ OwnedBy ownedByCtfe() const;
+ OwnedBy ownedByCtfe(OwnedBy v);
+
+ /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
+ * current stage and unmarks before return from this function.
+ * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
+ * (with infinite recursion) of this expression.
+ */
+ uint8_t stageflags;
+
StructDeclaration *sd; // which aggregate this is for
Expressions *elements; // parallels sd->fields[] with NULL entries for fields to skip
Type *stype; // final type of result (can be different from sd's type)
@@ -463,18 +474,7 @@ public:
StructLiteralExp *origin;
- /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
- * current stage and unmarks before return from this function.
- * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
- * (with infinite recursion) of this expression.
- */
- uint8_t stageflags;
-
- d_bool useStaticInit; // if this is true, use the StructDeclaration's init symbol
- d_bool isOriginal; // used when moving instances to indicate `this is this.origin`
- OwnedBy ownedByCtfe;
-
- static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
+ static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = nullptr);
bool equals(const RootObject * const o) const override;
StructLiteralExp *syntaxCopy() override;
@@ -486,7 +486,6 @@ class TypeExp final : public Expression
public:
TypeExp *syntaxCopy() override;
bool checkType() override;
- bool checkValue() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -497,7 +496,6 @@ public:
ScopeExp *syntaxCopy() override;
bool checkType() override;
- bool checkValue() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -509,7 +507,6 @@ public:
bool isLvalue() override;
bool checkType() override;
- bool checkValue() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -522,6 +519,7 @@ public:
Type *newtype;
Expressions *arguments; // Array of Expression's
Identifiers *names; // Array of names corresponding to expressions
+ Expression *placement; // if !NULL, placement expression
Expression *argprefix; // expression to be evaluated just before arguments[]
@@ -531,7 +529,7 @@ public:
Expression *lowering; // lowered druntime hook: `_d_newclass`
- static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments);
+ static NewExp *create(Loc loc, Expression *placement, Expression *thisexp, Type *newtype, Expressions *arguments);
NewExp *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -545,6 +543,7 @@ public:
Expression *thisexp; // if !NULL, 'this' for class being allocated
ClassDeclaration *cd; // class being instantiated
Expressions *arguments; // Array of Expression's to call class constructor
+ Expression *placement; // if !NULL, placement expression
NewAnonClassExp *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -578,7 +577,7 @@ class VarExp final : public SymbolExp
{
public:
d_bool delegateWasExtracted;
- static VarExp *create(const Loc &loc, Declaration *var, bool hasOverloads = true);
+ static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true);
bool equals(const RootObject * const o) const override;
bool isLvalue() override;
@@ -607,9 +606,7 @@ public:
bool equals(const RootObject * const o) const override;
FuncExp *syntaxCopy() override;
- const char *toChars() const override;
bool checkType() override;
- bool checkValue() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -691,9 +688,6 @@ public:
Expression *e1;
Expression *e2;
- Type *att1; // Save alias this type to detect recursion
- Type *att2; // Save alias this type to detect recursion
-
BinExp *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -746,7 +740,7 @@ public:
d_bool wantsym; // do not replace Symbol with its initializer during semantic()
d_bool arrow; // ImportC: if -> instead of .
- static DotIdExp *create(const Loc &loc, Expression *e, Identifier *ident);
+ static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
void accept(Visitor *v) override { v->visit(this); }
};
@@ -756,7 +750,6 @@ public:
TemplateDeclaration *td;
bool checkType() override;
- bool checkValue() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -777,7 +770,6 @@ public:
DotTemplateInstanceExp *syntaxCopy() override;
bool checkType() override;
- bool checkValue() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -827,10 +819,10 @@ public:
d_bool isUfcsRewrite; // the first argument was pushed in here by a UFCS rewrite
VarDeclaration *vthis2; // container for multi-context
- static CallExp *create(const Loc &loc, Expression *e, Expressions *exps);
- static CallExp *create(const Loc &loc, Expression *e);
- static CallExp *create(const Loc &loc, Expression *e, Expression *earg1);
- static CallExp *create(const Loc &loc, FuncDeclaration *fd, Expression *earg1);
+ static CallExp *create(Loc loc, Expression *e, Expressions *exps);
+ static CallExp *create(Loc loc, Expression *e);
+ static CallExp *create(Loc loc, Expression *e, Expression *earg1);
+ static CallExp *create(Loc loc, FuncDeclaration *fd, Expression *earg1);
CallExp *syntaxCopy() override;
bool isLvalue() override;
@@ -889,6 +881,7 @@ public:
// Possible to cast to one type while painting to another type
Type *to; // type to cast to
unsigned char mod; // MODxxxxx
+ d_bool trusted; // assume cast is safe
CastExp *syntaxCopy() override;
bool isLvalue() override;
@@ -903,7 +896,7 @@ public:
unsigned dim; // number of elements in the vector
OwnedBy ownedByCtfe;
- static VectorExp *create(const Loc &loc, Expression *e, Type *t);
+ static VectorExp *create(Loc loc, Expression *e, Type *t);
VectorExp *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -1059,7 +1052,6 @@ class LoweredAssignExp final : public AssignExp
public:
Expression *lowering;
- const char *toChars() const override;
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 7ae7f40..b02f6ea 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -3,12 +3,12 @@
*
* Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expressionsem.d, _expressionsem.d)
* Documentation: https://dlang.org/phobos/dmd_expressionsem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expressionsem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/expressionsem.d
*/
module dmd.expressionsem;
@@ -25,6 +25,7 @@ import dmd.astcodegen;
import dmd.astenums;
import dmd.canthrow;
import dmd.chkformat;
+import dmd.cond;
import dmd.ctorflow;
import dmd.dscope;
import dmd.dsymbol;
@@ -33,9 +34,9 @@ import dmd.dclass;
import dmd.dcast;
import dmd.delegatize;
import dmd.denum;
+import dmd.deps;
import dmd.dimport;
import dmd.dinterpret;
-import dmd.dmangle;
import dmd.dmodule;
import dmd.dstruct;
import dmd.dsymbolsem;
@@ -59,15 +60,16 @@ import dmd.initsem;
import dmd.inline;
import dmd.intrange;
import dmd.location;
+import dmd.mangle;
import dmd.mtype;
import dmd.mustuse;
import dmd.nspace;
+import dmd.nogc;
import dmd.objc;
import dmd.opover;
import dmd.optimize;
import dmd.parse;
import dmd.printast;
-import dmd.postordervisitor;
import dmd.root.array;
import dmd.root.ctfloat;
import dmd.root.filename;
@@ -80,6 +82,7 @@ import dmd.semantic3;
import dmd.sideeffect;
import dmd.safe;
import dmd.target;
+import dmd.templatesem : matchWithInstance;
import dmd.tokens;
import dmd.traits;
import dmd.typesem;
@@ -87,6 +90,7 @@ import dmd.typinf;
import dmd.utils;
import dmd.utils : arrayCastBigEndian;
import dmd.visitor;
+import dmd.visitor.postorder;
enum LOGSEMANTIC = false;
@@ -115,10 +119,9 @@ private bool isNeedThisScope(Scope* sc, Declaration d)
{
if (ad2 == ad)
return false;
- else if (ad2.isNested())
+ if (ad2.isNested())
continue;
- else
- return true;
+ return true;
}
if (FuncDeclaration f = s.isFuncDeclaration())
{
@@ -137,16 +140,26 @@ private bool isNeedThisScope(Scope* sc, Declaration d)
* buf = append generated string to buffer
* sc = context
* exps = array of Expressions
+ * loc = location of the pragma / mixin where this conversion was requested, for supplemental error
+ * fmt = format string for supplemental error. May contain 1 `%s` which prints the faulty expression
+ * expandTuples = whether tuples should be expanded rather than printed as tuple syntax
* Returns:
* true on error
*/
-bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
+bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps,
+ Loc loc, const(char)* fmt, bool expandTuples)
{
if (!exps)
return false;
foreach (ex; *exps)
{
+ bool error()
+ {
+ if (loc != Loc.initial && fmt)
+ errorSupplemental(loc, fmt, ex.toChars());
+ return true;
+ }
if (!ex)
continue;
auto sc2 = sc.startCTFE();
@@ -159,15 +172,16 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
// allowed to contain types as well as expressions
auto e4 = ctfeInterpretForPragmaMsg(e3);
if (!e4 || e4.op == EXP.error)
- return true;
+ return error();
// expand tuple
- if (auto te = e4.isTupleExp())
- {
- if (expressionsToString(buf, sc, te.exps))
- return true;
- continue;
- }
+ if (expandTuples)
+ if (auto te = e4.isTupleExp())
+ {
+ if (expressionsToString(buf, sc, te.exps, loc, fmt, true))
+ return error();
+ continue;
+ }
// char literals exp `.toStringExp` return `null` but we cant override it
// because in most contexts we don't want the conversion to succeed.
IntegerExp ie = e4.isIntegerExp();
@@ -178,9 +192,11 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
}
- if (StringExp se = e4.toStringExp())
+ StringExp se = e4.toStringExp();
+
+ if (se && se.type.nextOf().ty.isSomeChar)
buf.writestring(se.toUTF8(sc).peekString());
- else
+ else if (!(se && se.len == 0)) // don't print empty array literal `[]`
buf.writestring(e4.toString());
}
return false;
@@ -293,7 +309,7 @@ extern (D) bool findTempDecl(DotTemplateInstanceExp exp, Scope* sc)
* Returns:
* String literal, or `null` if error happens.
*/
-StringExp semanticString(Scope *sc, Expression exp, const char* s)
+StringExp semanticString(Scope* sc, Expression exp, const char* s)
{
sc = sc.startCTFE();
exp = exp.expressionSemantic(sc);
@@ -311,14 +327,11 @@ StringExp semanticString(Scope *sc, Expression exp, const char* s)
return null;
}
- auto se = e.toStringExp();
- if (!se)
- {
- error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`",
- s, exp.toChars(), exp.type.toChars());
- return null;
- }
- return se;
+ if (auto se = e.toStringExp())
+ return se;
+ error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`",
+ s, exp.toChars(), exp.type.toChars());
+ return null;
}
/****************************************
@@ -326,17 +339,75 @@ StringExp semanticString(Scope *sc, Expression exp, const char* s)
*/
StringExp toUTF8(StringExp se, Scope* sc)
{
- if (se.sz != 1)
+ if (se.sz == 1)
+ return se;
+ // Convert to UTF-8 string
+ se.committed = false;
+ Expression e = castTo(se, sc, Type.tchar.arrayOf());
+ e = e.optimize(WANTvalue);
+ auto result = e.isStringExp();
+ assert(result);
+ assert(result.sz == 1);
+ return result;
+}
+/********************************
+ * The type for a unary expression is incompatible.
+ * Print error message.
+ * Returns:
+ * ErrorExp
+ */
+private Expression incompatibleTypes(UnaExp e)
+{
+ if (e.e1.type.toBasetype() == Type.terror)
+ return e.e1;
+
+ if (e.e1.op == EXP.type)
{
- // Convert to UTF-8 string
- se.committed = false;
- Expression e = castTo(se, sc, Type.tchar.arrayOf());
- e = e.optimize(WANTvalue);
- auto result = e.isStringExp();
- assert(result.sz == 1);
- return result;
+ error(e.loc, "incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(e.op).ptr, e.e1.toErrMsg(), EXPtoString(e.op).ptr);
+ }
+ else
+ {
+ error(e.loc, "incompatible type for `%s(%s)`: `%s`", EXPtoString(e.op).ptr, e.e1.toErrMsg(), e.e1.type.toChars());
}
- return se;
+ return ErrorExp.get();
+}
+
+/********************************
+ * The types for a binary expression are incompatible.
+ * Print error message.
+ * Returns:
+ * ErrorExp
+ */
+extern (D) Expression incompatibleTypes(BinExp e, Scope* sc = null)
+{
+ if (e.e1.type.toBasetype() == Type.terror)
+ return e.e1;
+ if (e.e2.type.toBasetype() == Type.terror)
+ return e.e2;
+
+ // CondExp uses 'a ? b : c' but we're comparing 'b : c'
+ const(char)* thisOp = (e.op == EXP.question) ? ":" : EXPtoString(e.op).ptr;
+
+ if (sc && suggestBinaryOverloads(e, sc))
+ return ErrorExp.get();
+
+ if (e.e1.op == EXP.type || e.e2.op == EXP.type)
+ {
+ error(e.loc, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
+ e.e1.toErrMsg(), thisOp, e.e2.toErrMsg(), EXPtoString(e.op).ptr);
+ }
+ else if (e.e1.type.equals(e.e2.type))
+ {
+ error(e.loc, "incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
+ e.e1.toErrMsg(), thisOp, e.e2.toErrMsg(), e.e1.type.toChars());
+ }
+ else
+ {
+ auto ts = toAutoQualChars(e.e1.type, e.e2.type);
+ error(e.loc, "incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
+ e.e1.toErrMsg(), thisOp, e.e2.toErrMsg(), ts[0], ts[1]);
+ }
+ return ErrorExp.get();
}
private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
@@ -401,12 +472,12 @@ private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
// T opAssign floating yields a floating. Prevent truncating conversions (float to int).
// See https://issues.dlang.org/show_bug.cgi?id=3841.
- // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
+ // Should we also prevent double to float (type.isFloating() && type.size() < t2.size()) ?
if (op == EXP.addAssign || op == EXP.minAssign ||
op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
op == EXP.powAssign)
{
- if ((type.isintegral() && t2.isfloating()))
+ if ((type.isIntegral() && t2.isFloating()))
{
warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
}
@@ -418,17 +489,17 @@ private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
// Any multiplication by an imaginary or complex number yields a complex result.
// r *= c, i*=c, r*=i, i*=i are all forbidden operations.
const(char)* opstr = EXPtoString(op).ptr;
- if (t1.isreal() && t2.iscomplex())
+ if (t1.isReal() && t2.isComplex())
{
error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
return ErrorExp.get();
}
- else if (t1.isimaginary() && t2.iscomplex())
+ else if (t1.isImaginary() && t2.isComplex())
{
error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
return ErrorExp.get();
}
- else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
+ else if ((t1.isReal() || t1.isImaginary()) && t2.isImaginary())
{
error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
return ErrorExp.get();
@@ -440,98 +511,92 @@ private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
{
// Addition or subtraction of a real and an imaginary is a complex result.
// Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
- if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
+ if ((t1.isReal() && (t2.isImaginary() || t2.isComplex())) || (t1.isImaginary() && (t2.isReal() || t2.isComplex())))
{
error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
return ErrorExp.get();
}
- if (type.isreal() || type.isimaginary())
+ if (type.isReal() || type.isImaginary())
{
- assert(global.errors || t2.isfloating());
+ assert(global.errors || t2.isFloating());
e2 = e2.castTo(sc, t1);
}
}
- if (op == EXP.mulAssign)
+ if (op == EXP.mulAssign && t2.isFloating())
{
- if (t2.isfloating())
+ if (t1.isReal())
{
- if (t1.isreal())
+ if (t2.isImaginary() || t2.isComplex())
{
- if (t2.isimaginary() || t2.iscomplex())
- {
- e2 = e2.castTo(sc, t1);
- }
- }
- else if (t1.isimaginary())
- {
- if (t2.isimaginary() || t2.iscomplex())
- {
- switch (t1.ty)
- {
- case Timaginary32:
- t2 = Type.tfloat32;
- break;
-
- case Timaginary64:
- t2 = Type.tfloat64;
- break;
-
- case Timaginary80:
- t2 = Type.tfloat80;
- break;
-
- default:
- assert(0);
- }
- e2 = e2.castTo(sc, t2);
- }
+ e2 = e2.castTo(sc, t1);
}
}
- }
- else if (op == EXP.divAssign)
- {
- if (t2.isimaginary())
+ else if (t1.isImaginary())
{
- if (t1.isreal())
- {
- // x/iv = i(-x/v)
- // Therefore, the result is 0
- e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
- e2.type = t1;
- Expression e = new AssignExp(loc, e1, e2);
- e.type = t1;
- return e;
- }
- else if (t1.isimaginary())
+ if (t2.isImaginary() || t2.isComplex())
{
- Type t3;
switch (t1.ty)
{
case Timaginary32:
- t3 = Type.tfloat32;
+ t2 = Type.tfloat32;
break;
case Timaginary64:
- t3 = Type.tfloat64;
+ t2 = Type.tfloat64;
break;
case Timaginary80:
- t3 = Type.tfloat80;
+ t2 = Type.tfloat80;
break;
default:
assert(0);
}
- e2 = e2.castTo(sc, t3);
- Expression e = new AssignExp(loc, e1, e2);
- e.type = t1;
- return e;
+ e2 = e2.castTo(sc, t2);
+ }
+ }
+ }
+ else if (op == EXP.divAssign && t2.isImaginary())
+ {
+ if (t1.isReal())
+ {
+ // x/iv = i(-x/v)
+ // Therefore, the result is 0
+ e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
+ e2.type = t1;
+ Expression e = new AssignExp(loc, e1, e2);
+ e.type = t1;
+ return e;
+ }
+ else if (t1.isImaginary())
+ {
+ Type t3;
+ switch (t1.ty)
+ {
+ case Timaginary32:
+ t3 = Type.tfloat32;
+ break;
+
+ case Timaginary64:
+ t3 = Type.tfloat64;
+ break;
+
+ case Timaginary80:
+ t3 = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
}
+ e2 = e2.castTo(sc, t3);
+ Expression e = new AssignExp(loc, e1, e2);
+ e.type = t1;
+ return e;
}
}
else if (op == EXP.modAssign)
{
- if (t2.iscomplex())
+ if (t2.isComplex())
{
error(loc, "cannot perform modulo complex arithmetic");
return ErrorExp.get();
@@ -547,7 +612,7 @@ 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.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
+ if (sc.ctfe ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
{
/* Even if opDollar is needed, 'e1' should be evaluate only once. So
* Rewrite:
@@ -602,25 +667,27 @@ TupleDeclaration isAliasThisTuple(Expression e)
* Runs semantic on ae.arguments. Declares temporary variables
* if '$' was used.
*/
-Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
+Expression resolveOpDollar(Scope* sc, ArrayExp ae, out Expression pe0)
{
assert(!ae.lengthVar);
- *pe0 = null;
AggregateDeclaration ad = isAggregate(ae.e1.type);
- Dsymbol slice = search_function(ad, Id.slice);
+ Dsymbol slice = search_function(ad, Id.opSlice);
//printf("slice = %s %s\n", slice.kind(), slice.toChars());
+ Expression fallback()
+ {
+ if (ae.arguments.length == 1)
+ return null;
+ error(ae.loc, "multi-dimensional slicing requires template `opSlice`");
+ return ErrorExp.get();
+ }
foreach (i, e; *ae.arguments)
{
if (i == 0)
- *pe0 = extractOpDollarSideEffect(sc, ae);
+ pe0 = extractOpDollarSideEffect(sc, ae);
if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
{
- Lfallback:
- if (ae.arguments.length == 1)
- return null;
- error(ae.loc, "multi-dimensional slicing requires template `opSlice`");
- return ErrorExp.get();
+ return fallback();
}
//printf("[%d] e = %s\n", i, e.toChars());
@@ -639,7 +706,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
// If $ was used, declare it now
Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
de = de.expressionSemantic(sc);
- *pe0 = Expression.combine(*pe0, de);
+ pe0 = Expression.combine(pe0, de);
}
sc = sc.pop();
@@ -654,22 +721,22 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
(*fargs)[0] = ie.lwr;
(*fargs)[1] = ie.upr;
- uint xerrors = global.startGagging();
+ const xerrors = global.startGagging();
sc = sc.push();
FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
sc = sc.pop();
global.endGagging(xerrors);
if (!fslice)
- goto Lfallback;
+ return fallback();
- e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
+ e = new DotTemplateInstanceExp(ae.loc, ae.e1, Id.opSlice, tiargs);
e = new CallExp(ae.loc, e, fargs);
e = e.expressionSemantic(sc);
}
if (!e.type)
{
- error(ae.loc, "`%s` has no value", e.toChars());
+ error(ae.loc, "`%s` has no value", e.toErrMsg());
e = ErrorExp.get();
}
if (e.op == EXP.error)
@@ -686,7 +753,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
* Returns:
* ae, or ErrorExp if errors occurred
*/
-Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
+Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, ref Expression pe0)
{
//assert(!ae.lengthVar);
if (!ie)
@@ -706,7 +773,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* p
e = resolveProperties(sc, e);
if (!e.type)
{
- error(ae.loc, "`%s` has no value", e.toChars());
+ error(ae.loc, "`%s` has no value", e.toErrMsg());
errors = true;
}
return e;
@@ -723,7 +790,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* p
// If $ was used, declare it now
Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
de = de.expressionSemantic(sc);
- *pe0 = Expression.combine(*pe0, de);
+ pe0 = Expression.combine(pe0, de);
}
sc = sc.pop();
@@ -756,21 +823,58 @@ extern(D) bool arrayExpressionSemantic(
* Params:
* sc = the scope where the expression is encountered
* e = the expression the needs to be moved or copied (source)
- * t = if the struct defines a copy constructor, the type of the destination
- *
+ * t = if the struct defines a copy constructor, the type of the destination (can be NULL)
+ * nrvo = true if the generated copy can be treated as NRVO
+ * move = true to allow a move constructor to be used, false to prevent infinite recursion
* Returns:
* The expression that copy constructs or moves the value.
*/
-extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
+extern (D) Expression doCopyOrMove(Scope* sc, Expression e, Type t, bool nrvo, bool move = false)
{
+ //printf("doCopyOrMove() %s\n", toChars(e));
+ StructDeclaration sd;
+ if (t)
+ {
+ if (auto ts = t.isTypeStruct())
+ sd = ts.sym;
+ }
+
if (auto ce = e.isCondExp())
{
- ce.e1 = doCopyOrMove(sc, ce.e1);
- ce.e2 = doCopyOrMove(sc, ce.e2);
+ ce.e1 = doCopyOrMove(sc, ce.e1, null, nrvo);
+ ce.e2 = doCopyOrMove(sc, ce.e2, null, nrvo);
+ }
+ else if (e.isLvalue())
+ {
+ e = callCpCtor(sc, e, t, nrvo);
+ }
+ else if (move && sd && sd.hasMoveCtor && !e.isCallExp() && !e.isStructLiteralExp())
+ {
+ // #move
+ /* Rewrite as:
+ * S __copyrvalue;
+ * __copyrvalue.moveCtor(e);
+ * __copyrvalue;
+ */
+ VarDeclaration vd = new VarDeclaration(e.loc, e.type, Identifier.generateId("__copyrvalue"), null);
+ if (nrvo)
+ vd.nrvo = true;
+ vd.storage_class |= STC.nodtor;
+ vd.dsymbolSemantic(sc);
+ Expression de = new DeclarationExp(e.loc, vd);
+ Expression ve = new VarExp(e.loc, vd);
+
+ Expression er;
+ er = new DotIdExp(e.loc, ve, Id.ctor); // ve.ctor
+ er = new CallExp(e.loc, er, e); // ve.ctor(e)
+ er = new CommaExp(e.loc, er, new VarExp(e.loc, vd)); // ve.ctor(e),vd
+ er = Expression.combine(de, er); // de,ve.ctor(e),vd
+
+ e = er.expressionSemantic(sc);
}
else
{
- e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
+ e = valueNoDtor(e);
}
return e;
}
@@ -779,47 +883,51 @@ extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
* If e is an instance of a struct, and that struct has a copy constructor,
* rewrite e as:
* (tmp = e),tmp
- * Input:
+ * Params:
* sc = just used to specify the scope of created temporary variable
* destinationType = the type of the object on which the copy constructor is called;
* may be null if the struct defines a postblit
+ * nrvo = true if the generated copy can be treated as NRVO
*/
-private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
+private Expression callCpCtor(Scope* sc, Expression e, Type destinationType, bool nrvo)
{
- if (auto ts = e.type.baseElemOf().isTypeStruct())
- {
- StructDeclaration sd = ts.sym;
- if (sd.postblit || sd.hasCopyCtor)
- {
- /* Create a variable tmp, and replace the argument e with:
- * (tmp = e),tmp
- * and let AssignExp() handle the construction.
- * This is not the most efficient, ideally tmp would be constructed
- * directly onto the stack.
- */
- auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
- if (sd.hasCopyCtor && destinationType)
- {
- // https://issues.dlang.org/show_bug.cgi?id=22619
- // If the destination type is inout we can preserve it
- // only if inside an inout function; if we are not inside
- // an inout function, then we will preserve the type of
- // the source
- if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
- tmp.type = e.type;
- else
- tmp.type = destinationType;
- }
- tmp.storage_class |= STC.nodtor;
- tmp.dsymbolSemantic(sc);
- Expression de = new DeclarationExp(e.loc, tmp);
- Expression ve = new VarExp(e.loc, tmp);
- de.type = Type.tvoid;
- ve.type = e.type;
- return Expression.combine(de, ve);
- }
- }
- return e;
+ //printf("callCpCtor(e: %s et: %s destinationType: %s\n", toChars(e), toChars(e.type), toChars(destinationType));
+ auto ts = e.type.baseElemOf().isTypeStruct();
+
+ if (!ts)
+ return e;
+ StructDeclaration sd = ts.sym;
+ if (!sd.postblit && !sd.hasCopyCtor)
+ return e;
+
+ /* Create a variable tmp, and replace the argument e with:
+ * (tmp = e),tmp
+ * and let AssignExp() handle the construction.
+ * This is not the most efficient, ideally tmp would be constructed
+ * directly onto the stack.
+ */
+ VarDeclaration tmp = copyToTemp(STC.rvalue, "__copytmp", e);
+ if (nrvo)
+ tmp.nrvo = true;
+ if (sd.hasCopyCtor && destinationType)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=22619
+ // If the destination type is inout we can preserve it
+ // only if inside an inout function; if we are not inside
+ // an inout function, then we will preserve the type of
+ // the source
+ if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
+ tmp.type = e.type;
+ else
+ tmp.type = destinationType;
+ }
+ tmp.storage_class |= STC.nodtor;
+ tmp.dsymbolSemantic(sc);
+ Expression de = new DeclarationExp(e.loc, tmp);
+ Expression ve = new VarExp(e.loc, tmp);
+ de.type = Type.tvoid;
+ ve.type = e.type;
+ return Expression.combine(de, ve);
}
/************************************************
@@ -828,6 +936,7 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
*/
Expression valueNoDtor(Expression e)
{
+ //printf("valueNoDtor() %s\n", toChars(e));
auto ex = lastComma(e);
if (auto ce = ex.isCallExp())
@@ -948,7 +1057,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
SearchOptFlags flags = SearchOpt.all;
Dsymbol s;
- if (sc.flags & SCOPE.ignoresymbolvisibility)
+ if (sc.ignoresymbolvisibility)
flags |= SearchOpt.ignoreVisibility;
// First look in local scopes
@@ -965,8 +1074,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
FuncDeclaration f = s.isFuncDeclaration();
if (f)
{
- TemplateDeclaration td = getFuncTemplateDecl(f);
- if (td)
+ if (TemplateDeclaration td = getFuncTemplateDecl(f))
{
if (td.overroot)
td = td.overroot;
@@ -1033,41 +1141,41 @@ private void hookDtors(CondExp ce, Scope* sc)
override void visit(DeclarationExp e)
{
auto v = e.declaration.isVarDeclaration();
- if (v && !v.isDataseg())
+ if (!v || v.isDataseg())
+ return;
+
+ if (v._init)
{
- if (v._init)
- {
- if (auto ei = v._init.isExpInitializer())
- walkPostorder(ei.exp, this);
- }
+ if (auto ei = v._init.isExpInitializer())
+ walkPostorder(ei.exp, this);
+ }
- if (v.edtor)
- walkPostorder(v.edtor, this);
+ if (v.edtor)
+ walkPostorder(v.edtor, this);
- if (v.needsScopeDtor())
- {
- if (!vcond)
- {
- vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
- vcond.dsymbolSemantic(sc);
+ if (!v.needsScopeDtor())
+ return;
- Expression de = new DeclarationExp(ce.econd.loc, vcond);
- de = de.expressionSemantic(sc);
+ if (!vcond)
+ {
+ vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
+ vcond.dsymbolSemantic(sc);
- Expression ve = new VarExp(ce.econd.loc, vcond);
- ce.econd = Expression.combine(de, ve);
- }
+ Expression de = new DeclarationExp(ce.econd.loc, vcond);
+ de = de.expressionSemantic(sc);
- //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
- Expression ve = new VarExp(vcond.loc, vcond);
- if (isThen)
- v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
- else
- v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
- v.edtor = v.edtor.expressionSemantic(sc);
- //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
- }
+ Expression ve = new VarExp(ce.econd.loc, vcond);
+ ce.econd = Expression.combine(de, ve);
}
+
+ //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
+ Expression ve = new VarExp(vcond.loc, vcond);
+ if (isThen)
+ v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
+ else
+ v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
+ v.edtor = v.edtor.expressionSemantic(sc);
+ //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
}
}
@@ -1103,7 +1211,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
eleft = die.e1;
Type t = eleft.type.toBasetype();
- if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
+ if (t.isStaticOrDynamicArray() || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
{
/* Built-in types and arrays have no callable properties, so do shortcut.
* It is necessary in: e.init()
@@ -1143,6 +1251,9 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
}
else
{
+ if (arrayExpressionSemantic(ce.arguments.peekSlice(), sc))
+ return ErrorExp.get();
+
if (Expression ey = die.dotIdSemanticProp(sc, 1))
{
if (ey.op == EXP.error)
@@ -1150,19 +1261,11 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
ce.e1 = ey;
if (isDotOpDispatch(ey))
{
- // even opDispatch and UFCS must have valid arguments,
- // so now that we've seen indication of a problem,
- // check them for issues.
- Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
-
- uint errors = global.startGagging();
+ const errors = global.startGagging();
e = ce.expressionSemantic(sc);
if (!global.endGagging(errors))
return e;
- if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
- return ErrorExp.get();
-
/* fall down to UFCS */
}
else
@@ -1349,11 +1452,6 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2
auto arguments = new Expressions(1);
(*arguments)[0] = eleft;
e = new CallExp(loc, e, arguments);
-
- // https://issues.dlang.org/show_bug.cgi?id=24017
- if (sc.flags & SCOPE.debug_)
- e.isCallExp().inDebugStatement = true;
-
e = e.expressionSemantic(sc);
return e;
}
@@ -1375,12 +1473,12 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
auto td = s.isTemplateDeclaration();
if (fd)
{
- if (fd.type.isTypeFunction().isproperty)
+ if (fd.type.isTypeFunction().isProperty)
return resolveProperties(sc, e1);
}
else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
{
- if (fd.type.isTypeFunction().isproperty ||
+ if (fd.type.isTypeFunction().isProperty ||
(fd.storage_class2 & STC.property) ||
(td._scope.stc & STC.property))
return resolveProperties(sc, e1);
@@ -1396,7 +1494,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
{
if (auto fd = td.onemember.isFuncDeclaration())
{
- if (fd.type.isTypeFunction().isproperty ||
+ if (fd.type.isTypeFunction().isProperty ||
(fd.storage_class2 & STC.property) ||
(td._scope.stc & STC.property))
return resolveProperties(sc, e1);
@@ -1408,7 +1506,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
Expression handleFuncDecl(FuncDeclaration fd)
{
assert(fd);
- if (fd.type.isTypeFunction().isproperty)
+ if (fd.type.isTypeFunction().isProperty)
return resolveProperties(sc, e1);
return e1;
}
@@ -1420,7 +1518,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
}
else if (auto oe = e1.isOverExp())
return handleOverloadSet(oe.vars);
- else if (auto dti = e1.isDotTemplateInstanceExp())
+ if (auto dti = e1.isDotTemplateInstanceExp())
{
if (dti.ti.tempdecl)
if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
@@ -1428,7 +1526,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
}
else if (auto dte = e1.isDotTemplateExp())
return handleTemplateDecl(dte.td);
- else if (auto se = e1.isScopeExp())
+ if (auto se = e1.isScopeExp())
{
Dsymbol s = se.sds;
TemplateInstance ti = s.isTemplateInstance();
@@ -1438,7 +1536,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
}
else if (auto et = e1.isTemplateExp())
return handleTemplateDecl(et.td);
- else if (e1.isDotVarExp() && e1.type.isTypeFunction())
+ if (e1.isDotVarExp() && e1.type.isTypeFunction())
{
DotVarExp dve = e1.isDotVarExp();
return handleFuncDecl(dve.var.isFuncDeclaration());
@@ -1461,7 +1559,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
* Returns:
* `s` turned into an expression, `ErrorExp` if an error occurred
*/
-Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
+Expression symbolToExp(Dsymbol s, Loc loc, Scope* sc, bool hasOverloads)
{
static if (LOGSEMANTIC)
{
@@ -1506,8 +1604,8 @@ Lagain:
{
if (sd.isSystem())
{
- if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
- "cannot access `@system` variable `%s` in @safe code", sd))
+ if (sc.setUnsafePreview(sc.previews.systemVariables, false, loc,
+ "access `@system` variable `%s`", sd))
{
if (auto v = sd.isVarDeclaration())
{
@@ -1690,7 +1788,7 @@ Lagain:
* Returns:
* Expression representing the `this` for the var
*/
-private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
+private Expression getRightThis(Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
{
//printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
L1:
@@ -1857,7 +1955,7 @@ private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc)
* we can only call other pure functions.
* Returns true if error occurs.
*/
-private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc)
+private bool checkPurity(FuncDeclaration f, Loc loc, Scope* sc)
{
if (!sc.func)
return false;
@@ -1865,7 +1963,7 @@ private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc)
return false;
if (sc.intypeof == 1)
return false;
- if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+ if (sc.ctfe || sc.debug_)
return false;
// If the call has a pure parent, then the called func must be pure.
@@ -1876,7 +1974,7 @@ private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc)
f.toPrettyChars());
if (!f.isDtorDeclaration())
- errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_);
+ errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_, global.errorSink);
f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
return true;
@@ -1898,7 +1996,7 @@ private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc)
* check = current check (e.g. whether it's pure)
* checkName = the kind of check (e.g. `"pure"`)
*/
-void checkOverriddenDtor(FuncDeclaration f, Scope* sc, const ref Loc loc,
+void checkOverriddenDtor(FuncDeclaration f, Scope* sc, Loc loc,
scope bool function(DtorDeclaration) check, const string checkName)
{
auto dd = f.isDtorDeclaration();
@@ -1959,12 +2057,67 @@ void checkOverriddenDtor(FuncDeclaration f, Scope* sc, const ref Loc loc,
}
}
+/********************************************
+ * Print the reason why `fd` was inferred `@system` as a supplemental error
+ * Params:
+ * fd = function to check
+ * maxDepth = up to how many functions deep to report errors
+ * deprecation = print deprecations instead of errors
+ * stc = storage class of attribute to check
+ * eSink = where the error messages go
+ */
+public void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc, ErrorSink eSink)
+{
+ auto errorFunc = deprecation ? &eSink.deprecationSupplemental : &eSink.errorSupplemental;
+
+ AttributeViolation* s;
+ string attr;
+ if (stc & STC.safe)
+ {
+ s = fd.safetyViolation;
+ attr = "@safe";
+ }
+ else if (stc & STC.pure_)
+ {
+ s = fd.pureViolation;
+ attr = "pure";
+ }
+ else if (stc & STC.nothrow_)
+ {
+ s = fd.nothrowViolation;
+ attr = "nothrow";
+ }
+ else if (stc & STC.nogc)
+ {
+ s = fd.nogcViolation;
+ attr = "@nogc";
+ }
+
+ if (!s)
+ return;
+
+ if (s.action.length > 0)
+ {
+ errorFunc(s.loc, "and %.*s makes it fail to infer `%.*s`", s.action.fTuple.expand, attr.fTuple.expand);
+ }
+ else if (s.fd)
+ {
+ if (maxDepth > 0)
+ {
+ errorFunc(s.loc, "which calls `%s`", s.fd.toErrMsg());
+ errorSupplementalInferredAttr(s.fd, maxDepth - 1, deprecation, stc, eSink);
+ }
+ }
+ else
+ assert(0);
+}
+
/*******************************************
* Accessing variable v.
* Check for purity and safety violations.
* Returns true if error occurs.
*/
-private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
+private bool checkPurity(VarDeclaration v, Loc loc, Scope* sc)
{
//printf("v = %s %s\n", v.type.toChars(), v.toChars());
/* Look for purity and safety violations when accessing variable v
@@ -1974,7 +2127,7 @@ private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
return false;
if (sc.intypeof == 1)
return false; // allow violations inside typeof(expression)
- if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+ if (sc.ctfe || sc.debug_)
return false; // allow violations inside compile-time evaluated expressions and debug conditionals
if (v.ident == Id.ctfe)
return false; // magic variable never violates pure and safe
@@ -2009,7 +2162,7 @@ private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
if (v.ident == Id.gate)
return false;
- if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v))
+ if (checkImpure(sc, loc, "accessing mutable static data `%s`", v))
{
error(loc, "`pure` %s `%s` cannot access mutable static data `%s`",
sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
@@ -2047,23 +2200,21 @@ private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
FuncDeclaration ff = s.isFuncDeclaration();
if (!ff)
break;
- if (ff.isNested() || ff.isThis())
- {
- if (ff.type.isImmutable() ||
- ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
- {
- OutBuffer ffbuf;
- OutBuffer vbuf;
- MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
- MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
- error(loc, "%s%s `%s` cannot access %sdata `%s`",
- ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
- err = true;
- break;
- }
- continue;
+ if (!ff.isNested() && !ff.isThis())
+ break;
+ if (ff.type.isImmutable() ||
+ ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
+ {
+ OutBuffer ffbuf;
+ OutBuffer vbuf;
+ MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
+ MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
+ error(loc, "%s%s `%s` cannot access %sdata `%s`",
+ ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
+ err = true;
+ break;
}
- break;
+ continue;
}
}
@@ -2071,8 +2222,7 @@ private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
*/
if (v.storage_class & STC.gshared)
{
- if (sc.setUnsafe(false, loc,
- "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
+ if (sc.setUnsafe(false, loc, "accessing `__gshared` data `%s`", v))
{
err = true;
}
@@ -2104,9 +2254,9 @@ private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc)
return false;
if (sc.intypeof == 1)
return false;
- if (sc.flags & SCOPE.debug_)
+ if (sc.debug_)
return false;
- if ((sc.flags & SCOPE.ctfe) && sc.func)
+ if (sc.ctfe && sc.func)
return false;
if (!sc.func)
@@ -2140,7 +2290,7 @@ private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc)
sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
prettyChars);
if (!f.isDtorDeclaration)
- errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe);
+ errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe, global.errorSink);
.errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
@@ -2154,12 +2304,12 @@ private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc)
if (sc.func.isSafeBypassingInference())
{
.deprecation(loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
- errorSupplementalInferredAttr(f, 10, true, STC.safe);
+ errorSupplementalInferredAttr(f, 10, true, STC.safe, global.errorSink);
}
else if (!sc.func.safetyViolation)
{
import dmd.func : AttributeViolation;
- sc.func.safetyViolation = new AttributeViolation(loc, null, f, null, null);
+ sc.func.safetyViolation = new AttributeViolation(loc, f);
}
}
return false;
@@ -2179,7 +2329,7 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
return false;
if (sc.intypeof == 1)
return false;
- if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+ if (sc.ctfe || sc.debug_)
return false;
/* The original expressions (`new S(...)` or `new S[...]``) will be
* verified instead. This is to keep errors related to the original code
@@ -2188,70 +2338,76 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT || f.ident == Id._d_newarraymTX)
return false;
- if (!f.isNogc())
- {
- if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f))
- {
- if (loc.linnum == 0) // e.g. implicitly generated dtor
- loc = sc.func.loc;
+ if (f.isNogc())
+ return false;
- // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
- // so don't print anything to avoid double error messages.
- if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
- || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
- || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
- {
- error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
- sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
+ if (isRootTraitsCompilesScope(sc) ? !sc.func.isNogcBypassingInference() : !sc.func.setGCCall(f))
+ return false;
- if (!f.isDtorDeclaration)
- f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc);
- }
+ if (loc == Loc.initial) // e.g. implicitly generated dtor
+ loc = sc.func.loc;
- f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
+ // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
+ // so don't print anything to avoid double error messages.
+ if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
+ || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
+ || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
+ {
+ error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
+ sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
- return true;
- }
+ if (!f.isDtorDeclaration)
+ f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc, global.errorSink);
}
- return false;
+
+ f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().isNogc, "non-@nogc");
+
+ return true;
}
/********************************************
- * Check that the postblit is callable if t is an array of structs.
- * Returns true if error happens.
+ * Check that the postblit of `t` isn't @disabled and has the right
+ * function attributes for this scope.
+ *
+ * Params:
+ * 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
*/
private bool checkPostblit(Type t, ref Loc loc, Scope* sc)
{
- if (auto ts = t.baseElemOf().isTypeStruct())
+ auto ts = t.baseElemOf().isTypeStruct();
+ if (!ts)
+ return false;
+
+ if (global.params.useTypeInfo && Type.dtypeinfo)
{
- if (global.params.useTypeInfo && Type.dtypeinfo)
- {
- // https://issues.dlang.org/show_bug.cgi?id=11395
- // Require TypeInfo generation for array concatenation
- semanticTypeInfo(sc, t);
- }
+ // https://issues.dlang.org/show_bug.cgi?id=11395
+ // Require TypeInfo generation for array concatenation
+ semanticTypeInfo(sc, t);
+ }
- StructDeclaration sd = ts.sym;
- if (sd.postblit)
- {
- if (sd.postblit.checkDisabled(loc, sc))
- return true;
+ StructDeclaration sd = ts.sym;
+ if (!sd.postblit)
+ return false;
- //checkDeprecated(sc, sd.postblit); // necessary?
- sd.postblit.checkPurity(loc, sc);
- sd.postblit.checkSafety(loc, sc);
- sd.postblit.checkNogc(loc, sc);
- //checkAccess(sd, loc, sc, sd.postblit); // necessary?
- return false;
- }
- }
- return false;
+ if (sd.postblit.checkDisabled(loc, sc))
+ return true;
+
+ //checkDeprecated(sc, sd.postblit); // necessary?
+ //checkAccess(sd, loc, sc, sd.postblit); // necessary?
+ bool result = false;
+ result |= sd.postblit.checkPurity(loc, sc);
+ result |= sd.postblit.checkSafety(loc, sc);
+ result |= sd.postblit.checkNogc(loc, sc);
+ return result;
}
/***************************************
* Pull out any properties.
*/
-private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null)
+private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, Type[2]* aliasThisStop = null)
{
//printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
Loc loc = e1.loc;
@@ -2304,37 +2460,33 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
return e.expressionSemantic(sc);
}
}
+ for (size_t i = 0; i < os.a.length; i++)
{
- for (size_t i = 0; i < os.a.length; i++)
+ FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
+ if (!f)
+ continue;
+ if (f.errors)
+ return ErrorExp.get();
+ fd = f;
+ assert(fd.type.ty == Tfunction);
+ auto tf = fd.type.isTypeFunction();
+ if (!tf.isRef && e2)
{
- if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
- {
- if (f.errors)
- return ErrorExp.get();
- fd = f;
- assert(fd.type.ty == Tfunction);
- auto tf = fd.type.isTypeFunction();
- if (!tf.isref && e2)
- {
- error(loc, "%s is not an lvalue", e1.toChars());
- return ErrorExp.get();
- }
- }
+ error(loc, "%s is not an lvalue", e1.toErrMsg());
+ return ErrorExp.get();
}
- if (fd)
+ }
+ if (fd)
+ {
+ Expression e = new CallExp(loc, e1);
+ if (e2)
{
- Expression e = new CallExp(loc, e1);
- if (e2)
- {
- e = new AssignExp(loc, e, e2);
- if (saveAtts)
- {
- (cast(BinExp)e).att1 = saveAtts.att1;
- (cast(BinExp)e).att2 = saveAtts.att2;
- }
- }
+ e = new AssignExp(loc, e, e2);
+ if (aliasThisStop)
+ return e.expressionSemantic(sc, *aliasThisStop);
return e.expressionSemantic(sc);
}
+ return e.expressionSemantic(sc);
}
if (e2)
goto Leprop;
@@ -2391,7 +2543,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
tthis = dve.e1.type;
goto Lfd;
}
- else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
+ else if (sc && sc.inCfile && e1.isVarExp() && !e2)
{
// ImportC: do not implicitly call function if no ( ) are present
}
@@ -2422,33 +2574,28 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
return e.expressionSemantic(sc);
}
}
+ FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
+ if (fd && fd.type)
{
- FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
- if (fd && fd.type)
+ if (fd.errors)
+ return ErrorExp.get();
+ TypeFunction tf = fd.type.isTypeFunction();
+ if (!e2 || tf.isRef)
{
- if (fd.errors)
- return ErrorExp.get();
- TypeFunction tf = fd.type.isTypeFunction();
- if (!e2 || tf.isref)
+ Expression e = new CallExp(loc, e1);
+ if (e2)
{
- Expression e = new CallExp(loc, e1);
- if (e2)
- {
- e = new AssignExp(loc, e, e2);
- if (saveAtts)
- {
- (cast(BinExp)e).att1 = saveAtts.att1;
- (cast(BinExp)e).att2 = saveAtts.att2;
- }
- }
- return e.expressionSemantic(sc);
+ e = new AssignExp(loc, e, e2);
+ if (aliasThisStop)
+ return e.expressionSemantic(sc, *aliasThisStop);
}
+ return e.expressionSemantic(sc);
}
}
- if (FuncDeclaration fd = s.isFuncDeclaration())
+ if (FuncDeclaration fd2 = s.isFuncDeclaration())
{
// Keep better diagnostic message for invalid property usage of functions
- assert(fd.type.ty == Tfunction);
+ assert(fd2.type.ty == Tfunction);
Expression e = new CallExp(loc, e1, e2);
return e.expressionSemantic(sc);
}
@@ -2493,13 +2640,13 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
if (!e1.type)
{
- error(loc, "cannot resolve type for %s", e1.toChars());
+ error(loc, "cannot resolve type for %s", e1.toErrMsg());
e1 = ErrorExp.get();
}
return e1;
Leprop:
- error(loc, "not a property %s", e1.toChars());
+ error(loc, "not a property %s", e1.toErrMsg());
return ErrorExp.get();
}
@@ -2507,20 +2654,19 @@ private bool checkRightThis(Expression e, Scope* sc)
{
if (e.op == EXP.error)
return true;
- if (e.op == EXP.variable && e.type.ty != Terror)
- {
- VarExp ve = cast(VarExp)e;
- if (isNeedThisScope(sc, ve.var))
- {
- //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
- // sc.intypeof, sc.getStructClassScope(), func, fdthis);
- auto t = ve.var.isThis();
- assert(t);
- error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars());
- return true;
- }
- }
- return false;
+ if (e.op != EXP.variable || e.type.ty == Terror)
+ return false;
+
+ VarExp ve = cast(VarExp)e;
+ if (!isNeedThisScope(sc, ve.var))
+ return false;
+
+ //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
+ // sc.intypeof, sc.getStructClassScope(), func, fdthis);
+ auto t = ve.var.isThis();
+ assert(t);
+ error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars());
+ return true;
}
Expression resolveProperties(Scope* sc, Expression e)
@@ -2564,7 +2710,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
e = resolveProperties(sc, e);
if (!e.type)
{
- error(e.loc, "`%s` has no value", e.toChars());
+ error(e.loc, "`%s` has no value", e.toErrMsg());
t0 = Type.terror;
continue;
}
@@ -2587,7 +2733,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
continue;
}
- e = doCopyOrMove(sc, e);
+ e = doCopyOrMove(sc, e, null, false);
if (!foundType && t0 && !t0.equals(e.type))
{
@@ -2643,7 +2789,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
return t0;
}
-private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
+private Expression opAssignToOp(Loc loc, EXP op, Expression e1, Expression e2) @safe
{
Expression e;
switch (op)
@@ -2733,56 +2879,57 @@ private Expression rewriteOpAssign(BinExp exp)
* Params:
* sc = scope
* argumentList = arguments to function
- * reportErrors = whether or not to report errors here. Some callers are not
+ * eSink = if not null, used to report errors. Some callers are not
* checking actual function params, so they'll do their own error reporting
* Returns:
* `true` when a semantic error occurred
*/
-private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
+private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, ErrorSink eSink)
{
Expressions* exps = argumentList.arguments;
+ if (!exps)
+ return false;
+
+ expandTuples(exps, argumentList.names);
+
bool err = false;
- if (exps)
+ for (size_t i = 0; i < exps.length; i++)
{
- expandTuples(exps, argumentList.names);
-
- for (size_t i = 0; i < exps.length; i++)
+ Expression arg = (*exps)[i];
+ arg = resolveProperties(sc, arg);
+ arg = arg.arrayFuncConv(sc);
+ if (arg.op == EXP.type)
{
- Expression arg = (*exps)[i];
- arg = resolveProperties(sc, arg);
- arg = arg.arrayFuncConv(sc);
- if (arg.op == EXP.type)
- {
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- arg = resolveAliasThis(sc, arg);
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ arg = resolveAliasThis(sc, arg);
- if (arg.op == EXP.type)
- {
- if (reportErrors)
- {
- error(arg.loc, "cannot pass type `%s` as a function argument", arg.toChars());
- arg = ErrorExp.get();
- }
- err = true;
- }
- }
- else if (arg.type.toBasetype().ty == Tfunction)
+ if (arg.op == EXP.type)
{
- if (reportErrors)
+ if (eSink)
{
- error(arg.loc, "cannot pass function `%s` as a function argument", arg.toChars());
+ eSink.error(arg.loc, "cannot pass type `%s` as a function argument", arg.toErrMsg());
arg = ErrorExp.get();
}
err = true;
}
- else if (checkNonAssignmentArrayOp(arg))
+ }
+ else if (arg.type.toBasetype().ty == Tfunction)
+ {
+ if (eSink)
{
+ eSink.error(arg.loc, "cannot pass function `%s` as a function argument", arg.toErrMsg());
arg = ErrorExp.get();
- err = true;
}
- (*exps)[i] = arg;
+ err = true;
}
+ else if (checkNonAssignmentArrayOp(arg))
+ {
+ arg = ErrorExp.get();
+ err = true;
+ }
+ (*exps)[i] = arg;
}
+
return err;
}
@@ -2827,12 +2974,12 @@ private bool checkDefCtor(Loc loc, Type t)
* Returns:
* true errors happened
*/
-private bool functionParameters(const ref Loc loc, Scope* sc,
+private bool functionParameters(Loc loc, Scope* sc,
TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd,
Type* prettype, Expression* peprefix)
{
Expressions* arguments = argumentList.arguments;
- //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
+ //printf("functionParameters() fd: %s tf: %s\n", fd ? fd.ident.toChars() : "", toChars(tf));
assert(arguments);
assert(fd || tf.next);
const size_t nparams = tf.parameterList.length;
@@ -2843,14 +2990,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
if (argumentList.names)
{
- const(char)* msg = null;
- auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
+ OutBuffer buf;
+ auto resolvedArgs = tf.resolveNamedArgs(argumentList, &buf);
if (!resolvedArgs)
{
// while errors are usually already caught by `tf.callMatch`,
// this can happen when calling `typeof(freefunc)`
- if (msg)
- error(loc, "%s", msg);
+ if (buf.length)
+ error(loc, "%s", buf.peekChars());
return true;
}
// note: the argument list should be mutated with named arguments / default arguments,
@@ -2907,149 +3054,143 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
{
Expression arg = (i < nargs) ? (*arguments)[i] : null;
- if (i < nparams)
+ if (i >= nparams)
+ break;
+
+ bool errorArgs()
{
- bool errorArgs()
- {
- error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
- return true;
- }
+ error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
+ return true;
+ }
- Parameter p = tf.parameterList[i];
+ Parameter p = tf.parameterList[i];
- if (!arg)
+ if (!arg)
+ {
+ if (!p.defaultArg)
{
- if (!p.defaultArg)
- {
- if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
- goto L2;
- return errorArgs();
- }
- arg = p.defaultArg;
- if (!arg.type)
- arg = arg.expressionSemantic(sc);
- arg = inlineCopy(arg, sc);
- // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
- arg = arg.resolveLoc(loc, sc);
- if (i >= nargs)
- {
- arguments.push(arg);
- nargs++;
- }
- else
- (*arguments)[i] = arg;
+ if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
+ goto L2;
+ return errorArgs();
}
- else
+ arg = p.defaultArg;
+ if (!arg.type)
+ arg = arg.expressionSemantic(sc);
+ arg = inlineCopy(arg, sc);
+ // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
+ arg = arg.resolveLoc(loc, sc);
+ if (i >= nargs)
{
- if (arg.isDefaultInitExp())
- {
- arg = arg.resolveLoc(loc, sc);
- (*arguments)[i] = arg;
- }
+ arguments.push(arg);
+ nargs++;
}
+ else
+ (*arguments)[i] = arg;
+ }
+ else if (arg.isDefaultInitExp())
+ {
+ arg = arg.resolveLoc(loc, sc);
+ (*arguments)[i] = arg;
+ }
-
- if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
+ if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
+ {
+ //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
+ if (MATCH m = arg.implicitConvTo(p.type))
{
- //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
- {
- MATCH m;
- if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
- {
- if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
- goto L2;
- else if (nargs != nparams)
- return errorArgs();
- goto L1;
- }
- }
- L2:
- Type tb = p.type.toBasetype();
- switch (tb.ty)
+ if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
+ goto L2;
+ else if (nargs != nparams)
+ return errorArgs();
+ goto L1;
+ }
+ L2:
+ Type tb = p.type.toBasetype();
+ switch (tb.ty)
+ {
+ case Tsarray:
+ case Tarray:
{
- case Tsarray:
- case Tarray:
- {
- /* Create a static array variable v of type arg.type:
- * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
- *
- * The array literal in the initializer of the hidden variable
- * is now optimized.
- * https://issues.dlang.org/show_bug.cgi?id=2356
- */
- Type tbn = (cast(TypeArray)tb).next; // array element type
- Type tret = p.isLazyArray();
+ /* Create a static array variable v of type arg.type:
+ * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
+ *
+ * The array literal in the initializer of the hidden variable
+ * is now optimized.
+ * https://issues.dlang.org/show_bug.cgi?id=2356
+ */
+ Type tbn = (cast(TypeArray)tb).next; // array element type
+ Type tret = p.isLazyArray();
- auto elements = new Expressions(nargs - i);
- foreach (u; 0 .. elements.length)
- {
- Expression a = (*arguments)[i + u];
- assert(a);
- if (tret && a.implicitConvTo(tret))
- {
- // p is a lazy array of delegates, tret is return type of the delegates
- a = a.implicitCastTo(sc, tret)
- .optimize(WANTvalue)
- .toDelegate(tret, sc);
- }
- else
- a = a.implicitCastTo(sc, tbn);
- a = a.addDtorHook(sc);
- (*elements)[u] = a;
- }
- // https://issues.dlang.org/show_bug.cgi?id=14395
- // Convert to a static array literal, or its slice.
- arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
- if (tb.ty == Tarray)
+ auto elements = new Expressions(nargs - i);
+ foreach (u; 0 .. elements.length)
+ {
+ Expression a = (*arguments)[i + u];
+ assert(a);
+ if (tret && a.implicitConvTo(tret))
{
- arg = new SliceExp(loc, arg, null, null);
- arg.type = p.type;
+ // p is a lazy array of delegates, tret is return type of the delegates
+ a = a.implicitCastTo(sc, tret)
+ .optimize(WANTvalue)
+ .toDelegate(tret, sc);
}
- break;
- }
- case Tclass:
- {
- /* Set arg to be:
- * new Tclass(arg0, arg1, ..., argn)
- */
- auto args = new Expressions(nargs - i);
- foreach (u; i .. nargs)
- (*args)[u - i] = (*arguments)[u];
- arg = new NewExp(loc, null, p.type, args);
- break;
+ else
+ a = a.implicitCastTo(sc, tbn);
+ a = a.addDtorHook(sc);
+ (*elements)[u] = a;
}
- default:
- if (!arg)
+ // https://issues.dlang.org/show_bug.cgi?id=14395
+ // Convert to a static array literal, or its slice.
+ arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
+ if (tb.ty == Tarray)
{
- error(loc, "not enough arguments");
- return true;
+ arg = new SliceExp(loc, arg, null, null);
+ arg.type = p.type;
}
break;
}
- arg = arg.expressionSemantic(sc);
- //printf("\targ = '%s'\n", arg.toChars());
- arguments.setDim(i + 1);
- (*arguments)[i] = arg;
- nargs = i + 1;
- done = true;
+ case Tclass:
+ {
+ /* Set arg to be:
+ * new Tclass(arg0, arg1, ..., argn)
+ */
+ auto args = new Expressions(nargs - i);
+ foreach (u; i .. nargs)
+ (*args)[u - i] = (*arguments)[u];
+ arg = new NewExp(loc, null, null, p.type, args);
+ break;
+ }
+ default:
+ if (!arg)
+ {
+ error(loc, "not enough arguments");
+ return true;
+ }
+ break;
}
+ arg = arg.expressionSemantic(sc);
+ //printf("\targ = '%s'\n", arg.toChars());
+ arguments.setDim(i + 1);
+ (*arguments)[i] = arg;
+ nargs = i + 1;
+ done = true;
+ }
- L1:
- if (!(p.isLazy() && p.type.ty == Tvoid))
+ L1:
+ if (!(p.isLazy() && p.type.ty == Tvoid))
+ {
+ if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
{
- if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
- {
- wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
- //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
- }
+ wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
+ //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
}
}
+
if (done)
break;
}
if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
tf.next && tf.next.hasWild() &&
- (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
+ (tf.isRef || !tf.next.implicitConvTo(tf.next.immutableOf())))
{
bool errorInout(MOD wildmatch)
{
@@ -3172,13 +3313,13 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
else if (p.storageClass & STC.ref_)
{
- if (global.params.rvalueRefParam == FeatureState.enabled &&
+ if (sc.previews.rvalueRefParam &&
!arg.isLvalue() &&
targ.isCopyable())
{ /* allow rvalues to be passed to ref parameters by copying
* them to a temp, then pass the temp as the argument
*/
- auto v = copyToTemp(0, "__rvalue", arg);
+ auto v = copyToTemp(STC.none, "__rvalue", arg);
Expression ev = new DeclarationExp(arg.loc, v);
ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
arg = ev.expressionSemantic(sc);
@@ -3222,7 +3363,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
/* Argument value can be assigned to firstArg.
* Check arg to see if it matters.
*/
- err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
+ err |= checkParamArgumentReturn(*sc, firstArg, arg, p, false);
}
// Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
// as lazy parameters to the next function, but that isn't escaping.
@@ -3236,7 +3377,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
* Check arg to see if it matters.
*/
VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
- err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
+ err |= checkParamArgumentEscape(*sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
}
// Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
@@ -3260,7 +3401,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
{
// allocate the array literal as temporary static array on the stack
ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
- auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
+ auto tmp = copyToTemp(STC.none, "__arrayliteral_on_stack", ale);
tmp.storage_class |= STC.exptemp;
auto declareTmp = new DeclarationExp(ale.loc, tmp);
auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
@@ -3369,13 +3510,13 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
{
if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
{
- error(arg.loc, "function `%s` is overloaded", arg.toChars());
+ error(arg.loc, "function `%s` is overloaded", arg.toErrMsg());
err = true;
}
}
err |= arg.checkValue();
err |= arg.checkSharedAccess(sc);
- err |= checkParamArgumentEscape(sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false);
+ err |= checkParamArgumentEscape(*sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false);
arg = arg.optimize(WANTvalue);
}
(*arguments)[i] = arg;
@@ -3563,7 +3704,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
*/
Type tv = arg.type.baseElemOf();
if (!isRef && tv.ty == Tstruct)
- arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
+ arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null, false);
}
(*arguments)[i] = arg;
@@ -3573,9 +3714,9 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
/* Test compliance with DIP1021 Argument Ownership and Function Calls
*/
- if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
- tf.islive)
- err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
+ if (sc.previews.dip1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
+ tf.isLive)
+ err |= checkMutableArguments(*sc, fd, tf, ethis, arguments, false);
// If D linkage and variadic, add _arguments[] as first argument
if (tf.isDstyleVariadic())
@@ -3674,6 +3815,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Scope* sc;
Expression result;
+ // For binary expressions, stores recursive 'alias this' types of lhs and rhs to prevent endless loops.
+ // See tryAliasThisSemantic
+ Type[2] aliasThisStop;
+
+ // (Optional) the expression this was lowered from, for better error messages
+ Expression parent;
+
this(Scope* sc) scope @safe
{
this.sc = sc;
@@ -3724,37 +3872,37 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (!e.type)
e.type = Type.tfloat64;
- else if (e.type.isimaginary && sc.flags & SCOPE.Cfile)
+ else if (!e.type.isImaginary || !sc.inCfile)
{
- /* Convert to core.stdc.config.complex
- */
- Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
- if (t.ty == Terror)
- return setError();
+ e.type = e.type.typeSemantic(e.loc, sc);
+ result = e;
+ return;
+ }
- Type tf;
- switch (e.type.ty)
- {
- case Timaginary32: tf = Type.tfloat32; break;
- case Timaginary64: tf = Type.tfloat64; break;
- case Timaginary80: tf = Type.tfloat80; break;
- default:
- assert(0);
- }
+ /* Convert to core.stdc.config.complex
+ */
+ Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
+ if (t.ty == Terror)
+ return setError();
- /* Construct ts{re : 0.0, im : e}
- */
- TypeStruct ts = t.isTypeStruct;
- Expressions* elements = new Expressions(2);
- (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf);
- (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
- Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
- result = sle.expressionSemantic(sc);
- return;
+ Type tf;
+ switch (e.type.ty)
+ {
+ case Timaginary32: tf = Type.tfloat32; break;
+ case Timaginary64: tf = Type.tfloat64; break;
+ case Timaginary80: tf = Type.tfloat80; break;
+ default:
+ assert(0);
}
- else
- e.type = e.type.typeSemantic(e.loc, sc);
- result = e;
+
+ /* Construct ts{re : 0.0, im : e}
+ */
+ TypeStruct ts = t.isTypeStruct;
+ Expressions* elements = new Expressions(2);
+ (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf);
+ (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
+ Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
+ result = sle.expressionSemantic(sc);
}
override void visit(ComplexExp e)
@@ -3772,11 +3920,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
}
- if (exp.type) // This is used as the dummy expression
- {
- result = exp;
- return;
- }
+
+ scope (exit) result.rvalue = exp.rvalue;
Dsymbol scopesym;
Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
@@ -3859,10 +4004,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
- if (global.params.fixAliasThis)
+ if (sc.previews.fixAliasThis)
{
- ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
- if (expDsym)
+ if (ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol())
{
//printf("expDsym = %s\n", expDsym.exp.toChars());
result = expDsym.exp.expressionSemantic(sc);
@@ -3876,7 +4020,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
- if (!global.params.fixAliasThis && hasThis(sc))
+ if (!sc.previews.fixAliasThis && hasThis(sc))
{
for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
{
@@ -3906,7 +4050,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.ident == Id.ctfe)
{
- if (sc.flags & SCOPE.ctfe)
+ if (sc.ctfe)
{
error(exp.loc, "variable `__ctfe` cannot be read at compile time");
return setError();
@@ -3934,35 +4078,37 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!sc2.scopesym)
continue;
- if (auto ss = sc2.scopesym.isWithScopeSymbol())
+ auto ss = sc2.scopesym.isWithScopeSymbol();
+ if (!ss)
+ continue;
+
+ if (ss.withstate.wthis)
{
- if (ss.withstate.wthis)
+ Expression e;
+ e = new VarExp(exp.loc, ss.withstate.wthis);
+ e = new DotIdExp(exp.loc, e, exp.ident);
+ e = e.trySemantic(sc);
+ if (e)
{
- Expression e;
- e = new VarExp(exp.loc, ss.withstate.wthis);
- e = new DotIdExp(exp.loc, e, exp.ident);
- e = e.trySemantic(sc);
- if (e)
- {
- result = e;
- return;
- }
+ result = e;
+ return;
}
- // Try Type.opDispatch (so the static version)
- else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
+ }
+ // Try Type.opDispatch (so the static version)
+ else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
+ {
+ Type t = ss.withstate.exp.isTypeExp().type;
+ if (!t)
+ continue;
+
+ Expression e;
+ e = new TypeExp(exp.loc, t);
+ e = new DotIdExp(exp.loc, e, exp.ident);
+ e = e.trySemantic(sc);
+ if (e)
{
- if (Type t = ss.withstate.exp.isTypeExp().type)
- {
- Expression e;
- e = new TypeExp(exp.loc, t);
- e = new DotIdExp(exp.loc, e, exp.ident);
- e = e.trySemantic(sc);
- if (e)
- {
- result = e;
- return;
- }
- }
+ result = e;
+ return;
}
}
}
@@ -3994,11 +4140,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("ThisExp::semantic()\n");
}
- if (e.type)
- {
- result = e;
- return;
- }
FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
AggregateDeclaration ad;
@@ -4013,7 +4154,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (!s)
{
- error(e.loc, "`%s` is not in a class or struct scope", e.toChars());
+ error(e.loc, "`%s` is not in a class or struct scope", e.toErrMsg());
return setError();
}
ClassDeclaration cd = s.isClassDeclaration();
@@ -4059,16 +4200,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("SuperExp::semantic('%s')\n", e.toChars());
}
- if (e.type)
- {
- result = e;
- return;
- }
FuncDeclaration fd = hasThis(sc);
ClassDeclaration cd;
Dsymbol s;
+ void err()
+ {
+ error(e.loc, "`super` is only allowed in non-static class member functions");
+ result = ErrorExp.get();
+ }
/* Special case for typeof(this) and typeof(super) since both
* should work even if they are not inside a non-static member function
*/
@@ -4079,26 +4220,26 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (!s)
{
- error(e.loc, "`%s` is not in a class scope", e.toChars());
+ error(e.loc, "`%s` is not in a class scope", e.toErrMsg());
return setError();
}
cd = s.isClassDeclaration();
- if (cd)
+ if (!cd)
+ continue;
+
+ cd = cd.baseClass;
+ if (!cd)
{
- cd = cd.baseClass;
- if (!cd)
- {
- error(e.loc, "class `%s` has no `super`", s.toChars());
- return setError();
- }
- e.type = cd.type;
- result = e;
- return;
+ error(e.loc, "class `%s` has no `super`", s.toChars());
+ return setError();
}
+ e.type = cd.type;
+ result = e;
+ return;
}
}
if (!fd)
- goto Lerr;
+ return err();
e.var = fd.vthis;
assert(e.var && e.var.parent);
@@ -4110,7 +4251,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
cd = s.isClassDeclaration();
//printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
if (!cd)
- goto Lerr;
+ return err();
if (!cd.baseClass)
{
error(e.loc, "no base class for `%s`", cd.toChars());
@@ -4126,11 +4267,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
result = e;
- return;
-
- Lerr:
- error(e.loc, "`super` is only allowed in non-static class member functions");
- result = ErrorExp.get();
}
override void visit(NullExp e)
@@ -4140,11 +4276,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("NullExp::semantic('%s')\n", e.toChars());
}
// NULL is the same as (void *)0
- if (e.type)
- {
- result = e;
- return;
- }
e.type = Type.tnull;
result = e;
}
@@ -4233,11 +4364,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("StringExp::semantic() %s\n", e.toChars());
}
- if (e.type)
- {
- result = e;
- return;
- }
OutBuffer buffer;
size_t newlen = 0;
@@ -4290,7 +4416,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
buffer.write4(0);
e.setData(buffer.extractData(), newlen, 4);
- if (sc && sc.flags & SCOPE.Cfile)
+ if (sc && sc.inCfile)
e.type = Type.tuns32.sarrayOf(e.len + 1);
else
e.type = Type.tdchar.immutableOf().arrayOf();
@@ -4315,7 +4441,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
buffer.writeUTF16(0);
e.setData(buffer.extractData(), newlen, 2);
- if (sc && sc.flags & SCOPE.Cfile)
+ if (sc && sc.inCfile)
e.type = Type.tuns16.sarrayOf(e.len + 1);
else
e.type = Type.twchar.immutableOf().arrayOf();
@@ -4327,7 +4453,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
goto default;
default:
- if (sc && sc.flags & SCOPE.Cfile)
+ if (sc && sc.inCfile)
e.type = Type.tchar.sarrayOf(e.len + 1);
else
e.type = Type.tchar.immutableOf().arrayOf();
@@ -4346,11 +4472,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("+TupleExp::semantic(%s)\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
if (exp.e0)
exp.e0 = exp.e0.expressionSemantic(sc);
@@ -4363,7 +4484,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e = e.expressionSemantic(sc);
if (!e.type)
{
- error(exp.loc, "`%s` has no value", e.toChars());
+ error(exp.loc, "`%s` has no value", e.toErrMsg());
err = true;
}
else if (e.op == EXP.error)
@@ -4388,11 +4509,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
}
- if (e.type)
- {
- result = e;
- return;
- }
/* Perhaps an empty array literal [ ] should be rewritten as null?
*/
@@ -4419,7 +4535,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (e.elements.length > 0 && t0.ty == Tvoid)
{
- error(e.loc, "`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
+ error(e.loc, "`%s` of type `%s` has no value", e.toErrMsg(), e.type.toChars());
return setError();
}
@@ -4435,11 +4551,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
}
- if (e.type)
- {
- result = e;
- return;
- }
// Run semantic() on each element
bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
@@ -4466,7 +4577,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
semanticTypeInfo(sc, e.type);
- if (checkAssocArrayLiteralEscape(sc, e, false))
+ if (checkAssocArrayLiteralEscape(*sc, e, false))
return setError();
result = e;
@@ -4478,11 +4589,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("StructLiteralExp::semantic('%s')\n", e.toChars());
}
- if (e.type)
- {
- result = e;
- return;
- }
e.sd.size(e.loc);
if (e.sd.sizeok != Sizeok.done)
@@ -4526,7 +4632,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Type t = cle.type.typeSemantic(cle.loc, sc);
auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
- auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
+ auto e = initializerToExpression(init, t, sc.inCfile);
if (!e)
{
error(cle.loc, "cannot convert initializer `%s` to expression", toChars(init));
@@ -4587,11 +4693,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
ScopeDsymbol sds2 = exp.sds;
TemplateInstance ti = sds2.isTemplateInstance();
@@ -4758,14 +4859,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs);
auto arguments = new Expressions();
- if (global.params.tracegc)
- {
- auto funcname = (sc.callsc && sc.callsc.func) ?
- sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
- arguments.push(new StringExp(ne.loc, ne.loc.filename.toDString()));
- arguments.push(new IntegerExp(ne.loc, ne.loc.linnum, Type.tint32));
- arguments.push(new StringExp(ne.loc, funcname.toDString()));
- }
id = new CallExp(ne.loc, id, arguments);
ne.lowering = id.expressionSemantic(sc);
@@ -4780,10 +4873,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("\tthisexp = %s\n", exp.thisexp.toChars());
printf("\tnewtype: %s\n", exp.newtype.toChars());
}
- if (exp.type) // if semantic() already run
+
+ if (exp.placement)
{
- result = exp;
- return;
+ exp.placement = exp.placement.expressionSemantic(sc);
+ auto p = exp.placement;
+ if (p.op == EXP.error)
+ return setError();
+ if (!p.isLvalue())
+ {
+ error(p.loc, "PlacementExpression `%s` is an rvalue, but must be an lvalue", p.toChars());
+ return setError();
+ }
+ if (sc.setUnsafe(false, p.loc, "`@safe` function `%s` cannot use placement `new`", sc.func))
+ {
+ return setError();
+ }
+ if (!exp.placement.type.isNaked())
+ {
+ error(p.loc, "PlacementExpression `%s` of type `%s` be unshared and mutable", p.toChars(), toChars(p.type));
+ return setError();
+ }
}
//for error messages if the argument in [] is not convertible to size_t
@@ -4861,7 +4971,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
return setError();
}
- if (preFunctionParameters(sc, exp.argumentList))
+ if (preFunctionParameters(sc, exp.argumentList, global.errorSink))
{
return setError();
}
@@ -4872,6 +4982,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
+ uinteger_t placementSize;
+ if (exp.placement)
+ {
+ placementSize = size(exp.placement.type, exp.placement.loc);
+ auto objectSize = size(tb, exp.placement.loc);
+ //printf("placementSize: %lld objectSize: %lld\n", placementSize, objectSize);
+ if (!tb.isTypeClass && placementSize < objectSize)
+ {
+ error(exp.placement.loc, "new placement size %llu must be >= object size %llu", placementSize, objectSize);
+ return setError();
+ }
+ }
+
const size_t nargs = exp.arguments ? exp.arguments.length : 0;
Expression newprefix = null;
@@ -4880,9 +5003,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto cd = tc.sym;
if (cd.errors)
return setError();
- cd.size(exp.loc);
+ auto objectSize = cd.size(exp.loc);
if (cd.sizeok != Sizeok.done)
return setError();
+ if (exp.placement && placementSize < objectSize)
+ {
+ error(exp.placement.loc, "new placement size %llu must be >= class object size %llu", placementSize, objectSize);
+ return setError();
+ }
if (!cd.ctor)
cd.ctor = cd.searchCtor();
if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
@@ -5071,7 +5199,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// When using `@nogc` exception handling, lower `throw new E(args)` to
// `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
- if (global.params.ehnogc && exp.thrownew &&
+ if (sc.previews.dip1008 && exp.thrownew &&
!cd.isCOMclass() && !cd.isCPPclass())
{
assert(cd.ctor);
@@ -5081,25 +5209,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto tiargs = new Objects();
tiargs.push(exp.newtype);
- id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
- id = new CallExp(exp.loc, id).expressionSemantic(sc);
- Expression idVal;
- Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
- // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
+ id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
- auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
- auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
+ id = new CallExp(exp.loc, id).expressionSemantic(sc);
- id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
- id = Expression.combine(id, ctorCall).expressionSemantic(sc);
- // id = Expression.combine(id, castTmp).expressionSemantic(sc);
+ exp.lowering = id.expressionSemantic(sc);
- result = id.expressionSemantic(sc);
+ result = exp;
return;
}
else if (sc.needsCodegen() && // interpreter doesn't need this lowered
- !exp.onstack && !exp.type.isscope()) // these won't use the GC
+ !exp.placement &&
+ !exp.onstack && !exp.type.isScopeClass()) // these won't use the GC
{
/* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
* or `_d_newclassTTrace`
@@ -5116,14 +5238,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
tiargs.push(t);
id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
auto arguments = new Expressions();
- if (global.params.tracegc)
- {
- auto funcname = (sc.callsc && sc.callsc.func) ?
- sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
- arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
- arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
- arguments.push(new StringExp(exp.loc, funcname.toDString()));
- }
id = new CallExp(exp.loc, id, arguments);
exp.lowering = id.expressionSemantic(sc);
@@ -5206,16 +5320,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
foreach (arg; *exp.arguments)
{
- if (arg && checkNewEscape(sc, arg, false))
+ if (arg && checkNewEscape(*sc, arg, false))
return setError();
}
}
exp.type = exp.type.pointerTo();
- tryLowerToNewItem(exp);
+ if (!exp.placement)
+ tryLowerToNewItem(exp);
}
else if (tb.ty == Tarray)
{
+ if (exp.placement)
+ {
+ error(exp.placement.loc, "placement new cannot be used with dynamic arrays");
+ return setError();
+ }
if (!nargs)
{
// https://issues.dlang.org/show_bug.cgi?id=20422
@@ -5265,9 +5385,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!global.params.useGC && sc.needsCodegen())
{
version(IN_GCC)
- error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars());
+ error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toErrMsg());
else
- error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars());
+ error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toErrMsg());
return setError();
}
@@ -5286,7 +5406,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
goto LskipNewArrayLowering;
}
- if (nargs == 1)
+ if (exp.placement) // no need to lower
+ {
+ }
+ else if (nargs == 1)
{
auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT;
if (!verifyHookExist(exp.loc, *sc, hook, "new array"))
@@ -5308,14 +5431,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
auto arguments = new Expressions();
- if (global.params.tracegc)
- {
- auto funcname = (sc.callsc && sc.callsc.func) ?
- sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
- arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
- arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
- arguments.push(new StringExp(exp.loc, funcname.toDString()));
- }
arguments.push((*exp.arguments)[0]);
arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool));
@@ -5335,7 +5450,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
lowering = new DotIdExp(exp.loc, lowering, Id.object);
auto tbn = exp.type.nextOf();
- while (tbn.ty == Tarray)
+ size_t i = nargs;
+ while (tbn.ty == Tarray && --i)
tbn = tbn.nextOf();
auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
MODFlags.immutable_ | MODFlags.shared_);
@@ -5346,14 +5462,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
auto arguments = new Expressions();
- if (global.params.tracegc)
- {
- auto funcname = (sc.callsc && sc.callsc.func) ?
- sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
- arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
- arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
- arguments.push(new StringExp(exp.loc, funcname.toDString()));
- }
arguments.push(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments));
arguments.push(new IntegerExp(exp.loc, tbn.isShared(), Type.tbool));
@@ -5362,7 +5470,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.lowering = lowering.expressionSemantic(sc);
}
}
- else if (tb.isscalar())
+ else if (tb.isScalar())
{
if (!nargs)
{
@@ -5385,10 +5493,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
exp.type = exp.type.pointerTo();
- tryLowerToNewItem(exp);
+ if (!exp.placement)
+ tryLowerToNewItem(exp);
}
else if (tb.ty == Taarray)
{
+ if (exp.placement)
+ {
+ error(exp.placement.loc, "placement new cannot be used with associative arrays");
+ return setError();
+ }
// e.g. `new Alias(args)`
if (nargs)
{
@@ -5426,7 +5540,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression d = new DeclarationExp(e.loc, e.cd);
sc = sc.push(); // just create new scope
- sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
+ sc.ctfe = false; // temporary stop CTFE
d = d.expressionSemantic(sc);
sc = sc.pop();
@@ -5438,7 +5552,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
sds.members.push(e.cd);
}
- Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
+ Expression n = new NewExp(e.loc, e.placement, e.thisexp, e.cd.type, e.arguments);
Expression c = new CommaExp(e.loc, d, n);
result = c.expressionSemantic(sc);
@@ -5461,7 +5575,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (auto f = e.var.isFuncDeclaration())
{
- if (f.checkNestedReference(sc, e.loc))
+ if (f.checkNestedFuncReference(sc, e.loc))
return setError();
}
@@ -5515,10 +5629,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (fd)
{
- // TODO: If fd isn't yet resolved its overload, the checkNestedReference
+ // TODO: If fd isn't yet resolved its overload, the checkNestedFuncReference
// call would cause incorrect validation.
// Maybe here should be moved in CallExp, or AddrExp for functions.
- if (fd.checkNestedReference(sc, e.loc))
+ if (fd.checkNestedFuncReference(sc, e.loc))
return setError();
}
else if (auto od = e.var.isOverDeclaration())
@@ -5531,48 +5645,48 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
private void genIdent(FuncExp exp, Scope* sc)
{
- if (exp.fd.ident == Id.empty)
- {
- const(char)[] s;
- if (exp.fd.fes)
- s = "__foreachbody";
- else if (exp.fd.tok == TOK.reserved)
- s = "__lambda";
- else if (exp.fd.tok == TOK.delegate_)
- s = "__dgliteral";
- else
- s = "__funcliteral";
+ if (exp.fd.ident != Id.empty)
+ return;
+
+ string s;
+ if (exp.fd.fes)
+ s = "__foreachbody";
+ else if (exp.fd.tok == TOK.reserved)
+ s = "__lambda";
+ else if (exp.fd.tok == TOK.delegate_)
+ s = "__dgliteral";
+ else
+ s = "__funcliteral";
- DsymbolTable symtab;
- if (FuncDeclaration func = sc.parent.isFuncDeclaration())
+ DsymbolTable symtab;
+ if (FuncDeclaration func = sc.parent.isFuncDeclaration())
+ {
+ if (func.localsymtab is null)
{
- if (func.localsymtab is null)
- {
- // Inside template constraint, symtab is not set yet.
- // Initialize it lazily.
- func.localsymtab = new DsymbolTable();
- }
- symtab = func.localsymtab;
+ // Inside template constraint, symtab is not set yet.
+ // Initialize it lazily.
+ func.localsymtab = new DsymbolTable();
}
- else
+ symtab = func.localsymtab;
+ }
+ else
+ {
+ ScopeDsymbol sds = sc.parent.isScopeDsymbol();
+ if (!sds.symtab)
{
- ScopeDsymbol sds = sc.parent.isScopeDsymbol();
- if (!sds.symtab)
- {
- // Inside template constraint, symtab may not be set yet.
- // Initialize it lazily.
- assert(sds.isTemplateInstance());
- sds.symtab = new DsymbolTable();
- }
- symtab = sds.symtab;
+ // Inside template constraint, symtab may not be set yet.
+ // Initialize it lazily.
+ assert(sds.isTemplateInstance());
+ sds.symtab = new DsymbolTable();
}
- assert(symtab);
- Identifier id = Identifier.generateId(s, symtab.length() + 1);
- exp.fd.ident = id;
- if (exp.td)
- exp.td.ident = id;
- symtab.insert(exp.td ? cast(Dsymbol)exp.td : cast(Dsymbol)exp.fd);
+ symtab = sds.symtab;
}
+ assert(symtab);
+ Identifier id = Identifier.generateIdWithLoc(s, exp.loc, cast(string) toDString(sc.parent.toPrettyChars()));
+ exp.fd.ident = id;
+ if (exp.td)
+ exp.td.ident = id;
+ symtab.insert(exp.td ? cast(Dsymbol)exp.td : cast(Dsymbol)exp.fd);
}
override void visit(FuncExp exp)
@@ -5584,17 +5698,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf(" treq = %s\n", exp.fd.treq.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
Expression e = exp;
- uint olderrors;
sc = sc.push(); // just create new scope
- sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
+ sc.ctfe = false; // temporary stop CTFE
sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
/* fd.treq might be incomplete type,
@@ -5620,6 +5728,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
+ void done()
+ {
+ sc = sc.pop();
+ result = e;
+ }
+
//printf("td = %p, treq = %p\n", td, fd.treq);
if (exp.td)
{
@@ -5635,10 +5749,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
e = ErrorExp.get();
}
- goto Ldone;
+ return done();
}
- olderrors = global.errors;
+ const olderrors = global.errors;
exp.fd.dsymbolSemantic(sc);
if (olderrors == global.errors)
{
@@ -5651,7 +5765,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
(cast(TypeFunction)exp.fd.type).next = Type.terror;
e = ErrorExp.get();
- goto Ldone;
+ return done();
}
// Type is a "delegate to" or "pointer to" the function literal
@@ -5664,7 +5778,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.fd.type.isTypeError())
{
e = ErrorExp.get();
- goto Ldone;
+ return done();
}
exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
exp.type = exp.type.typeSemantic(exp.loc, sc);
@@ -5693,10 +5807,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
exp.fd.tookAddressOf++;
-
- Ldone:
- sc = sc.pop();
- result = e;
+ done();
}
/**
@@ -5709,70 +5820,69 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
{
- if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length)
+ if ((exp.type && exp.type != Type.tvoid) || !exp.td ||! arguments || !arguments.length)
+ return exp.expressionSemantic(sc);
+
+ for (size_t k = 0; k < arguments.length; k++)
{
- for (size_t k = 0; k < arguments.length; k++)
- {
- Expression checkarg = (*arguments)[k];
- if (checkarg.op == EXP.error)
- return checkarg;
- }
+ Expression checkarg = (*arguments)[k];
+ if (checkarg.op == EXP.error)
+ return checkarg;
+ }
- genIdent(exp, sc);
+ genIdent(exp, sc);
- assert(exp.td.parameters && exp.td.parameters.length);
- exp.td.dsymbolSemantic(sc);
+ assert(exp.td.parameters && exp.td.parameters.length);
+ exp.td.dsymbolSemantic(sc);
- TypeFunction tfl = cast(TypeFunction)exp.fd.type;
- size_t dim = tfl.parameterList.length;
- if (arguments.length < dim)
- {
- // Default arguments are always typed, so they don't need inference.
- Parameter p = tfl.parameterList[arguments.length];
- if (p.defaultArg)
- dim = arguments.length;
- }
+ TypeFunction tfl = cast(TypeFunction)exp.fd.type;
+ size_t dim = tfl.parameterList.length;
+ if (arguments.length < dim)
+ {
+ // Default arguments are always typed, so they don't need inference.
+ Parameter p = tfl.parameterList[arguments.length];
+ if (p.defaultArg)
+ dim = arguments.length;
+ }
- if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
- arguments.length < dim)
- {
- OutBuffer buf;
- foreach (idx, ref arg; *arguments)
- buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
- error(exp.loc, "function literal `%s%s` is not callable using argument types `(%s)`",
- exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
- buf.peekChars());
- errorSupplemental(exp.loc, "too %s arguments, expected %d, got %d",
- arguments.length < dim ? "few".ptr : "many".ptr,
- cast(int)dim, cast(int)arguments.length);
- return ErrorExp.get();
- }
+ if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
+ arguments.length < dim)
+ {
+ OutBuffer buf;
+ foreach (idx, ref arg; *arguments)
+ buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
+ error(exp.loc, "`%s` is not callable using argument types `(%s)`",
+ exp.fd.toErrMsg(), // parametersTypeToChars(tfl.parameterList),
+ buf.peekChars());
+ errorSupplemental(exp.loc, "too %s arguments, expected %d, got %d",
+ arguments.length < dim ? "few".ptr : "many".ptr,
+ cast(int)dim, cast(int)arguments.length);
+ return ErrorExp.get();
+ }
- auto tiargs = new Objects();
- tiargs.reserve(exp.td.parameters.length);
+ auto tiargs = new Objects();
+ tiargs.reserve(exp.td.parameters.length);
- for (size_t i = 0; i < exp.td.parameters.length; i++)
+ for (size_t i = 0; i < exp.td.parameters.length; i++)
+ {
+ TemplateParameter tp = (*exp.td.parameters)[i];
+ assert(dim <= tfl.parameterList.length);
+ foreach (u, p; tfl.parameterList)
{
- TemplateParameter tp = (*exp.td.parameters)[i];
- assert(dim <= tfl.parameterList.length);
- foreach (u, p; tfl.parameterList)
- {
- if (u == dim)
- break;
+ if (u == dim)
+ break;
- if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
- {
- Expression e = (*arguments)[u];
- tiargs.push(e.type);
- break;
- }
+ if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
+ {
+ Expression e = (*arguments)[u];
+ tiargs.push(e.type);
+ break;
}
}
-
- auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
- return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
}
- return exp.expressionSemantic(sc);
+
+ auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
+ return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
}
override void visit(CallExp exp)
@@ -5781,10 +5891,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("CallExp::semantic() %s\n", exp.toChars());
}
- if (exp.type)
+
+ scope (exit)
{
- result = exp;
- return; // semantic() already run
+ if (TypeFunction tf = exp.f ? cast(TypeFunction)exp.f.type : null)
+ {
+ result.rvalue = tf.isRvalue;
+ if (tf.isRvalue && !tf.isRef)
+ {
+ error(exp.f.loc, "`__rvalue` only valid on functions that return by `ref`");
+ setError();
+ }
+ }
}
Objects* tiargs = null; // initial list of template arguments
@@ -5810,7 +5928,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (FuncExp fe = exp.e1.isFuncExp())
{
if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
- preFunctionParameters(sc, exp.argumentList))
+ preFunctionParameters(sc, exp.argumentList, global.errorSink))
return setError();
// Run e1 semantic even if arguments have any errors
@@ -5821,7 +5939,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
}
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* See if need to rewrite the AST because of cast/call ambiguity
*/
@@ -5952,7 +6070,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
__gshared int nest;
if (++nest > global.recursionLimit)
{
- error(exp.loc, "recursive evaluation of `%s`", exp.toChars());
+ error(exp.loc, "recursive evaluation of `%s`", exp.toErrMsg());
--nest;
return setError();
}
@@ -6004,7 +6122,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Rewrite (*fp)(arguments) to fp(arguments)
exp.e1 = (cast(PtrExp)exp.e1).e1;
}
- else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
+ else if (exp.e1.op == EXP.type && (sc && sc.inCfile))
{
const numArgs = exp.arguments ? exp.arguments.length : 0;
@@ -6050,7 +6168,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
- preFunctionParameters(sc, exp.argumentList))
+ preFunctionParameters(sc, exp.argumentList, global.errorSink))
return setError();
// Check for call operator overload
@@ -6075,7 +6193,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (sd.ctor)
{
auto ctor = sd.ctor.isCtorDeclaration();
- if (ctor && ctor.isCpCtor && ctor.isGenerated())
+ if (ctor && (ctor.isCpCtor || ctor.isMoveCtor) && ctor.isGenerated())
sd.ctor = null;
}
@@ -6131,7 +6249,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
// No constructor, look for overload of opCall
- if (search_function(sd, Id.call))
+ if (search_function(sd, Id.opCall))
goto L1;
// overload of opCall, therefore it's a call
if (exp.e1.op != EXP.type)
@@ -6172,13 +6290,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
L1:
// Rewrite as e1.call(arguments)
- Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
+ Expression e = new DotIdExp(exp.loc, exp.e1, Id.opCall);
e = new CallExp(exp.loc, e, exp.arguments, exp.names);
e = e.expressionSemantic(sc);
result = e;
return;
}
- else if (exp.e1.op == EXP.type && t1.isscalar())
+ else if (exp.e1.op == EXP.type && t1.isScalar())
{
Expression e;
@@ -6219,46 +6337,45 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (tiargs && s.isFuncDeclaration())
continue;
- if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
+ auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet);
+ if (!f2)
+ continue;
+ if (f2.errors)
+ return null;
+ if (!f)
{
- if (f2.errors)
- return null;
- if (f)
- {
- /* Match in more than one overload set,
- * even if one is a 'better' match than the other.
- */
- if (f.isCsymbol() && f2.isCsymbol())
- {
- /* C has global name space, so just pick one, such as f.
- * If f and f2 are not compatible, that's how C rolls.
- */
- }
- else
- ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
- }
- else
- f = f2;
+ f = f2;
+ continue;
}
- }
- if (!f)
- {
- .error(loc, "no overload matches for `%s`", exp.toChars());
- errorSupplemental(loc, "Candidates are:");
- foreach (s; os.a)
+ /* Match in more than one overload set,
+ * even if one is a 'better' match than the other.
+ */
+ if (f.isCsymbol() && f2.isCsymbol())
{
- overloadApply(s, (ds){
- if (auto fd = ds.isFuncDeclaration())
- .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
- fd.type.toTypeFunction().parameterList.parametersTypeToChars());
- else
- .errorSupplemental(ds.loc, "%s", ds.toChars());
- return 0;
- });
+ /* C has global name space, so just pick one, such as f.
+ * If f and f2 are not compatible, that's how C rolls.
+ */
}
+ else
+ ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
+ }
+ if (f && f.errors)
+ return null;
+ if (f)
+ return f;
+ .error(loc, "no overload matches for `%s`", exp.toErrMsg());
+ errorSupplemental(loc, "Candidates are:");
+ foreach (s; os.a)
+ {
+ overloadApply(s, (ds){
+ if (auto fd = ds.isFuncDeclaration())
+ .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
+ fd.type.toTypeFunction().parameterList.parametersTypeToChars());
+ else
+ .errorSupplemental(ds.loc, "%s", ds.toChars());
+ return 0;
+ });
}
- else if (f.errors)
- f = null;
return f;
}
@@ -6316,7 +6433,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
tthis = ue.e1.type;
if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
{
- if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
+ if (checkParamArgumentEscape(*sc, exp.f, Id.This, exp.f.vthis, STC.none, ethis, false, false))
return setError();
}
}
@@ -6506,7 +6623,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else if (!t1)
{
- error(exp.loc, "function expected before `()`, not `%s`", exp.e1.toChars());
+ error(exp.loc, "function expected before `()`, not `%s`", exp.e1.toErrMsg());
return setError();
}
else if (t1.ty == Terror)
@@ -6589,7 +6706,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else
{
- error(exp.loc, "function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
+ error(exp.loc, "function expected before `()`, not `%s` of type `%s`", exp.e1.toErrMsg(), exp.e1.type.toChars());
return setError();
}
@@ -6603,13 +6720,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
tthis.modToBuffer(buf);
//printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
- .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
- p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
+ .error(exp.loc, "%s `%s` is not callable using argument types `%s`",
+ p, exp.e1.toErrMsg(), buf.peekChars());
if (failMessage)
errorSupplemental(exp.loc, "%s", failMessage);
}
- if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
+ if (callMatch(exp.f, tf, null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
return setError();
// Purity and safety check should run after testing arguments matching
@@ -6618,29 +6735,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.f.checkPurity(exp.loc, sc);
exp.f.checkSafety(exp.loc, sc);
exp.f.checkNogc(exp.loc, sc);
- if (exp.f.checkNestedReference(sc, exp.loc))
+ if (exp.f.checkNestedFuncReference(sc, exp.loc))
return setError();
}
- else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
+ else if (sc.func && sc.intypeof != 1 && !(sc.ctfe || sc.debug_))
{
bool err = false;
- if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1))
+ if (!tf.purity && sc.func.setImpure(exp.loc, "calling impure `%s`", exp.e1))
{
error(exp.loc, "`pure` %s `%s` cannot call impure %s `%s`",
- sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
+ sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toErrMsg());
err = true;
}
- if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1))
+ if (!tf.isNogc && sc.func.setGC(exp.loc, "calling non-@nogc `%s`", exp.e1))
{
error(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
- sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
+ sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toErrMsg());
err = true;
}
if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
- "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
+ "calling `@system` `%s`", exp.e1))
{
error(exp.loc, "`@safe` %s `%s` cannot call `@system` %s `%s`",
- sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
+ sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toErrMsg());
err = true;
}
if (err)
@@ -6685,14 +6802,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
.error(exp.loc, "%s `%s` is not callable using argument types `%s`",
- exp.f.kind(), exp.f.toChars(), buf.peekChars());
+ exp.f.kind(), exp.f.toErrMsg(), buf.peekChars());
if (failMessage)
errorSupplemental(exp.loc, "%s", failMessage);
.errorSupplemental(exp.f.loc, "`%s%s` declared here", exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList));
exp.f = null;
}
- if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
+ if (callMatch(exp.f, tf, null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
exp.f = null;
}
if (!exp.f || exp.f.errors)
@@ -6701,7 +6818,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.f.needThis())
{
// Change the ancestor lambdas to delegate before hasThis(sc) call.
- if (exp.f.checkNestedReference(sc, exp.loc))
+ if (exp.f.checkNestedFuncReference(sc, exp.loc))
return setError();
auto memberFunc = hasThis(sc);
@@ -6736,7 +6853,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
checkFunctionAttributes(exp, sc, exp.f);
checkAccess(exp.loc, sc, null, exp.f);
- if (exp.f.checkNestedReference(sc, exp.loc))
+ if (exp.f.checkNestedFuncReference(sc, exp.loc))
return setError();
ethis = null;
@@ -6761,7 +6878,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
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.toChars());
+ error(exp.loc, "forward reference to inferred return type of function call `%s`", exp.toErrMsg());
return setError();
}
@@ -6798,10 +6915,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Loc loc = exp.loc;
auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
- auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
+ auto vptrTmpDecl = copyToTemp(STC.none, "__vptrTmp", vptr);
auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
- auto superTmpDecl = copyToTemp(0, "__superTmp", result);
+ auto superTmpDecl = copyToTemp(STC.none, "__superTmp", result);
auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
@@ -6845,17 +6962,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(DeclarationExp e)
{
- if (e.type)
- {
- result = e;
- return;
- }
static if (LOGSEMANTIC)
{
printf("DeclarationExp::semantic() %s\n", e.toChars());
}
- uint olderrors = global.errors;
+ const olderrors = global.errors;
/* This is here to support extern(linkage) declaration,
* where the extern(linkage) winds up being an AttribDeclaration
@@ -6866,15 +6978,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
while (1)
{
AttribDeclaration ad = s.isAttribDeclaration();
- if (ad)
- {
- if (ad.decl && ad.decl.length == 1)
- {
- s = (*ad.decl)[0];
- continue;
- }
- }
- break;
+ if (ad && ad.decl && ad.decl.length == 1)
+ s = (*ad.decl)[0];
+ else
+ break;
}
//printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
@@ -6885,7 +6992,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
VarDeclaration v = s.isVarDeclaration();
if (v)
{
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* Do semantic() on the type before inserting v into the symbol table
*/
@@ -6919,7 +7026,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
- if (v && (sc.flags & SCOPE.Cfile))
+ if (v && sc.inCfile)
{
/* Do semantic() on initializer last so this will be legal:
* int a = a;
@@ -6957,7 +7064,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// The mangling change only works for D mangling
}
- if (!(sc.flags & SCOPE.Cfile))
+ if (!sc.inCfile)
{
/* https://issues.dlang.org/show_bug.cgi?id=21272
* If we are in a foreach body we need to extract the
@@ -6970,27 +7077,26 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Disallow shadowing
for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
{
- Dsymbol s2;
- if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
+ if (!scx.scopesym || !scx.scopesym.symtab)
+ continue;
+ Dsymbol s2 = scx.scopesym.symtab.lookup(s.ident);
+ if (s2 is null || s == s2)
+ continue;
+ // allow STC.local symbols to be shadowed
+ // TODO: not really an optimal design
+ auto decl = s2.isDeclaration();
+ if (decl && (decl.storage_class & STC.local))
+ continue;
+ if (sc.func.fes)
{
- // allow STC.local symbols to be shadowed
- // TODO: not really an optimal design
- auto decl = s2.isDeclaration();
- if (!decl || !(decl.storage_class & STC.local))
- {
- if (sc.func.fes)
- {
- deprecation(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
- deprecationSupplemental(s2.loc, "declared here");
-
- }
- else
- {
- error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
- errorSupplemental(s2.loc, "declared here");
- return setError();
- }
- }
+ deprecation(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
+ deprecationSupplemental(s2.loc, "declared here");
+ }
+ else
+ {
+ error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
+ errorSupplemental(s2.loc, "declared here");
+ return setError();
}
}
}
@@ -7052,62 +7158,51 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!ta)
{
//printf("ta %p ea %p sa %p\n", ta, ea, sa);
- error(exp.loc, "no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
+ error(exp.loc, "no type for `typeid(%s)`", ea ? ea.toErrMsg() : (sa ? sa.toChars() : ""));
return setError();
}
ta.checkComplexTransition(exp.loc, sc);
- Expression e;
auto tb = ta.toBasetype();
if (ea && tb.ty == Tclass)
{
if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
{
error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
- e = ErrorExp.get();
+ return setError();
}
else if (!Type.typeinfoclass)
{
error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
- e = ErrorExp.get();
+ return setError();
}
else
{
/* Get the dynamic type, which is .classinfo
*/
ea = ea.expressionSemantic(sc);
- e = new TypeidExp(ea.loc, ea);
+ Expression e = new TypeidExp(ea.loc, ea);
e.type = Type.typeinfoclass.type;
+ result = e;
+ return;
}
}
else if (ta.ty == Terror)
{
- e = ErrorExp.get();
+ return setError();
}
- else
- {
- // Handle this in the glue layer
- e = new TypeidExp(exp.loc, ta);
- bool genObjCode = true;
-
- // https://issues.dlang.org/show_bug.cgi?id=23650
- // We generate object code for typeinfo, required
- // by typeid, only if in non-speculative context
- if (sc.flags & SCOPE.compile)
- {
- genObjCode = false;
- }
+ // Handle this in the glue layer
+ Expression e = new TypeidExp(exp.loc, ta);
- e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
- semanticTypeInfo(sc, ta);
+ e.type = getTypeInfoType(exp.loc, ta, sc);
+ semanticTypeInfo(sc, ta);
- if (ea)
- {
- e = new CommaExp(exp.loc, ea, e); // execute ea
- e = e.expressionSemantic(sc);
- }
+ if (ea)
+ {
+ e = new CommaExp(exp.loc, ea, e); // execute ea
+ e = e.expressionSemantic(sc);
}
result = e;
}
@@ -7178,7 +7273,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("IsExp::semantic(%s)\n", e.toChars());
}
- if (e.id && !(sc.flags & SCOPE.condition))
+ if (e.id && !sc.condition)
{
error(e.loc, "can only declare type aliases within `static if` conditionals or `static assert`s");
return setError();
@@ -7197,7 +7292,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return no();
if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
return no();
- else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
+ if (e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
return no();
tded = e.targ;
return yes();
@@ -7207,7 +7302,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Scope* sc2 = sc.copy(); // keep sc.flags
sc2.tinst = null;
sc2.minst = null;
- sc2.flags |= SCOPE.fullinst;
+ sc2.fullinst = true;
Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2);
sc2.pop();
if (!t) // errors, so condition is false
@@ -7387,39 +7482,37 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
//printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
//printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
- if (e.tok == TOK.colon)
+ if (e.tok != TOK.colon) /* == */
{
- // current scope is itself deprecated, or deprecations are not errors
- const bool deprecationAllowed = sc.isDeprecated
- || global.params.useDeprecated != DiagnosticReporting.error;
- const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
+ if (e.targ.equals(e.tspec))
+ return yes();
+ else
+ return no();
+ }
- if (preventAliasThis && e.targ.ty == Tstruct)
- {
- if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
- return yes();
- else
- return no();
- }
- else if (preventAliasThis && e.targ.ty == Tclass)
- {
- if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
- return yes();
- else
- return no();
- }
- else if (e.targ.implicitConvTo(e.tspec))
+ // current scope is itself deprecated, or deprecations are not errors
+ const bool deprecationAllowed = sc.isDeprecated
+ || global.params.useDeprecated != DiagnosticReporting.error;
+ const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
+
+ if (preventAliasThis && e.targ.ty == Tstruct)
+ {
+ if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
return yes();
else
return no();
}
- else /* == */
+ else if (preventAliasThis && e.targ.ty == Tclass)
{
- if (e.targ.equals(e.tspec))
+ if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
return yes();
else
return no();
}
+ else if (e.targ.implicitConvTo(e.tspec))
+ return yes();
+ else
+ return no();
}
else if (e.tspec)
{
@@ -7441,41 +7534,37 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
MATCH m = deduceType(e.targ, sc, e.tspec, *e.parameters, dedtypes, null, 0, e.tok == TOK.equal);
if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
- {
return no();
- }
- else
- {
- tded = cast(Type)dedtypes[0];
- if (!tded)
- tded = e.targ;
- Objects tiargs = Objects(1);
- tiargs[0] = e.targ;
- /* Declare trailing parameters
- */
- for (size_t i = 1; i < e.parameters.length; i++)
- {
- TemplateParameter tp = (*e.parameters)[i];
- Declaration s = null;
+ tded = cast(Type)dedtypes[0];
+ if (!tded)
+ tded = e.targ;
+ Objects tiargs = Objects(1);
+ tiargs[0] = e.targ;
- m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s);
- if (m == MATCH.nomatch)
- return no();
- s.dsymbolSemantic(sc);
- if (!sc.insert(s))
- {
- Dsymbol pscopesym;
- auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
- error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
- errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
- conflict.kind(), conflict.toChars());
- }
+ /* Declare trailing parameters
+ */
+ for (size_t i = 1; i < e.parameters.length; i++)
+ {
+ TemplateParameter tp = (*e.parameters)[i];
+ Declaration s = null;
- unSpeculative(sc, s);
+ m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s);
+ if (m == MATCH.nomatch)
+ return no();
+ s.dsymbolSemantic(sc);
+ if (!sc.insert(s))
+ {
+ Dsymbol pscopesym;
+ auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
+ error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
+ errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
+ conflict.kind(), conflict.toChars());
}
- return yes();
+
+ unSpeculative(sc, s);
}
+ return yes();
}
else if (e.id)
{
@@ -7489,19 +7578,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(BinAssignExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinaryAssign(sc, aliasThisStop))
{
result = e;
return;
}
+ Expression e;
if (exp.e1.op == EXP.arrayLength)
{
// arr.length op= e2;
@@ -7510,7 +7594,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
return;
}
- if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
+ if (exp.e1.op == EXP.slice || exp.e1.type.isStaticOrDynamicArray())
{
if (checkNonAssignmentArrayOp(exp.e1))
return setError();
@@ -7539,15 +7623,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
exp.type = exp.e1.type;
- if (auto ad = isAggregate(exp.e1.type))
- {
- if (const s = search_function(ad, Id.opOpAssign))
- {
- error(exp.loc, "none of the `opOpAssign` overloads of `%s` are callable for `%s` of type `%s`", ad.toChars(), exp.e1.toChars(), exp.e1.type.toChars());
- return setError();
- }
- }
- if (exp.e1.checkScalar() ||
+ if (exp.suggestOpOpAssign(sc, parent) ||
+ exp.e1.checkScalar() ||
exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
exp.e1.checkSharedAccess(sc))
return setError();
@@ -7561,7 +7638,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else if (exp.checkNoBool())
return setError();
- if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
+ if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isIntegral())
{
result = scaleFactor(exp, sc);
return;
@@ -7604,19 +7681,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = (cast(BinExp)e).reorderSettingAAElem(sc);
}
- private Expression compileIt(MixinExp exp, Scope *sc)
+ private Expression compileIt(MixinExp exp, Scope* sc)
{
OutBuffer buf;
- if (expressionsToString(buf, sc, exp.exps))
+ if (expressionsToString(buf, sc, exp.exps, exp.loc, null, true))
return null;
- uint errors = global.errors;
+ const errors = global.errors;
const len = buf.length;
const str = buf.extractChars()[0 .. len];
const bool doUnittests = global.params.parsingUnittestsRequired();
- auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut);
- scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
- p.transitionIn = global.params.v.vin;
+ scope p = new Parser!ASTCodegen(sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
+ adjustLocForMixin(str, exp.loc, *p.baseLoc, global.params.mixinOut);
+ p.linnum = p.baseLoc.startLine;
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
@@ -7722,35 +7799,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
const slice = se.peekString();
message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
}
- if (global.params.moduleDeps.buffer !is null)
- {
- OutBuffer* ob = global.params.moduleDeps.buffer;
- Module imod = sc._module;
- if (!global.params.moduleDeps.name)
- ob.writestring("depsFile ");
- ob.writestring(imod.toPrettyChars());
- ob.writestring(" (");
- escapePath(ob, imod.srcfile.toChars());
- ob.writestring(") : ");
- if (global.params.moduleDeps.name)
- ob.writestring("string : ");
- ob.write(se.peekString());
- ob.writestring(" (");
- escapePath(ob, resolvedNamez.ptr);
- ob.writestring(")");
- ob.writenl();
- }
- if (global.params.makeDeps.doOutput)
- {
- global.params.makeDeps.files.push(resolvedNamez.ptr);
- }
+ addImportExpDep(global.params.moduleDeps, global.params.makeDeps, resolvedNamez, se.peekString(), sc._module);
{
auto fileName = FileName(resolvedNamez);
if (auto fmResult = global.fileManager.getFileContents(fileName))
{
se = new StringExp(e.loc, fmResult);
+ se.hexString = true;
}
else
{
@@ -7773,7 +7830,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// deprecated in 2.107
deprecation(e.loc, "assert condition cannot be a string literal");
deprecationSupplemental(e.loc, "If intentional, use `%s !is null` instead to preserve behaviour",
- e.toChars());
+ e.toErrMsg());
}
const generateMsg = !exp.msg &&
@@ -7878,7 +7935,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return res.expressionSemantic(sc);
}
- const stc = op.isLvalue() ? STC.ref_ : 0;
+ const stc = op.isLvalue() ? STC.ref_ : STC.none;
auto tmp = copyToTemp(stc, "__assertOp", op);
tmp.dsymbolSemantic(sc);
@@ -7913,7 +7970,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
const callExpIdent = callExpFunc.ident;
isEqualsCallExpression = callExpIdent == Id.__equals ||
- callExpIdent == Id.eq;
+ callExpIdent == Id.opEquals;
}
}
if (op == EXP.equal || op == EXP.notEqual ||
@@ -8046,7 +8103,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.msg = resolveProperties(sc, exp.msg);
exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
exp.msg = exp.msg.optimize(WANTvalue);
- checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
+ checkParamArgumentEscape(*sc, null, null, null, STC.none, exp.msg, true, false);
}
if (exp.msg && exp.msg.op == EXP.error)
@@ -8065,8 +8122,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
/* This is an `assert(0)` which means halt program execution
*/
FuncDeclaration fd = sc.parent.isFuncDeclaration();
- if (fd)
- fd.hasReturnExp |= 4;
sc.ctorflow.orCSX(CSX.halt);
if (global.params.useAssert == CHECKENABLE.off)
@@ -8094,6 +8149,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
import dmd.statementsem;
+ te.type = Type.tnoreturn;
if (throwSemantic(te.loc, te.e1, sc))
result = te;
else
@@ -8105,10 +8161,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
static if (LOGSEMANTIC)
{
printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
- //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
+ printAST(exp);
}
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* See if need to rewrite the AST because of cast/call ambiguity
*/
@@ -8163,7 +8219,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (e && isDotOpDispatch(e))
{
auto ode = e;
- uint errors = global.startGagging();
+ const errors = global.startGagging();
e = resolvePropertiesX(sc, e);
// Any error or if 'e' is not resolved, go to UFCS
if (global.endGagging(errors) || e is ode)
@@ -8188,11 +8244,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(DotTemplateExp e)
{
- if (e.type)
- {
- result = e;
- return;
- }
if (Expression ex = unaSemantic(e, sc))
{
result = ex;
@@ -8209,11 +8260,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("DotVarExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
exp.var = exp.var.toAlias().isDeclaration();
@@ -8381,11 +8427,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
// Indicate we need to resolve by UFCS.
Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
if (!e)
@@ -8401,11 +8442,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("DelegateExp::semantic('%s')\n", e.toChars());
}
- if (e.type)
- {
- result = e;
- return;
- }
e.e1 = e.e1.expressionSemantic(sc);
@@ -8426,7 +8462,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
error(e.loc, "%smethod `%s` is not callable using a %s`%s`",
- funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
+ funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toErrMsg());
return setError();
}
}
@@ -8467,11 +8503,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("DotTypeExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
if (auto e = unaSemantic(exp, sc))
{
@@ -8489,11 +8520,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("AddrExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
if (Expression ex = unaSemantic(exp, sc))
{
@@ -8501,7 +8527,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* Special handling for &"string"/&(T[]){0, 1}
* since C regards string/array literals as lvalues
@@ -8593,8 +8619,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (1)
{
- if (sc.setUnsafe(false, exp.loc,
- "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
+ if (sc.setUnsafe(false, exp.loc, "taking address of lazy parameter `%s`", ve))
{
setError();
return;
@@ -8621,7 +8646,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!exp.e1.type)
{
- error(exp.loc, "cannot take address of `%s`", exp.e1.toChars());
+ error(exp.loc, "cannot take address of `%s`", exp.e1.toErrMsg());
return setError();
}
if (!checkAddressable(exp, sc))
@@ -8645,7 +8670,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
error(exp.loc, "forward reference to %s `%s`", d.kind(), d.toChars());
}
else
- error(exp.loc, "forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
+ error(exp.loc, "forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toErrMsg());
return setError();
}
}
@@ -8741,11 +8766,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
return;
}
- if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
+ if (sc.func && !sc.intypeof && !sc.debug_)
{
- sc.setUnsafe(false, exp.loc,
- "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
- f, sc.func);
+ sc.setUnsafe(false, exp.loc, "taking address of member `%s` without `this` reference", f);
}
}
}
@@ -8757,7 +8780,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* &a[i]
* check 'a' the same as for a regular variable
*/
- if (VarDeclaration v = expToVariable(exp.e1))
+ int deref;
+ if (VarDeclaration v = expToVariable(exp.e1, deref))
{
v.checkPurity(exp.e1.loc, sc);
}
@@ -8789,14 +8813,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("PtrExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadUnary(sc))
{
result = e;
return;
@@ -8815,7 +8833,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
case Tarray:
if (isNonAssignmentArrayOp(exp.e1))
goto default;
- error(exp.loc, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
+ error(exp.loc, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toErrMsg());
exp.type = (cast(TypeArray)tb).next;
exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
break;
@@ -8832,7 +8850,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
goto case Terror;
}
- if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid)
+ if (sc.inCfile && exp.type && exp.type.toBasetype().ty == Tvoid)
{
// https://issues.dlang.org/show_bug.cgi?id=23752
// `&*((void*)(0))` is allowed in C
@@ -8852,14 +8870,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("NegExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadUnary(sc))
{
result = e;
return;
@@ -8868,7 +8880,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
fix16997(sc, exp);
exp.type = exp.e1.type;
Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
if (!isArrayOpValid(exp.e1))
{
@@ -8883,9 +8895,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = exp.incompatibleTypes();
return;
}
- if (exp.e1.checkNoBool())
- return setError();
- if (exp.e1.checkArithmetic(exp.op) ||
+ if (exp.e1.checkNoBool() ||
+ exp.e1.checkArithmetic(exp.op) ||
exp.e1.checkSharedAccess(sc))
return setError();
@@ -8898,10 +8909,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("UAddExp::semantic('%s')\n", exp.toChars());
}
- assert(!exp.type);
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadUnary(sc))
{
result = e;
return;
@@ -8913,11 +8922,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = exp.incompatibleTypes();
return;
}
- if (exp.e1.checkNoBool())
- return setError();
- if (exp.e1.checkArithmetic(exp.op))
- return setError();
- if (exp.e1.checkSharedAccess(sc))
+
+ if (exp.e1.checkNoBool() ||
+ exp.e1.checkArithmetic(exp.op) ||
+ exp.e1.checkSharedAccess(sc))
return setError();
result = exp.e1;
@@ -8925,14 +8933,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(ComExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadUnary(sc))
{
result = e;
return;
@@ -8941,7 +8943,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
fix16997(sc, exp);
exp.type = exp.e1.type;
Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
if (!isArrayOpValid(exp.e1))
{
@@ -8956,9 +8958,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = exp.incompatibleTypes();
return;
}
- if (exp.e1.checkNoBool())
- return setError();
- if (exp.e1.checkIntegral() ||
+ if (exp.e1.checkNoBool() ||
+ exp.e1.checkIntegral() ||
exp.e1.checkSharedAccess(sc))
return setError();
@@ -8967,11 +8968,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(NotExp e)
{
- if (e.type)
- {
- result = e;
- return;
- }
e.setNoderefOperand();
@@ -9003,23 +8999,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (checkNonAssignmentArrayOp(e.e1))
return setError();
- e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
+ e.type = (sc && sc.inCfile) ? Type.tint32 : Type.tbool;
result = e;
}
override void visit(DeleteExp exp)
{
- // @@@DEPRECATED_2.109@@@
- // 1. Deprecated since 2.079
- // 2. Error since 2.099
- // 3. Removal of keyword, "delete" can be used for other identities
- if (!exp.isRAII)
- {
- error(exp.loc, "the `delete` keyword is obsolete");
- errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
- return setError();
- }
-
Expression e = exp;
if (Expression ex = unaSemantic(exp, sc))
@@ -9076,13 +9061,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("CastExp::semantic('%s')\n", exp.toChars());
}
//static int x; assert(++x < 10);
- if (exp.type)
- {
- result = exp;
- return;
- }
- if ((sc && sc.flags & SCOPE.Cfile) &&
+ if ((sc && sc.inCfile) &&
exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
(exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
@@ -9136,6 +9116,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
+ // https://issues.dlang.org/show_bug.cgi?id=24701
+ auto r = checkNoreturnVarAccess(exp.e1);
+ if (r != exp.e1 && exp.to && !exp.to.isTypeNoreturn())
+ {
+ result = r;
+ return;
+ }
+
if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
exp.e1 = exp.e1.arrayFuncConv(sc);
@@ -9155,7 +9143,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!exp.e1.type)
{
- error(exp.loc, "cannot cast `%s`", exp.e1.toChars());
+ error(exp.loc, "cannot cast `%s`", exp.e1.toErrMsg());
return setError();
}
@@ -9193,7 +9181,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.to.ty == Ttuple)
{
- error(exp.loc, "cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
+ error(exp.loc, "cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toErrMsg(), exp.e1.type.toChars(), exp.to.toChars());
return setError();
}
@@ -9207,7 +9195,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
{
- if (Expression e = exp.op_overload(sc))
+ if (Expression e = exp.opOverloadCast(sc))
{
result = e.implicitCastTo(sc, exp.to);
return;
@@ -9236,7 +9224,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
- if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
+ if (!t1b.equals(tob) && t1b.isStaticOrDynamicArray())
{
if (checkNonAssignmentArrayOp(exp.e1))
return setError();
@@ -9250,13 +9238,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
// Check for unsafe casts
- if (!isSafeCast(ex, t1b, tob))
+ string msg;
+ if (!isSafeCast(ex, t1b, tob, msg))
{
- if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
+ if (sc.setUnsafe(false, exp.loc,
+ "cast from `%s` to `%s`", exp.e1.type, exp.to))
{
+ if (msg.length)
+ errorSupplemental(exp.loc, "%.*s", msg.fTuple.expand);
return setError();
}
}
+ else if (msg.length) // deprecated unsafe
+ {
+ const err = sc.setUnsafePreview(FeatureState.default_, false, exp.loc,
+ "cast from `%s` to `%s`", exp.e1.type, exp.to);
+ // if message was printed
+ if (sc.func && sc.func.isSafeBypassingInference() && !sc.isDeprecated())
+ deprecationSupplemental(exp.loc, "%.*s", msg.fTuple.expand);
+ if (err)
+ return setError();
+ }
// `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
// to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
@@ -9322,7 +9324,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
- if (sc && sc.flags & SCOPE.Cfile)
+ if (sc && sc.inCfile)
{
/* C11 6.5.4-5: A cast does not yield an lvalue.
* So ensure that castTo does not strip away the cast so that this
@@ -9343,11 +9345,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("VectorExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
exp.e1 = exp.e1.expressionSemantic(sc);
exp.type = exp.to.typeSemantic(exp.loc, sc);
@@ -9368,7 +9365,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (elem.isConst() == 1)
return false;
- error(exp.loc, "constant expression expected, not `%s`", elem.toChars());
+ error(exp.loc, "constant expression expected, not `%s`", elem.toErrMsg());
return true;
}
@@ -9416,11 +9413,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("SliceExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
// operator overloading should be handled in ArrayExp already.
if (Expression ex = unaSemantic(exp, sc))
@@ -9433,7 +9425,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (exp.lwr || exp.upr)
{
- error(exp.loc, "cannot slice type `%s`", exp.e1.toChars());
+ error(exp.loc, "cannot slice type `%s`", exp.e1.toErrMsg());
return setError();
}
Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
@@ -9485,7 +9477,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (t1b.isPtrToFunction())
{
- error(exp.loc, "cannot slice function pointer `%s`", exp.e1.toChars());
+ error(exp.loc, "cannot slice function pointer `%s`", exp.e1.toErrMsg());
return setError();
}
if (!exp.lwr || !exp.upr)
@@ -9493,8 +9485,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
error(exp.loc, "upper and lower bounds are needed to slice a pointer");
if (auto ad = isAggregate(tp.next.toBasetype()))
{
- auto s = search_function(ad, Id.index);
- if (!s) s = search_function(ad, Id.slice);
+ auto s = search_function(ad, Id.opIndex);
+ if (!s) s = search_function(ad, Id.opSlice);
if (s)
{
auto fd = s.isFuncDeclaration();
@@ -9502,9 +9494,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
errorSupplemental(exp.loc,
"pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
- exp.e1.toChars(),
+ exp.e1.toErrMsg(),
s.ident.toChars(),
- exp.e1.toChars()
+ exp.e1.toErrMsg()
);
}
@@ -9513,7 +9505,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
- if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
+ if (sc.setUnsafe(false, exp.loc, "pointer slicing"))
return setError();
}
else if (t1b.ty == Tarray)
@@ -9545,14 +9537,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else
{
- error(exp.loc, "`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
+ error(exp.loc, "`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toErrMsg() : t1b.toChars());
return setError();
}
/* Run semantic on lwr and upr.
*/
Scope* scx = sc;
- if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
+ if (t1b.isStaticOrDynamicArray() || t1b.ty == Ttuple)
{
// Create scope for 'length' variable
ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
@@ -9659,7 +9651,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
IntRange lwrRange = getIntRange(exp.lwr);
IntRange uprRange = getIntRange(exp.upr);
- if (t1b.ty == Tsarray || t1b.ty == Tarray)
+ if (t1b.isStaticOrDynamicArray())
{
Expression el = new ArrayLengthExp(exp.loc, exp.e1);
el = el.expressionSemantic(sc);
@@ -9703,11 +9695,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
}
- if (e.type)
- {
- result = e;
- return;
- }
if (Expression ex = unaSemantic(e, sc))
{
@@ -9726,9 +9713,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("ArrayExp::semantic('%s')\n", exp.toChars());
}
- assert(!exp.type);
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* See if need to rewrite the AST because of cast/call ambiguity
*/
@@ -9743,15 +9729,48 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (result)
return;
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadArray(sc))
{
result = e;
return;
}
- if (isAggregate(exp.e1.type))
- error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
+ if (auto ad = isAggregate(exp.e1.type))
+ {
+ if (exp.arguments.length == 0)
+ {
+ error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
+ errorSupplemental(ad.loc, "perhaps define `auto opIndex() {}` for `%s`", ad.toPrettyChars());
+ }
+ else
+ {
+ const(char)* typeString(Expression exp)
+ {
+ if (auto e = exp.trySemantic(sc))
+ return e.type.toChars();
+ else
+ return "__error__";
+ }
+
+ if (auto ie = (*exp.arguments)[0].isIntervalExp())
+ {
+ error(exp.loc, "no `[%s]` operator overload for type `%s`", ie.toChars(), exp.e1.type.toChars());
+ errorSupplemental(ad.loc, "perhaps define `auto opSlice(%s lower, %s upper) {}` for `%s`",
+ typeString(ie.lwr), typeString(ie.upr), ad.toPrettyChars());
+ }
+ else
+ {
+ OutBuffer buf;
+ buf.printf("%s", typeString((*exp.arguments)[0]));
+ foreach (e; (*exp.arguments)[1 .. $])
+ buf.printf(", %s", typeString(e));
+
+ error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
+ errorSupplemental(ad.loc, "perhaps define `auto opIndex(%s) {}` for `%s`",
+ buf.extractChars, ad.toPrettyChars());
+ }
+ }
+ }
else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
error(exp.loc, "static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
else if (isIndexableNonAggregate(exp.e1.type))
@@ -9797,11 +9816,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(CommaExp e)
{
//printf("Semantic.CommaExp() %s\n", e.toChars());
- if (e.type)
- {
- result = e;
- return;
- }
// Allow `((a,b),(x,y))`
if (e.allowCommaExp)
@@ -9826,16 +9840,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e.type = e.e2.type;
result = e;
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
return;
- if (e.type is Type.tvoid)
+ if (!e.isGenerated)
{
- checkMustUse(e.e1, sc);
- discardValue(e.e1);
+ if (e.allowCommaExp)
+ {
+ checkMustUse(e.e1, sc);
+ discardValue(e.e1);
+ }
+ else
+ error(e.loc, "using the result of a comma expression is not allowed");
}
- else if (!e.allowCommaExp && !e.isGenerated)
- error(e.loc, "using the result of a comma expression is not allowed");
}
override void visit(IntervalExp e)
@@ -9844,11 +9861,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("IntervalExp::semantic('%s')\n", e.toChars());
}
- if (e.type)
- {
- result = e;
- return;
- }
Expression le = e.lwr;
le = le.expressionSemantic(sc);
@@ -9923,11 +9935,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("IndexExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
// operator overloading should be handled in ArrayExp already.
if (!exp.e1.type)
@@ -9965,7 +9972,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
t1b = t1b.castMod(tv1.mod);
exp.e1 = exp.e1.castTo(sc, t1b);
}
- if (t1b.ty == Tsarray || t1b.ty == Tarray)
+ if (t1b.isStaticOrDynamicArray())
{
if (!checkAddressable(exp, sc))
return setError();
@@ -9974,7 +9981,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
/* Run semantic on e2
*/
Scope* scx = sc;
- if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
+ if (t1b.isStaticOrDynamicArray() || t1b.ty == Ttuple)
{
// Create scope for 'length' variable
ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
@@ -10006,7 +10013,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
case Tpointer:
if (t1b.isPtrToFunction())
{
- error(exp.loc, "cannot index function pointer `%s`", exp.e1.toChars());
+ error(exp.loc, "cannot index function pointer `%s`", exp.e1.toErrMsg());
return setError();
}
exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
@@ -10016,7 +10023,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
{
}
- else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
+ else if (sc.setUnsafe(false, exp.loc, "indexing pointer `%s`", exp.e1))
{
return setError();
}
@@ -10054,7 +10061,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
semanticTypeInfo(sc, taa);
- checkNewEscape(sc, exp.e2, false);
+ checkNewEscape(*sc, exp.e2, false);
exp.type = taa.next;
break;
@@ -10088,7 +10095,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (length <= index)
{
- error(exp.loc, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
+ error(exp.loc, "sequence index `[%llu]` is outside bounds `[0 .. %llu]`", index, cast(ulong)length);
return setError();
}
Expression e;
@@ -10103,14 +10110,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
default:
- error(exp.loc, "`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
+ error(exp.loc, "`%s` must be an array or pointer type, not `%s`", exp.e1.toErrMsg(), exp.e1.type.toChars());
return setError();
}
// We might know $ now
setLengthVarIfKnown(exp.lengthVar, t1b);
- if (t1b.ty == Tsarray || t1b.ty == Tarray)
+ if (t1b.isStaticOrDynamicArray())
{
Expression el = new ArrayLengthExp(exp.loc, exp.e1);
el = el.expressionSemantic(sc);
@@ -10125,7 +10132,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// OR it in, because it might already be set for C array indexing
exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
}
- else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
+ else if (sc.inCfile && t1b.ty == Tsarray)
{
if (auto ve = exp.e1.isVarExp())
{
@@ -10150,13 +10157,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("PostExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* See if need to rewrite the AST because of cast/call ambiguity
*/
@@ -10180,20 +10182,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
exp.e1 = e1x;
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
if (exp.e1.checkReadModifyWrite(exp.op))
return setError();
if (exp.e1.op == EXP.slice)
{
const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
- error(exp.loc, "cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
+ error(exp.loc, "cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toErrMsg(), s);
return setError();
}
@@ -10218,7 +10213,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
/* Rewrite as:
* auto tmp = e1; ++e1; tmp
*/
- auto tmp = copyToTemp(0, "__pitmp", exp.e1);
+ auto tmp = copyToTemp(STC.none, "__pitmp", exp.e1);
Expression ea = new DeclarationExp(exp.loc, tmp);
Expression eb = exp.e1.syntaxCopy();
@@ -10229,7 +10224,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Combine de,ea,eb,ec
if (de)
ea = new CommaExp(exp.loc, de, ea);
- e = new CommaExp(exp.loc, ea, eb);
+ Expression e = new CommaExp(exp.loc, ea, eb);
e = new CommaExp(exp.loc, e, ec);
e = e.expressionSemantic(sc);
result = e;
@@ -10239,7 +10234,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = exp.e1.modifiableLvalue(sc);
exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
- e = exp;
+ Expression e = exp;
if (exp.e1.checkScalar() ||
exp.e1.checkSharedAccess(sc))
return setError();
@@ -10256,20 +10251,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(PreExp exp)
{
- Expression e = exp.op_overload(sc);
// printf("PreExp::semantic('%s')\n", toChars());
- if (e)
+ if (Expression e = exp.opOverloadUnary(sc))
{
result = e;
return;
}
// Rewrite as e1+=1 or e1-=1
+ Expression e;
if (exp.op == EXP.prePlusPlus)
e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
else
e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
- result = e.expressionSemantic(sc);
+ result = e.expressionSemanticWithParent(sc, exp);
}
/*
@@ -10312,9 +10307,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
static if (LOGSEMANTIC)
{
- if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
- if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
- if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
+ if (exp.op == EXP.blit) printf("BlitExp.semantic('%s')\n", exp.toChars());
+ if (exp.op == EXP.assign) printf("AssignExp.semantic('%s')\n", exp.toChars());
+ if (exp.op == EXP.construct) printf("ConstructExp.semantic('%s')\n", exp.toChars());
}
void setResult(Expression e, int line = __LINE__)
@@ -10323,16 +10318,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
}
- if (exp.type)
- {
- return setResult(exp);
- }
-
Expression e1old = exp.e1;
if (auto e2comma = exp.e2.isCommaExp())
{
- if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
+ if (!e2comma.isGenerated && !sc.inCfile)
error(exp.loc, "using the result of a comma expression is not allowed");
/* Rewrite to get rid of the comma from rvalue
@@ -10380,10 +10370,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
AggregateDeclaration ad = isAggregate(t1b);
if (!ad)
break;
- if (search_function(ad, Id.indexass))
+ if (search_function(ad, Id.opIndexAssign))
{
// Deal with $
- res = resolveOpDollar(sc, ae, &e0);
+ res = resolveOpDollar(sc, ae, e0);
if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
goto Lfallback;
if (res.op == EXP.error)
@@ -10399,7 +10389,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
Expressions* a = ae.arguments.copy();
a.insert(0, exp.e2);
- res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
+ res = new DotIdExp(exp.loc, ae.e1, Id.opIndexAssign);
res = new CallExp(exp.loc, res, a);
if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
res = res.trySemantic(sc);
@@ -10410,10 +10400,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Lfallback:
- if (maybeSlice && search_function(ad, Id.sliceass))
+ if (maybeSlice && search_function(ad, Id.opSliceAssign))
{
// Deal with $
- res = resolveOpDollar(sc, ae, ie, &e0);
+ res = resolveOpDollar(sc, ae, ie, e0);
if (res.op == EXP.error)
return setResult(res);
@@ -10433,7 +10423,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
a.push(ie.lwr);
a.push(ie.upr);
}
- res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
+ res = new DotIdExp(exp.loc, ae.e1, Id.opSliceAssign);
res = new CallExp(exp.loc, res, a);
res = res.expressionSemantic(sc);
return setResult(Expression.combine(e0, res));
@@ -10477,7 +10467,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e1x = e;
}
- else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
+ else if (sc.inCfile && e1x.isDotIdExp())
{
auto die = e1x.isDotIdExp();
e1x = fieldLookup(die.e1, sc, die.ident, die.arrow);
@@ -10497,7 +10487,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
auto ode = e;
exp.e2 = exp.e2.expressionSemantic(sc);
- uint errors = global.startGagging();
+ const errors = global.startGagging();
e = resolvePropertiesX(sc, e, exp.e2);
// Any error or if 'e' is not resolved, go to UFCS
if (global.endGagging(errors) || e is ode)
@@ -10523,7 +10513,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* or:
* f() = value
*/
- if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
+ if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, &aliasThisStop))
return setResult(e);
if (e1x.checkRightThis(sc))
@@ -10656,6 +10646,35 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.op == EXP.assign
&& exp.e1.checkModifiable(sc) == Modifiable.initialization)
{
+ // Check common mistake of misspelled parameters in constructors,
+ // e.g. `this(int feild) { this.field = field; }`
+ if (auto dve1 = exp.e1.isDotVarExp)
+ if (auto dve2 = exp.e2.isDotVarExp)
+ if (sc.func && sc.func.parameters && dve1.e1.isThisExp && dve2.e1.isThisExp()
+ && dve1.var.ident.equals(dve2.var.ident))
+ {
+ // @@@DEPRECATED_2.121@@@
+ // Deprecated in 2.111, make it an error in 2.121
+ deprecation(exp.e1.loc, "cannot initialize field `%s` with itself", dve1.var.toChars());
+ auto findParameter(const(char)[] s, ref int cost)
+ {
+ foreach (p; *sc.func.parameters)
+ {
+ if (p.ident.toString == s)
+ {
+ cost = 1;
+ return p.ident.toString;
+ }
+ }
+ return null;
+ }
+ import dmd.root.speller : speller;
+ if (auto s = speller!findParameter(dve1.var.ident.toString))
+ {
+ deprecationSupplemental(sc.func.loc, "did you mean to use parameter `%.*s`?\n", s.fTuple.expand);
+ }
+ }
+
//printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
auto t = exp.type;
exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
@@ -10750,7 +10769,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
dvx.e1 = e1x;
auto cx = cast(CallExp)ce.copy();
cx.e1 = dvx;
- if (checkConstructorEscape(sc, cx, false))
+ if (checkConstructorEscape(*sc, cx, false))
return setError();
Expression e0;
@@ -10784,6 +10803,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
/* We have a copy constructor for this
*/
+ //printf("exp: %s\n", toChars(exp));
+ //printf("e2x: %s\n", toChars(e2x));
if (e2x.isLvalue())
{
if (sd.hasCopyCtor)
@@ -10830,6 +10851,38 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
}
+ else if (sd.hasMoveCtor && (!e2x.isCallExp() || e2x.rvalue) && !e2x.isStructLiteralExp())
+ {
+ // #move
+ /* The !e2x.isCallExp() is because it is already an rvalue
+ and the move constructor is unnecessary:
+ struct S {
+ alias TT this;
+ long TT();
+ this(T)(int x) {}
+ this(S);
+ this(ref S);
+ ~this();
+ }
+ S fun(ref S arg);
+ void test() { S st; fun(st); }
+ */
+ /* Rewrite as:
+ * e1 = init, e1.moveCtor(e2);
+ */
+ Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
+ einit.type = e1x.type;
+
+ Expression e;
+ e = new DotIdExp(exp.loc, e1x, Id.ctor);
+ e = new CallExp(exp.loc, e, e2x);
+ e = new CommaExp(exp.loc, einit, e);
+
+ //printf("e: %s\n", e.toChars());
+
+ result = e.expressionSemantic(sc);
+ return;
+ }
else
{
/* The struct value returned from the function is transferred
@@ -10844,13 +10897,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!e2x.implicitConvTo(t1))
{
AggregateDeclaration ad2 = isAggregate(e2x.type);
- if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
+ if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(aliasThisStop[1], exp.e2.type))
{
/* Rewrite (e1 op e2) as:
* (e1 op e2.aliasthis)
*/
exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
- result = exp.expressionSemantic(sc);
+ result = exp.expressionSemantic(sc, aliasThisStop);
return;
}
}
@@ -10888,7 +10941,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (newExp.newtype && newExp.newtype == t1)
{
error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
- newExp.toChars(), newExp.type.toChars(), t1.toChars());
+ newExp.toErrMsg(), newExp.type.toChars(), t1.toChars());
errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
return setError();
}
@@ -10905,14 +10958,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
return;
}
- if (search_function(sd, Id.call))
+ if (search_function(sd, Id.opCall))
{
/* Look for static opCall
* https://issues.dlang.org/show_bug.cgi?id=2702
* Rewrite as:
* e1 = typeof(e1).opCall(arguments)
*/
- e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
+ e2x = typeDotIdExp(e2x.loc, e1x.type, Id.opCall);
e2x = new CallExp(exp.loc, e2x, exp.e2);
e2x = e2x.expressionSemantic(sc);
@@ -10929,13 +10982,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else // https://issues.dlang.org/show_bug.cgi?id=11355
{
AggregateDeclaration ad2 = isAggregate(e2x.type);
- if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
+ if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(aliasThisStop[1], exp.e2.type))
{
/* Rewrite (e1 op e2) as:
* (e1 op e2.aliasthis)
*/
exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
- result = exp.expressionSemantic(sc);
+ result = exp.expressionSemantic(sc, aliasThisStop);
return;
}
}
@@ -10976,8 +11029,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
ae.e1 = ae.e1.expressionSemantic(sc);
ae.e1 = ae.e1.optimize(WANTvalue);
ae.e2 = ev;
- Expression e = ae.op_overload(sc);
- if (e)
+ if (Expression e = ae.opOverloadAssign(sc, aliasThisStop))
{
Expression ey = null;
if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
@@ -11027,14 +11079,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
}
- else
+ else if (Expression e = exp.isAssignExp().opOverloadAssign(sc, aliasThisStop))
{
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
+ result = e;
+ return;
}
}
else
@@ -11051,8 +11099,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Disallow assignment operator overloads for same type
if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
{
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.isAssignExp().opOverloadAssign(sc, aliasThisStop))
{
result = e;
return;
@@ -11072,7 +11119,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* string to match the size of e1.
*/
Type t2 = e2x.type.toBasetype();
- if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
+ if (sc.inCfile && e2x.isStringExp() && t2.isTypeSArray())
{
uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
@@ -11185,6 +11232,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e2 = e2x;
t1 = e1x.type.toBasetype();
}
+ else if (t1.ty == Taarray)
+ {
+ // when assigning a constant, the need for TypeInfo might change
+ semanticTypeInfo(sc, t1);
+ }
/* Check the mutability of e1.
*/
if (auto ale = exp.e1.isArrayLengthExp())
@@ -11233,14 +11285,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = id.expressionSemantic(sc);
auto arguments = new Expressions();
- arguments.reserve(5);
- if (global.params.tracegc)
- {
- auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
- arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
- arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
- arguments.push(new StringExp(exp.loc, funcname.toDString()));
- }
arguments.push(ale.e1);
arguments.push(exp.e2);
@@ -11267,7 +11311,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
{
error(exp.loc, "slice `%s` is not mutable, struct `%s` has immutable members",
- exp.e1.toChars(), tn.baseElemOf().toChars());
+ exp.e1.toErrMsg(), tn.baseElemOf().toChars());
result = ErrorExp.get();
return;
}
@@ -11290,7 +11334,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (tn && !tn.baseElemOf().isAssignable())
{
error(exp.loc, "array `%s` is not mutable, struct `%s` has immutable members",
- exp.e1.toChars(), tn.baseElemOf().toChars());
+ exp.e1.toErrMsg(), tn.baseElemOf().toChars());
result = ErrorExp.get();
return;
}
@@ -11336,7 +11380,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
else if (exp.e1.op == EXP.slice &&
- (t2.ty == Tarray || t2.ty == Tsarray) &&
+ t2.isStaticOrDynamicArray() &&
t2.nextOf().implicitConvTo(t1.nextOf()))
{
// Check element-wise assignment.
@@ -11360,7 +11404,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
uinteger_t dim2 = tsa2.dim.toInteger();
if (dim1 != dim2)
{
- error(exp.loc, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
+ error(exp.loc, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toErrMsg());
return setError();
}
}
@@ -11412,11 +11456,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
e2x = e2x.implicitCastTo(sc, exp.e1.type);
}
- if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
- {
- if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
- return setError();
- }
}
else
{
@@ -11433,7 +11472,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
{
scope sd = (cast(TypeStruct)t1).sym;
- Dsymbol opAssign = search_function(sd, Id.assign);
+ Dsymbol opAssign = search_function(sd, Id.opAssign);
// and the struct defines an opAssign
if (opAssign)
@@ -11441,13 +11480,40 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// offer more information about the cause of the problem
errorSupplemental(exp.loc,
"`%s` is the first assignment of `%s` therefore it represents its initialization",
- exp.toChars(), exp.e1.toChars());
+ exp.toErrMsg(), exp.e1.toErrMsg());
errorSupplemental(exp.loc,
"`opAssign` methods are not used for initialization, but for subsequent assignments");
}
}
}
}
+
+ if (exp.e1.op == EXP.slice &&
+ t1.isStaticOrDynamicArray() &&
+ t1.nextOf().toBasetype().ty == Tvoid)
+ {
+ if (t2.nextOf().implicitConvTo(t1.nextOf()))
+ {
+ if (sc.setUnsafe(false, exp.loc, "copying `%s` to `%s`", t2, t1))
+ return setError();
+ }
+ else
+ {
+ // copying from non-void to void was overlooked, deprecate
+ if (sc.setUnsafePreview(FeatureState.default_, false, exp.loc,
+ "copying `%s` to `%s`", t2, t1))
+ return setError();
+ }
+ if (sc.previews.fixImmutableConv && !t2.implicitConvTo(t1))
+ {
+ error(exp.loc, "cannot copy `%s` to `%s`",
+ t2.toChars(), t1.toChars());
+ errorSupplemental(exp.loc,
+ "Source data has incompatible type qualifier(s)");
+ errorSupplemental(exp.loc, "Use `cast(%s)` to force copy", t1.toChars());
+ return setError();
+ }
+ }
if (e2x.op == EXP.error)
{
result = e2x;
@@ -11458,7 +11524,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
/* Look for array operations
*/
- if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
+ if (t2.isStaticOrDynamicArray() && isArrayOpValid(exp.e2))
{
// Look for valid array operations
if (exp.memset != MemorySet.blockAssign &&
@@ -11511,9 +11577,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* `checkAssignExp` expects only AssignExps.
*/
if (res == exp) // no `AA[k] = v` rewrite was performed
- checkAssignEscape(sc, res, false, false);
+ checkAssignEscape(*sc, res, false, false);
else
- checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
+ checkNewEscape(*sc, assignElem, false); // assigning to AA puts it on heap
if (auto ae = res.isConstructExp())
{
@@ -11635,7 +11701,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return ae;
const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
- (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
+ (ae.e2.type.isStaticOrDynamicArray()) &&
(ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
@@ -11675,7 +11741,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// `__assigntmp` will be destroyed together with the array `ae.e1`.
// When `ae.e2` is a variadic arg array, it is also `scope`, so
// `__assigntmp` may also be scope.
- StorageClass stc = STC.nodtor;
+ STC stc = STC.nodtor;
if (isArrayAssign)
stc |= STC.rvalue | STC.scope_;
@@ -11701,24 +11767,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(PowAssignExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinaryAssign(sc, aliasThisStop))
{
result = e;
return;
}
- if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
+ if (exp.suggestOpOpAssign(sc, parent) ||
+ exp.e1.checkReadModifyWrite(exp.op, exp.e2))
return setError();
assert(exp.e1.type && exp.e2.type);
- if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
+ if (exp.e1.op == EXP.slice || exp.e1.type.isStaticOrDynamicArray())
{
if (checkNonAssignmentArrayOp(exp.e1))
return setError();
@@ -11738,9 +11798,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// Check element types are arithmetic
Type tb1 = exp.e1.type.nextOf().toBasetype();
Type tb2 = exp.e2.type.toBasetype();
- if (tb2.ty == Tarray || tb2.ty == Tsarray)
+ if (tb2.isStaticOrDynamicArray())
tb2 = tb2.nextOf().toBasetype();
- if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
+ if ((tb1.isIntegral() || tb1.isFloating()) && (tb2.isIntegral() || tb2.isFloating()))
{
exp.type = exp.e1.type;
result = arrayOp(exp, sc);
@@ -11752,10 +11812,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = exp.e1.modifiableLvalue(sc);
}
- if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
+ if ((exp.e1.type.isIntegral() || exp.e1.type.isFloating()) && (exp.e2.type.isIntegral() || exp.e2.type.isFloating()))
{
Expression e0 = null;
- e = exp.reorderSettingAAElem(sc);
+ Expression e = exp.reorderSettingAAElem(sc);
e = Expression.extractLast(e, e0);
assert(e == exp);
@@ -11785,20 +11845,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(CatAssignExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
//printf("CatAssignExp::semantic() %s\n", exp.toChars());
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinaryAssign(sc, aliasThisStop))
{
result = e;
return;
}
+ if (exp.suggestOpOpAssign(sc, parent))
+ return setError();
+
if (SliceExp se = exp.e1.isSliceExp())
{
if (se.e1.type.toBasetype().ty == Tsarray)
@@ -11833,9 +11890,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* EXP.concatenateDcharAssign: appending dchar to T[]
*/
if ((tb1.ty == Tarray) &&
- (tb2.ty == Tarray || tb2.ty == Tsarray) &&
+ tb2.isStaticOrDynamicArray() &&
(exp.e2.implicitConvTo(exp.e1.type) ||
(tb2.nextOf().implicitConvTo(tb1next) &&
+ // Do not strip const(void)[]
+ (!sc.previews.fixImmutableConv || tb1next.ty != Tvoid) &&
(tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
{
// EXP.concatenateAssign
@@ -11861,11 +11920,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (tb2.checkPostblit(exp.e2.loc, sc))
return setError();
- if (checkNewEscape(sc, exp.e2, false))
+ if (checkNewEscape(*sc, exp.e2, false))
return setError();
- exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
- exp.e2 = doCopyOrMove(sc, exp.e2);
+ auto ecast = exp.e2.castTo(sc, tb1next);
+ if (auto ce = ecast.isCastExp())
+ ce.trusted = true;
+
+ exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, ecast);
+ exp.e2 = doCopyOrMove(sc, exp.e2, null, false);
}
else if (tb1.ty == Tarray &&
(tb1next.ty == Tchar || tb1next.ty == Twchar) &&
@@ -11881,49 +11944,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
else
{
- // Try alias this on first operand
- static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
- {
- AggregateDeclaration ad1 = isAggregate(exp.e1.type);
- if (!ad1 || !ad1.aliasthis)
- return null;
-
- /* Rewrite (e1 op e2) as:
- * (e1.aliasthis op e2)
- */
- if (isRecursiveAliasThis(exp.att1, exp.e1.type))
- return null;
- //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
- Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
- BinExp be = cast(BinExp)exp.copy();
- be.e1 = e1;
- return be.trySemantic(sc);
- }
-
- // Try alias this on second operand
- static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
- {
- AggregateDeclaration ad2 = isAggregate(exp.e2.type);
- if (!ad2 || !ad2.aliasthis)
- return null;
- /* Rewrite (e1 op e2) as:
- * (e1 op e2.aliasthis)
- */
- if (isRecursiveAliasThis(exp.att2, exp.e2.type))
- return null;
- //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
- Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
- BinExp be = cast(BinExp)exp.copy();
- be.e2 = e2;
- return be.trySemantic(sc);
- }
-
Laliasthis:
- result = tryAliasThisForLhs(exp, sc);
+ result = checkAliasThisForLhs(isAggregate(exp.e1.type), sc, exp, aliasThisStop);
if (result)
return;
- result = tryAliasThisForRhs(exp, sc);
+ result = checkAliasThisForRhs(isAggregate(exp.e2.type), sc, exp, aliasThisStop);
if (result)
return;
@@ -11938,9 +11964,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto assignElem = exp.e2;
auto res = exp.reorderSettingAAElem(sc);
if (res != exp) // `AA[k] = v` rewrite was performed
- checkNewEscape(sc, assignElem, false);
+ checkNewEscape(*sc, assignElem, false);
else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
- checkAssignEscape(sc, res, false, false);
+ checkAssignEscape(*sc, res, false, false);
result = res;
@@ -11976,15 +12002,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = new DotIdExp(exp.loc, id, hook);
auto arguments = new Expressions();
- arguments.reserve(5);
- if (global.params.tracegc)
- {
- auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
- arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
- arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
- arguments.push(new StringExp(exp.loc, funcname.toDString()));
- }
-
arguments.push(exp.e1);
arguments.push(exp.e2);
Expression ce = new CallExp(exp.loc, id, arguments);
@@ -12019,15 +12036,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = new DotIdExp(exp.loc, id, hook);
auto arguments = new Expressions();
- arguments.reserve(5);
- if (global.params.tracegc)
- {
- auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
- arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
- arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
- arguments.push(new StringExp(exp.loc, funcname.toDString()));
- }
-
Expression eValue1;
Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
@@ -12075,19 +12083,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("AddExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinary(sc, aliasThisStop))
{
result = e;
return;
@@ -12113,13 +12110,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (err)
return setError();
- if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
+ if (tb1.ty == Tpointer && exp.e2.type.isIntegral() || tb2.ty == Tpointer && exp.e1.type.isIntegral())
{
result = scaleFactor(exp, sc);
return;
}
- if (tb1.ty == Tpointer && tb2.ty == Tpointer)
+ if (tb1.ty == Tpointer && tb2.ty == Tpointer ||
+ tb1.ty == Tnull && tb2.ty == Tnull)
{
result = exp.incompatibleTypes();
return;
@@ -12132,7 +12130,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
if (!isArrayOpValid(exp))
{
@@ -12143,13 +12141,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
+ if (exp.suggestBinaryOverloads(sc) || exp.checkArithmeticBin())
+ return setError();
+
tb1 = exp.e1.type.toBasetype();
if (!target.isVectorOpSupported(tb1, exp.op, tb2))
{
result = exp.incompatibleTypes();
return;
}
- if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
+ if ((tb1.isReal() && exp.e2.type.isImaginary()) || (tb1.isImaginary() && exp.e2.type.isReal()))
{
switch (exp.type.toBasetype().ty)
{
@@ -12181,19 +12182,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("MinExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinary(sc, aliasThisStop))
{
result = e;
return;
@@ -12216,11 +12206,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
}
+ if (t1.ty == Tnull && t2.ty == Tnull)
+ {
+ exp.incompatibleTypes();
+ return setError();
+ }
if (err)
return setError();
if (t1.ty == Tpointer)
{
+ Expression e;
if (t2.ty == Tpointer)
{
// https://dlang.org/spec/expression.html#add_expressions
@@ -12232,12 +12228,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!p1.equivalent(p2))
{
- // Deprecation to remain for at least a year, after which this should be
- // changed to an error
// See https://github.com/dlang/dmd/pull/7332
- deprecation(exp.loc,
- "cannot subtract pointers to different types: `%s` and `%s`.",
+ error(exp.loc, "cannot subtract pointers to different types: `%s` and `%s`.",
t1.toChars(), t2.toChars());
+ return setError();
}
// Need to divide the result by the stride
@@ -12265,7 +12259,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e.type = Type.tptrdiff_t;
}
}
- else if (t2.isintegral())
+ else if (t2.isIntegral())
e = scaleFactor(exp, sc);
else
{
@@ -12289,7 +12283,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
if (!isArrayOpValid(exp))
{
@@ -12300,6 +12294,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
+ if (exp.suggestBinaryOverloads(sc) || exp.checkArithmeticBin())
+ return setError();
+
t1 = exp.e1.type.toBasetype();
t2 = exp.e2.type.toBasetype();
if (!target.isVectorOpSupported(t1, exp.op, t2))
@@ -12307,7 +12304,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = exp.incompatibleTypes();
return;
}
- if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
+ if ((t1.isReal() && t2.isImaginary()) || (t1.isImaginary() && t2.isReal()))
{
switch (exp.type.ty)
{
@@ -12360,7 +12357,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return result;
}
- void handleCatArgument(Expressions *arguments, Expression e, Type catType, bool isRightArg)
+ void handleCatArgument(Expressions* arguments, Expression e, Type catType, bool isRightArg)
{
auto tb = e.type.toBasetype();
@@ -12382,7 +12379,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (hook == Id._d_arraycatnTX)
arguments.pushSlice((*callExp.arguments)[]);
else
- arguments.pushSlice((*callExp.arguments)[3 .. $]);
+ arguments.pushSlice((*callExp.arguments)[0 .. $ - 3]);
}
}
else
@@ -12390,15 +12387,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
auto arguments = new Expressions();
- if (useTraceGCHook)
- {
- auto funcname = (sc.callsc && sc.callsc.func) ?
- sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
- arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
- arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
- arguments.push(new StringExp(exp.loc, funcname.toDString()));
- }
-
handleCatArgument(arguments, exp.e1, exp.type.toBasetype(), false);
handleCatArgument(arguments, exp.e2, exp.type.toBasetype(), true);
@@ -12428,19 +12416,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
// https://dlang.org/spec/expression.html#cat_expressions
//printf("CatExp.semantic() %s\n", toChars());
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinary(sc, aliasThisStop))
{
result = e;
return;
@@ -12480,11 +12456,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
// Check for: array ~ element
- if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
+ if (tb1.isStaticOrDynamicArray() && tb2.ty != Tvoid)
{
if (exp.e1.op == EXP.arrayLiteral)
{
- exp.e2 = doCopyOrMove(sc, exp.e2);
+ exp.e2 = doCopyOrMove(sc, exp.e2, null, false);
// https://issues.dlang.org/show_bug.cgi?id=14686
// Postblit call appears in AST, and this is
// finally translated to an ArrayLiteralExp in below optimize().
@@ -12511,7 +12487,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
exp.type = tb1next.arrayOf();
L2elem:
- if (checkNewEscape(sc, exp.e2, false))
+ if (checkNewEscape(*sc, exp.e2, false))
return setError();
result = exp.optimize(WANTvalue);
trySetCatExpLowering(result);
@@ -12519,11 +12495,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
// Check for: element ~ array
- if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
+ if (tb2.isStaticOrDynamicArray() && tb1.ty != Tvoid)
{
if (exp.e2.op == EXP.arrayLiteral)
{
- exp.e1 = doCopyOrMove(sc, exp.e1);
+ exp.e1 = doCopyOrMove(sc, exp.e1, null, false);
}
else if (exp.e2.op == EXP.string_)
{
@@ -12545,7 +12521,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
exp.type = tb2next.arrayOf();
L1elem:
- if (checkNewEscape(sc, exp.e1, false))
+ if (checkNewEscape(*sc, exp.e1, false))
return setError();
result = exp.optimize(WANTvalue);
trySetCatExpLowering(result);
@@ -12554,7 +12530,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Lpeer:
- if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
+ if (tb1.isStaticOrDynamicArray() && tb2.isStaticOrDynamicArray() &&
+ (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
{
Type t1 = tb1next.mutableOf().constOf().arrayOf();
Type t2 = tb2next.mutableOf().constOf().arrayOf();
@@ -12581,7 +12558,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.type = tb.nextOf().arrayOf();
if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
{
- exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
+ // Do not strip const(void)[]
+ if (!sc.previews.fixImmutableConv || tb.nextOf().ty != Tvoid)
+ exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
}
if (Type tbn = tb.nextOf())
{
@@ -12590,8 +12569,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Type t1 = exp.e1.type.toBasetype();
Type t2 = exp.e2.type.toBasetype();
- if ((t1.ty == Tarray || t1.ty == Tsarray) &&
- (t2.ty == Tarray || t2.ty == Tsarray))
+ Expression e;
+ if (t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray())
{
// Normalize to ArrayLiteralExp or StringExp as far as possible
e = exp.optimize(WANTvalue);
@@ -12607,67 +12586,64 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
trySetCatExpLowering(result);
}
- override void visit(MulExp exp)
+ bool commonArithBinOpSemantic(BinExp exp)
{
- version (none)
- {
- printf("MulExp::semantic() %s\n", exp.toChars());
- }
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinary(sc, aliasThisStop))
{
result = e;
- return;
+ return true;
}
if (Expression ex = typeCombine(exp, sc))
{
result = ex;
- return;
+ return true;
}
Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
if (!isArrayOpValid(exp))
{
result = arrayOpInvalidError(exp);
- return;
+ return true;
}
result = exp;
- return;
+ return true;
}
- if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
- return setError();
+ if (exp.suggestBinaryOverloads(sc) || exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
+ {
+ setError();
+ return true;
+ }
+ return false;
+ }
+ override void visit(MulExp exp)
+ {
+ version (none)
+ {
+ printf("MulExp::semantic() %s\n", exp.toChars());
+ }
- if (exp.type.isfloating())
+ if (commonArithBinOpSemantic(exp))
+ return;
+ if (exp.type.isFloating())
{
Type t1 = exp.e1.type;
Type t2 = exp.e2.type;
- if (t1.isreal())
+ if (t1.isReal())
{
exp.type = t2;
}
- else if (t2.isreal())
+ else if (t2.isReal())
{
exp.type = t1;
}
- else if (t1.isimaginary())
+ else if (t1.isImaginary())
{
- if (t2.isimaginary())
+ if (t2.isImaginary())
{
switch (t1.toBasetype().ty)
{
@@ -12690,7 +12666,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// iy * iv = -yv
exp.e1.type = exp.type;
exp.e2.type = exp.type;
- e = new NegExp(exp.loc, exp);
+ Expression e = new NegExp(exp.loc, exp);
e = e.expressionSemantic(sc);
result = e;
return;
@@ -12698,12 +12674,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
exp.type = t2; // t2 is complex
}
- else if (t2.isimaginary())
+ else if (t2.isImaginary())
{
exp.type = t1; // t1 is complex
}
}
- else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ else if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
{
result = exp.incompatibleTypes();
return;
@@ -12713,70 +12689,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(DivExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
+ if (commonArithBinOpSemantic(exp))
return;
- }
-
- if (Expression ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- result = arrayOpInvalidError(exp);
- return;
- }
- result = exp;
- return;
- }
-
- if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
- return setError();
- if (exp.type.isfloating())
+ if (exp.type.isFloating())
{
Type t1 = exp.e1.type;
Type t2 = exp.e2.type;
- if (t1.isreal())
+ if (t1.isReal())
{
exp.type = t2;
- if (t2.isimaginary())
+ if (t2.isImaginary())
{
// x/iv = i(-x/v)
exp.e2.type = t1;
- e = new NegExp(exp.loc, exp);
+ Expression e = new NegExp(exp.loc, exp);
e = e.expressionSemantic(sc);
result = e;
return;
}
}
- else if (t2.isreal())
+ else if (t2.isReal())
{
exp.type = t1;
}
- else if (t1.isimaginary())
+ else if (t1.isImaginary())
{
- if (t2.isimaginary())
+ if (t2.isImaginary())
{
switch (t1.toBasetype().ty)
{
@@ -12799,12 +12739,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
exp.type = t2; // t2 is complex
}
- else if (t2.isimaginary())
+ else if (t2.isImaginary())
{
exp.type = t1; // t1 is complex
}
}
- else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ else if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
{
result = exp.incompatibleTypes();
return;
@@ -12814,54 +12754,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(ModExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression ex = typeCombine(exp, sc))
- {
- result = ex;
+ if (commonArithBinOpSemantic(exp))
return;
- }
- Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- result = arrayOpInvalidError(exp);
- return;
- }
- result = exp;
- return;
- }
- if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
{
result = exp.incompatibleTypes();
return;
}
- if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
- return setError();
-
- if (exp.type.isfloating())
+ if (exp.type.isFloating())
{
exp.type = exp.e1.type;
- if (exp.e2.type.iscomplex())
+ if (exp.e2.type.isComplex())
{
error(exp.loc, "cannot perform modulo complex arithmetic");
return setError();
@@ -12872,54 +12777,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(PowExp exp)
{
- if (exp.type)
- {
- result = exp;
+ if (commonArithBinOpSemantic(exp))
return;
- }
- //printf("PowExp::semantic() %s\n", toChars());
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- result = arrayOpInvalidError(exp);
- return;
- }
- result = exp;
- return;
- }
-
- if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
- return setError();
-
- if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
{
result = exp.incompatibleTypes();
return;
}
// First, attempt to fold the expression.
- e = exp.optimize(WANTvalue);
+ Expression e = exp.optimize(WANTvalue);
if (e.op != EXP.pow)
{
e = e.expressionSemantic(sc);
@@ -12930,7 +12798,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Module mmath = Module.loadStdMath();
if (!mmath)
{
- error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toChars());
+ error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toErrMsg());
return setError();
}
e = new ScopeExp(exp.loc, mmath);
@@ -12950,28 +12818,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
- override void visit(ShlExp exp)
+ private void visitShift(BinExp exp)
{
- //printf("ShlExp::semantic(), type = %p\n", type);
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinary(sc, aliasThisStop))
{
result = e;
return;
}
- if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
+ if (exp.suggestBinaryOverloads(sc) || exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
return setError();
if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
@@ -12979,101 +12834,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = exp.incompatibleTypes();
return;
}
+
exp.e1 = integralPromotions(exp.e1, sc);
if (exp.e2.type.toBasetype().ty != Tvector)
- exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
+ {
+ Type tb1 = exp.e1.type.toBasetype();
+ exp.e2 = exp.e2.castTo(sc, tb1.ty == Tvector ? tb1 : Type.tshiftcnt);
+ }
exp.type = exp.e1.type;
result = exp;
}
+ override void visit(ShlExp exp)
+ {
+ visitShift(exp);
+ }
override void visit(ShrExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
- return setError();
-
- if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
- {
- result = exp.incompatibleTypes();
- return;
- }
- exp.e1 = integralPromotions(exp.e1, sc);
- if (exp.e2.type.toBasetype().ty != Tvector)
- exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
-
- exp.type = exp.e1.type;
- result = exp;
+ visitShift(exp);
}
-
override void visit(UshrExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
- return setError();
-
- if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
- {
- result = exp.incompatibleTypes();
- return;
- }
- exp.e1 = integralPromotions(exp.e1, sc);
- if (exp.e2.type.toBasetype().ty != Tvector)
- exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
-
- exp.type = exp.e1.type;
- result = exp;
+ visitShift(exp);
}
- override void visit(AndExp exp)
+ private void visitBinaryBitOp(BinExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinary(sc, aliasThisStop))
{
result = e;
return;
@@ -13093,7 +12881,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
+ if (tb.isStaticOrDynamicArray())
{
if (!isArrayOpValid(exp))
{
@@ -13108,120 +12896,24 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = exp.incompatibleTypes();
return;
}
- if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
+
+ if (exp.suggestBinaryOverloads(sc) || exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
return setError();
result = exp;
}
+ override void visit(AndExp exp)
+ {
+ visitBinaryBitOp(exp);
+ }
override void visit(OrExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
- {
- exp.type = exp.e1.type;
- result = exp;
- return;
- }
-
- if (Expression ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- result = arrayOpInvalidError(exp);
- return;
- }
- result = exp;
- return;
- }
- if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
- {
- result = exp.incompatibleTypes();
- return;
- }
- if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
- return setError();
-
- result = exp;
+ visitBinaryBitOp(exp);
}
-
override void visit(XorExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
- {
- exp.type = exp.e1.type;
- result = exp;
- return;
- }
-
- if (Expression ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type tb = exp.type.toBasetype();
- if (tb.ty == Tarray || tb.ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- result = arrayOpInvalidError(exp);
- return;
- }
- result = exp;
- return;
- }
- if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
- {
- result = exp.incompatibleTypes();
- return;
- }
- if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
- return setError();
-
- result = exp;
+ visitBinaryBitOp(exp);
}
override void visit(LogicalExp exp)
@@ -13231,11 +12923,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("LogicalExp::semantic() %s\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
exp.setNoderefOperands();
@@ -13248,14 +12935,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e1x = resolveProperties(sc, e1x);
e1x = e1x.toBoolean(sc);
- if (sc.flags & SCOPE.condition)
+ if (sc.condition)
{
/* If in static if, don't evaluate e2 if we don't have to.
*/
e1x = e1x.optimize(WANTvalue);
if (e1x.toBool().hasValue(exp.op == EXP.orOr))
{
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
result = new IntegerExp(exp.op == EXP.orOr);
else
result = IntegerExp.createBool(exp.op == EXP.orOr);
@@ -13285,7 +12972,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (e2x.op == EXP.type || e2x.op == EXP.scope_)
{
- error(exp.loc, "`%s` is not an expression", exp.e2.toChars());
+ error(exp.loc, "`%s` is not an expression", exp.e2.toErrMsg());
return setError();
}
if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
@@ -13303,7 +12990,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (e2x.type.ty == Tvoid)
exp.type = Type.tvoid;
else
- exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
+ exp.type = (sc && sc.inCfile) ? Type.tint32 : Type.tbool;
exp.e1 = e1x;
exp.e2 = e2x;
@@ -13317,11 +13004,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("CmpExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
exp.setNoderefOperands();
@@ -13338,57 +13020,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
-
- EXP cmpop = exp.op;
- if (auto e = exp.op_overload(sc, &cmpop))
+ if (auto e = exp.opOverloadCmp(sc, aliasThisStop))
{
- if (!e.type.isscalar() && e.type.equals(exp.e1.type))
- {
- error(exp.loc, "recursive `opCmp` expansion");
- return setError();
- }
- if (e.op == EXP.call)
- {
-
- if (t1.ty == Tclass && t2.ty == Tclass)
- {
- // Lower to object.__cmp(e1, e2)
- Expression cl = new IdentifierExp(exp.loc, Id.empty);
- cl = new DotIdExp(exp.loc, cl, Id.object);
- cl = new DotIdExp(exp.loc, cl, Id.__cmp);
- cl = cl.expressionSemantic(sc);
-
- auto arguments = new Expressions();
- // Check if op_overload found a better match by calling e2.opCmp(e1)
- // If the operands were swapped, then the result must be reversed
- // e1.opCmp(e2) == -e2.opCmp(e1)
- // cmpop takes care of this
- if (exp.op == cmpop)
- {
- arguments.push(exp.e1);
- arguments.push(exp.e2);
- }
- else
- {
- // Use better match found by op_overload
- arguments.push(exp.e2);
- arguments.push(exp.e1);
- }
-
- cl = new CallExp(exp.loc, cl, arguments);
- cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
- result = cl.expressionSemantic(sc);
- return;
- }
-
- e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
- e = e.expressionSemantic(sc);
- }
result = e;
return;
}
-
if (Expression ex = typeCombine(exp, sc))
{
result = ex;
@@ -13400,13 +13037,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (f1 || f2)
return setError();
- exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
+ exp.type = (sc && sc.inCfile) ? Type.tint32 : Type.tbool;
// Special handling for array comparisons
Expression arrayLowering = null;
t1 = exp.e1.type.toBasetype();
t2 = exp.e2.type.toBasetype();
- if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
+ if ((t1.isStaticOrDynamicArray() || t1.ty == Tpointer) && (t2.isStaticOrDynamicArray() || t2.ty == Tpointer))
{
Type t1next = t1.nextOf();
Type t2next = t2.nextOf();
@@ -13416,8 +13053,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
- if ((t1.ty == Tarray || t1.ty == Tsarray) &&
- (t2.ty == Tarray || t2.ty == Tsarray))
+ if (t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray())
{
if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
return setError();
@@ -13438,19 +13074,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
arrayLowering = al;
}
}
- else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
+ else if (t1.isTypeClass() && t2.isTypeClass())
{
- if (t2.ty == Tstruct)
- error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
- else
- error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
+ error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
return setError();
}
- else if (t1.iscomplex() || t2.iscomplex())
+ else if (t1.isComplex() || t2.isComplex())
{
error(exp.loc, "compare not defined for complex operands");
return setError();
}
+ else if (t1.isTypeFunction() || t2.isTypeFunction())
+ {
+ error(exp.loc, "comparison is not defined for function types");
+ return setError();
+ }
else if (t1.ty == Taarray || t2.ty == Taarray)
{
error(exp.loc, "`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
@@ -13486,19 +13124,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(InExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
-
- if (Expression ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression e = exp.op_overload(sc);
- if (e)
+ if (Expression e = exp.opOverloadBinary(sc, aliasThisStop))
{
result = e;
return;
@@ -13518,7 +13144,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
}
- semanticTypeInfo(sc, ta.index);
+ // 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();
@@ -13529,15 +13158,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
case Tarray, Tsarray:
- result = exp.incompatibleTypes();
+ result = exp.incompatibleTypes(sc);
errorSupplemental(exp.loc, "`in` is only allowed on associative arrays");
const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
errorSupplemental(exp.loc, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
- exp.e1.toChars(), exp.e2.toChars(), slice);
+ exp.e1.toErrMsg(), exp.e2.toErrMsg(), slice);
return;
default:
- result = exp.incompatibleTypes();
+ result = exp.incompatibleTypes(sc);
return;
}
result = exp;
@@ -13556,11 +13185,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(EqualExp exp)
{
//printf("EqualExp::semantic('%s')\n", exp.toChars());
- if (exp.type)
- {
- result = exp;
- return;
- }
exp.setNoderefOperands();
@@ -13667,15 +13291,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return false;
}
- if (auto e = exp.op_overload(sc))
+ if (auto e = exp.opOverloadEqual(sc, aliasThisStop))
{
result = e;
return;
}
-
- const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
- (t2.ty == Tarray || t2.ty == Tsarray);
+ const isArrayComparison = t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray();
const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
if (!needsArrayLowering)
@@ -13695,11 +13317,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (f1 || f2)
return setError();
- exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
+ exp.type = (sc && sc.inCfile) ? Type.tint32 : Type.tbool;
if (!isArrayComparison)
{
- if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
+ if (exp.e1.type != exp.e2.type && exp.e1.type.isFloating() && exp.e2.type.isFloating())
{
// Cast both to complex
exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
@@ -13762,8 +13384,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
if (exp.e1.type.toBasetype().ty == Taarray)
+ {
semanticTypeInfo(sc, exp.e1.type.toBasetype());
-
+ }
if (!target.isVectorOpSupported(t1, exp.op, t2))
{
@@ -13771,6 +13394,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
+ if (t1.isTypeFunction() || t2.isTypeFunction())
+ {
+ error(exp.loc, "operator `==` is not defined for function types");
+ return setError();
+ }
+
if (auto tv = t1.isTypeVector())
exp.type = tv.toBooleanVector();
@@ -13779,11 +13408,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
override void visit(IdentityExp exp)
{
- if (exp.type)
- {
- result = exp;
- return;
- }
exp.setNoderefOperands();
@@ -13812,7 +13436,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.type = Type.tbool;
- if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
+ if (exp.e1.type != exp.e2.type && exp.e1.type.isFloating() && exp.e2.type.isFloating())
{
// Cast both to complex
exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
@@ -13832,6 +13456,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.e2.op == EXP.call)
exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
+ if (exp.e1.type.isTypeFunction() || exp.e2.type.isTypeFunction())
+ {
+ error(exp.loc, "operator `is` is not defined for function types");
+ return setError();
+ }
+
if (exp.e1.type.toBasetype().ty == Tsarray ||
exp.e2.type.toBasetype().ty == Tsarray)
deprecation(exp.loc, "identity comparison of static arrays "
@@ -13847,11 +13477,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
printf("CondExp::semantic('%s')\n", exp.toChars());
}
- if (exp.type)
- {
- result = exp;
- return;
- }
if (auto die = exp.econd.isDotIdExp())
die.noderef = true;
@@ -13911,7 +13536,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// https://issues.dlang.org/show_bug.cgi?id=23767
// `cast(void*) 0` should be treated as `null` so the ternary expression
// gets the pointer type of the other branch
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
static void rewriteCNull(ref Expression e, ref Type t)
{
@@ -14143,7 +13768,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression trySemantic(Expression exp, Scope* sc)
{
//printf("+trySemantic(%s)\n", exp.toChars());
- uint errors = global.startGagging();
+ const errors = global.startGagging();
Expression e = expressionSemantic(exp, sc);
if (global.endGagging(errors))
{
@@ -14153,6 +13778,32 @@ Expression trySemantic(Expression exp, Scope* sc)
return e;
}
+/**********************************
+ * Try expression semantic on `exp`, gagging semantic errors,
+ * but don't resolve alias this on a BinExp when the lhs or rhs
+ * has the corresponding type in `aliasThisStop` (See `isRecursiveAliasThis`).
+ *
+ * Params:
+ * exp = expression to try semantic on
+ * sc = scope
+ * aliasThisStop = pair of recursive alias this types to stop endless recursion
+ * Returns:
+ * exp after expression semantic, or `null` on error
+ */
+Expression trySemanticAliasThis(Expression exp, Scope* sc, Type[2] aliasThisStop)
+{
+ if (exp.expressionSemanticDone)
+ return exp;
+
+ const errors = global.startGagging();
+ Expression e = expressionSemantic(exp, sc, aliasThisStop);
+
+ if (global.endGagging(errors))
+ return null;
+
+ return e;
+}
+
/**************************
* Helper function for easy error propagation.
* If error occurs, returns ErrorExp. Otherwise returns NULL.
@@ -14213,26 +13864,68 @@ Expression binSemanticProp(BinExp e, Scope* sc)
return null;
}
+/// Returns: whether expressionSemantic() has been run on expression `e`
+private bool expressionSemanticDone(Expression e)
+{
+ // Usually, Expression.type gets set by expressionSemantic and is `null` beforehand
+ // There are some exceptions however:
+ return e.type !is null && !(
+ e.isRealExp() // type sometimes gets set already before semantic
+ || 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
+ );
+}
+
// entrypoint for semantic ExpressionSemanticVisitor
Expression expressionSemantic(Expression e, Scope* sc)
{
+ if (e.expressionSemanticDone)
+ return e;
+
scope v = new ExpressionSemanticVisitor(sc);
e.accept(v);
return v.result;
}
+// ditto, but passes alias this stop types, see trySemanticAliasThis
+private Expression expressionSemantic(Expression e, Scope* sc, Type[2] aliasThisStop)
+{
+ if (e.expressionSemanticDone)
+ return e;
+
+ scope v = new ExpressionSemanticVisitor(sc);
+ v.aliasThisStop = aliasThisStop;
+ e.accept(v);
+ return v.result;
+}
+
+// ditto, but with `parent` parameter that represents the expression before rewriting.
+// This way, when lowering an expression (e.g. i++ to i+=1), error messages can still
+// refer to the original expression.
+private Expression expressionSemanticWithParent(Expression e, Scope* sc, Expression parent)
+{
+ if (e.expressionSemanticDone)
+ return e;
+
+ scope v = new ExpressionSemanticVisitor(sc);
+ v.parent = parent;
+ e.accept(v);
+ return v.result;
+}
+
private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
{
- //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
+ //printf("dotIdSemanticPropX() %s\n", toChars(exp));
if (Expression ex = unaSemantic(exp, sc))
return ex;
- if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
+ if (!sc.inCfile && exp.ident == Id._mangleof)
{
// symbol.mangleof
// return mangleof as an Expression
- static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds, bool hasOverloads)
+ static Expression dotMangleof(Loc loc, Scope* sc, Dsymbol ds, bool hasOverloads)
{
Expression e;
@@ -14301,14 +13994,16 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
if (auto te = exp.e1.isTupleExp())
{
- if (exp.ident == Id.offsetof)
+ if (exp.ident == Id.offsetof ||
+ exp.ident == Id.bitoffsetof ||
+ exp.ident == Id.bitwidth)
{
/* 'distribute' the .offsetof to each of the tuple elements.
*/
auto exps = new Expressions(te.exps.length);
foreach (i, e; (*te.exps)[])
{
- (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
+ (*exps)[i] = new DotIdExp(e.loc, e, exp.ident);
}
// Don't evaluate te.e0 in runtime
Expression e = new TupleExp(exp.loc, null, exps);
@@ -14326,26 +14021,18 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
// Template has no built-in properties except for 'stringof'.
if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
{
- error(exp.loc, "template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
+ error(exp.loc, "template `%s` does not have property `%s`", exp.e1.toErrMsg(), exp.ident.toChars());
return ErrorExp.get();
}
if (!exp.e1.type)
{
- error(exp.loc, "expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
+ error(exp.loc, "expression `%s` does not have property `%s`", exp.e1.toErrMsg(), exp.ident.toChars());
return ErrorExp.get();
}
return exp;
}
-private bool checkDisabled(Dsymbol s, ref Loc loc, Scope* sc)
-{
- if (auto d = s.isDeclaration())
- return d.checkDisabled(loc, sc);
-
- return false;
-}
-
/******************************
* Resolve properties, i.e. `e1.ident`, without seeing UFCS.
* Params:
@@ -14357,11 +14044,11 @@ private bool checkDisabled(Dsymbol s, ref Loc loc, Scope* sc)
*/
Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
{
- //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
+ //printf("dotIdSemanticProp('%s')\n", exp.toChars());
//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
- const cfile = (sc.flags & SCOPE.Cfile) != 0;
+ const cfile = sc.inCfile;
/* Special case: rewrite this.id and super.id
* to be classtype.id and baseclasstype.id
@@ -14416,13 +14103,13 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
*/
if (ie.sds.isModule() && ie.sds != sc._module)
flags |= SearchOpt.ignorePrivateImports;
- if (sc.flags & SCOPE.ignoresymbolvisibility)
+ if (sc.ignoresymbolvisibility)
flags |= SearchOpt.ignoreVisibility;
Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
/* Check for visibility before resolving aliases because public
* aliases to private symbols are public.
*/
- if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
+ if (s && !sc.ignoresymbolvisibility && !symbolIsVisible(sc._module, s))
{
s = null;
}
@@ -14440,7 +14127,8 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
s = s.toAlias();
s.checkDeprecated(exp.loc, sc);
- s.checkDisabled(exp.loc, sc);
+ if (auto d = s.isDeclaration())
+ d.checkDisabled(exp.loc, sc);
if (auto em = s.isEnumMember())
{
@@ -14631,6 +14319,8 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
!cfile &&
(exp.ident == Id._mangleof ||
exp.ident == Id.offsetof ||
+ exp.ident == Id.bitoffsetof ||
+ exp.ident == Id.bitwidth ||
exp.ident == Id._init ||
exp.ident == Id.stringof)
))
@@ -14692,7 +14382,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
- Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
+ Expression e = dotExp(exp.e1.type, sc, exp.e1, exp.ident, flag);
if (e)
{
e = e.expressionSemantic(sc);
@@ -14735,11 +14425,18 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool g
auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
Expression e = die.dotIdSemanticPropX(sc);
+
+ Expression notTemplate()
+ {
+ error(exp.loc, "`%s` isn't a template", e.toErrMsg());
+ return errorExp();
+ }
+
if (e == die)
{
exp.e1 = die.e1; // take back
Type t1b = exp.e1.type.toBasetype();
- if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
+ if (t1b.isStaticOrDynamicArray() || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
{
/* No built-in type has templatized properties, so do shortcut.
* It is necessary in: 1024.max!"a < b"
@@ -14779,7 +14476,7 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool g
exp.e1 = dve.e1; // pull semantic() result
if (!exp.findTempDecl(sc))
- goto Lerr;
+ return notTemplate();
if (exp.ti.needsTypeInference(sc))
return exp;
exp.ti.dsymbolSemantic(sc);
@@ -14875,9 +14572,7 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool g
.expressionSemantic(sc);
}
-Lerr:
- error(exp.loc, "`%s` isn't a template", e.toChars());
- return errorExp();
+ return notTemplate();
}
MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
@@ -14997,14 +14692,14 @@ MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink
convertMatch = true;
auto tfy = new TypeFunction(tfx.parameterList, tof.next,
- tfx.linkage, STC.undefined_);
+ tfx.linkage, STC.none);
tfy.mod = tfx.mod;
tfy.trust = tfx.trust;
- tfy.isnothrow = tfx.isnothrow;
- tfy.isnogc = tfx.isnogc;
+ tfy.isNothrow = tfx.isNothrow;
+ tfy.isNogc = tfx.isNogc;
tfy.purity = tfx.purity;
- tfy.isproperty = tfx.isproperty;
- tfy.isref = tfx.isref;
+ tfy.isProperty = tfx.isProperty;
+ tfy.isRef = tfx.isRef;
tfy.isInOutParam = tfx.isInOutParam;
tfy.isInOutQual = tfx.isInOutQual;
tfy.deco = tfy.merge().deco;
@@ -15048,11 +14743,115 @@ MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink
{
auto ts = toAutoQualChars(tx, to);
eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
- funcExp.toChars(), ts[0], ts[1]);
+ funcExp.toErrMsg(), ts[0], ts[1]);
}
return m;
}
+private bool checkScalar(Expression e)
+{
+ if (e.op == EXP.error)
+ return true;
+ if (e.type.toBasetype().ty == Terror)
+ return true;
+ if (!e.type.isScalar())
+ {
+ error(e.loc, "`%s` is not a scalar, it is a `%s`", e.toErrMsg(), e.type.toChars());
+ return true;
+ }
+ return e.checkValue();
+}
+
+private bool checkNoBool(Expression e)
+{
+ if (e.op == EXP.error)
+ return true;
+ if (e.type.toBasetype().ty == Terror)
+ return true;
+ if (e.type.toBasetype().ty == Tbool)
+ {
+ error(e.loc, "operation not allowed on `bool` `%s`", e.toErrMsg());
+ return true;
+ }
+ return false;
+}
+
+private bool checkIntegral(Expression e)
+{
+ if (e.op == EXP.error)
+ return true;
+ if (e.type.toBasetype().ty == Terror)
+ return true;
+ if (!e.type.isIntegral())
+ {
+ error(e.loc, "`%s` is not of integral type, it is a `%s`", e.toErrMsg(), e.type.toChars());
+ return true;
+ }
+ return e.checkValue();
+}
+
+private bool checkArithmetic(Expression e, EXP op)
+{
+ if (op == EXP.error)
+ return true;
+ if (e.type.toBasetype().ty == Terror)
+ return true;
+ if (!e.type.isIntegral() && !e.type.isFloating())
+ {
+ // unary aggregate ops error here
+ const char* msg = e.type.isAggregate() ?
+ "operator `%s` is not defined for `%s` of type `%s`" :
+ "illegal operator `%s` for `%s` of type `%s`";
+ error(e.loc, msg, EXPtoString(op).ptr, e.toErrMsg(), e.type.toChars());
+ return true;
+ }
+
+ if ((op == EXP.add || op == EXP.min) && e.isTypeExp())
+ {
+ // @@@DEPRECATED_2.121@@@
+ // Deprecated in 2.111
+ // In 2.121, remove this branch to let `checkValue` raise the error
+ deprecation(e.loc, "type `%s` has no value", e.toChars);
+ if (!e.type.isOpaqueType)
+ deprecationSupplemental(e.loc, "perhaps use `%s.init`", e.toChars);
+ return false;
+ }
+
+ return e.checkValue();
+}
+
+/*******************************
+ * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
+ * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
+ * Returns true if error occurs.
+ */
+private bool checkReadModifyWrite(Expression e, EXP rmwOp, Expression ex = null)
+{
+ //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
+ if (!e.type || !e.type.isShared() || e.type.isTypeStruct() || e.type.isTypeClass())
+ return false;
+
+ // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
+ switch (rmwOp)
+ {
+ case EXP.plusPlus:
+ case EXP.prePlusPlus:
+ rmwOp = EXP.addAssign;
+ break;
+ case EXP.minusMinus:
+ case EXP.preMinusMinus:
+ rmwOp = EXP.minAssign;
+ break;
+ default:
+ break;
+ }
+
+ error(e.loc, "read-modify-write operations are not allowed for `shared` variables");
+ errorSupplemental(e.loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
+ EXPtoString(rmwOp).ptr, e.toChars(), ex ? ex.toChars() : "1");
+ return true;
+}
+
private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
{
const r1 = binExp.e1.checkSharedAccess(sc);
@@ -15060,6 +14859,89 @@ private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
return (r1 || r2);
}
+private bool checkIntegralBin(BinExp e)
+{
+ bool r1 = e.e1.checkIntegral();
+ bool r2 = e.e2.checkIntegral();
+ return (r1 || r2);
+}
+
+private bool checkArithmeticBin(BinExp e)
+{
+ return (e.e1.checkArithmetic(e.op) || e.e2.checkArithmetic(e.op));
+}
+
+/****************************************
+ * Check that the expression has a valid value.
+ * If not, generates an error "... has no value".`
+ *
+ * Params:
+ * e = expression to check
+ *
+ * Returns:
+ * `true` if the expression is not valid or has `void` type.
+ */
+bool checkValue(Expression e)
+{
+ if (auto te = e.isTypeExp())
+ {
+ error(e.loc, "type `%s` has no value", e.toErrMsg());
+ if (!e.type.isOpaqueType)
+ errorSupplemental(e.loc, "perhaps use `%s.init`", e.toChars());
+ return true;
+ }
+
+ if (auto dtie = e.isDotTemplateInstanceExp())
+ {
+ if (dtie.ti.tempdecl &&
+ dtie.ti.semantictiargsdone &&
+ dtie.ti.semanticRun == PASS.initial)
+
+ error(e.loc, "partial %s `%s` has no value", dtie.ti.kind(), e.toErrMsg());
+ else
+ error(e.loc, "%s `%s` has no value", dtie.ti.kind(), dtie.ti.toChars());
+ return true;
+ }
+
+ if (auto se = e.isScopeExp())
+ {
+ error(e.loc, "%s `%s` has no value", se.sds.kind(), se.sds.toChars());
+ return true;
+ }
+
+ if (auto te = e.isTemplateExp())
+ {
+ error(e.loc, "%s `%s` has no value", te.td.kind(), te.toChars());
+ return true;
+ }
+
+ if (auto fe = e.isFuncExp())
+ {
+ if (fe.td)
+ {
+ error(e.loc, "template lambda has no value");
+ return true;
+ }
+ return false;
+ }
+
+ if (auto dte = e.isDotTemplateExp())
+ {
+ error(e.loc, "%s `%s` has no value", dte.td.kind(), e.toErrMsg());
+ return true;
+ }
+
+ if (e.type && e.type.toBasetype().ty == Tvoid)
+ {
+ error(e.loc, "expression `%s` is `void` and has no value", e.toErrMsg());
+ //print(); assert(0);
+ if (!global.gag)
+ e.type = Type.terror;
+ return true;
+ }
+ return false;
+}
+
/***************************************
* If expression is shared, check that we can access it.
* Give error message if not.
@@ -15075,13 +14957,34 @@ private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
*/
bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
{
- if (global.params.noSharedAccess != FeatureState.enabled ||
- !sc ||
+ if (!sc ||
+ !sc.previews.noSharedAccess ||
sc.intypeof ||
- sc.flags & SCOPE.ctfe)
+ sc.ctfe)
{
return false;
}
+ else if (sc._module.ident == Id.atomic && sc._module.parent !is null)
+ {
+ // Allow core.internal.atomic, it is an compiler implementation for a given platform module.
+ // It is then exposed by other modules such as core.atomic and core.stdc.atomic.
+ // This is available as long as druntime is on the import path and the platform supports that operation.
+
+ // https://issues.dlang.org/show_bug.cgi?id=24846
+
+ Package parent = sc._module.parent.isPackage();
+ if (parent !is null)
+ {
+ // This can be easily converted over to apply to core.atomic and core.internal.atomic
+ if (parent.ident == Id.internal)
+ {
+ parent = parent.parent.isPackage();
+
+ if (parent !is null && parent.ident == Id.core && parent.parent is null)
+ return false;
+ }
+ }
+ }
//printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
@@ -15090,7 +14993,7 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
bool sharedError(Expression e)
{
// https://dlang.org/phobos/core_atomic.html
- error(e.loc, "direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
+ error(e.loc, "direct access to shared `%s` is not allowed, see `core.atomic`", e.toErrMsg());
return true;
}
@@ -15106,6 +15009,8 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
bool visitNew(NewExp e)
{
+ if (e.placement)
+ check(e.placement, false);
if (e.thisexp)
check(e.thisexp, false);
return false;
@@ -15126,10 +15031,8 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
{
if (e.var.isThisDeclaration())
return false;
- else
- return sharedError(e);
}
- else if (!allowRef && e.var.type.isShared())
+ if (!allowRef && e.var.type.isShared())
return sharedError(e);
return false;
@@ -15233,7 +15136,7 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
/****************************************
* Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
*/
-Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
+Expression resolveLoc(Expression exp, Loc loc, Scope* sc)
{
// Don't replace the special keywords, while we are inside a default
// argument. They are replaced later when copied to the call site.
@@ -15277,6 +15180,9 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
Expression visitStructLiteral(StructLiteralExp exp)
{
+ if (!exp.elements)
+ return exp;
+
foreach (ref element; *exp.elements)
{
if (element)
@@ -15288,6 +15194,8 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
Expression visitNew(NewExp exp)
{
+ if (exp.placement)
+ exp.placement = exp.placement.resolveLoc(loc, sc);
if (exp.thisexp)
exp.thisexp = exp.thisexp.resolveLoc(loc, sc);
if (exp.argprefix)
@@ -15295,6 +15203,9 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
if (exp.lowering)
exp.lowering = exp.lowering.resolveLoc(loc, sc);
+ if (!exp.arguments)
+ return exp;
+
foreach (ref element; *exp.arguments)
{
if (element)
@@ -15306,6 +15217,9 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
Expression visitCall(CallExp exp)
{
+ if (!exp.arguments)
+ return exp;
+
foreach (ref element; *exp.arguments)
{
if (element)
@@ -15319,6 +15233,9 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
{
exp.e1 = exp.e1.resolveLoc(loc, sc);
+ if (!exp.arguments)
+ return exp;
+
foreach (ref element; *exp.arguments)
{
if (element)
@@ -15331,8 +15248,10 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
Expression visitSlice(SliceExp exp)
{
exp.e1 = exp.e1.resolveLoc(loc, sc);
- exp.lwr = exp.lwr.resolveLoc(loc, sc);
- exp.upr = exp.upr.resolveLoc(loc, sc);
+ if (exp.lwr)
+ exp.lwr = exp.lwr.resolveLoc(loc, sc);
+ if (exp.upr)
+ exp.upr = exp.upr.resolveLoc(loc, sc);
return exp;
}
@@ -15350,6 +15269,9 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
if (exp.basis)
exp.basis = exp.basis.resolveLoc(loc, sc);
+ if (!exp.elements)
+ return exp;
+
foreach (ref element; *exp.elements)
{
if (element)
@@ -15469,6 +15391,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
*/
Expression addDtorHook(Expression e, Scope* sc)
{
+ //printf("addDtorHook() %s\n", toChars(e));
Expression visit(Expression exp)
{
return exp;
@@ -15494,7 +15417,7 @@ Expression addDtorHook(Expression e, Scope* sc)
buf[0 .. prefix.length] = prefix;
buf[prefix.length .. len] = ident[0 .. len - prefix.length];
- auto tmp = copyToTemp(0, buf[0 .. len], exp);
+ auto tmp = copyToTemp(STC.none, buf[0 .. len], exp);
Expression ae = new DeclarationExp(exp.loc, tmp);
Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp));
e = e.expressionSemantic(sc);
@@ -15514,7 +15437,7 @@ Expression addDtorHook(Expression e, Scope* sc)
if (auto tf = e1.type.isTypeFunction())
{
- if (tf.isref)
+ if (tf.isRef)
return exp;
}
@@ -15527,7 +15450,7 @@ Expression addDtorHook(Expression e, Scope* sc)
/* Type needs destruction, so declare a tmp
* which the back end will recognize and call dtor on
*/
- auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp);
+ auto tmp = copyToTemp(STC.none, Id.__tmpfordtor.toString(), exp);
auto de = new DeclarationExp(exp.loc, tmp);
auto ve = new VarExp(exp.loc, tmp);
Expression e = new CommaExp(exp.loc, de, ve);
@@ -15598,9 +15521,9 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
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.toChars());
+ error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toErrMsg());
else
- error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars());
+ error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toErrMsg());
return ErrorExp.get();
}
@@ -15609,7 +15532,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
{
if (!_this.loc.isValid())
_this.loc = e.loc;
- error(e.loc, "cannot %s constant `%s`", action, e.toChars());
+ error(e.loc, "cannot %s constant `%s`", action, e.toErrMsg());
return ErrorExp.get();
}
@@ -15632,7 +15555,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
Expression visitStructLiteral(StructLiteralExp _this)
{
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
return _this; // C struct literals are lvalues
else
return visit(_this);
@@ -15679,7 +15602,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
auto e1 = _this.e1;
auto var = _this.var;
//printf("DotVarExp::toLvalue(%s)\n", toChars());
- if (sc && sc.flags & SCOPE.Cfile)
+ 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.
@@ -15725,14 +15648,22 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
Expression visitCast(CastExp _this)
{
- if (sc && sc.flags & SCOPE.Cfile)
+ if (sc && sc.inCfile)
{
/* C11 6.5.4-5: A cast does not yield an lvalue.
*/
return visit(_this);
}
if (_this.isLvalue())
+ {
+ with (_this)
+ if (!trusted && !e1.type.pointerTo().implicitConvTo(to.pointerTo()))
+ sc.setUnsafePreview(FeatureState.default_, false, loc,
+ "using the result of a cast from `%s` to `%s` as an lvalue",
+ e1.type, to);
+
return _this;
+ }
return visit(_this);
}
@@ -16026,12 +15957,12 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
break;
if (!ff.type.isMutable)
{
- error(exp.loc, "cannot modify `%s` in `%s` function", exp.toChars(), MODtoChars(type.mod));
+ error(exp.loc, "cannot modify `%s` in `%s` function", exp.toErrMsg(), MODtoChars(type.mod));
return ErrorExp.get();
}
}
}
- error(exp.loc, "cannot modify `%s` expression `%s`", MODtoChars(type.mod), exp.toChars());
+ error(exp.loc, "cannot modify `%s` expression `%s`", MODtoChars(type.mod), exp.toErrMsg());
return ErrorExp.get();
}
else if (!type.isAssignable())
@@ -16046,7 +15977,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
Expression visitString(StringExp exp)
{
- error(exp.loc, "cannot modify string literal `%s`", exp.toChars());
+ error(exp.loc, "cannot modify string literal `%s`", exp.toErrMsg());
return ErrorExp.get();
}
@@ -16055,7 +15986,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
//printf("VarExp::modifiableLvalue('%s')\n", exp.var.toChars());
if (exp.var.storage_class & STC.manifest)
{
- error(exp.loc, "cannot modify manifest constant `%s`", exp.toChars());
+ error(exp.loc, "cannot modify manifest constant `%s`", exp.toErrMsg());
return ErrorExp.get();
}
// See if this expression is a modifiable lvalue (i.e. not const)
@@ -16084,7 +16015,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
Expression visitSlice(SliceExp exp)
{
- error(exp.loc, "slice expression `%s` is not a modifiable lvalue", exp.toChars());
+ error(exp.loc, "slice expression `%s` is not a modifiable lvalue", exp.toErrMsg());
return exp;
}
@@ -16096,7 +16027,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
Expression visitDelegatePtr(DelegatePtrExp exp)
{
- if (sc.setUnsafe(false, exp.loc, "cannot modify delegate pointer in `@safe` code `%s`", exp))
+ if (sc.setUnsafe(false, exp.loc, "modifying delegate pointer `%s`", exp))
{
return ErrorExp.get();
}
@@ -16105,7 +16036,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
Expression visitDelegateFuncptr(DelegateFuncptrExp exp)
{
- if (sc.setUnsafe(false, exp.loc, "cannot modify delegate function pointer in `@safe` code `%s`", exp))
+ if (sc.setUnsafe(false, exp.loc, "modifying delegate function pointer `%s`", exp))
{
return ErrorExp.get();
}
@@ -16126,7 +16057,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
{
if (!exp.e1.isLvalue() && !exp.e2.isLvalue())
{
- error(exp.loc, "conditional expression `%s` is not a modifiable lvalue", exp.toChars());
+ error(exp.loc, "conditional expression `%s` is not a modifiable lvalue", exp.toErrMsg());
return ErrorExp.get();
}
exp.e1 = exp.e1.modifiableLvalue(sc);
@@ -16159,7 +16090,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
* Returns:
* `true` if ok, `false` for error
*/
-bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
+private bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
{
//printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
if (v is null)
@@ -16167,14 +16098,14 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
if (!v.canTakeAddressOf())
{
- error(exp.loc, "cannot take address of `%s`", exp.toChars());
+ error(exp.loc, "cannot take address of `%s`", exp.toErrMsg());
return false;
}
if (sc.func && !sc.intypeof && !v.isDataseg())
{
if (sc.useDIP1000 != FeatureState.enabled &&
!(v.storage_class & STC.temp) &&
- sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
+ sc.setUnsafe(false, exp.loc, "taking the address of stack-allocated local variable `%s`", v))
{
return false;
}
@@ -16220,7 +16151,7 @@ bool checkAddressable(Expression e, Scope* sc)
continue;
case EXP.variable:
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
// C11 6.5.3.2: A variable that has its address taken cannot be
// stored in a register.
@@ -16229,9 +16160,9 @@ bool checkAddressable(Expression e, Scope* sc)
if (ex.isVarExp().var.storage_class & STC.register)
{
if (e.isIndexExp())
- error(e.loc, "cannot index through register variable `%s`", ex.toChars());
+ error(e.loc, "cannot index through register variable `%s`", ex.toErrMsg());
else
- error(e.loc, "cannot take address of register variable `%s`", ex.toChars());
+ error(e.loc, "cannot take address of register variable `%s`", ex.toErrMsg());
return false;
}
}
@@ -16282,7 +16213,7 @@ private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration
* Returns:
* Expression representing the `this` for the var
*/
-Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
+Expression getThisSkipNestedFuncs(Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
{
int n = 0;
while (s && s.isFuncDeclaration())
@@ -16343,7 +16274,7 @@ Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, Aggre
* newly created variable such that a closure is made for the variable when
* the address of `fd` is taken.
*/
-VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
+private VarDeclaration makeThis2Argument(Loc loc, Scope* sc, FuncDeclaration fd)
{
Type tthis2 = Type.tvoidptr.sarrayOf(2);
VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
@@ -16369,7 +16300,7 @@ VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration f
* Returns:
* a `bool` indicating if the hook is present.
*/
-bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
+bool verifyHookExist(Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
{
Dsymbol pscopesym;
auto rootSymbol = sc.search(loc, Id.empty, pscopesym);
@@ -16393,7 +16324,7 @@ bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string desc
* false if any errors occur,
* otherwise true and elements[] are rewritten for the output.
*/
-private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
+private bool fit(StructDeclaration sd, Loc loc, Scope* sc, Expressions* elements, Type stype)
{
if (!elements)
return true;
@@ -16447,7 +16378,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
(v.offset & (target.ptrsize - 1))) &&
(sc.setUnsafe(false, loc,
- "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
+ "field `%s.%s` assigning to misaligned pointers", sd, v)))
{
return false;
}
@@ -16465,7 +16396,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
Type typeb = se.type.toBasetype();
TY tynto = tb.nextOf().ty;
if (!se.committed &&
- (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
+ typeb.isStaticOrDynamicArray() && tynto.isSomeChar &&
se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
{
e = se.castTo(sc, t);
@@ -16489,7 +16420,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
if (e.op == EXP.error)
return false;
- (*elements)[i] = doCopyOrMove(sc, e);
+ (*elements)[i] = doCopyOrMove(sc, e, null, false);
}
return true;
}
@@ -16504,7 +16435,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
* Returns:
* VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
*/
-Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
+Expression getVarExp(EnumMember em, Loc loc, Scope* sc)
{
dsymbolSemantic(em, sc);
if (em.errors)
@@ -16522,7 +16453,7 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
return ErrorExp.get();
Expression e = new VarExp(loc, em);
e = e.expressionSemantic(sc);
- if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
+ if (!sc.inCfile && em.isCsymbol())
{
/* C11 types them as int. But if in D file,
* type qualified names as the enum
@@ -16563,7 +16494,7 @@ Expression toBoolean(Expression exp, Scope* sc)
case EXP.construct:
case EXP.blit:
case EXP.loweredAssignExp:
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
return exp;
// Things like:
// if (a = b) ...
@@ -16610,7 +16541,7 @@ Expression toBoolean(Expression exp, Scope* sc)
/* Don't really need to check for opCast first, but by doing so we
* get better error messages if it isn't there.
*/
- if (Dsymbol fd = search_function(ad, Id._cast))
+ if (Dsymbol fd = search_function(ad, Id.opCast))
{
e = new CastExp(exp.loc, e, Type.tbool);
e = e.expressionSemantic(sc);
@@ -16702,7 +16633,7 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
const uint nerrors = global.errors;
sc = sc.startCTFE();
- sc.flags |= SCOPE.condition;
+ sc.condition = true;
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
@@ -16725,7 +16656,7 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
if (opt.isEmpty())
{
if (!e.type.isTypeError())
- error(e.loc, "expression `%s` is not constant", e.toChars());
+ error(e.loc, "expression `%s` is not constant", e.toErrMsg());
errors = true;
return false;
}
@@ -16736,3 +16667,1007 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
}
return impl(e);
}
+
+/************************************
+ * Check to see the aggregate type is nested and its context pointer is
+ * accessible from the current scope.
+ * Returns true if error occurs.
+ */
+bool checkFrameAccess(Loc loc, Scope* sc, AggregateDeclaration ad, size_t iStart = 0)
+{
+ Dsymbol sparent = ad.toParentLocal();
+ Dsymbol sparent2 = ad.toParent2();
+ Dsymbol s = sc.func;
+ if (ad.isNested() && s)
+ {
+ //printf("ad = %p %s [%s], parent:%p\n", ad, ad.toChars(), ad.loc.toChars(), ad.parent);
+ //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent.toChars(), sparent.loc.toChars(), sparent.parent,toChars());
+ //printf("sparent2 = %p %s [%s], parent: %s\n", sparent2, sparent2.toChars(), sparent2.loc.toChars(), sparent2.parent,toChars());
+ if (!ensureStaticLinkTo(s, sparent) || sparent != sparent2 && !ensureStaticLinkTo(s, sparent2))
+ {
+ error(loc, "cannot access frame pointer of `%s`", ad.toPrettyChars());
+ return true;
+ }
+ }
+
+ bool result = false;
+ for (size_t i = iStart; i < ad.fields.length; i++)
+ {
+ VarDeclaration vd = ad.fields[i];
+ Type tb = vd.type.baseElemOf();
+ if (tb.ty == Tstruct)
+ {
+ result |= checkFrameAccess(loc, sc, (cast(TypeStruct)tb).sym);
+ }
+ }
+ return result;
+}
+
+/// Return value for `checkModifiable`
+enum Modifiable
+{
+ /// Not modifiable
+ no,
+ /// Modifiable (the type is mutable)
+ yes,
+ /// Modifiable because it is initialization
+ initialization,
+}
+
+/**
+ * Specifies how the checkModify deals with certain situations
+ */
+enum ModifyFlags
+{
+ /// Issue error messages on invalid modifications of the variable
+ none,
+ /// No errors are emitted for invalid modifications
+ noError = 0x1,
+ /// The modification occurs for a subfield of the current variable
+ fieldAssign = 0x2,
+}
+
+/*************************************
+ * Check to see if declaration can be modified in this context (sc).
+ * Issue error if not.
+ * Params:
+ * loc = location for error messages
+ * e1 = `null` or `this` expression when this declaration is a field
+ * sc = context
+ * flag = if the first bit is set it means do not issue error message for
+ * invalid modification; if the second bit is set, it means that
+ this declaration is a field and a subfield of it is modified.
+ * Returns:
+ * Modifiable.yes or Modifiable.initialization
+ */
+private Modifiable checkModify(Declaration d, Loc loc, Scope* sc, Expression e1, ModifyFlags flag)
+{
+ VarDeclaration v = d.isVarDeclaration();
+ if (v && v.canassign)
+ return Modifiable.initialization;
+
+ if (d.isParameter() || d.isResult())
+ {
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (scx.func == d.parent && scx.contract != Contract.none)
+ {
+ const(char)* s = d.isParameter() && d.parent.ident != Id.ensure ? "parameter" : "result";
+ if (!(flag & ModifyFlags.noError))
+ error(loc, "%s `%s` cannot modify %s `%s` in contract", d.kind, d.toPrettyChars, s, d.toChars());
+ return Modifiable.initialization; // do not report type related errors
+ }
+ }
+ }
+
+ if (e1 && e1.op == EXP.this_ && d.isField())
+ {
+ VarDeclaration vthis = e1.isThisExp().var;
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (scx.func == vthis.parent && scx.contract != Contract.none)
+ {
+ if (!(flag & ModifyFlags.noError))
+ error(loc, "cannot modify member variable `%s` in contract", d.toPrettyChars());
+ return Modifiable.initialization; // do not report type related errors
+ }
+ }
+ }
+
+ if (v && (v.isCtorinit() || d.isField()))
+ {
+ // It's only modifiable if inside the right constructor
+ if ((d.storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_))
+ return Modifiable.initialization;
+ if (flag & ModifyFlags.fieldAssign)
+ return Modifiable.yes;
+ return modifyFieldVar(loc, sc, v, e1) ? Modifiable.initialization : Modifiable.yes;
+ }
+ return Modifiable.yes;
+}
+
+/***********************************************
+ * Mark variable v as modified if it is inside a constructor that var
+ * is a field in.
+ * Also used to allow immutable globals to be initialized inside a static constructor.
+ * Returns:
+ * true if it's an initialization of v
+ */
+private bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
+{
+ //printf("modifyFieldVar(var = %s)\n", var.toChars());
+ Dsymbol s = sc.func;
+ while (1)
+ {
+ FuncDeclaration fd = null;
+ if (s)
+ fd = s.isFuncDeclaration();
+ if (fd &&
+ ((fd.isCtorDeclaration() && var.isField()) ||
+ ((fd.isStaticCtorDeclaration() || fd.isCrtCtor) && !var.isField())) &&
+ fd.toParentDecl() == var.toParent2() &&
+ (!e1 || e1.op == EXP.this_))
+ {
+ bool result = true;
+
+ var.ctorinit = true;
+ //printf("setting ctorinit\n");
+
+ if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof)
+ {
+ assert(e1);
+ auto mustInit = ((var.storage_class & STC.nodefaultctor) != 0 ||
+ var.type.needsNested());
+
+ const dim = sc.ctorflow.fieldinit.length;
+ auto ad = fd.isMemberDecl();
+ assert(ad);
+ size_t i;
+ for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ?
+ {
+ if (ad.fields[i] == var)
+ break;
+ }
+ assert(i < dim);
+ auto fieldInit = &sc.ctorflow.fieldinit[i];
+ const fi = fieldInit.csx;
+
+ if (fi & CSX.this_ctor)
+ {
+ if (var.type.isMutable() && e1.type.isMutable())
+ result = false;
+ else
+ {
+ const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
+ .error(loc, "%s field `%s` initialized multiple times", modStr, var.toChars());
+ .errorSupplemental(fieldInit.loc, "Previous initialization is here.");
+ }
+ }
+ else if (sc.inLoop || (fi & CSX.label))
+ {
+ if (!mustInit && var.type.isMutable() && e1.type.isMutable())
+ result = false;
+ else
+ {
+ const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
+ .error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var.toChars());
+ }
+ }
+
+ fieldInit.csx |= CSX.this_ctor;
+ fieldInit.loc = e1.loc;
+ if (var.overlapped) // https://issues.dlang.org/show_bug.cgi?id=15258
+ {
+ foreach (j, v; ad.fields)
+ {
+ if (v is var || !var.isOverlappedWith(v))
+ continue;
+ v.ctorinit = true;
+ sc.ctorflow.fieldinit[j].csx = CSX.this_ctor;
+ }
+ }
+ }
+ else if (fd != sc.func)
+ {
+ if (var.type.isMutable())
+ result = false;
+ else if (sc.func.fes)
+ {
+ const(char)* p = var.isField() ? "field" : var.kind();
+ .error(loc, "%s %s `%s` initialization is not allowed in foreach loop",
+ MODtoChars(var.type.mod), p, var.toChars());
+ }
+ else
+ {
+ const(char)* p = var.isField() ? "field" : var.kind();
+ .error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`",
+ MODtoChars(var.type.mod), p, var.toChars(), sc.func.toChars());
+ }
+ }
+ else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
+ var.type.isImmutable())
+ {
+ .error(loc, "%s %s `%s` initialization is not allowed in `static this`",
+ MODtoChars(var.type.mod), var.kind(), var.toChars());
+ errorSupplemental(loc, "Use `shared static this` instead.");
+ }
+ else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
+ var.type.isConst())
+ {
+ // @@@DEPRECATED_2.116@@@
+ // Turn this into an error, merging with the branch above
+ .deprecation(loc, "%s %s `%s` initialization is not allowed in `static this`",
+ MODtoChars(var.type.mod), var.kind(), var.toChars());
+ deprecationSupplemental(loc, "Use `shared static this` instead.");
+ }
+ return result;
+ }
+ else
+ {
+ if (s)
+ {
+ s = s.toParentP(var.toParent2());
+ continue;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+/***************************************
+ * Request additional semantic analysis for TypeInfo generation.
+ * Params:
+ * sc = context
+ * t = type that TypeInfo is being generated for
+ */
+void semanticTypeInfo(Scope* sc, Type t)
+{
+ if (sc)
+ {
+ if (sc.intypeof)
+ return;
+ if (!sc.needsCodegen())
+ return;
+ }
+
+ if (!t)
+ return;
+
+ void visitVector(TypeVector t)
+ {
+ semanticTypeInfo(sc, t.basetype);
+ }
+
+ void visitAArray(TypeAArray t)
+ {
+ semanticTypeInfo(sc, t.index);
+ semanticTypeInfo(sc, t.next);
+
+ if (global.params.useTypeInfo)
+ getTypeInfoType(t.loc, t, sc);
+ }
+
+ void visitStruct(TypeStruct t)
+ {
+ //printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars());
+ StructDeclaration sd = t.sym;
+
+ /* Step 1: create TypeInfoDeclaration
+ */
+ if (!sc) // inline may request TypeInfo.
+ {
+ Scope scx;
+ scx.eSink = global.errorSink;
+ scx._module = sd.getModule();
+ if (global.params.useTypeInfo)
+ {
+ getTypeInfoType(sd.loc, t, &scx);
+ sd.requestTypeInfo = true;
+ }
+ }
+ else if (!sc.minst)
+ {
+ // don't yet have to generate TypeInfo instance if
+ // the typeid(T) expression exists in speculative scope.
+ }
+ else
+ {
+ getTypeInfoType(sd.loc, t, sc);
+ sd.requestTypeInfo = true;
+
+ // https://issues.dlang.org/show_bug.cgi?id=15149
+ // if the typeid operand type comes from a
+ // result of auto function, it may be yet speculative.
+ // unSpeculative(sc, sd);
+ }
+
+ /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
+ * This should be done even if typeid(T) exists in speculative scope.
+ * Because it may appear later in non-speculative scope.
+ */
+ if (!sd.members)
+ return; // opaque struct
+ if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.tidtor && !sd.xhash && !search_toString(sd))
+ return; // none of TypeInfo-specific members
+
+ // If the struct is in a non-root module, run semantic3 to get
+ // correct symbols for the member function.
+ if (sd.semanticRun >= PASS.semantic3)
+ {
+ // semantic3 is already done
+ }
+ else if (TemplateInstance ti = sd.isInstantiated())
+ {
+ if (ti.minst && !ti.minst.isRoot())
+ Module.addDeferredSemantic3(sd);
+ }
+ else
+ {
+ if (sd.inNonRoot())
+ {
+ //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot());
+ Module.addDeferredSemantic3(sd);
+ }
+ }
+ }
+
+ void visitTuple(TypeTuple t)
+ {
+ if (t.arguments)
+ {
+ foreach (arg; *t.arguments)
+ {
+ semanticTypeInfo(sc, arg.type);
+ }
+ }
+ }
+
+ /* Note structural similarity of this Type walker to that in isSpeculativeType()
+ */
+
+ Type tb = t.toBasetype();
+ switch (tb.ty)
+ {
+ case Tvector: visitVector(tb.isTypeVector()); break;
+ case Taarray: visitAArray(tb.isTypeAArray()); break;
+ case Tstruct: visitStruct(tb.isTypeStruct()); break;
+ case Ttuple: visitTuple (tb.isTypeTuple()); break;
+
+ case Tclass:
+ case Tenum: break;
+
+ default: semanticTypeInfo(sc, tb.nextOf()); break;
+ }
+}
+
+/**
+ * Issue an error if an attempt to call a disabled method is made
+ *
+ * If the declaration is disabled but inside a disabled function,
+ * returns `true` but do not issue an error message.
+ *
+ * Params:
+ * d = Declaration to check
+ * loc = Location information of the call
+ * sc = Scope in which the call occurs
+ * isAliasedDeclaration = if `true` searches overload set
+ *
+ * Returns:
+ * `true` if this `Declaration` is `@disable`d, `false` otherwise.
+ */
+bool checkDisabled(Declaration d, Loc loc, Scope* sc, bool isAliasedDeclaration = false)
+{
+ if (!(d.storage_class & STC.disable))
+ return false;
+
+ if (sc.func && sc.func.storage_class & STC.disable)
+ return true;
+
+ if (auto p = d.toParent())
+ {
+ if (auto postblit = d.isPostBlitDeclaration())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=21885
+ *
+ * If the generated postblit is disabled, it
+ * means that one of the fields has a disabled
+ * postblit. Print the first field that has
+ * a disabled postblit.
+ */
+ if (postblit.isGenerated())
+ {
+ auto sd = p.isStructDeclaration();
+ assert(sd);
+ for (size_t i = 0; i < sd.fields.length; i++)
+ {
+ auto structField = sd.fields[i];
+ if (structField.overlapped)
+ continue;
+ Type tv = structField.type.baseElemOf();
+ if (tv.ty != Tstruct)
+ continue;
+ auto sdv = (cast(TypeStruct)tv).sym;
+ if (!sdv.postblit)
+ continue;
+ if (sdv.postblit.isDisabled())
+ {
+ .error(loc, "%s `%s` is not copyable because field `%s` is not copyable", p.kind, p.toPrettyChars, structField.toChars());
+ return true;
+ }
+ }
+ }
+ .error(loc, "%s `%s` is not copyable because it has a disabled postblit", p.kind, p.toPrettyChars);
+ return true;
+ }
+ }
+
+ // if the function is @disabled, maybe there
+ // is an overload in the overload set that isn't
+ if (isAliasedDeclaration)
+ {
+ if (FuncDeclaration fd = d.isFuncDeclaration())
+ {
+ for (FuncDeclaration ovl = fd; ovl; ovl = cast(FuncDeclaration)ovl.overnext)
+ if (!(ovl.storage_class & STC.disable))
+ return false;
+ }
+ }
+
+ if (auto ctor = d.isCtorDeclaration())
+ {
+ //printf("checkDisabled() %s %s\n", ctor.toPrettyChars(), toChars(ctor.type));
+ 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;
+ }
+ }
+ .error(loc, "%s `%s` cannot be used because it is annotated with `@disable`", d.kind, d.toPrettyChars);
+ return true;
+}
+
+/*******************************************
+ * Helper function for the expansion of manifest constant.
+ */
+private Expression expandInitializer(VarDeclaration vd, Loc loc)
+{
+ assert((vd.storage_class & STC.manifest) && vd._init);
+
+ auto e = vd.getConstInitializer();
+ if (!e)
+ {
+ .error(loc, "cannot make expression out of initializer for `%s`", vd.toChars());
+ return ErrorExp.get();
+ }
+
+ e = e.copy();
+ e.loc = loc; // for better error message
+ return e;
+}
+
+/*****************************************************
+ * Determine if template instance is really a template function,
+ * and that template function needs to infer types from the function
+ * arguments.
+ *
+ * Like findBestMatch, iterate possible template candidates,
+ * but just looks only the necessity of type inference.
+ */
+private bool needsTypeInference(TemplateInstance ti, Scope* sc, int flag = 0)
+{
+ //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
+ if (ti.semanticRun != PASS.initial)
+ return false;
+
+ const olderrs = global.errors;
+ Objects dedtypes;
+ size_t count = 0;
+
+ 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 any of the overloaded template declarations need inference,
+ * then return true
+ */
+ if (!td.onemember)
+ return 0;
+ if (auto td2 = td.onemember.isTemplateDeclaration())
+ {
+ if (!td2.onemember || !td2.onemember.isFuncDeclaration())
+ return 0;
+ if (ti.tiargs.length >= td.parameters.length - (td.isVariadic() ? 1 : 0))
+ return 0;
+ return 1;
+ }
+ auto fd = td.onemember.isFuncDeclaration();
+ if (!fd || fd.type.ty != Tfunction)
+ return 0;
+
+ foreach (tp; *td.parameters)
+ {
+ if (tp.isTemplateThisParameter())
+ return 1;
+ }
+
+ /* Determine if the instance arguments, tiargs, are all that is necessary
+ * to instantiate the template.
+ */
+ //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
+ auto tf = fd.type.isTypeFunction();
+ if (tf.parameterList.length)
+ {
+ auto tp = td.isVariadic();
+ if (tp && td.parameters.length > 1)
+ return 1;
+
+ if (!tp && ti.tiargs.length < td.parameters.length)
+ {
+ // Can remain tiargs be filled by default arguments?
+ foreach (size_t i; ti.tiargs.length .. td.parameters.length)
+ {
+ if (!(*td.parameters)[i].hasDefaultArg())
+ return 1;
+ }
+ }
+
+ foreach (i, fparam; tf.parameterList)
+ {
+ // 'auto ref' needs inference.
+ if (fparam.storageClass & STC.auto_)
+ return 1;
+ }
+ }
+
+ if (!flag)
+ {
+ /* Calculate the need for overload resolution.
+ * When only one template can match with tiargs, inference is not necessary.
+ */
+ dedtypes.setDim(td.parameters.length);
+ dedtypes.zero();
+ 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(ti.loc, "%s `%s` `%s` forward references template declaration `%s`",
+ ti.kind, ti.toPrettyChars, ti.toChars(), td.toChars());
+ return 1;
+ }
+ }
+ MATCH m = matchWithInstance(sc, td, ti, dedtypes, ArgumentList(), 0);
+ if (m == MATCH.nomatch)
+ return 0;
+ }
+
+ /* If there is more than one function template which matches, we may
+ * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
+ */
+ return ++count > 1 ? 1 : 0;
+ });
+ if (r)
+ return true;
+ }
+
+ if (olderrs != global.errors)
+ {
+ if (!global.gag)
+ {
+ errorSupplemental(ti.loc, "while looking for match for `%s`", ti.toChars());
+ ti.semanticRun = PASS.semanticdone;
+ ti.inst = ti;
+ }
+ ti.errors = true;
+ }
+ //printf("false\n");
+ return false;
+}
+
+/***************************************
+ * Fill out remainder of elements[] with default initializers for fields[].
+ * Params:
+ * sd = struct
+ * loc = location
+ * elements = explicit arguments which given to construct object.
+ * ctorinit = true if the elements will be used for default initialization.
+ * Returns:
+ * false if any errors occur.
+ * Otherwise, returns true and the missing arguments will be pushed in elements[].
+ */
+bool fill(StructDeclaration sd, Loc loc, ref Expressions elements, bool ctorinit)
+{
+ //printf("AggregateDeclaration::fill() %s\n", toChars());
+ assert(sd.sizeok == Sizeok.done);
+ const nfields = sd.nonHiddenFields();
+ bool errors = false;
+
+ size_t dim = elements.length;
+ elements.setDim(nfields);
+ foreach (size_t i; dim .. nfields)
+ elements[i] = null;
+
+ // Fill in missing any elements with default initializers
+ foreach (i; 0 .. nfields)
+ {
+ if (elements[i])
+ continue;
+
+ auto vd = sd.fields[i];
+ auto vx = vd;
+ if (vd._init && vd._init.isVoidInitializer())
+ vx = null;
+
+ // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
+ size_t fieldi = i;
+ foreach (j; 0 .. nfields)
+ {
+ if (i == j)
+ continue;
+ auto v2 = sd.fields[j];
+ if (!vd.isOverlappedWith(v2))
+ continue;
+
+ if (elements[j])
+ {
+ vx = null;
+ break;
+ }
+ if (v2._init && v2._init.isVoidInitializer())
+ continue;
+
+ version (all)
+ {
+ /* Prefer first found non-void-initialized field
+ * union U { int a; int b = 2; }
+ * U u; // Error: overlapping initialization for field a and b
+ */
+ if (!vx)
+ {
+ vx = v2;
+ fieldi = j;
+ }
+ else if (v2._init)
+ {
+ .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+ errors = true;
+ }
+ }
+ else
+ {
+ // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
+
+ /* Prefer explicitly initialized field
+ * union U { int a; int b = 2; }
+ * U u; // OK (u.b == 2)
+ */
+ if (!vx || !vx._init && v2._init)
+ {
+ vx = v2;
+ fieldi = j;
+ }
+ else if (vx != vd && !vx.isOverlappedWith(v2))
+ {
+ // Both vx and v2 fills vd, but vx and v2 does not overlap
+ }
+ else if (vx._init && v2._init)
+ {
+ .error(loc, "overlapping default initialization for field `%s` and `%s`",
+ v2.toChars(), vd.toChars());
+ errors = true;
+ }
+ else
+ assert(vx._init || !vx._init && !v2._init);
+ }
+ }
+ if (!vx)
+ continue;
+
+ Expression e;
+ if (vx.type.size() == 0)
+ {
+ e = null;
+ }
+ else if (vx._init)
+ {
+ assert(!vx._init.isVoidInitializer());
+ if (vx.inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
+ {
+ .error(loc, "%s `%s` recursive initialization of field", vx.kind(), vx.toPrettyChars());
+ errors = true;
+ }
+ else
+ e = vx.getConstInitializer(false);
+ }
+ else
+ {
+ if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
+ {
+ .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
+ sd.type.toChars(), vx.toChars());
+ errors = true;
+ }
+ /* https://issues.dlang.org/show_bug.cgi?id=12509
+ * Get the element of static array type.
+ */
+ Type telem = vx.type;
+ if (telem.ty == Tsarray)
+ {
+ /* We cannot use Type::baseElemOf() here.
+ * If the bottom of the Tsarray is an enum type, baseElemOf()
+ * will return the base of the enum, and its default initializer
+ * would be different from the enum's.
+ */
+ TypeSArray tsa;
+ while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
+ telem = tsa.next;
+ if (telem.ty == Tvoid)
+ telem = Type.tuns8.addMod(telem.mod);
+ }
+ if (telem.needsNested() && ctorinit)
+ e = telem.defaultInit(loc);
+ else
+ e = telem.defaultInitLiteral(loc);
+ }
+ elements[fieldi] = e;
+ }
+ foreach (e; elements)
+ {
+ if (e && e.op == EXP.error)
+ return false;
+ }
+
+ return !errors;
+}
+
+/*****************************************
+* Lower any aggregate that is not an array to an array using a
+* regular foreach loop within CTFE. If there are multiple
+* `static foreach` loop variables, an array of tuples is
+* generated. In thise case, the field `needExpansion` is set to
+* true to indicate that the static foreach loop expansion will
+* need to expand the tuples into multiple variables.
+*
+* For example, `static foreach (x; range) { ... }` is lowered to:
+*
+* static foreach (x; {
+* typeof({
+* foreach (x; range) return x;
+* }())[] __res;
+* foreach (x; range) __res ~= x;
+* return __res;
+* }()) { ... }
+*
+* Finally, call `lowerArrayAggregate` to turn the produced
+* array into an expression tuple.
+*
+* Params:
+* sfe = The 'static foreach'.
+* sc = The current scope.
+*/
+extern (C++) void lowerNonArrayAggregate(StaticForeach sfe, Scope* sc)
+{
+ import dmd.statement;
+
+ auto nvars = sfe.aggrfe ? sfe.aggrfe.parameters.length : 1;
+ auto aloc = sfe.aggrfe ? sfe.aggrfe.aggr.loc : sfe.rangefe.lwr.loc;
+ // We need three sets of foreach loop variables because the
+ // lowering contains three foreach loops.
+ Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()];
+ foreach (i; 0 .. nvars)
+ {
+ foreach (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));
+ }
+ }
+ Expression[2] res;
+ TypeStruct tplty = null;
+ if (nvars == 1) // only one `static foreach` variable, generate identifiers.
+ {
+ foreach (i; 0 .. 2)
+ {
+ res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident);
+ }
+ }
+ else // multiple `static foreach` variables, generate tuples.
+ {
+ foreach (i; 0 .. 2)
+ {
+ auto e = new Expressions(pparams[0].length);
+ foreach (j, ref elem; *e)
+ {
+ auto p = (*pparams[i])[j];
+ elem = new IdentifierExp(aloc, p.ident);
+ }
+ if (!tplty)
+ {
+ tplty = sfe.createTupleType(aloc, e, sc);
+ }
+ res[i] = sfe.createTuple(aloc, tplty, e);
+ }
+ sfe.needExpansion = true; // need to expand the tuples later
+ }
+ // generate remaining code for the new aggregate which is an
+ // array (see documentation comment).
+ if (sfe.rangefe)
+ {
+ sc = sc.startCTFE();
+ sfe.rangefe.lwr = sfe.rangefe.lwr.expressionSemantic(sc);
+ sfe.rangefe.lwr = resolveProperties(sc, sfe.rangefe.lwr);
+ sfe.rangefe.upr = sfe.rangefe.upr.expressionSemantic(sc);
+ sfe.rangefe.upr = resolveProperties(sc, sfe.rangefe.upr);
+ sc = sc.endCTFE();
+ sfe.rangefe.lwr = sfe.rangefe.lwr.optimize(WANTvalue);
+ sfe.rangefe.lwr = sfe.rangefe.lwr.ctfeInterpret();
+ 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)));
+ Type ety = new TypeTypeof(aloc, sfe.wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
+ auto aty = ety.arrayOf();
+ auto idres = Identifier.generateId("__res");
+ auto vard = new VarDeclaration(aloc, aty, idres, null, STC.temp);
+ auto s2 = new Statements();
+
+ // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
+ // an empty foreach to expose them.
+ const olderrors = global.startGagging();
+ ety = ety.typeSemantic(aloc, sc);
+ if (global.endGagging(olderrors))
+ s2.push(sfe.createForeach(aloc, pparams[1], null));
+ else
+ {
+ s2.push(new ExpStatement(aloc, vard));
+ auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
+ s2.push(sfe.createForeach(aloc, pparams[1], new ExpStatement(aloc, catass)));
+ s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
+ }
+
+ Expression aggr = void;
+ Type indexty = void;
+
+ if (sfe.rangefe && (indexty = ety).isIntegral())
+ {
+ sfe.rangefe.lwr.type = indexty;
+ sfe.rangefe.upr.type = indexty;
+ auto lwrRange = getIntRange(sfe.rangefe.lwr);
+ auto uprRange = getIntRange(sfe.rangefe.upr);
+
+ const lwr = sfe.rangefe.lwr.toInteger();
+ auto upr = sfe.rangefe.upr.toInteger();
+ size_t length = 0;
+
+ if (lwrRange.imin <= uprRange.imax)
+ length = cast(size_t) (upr - lwr);
+
+ auto exps = new Expressions(length);
+
+ if (sfe.rangefe.op == TOK.foreach_)
+ {
+ foreach (i; 0 .. length)
+ (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
+ }
+ else
+ {
+ --upr;
+ foreach (i; 0 .. length)
+ (*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
+ }
+ aggr = new ArrayLiteralExp(aloc, indexty.arrayOf(), exps);
+ }
+ else
+ {
+ aggr = sfe.wrapAndCall(aloc, new CompoundStatement(aloc, s2));
+ sc = sc.startCTFE();
+ aggr = aggr.expressionSemantic(sc);
+ aggr = resolveProperties(sc, aggr);
+ sc = sc.endCTFE();
+ aggr = aggr.optimize(WANTvalue);
+ aggr = aggr.ctfeInterpret();
+ }
+
+ assert(!!sfe.aggrfe ^ !!sfe.rangefe);
+ sfe.aggrfe = new ForeachStatement(sfe.loc, TOK.foreach_, pparams[2], aggr,
+ sfe.aggrfe ? sfe.aggrfe._body : sfe.rangefe._body,
+ sfe.aggrfe ? sfe.aggrfe.endloc : sfe.rangefe.endloc);
+ sfe.rangefe = null;
+ sfe.lowerArrayAggregate(sc); // finally, turn generated array into expression tuple
+}
+
+/*****************************************
+* Perform `static foreach` lowerings that are necessary in order
+* to finally expand the `static foreach` using
+* `dmd.statementsem.makeTupleForeach`.
+*/
+extern(D) void prepare(StaticForeach sfe, Scope* sc)
+{
+ assert(sc);
+
+ if (sfe.aggrfe)
+ {
+ sc = sc.startCTFE();
+ sfe.aggrfe.aggr = sfe.aggrfe.aggr.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ }
+
+ if (sfe.aggrfe && sfe.aggrfe.aggr.type.toBasetype().ty == Terror)
+ {
+ return;
+ }
+
+ if (!sfe.ready())
+ {
+ if (sfe.aggrfe && sfe.aggrfe.aggr.type.toBasetype().ty == Tarray)
+ {
+ sfe.lowerArrayAggregate(sc);
+ }
+ else
+ {
+ sfe.lowerNonArrayAggregate(sc);
+ }
+ }
+}
+
+/*****************************************
+ * Turn an aggregate which is an array into an expression tuple
+ * of its elements. I.e., lower
+ * static foreach (x; [1, 2, 3, 4]) { ... }
+ * to
+ * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
+ */
+extern(D) void lowerArrayAggregate(StaticForeach sfe, Scope* sc)
+{
+ auto aggr = sfe.aggrfe.aggr;
+ Expression el = new ArrayLengthExp(aggr.loc, aggr);
+ sc = sc.startCTFE();
+ el = el.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ el = el.optimize(WANTvalue);
+ el = el.ctfeInterpret();
+ if (el.op != EXP.int64)
+ {
+ sfe.aggrfe.aggr = ErrorExp.get();
+ return;
+ }
+
+ Expressions* es;
+ if (auto ale = aggr.isArrayLiteralExp())
+ {
+ // Directly use the elements of the array for the TupleExp creation
+ es = ale.elements;
+ }
+ else
+ {
+ const length = cast(size_t)el.toInteger();
+ es = new Expressions(length);
+ foreach (i; 0 .. length)
+ {
+ auto index = new IntegerExp(sfe.loc, i, Type.tsize_t);
+ auto value = new IndexExp(aggr.loc, aggr, index);
+ (*es)[i] = value;
+ }
+ }
+ sfe.aggrfe.aggr = new TupleExp(aggr.loc, es);
+ sfe.aggrfe.aggr = sfe.aggrfe.aggr.expressionSemantic(sc);
+ sfe.aggrfe.aggr = sfe.aggrfe.aggr.optimize(WANTvalue);
+ sfe.aggrfe.aggr = sfe.aggrfe.aggr.ctfeInterpret();
+}
diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d
index c696a5c..2ccb1d2 100644
--- a/gcc/d/dmd/file_manager.d
+++ b/gcc/d/dmd/file_manager.d
@@ -1,16 +1,17 @@
/**
* Read a file from disk and store it in memory.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d, _file_manager.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/file_manager.d, _file_manager.d)
* Documentation: https://dlang.org/phobos/dmd_file_manager.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/file_manager.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/file_manager.d
*/
module dmd.file_manager;
import core.stdc.stdio;
+import dmd.common.outbuffer;
import dmd.root.stringtable : StringTable;
import dmd.root.file : File, Buffer;
import dmd.root.filename : FileName, isDirSeparator;
@@ -70,44 +71,87 @@ private struct PathStack
}
}
-final class FileManager
+/***************************
+ * Cache path lookups so the operating system
+ * is only consulted once for each path.
+ */
+private struct PathCache
{
- private StringTable!(const(ubyte)[]) files; // contents of files indexed by file name
- private StringTable!(bool) packageStatus;
+ /* for filespec "a/b/c/d.ext"
+ * a b and c are directories, a, a/b, a/b/c are paths.
+ */
+
+ StringTable!(bool) pathStatus; // cached value of does a path exist or not
+
+ nothrow:
- // check if the package path of the given path exists. The input path is
- // expected to contain the full path to the module, so the parent
- // directories of that path are checked.
- private bool packageExists(const(char)[] p) nothrow
+ /**
+ * Determine if the path part of path/filename exists.
+ * Cache the results for the path and each left-justified subpath of the path.
+ * Params:
+ * filespec = path/filename
+ * Returns:
+ * true if path exists, false if it does not
+ */
+ bool pathExists(const(char)[] filespec) nothrow
{
- // step 1, look for the closest parent path that is cached
+ /* look for the longest leftmost parent path that is cached
+ * by starting at the right and working to the left
+ */
bool exists = true;
- auto st = PathStack(p);
- while (st.up) {
- if (auto cached = packageStatus.lookup(st.cur)) {
+ auto st = PathStack(filespec);
+ while (st.up)
+ {
+ if (auto cached = pathStatus.lookup(st.cur))
+ {
exists = cached.value;
break;
}
}
- // found a parent that is cached (or reached the end of the stack).
- // step 2, traverse back up the stack storing either false if the
- // parent doesn't exist, or the result of the `exists` call if it does.
- while (st.down) {
+ /* found a parent path that is cached (or reached the left end of the path).
+ * Now move right caching the results of those directories.
+ * Once a directory is found to not exist, all the directories
+ * to the right of it do not exist
+ */
+ while (st.down)
+ {
if (!exists)
- packageStatus.insert(st.cur, false);
+ pathStatus.insert(st.cur, false);
else
- exists = packageStatus.insert(st.cur, FileName.exists(st.cur) == 2).value;
+ exists = pathStatus.insert(st.cur, FileName.exists(st.cur) == 2).value;
}
- // at this point, exists should be the answer.
return exists;
}
+ /**
+ * Ask if path ends in a directory.
+ * Cache result for speed.
+ * Params:
+ * path = a path
+ * Returns:
+ * true if it's a path, false if not
+ */
+ bool isExistingPath(const char[] path)
+ {
+ auto cached = pathStatus.lookup(path);
+ if (!cached)
+ cached = pathStatus.insert(path, FileName.exists(path) == 2);
+ return cached.value;
+ }
+}
+
+final class FileManager
+{
+ private StringTable!(const(ubyte)[]) files; // contents of files indexed by file name
+
+ private PathCache pathCache;
+
///
public this () nothrow
{
this.files._init();
- this.packageStatus._init();
+ this.pathCache.pathStatus._init();
}
nothrow:
@@ -117,39 +161,37 @@ nothrow:
* Does not open the file.
* Params:
* filename = as supplied by the user
- * path = path to look for filename
+ * pathsInfo = pathsInfo to look for filename with metadata
+ * whichPathFoundThis = Which path from `path` was used in determining the output path, or -1 if unknown.
* Returns:
* the found file name or
* `null` if it is not different from filename.
*/
- const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
+ const(char)[] lookForSourceFile(const char[] filename, const ImportPathInfo[] pathsInfo, out ptrdiff_t whichPathFoundThis)
{
//printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
- /* Search along path[] for .di file, then .d file.
+ /* Search along pathsInfo[] for .di file, then .d file.
*/
+
+ whichPathFoundThis = -1;
+
// see if we should check for the module locally.
- bool checkLocal = packageExists(filename);
+ 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_ext);
- // Special file name representing `stdin`, always assume its presence
- if (sd == "__stdin.d")
- return sd;
if (checkLocal && FileName.exists(sd) == 1)
return sd;
scope(exit) FileName.free(sd.ptr);
if (checkLocal)
{
- auto cached = packageStatus.lookup(filename);
- if (!cached)
- cached = packageStatus.insert(filename, FileName.exists(filename) == 2);
- if (cached.value)
+ if (pathCache.isExistingPath(filename))
{
- /* The filename exists and it's a directory.
+ /* The filename exists but it's a directory.
* Therefore, the result should be: filename/package.d
* iff filename/package.d is a file
*/
@@ -167,56 +209,57 @@ nothrow:
if (FileName.absolute(filename))
return null;
- if (!path.length)
+ if (!pathsInfo.length)
return null;
- foreach (entry; path)
+ foreach (pathIndex, entry; pathsInfo)
{
- const p = entry.toDString();
+ const p = entry.path.toDString();
const(char)[] n = FileName.combine(p, sdi);
- if (!packageExists(n)) {
+ if (!pathCache.pathExists(n))
+ {
FileName.free(n.ptr);
continue; // no need to check for anything else.
}
- if (FileName.exists(n) == 1) {
+ if (FileName.exists(n) == 1)
return n;
- }
+
FileName.free(n.ptr);
n = FileName.combine(p, sd);
- if (FileName.exists(n) == 1) {
+ if (FileName.exists(n) == 1)
+ {
+ whichPathFoundThis = pathIndex;
return n;
}
FileName.free(n.ptr);
- const b = FileName.removeExt(filename);
- n = FileName.combine(p, b);
- FileName.free(b.ptr);
-
+ n = FileName.combine(p, FileName.sansExt(filename));
scope(exit) FileName.free(n.ptr);
// also cache this if we are looking for package.d[i]
- auto cached = packageStatus.lookup(n);
- if (!cached) {
- cached = packageStatus.insert(n, FileName.exists(n) == 2);
- }
-
- if (cached.value)
+ if (pathCache.isExistingPath(n))
{
const n2i = FileName.combine(n, package_di);
if (FileName.exists(n2i) == 1)
+ {
+ whichPathFoundThis = pathIndex;
return n2i;
+ }
+
FileName.free(n2i.ptr);
const n2 = FileName.combine(n, package_d);
- if (FileName.exists(n2) == 1) {
+ if (FileName.exists(n2) == 1)
+ {
+ whichPathFoundThis = pathIndex;
return n2;
}
FileName.free(n2.ptr);
}
}
- /* ImportC: No D modules found, now search along path[] for .i file, then .c file.
+ /* ImportC: No D modules found, now search along paths[] for .i file, then .c file.
*/
const si = FileName.forceExt(filename, i_ext);
if (FileName.exists(si) == 1)
@@ -227,18 +270,22 @@ nothrow:
if (FileName.exists(sc) == 1)
return sc;
scope(exit) FileName.free(sc.ptr);
- foreach (entry; path)
+ foreach (pathIndex, entry; pathsInfo)
{
- const p = entry.toDString();
+ const p = entry.path.toDString();
const(char)[] n = FileName.combine(p, si);
- if (FileName.exists(n) == 1) {
+ if (FileName.exists(n) == 1)
+ {
+ whichPathFoundThis = pathIndex;
return n;
}
FileName.free(n.ptr);
n = FileName.combine(p, sc);
- if (FileName.exists(n) == 1) {
+ if (FileName.exists(n) == 1)
+ {
+ whichPathFoundThis = pathIndex;
return n;
}
FileName.free(n.ptr);
@@ -261,128 +308,23 @@ nothrow:
if (auto val = files.lookup(name)) // if `name` is cached
return val.value; // return its contents
- if (name == "__stdin.d") // special name for reading from stdin
- {
- const ubyte[] buffer = readFromStdin().extractSlice();
- if (this.files.insert(name, buffer) is null)
- // this.files already contains the name
- assert(0, "stdin: Insert after lookup failure should never return `null`");
- return buffer;
- }
-
if (FileName.exists(name) != 1) // if not an ordinary file
return null;
- auto readResult = File.read(name);
- if (!readResult.success)
- return null;
+ OutBuffer buf;
+ if (File.read(name, buf))
+ return null; // failed
- const ubyte[] fb = readResult.extractSlice();
+ buf.write32(0); // terminating dchar 0
+
+ const length = buf.length;
+ const ubyte[] fb = cast(ubyte[])(buf.extractSlice()[0 .. length - 4]);
if (files.insert(name, fb) is null)
assert(0, "Insert after lookup failure should never return `null`");
return fb;
}
- /**********************************
- * Take `text` and turn it into an InputRange that emits
- * slices into `text` for each line.
- * Params:
- * text = array of characters
- * Returns:
- * InputRange accessing `text` as a sequence of lines
- * Reference:
- * `std.string.splitLines()`
- */
- auto splitLines(const char[] text)
- {
- struct Range
- {
- @safe:
- @nogc:
- nothrow:
- pure:
- private:
-
- const char[] text;
- size_t index; // index of start of line
- size_t eolIndex; // index of end of line before newline characters
- size_t nextIndex; // index past end of line
-
- public this(const char[] text)
- {
- this.text = text;
- }
-
- public bool empty() { return index == text.length; }
-
- public void popFront() { advance(); index = nextIndex; }
-
- public const(char)[] front() { advance(); return text[index .. eolIndex]; }
-
- private void advance()
- {
- if (index != nextIndex) // if already advanced
- return;
-
- for (size_t i = index; i < text.length; ++i)
- {
- switch (text[i])
- {
- case '\v', '\f', '\n':
- eolIndex = i;
- nextIndex = i + 1;
- return;
-
- case '\r':
- if (i + 1 < text.length && text[i + 1] == '\n') // decode "\r\n"
- {
- eolIndex = i;
- nextIndex = i + 2;
- return;
- }
- eolIndex = i;
- nextIndex = i + 1;
- return;
-
- /* Manually decode:
- * NEL is C2 85
- */
- case 0xC2:
- if (i + 1 < text.length && text[i + 1] == 0x85)
- {
- eolIndex = i;
- nextIndex = i + 2;
- return;
- }
- break;
-
- /* Manually decode:
- * lineSep is E2 80 A8
- * paraSep is E2 80 A9
- */
- case 0xE2:
- if (i + 2 < text.length &&
- text[i + 1] == 0x80 &&
- (text[i + 2] == 0xA8 || text[i + 2] == 0xA9)
- )
- {
- eolIndex = i;
- nextIndex = i + 3;
- return;
- }
- break;
-
- default:
- break;
- }
- }
- }
- }
-
- return Range(text);
- }
-
/**
* Adds the contents of a file to the table.
* Params:
@@ -397,46 +339,3 @@ nothrow:
return val == null ? null : val.value;
}
}
-
-private Buffer readFromStdin() nothrow
-{
- import core.stdc.stdio;
- import dmd.errors;
- import dmd.root.rmem;
-
- enum bufIncrement = 128 * 1024;
- size_t pos = 0;
- size_t sz = bufIncrement;
-
- ubyte* buffer = null;
- for (;;)
- {
- buffer = cast(ubyte*)mem.xrealloc(buffer, sz + 4); // +2 for sentinel and +2 for lexer
-
- // Fill up buffer
- do
- {
- assert(sz > pos);
- size_t rlen = fread(buffer + pos, 1, sz - pos, stdin);
- pos += rlen;
- if (ferror(stdin))
- {
- import core.stdc.errno;
- error(Loc.initial, "cannot read from stdin, errno = %d", errno);
- fatal();
- }
- if (feof(stdin))
- {
- // We're done
- assert(pos < sz + 2);
- buffer[pos .. pos + 4] = '\0';
- return Buffer(buffer[0 .. pos]);
- }
- } while (pos < sz);
-
- // Buffer full, expand
- sz += bufIncrement;
- }
-
- assert(0);
-}
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 7003c2b..064b67f 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -8,12 +8,12 @@
* - `invariant`
* - `unittest`
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/func.d, _func.d)
* Documentation: https://dlang.org/phobos/dmd_func.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/func.d
*/
module dmd.func;
@@ -29,15 +29,14 @@ import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
import dmd.delegatize;
-import dmd.dinterpret;
import dmd.dmodule;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
import dmd.dtemplate;
-import dmd.errors;
import dmd.escape;
import dmd.expression;
+import dmd.funcsem : overloadApply;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -46,17 +45,12 @@ import dmd.init;
import dmd.location;
import dmd.mtype;
import dmd.objc;
-import dmd.root.aav;
import dmd.common.outbuffer;
import dmd.rootobject;
import dmd.root.string;
import dmd.root.stringtable;
-import dmd.semantic2;
-import dmd.semantic3;
-import dmd.statement_rewrite_walker;
import dmd.statement;
import dmd.tokens;
-import dmd.typesem;
import dmd.visitor;
version (IN_GCC) {}
@@ -109,7 +103,8 @@ enum BUILTIN : ubyte
yl2xp1,
toPrecFloat,
toPrecDouble,
- toPrecReal
+ toPrecReal,
+ ctfeWrite,
}
private struct FUNCFLAG
@@ -118,9 +113,9 @@ private struct FUNCFLAG
bool safetyInprocess; /// working on determining safety
bool nothrowInprocess; /// working on determining nothrow
bool nogcInprocess; /// working on determining @nogc
- bool returnInprocess; /// working on inferring 'return' for parameters
+ bool saferD; /// do -preview=safer checks if this function has default safety
+ bool scopeInprocess; /// infer `return` and `scope` for parameters
bool inlineScanned; /// function has been scanned for inline possibilities
- bool inferScope; /// infer 'scope' for parameters
bool hasCatches; /// function has try-catch statements
bool skipCodegen; /// do not generate code for this function.
bool printf; /// is a printf-like function
@@ -143,6 +138,10 @@ private struct FUNCFLAG
bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
bool dllImport; /// __declspec(dllimport)
bool dllExport; /// __declspec(dllexport)
+
+ bool hasReturnExp; /// Has return exp; statement
+ bool hasInlineAsm; /// Has asm{} statement
+ bool hasMultipleReturnExp; /// Has multiple return exp; statements
}
/***********************************************************
@@ -164,15 +163,12 @@ extern (C++) struct Ensure
*/
static Ensures* arraySyntaxCopy(Ensures* a)
{
- Ensures* b = null;
- if (a)
- {
- b = a.copy();
- foreach (i, e; *a)
- {
- (*b)[i] = e.syntaxCopy();
- }
- }
+ if (!a)
+ return null;
+
+ Ensures* b = a.copy();
+ foreach (i, e; *a)
+ (*b)[i] = e.syntaxCopy();
return b;
}
@@ -239,17 +235,10 @@ extern (C++) class FuncDeclaration : Declaration
*/
Type tintro;
- StorageClass storage_class2; /// storage class for template onemember's
+ STC storage_class2; /// storage class for template onemember's
// Things that should really go into Scope
- /// 1 if there's a return exp; statement
- /// 2 if there's a throw statement
- /// 4 if there's an assert(0)
- /// 8 if there's inline asm
- /// 16 if there are multiple return statements
- int hasReturnExp;
-
VarDeclaration nrvo_var; /// variable to replace with shidden
Symbol* shidden; /// hidden pointer passed to function
@@ -281,10 +270,14 @@ extern (C++) class FuncDeclaration : Declaration
*/
VarDeclarations outerVars;
+ // Most recent encountered `main` (`WinMain` or `DllMain`) function.
+ // Track it to give error messages for multiple entrypoints
+ __gshared FuncDeclaration lastMain;
+
/// Sibling nested functions which called this one
FuncDeclarations siblingCallers;
- FuncDeclarations *inlinedNestedCallees;
+ FuncDeclarations* inlinedNestedCallees;
/// In case of failed `@safe` inference, store the error that made the function `@system` for
/// better diagnostics
@@ -303,9 +296,9 @@ extern (C++) class FuncDeclaration : Declaration
*/
ObjcFuncDeclaration objc;
- extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
+ extern (D) this(Loc loc, Loc endloc, Identifier ident, STC storage_class, Type type, bool noreturn = false)
{
- super(loc, ident);
+ super(DSYM.funcDeclaration, loc, ident);
//.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars());
//.printf("storage_class = x%llx\n", storage_class);
this.storage_class = storage_class;
@@ -327,9 +320,9 @@ extern (C++) class FuncDeclaration : Declaration
this.inferRetType = true;
}
- static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
+ static FuncDeclaration create(Loc loc, Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
{
- return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
+ return new FuncDeclaration(loc, endloc, id, cast(STC) storage_class, type, noreturn);
}
final nothrow pure @safe
@@ -386,61 +379,38 @@ extern (C++) class FuncDeclaration : Declaration
if (this == o)
return true;
- if (auto s = isDsymbol(o))
- {
- auto fd1 = this;
- auto fd2 = s.isFuncDeclaration();
- if (!fd2)
- return false;
+ auto s = isDsymbol(o);
+ if (!s)
+ return false;
- auto fa1 = fd1.isFuncAliasDeclaration();
- auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
+ auto fd1 = this;
+ auto fd2 = s.isFuncDeclaration();
+ if (!fd2)
+ return false;
- auto fa2 = fd2.isFuncAliasDeclaration();
- auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
+ auto fa1 = fd1.isFuncAliasDeclaration();
+ auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
- if (fa1 && fa2)
- {
- return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
- }
+ auto fa2 = fd2.isFuncAliasDeclaration();
+ auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
- bool b1 = fa1 !is null;
- if (b1 && faf1.isUnique() && !fa1.hasOverloads)
- b1 = false;
+ if (fa1 && fa2)
+ return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
- bool b2 = fa2 !is null;
- if (b2 && faf2.isUnique() && !fa2.hasOverloads)
- b2 = false;
+ bool b1 = fa1 !is null;
+ if (b1 && faf1.isUnique() && !fa1.hasOverloads)
+ b1 = false;
- if (b1 != b2)
- return false;
+ bool b2 = fa2 !is null;
+ if (b2 && faf2.isUnique() && !fa2.hasOverloads)
+ b2 = false;
- return faf1.toParent().equals(faf2.toParent()) &&
- faf1.ident.equals(faf2.ident) &&
- faf1.type.equals(faf2.type);
- }
- return false;
- }
+ if (b1 != b2)
+ return false;
- /****************************************************
- * Determine if 'this' overrides fd.
- * Return !=0 if it does.
- */
- extern (D) final int overrides(FuncDeclaration fd)
- {
- int result = 0;
- if (fd.ident == ident)
- {
- const cov = type.covariant(fd.type);
- if (cov != Covariant.distinct)
- {
- ClassDeclaration cd1 = toParent().isClassDeclaration();
- ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
- if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
- result = 1;
- }
- }
- return result;
+ return faf1.toParent().equals(faf2.toParent()) &&
+ faf1.ident.equals(faf2.ident) &&
+ faf1.type.equals(faf2.type);
}
/****************************************************
@@ -451,8 +421,7 @@ extern (C++) class FuncDeclaration : Declaration
{
//printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
assert(s != this);
- AliasDeclaration ad = s.isAliasDeclaration();
- if (ad)
+ if (AliasDeclaration ad = s.isAliasDeclaration())
{
if (overnext)
return overnext.overloadInsert(ad);
@@ -479,26 +448,6 @@ extern (C++) class FuncDeclaration : Declaration
if (!fd)
return false;
- version (none)
- {
- /* Disable this check because:
- * const void foo();
- * semantic() isn't run yet on foo(), so the const hasn't been
- * applied yet.
- */
- if (type)
- {
- printf("type = %s\n", type.toChars());
- printf("fd.type = %s\n", fd.type.toChars());
- }
- // fd.type can be NULL for overloaded constructors
- if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
- {
- //printf("\tfalse: conflict %s\n", kind());
- return false;
- }
- }
-
if (overnext)
{
td = overnext.isTemplateDeclaration();
@@ -513,149 +462,6 @@ extern (C++) class FuncDeclaration : Declaration
}
/********************************************
- * Find function in overload list that exactly matches t.
- */
- extern (D) final FuncDeclaration overloadExactMatch(Type t)
- {
- FuncDeclaration fd;
- overloadApply(this, (Dsymbol s)
- {
- auto f = s.isFuncDeclaration();
- if (!f)
- return 0;
- if (f.storage_class & STC.disable)
- return 0;
- if (t.equals(f.type))
- {
- fd = f;
- return 1;
- }
-
- /* Allow covariant matches, as long as the return type
- * is just a const conversion.
- * This allows things like pure functions to match with an impure function type.
- */
- if (t.ty == Tfunction)
- {
- auto tf = cast(TypeFunction)f.type;
- if (tf.covariant(t) == Covariant.yes &&
- tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
- {
- fd = f;
- return 1;
- }
- }
- return 0;
- });
- return fd;
- }
-
- /********************************************
- * Find function in overload list that matches to the 'this' modifier.
- * There's four result types.
- *
- * 1. If the 'tthis' matches only one candidate, it's an "exact match".
- * Returns the function and 'hasOverloads' is set to false.
- * eg. If 'tthis" is mutable and there's only one mutable method.
- * 2. If there's two or more match candidates, but a candidate function will be
- * a "better match".
- * Returns the better match function but 'hasOverloads' is set to true.
- * eg. If 'tthis' is mutable, and there's both mutable and const methods,
- * the mutable method will be a better match.
- * 3. If there's two or more match candidates, but there's no better match,
- * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
- * eg. If 'tthis' is mutable, and there's two or more mutable methods.
- * 4. If there's no candidates, it's "no match" and returns null with error report.
- * e.g. If 'tthis' is const but there's no const methods.
- */
- extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
- {
- //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
- MatchAccumulator m;
- overloadApply(this, (Dsymbol s)
- {
- auto f = s.isFuncDeclaration();
- if (!f || f == m.lastf) // skip duplicates
- return 0;
-
- auto tf = f.type.toTypeFunction();
- //printf("tf = %s\n", tf.toChars());
-
- MATCH match;
- if (tthis) // non-static functions are preferred than static ones
- {
- if (f.needThis())
- match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
- else
- match = MATCH.constant; // keep static function in overload candidates
- }
- else // static functions are preferred than non-static ones
- {
- if (f.needThis())
- match = MATCH.convert;
- else
- match = MATCH.exact;
- }
- if (match == MATCH.nomatch)
- return 0;
-
- if (match > m.last) goto LcurrIsBetter;
- if (match < m.last) goto LlastIsBetter;
-
- // See if one of the matches overrides the other.
- if (m.lastf.overrides(f)) goto LlastIsBetter;
- if (f.overrides(m.lastf)) goto LcurrIsBetter;
-
- //printf("\tambiguous\n");
- m.nextf = f;
- m.count++;
- return 0;
-
- LlastIsBetter:
- //printf("\tlastbetter\n");
- m.count++; // count up
- return 0;
-
- LcurrIsBetter:
- //printf("\tisbetter\n");
- if (m.last <= MATCH.convert)
- {
- // clear last secondary matching
- m.nextf = null;
- m.count = 0;
- }
- m.last = match;
- m.lastf = f;
- m.count++; // count up
- return 0;
- });
-
- if (m.count == 1) // exact match
- {
- hasOverloads = false;
- }
- else if (m.count > 1) // better or ambiguous match
- {
- hasOverloads = true;
- }
- else // no match
- {
- hasOverloads = true;
- auto tf = this.type.toTypeFunction();
- assert(tthis);
- assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
- {
- OutBuffer thisBuf, funcBuf;
- MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
- MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
- .error(loc, "%smethod %s is not callable using a %sobject", kind, toPrettyChars,
- funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
- }
- }
- return m.lastf;
- }
-
- /********************************************
* find function template root in overload list
*/
extern (D) final TemplateDeclaration findTemplateDeclRoot()
@@ -664,8 +470,7 @@ extern (C++) class FuncDeclaration : Declaration
while (f && f.overnext)
{
//printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
- TemplateDeclaration td = f.overnext.isTemplateDeclaration();
- if (td)
+ if (TemplateDeclaration td = f.overnext.isTemplateDeclaration())
return td;
f = f.overnext.isFuncDeclaration();
}
@@ -689,91 +494,6 @@ extern (C++) class FuncDeclaration : Declaration
return false;
}
- /*************************************
- * Determine partial specialization order of functions `f` vs `g`.
- * This is very similar to TemplateDeclaration::leastAsSpecialized().
- * Params:
- * f = first function
- * g = second function
- * names = names of parameters
- * Returns:
- * match 'this' is at least as specialized as g
- * 0 g is more specialized than 'this'
- */
- static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names)
- {
- enum LOG_LEASTAS = 0;
- static if (LOG_LEASTAS)
- {
- import core.stdc.stdio : printf;
- printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null");
- printf("%s, %s\n", f.type.toChars(), g.type.toChars());
- }
-
- /* This works by calling g() with f()'s parameters, and
- * if that is possible, then f() is at least as specialized
- * as g() is.
- */
-
- TypeFunction tf = f.type.toTypeFunction();
- TypeFunction tg = g.type.toTypeFunction();
-
- /* If both functions have a 'this' pointer, and the mods are not
- * the same and g's is not const, then this is less specialized.
- */
- if (f.needThis() && g.needThis() && tf.mod != tg.mod)
- {
- if (f.isCtorDeclaration())
- {
- if (!MODimplicitConv(tg.mod, tf.mod))
- return MATCH.nomatch;
- }
- else
- {
- if (!MODimplicitConv(tf.mod, tg.mod))
- return MATCH.nomatch;
- }
- }
-
- /* Create a dummy array of arguments out of the parameters to f()
- */
- Expressions args;
- foreach (u, p; tf.parameterList)
- {
- Expression e;
- if (p.isReference())
- {
- e = new IdentifierExp(Loc.initial, p.ident);
- e.type = p.type;
- }
- else
- e = p.type.defaultInitLiteral(Loc.initial);
- args.push(e);
- }
-
- MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
- if (m > MATCH.nomatch)
- {
- /* A variadic parameter list is less specialized than a
- * non-variadic one.
- */
- if (tf.parameterList.varargs && !tg.parameterList.varargs)
- goto L1; // less specialized
-
- static if (LOG_LEASTAS)
- {
- printf(" matches %d, so is least as specialized\n", m);
- }
- return m;
- }
- L1:
- static if (LOG_LEASTAS)
- {
- printf(" doesn't match, so is not as specialized\n");
- }
- return MATCH.nomatch;
- }
-
/********************************
* Searches for a label with the given identifier. This function will insert a new
* `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
@@ -784,7 +504,7 @@ extern (C++) class FuncDeclaration : Declaration
*
* Returns: the `LabelDsymbol` for `ident`
*/
- final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc)
+ final LabelDsymbol searchLabel(Identifier ident, Loc loc)
{
Dsymbol s;
if (!labtab)
@@ -855,51 +575,13 @@ extern (C++) class FuncDeclaration : Declaration
return level;
}
- /***********************************
- * Determine lexical level difference from `this` to nested function `fd`.
- * Issue error if `this` cannot call `fd`.
- *
- * Params:
- * loc = location for error messages
- * sc = context
- * fd = target of call
- * decl = The `Declaration` that triggered this check.
- * Used to provide a better error message only.
- * Returns:
- * 0 same level
- * >0 decrease nesting by number
- * -1 increase nesting by 1 (`fd` is nested within 'this')
- * LevelError error
- */
- extern (D) final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
- Declaration decl)
- {
- int level = getLevel(fd, sc.intypeof);
- if (level != LevelError)
- return level;
-
- // Don't give error if in template constraint
- if (!(sc.flags & SCOPE.constraint))
- {
- const(char)* xstatic = isStatic() ? "`static` " : "";
- // better diagnostics for static functions
- .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
- xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
- fd.toPrettyChars());
- .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
- return LevelError;
- }
- return 1;
- }
-
enum LevelError = -2;
override const(char)* toPrettyChars(bool QualifyTypes = false)
{
if (isMain())
return "D main";
- else
- return Dsymbol.toPrettyChars(QualifyTypes);
+ return Dsymbol.toPrettyChars(QualifyTypes);
}
/** for diagnostics, e.g. 'int foo(int x, int y) pure' */
@@ -990,293 +672,31 @@ extern (C++) class FuncDeclaration : Declaration
return false;
}
- /**********************************
- * Decide if attributes for this function can be inferred from examining
- * the function body.
- * Returns:
- * true if can
- */
- final bool canInferAttributes(Scope* sc)
- {
- if (!fbody)
- return false;
-
- if (isVirtualMethod() &&
- /*
- * https://issues.dlang.org/show_bug.cgi?id=21719
- *
- * If we have an auto virtual function we can infer
- * the attributes.
- */
- !(inferRetType && !isCtorDeclaration()))
- return false; // since they may be overridden
-
- if (sc.func &&
- /********** this is for backwards compatibility for the moment ********/
- (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
- return true;
-
- if (isFuncLiteralDeclaration() || // externs are not possible with literals
- (storage_class & STC.inference) || // do attribute inference
- (inferRetType && !isCtorDeclaration()))
- return true;
-
- if (isInstantiated())
- {
- auto ti = parent.isTemplateInstance();
- if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
- return true;
- }
-
- return false;
- }
-
- /*****************************************
- * Initialize for inferring the attributes of this function.
- */
- final void initInferAttributes()
- {
- //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
- TypeFunction tf = type.toTypeFunction();
- if (tf.purity == PURE.impure) // purity not specified
- purityInprocess = true;
-
- if (tf.trust == TRUST.default_)
- safetyInprocess = true;
-
- if (!tf.isnothrow)
- nothrowInprocess = true;
-
- if (!tf.isnogc)
- nogcInprocess = true;
-
- if (!isVirtual() || this.isIntroducing())
- returnInprocess = true;
-
- // Initialize for inferring STC.scope_
- inferScope = true;
- }
-
- final PURE isPure()
- {
- //printf("FuncDeclaration::isPure() '%s'\n", toChars());
-
-
- TypeFunction tf = type.toTypeFunction();
- if (purityInprocess)
- setImpure();
- if (tf.purity == PURE.fwdref)
- tf.purityLevel();
- PURE purity = tf.purity;
- if (purity > PURE.weak && isNested())
- purity = PURE.weak;
- if (purity > PURE.weak && needThis())
- {
- // The attribute of the 'this' reference affects purity strength
- if (type.mod & MODFlags.immutable_)
- {
- }
- else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
- purity = PURE.const_;
- else
- purity = PURE.weak;
- }
- tf.purity = purity;
- // ^ This rely on the current situation that every FuncDeclaration has a
- // unique TypeFunction.
- return purity;
- }
-
- extern (D) final PURE isPureBypassingInference()
- {
- if (purityInprocess)
- return PURE.fwdref;
- else
- return isPure();
- }
-
- /**************************************
- * The function is doing something impure, so mark it as impure.
- *
- * Params:
- * loc = location of impure action
- * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
- * arg0 = (optional) argument to format string
- *
- * Returns: `true` if there's a purity error
- */
- extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
- {
- if (purityInprocess)
- {
- purityInprocess = false;
- if (fmt)
- pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
- else if (arg0)
- pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
-
- if (fes)
- fes.func.setImpure(loc, fmt, arg0);
- }
- else if (isPure())
- return true;
- return false;
- }
-
- extern (D) final uint flags()
+ extern (D) final uint saveFlags()
{
return bitFields;
}
- extern (D) final uint flags(uint f)
+ extern (D) final uint restoreFlags(uint f)
{
bitFields = f;
return bitFields;
}
- final bool isSafe()
- {
- if (safetyInprocess)
- setUnsafe();
- return type.toTypeFunction().trust == TRUST.safe;
- }
-
- extern (D) final bool isSafeBypassingInference()
- {
- return !(safetyInprocess) && isSafe();
- }
-
- final bool isTrusted()
- {
- if (safetyInprocess)
- setUnsafe();
- return type.toTypeFunction().trust == TRUST.trusted;
- }
-
- /**************************************
- * The function is doing something unsafe, so mark it as unsafe.
- *
- * Params:
- * gag = surpress error message (used in escape.d)
- * loc = location of error
- * fmt = printf-style format string
- * arg0 = (optional) argument for first %s format specifier
- * arg1 = (optional) argument for second %s format specifier
- * arg2 = (optional) argument for third %s format specifier
- * Returns: whether there's a safe error
- */
- extern (D) final bool setUnsafe(
- bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
- RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
- {
- if (safetyInprocess)
- {
- safetyInprocess = false;
- type.toTypeFunction().trust = TRUST.system;
- if (fmt || arg0)
- safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
-
- if (fes)
- fes.func.setUnsafe();
- }
- else if (isSafe())
- {
- if (!gag && fmt)
- .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
-
- return true;
- }
- return false;
- }
-
- /**************************************
- * The function is calling `@system` function `f`, so mark it as unsafe.
- *
- * Params:
- * f = function being called (needed for diagnostic of inferred functions)
- * Returns: whether there's a safe error
- */
- extern (D) final bool setUnsafeCall(FuncDeclaration f)
- {
- return setUnsafe(false, f.loc, null, f, null);
- }
-
- final bool isNogc()
- {
- //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
- if (nogcInprocess)
- setGC(loc, null);
- return type.toTypeFunction().isnogc;
- }
-
- extern (D) final bool isNogcBypassingInference()
- {
- return !nogcInprocess && isNogc();
- }
-
- /**************************************
- * The function is doing something that may allocate with the GC,
- * so mark it as not nogc (not no-how).
- *
- * Params:
- * loc = location of impure action
- * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
- * arg0 = (optional) argument to format string
- *
- * Returns:
- * true if function is marked as @nogc, meaning a user error occurred
- */
- extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null)
- {
- //printf("setGC() %s\n", toChars());
- if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
- {
- this.semantic2(_scope);
- this.semantic3(_scope);
- }
-
- if (nogcInprocess)
- {
- nogcInprocess = false;
- if (fmt)
- nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC
- else if (arg0)
- nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
-
- type.toTypeFunction().isnogc = false;
- if (fes)
- fes.func.setGC(Loc.init, null, null);
- }
- else if (isNogc())
- return true;
- return false;
- }
-
- /**************************************
- * The function calls non-`@nogc` function f, mark it as not nogc.
- * Params:
- * f = function being called
- * Returns:
- * true if function is marked as @nogc, meaning a user error occurred
- */
- extern (D) final bool setGCCall(FuncDeclaration f)
- {
- return setGC(loc, null, f);
- }
/**************************************
* The function is doing something that may throw an exception, register that in case nothrow is being inferred
*
* Params:
* loc = location of action
- * fmt = format string for error message
- * arg0 = (optional) argument to format string
+ * format = format string for error message
+ * args = arguments to format string
*/
- extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
+ extern (D) final void setThrow(Loc loc, const(char)* format, RootObject[] args...)
{
if (nothrowInprocess && !nothrowViolation)
{
- nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
+ nothrowViolation = new AttributeViolation(loc, format, args); // action that requires GC
}
}
@@ -1284,204 +704,14 @@ extern (C++) class FuncDeclaration : Declaration
* The function calls non-`nothrow` function f, register that in case nothrow is being inferred
* Params:
* loc = location of call
- * f = function being called
- */
- extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
- {
- return setThrow(loc, null, f);
- }
-
- extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
- {
- if (!global.params.v.gc)
- return;
-
- Module m = getModule();
- if (m && m.isRoot() && !inUnittest())
- {
- message(loc, "vgc: %s", warn);
- }
- }
-
- /********************************************
- * See if pointers from function parameters, mutable globals, or uplevel functions
- * could leak into return value.
- * Returns:
- * true if the function return value is isolated from
- * any inputs to the function
+ * fd = function being called
*/
- extern (D) final bool isReturnIsolated()
+ extern (D) final void setThrowCall(Loc loc, FuncDeclaration fd)
{
- //printf("isReturnIsolated(this: %s)\n", this.toChars);
- TypeFunction tf = type.toTypeFunction();
- assert(tf.next);
-
- Type treti = tf.next;
- if (tf.isref)
- return isTypeIsolatedIndirect(treti); // check influence from parameters
-
- return isTypeIsolated(treti);
- }
-
- /********************
- * See if pointers from function parameters, mutable globals, or uplevel functions
- * could leak into type `t`.
- * Params:
- * t = type to check if it is isolated
- * Returns:
- * true if `t` is isolated from
- * any inputs to the function
- */
- extern (D) final bool isTypeIsolated(Type t)
- {
- StringTable!Type parentTypes;
- const uniqueTypeID = t.getUniqueID();
- if (uniqueTypeID)
- {
- const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
- if (cacheResultPtr !is null)
- return *cacheResultPtr;
-
- parentTypes._init();
- const isIsolated = isTypeIsolated(t, parentTypes);
- isTypeIsolatedCache[uniqueTypeID] = isIsolated;
- return isIsolated;
- }
- else
- {
- parentTypes._init();
- return isTypeIsolated(t, parentTypes);
- }
- }
-
- ///ditto
- extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
- {
- //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
-
- t = t.baseElemOf();
- switch (t.ty)
- {
- case Tarray:
- case Tpointer:
- return isTypeIsolatedIndirect(t.nextOf()); // go down one level
-
- case Taarray:
- case Tclass:
- return isTypeIsolatedIndirect(t);
-
- case Tstruct:
- /* Drill down and check the struct's fields
- */
- auto sym = t.toDsymbol(null).isStructDeclaration();
- const tName = t.toChars.toDString;
- const entry = parentTypes.insert(tName, t);
- if (entry == null)
- {
- //we've already seen this type in a parent, not isolated
- return false;
- }
- foreach (v; sym.fields)
- {
- Type tmi = v.type.addMod(t.mod);
- //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
- // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
- if (!isTypeIsolated(tmi, parentTypes))
- return false;
- }
- return true;
-
- default:
- return true;
- }
- }
-
- /********************************************
- * Params:
- * t = type of object to test one level of indirection down
- * Returns:
- * true if an object typed `t` has no indirections
- * which could have come from the function's parameters, mutable
- * globals, or uplevel functions.
- */
- private bool isTypeIsolatedIndirect(Type t)
- {
- //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
- assert(t);
-
- /* Since `t` is one level down from an indirection, it could pick
- * up a reference to a mutable global or an outer function, so
- * return false.
- */
- if (!isPureBypassingInference() || isNested())
- return false;
-
- TypeFunction tf = type.toTypeFunction();
-
- //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
-
- foreach (i, fparam; tf.parameterList)
- {
- Type tp = fparam.type;
- if (!tp)
- continue;
-
- if (fparam.isLazy() || fparam.isReference())
- {
- if (!traverseIndirections(tp, t))
- return false;
- continue;
- }
-
- /* Goes down one level of indirection, then calls traverseIndirection() on
- * the result.
- * Returns:
- * true if t is isolated from tp
- */
- static bool traverse(Type tp, Type t)
- {
- tp = tp.baseElemOf();
- switch (tp.ty)
- {
- case Tarray:
- case Tpointer:
- return traverseIndirections(tp.nextOf(), t);
-
- case Taarray:
- case Tclass:
- return traverseIndirections(tp, t);
-
- case Tstruct:
- /* Drill down and check the struct's fields
- */
- auto sym = tp.toDsymbol(null).isStructDeclaration();
- foreach (v; sym.fields)
- {
- Type tprmi = v.type.addMod(tp.mod);
- //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
- if (!traverse(tprmi, t))
- return false;
- }
- return true;
-
- default:
- return true;
- }
- }
-
- if (!traverse(tp, t))
- return false;
- }
- // The 'this' reference is a parameter, too
- if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
+ if (nothrowInprocess && !nothrowViolation)
{
- Type tthis = ad.getType().addMod(tf.mod);
- //printf("\ttthis = %s\n", tthis.toChars());
- if (!traverseIndirections(tthis, t))
- return false;
+ nothrowViolation = new AttributeViolation(loc, fd); // action that requires GC
}
-
- return true;
}
/****************************************
@@ -1633,101 +863,6 @@ extern (C++) class FuncDeclaration : Declaration
return result;
}
- /*********************************************
- * In the current function, we are calling 'this' function.
- * 1. Check to see if the current function can call 'this' function, issue error if not.
- * 2. If the current function is not the parent of 'this' function, then add
- * the current function to the list of siblings of 'this' function.
- * 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.
- */
- extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
- {
- //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
-
- if (auto fld = this.isFuncLiteralDeclaration())
- {
- if (fld.tok == TOK.reserved)
- {
- fld.tok = TOK.function_;
- fld.vthis = null;
- }
- }
-
- if (!parent || parent == sc.parent)
- return false;
- if (ident == Id.require || ident == Id.ensure)
- return false;
- if (!isThis() && !isNested())
- return false;
-
- // The current function
- FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
- if (!fdthis)
- return false; // out of function scope
-
- Dsymbol p = toParentLocal();
- Dsymbol p2 = toParent2();
-
- // Function literals from fdthis to p must be delegates
- ensureStaticLinkTo(fdthis, p);
- if (p != p2)
- ensureStaticLinkTo(fdthis, p2);
-
- if (isNested())
- {
- // 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 != this)
- {
- bool found = false;
- for (size_t i = 0; i < siblingCallers.length; ++i)
- {
- if (siblingCallers[i] == fdthis)
- found = true;
- }
- if (!found)
- {
- //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
- if (!sc.intypeof && !(sc.flags & SCOPE.compile))
- {
- siblingCallers.push(fdthis);
- computedEscapingSiblings = false;
- }
- }
- }
-
- const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
- if (lv == 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;
- }
-
/*******************************
* Look at all the variables in this function that are referenced
* by nested functions, and determine if a closure needs to be
@@ -1822,75 +957,6 @@ extern (C++) class FuncDeclaration : Declaration
}
/***********************************************
- * Check that the function contains any closure.
- * If it's @nogc, report suitable errors.
- * This is mostly consistent with FuncDeclaration::needsClosure().
- *
- * Returns:
- * true if any errors occur.
- */
- extern (C++) final bool checkClosure()
- {
- //printf("checkClosure() %s\n", toPrettyChars());
- if (!needsClosure())
- return false;
-
- if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this))
- {
- .error(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
- if (global.gag) // need not report supplemental errors
- return true;
- }
- else if (!global.params.useGC)
- {
- .error(loc, "%s `%s` is `-betterC` yet allocates closure for `%s()` with the GC", kind, toPrettyChars, toChars());
- if (global.gag) // need not report supplemental errors
- return true;
- }
- else
- {
- printGCUsage(loc, "using closure causes GC allocation");
- return false;
- }
-
- FuncDeclarations a;
- foreach (v; closureVars)
- {
- foreach (f; v.nestedrefs)
- {
- assert(f !is this);
-
- LcheckAncestorsOfANestedRef:
- for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
- {
- auto fx = s.isFuncDeclaration();
- if (!fx)
- continue;
- if (fx.isThis() ||
- fx.tookAddressOf ||
- checkEscapingSiblings(fx, this))
- {
- foreach (f2; a)
- {
- if (f2 == f)
- break LcheckAncestorsOfANestedRef;
- }
- a.push(f);
- .errorSupplemental(f.loc, "%s `%s` closes over variable `%s`",
- f.kind, f.toPrettyChars(), v.toChars());
- if (v.ident != Id.This)
- .errorSupplemental(v.loc, "`%s` declared here", v.toChars());
-
- break LcheckAncestorsOfANestedRef;
- }
- }
- }
- }
-
- return true;
- }
-
- /***********************************************
* Determine if function's variables are referenced by a function
* nested within it.
*/
@@ -1922,394 +988,6 @@ extern (C++) class FuncDeclaration : Declaration
return false;
}
- /****************************************************
- * Check whether result variable can be built.
- * Returns:
- * `true` if the function has a return type that
- * is different from `void`.
- */
- extern (D) private bool canBuildResultVar()
- {
- auto f = cast(TypeFunction)type;
- return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
- }
-
- /****************************************************
- * Merge into this function the 'in' contracts of all it overrides.
- * 'in's are OR'd together, i.e. only one of them needs to pass.
- */
- extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
- {
- /* If a base function and its override both have an IN contract, then
- * only one of them needs to succeed. This is done by generating:
- *
- * void derived.in() {
- * try {
- * base.in();
- * }
- * catch () {
- * ... body of derived.in() ...
- * }
- * }
- *
- * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
- * If base.in() throws, then derived.in()'s body is executed.
- */
-
- foreach (fdv; foverrides)
- {
- /* The semantic pass on the contracts of the overridden functions must
- * be completed before code generation occurs.
- * https://issues.dlang.org/show_bug.cgi?id=3602
- */
- if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
- {
- assert(fdv._scope);
- Scope* sc = fdv._scope.push();
- sc.stc &= ~STC.override_;
- fdv.semantic3(sc);
- sc.pop();
- }
-
- sf = fdv.mergeFrequire(sf, params);
- if (!sf || !fdv.fdrequire)
- return null;
- //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
- /* Make the call:
- * try { __require(params); }
- * catch (Throwable) { frequire; }
- */
- params = Expression.arraySyntaxCopy(params);
- Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
- Statement s2 = new ExpStatement(loc, e);
-
- auto c = new Catch(loc, getThrowable(), null, sf);
- c.internalCatch = true;
- auto catches = new Catches();
- catches.push(c);
- sf = new TryCatchStatement(loc, s2, catches);
- }
- return sf;
- }
-
- /****************************************************
- * Merge into this function the 'in' contracts of all it overrides.
- */
- extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
- {
- /* If a base function and its override both have an IN contract, then
- * the override in contract must widen the guarantee of the base contract.
- * This is checked by generating:
- *
- * void derived.in() {
- * try {
- * ... body of derived.in() ...
- * }
- * catch () {
- * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
- * base.in();
- * assert(false, "Logic error: " ~ thr.msg);
- * }
- * }
- */
-
- foreach (fdv; foverrides)
- {
- /* The semantic pass on the contracts of the overridden functions must
- * be completed before code generation occurs.
- * https://issues.dlang.org/show_bug.cgi?id=3602
- */
- if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
- {
- assert(fdv._scope);
- Scope* sc = fdv._scope.push();
- sc.stc &= ~STC.override_;
- fdv.semantic3(sc);
- sc.pop();
- }
-
- sf = fdv.mergeFrequireInclusivePreview(sf, params);
- if (sf && fdv.fdrequire)
- {
- const loc = this.fdrequire.loc;
-
- //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
- /* Make the call:
- * try { frequire; }
- * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
- */
- Identifier id = Identifier.generateId("thr");
- params = Expression.arraySyntaxCopy(params);
- Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
- Statement s2 = new ExpStatement(loc, e);
- // assert(false, ...)
- // TODO make this a runtime helper to allow:
- // - chaining the original expression
- // - nogc concatenation
- Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
- Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
-
- Statement s3 = new CompoundStatement(loc, s2, fail);
-
- auto c = new Catch(loc, getThrowable(), id, s3);
- c.internalCatch = true;
- auto catches = new Catches();
- catches.push(c);
- sf = new TryCatchStatement(loc, sf, catches);
- }
- else
- return null;
- }
- return sf;
- }
-
- /****************************************************
- * Determine whether an 'out' contract is declared inside
- * the given function or any of its overrides.
- * Params:
- * fd = the function to search
- * Returns:
- * true found an 'out' contract
- */
- static bool needsFensure(FuncDeclaration fd) @safe
- {
- if (fd.fensures)
- return true;
-
- foreach (fdv; fd.foverrides)
- {
- if (needsFensure(fdv))
- return true;
- }
- return false;
- }
-
- /****************************************************
- * Rewrite contracts as statements.
- */
- final void buildEnsureRequire()
- {
-
- if (frequires)
- {
- /* in { statements1... }
- * in { statements2... }
- * ...
- * becomes:
- * in { { statements1... } { statements2... } ... }
- */
- assert(frequires.length);
- auto loc = (*frequires)[0].loc;
- auto s = new Statements;
- foreach (r; *frequires)
- {
- s.push(new ScopeStatement(r.loc, r, r.loc));
- }
- frequire = new CompoundStatement(loc, s);
- }
-
- if (fensures)
- {
- /* out(id1) { statements1... }
- * out(id2) { statements2... }
- * ...
- * becomes:
- * out(__result) { { ref id1 = __result; { statements1... } }
- * { ref id2 = __result; { statements2... } } ... }
- */
- assert(fensures.length);
- auto loc = (*fensures)[0].ensure.loc;
- auto s = new Statements;
- foreach (r; *fensures)
- {
- if (r.id && canBuildResultVar())
- {
- auto rloc = r.ensure.loc;
- auto resultId = new IdentifierExp(rloc, Id.result);
- auto init = new ExpInitializer(rloc, resultId);
- auto stc = STC.ref_ | STC.temp | STC.result;
- auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
- auto sdecl = new ExpStatement(rloc, decl);
- s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
- }
- else
- {
- s.push(r.ensure);
- }
- }
- fensure = new CompoundStatement(loc, s);
- }
-
- if (!isVirtual())
- return;
-
- /* Rewrite contracts as nested functions, then call them. Doing it as nested
- * functions means that overriding functions can call them.
- */
- TypeFunction f = cast(TypeFunction) type;
-
- /* Make a copy of the parameters and make them all ref */
- static Parameters* toRefCopy(ParameterList parameterList)
- {
- auto result = new Parameters();
-
- foreach (n, p; parameterList)
- {
- p = p.syntaxCopy();
- if (!p.isLazy())
- p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
- p.defaultArg = null; // won't be the same with ref
- result.push(p);
- }
-
- return result;
- }
-
- if (frequire)
- {
- /* in { ... }
- * becomes:
- * void __require(ref params) { ... }
- * __require(params);
- */
- Loc loc = frequire.loc;
- fdrequireParams = new Expressions();
- if (parameters)
- {
- foreach (vd; *parameters)
- fdrequireParams.push(new VarExp(loc, vd));
- }
- auto fo = cast(TypeFunction)(originalType ? originalType : f);
- auto fparams = toRefCopy(fo.parameterList);
- auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
- tf.isnothrow = f.isnothrow;
- tf.isnogc = f.isnogc;
- tf.purity = f.purity;
- tf.trust = f.trust;
- auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
- fd.fbody = frequire;
- Statement s1 = new ExpStatement(loc, fd);
- Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
- Statement s2 = new ExpStatement(loc, e);
- frequire = new CompoundStatement(loc, s1, s2);
- fdrequire = fd;
- }
-
- /* We need to set fdensureParams here and not in the block below to
- * have the parameters available when calling a base class ensure(),
- * even if this function doesn't have an out contract.
- */
- fdensureParams = new Expressions();
- if (canBuildResultVar())
- fdensureParams.push(new IdentifierExp(loc, Id.result));
- if (parameters)
- {
- foreach (vd; *parameters)
- fdensureParams.push(new VarExp(loc, vd));
- }
-
- if (fensure)
- {
- /* out (result) { ... }
- * becomes:
- * void __ensure(ref tret result, ref params) { ... }
- * __ensure(result, params);
- */
- Loc loc = fensure.loc;
- auto fparams = new Parameters();
- if (canBuildResultVar())
- {
- Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
- fparams.push(p);
- }
- auto fo = cast(TypeFunction)(originalType ? originalType : f);
- fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
- auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
- tf.isnothrow = f.isnothrow;
- tf.isnogc = f.isnogc;
- tf.purity = f.purity;
- tf.trust = f.trust;
- auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
- fd.fbody = fensure;
- Statement s1 = new ExpStatement(loc, fd);
- Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
- Statement s2 = new ExpStatement(loc, e);
- fensure = new CompoundStatement(loc, s1, s2);
- fdensure = fd;
- }
- }
-
- /****************************************************
- * Merge into this function the 'out' contracts of all it overrides.
- * 'out's are AND'd together, i.e. all of them need to pass.
- */
- extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
- {
- /* Same comments as for mergeFrequire(), except that we take care
- * of generating a consistent reference to the 'result' local by
- * explicitly passing 'result' to the nested function as a reference
- * argument.
- * This won't work for the 'this' parameter as it would require changing
- * the semantic code for the nested function so that it looks on the parameter
- * list for the 'this' pointer, something that would need an unknown amount
- * of tweaking of various parts of the compiler that I'd rather leave alone.
- */
- foreach (fdv; foverrides)
- {
- /* The semantic pass on the contracts of the overridden functions must
- * be completed before code generation occurs.
- * https://issues.dlang.org/show_bug.cgi?id=3602 and
- * https://issues.dlang.org/show_bug.cgi?id=5230
- */
- if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
- {
- assert(fdv._scope);
- Scope* sc = fdv._scope.push();
- sc.stc &= ~STC.override_;
- fdv.semantic3(sc);
- sc.pop();
- }
-
- sf = fdv.mergeFensure(sf, oid, params);
- if (fdv.fdensure)
- {
- //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
- // Make the call: __ensure(result, params)
- params = Expression.arraySyntaxCopy(params);
- if (canBuildResultVar())
- {
- Type t1 = fdv.type.nextOf().toBasetype();
- Type t2 = this.type.nextOf().toBasetype();
- if (t1.isBaseOf(t2, null))
- {
- /* Making temporary reference variable is necessary
- * in covariant return.
- * https://issues.dlang.org/show_bug.cgi?id=5204
- * https://issues.dlang.org/show_bug.cgi?id=10479
- */
- Expression* eresult = &(*params)[0];
- auto ei = new ExpInitializer(Loc.initial, *eresult);
- auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
- v.storage_class |= STC.temp;
- auto de = new DeclarationExp(Loc.initial, v);
- auto ve = new VarExp(Loc.initial, v);
- *eresult = new CommaExp(Loc.initial, de, ve);
- }
- }
- Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
- Statement s2 = new ExpStatement(loc, e);
-
- if (sf)
- {
- sf = new CompoundStatement(sf.loc, s2, sf);
- }
- else
- sf = s2;
- }
- }
- return sf;
- }
-
/*********************************************
* Returns: the function's parameter list, and whether
* it is variadic or not.
@@ -2318,8 +996,7 @@ extern (C++) class FuncDeclaration : Declaration
{
if (type)
{
- TypeFunction fdtype = type.isTypeFunction();
- if (fdtype) // Could also be TypeError
+ if (TypeFunction fdtype = type.isTypeFunction()) // Could also be TypeError
return fdtype.parameterList;
}
@@ -2329,12 +1006,12 @@ extern (C++) class FuncDeclaration : Declaration
/**********************************
* Generate a FuncDeclaration for a runtime library function.
*/
- static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
+ extern(D) static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, STC stc = STC.none)
{
return genCfunc(fparams, treturn, Identifier.idPool(name[0 .. strlen(name)]), stc);
}
- static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
+ extern(D) static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, STC stc = STC.none)
{
FuncDeclaration fd;
TypeFunction tf;
@@ -2366,185 +1043,7 @@ extern (C++) class FuncDeclaration : Declaration
return fd;
}
- /+
- + Checks the parameter and return types iff this is a `main` function.
- +
- + The following signatures are allowed for a `D main`:
- + - Either no or a single parameter of type `string[]`
- + - Return type is either `void`, `int` or `noreturn`
- +
- + The following signatures are standard C:
- + - `int main()`
- + - `int main(int, char**)`
- +
- + This function accepts the following non-standard extensions:
- + - `char** envp` as a third parameter
- + - `void` / `noreturn` as return type
- +
- + This function will issue errors for unexpected arguments / return types.
- +/
- extern (D) final void checkMain()
- {
- if (ident != Id.main || isMember() || isNested())
- return; // Not a main function
-
- TypeFunction tf = type.toTypeFunction();
-
- Type retType = tf.nextOf();
- if (!retType)
- {
- // auto main(), check after semantic
- assert(this.inferRetType);
- return;
- }
-
- /// Checks whether `t` is equivalent to `char**`
- /// Ignores qualifiers and treats enums according to their base type
- static bool isCharPtrPtr(Type t)
- {
- auto tp = t.toBasetype().isTypePointer();
- if (!tp)
- return false;
-
- tp = tp.next.toBasetype().isTypePointer();
- if (!tp)
- return false;
-
- return tp.next.toBasetype().ty == Tchar;
- }
-
- // Neither of these qualifiers is allowed because they affect the ABI
- enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
-
- const nparams = tf.parameterList.length;
- bool argerr;
-
- const linkage = resolvedLinkage();
- if (linkage == LINK.d)
- {
- if (nparams == 1)
- {
- auto fparam0 = tf.parameterList[0];
- auto t = fparam0.type.toBasetype();
- if (t.ty != Tarray ||
- t.nextOf().ty != Tarray ||
- t.nextOf().nextOf().ty != Tchar ||
- fparam0.storageClass & invalidSTC)
- {
- argerr = true;
- }
- }
-
- if (tf.parameterList.varargs || nparams >= 2 || argerr)
- .error(loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind, toPrettyChars);
- }
-
- else if (linkage == LINK.c)
- {
- if (nparams == 2 || nparams == 3)
- {
- // Argument count must be int
- auto argCount = tf.parameterList[0];
- argerr |= !!(argCount.storageClass & invalidSTC);
- argerr |= argCount.type.toBasetype().ty != Tint32;
-
- // Argument pointer must be char**
- auto argPtr = tf.parameterList[1];
- argerr |= !!(argPtr.storageClass & invalidSTC);
- argerr |= !isCharPtrPtr(argPtr.type);
-
- // `char** environ` is a common extension, see J.5.1 of the C standard
- if (nparams == 3)
- {
- auto envPtr = tf.parameterList[2];
- argerr |= !!(envPtr.storageClass & invalidSTC);
- argerr |= !isCharPtrPtr(envPtr.type);
- }
- }
- else
- argerr = nparams != 0;
-
- // Disallow variadic main() - except for K&R declarations in C files.
- // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
- if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
- argerr |= true;
-
- if (argerr)
- {
- .error(loc, "%s `%s` parameters must match one of the following signatures", kind, toPrettyChars);
- loc.errorSupplemental("`main()`");
- loc.errorSupplemental("`main(int argc, char** argv)`");
- loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
- }
- }
- else
- return; // Neither C nor D main, ignore (should probably be an error)
-
- // Allow enums with appropriate base types (same ABI)
- retType = retType.toBasetype();
-
- if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
- .error(loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind, toPrettyChars, tf.nextOf().toChars());
- }
-
- /***********************************************
- * Check all return statements for a function to verify that returning
- * using NRVO is possible.
- *
- * Returns:
- * `false` if the result cannot be returned by hidden reference.
- */
- extern (D) final bool checkNRVO()
- {
- if (!isNRVO() || returns is null)
- return false;
-
- auto tf = type.toTypeFunction();
- if (tf.isref)
- return false;
-
- foreach (rs; *returns)
- {
- if (auto ve = rs.exp.isVarExp())
- {
- auto v = ve.var.isVarDeclaration();
- if (!v || v.isReference())
- return false;
- else if (nrvo_var is null)
- {
- // Variables in the data segment (e.g. globals, TLS or not),
- // parameters and closure variables cannot be NRVOed.
- if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
- return false;
- if (v.nestedrefs.length && needsClosure())
- return false;
- // don't know if the return storage is aligned
- version (MARS)
- {
- if (alignSectionVars && (*alignSectionVars).contains(v))
- return false;
- }
- // The variable type needs to be equivalent to the return type.
- if (!v.type.equivalent(tf.next))
- return false;
- //printf("Setting nrvo to %s\n", v.toChars());
- nrvo_var = v;
- }
- else if (nrvo_var != v)
- return false;
- }
- else //if (!exp.isLvalue()) // keep NRVO-ability
- return false;
- }
- return true;
- }
-
- override final inout(FuncDeclaration) isFuncDeclaration() inout
- {
- return this;
- }
-
- inout(FuncDeclaration) toAliasFunc() inout
+ inout(FuncDeclaration) toAliasFunc() inout @safe
{
return this;
}
@@ -2555,118 +1054,6 @@ extern (C++) class FuncDeclaration : Declaration
}
}
-/***************************************************
- * Visit each overloaded function/template in turn, and call dg(s) on it.
- * Exit when no more, or dg(s) returns nonzero.
- *
- * Params:
- * fstart = symbol to start from
- * dg = the delegate to be called on the overload
- * sc = context used to check if symbol is accessible (and therefore visible),
- * can be null
- *
- * Returns:
- * ==0 continue
- * !=0 done (and the return value from the last dg() call)
- */
-extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
-{
- Dsymbols visited;
-
- int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
- {
- // Detect cyclic calls.
- if (visited.contains(fstart))
- return 0;
- visited.push(fstart);
-
- Dsymbol next;
- for (auto d = fstart; d; d = next)
- {
- import dmd.access : checkSymbolAccess;
- if (auto od = d.isOverDeclaration())
- {
- /* The scope is needed here to check whether a function in
- an overload set was added by means of a private alias (or a
- selective import). If the scope where the alias is created
- is imported somewhere, the overload set is visible, but the private
- alias is not.
- */
- if (sc)
- {
- if (checkSymbolAccess(sc, od))
- {
- if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
- return r;
- }
- }
- else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
- return r;
- next = od.overnext;
- }
- else if (auto fa = d.isFuncAliasDeclaration())
- {
- if (fa.hasOverloads)
- {
- if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
- return r;
- }
- else if (auto fd = fa.toAliasFunc())
- {
- if (int r = dg(fd))
- return r;
- }
- else
- {
- .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
- break;
- }
- next = fa.overnext;
- }
- else if (auto ad = d.isAliasDeclaration())
- {
- if (sc)
- {
- if (checkSymbolAccess(sc, ad))
- next = ad.toAlias();
- }
- else
- next = ad.toAlias();
- if (next == ad)
- break;
- if (next == fstart)
- break;
- }
- else if (auto td = d.isTemplateDeclaration())
- {
- if (int r = dg(td))
- return r;
- next = td.overnext;
- }
- else if (auto fd = d.isFuncDeclaration())
- {
- if (int r = dg(fd))
- return r;
- next = fd.overnext;
- }
- else if (auto os = d.isOverloadSet())
- {
- foreach (ds; os.a)
- if (int r = dg(ds))
- return r;
- }
- else
- {
- .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
- break;
- // BUG: should print error message?
- }
- }
- return 0;
- }
- return overloadApplyRecurse(fstart, dg, sc);
-}
-
/**
Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
mismatching modifiers to `buf`.
@@ -2748,133 +1135,6 @@ unittest
assert(mismatches.isMutable);
}
-/**************************************
- * Returns an indirect type one step from t.
- */
-Type getIndirection(Type t)
-{
- t = t.baseElemOf();
- if (t.ty == Tarray || t.ty == Tpointer)
- return t.nextOf().toBasetype();
- if (t.ty == Taarray || t.ty == Tclass)
- return t;
- if (t.ty == Tstruct)
- return t.hasPointers() ? t : null; // TODO
-
- // should consider TypeDelegate?
- return null;
-}
-
-/**************************************
- * Performs type-based alias analysis between a newly created value and a pre-
- * existing memory reference:
- *
- * Assuming that a reference A to a value of type `ta` was available to the code
- * that created a reference B to a value of type `tb`, it returns whether B
- * might alias memory reachable from A based on the types involved (either
- * directly or via any number of indirections in either A or B).
- *
- * This relation is not symmetric in the two arguments. For example, a
- * a `const(int)` reference can point to a pre-existing `int`, but not the other
- * way round.
- *
- * Examples:
- *
- * ta, tb, result
- * `const(int)`, `int`, `false`
- * `int`, `const(int)`, `true`
- * `int`, `immutable(int)`, `false`
- * const(immutable(int)*), immutable(int)*, false // BUG: returns true
- *
- * Params:
- * ta = value type being referred to
- * tb = referred to value type that could be constructed from ta
- *
- * Returns:
- * true if reference to `tb` is isolated from reference to `ta`
- */
-private bool traverseIndirections(Type ta, Type tb)
-{
- //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
-
- static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
- {
- //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
- ta = ta.baseElemOf();
- tb = tb.baseElemOf();
-
- // First, check if the pointed-to types are convertible to each other such
- // that they might alias directly.
- static bool mayAliasDirect(Type source, Type target)
- {
- return
- // if source is the same as target or can be const-converted to target
- source.constConv(target) != MATCH.nomatch ||
- // if target is void and source can be const-converted to target
- (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
- }
-
- if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
- {
- //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
- return false;
- }
- if (ta.nextOf() && ta.nextOf() == tb.nextOf())
- {
- //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
- return true;
- }
-
- if (tb.ty == Tclass || tb.ty == Tstruct)
- {
- /* Traverse the type of each field of the aggregate
- */
- bool* found = table.getLvalue(tb.deco);
- if (*found == true)
- return true; // We have already seen this symbol, break the cycle
- else
- *found = true;
-
- AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
- foreach (v; sym.fields)
- {
- Type tprmi = v.type.addMod(tb.mod);
- //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
- if (!traverse(ta, tprmi, table, reversePass))
- return false;
- }
- }
- else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
- {
- Type tind = tb.nextOf();
- if (!traverse(ta, tind, table, reversePass))
- return false;
- }
- else if (tb.hasPointers())
- {
- // BUG: consider the context pointer of delegate types
- return false;
- }
-
- // Still no match, so try breaking up ta if we have not done so yet.
- if (!reversePass)
- {
- scope newTable = AssocArray!(const(char)*, bool)();
- return traverse(tb, ta, newTable, true);
- }
-
- return true;
- }
-
- // To handle arbitrary levels of indirections in both parameters, we
- // recursively descend into aggregate members/levels of indirection in both
- // `ta` and `tb` while avoiding cycles. Start with the original types.
- scope table = AssocArray!(const(char)*, bool)();
- const result = traverse(ta, tb, table, false);
- //printf(" returns %d\n", result);
- return result;
-}
-
/* For all functions between outerFunc and f, mark them as needing
* a closure.
*/
@@ -2907,7 +1167,7 @@ private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
* Returns:
* true if any closures were needed
*/
-private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
+bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
{
static struct PrevSibling
{
@@ -2978,6 +1238,7 @@ extern (C++) final class FuncAliasDeclaration : FuncDeclaration
super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
assert(funcalias != this);
this.funcalias = funcalias;
+ this.dsym = DSYM.funcAliasDeclaration;
this.hasOverloads = hasOverloads;
if (hasOverloads)
@@ -2994,11 +1255,6 @@ extern (C++) final class FuncAliasDeclaration : FuncDeclaration
userAttribDecl = funcalias.userAttribDecl;
}
- override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
- {
- return this;
- }
-
override const(char)* kind() const
{
return "function alias";
@@ -3025,15 +1281,16 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
// backend
bool deferToObj;
- extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null, StorageClass storage_class = STC.undefined_)
+ extern (D) this(Loc loc, Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null, STC storage_class = STC.none)
{
super(loc, endloc, null, storage_class, type);
+ this.dsym = DSYM.funcLiteralDeclaration;
this.ident = id ? id : Id.empty;
this.tok = tok;
this.fes = fes;
// Always infer scope for function literals
// See https://issues.dlang.org/show_bug.cgi?id=20362
- this.inferScope = true;
+ this.scopeInprocess = true;
//printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
}
@@ -3073,61 +1330,6 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
return false;
}
- /*******************************
- * Modify all expression type of return statements to tret.
- *
- * On function literals, return type may be modified based on the context type
- * after its semantic3 is done, in FuncExp::implicitCastTo.
- *
- * A function() dg = (){ return new B(); } // OK if is(B : A) == true
- *
- * If B to A conversion is convariant that requires offseet adjusting,
- * all return statements should be adjusted to return expressions typed A.
- */
- extern (D) void modifyReturns(Scope* sc, Type tret)
- {
- import dmd.statement_rewrite_walker;
-
- extern (C++) final class RetWalker : StatementRewriteWalker
- {
- alias visit = typeof(super).visit;
- public:
- Scope* sc;
- Type tret;
- FuncLiteralDeclaration fld;
-
- override void visit(ReturnStatement s)
- {
- Expression exp = s.exp;
- if (exp && !exp.type.equals(tret))
- s.exp = exp.implicitCastTo(sc, tret);
- }
- }
-
- if (semanticRun < PASS.semantic3done)
- return;
-
- if (fes)
- return;
-
- scope RetWalker w = new RetWalker();
- w.sc = sc;
- w.tret = tret;
- w.fld = this;
- fbody.accept(w);
-
- // Also update the inferred function type to match the new return type.
- // This is required so the code generator does not try to cast the
- // modified returns back to the original type.
- if (inferRetType && type.nextOf() != tret)
- type.toTypeFunction().next = tret;
- }
-
- override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
- {
- return this;
- }
-
override const(char)* kind() const
{
// GCC requires the (char*) casts
@@ -3138,8 +1340,7 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
{
if (parent)
{
- TemplateInstance ti = parent.isTemplateInstance();
- if (ti)
+ if (TemplateInstance ti = parent.isTemplateInstance())
return ti.tempdecl.toPrettyChars(QualifyTypes);
}
return Dsymbol.toPrettyChars(QualifyTypes);
@@ -3155,11 +1356,12 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
*/
extern (C++) final class CtorDeclaration : FuncDeclaration
{
- bool isCpCtor;
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
+ bool isCpCtor; // copy constructor
+ bool isMoveCtor; // move constructor (aka rvalue constructor)
+ extern (D) this(Loc loc, Loc endloc, STC stc, Type type)
{
super(loc, endloc, Id.ctor, stc, type);
- this.isCpCtor = isCpCtor;
+ this.dsym = DSYM.ctorDeclaration;
//printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this);
}
@@ -3176,11 +1378,6 @@ extern (C++) final class CtorDeclaration : FuncDeclaration
return isCpCtor ? "copy constructor" : "constructor";
}
- override const(char)* toChars() const
- {
- return "this";
- }
-
override bool isVirtual() const
{
return false;
@@ -3196,11 +1393,6 @@ extern (C++) final class CtorDeclaration : FuncDeclaration
return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
}
- override inout(CtorDeclaration) isCtorDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3211,9 +1403,10 @@ extern (C++) final class CtorDeclaration : FuncDeclaration
*/
extern (C++) final class PostBlitDeclaration : FuncDeclaration
{
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
+ extern (D) this(Loc loc, Loc endloc, STC stc, Identifier id)
{
super(loc, endloc, id, stc, null);
+ this.dsym = DSYM.postBlitDeclaration;
}
override PostBlitDeclaration syntaxCopy(Dsymbol s)
@@ -3244,11 +1437,6 @@ extern (C++) final class PostBlitDeclaration : FuncDeclaration
return false; // cannot overload postblits
}
- override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3259,14 +1447,16 @@ extern (C++) final class PostBlitDeclaration : FuncDeclaration
*/
extern (C++) final class DtorDeclaration : FuncDeclaration
{
- extern (D) this(const ref Loc loc, const ref Loc endloc)
+ extern (D) this(Loc loc, Loc endloc)
{
- super(loc, endloc, Id.dtor, STC.undefined_, null);
+ super(loc, endloc, Id.dtor, STC.none, null);
+ this.dsym = DSYM.dtorDeclaration;
}
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
+ extern (D) this(Loc loc, Loc endloc, STC stc, Identifier id)
{
super(loc, endloc, id, stc, null);
+ this.dsym = DSYM.dtorDeclaration;
}
override DtorDeclaration syntaxCopy(Dsymbol s)
@@ -3282,11 +1472,6 @@ extern (C++) final class DtorDeclaration : FuncDeclaration
return "destructor";
}
- override const(char)* toChars() const
- {
- return "~this";
- }
-
override bool isVirtual() const
{
// D dtor's don't get put into the vtbl[]
@@ -3309,11 +1494,6 @@ extern (C++) final class DtorDeclaration : FuncDeclaration
return false; // cannot overload destructors
}
- override inout(DtorDeclaration) isDtorDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3324,14 +1504,16 @@ extern (C++) final class DtorDeclaration : FuncDeclaration
*/
extern (C++) class StaticCtorDeclaration : FuncDeclaration
{
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
+ extern (D) this(Loc loc, Loc endloc, STC stc)
{
super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
+ this.dsym = DSYM.staticCtorDeclaration;
}
- extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
+ extern (D) this(Loc loc, Loc endloc, string name, STC stc)
{
super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
+ this.dsym = DSYM.staticCtorDeclaration;
}
override StaticCtorDeclaration syntaxCopy(Dsymbol s)
@@ -3362,16 +1544,6 @@ extern (C++) class StaticCtorDeclaration : FuncDeclaration
return false;
}
- override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
- {
- return true;
- }
-
- override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3385,9 +1557,10 @@ extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
/// Exclude this constructor from cyclic dependency check
bool standalone;
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
+ extern (D) this(Loc loc, Loc endloc, STC stc)
{
super(loc, endloc, "_sharedStaticCtor", stc);
+ this.dsym = DSYM.sharedStaticCtorDeclaration;
}
override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
@@ -3398,11 +1571,6 @@ extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
return scd;
}
- override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3415,14 +1583,16 @@ extern (C++) class StaticDtorDeclaration : FuncDeclaration
{
VarDeclaration vgate; // 'gate' variable
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
+ extern (D) this(Loc loc, Loc endloc, STC stc)
{
super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
+ this.dsym = DSYM.staticDtorDeclaration;
}
- extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
+ extern (D) this(Loc loc, Loc endloc, string name, STC stc)
{
super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
+ this.dsym = DSYM.staticDtorDeclaration;
}
override StaticDtorDeclaration syntaxCopy(Dsymbol s)
@@ -3443,11 +1613,6 @@ extern (C++) class StaticDtorDeclaration : FuncDeclaration
return false;
}
- override final bool hasStaticCtorOrDtor()
- {
- return true;
- }
-
override final bool addPreInvariant()
{
return false;
@@ -3458,11 +1623,6 @@ extern (C++) class StaticDtorDeclaration : FuncDeclaration
return false;
}
- override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3473,9 +1633,10 @@ extern (C++) class StaticDtorDeclaration : FuncDeclaration
*/
extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
{
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
+ extern (D) this(Loc loc, Loc endloc, STC stc)
{
super(loc, endloc, "_sharedStaticDtor", stc);
+ this.dsym = DSYM.sharedStaticDtorDeclaration;
}
override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
@@ -3486,11 +1647,6 @@ extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
return sdd;
}
- override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3501,11 +1657,12 @@ extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
*/
extern (C++) final class InvariantDeclaration : FuncDeclaration
{
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
+ extern (D) this(Loc loc, Loc endloc, STC stc, Identifier id, Statement fbody)
{
// Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
this.fbody = fbody;
+ this.dsym = DSYM.invariantDeclaration;
}
override InvariantDeclaration syntaxCopy(Dsymbol s)
@@ -3531,11 +1688,6 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration
return false;
}
- override inout(InvariantDeclaration) isInvariantDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3561,10 +1713,11 @@ extern (C++) final class UnitTestDeclaration : FuncDeclaration
// toObjFile() these nested functions after this one
FuncDeclarations deferredNested;
- extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
+ extern (D) this(Loc loc, Loc endloc, STC stc, char* codedoc)
{
super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
this.codedoc = codedoc;
+ this.dsym = DSYM.unitTestDeclaration;
}
override UnitTestDeclaration syntaxCopy(Dsymbol s)
@@ -3595,11 +1748,6 @@ extern (C++) final class UnitTestDeclaration : FuncDeclaration
return false;
}
- override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3610,9 +1758,10 @@ extern (C++) final class UnitTestDeclaration : FuncDeclaration
*/
extern (C++) final class NewDeclaration : FuncDeclaration
{
- extern (D) this(const ref Loc loc, StorageClass stc)
+ extern (D) this(Loc loc, STC stc)
{
super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
+ this.dsym = DSYM.newDeclaration;
}
override NewDeclaration syntaxCopy(Dsymbol s)
@@ -3643,230 +1792,42 @@ extern (C++) final class NewDeclaration : FuncDeclaration
return false;
}
- override inout(NewDeclaration) isNewDeclaration() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
}
}
-/**************************************
- * When a traits(compiles) is used on a function literal call
- * we need to take into account if the body of the function
- * violates any attributes, however, we must not affect the
- * attribute inference on the outer function. The attributes
- * of the function literal still need to be inferred, therefore
- * we need a way to check for the scope that the traits compiles
- * introduces.
- *
- * Params:
- * sc = scope to be checked for
- *
- * Returns: `true` if the provided scope is the root
- * of the traits compiles list of scopes.
- */
-bool isRootTraitsCompilesScope(Scope* sc)
-{
- return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
-}
-
-/**************************************
- * A statement / expression in this scope is not `@safe`,
- * so mark the enclosing function as `@system`
- *
- * Params:
- * sc = scope that the unsafe statement / expression is in
- * gag = surpress error message (used in escape.d)
- * loc = location of error
- * fmt = printf-style format string
- * arg0 = (optional) argument for first %s format specifier
- * arg1 = (optional) argument for second %s format specifier
- * arg2 = (optional) argument for third %s format specifier
- * Returns: whether there's a safe error
- */
-bool setUnsafe(Scope* sc,
- bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
- RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
-{
- if (sc.intypeof)
- return false; // typeof(cast(int*)0) is safe
-
- if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
- return false;
-
- if (!sc.func)
- {
- if (sc.varDecl)
- {
- if (sc.varDecl.storage_class & STC.safe)
- {
- .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
- return true;
- }
- else if (!(sc.varDecl.storage_class & STC.trusted))
- {
- sc.varDecl.storage_class |= STC.system;
- sc.varDecl.systemInferred = true;
- }
- }
- return false;
- }
-
-
- if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
- {
- if (sc.func.isSafeBypassingInference())
- {
- // Message wil be gagged, but still call error() to update global.errors and for
- // -verrors=spec
- .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
- return true;
- }
- return false;
- }
-
- return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
-}
-
-/***************************************
- * Like `setUnsafe`, but for safety errors still behind preview switches
- *
- * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
- * the behavior changes based on the setting:
- *
- * - In case of `-revert=fs`, it does nothing.
- * - In case of `-preview=fs`, it's the same as `setUnsafe`
- * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
- *
- * Params:
- * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
- * fs = feature state from the preview flag
- * gag = surpress error message
- * loc = location of error
- * msg = printf-style format string
- * arg0 = (optional) argument for first %s format specifier
- * arg1 = (optional) argument for second %s format specifier
- * arg2 = (optional) argument for third %s format specifier
- * Returns: whether an actual safe error (not deprecation) occured
- */
-bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
- RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
-{
- //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
- with (FeatureState) final switch (fs)
- {
- case disabled:
- return false;
-
- case enabled:
- return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
-
- case default_:
- if (!sc.func)
- return false;
- if (sc.func.isSafeBypassingInference())
- {
- if (!gag && !sc.isDeprecated())
- {
- deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
- }
- }
- else if (!sc.func.safetyViolation)
- {
- import dmd.func : AttributeViolation;
- sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
- }
- return false;
- }
-}
-
/// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
///
/// Has two modes:
-/// - a regular safety error, stored in (fmtStr, arg0, arg1)
+/// - a regular safety error, stored in `action`
/// - a call to a function without the attribute, which is a special case, because in that case,
/// that function might recursively also have a `AttributeViolation`. This way, in case
/// of a big call stack, the error can go down all the way to the root cause.
-/// The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
struct AttributeViolation
{
- /// location of error
- Loc loc = Loc.init;
- /// printf-style format string
- const(char)* fmtStr = null;
- /// Arguments for up to two `%s` format specifiers in format string
- RootObject arg0 = null;
- /// ditto
- RootObject arg1 = null;
- /// ditto
- RootObject arg2 = null;
-}
+ Loc loc; /// location of error
-/// Print the reason why `fd` was inferred `@system` as a supplemental error
-/// Params:
-/// fd = function to check
-/// maxDepth = up to how many functions deep to report errors
-/// deprecation = print deprecations instead of errors
-/// stc = storage class of attribute to check
-void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
-{
- auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
+ FuncDeclaration fd; /// function is the focus of the violation
- AttributeViolation* s;
- const(char)* attr;
- if (stc & STC.safe)
- {
- s = fd.safetyViolation;
- attr = "@safe";
- }
- else if (stc & STC.pure_)
- {
- s = fd.pureViolation;
- attr = "pure";
- }
- else if (stc & STC.nothrow_)
- {
- s = fd.nothrowViolation;
- attr = "nothrow";
- }
- else if (stc & STC.nogc)
- {
- s = fd.nogcViolation;
- attr = "@nogc";
- }
+ // -- OR --
- if (s)
+ string action; /// Action that made the attribute fail to get inferred
+
+ this(Loc loc, FuncDeclaration fd) { this.loc = loc; this.fd = fd; }
+
+ this(Loc loc, const(char)* fmt, RootObject[] args)
{
- if (s.fmtStr)
- {
- errorFunc(s.loc, deprecation ?
- "which wouldn't be `%s` because of:" :
- "which wasn't inferred `%s` because of:", attr);
- if (stc == STC.nogc || stc == STC.pure_)
- {
- auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
- errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
- }
- else
- {
- errorFunc(s.loc, s.fmtStr,
- s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
- }
- }
- else if (auto sa = s.arg0.isDsymbol())
- {
- if (FuncDeclaration fd2 = sa.isFuncDeclaration())
- {
- if (maxDepth > 0)
- {
- errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
- errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);
- }
- }
- }
+ this.loc = loc;
+ assert(args.length <= 4); // expand if necessary
+ OutBuffer buf;
+ buf.printf(fmt,
+ args.length > 0 && args[0] ? args[0].toErrMsg() : "",
+ args.length > 1 && args[1] ? args[1].toErrMsg() : "",
+ args.length > 2 && args[2] ? args[2].toErrMsg() : "",
+ args.length > 3 && args[3] ? args[3].toErrMsg() : "",
+ );
+ this.action = buf.extractSlice();
}
}
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
index 2cadc40..1231496 100644
--- a/gcc/d/dmd/funcsem.d
+++ b/gcc/d/dmd/funcsem.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/function.html, Functions)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/funcsem.d, _funcsem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/funcsem.d, _funcsem.d)
* Documentation: https://dlang.org/phobos/dmd_funcsem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/funcsem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/funcsem.d
*/
module dmd.funcsem;
@@ -54,9 +54,9 @@ import dmd.rootobject;
import dmd.root.filename;
import dmd.root.string;
import dmd.root.stringtable;
+import dmd.safe;
import dmd.semantic2;
import dmd.semantic3;
-import dmd.statement_rewrite_walker;
import dmd.statement;
import dmd.statementsem;
import dmd.target;
@@ -64,6 +64,11 @@ import dmd.templatesem;
import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
+import dmd.visitor.statement_rewrite_walker;
+
+version (IN_GCC) {}
+else version (IN_LLVM) {}
+else version = MARS;
/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
*/
@@ -149,6 +154,28 @@ public:
}
}
+/****************************************
+ * Only one entry point function is allowed. Print error if more than one.
+ * Params:
+ * fd = a "main" function
+ * Returns:
+ * true if haven't seen "main" before
+ */
+extern (C++) bool onlyOneMain(FuncDeclaration fd)
+{
+ if (auto lastMain = FuncDeclaration.lastMain)
+ {
+ const format = (target.os == Target.OS.Windows)
+ ? "only one entry point `main`, `WinMain` or `DllMain` is allowed"
+ : "only one entry point `main` is allowed";
+ error(fd.loc, format.ptr);
+ errorSupplemental(lastMain.loc, "previously found `%s` here", lastMain.toFullSignature());
+ return false;
+ }
+ FuncDeclaration.lastMain = fd;
+ return true;
+}
+
/**********************************
* Main semantic routine for functions.
*/
@@ -210,11 +237,11 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
//printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal());
- if (sc.flags & SCOPE.compile)
+ if (sc.traitsCompiles)
funcdecl.skipCodegen = true;
funcdecl._linkage = sc.linkage;
- if (sc.flags & SCOPE.Cfile && funcdecl.isFuncLiteralDeclaration())
+ if (sc.inCfile && funcdecl.isFuncLiteralDeclaration())
funcdecl._linkage = LINK.d; // so they are uniquely mangled
if (auto fld = funcdecl.isFuncLiteralDeclaration())
@@ -239,7 +266,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
funcdecl.visibility = sc.visibility;
funcdecl.userAttribDecl = sc.userAttribDecl;
- UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl._linkage);
+ checkGNUABITag(funcdecl, funcdecl._linkage);
checkMustUseReserved(funcdecl);
if (!funcdecl.originalType)
@@ -259,7 +286,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
return null;
}
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* C11 allows a function to be declared with a typedef, D does not.
*/
@@ -328,15 +355,15 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
}
}
- if (tf.isref)
+ if (tf.isRef)
sc.stc |= STC.ref_;
if (tf.isScopeQual)
sc.stc |= STC.scope_;
- if (tf.isnothrow)
+ if (tf.isNothrow)
sc.stc |= STC.nothrow_;
- if (tf.isnogc)
+ if (tf.isNogc)
sc.stc |= STC.nogc;
- if (tf.isproperty)
+ if (tf.isProperty)
sc.stc |= STC.property;
if (tf.purity == PURE.fwdref)
sc.stc |= STC.pure_;
@@ -354,7 +381,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
if (funcdecl.isCtorDeclaration())
{
- tf.isctor = true;
+ tf.isCtor = true;
Type tret = ad.handleType();
assert(tret);
tret = tret.addStorageClass(funcdecl.storage_class | sc.stc);
@@ -365,7 +392,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
}
// 'return' on a non-static class member function implies 'scope' as well
- if (ad && ad.isClassDeclaration() && (tf.isreturn || sc.stc & STC.return_) && !(sc.stc & STC.static_))
+ if (ad && ad.isClassDeclaration() && (tf.isReturn || sc.stc & STC.return_) && !(sc.stc & STC.static_))
sc.stc |= STC.scope_;
// If 'this' has no pointers, remove 'scope' as it has no meaning
@@ -376,11 +403,11 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
{
sc.stc &= ~STC.scope_;
tf.isScopeQual = false;
- if (tf.isreturnscope)
+ if (tf.isReturnScope)
{
sc.stc &= ~(STC.return_ | STC.returnScope);
- tf.isreturn = false;
- tf.isreturnscope = false;
+ tf.isReturn = false;
+ tf.isReturnScope = false;
}
}
@@ -426,12 +453,12 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
TypeFunction tfo = funcdecl.originalType.toTypeFunction();
tfo.mod = f.mod;
tfo.isScopeQual = f.isScopeQual;
- tfo.isreturninferred = f.isreturninferred;
- tfo.isscopeinferred = f.isscopeinferred;
- tfo.isref = f.isref;
- tfo.isnothrow = f.isnothrow;
- tfo.isnogc = f.isnogc;
- tfo.isproperty = f.isproperty;
+ tfo.isReturnInferred = f.isReturnInferred;
+ tfo.isScopeInferred = f.isScopeInferred;
+ tfo.isRef = f.isRef;
+ tfo.isNothrow = f.isNothrow;
+ tfo.isNogc = f.isNogc;
+ tfo.isProperty = f.isProperty;
tfo.purity = f.purity;
tfo.trust = f.trust;
@@ -468,10 +495,10 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
funcdecl.overnext = null; // don't overload the redeclarations
}
- if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType)
+ if ((funcdecl.storage_class & STC.auto_) && !f.isRef && !funcdecl.inferRetType)
.error(funcdecl.loc, "%s `%s` storage class `auto` has no effect if return type is not inferred", funcdecl.kind, funcdecl.toPrettyChars);
- if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested())
+ if (f.isReturn && !funcdecl.needThis() && !funcdecl.isNested())
{
/* Non-static nested functions have a hidden 'this' pointer to which
* the 'return' applies
@@ -742,7 +769,10 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
{
if (fdv.isFuture())
{
- deprecation(funcdecl.loc, "`@__future` base class method `%s` is being overridden by `%s`; rename the latter", fdv.toPrettyChars(), funcdecl.toPrettyChars());
+ deprecation(funcdecl.loc, "method `%s` implicitly overrides `@__future` base class method; rename the former",
+ funcdecl.toPrettyChars());
+ deprecationSupplemental(fdv.loc, "base method `%s` defined here",
+ fdv.toPrettyChars());
// Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[]
goto Lintro;
}
@@ -1040,8 +1070,7 @@ Ldone:
}
// If it's a member template
- ClassDeclaration cd = ti.tempdecl.isClassMember();
- if (cd)
+ if (ClassDeclaration cd = ti.tempdecl.isClassMember())
{
.error(funcdecl.loc, "%s `%s` cannot use template to add virtual function to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars());
}
@@ -1074,7 +1103,7 @@ Ldone:
{
printedMain = true;
auto name = mod.srcfile.toChars();
- auto path = FileName.searchPath(global.path, name, true);
+ auto path = FileName.searchPath(global.importPaths, name, true);
message("entry %-10s\t%s", type, path ? path : name);
}
}
@@ -1117,6 +1146,28 @@ Ldone:
}
}
+/*****************************************
+ * Initialize for inferring the attributes of this function.
+ */
+private void initInferAttributes(FuncDeclaration fd)
+{
+ //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
+ TypeFunction tf = fd.type.toTypeFunction();
+ if (tf.purity == PURE.impure) // purity not specified
+ fd.purityInprocess = true;
+
+ if (tf.trust == TRUST.default_)
+ fd.safetyInprocess = true;
+
+ if (!tf.isNothrow)
+ fd.nothrowInprocess = true;
+
+ if (!tf.isNogc)
+ fd.nogcInprocess = true;
+
+ // Initialize for inferring STC.scope_
+ fd.scopeInprocess = true;
+}
/****************************************************
* Resolve forward reference of function signature -
@@ -1138,8 +1189,8 @@ bool functionSemantic(FuncDeclaration fd)
if (!fd.originalType) // semantic not yet run
{
TemplateInstance spec = fd.isSpeculative();
- uint olderrs = global.errors;
- uint oldgag = global.gag;
+ const olderrs = global.errors;
+ const oldgag = global.gag;
if (global.gag && !spec)
global.gag = 0;
dsymbolSemantic(fd, fd._scope);
@@ -1194,8 +1245,8 @@ bool functionSemantic3(FuncDeclaration fd)
* we need to temporarily ungag errors.
*/
TemplateInstance spec = fd.isSpeculative();
- uint olderrs = global.errors;
- uint oldgag = global.gag;
+ const olderrs = global.errors;
+ const oldgag = global.gag;
if (global.gag && !spec)
global.gag = 0;
semantic3(fd, fd._scope);
@@ -1224,6 +1275,7 @@ extern (D) void declareThis(FuncDeclaration fd, Scope* sc)
const bool dualCtx = (fd.toParent2() != fd.toParentLocal());
if (dualCtx)
fd.hasDualContext = true;
+
auto ad = fd.isThis();
if (!dualCtx && !ad && !fd.isNested())
{
@@ -1262,11 +1314,11 @@ extern (D) void declareThis(FuncDeclaration fd, Scope* sc)
if (auto tf = fd.type.isTypeFunction())
{
- if (tf.isreturn)
+ if (tf.isReturn)
fd.vthis.storage_class |= STC.return_;
if (tf.isScopeQual)
fd.vthis.storage_class |= STC.scope_;
- if (tf.isreturnscope)
+ if (tf.isReturnScope)
fd.vthis.storage_class |= STC.returnScope;
}
@@ -1282,7 +1334,7 @@ extern (D) void declareThis(FuncDeclaration fd, Scope* sc)
* Check that this function type is properly resolved.
* If not, report "forward reference error" and return true.
*/
-extern (D) bool checkForwardRef(FuncDeclaration fd, const ref Loc loc)
+extern (D) bool checkForwardRef(FuncDeclaration fd, Loc loc)
{
if (!functionSemantic(fd))
return true;
@@ -1318,66 +1370,66 @@ int findVtblIndex(FuncDeclaration fd, Dsymbol[] vtbl)
import dmd.typesem : covariant;
FuncDeclaration mismatch = null;
- StorageClass mismatchstc = 0;
+ STC mismatchstc = STC.none;
int mismatchvi = -1;
int exactvi = -1;
int bestvi = -1;
for (int vi = 0; vi < cast(int)vtbl.length; vi++)
{
FuncDeclaration fdv = vtbl[vi].isFuncDeclaration();
- if (fdv && fdv.ident == fd.ident)
+ if (!fdv || fdv.ident != fd.ident)
+ continue;
+
+ if (fd.type.equals(fdv.type)) // if exact match
{
- if (fd.type.equals(fdv.type)) // if exact match
+ if (fdv.parent.isClassDeclaration())
{
- if (fdv.parent.isClassDeclaration())
- {
- if (fdv.isFuture())
- {
- bestvi = vi;
- continue; // keep looking
- }
- return vi; // no need to look further
- }
-
- if (exactvi >= 0)
+ if (fdv.isFuture())
{
- .error(fd.loc, "%s `%s` cannot determine overridden function", fd.kind, fd.toPrettyChars);
- return exactvi;
+ bestvi = vi;
+ continue; // keep looking
}
- exactvi = vi;
- bestvi = vi;
- continue;
+ return vi; // no need to look further
}
- StorageClass stc = 0;
- const cov = fd.type.covariant(fdv.type, &stc);
- //printf("\tbaseclass cov = %d\n", cov);
- final switch (cov)
+ if (exactvi >= 0)
{
- case Covariant.distinct:
- // types are distinct
- break;
+ .error(fd.loc, "%s `%s` cannot determine overridden function", fd.kind, fd.toPrettyChars);
+ return exactvi;
+ }
+ exactvi = vi;
+ bestvi = vi;
+ continue;
+ }
- case Covariant.yes:
- bestvi = vi; // covariant, but not identical
- break;
- // keep looking for an exact match
+ STC stc = STC.none;
+ const cov = fd.type.covariant(fdv.type, &stc);
+ //printf("\tbaseclass cov = %d\n", cov);
+ final switch (cov)
+ {
+ case Covariant.distinct:
+ // types are distinct
+ break;
- case Covariant.no:
- mismatchvi = vi;
- mismatchstc = stc;
- mismatch = fdv; // overrides, but is not covariant
- break;
- // keep looking for an exact match
+ case Covariant.yes:
+ bestvi = vi; // covariant, but not identical
+ break;
+ // keep looking for an exact match
- case Covariant.fwdref:
- return -2; // forward references
- }
+ case Covariant.no:
+ mismatchvi = vi;
+ mismatchstc = stc;
+ mismatch = fdv; // overrides, but is not covariant
+ break;
+ // keep looking for an exact match
+
+ case Covariant.fwdref:
+ return -2; // forward references
}
}
if (fd._linkage == LINK.cpp && bestvi != -1)
{
- StorageClass stc = 0;
+ STC stc = STC.none;
FuncDeclaration fdv = vtbl[bestvi].isFuncDeclaration();
assert(fdv && fdv.ident == fd.ident);
if (fd.type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
@@ -1475,16 +1527,17 @@ enum FuncResolveFlag : ubyte
* Returns:
* if match is found, then function symbol, else null
*/
-FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
+FuncDeclaration resolveFuncCall(Loc loc, Scope* sc, Dsymbol s,
Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
{
+ //printf("resolveFuncCall() %s\n", s.toChars());
auto fargs = argumentList.arguments;
if (!s)
return null; // no match
version (none)
{
- printf("resolveFuncCall('%s')\n", s.toChars());
+ printf("resolveFuncCall() %s)\n", s.toChars());
if (tthis)
printf("\tthis: %s\n", tthis.toChars());
if (fargs)
@@ -1496,7 +1549,6 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
}
}
- printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
}
if (tiargs && arrayObjectIsError(*tiargs))
@@ -1564,9 +1616,26 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
- .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
+ string match = "";
+ final switch (m.last)
+ {
+ case MATCH.convert:
+ match = "after implicit conversions";
+ break;
+ case MATCH.constant:
+ match = "after qualifier conversion";
+ break;
+ case MATCH.exact:
+ match = "exactly";
+ break;
+ case MATCH.nomatch:
+ assert(0);
+ }
+
+ .error(loc, "`%s.%s` called with argument types `%s` matches multiple overloads %.*s:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
s.parent.toPrettyChars(), s.ident.toChars(),
fargsBuf.peekChars(),
+ match.fTuple.expand,
m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
return null;
@@ -1615,9 +1684,12 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
{
.error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
+ if (!global.gag || global.params.v.showGaggedErrors)
+ printCandidates(loc, od, sc.isDeprecated());
return null;
}
+ import dmd.expressionsem : checkDisabled;
// remove when deprecation period of class allocators and deallocators is over
if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
return null;
@@ -1694,39 +1766,40 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
tf.modToChars(), fargsBuf.peekChars());
+ if (global.gag && !global.params.v.showGaggedErrors)
+ return null;
+
// re-resolve to check for supplemental message
- if (!global.gag || global.params.v.showGaggedErrors)
+ if (tthis)
{
- if (tthis)
+ if (auto classType = tthis.isTypeClass())
{
- if (auto classType = tthis.isTypeClass())
+ if (auto baseClass = classType.sym.baseClass)
{
- if (auto baseClass = classType.sym.baseClass)
+ if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
{
- if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
+ MatchAccumulator mErr;
+ functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
+ if (mErr.last > MATCH.nomatch && mErr.lastf)
{
- MatchAccumulator mErr;
- functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
- if (mErr.last > MATCH.nomatch && mErr.lastf)
- {
- errorSupplemental(loc, "%s `%s` hides base class function `%s`",
- fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
- errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
- fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
- return null;
- }
+ errorSupplemental(loc, "%s `%s` hides base class function `%s`",
+ fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
+ errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
+ fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
+ return null;
}
}
}
}
+ }
- void errorHelper2(const(char)* failMessage) scope
- {
- errorSupplemental(loc, failMessage);
- }
-
- functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
+ void errorHelper2(const(char)* failMessage) scope
+ {
+ errorSupplemental(loc, failMessage);
}
+
+ functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
+
return null;
}
@@ -1737,16 +1810,29 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
* declaration = the declaration to print overload candidates for
* showDeprecated = If `false`, `deprecated` function won't be shown
*/
-private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
-if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
+private void printCandidates(Decl)(Loc loc, Decl declaration, bool showDeprecated)
{
// max num of overloads to print (-v or -verror-supplements overrides this).
const uint DisplayLimit = global.params.v.errorSupplementCount();
const(char)* constraintsTip;
- // determine if the first candidate was printed
- int printed;
- bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
+ int printed = 0; // number of candidates printed
+ int count = 0; // total candidates
+ bool child; // true if inside an eponymous template
+ const(char)* errorPrefix() @safe
+ {
+ if (child)
+ return " - Containing: ";
+
+ // align with blank spaces after first message
+ enum plural = "Candidates are: ";
+ enum spaces = " ";
+ if (printed)
+ return spaces;
+
+ return (count == 1) ? "Candidate is: " : plural;
+ }
+ bool matchSymbol(Dsymbol s, bool print)
{
if (auto fd = s.isFuncDeclaration())
{
@@ -1762,16 +1848,14 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
return true;
auto tf = cast(TypeFunction) fd.type;
OutBuffer buf;
- buf.writestring(fd.toPrettyChars());
+ buf.writestring(child ? fd.toChars() : fd.toPrettyChars());
buf.writestring(parametersTypeToChars(tf.parameterList));
if (tf.mod)
{
buf.writeByte(' ');
buf.MODtoBuffer(tf.mod);
}
- .errorSupplemental(fd.loc,
- printed ? " `%s`" :
- single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
+ .errorSupplemental(fd.loc, "%s`%s`", errorPrefix(), buf.peekChars());
}
else if (auto td = s.isTemplateDeclaration())
{
@@ -1779,35 +1863,46 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
if (!print)
return true;
+
+ // if td.onemember is a function, toCharsMaybeConstraints can print it
+ // without us recursing, otherwise we have to handle it.
+ // td.onemember may not have overloads set
+ // (see fail_compilation/onemember_overloads.d)
+ // assume if more than one member it is overloaded internally
+ bool recurse = td.onemember && (!td.onemember.isFuncDeclaration ||
+ td.members.length > 1);
OutBuffer buf;
HdrGenState hgs;
- hgs.skipConstraints = true;
+ hgs.skipConstraints = true; // failing constraint should get printed below
+ hgs.showOneMember = !recurse;
toCharsMaybeConstraints(td, buf, hgs);
const tmsg = buf.peekChars();
- const cmsg = td.getConstraintEvalError(constraintsTip);
-
- // add blank space if there are multiple candidates
- // the length of the blank space is `strlen("Candidates are: ")`
+ const cmsg = child ? null : td.getConstraintEvalError(constraintsTip);
if (cmsg)
- {
- .errorSupplemental(td.loc,
- printed ? " `%s`\n%s" :
- single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
- tmsg, cmsg);
- }
+ .errorSupplemental(td.loc, "%s`%s`\n%s", errorPrefix(), tmsg, cmsg);
else
+ .errorSupplemental(td.loc, "%s`%s`", errorPrefix(), tmsg);
+
+ if (recurse)
{
- .errorSupplemental(td.loc,
- printed ? " `%s`" :
- single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
- tmsg);
+ child = true;
+ foreach (d; *td.members)
+ {
+ if (d.ident != td.ident)
+ continue;
+
+ if (auto fd2 = d.isFuncDeclaration())
+ matchSymbol(fd2, print);
+ else if (auto td2 = d.isTemplateDeclaration())
+ matchSymbol(td2, print);
+ }
+ child = false;
}
}
return true;
}
// determine if there's > 1 candidate
- int count = 0;
overloadApply(declaration, (s) {
if (matchSymbol(s, false))
count++;
@@ -1817,7 +1912,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
overloadApply(declaration, (s) {
if (global.params.v.verbose || printed < DisplayLimit)
{
- if (matchSymbol(s, true, count == 1))
+ if (matchSymbol(s, true))
printed++;
}
else
@@ -1862,33 +1957,450 @@ Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
break;
inv = cd.inv;
}
- if (inv)
+ if (!inv)
+ return e;
+
+ version (all)
+ {
+ // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
+ // For the correct mangling,
+ // run attribute inference on inv if needed.
+ functionSemantic(inv);
+ }
+
+ //e = new DsymbolExp(Loc.initial, inv);
+ //e = new CallExp(Loc.initial, e);
+ //e = e.semantic(sc2);
+
+ /* https://issues.dlang.org/show_bug.cgi?id=13113
+ * Currently virtual invariant calls completely
+ * bypass attribute enforcement.
+ * Change the behavior of pre-invariant call by following it.
+ */
+ e = new ThisExp(Loc.initial);
+ e.type = ad.type.addMod(vthis.type.mod);
+ e = new DotVarExp(Loc.initial, e, inv, false);
+ e.type = inv.type;
+ e = new CallExp(Loc.initial, e);
+ e.type = Type.tvoid;
+ return e;
+}
+
+/********************************************
+ * Find function in overload list that exactly matches t.
+ */
+FuncDeclaration overloadExactMatch(FuncDeclaration thisfd, Type t)
+{
+ FuncDeclaration fd;
+ overloadApply(thisfd, (Dsymbol s)
+ {
+ auto f = s.isFuncDeclaration();
+ if (!f)
+ return 0;
+ if (f.storage_class & STC.disable)
+ return 0;
+ if (t.equals(f.type))
+ {
+ fd = f;
+ return 1;
+ }
+ /* Allow covariant matches, as long as the return type
+ * is just a const conversion.
+ * This allows things like pure functions to match with an impure function type.
+ */
+ if (t.ty == Tfunction)
+ {
+ auto tf = cast(TypeFunction)f.type;
+ if (tf.covariant(t) == Covariant.yes &&
+ tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
+ {
+ fd = f;
+ return 1;
+ }
+ }
+ return 0;
+ });
+ return fd;
+}
+
+/****************************************************
+ * Determine if fd1 overrides fd2.
+ * Return !=0 if it does.
+ */
+int overrides(FuncDeclaration fd1, FuncDeclaration fd2)
+{
+ if (fd1.ident != fd2.ident)
+ return 0;
+
+ const cov = fd1.type.covariant(fd2.type);
+ if (cov == Covariant.distinct)
+ return 0;
+
+ ClassDeclaration cd1 = fd1.toParent().isClassDeclaration();
+ ClassDeclaration cd2 = fd2.toParent().isClassDeclaration();
+
+ if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
+ return 1;
+ return 0;
+}
+
+/*************************************
+ * Determine partial specialization order of functions `f` vs `g`.
+ * This is very similar to TemplateDeclaration::leastAsSpecialized().
+ * Params:
+ * f = first function
+ * g = second function
+ * names = names of parameters
+ * Returns:
+ * match 'this' is at least as specialized as g
+ * 0 g is more specialized than 'this'
+ */
+MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names)
+{
+ enum LOG_LEASTAS = 0;
+ static if (LOG_LEASTAS)
+ {
+ import core.stdc.stdio : printf;
+ printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null");
+ printf("%s, %s\n", f.type.toChars(), g.type.toChars());
+ }
+
+ /* This works by calling g() with f()'s parameters, and
+ * if that is possible, then f() is at least as specialized
+ * as g() is.
+ */
+
+ TypeFunction tf = f.type.toTypeFunction();
+ TypeFunction tg = g.type.toTypeFunction();
+
+ /* If both functions have a 'this' pointer, and the mods are not
+ * the same and g's is not const, then this is less specialized.
+ */
+ if (f.needThis() && g.needThis() && tf.mod != tg.mod)
{
- version (all)
+ if (f.isCtorDeclaration())
+ {
+ if (!MODimplicitConv(tg.mod, tf.mod))
+ return MATCH.nomatch;
+ }
+ else
{
- // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
- // For the correct mangling,
- // run attribute inference on inv if needed.
- functionSemantic(inv);
+ if (!MODimplicitConv(tf.mod, tg.mod))
+ return MATCH.nomatch;
}
+ }
- //e = new DsymbolExp(Loc.initial, inv);
- //e = new CallExp(Loc.initial, e);
- //e = e.semantic(sc2);
+ /* Create a dummy array of arguments out of the parameters to f()
+ */
+ Expressions args;
+ foreach (u, p; tf.parameterList)
+ {
+ Expression e;
+ if (p.isReference())
+ {
+ e = new IdentifierExp(Loc.initial, p.ident);
+ e.type = p.type;
+ }
+ else
+ e = p.type.defaultInitLiteral(Loc.initial);
+ args.push(e);
+ }
- /* https://issues.dlang.org/show_bug.cgi?id=13113
- * Currently virtual invariant calls completely
- * bypass attribute enforcement.
- * Change the behavior of pre-invariant call by following it.
+ MATCH m = callMatch(g, tg, null, ArgumentList(&args, names), 1);
+ if (m > MATCH.nomatch)
+ {
+ /* A variadic parameter list is less specialized than a
+ * non-variadic one.
*/
- e = new ThisExp(Loc.initial);
- e.type = ad.type.addMod(vthis.type.mod);
- e = new DotVarExp(Loc.initial, e, inv, false);
- e.type = inv.type;
- e = new CallExp(Loc.initial, e);
- e.type = Type.tvoid;
+ if (tf.parameterList.varargs && !tg.parameterList.varargs)
+ goto L1; // less specialized
+
+ static if (LOG_LEASTAS)
+ {
+ printf(" matches %d, so is least as specialized\n", m);
+ }
+ return m;
}
- return e;
+L1:
+ static if (LOG_LEASTAS)
+ {
+ printf(" doesn't match, so is not as specialized\n");
+ }
+ return MATCH.nomatch;
+}
+
+/********************************************
+ * Find function in overload list that matches to the 'this' modifier.
+ * There's four result types.
+ *
+ * 1. If the 'tthis' matches only one candidate, it's an "exact match".
+ * Returns the function and 'hasOverloads' is set to false.
+ * eg. If 'tthis" is mutable and there's only one mutable method.
+ * 2. If there's two or more match candidates, but a candidate function will be
+ * a "better match".
+ * Returns the better match function but 'hasOverloads' is set to true.
+ * eg. If 'tthis' is mutable, and there's both mutable and const methods,
+ * the mutable method will be a better match.
+ * 3. If there's two or more match candidates, but there's no better match,
+ * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
+ * eg. If 'tthis' is mutable, and there's two or more mutable methods.
+ * 4. If there's no candidates, it's "no match" and returns null with error report.
+ * e.g. If 'tthis' is const but there's no const methods.
+ */
+FuncDeclaration overloadModMatch(FuncDeclaration thisfd, Loc loc, Type tthis, ref bool hasOverloads)
+{
+ //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
+ MatchAccumulator m;
+ overloadApply(thisfd, (Dsymbol s)
+ {
+ auto f = s.isFuncDeclaration();
+ if (!f || f == m.lastf) // skip duplicates
+ return 0;
+ auto tf = f.type.toTypeFunction();
+ //printf("tf = %s\n", tf.toChars());
+ MATCH match;
+ int lastIsBetter()
+ {
+ //printf("\tlastbetter\n");
+ m.count++; // count up
+ return 0;
+ }
+ int currIsBetter()
+ {
+ //printf("\tisbetter\n");
+ if (m.last <= MATCH.convert)
+ {
+ // clear last secondary matching
+ m.nextf = null;
+ m.count = 0;
+ }
+ m.last = match;
+ m.lastf = f;
+ m.count++; // count up
+ return 0;
+ }
+ if (tthis) // non-static functions are preferred than static ones
+ {
+ if (f.needThis())
+ match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
+ else
+ match = MATCH.constant; // keep static function in overload candidates
+ }
+ else // static functions are preferred than non-static ones
+ {
+ if (f.needThis())
+ match = MATCH.convert;
+ else
+ match = MATCH.exact;
+ }
+ if (match == MATCH.nomatch)
+ return 0;
+ if (match > m.last) return currIsBetter();
+ if (match < m.last) return lastIsBetter();
+ // See if one of the matches overrides the other.
+ if (m.lastf.overrides(f)) return lastIsBetter();
+ if (f.overrides(m.lastf)) return currIsBetter();
+ //printf("\tambiguous\n");
+ m.nextf = f;
+ m.count++;
+ return 0;
+ });
+ if (m.count == 1) // exact match
+ {
+ hasOverloads = false;
+ }
+ else if (m.count > 1) // better or ambiguous match
+ {
+ hasOverloads = true;
+ }
+ else // no match
+ {
+ hasOverloads = true;
+ auto tf = thisfd.type.toTypeFunction();
+ assert(tthis);
+ assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
+ {
+ OutBuffer thisBuf, funcBuf;
+ MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
+ MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
+ .error(loc, "%smethod %s is not callable using a %sobject", thisfd.kind, thisfd.toPrettyChars,
+ funcBuf.peekChars(), thisfd.toPrettyChars(), thisBuf.peekChars());
+ }
+ }
+ return m.lastf;
+}
+
+/***********************************
+ * Determine lexical level difference from `fd` to nested function `target`.
+ * Issue error if `fd` cannot call `target`.
+ *
+ * Params:
+ * fd = function
+ * loc = location for error messages
+ * sc = context
+ * target = target of call
+ * decl = The `Declaration` that triggered this check.
+ * Used to provide a better error message only.
+ * Returns:
+ * 0 same level
+ * >0 decrease nesting by number
+ * -1 increase nesting by 1 (`target` is nested within 'fd')
+ * LevelError error
+ */
+int getLevelAndCheck(FuncDeclaration fd, Loc loc, Scope* sc, FuncDeclaration target,
+ Declaration decl)
+{
+ int level = fd.getLevel(target, sc.intypeof);
+ if (level != fd.LevelError)
+ return level;
+ // Don't give error if in template constraint
+ if (!sc.inTemplateConstraint)
+ {
+ const(char)* xstatic = fd.isStatic() ? "`static` " : "";
+ // better diagnostics for static functions
+ .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
+ xstatic, fd.kind(), fd.toPrettyChars(), decl.kind(), decl.toChars(),
+ target.toPrettyChars());
+ .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
+ return fd.LevelError;
+ }
+ return 1;
+}
+
+/**********************************
+ * Decide if attributes for this function can be inferred from examining
+ * the function body.
+ * Params:
+ * fd = function to infer attributes for
+ * sc = context
+ * Returns:
+ * true if can
+ */
+bool canInferAttributes(FuncDeclaration fd, Scope* sc)
+{
+ if (!fd.fbody)
+ return false;
+ if (fd.isVirtualMethod() &&
+ /*
+ * https://issues.dlang.org/show_bug.cgi?id=21719
+ *
+ * If we have an auto virtual function we can infer
+ * the attributes.
+ */
+ !(fd.inferRetType && !fd.isCtorDeclaration()))
+ return false; // since they may be overridden
+ if (sc.func &&
+ /********** this is for backwards compatibility for the moment ********/
+ (!fd.isMember() || sc.func.isSafeBypassingInference() && !fd.isInstantiated()))
+ return true;
+ if (fd.isFuncLiteralDeclaration() || // externs are not possible with literals
+ (fd.storage_class & STC.inference) || // do attribute inference
+ fd.isGenerated || // compiler generated function
+ (fd.inferRetType && !fd.isCtorDeclaration()))
+ return true;
+ if (fd.isInstantiated())
+ {
+ auto ti = fd.parent.isTemplateInstance();
+ if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == fd.ident)
+ return true;
+ }
+ return false;
+}
+
+/*********************************************
+ * 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.
+ */
+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;
+}
+
+/****************************************************
+ * Check whether result variable can be built.
+ * Returns:
+ * `true` if the function has a return type that
+ * is different from `void`.
+ */
+private bool canBuildResultVar(FuncDeclaration fd)
+{
+ auto f = cast(TypeFunction)fd.type;
+ return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
}
/****************************************************
@@ -1914,7 +2426,7 @@ void buildResultVar(FuncDeclaration fd, Scope* sc, Type tret)
if (sc && fd.vresult.semanticRun == PASS.initial)
{
TypeFunction tf = fd.type.toTypeFunction();
- if (tf.isref)
+ if (tf.isRef)
fd.vresult.storage_class |= STC.ref_;
fd.vresult.type = tret;
fd.vresult.dsymbolSemantic(sc);
@@ -1923,3 +2435,1134 @@ void buildResultVar(FuncDeclaration fd, Scope* sc, Type tret)
assert(fd.vresult.parent == fd);
}
}
+
+/****************************************************
+ * Merge into this function the 'in' contracts of all it overrides.
+ * 'in's are OR'd together, i.e. only one of them needs to pass.
+ */
+Statement mergeFrequire(FuncDeclaration fd, Statement sf, Expressions* params)
+{
+ /* If a base function and its override both have an IN contract, then
+ * only one of them needs to succeed. This is done by generating:
+ *
+ * void derived.in() {
+ * try {
+ * base.in();
+ * }
+ * catch () {
+ * ... body of derived.in() ...
+ * }
+ * }
+ *
+ * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
+ * If base.in() throws, then derived.in()'s body is executed.
+ */
+ foreach (fdv; fd.foverrides)
+ {
+ /* The semantic pass on the contracts of the overridden functions must
+ * be completed before code generation occurs.
+ * https://issues.dlang.org/show_bug.cgi?id=3602
+ */
+ if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
+ {
+ assert(fdv._scope);
+ Scope* sc = fdv._scope.push();
+ sc.stc &= ~STC.override_;
+ fdv.semantic3(sc);
+ sc.pop();
+ }
+ sf = fdv.mergeFrequire(sf, params);
+ if (!sf || !fdv.fdrequire)
+ return null;
+ //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
+ /* Make the call:
+ * try { __require(params); }
+ * catch (Throwable) { frequire; }
+ */
+ params = Expression.arraySyntaxCopy(params);
+ Expression e = new CallExp(fd.loc, new VarExp(fd.loc, fdv.fdrequire, false), params);
+ Statement s2 = new ExpStatement(fd.loc, e);
+ auto c = new Catch(fd.loc, getThrowable(), null, sf);
+ c.internalCatch = true;
+ auto catches = new Catches();
+ catches.push(c);
+ sf = new TryCatchStatement(fd.loc, s2, catches);
+ }
+ return sf;
+}
+
+/****************************************************
+ * Merge into this function the 'in' contracts of all it overrides.
+ */
+Statement mergeFrequireInclusivePreview(FuncDeclaration fd, Statement sf, Expressions* params)
+{
+ /* If a base function and its override both have an IN contract, then
+ * the override in contract must widen the guarantee of the base contract.
+ * This is checked by generating:
+ *
+ * void derived.in() {
+ * try {
+ * ... body of derived.in() ...
+ * }
+ * catch () {
+ * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
+ * base.in();
+ * assert(false, "Logic error: " ~ thr.msg);
+ * }
+ * }
+ */
+ foreach (fdv; fd.foverrides)
+ {
+ /* The semantic pass on the contracts of the overridden functions must
+ * be completed before code generation occurs.
+ * https://issues.dlang.org/show_bug.cgi?id=3602
+ */
+ if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
+ {
+ assert(fdv._scope);
+ Scope* sc = fdv._scope.push();
+ sc.stc &= ~STC.override_;
+ fdv.semantic3(sc);
+ sc.pop();
+ }
+ sf = fdv.mergeFrequireInclusivePreview(sf, params);
+ if (!sf || !fdv.fdrequire)
+ return null;
+
+ const loc = fd.fdrequire.loc;
+ //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
+ /* Make the call:
+ * try { frequire; }
+ * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
+ */
+ Identifier id = Identifier.generateId("thr");
+ params = Expression.arraySyntaxCopy(params);
+ Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
+ Statement s2 = new ExpStatement(loc, e);
+ // assert(false, ...)
+ // TODO make this a runtime helper to allow:
+ // - chaining the original expression
+ // - nogc concatenation
+ Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
+ Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
+ Statement s3 = new CompoundStatement(loc, s2, fail);
+ auto c = new Catch(loc, getThrowable(), id, s3);
+ c.internalCatch = true;
+ auto catches = new Catches();
+ catches.push(c);
+ sf = new TryCatchStatement(loc, sf, catches);
+ }
+ return sf;
+}
+
+/****************************************************
+ * Rewrite contracts as statements.
+ */
+void buildEnsureRequire(FuncDeclaration thisfd)
+{
+ if (thisfd.frequires)
+ {
+ /* in { statements1... }
+ * in { statements2... }
+ * ...
+ * becomes:
+ * in { { statements1... } { statements2... } ... }
+ */
+ assert(thisfd.frequires.length);
+ auto loc = (*thisfd.frequires)[0].loc;
+ auto s = new Statements;
+ foreach (r; *thisfd.frequires)
+ {
+ s.push(new ScopeStatement(r.loc, r, r.loc));
+ }
+ thisfd.frequire = new CompoundStatement(loc, s);
+ }
+ if (thisfd.fensures)
+ {
+ /* out(id1) { statements1... }
+ * out(id2) { statements2... }
+ * ...
+ * becomes:
+ * out(__result) { { ref id1 = __result; { statements1... } }
+ * { ref id2 = __result; { statements2... } } ... }
+ */
+ assert(thisfd.fensures.length);
+ auto loc = (*thisfd.fensures)[0].ensure.loc;
+ auto s = new Statements;
+ foreach (r; *thisfd.fensures)
+ {
+ if (r.id && thisfd.canBuildResultVar())
+ {
+ auto rloc = r.ensure.loc;
+ auto resultId = new IdentifierExp(rloc, Id.result);
+ auto init = new ExpInitializer(rloc, resultId);
+ auto stc = STC.ref_ | STC.temp | STC.result;
+ auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
+ auto sdecl = new ExpStatement(rloc, decl);
+ s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
+ }
+ else
+ {
+ s.push(r.ensure);
+ }
+ }
+ thisfd.fensure = new CompoundStatement(loc, s);
+ }
+ if (!thisfd.isVirtual())
+ return;
+ /* Rewrite contracts as nested functions, then call them. Doing it as nested
+ * functions means that overriding functions can call them.
+ */
+ auto f = cast(TypeFunction) thisfd.type;
+ /* Make a copy of the parameters and make them all ref */
+ static Parameters* toRefCopy(ParameterList parameterList)
+ {
+ auto result = new Parameters();
+ foreach (n, p; parameterList)
+ {
+ p = p.syntaxCopy();
+ if (!p.isLazy())
+ p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
+ p.defaultArg = null; // won't be the same with ref
+ result.push(p);
+ }
+ return result;
+ }
+ if (thisfd.frequire)
+ {
+ /* in { ... }
+ * becomes:
+ * void __require(ref params) { ... }
+ * __require(params);
+ */
+ Loc loc = thisfd.frequire.loc;
+ thisfd.fdrequireParams = new Expressions();
+ if (thisfd.parameters)
+ {
+ foreach (vd; *thisfd.parameters)
+ thisfd.fdrequireParams.push(new VarExp(loc, vd));
+ }
+ auto fo = cast(TypeFunction)(thisfd.originalType ? thisfd.originalType : f);
+ auto fparams = toRefCopy(fo.parameterList);
+ auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
+ tf.isNothrow = f.isNothrow;
+ tf.isNogc = f.isNogc;
+ tf.purity = f.purity;
+ tf.trust = f.trust;
+ auto fd = new FuncDeclaration(loc, loc, Id.require, STC.none, tf);
+ fd.fbody = thisfd.frequire;
+ Statement s1 = new ExpStatement(loc, fd);
+ Expression e = new CallExp(loc, new VarExp(loc, fd, false), thisfd.fdrequireParams);
+ Statement s2 = new ExpStatement(loc, e);
+ thisfd.frequire = new CompoundStatement(loc, s1, s2);
+ thisfd.fdrequire = fd;
+ }
+ /* We need to set fdensureParams here and not in the block below to
+ * have the parameters available when calling a base class ensure(),
+ * even if this function doesn't have an out contract.
+ */
+ thisfd.fdensureParams = new Expressions();
+ if (thisfd.canBuildResultVar())
+ thisfd.fdensureParams.push(new IdentifierExp(thisfd.loc, Id.result));
+ if (thisfd.parameters)
+ {
+ foreach (vd; *thisfd.parameters)
+ thisfd.fdensureParams.push(new VarExp(thisfd.loc, vd));
+ }
+ if (thisfd.fensure)
+ {
+ /* out (result) { ... }
+ * becomes:
+ * void __ensure(ref tret result, ref params) { ... }
+ * __ensure(result, params);
+ */
+ Loc loc = thisfd.fensure.loc;
+ auto fparams = new Parameters();
+ if (thisfd.canBuildResultVar())
+ {
+ Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
+ fparams.push(p);
+ }
+ auto fo = cast(TypeFunction)(thisfd.originalType ? thisfd.originalType : f);
+ fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
+ auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
+ tf.isNothrow = f.isNothrow;
+ tf.isNogc = f.isNogc;
+ tf.purity = f.purity;
+ tf.trust = f.trust;
+ auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.none, tf);
+ fd.fbody = thisfd.fensure;
+ Statement s1 = new ExpStatement(loc, fd);
+ Expression e = new CallExp(loc, new VarExp(loc, fd, false), thisfd.fdensureParams);
+ Statement s2 = new ExpStatement(loc, e);
+ thisfd.fensure = new CompoundStatement(loc, s1, s2);
+ thisfd.fdensure = fd;
+ }
+}
+
+/****************************************************
+ * Determine whether an 'out' contract is declared inside
+ * the given function or any of its overrides.
+ * Params:
+ * fd = the function to search
+ * Returns:
+ * true found an 'out' contract
+ */
+bool needsFensure(FuncDeclaration fd) @safe
+{
+ if (fd.fensures)
+ return true;
+
+ foreach (fdv; fd.foverrides)
+ {
+ if (needsFensure(fdv))
+ return true;
+ }
+ return false;
+}
+
+/****************************************************
+ * Merge into this function the 'out' contracts of all it overrides.
+ * 'out's are AND'd together, i.e. all of them need to pass.
+ */
+Statement mergeFensure(FuncDeclaration fd, Statement sf, Identifier oid, Expressions* params)
+{
+ /* Same comments as for mergeFrequire(), except that we take care
+ * of generating a consistent reference to the 'result' local by
+ * explicitly passing 'result' to the nested function as a reference
+ * argument.
+ * This won't work for the 'this' parameter as it would require changing
+ * the semantic code for the nested function so that it looks on the parameter
+ * list for the 'this' pointer, something that would need an unknown amount
+ * of tweaking of various parts of the compiler that I'd rather leave alone.
+ */
+ foreach (fdv; fd.foverrides)
+ {
+ /* The semantic pass on the contracts of the overridden functions must
+ * be completed before code generation occurs.
+ * https://issues.dlang.org/show_bug.cgi?id=3602 and
+ * https://issues.dlang.org/show_bug.cgi?id=5230
+ */
+ if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
+ {
+ assert(fdv._scope);
+ Scope* sc = fdv._scope.push();
+ sc.stc &= ~STC.override_;
+ fdv.semantic3(sc);
+ sc.pop();
+ }
+ sf = fdv.mergeFensure(sf, oid, params);
+ if (!fdv.fdensure)
+ continue;
+
+ //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
+ // Make the call: __ensure(result, params)
+ params = Expression.arraySyntaxCopy(params);
+ if (fd.canBuildResultVar())
+ {
+ Type t1 = fdv.type.nextOf().toBasetype();
+ Type t2 = fd.type.nextOf().toBasetype();
+ if (t1.isBaseOf(t2, null))
+ {
+ /* Making temporary reference variable is necessary
+ * in covariant return.
+ * https://issues.dlang.org/show_bug.cgi?id=5204
+ * https://issues.dlang.org/show_bug.cgi?id=10479
+ */
+ Expression* eresult = &(*params)[0];
+ auto ei = new ExpInitializer(Loc.initial, *eresult);
+ auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
+ v.storage_class |= STC.temp;
+ auto de = new DeclarationExp(Loc.initial, v);
+ auto ve = new VarExp(Loc.initial, v);
+ *eresult = new CommaExp(Loc.initial, de, ve);
+ }
+ }
+ Expression e = new CallExp(fd.loc, new VarExp(fd.loc, fdv.fdensure, false), params);
+ Statement s2 = new ExpStatement(fd.loc, e);
+ if (sf)
+ {
+ sf = new CompoundStatement(sf.loc, s2, sf);
+ }
+ else
+ sf = s2;
+ }
+ return sf;
+}
+
+/*******************************
+ * Modify all expression type of return statements to tret.
+ *
+ * On function literals, return type may be modified based on the context type
+ * after its semantic3 is done, in FuncExp::implicitCastTo.
+ *
+ * A function() dg = (){ return new B(); } // OK if is(B : A) == true
+ *
+ * If B to A conversion is convariant that requires offseet adjusting,
+ * all return statements should be adjusted to return expressions typed A.
+ */
+void modifyReturns(FuncLiteralDeclaration fld, Scope* sc, Type tret)
+{
+ extern (C++) final class RetWalker : StatementRewriteWalker
+ {
+ alias visit = typeof(super).visit;
+ public:
+ Scope* sc;
+ Type tret;
+ FuncLiteralDeclaration fld;
+ override void visit(ReturnStatement s)
+ {
+ Expression exp = s.exp;
+ if (exp && !exp.type.equals(tret))
+ s.exp = exp.implicitCastTo(sc, tret);
+ }
+ }
+ if (fld.semanticRun < PASS.semantic3done)
+ return;
+ if (fld.fes)
+ return;
+ scope RetWalker w = new RetWalker();
+ w.sc = sc;
+ w.tret = tret;
+ w.fld = fld;
+ fld.fbody.accept(w);
+ // Also update the inferred function type to match the new return type.
+ // This is required so the code generator does not try to cast the
+ // modified returns back to the original type.
+ if (fld.inferRetType && fld.type.nextOf() != tret)
+ fld.type.toTypeFunction().next = tret;
+}
+
+/**************************************
+ * When a traits(compiles) is used on a function literal call
+ * we need to take into account if the body of the function
+ * violates any attributes, however, we must not affect the
+ * attribute inference on the outer function. The attributes
+ * of the function literal still need to be inferred, therefore
+ * we need a way to check for the scope that the traits compiles
+ * introduces.
+ *
+ * Params:
+ * sc = scope to be checked for
+ *
+ * Returns: `true` if the provided scope is the root
+ * of the traits compiles list of scopes.
+ */
+bool isRootTraitsCompilesScope(Scope* sc) @safe
+{
+ return (sc.traitsCompiles) && !sc.func.skipCodegen;
+}
+
+/+
+ + Checks the parameter and return types iff this is a `main` function.
+ +
+ + The following signatures are allowed for a `D main`:
+ + - Either no or a single parameter of type `string[]`
+ + - Return type is either `void`, `int` or `noreturn`
+ +
+ + The following signatures are standard C:
+ + - `int main()`
+ + - `int main(int, char**)`
+ +
+ + This function accepts the following non-standard extensions:
+ + - `char** envp` as a third parameter
+ + - `void` / `noreturn` as return type
+ +
+ + This function will issue errors for unexpected arguments / return types.
+ +/
+extern (D) void checkMain(FuncDeclaration fd)
+{
+ if (fd.ident != Id.main || fd.isMember() || fd.isNested())
+ return; // Not a main function
+
+ TypeFunction tf = fd.type.toTypeFunction();
+
+ Type retType = tf.nextOf();
+ if (!retType)
+ {
+ // auto main(), check after semantic
+ assert(fd.inferRetType);
+ return;
+ }
+
+ /// Checks whether `t` is equivalent to `char**`
+ /// Ignores qualifiers and treats enums according to their base type
+ static bool isCharPtrPtr(Type t)
+ {
+ auto tp = t.toBasetype().isTypePointer();
+ if (!tp)
+ return false;
+
+ tp = tp.next.toBasetype().isTypePointer();
+ if (!tp)
+ return false;
+
+ return tp.next.toBasetype().ty == Tchar;
+ }
+
+ // Neither of these qualifiers is allowed because they affect the ABI
+ enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
+
+ const nparams = tf.parameterList.length;
+ bool argerr;
+
+ const linkage = fd.resolvedLinkage();
+ if (linkage == LINK.d)
+ {
+ if (nparams == 1)
+ {
+ auto fparam0 = tf.parameterList[0];
+ auto t = fparam0.type.toBasetype();
+ if (t.ty != Tarray ||
+ t.nextOf().ty != Tarray ||
+ t.nextOf().nextOf().ty != Tchar ||
+ fparam0.storageClass & invalidSTC)
+ {
+ argerr = true;
+ }
+ }
+
+ if (tf.parameterList.varargs || nparams >= 2 || argerr)
+ .error(fd.loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", fd.kind, fd.toPrettyChars);
+ }
+
+ else if (linkage == LINK.c)
+ {
+ if (nparams == 2 || nparams == 3)
+ {
+ // Argument count must be int
+ auto argCount = tf.parameterList[0];
+ argerr |= !!(argCount.storageClass & invalidSTC);
+ argerr |= argCount.type.toBasetype().ty != Tint32;
+
+ // Argument pointer must be char**
+ auto argPtr = tf.parameterList[1];
+ argerr |= !!(argPtr.storageClass & invalidSTC);
+ argerr |= !isCharPtrPtr(argPtr.type);
+
+ // `char** environ` is a common extension, see J.5.1 of the C standard
+ if (nparams == 3)
+ {
+ auto envPtr = tf.parameterList[2];
+ argerr |= !!(envPtr.storageClass & invalidSTC);
+ argerr |= !isCharPtrPtr(envPtr.type);
+ }
+ }
+ else
+ argerr = nparams != 0;
+
+ // Disallow variadic main() - except for K&R declarations in C files.
+ // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
+ if (tf.parameterList.varargs && (!fd.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
+ argerr |= true;
+
+ if (argerr)
+ {
+ .error(fd.loc, "%s `%s` parameters must match one of the following signatures", fd.kind, fd.toPrettyChars);
+ fd.loc.errorSupplemental("`main()`");
+ fd.loc.errorSupplemental("`main(int argc, char** argv)`");
+ fd.loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
+ }
+ }
+ else
+ return; // Neither C nor D main, ignore (should probably be an error)
+
+ // Allow enums with appropriate base types (same ABI)
+ retType = retType.toBasetype();
+
+ if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
+ .error(fd.loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", fd.kind, fd.toPrettyChars, tf.nextOf().toChars());
+}
+
+/***********************************************
+ * Check all return statements for a function to verify that returning
+ * using NRVO is possible.
+ *
+ * Returns:
+ * `false` if the result cannot be returned by hidden reference.
+ */
+extern (D) bool checkNRVO(FuncDeclaration fd)
+{
+ //printf("checkNRVO*() %s\n", fd.ident.toChars());
+ if (!fd.isNRVO() || fd.returns is null)
+ return false;
+
+ auto tf = fd.type.toTypeFunction();
+ if (tf.isRef)
+ return false;
+
+ foreach (rs; *fd.returns)
+ {
+ if (auto ve = rs.exp.isVarExp())
+ {
+ auto v = ve.var.isVarDeclaration();
+ if (!v || v.isReference())
+ return false;
+ if (fd.nrvo_var is null)
+ {
+ // Variables in the data segment (e.g. globals, TLS or not),
+ // parameters and closure variables cannot be NRVOed.
+ if (v.isDataseg() || v.isParameter() || v.toParent2() != fd)
+ return false;
+ if (v.nestedrefs.length && fd.needsClosure())
+ return false;
+ // don't know if the return storage is aligned
+ version (MARS)
+ {
+ if (fd.alignSectionVars && (*fd.alignSectionVars).contains(v))
+ return false;
+ }
+ // The variable type needs to be equivalent to the return type.
+ if (!v.type.equivalent(tf.next))
+ return false;
+ //printf("Setting nrvo to %s\n", v.toChars());
+ fd.nrvo_var = v;
+ }
+ else if (fd.nrvo_var != v)
+ return false;
+ }
+ else //if (!exp.isLvalue()) // keep NRVO-ability
+ return false;
+ }
+ return true;
+}
+
+/**************************************
+ * The function is doing something impure, so mark it as impure.
+ *
+ * Params:
+ * fd = function declaration to mark
+ * loc = location of impure action
+ * fmt = format string for error message
+ * args = argument to format string
+ *
+ * Returns: `true` if there's a purity error
+ */
+extern (D) bool setImpure(FuncDeclaration fd, Loc loc, const(char)* fmt, RootObject[] args...)
+{
+ if (fd.purityInprocess)
+ {
+ fd.purityInprocess = false;
+ if (fmt)
+ fd.pureViolation = new AttributeViolation(loc, fmt, args); // impure action
+ else if (args.length > 0)
+ {
+ if (auto sa = args[0].isDsymbol())
+ {
+ if (FuncDeclaration fd2 = sa.isFuncDeclaration())
+ {
+ fd.pureViolation = new AttributeViolation(loc, fd2); // call to impure function
+ }
+ }
+ }
+
+ if (fd.fes)
+ fd.fes.func.setImpure(loc, fmt, args);
+ }
+ else if (fd.isPure())
+ return true;
+ return false;
+}
+
+PURE isPure(FuncDeclaration fd)
+{
+ //printf("FuncDeclaration::isPure() '%s'\n", toChars());
+
+
+ TypeFunction tf = fd.type.toTypeFunction();
+ if (fd.purityInprocess)
+ fd.setImpure(Loc.initial, null);
+ if (tf.purity == PURE.fwdref)
+ tf.purityLevel();
+ PURE purity = tf.purity;
+ if (purity > PURE.weak && fd.isNested())
+ purity = PURE.weak;
+ if (purity > PURE.weak && fd.needThis())
+ {
+ // The attribute of the 'this' reference affects purity strength
+ if (fd.type.mod & MODFlags.immutable_)
+ {
+ }
+ else if (fd.type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
+ purity = PURE.const_;
+ else
+ purity = PURE.weak;
+ }
+ tf.purity = purity;
+ // ^ This rely on the current situation that every FuncDeclaration has a
+ // unique TypeFunction.
+ return purity;
+}
+
+extern (D) PURE isPureBypassingInference(FuncDeclaration fd)
+{
+ if (fd.purityInprocess)
+ return PURE.fwdref;
+ else
+ return fd.isPure();
+}
+
+/**************************************
+ * Performs type-based alias analysis between a newly created value and a pre-
+ * existing memory reference:
+ *
+ * Assuming that a reference A to a value of type `ta` was available to the code
+ * that created a reference B to a value of type `tb`, it returns whether B
+ * might alias memory reachable from A based on the types involved (either
+ * directly or via any number of indirections in either A or B).
+ *
+ * This relation is not symmetric in the two arguments. For example, a
+ * a `const(int)` reference can point to a pre-existing `int`, but not the other
+ * way round.
+ *
+ * Examples:
+ *
+ * ta, tb, result
+ * `const(int)`, `int`, `false`
+ * `int`, `const(int)`, `true`
+ * `int`, `immutable(int)`, `false`
+ * const(immutable(int)*), immutable(int)*, false // BUG: returns true
+ *
+ * Params:
+ * ta = value type being referred to
+ * tb = referred to value type that could be constructed from ta
+ *
+ * Returns:
+ * true if reference to `tb` is isolated from reference to `ta`
+ */
+bool traverseIndirections(Type ta, Type tb)
+{
+ //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
+
+ static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
+ {
+ //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
+ ta = ta.baseElemOf();
+ tb = tb.baseElemOf();
+
+ // First, check if the pointed-to types are convertible to each other such
+ // that they might alias directly.
+ static bool mayAliasDirect(Type source, Type target)
+ {
+ return
+ // if source is the same as target or can be const-converted to target
+ source.constConv(target) != MATCH.nomatch ||
+ // if target is void and source can be const-converted to target
+ (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
+ }
+
+ if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
+ {
+ //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
+ return false;
+ }
+ if (ta.nextOf() && ta.nextOf() == tb.nextOf())
+ {
+ //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
+ return true;
+ }
+
+ if (tb.ty == Tclass || tb.ty == Tstruct)
+ {
+ /* Traverse the type of each field of the aggregate
+ */
+ bool* found = table.getLvalue(tb.deco);
+ if (*found == true)
+ return true; // We have already seen this symbol, break the cycle
+ else
+ *found = true;
+
+ AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
+ foreach (v; sym.fields)
+ {
+ Type tprmi = v.type.addMod(tb.mod);
+ //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
+ if (!traverse(ta, tprmi, table, reversePass))
+ return false;
+ }
+ }
+ else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
+ {
+ Type tind = tb.nextOf();
+ if (!traverse(ta, tind, table, reversePass))
+ return false;
+ }
+ else if (tb.hasPointers())
+ {
+ // BUG: consider the context pointer of delegate types
+ return false;
+ }
+
+ // Still no match, so try breaking up ta if we have not done so yet.
+ if (!reversePass)
+ {
+ scope newTable = AssocArray!(const(char)*, bool)();
+ return traverse(tb, ta, newTable, true);
+ }
+
+ return true;
+ }
+
+ // To handle arbitrary levels of indirections in both parameters, we
+ // recursively descend into aggregate members/levels of indirection in both
+ // `ta` and `tb` while avoiding cycles. Start with the original types.
+ scope table = AssocArray!(const(char)*, bool)();
+ const result = traverse(ta, tb, table, false);
+ //printf(" returns %d\n", result);
+ return result;
+}
+
+/********************************************
+ * Params:
+ * fd = function declaration to check
+ * t = type of object to test one level of indirection down
+ * Returns:
+ * true if an object typed `t` has no indirections
+ * which could have come from the function's parameters, mutable
+ * globals, or uplevel functions.
+ */
+bool isTypeIsolatedIndirect(FuncDeclaration fd, Type t)
+{
+ //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
+ assert(t);
+
+ /* Since `t` is one level down from an indirection, it could pick
+ * up a reference to a mutable global or an outer function, so
+ * return false.
+ */
+ if (!fd.isPureBypassingInference() || fd.isNested())
+ return false;
+
+ TypeFunction tf = fd.type.toTypeFunction();
+
+ //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
+
+ foreach (i, fparam; tf.parameterList)
+ {
+ Type tp = fparam.type;
+ if (!tp)
+ continue;
+
+ if (fparam.isLazy() || fparam.isReference())
+ {
+ if (!traverseIndirections(tp, t))
+ return false;
+ continue;
+ }
+
+ /* Goes down one level of indirection, then calls traverseIndirection() on
+ * the result.
+ * Returns:
+ * true if t is isolated from tp
+ */
+ static bool traverse(Type tp, Type t)
+ {
+ tp = tp.baseElemOf();
+ switch (tp.ty)
+ {
+ case Tarray:
+ case Tpointer:
+ return traverseIndirections(tp.nextOf(), t);
+
+ case Taarray:
+ case Tclass:
+ return traverseIndirections(tp, t);
+
+ case Tstruct:
+ /* Drill down and check the struct's fields
+ */
+ auto sym = tp.toDsymbol(null).isStructDeclaration();
+ foreach (v; sym.fields)
+ {
+ Type tprmi = v.type.addMod(tp.mod);
+ //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
+ if (!traverse(tprmi, t))
+ return false;
+ }
+ return true;
+
+ default:
+ return true;
+ }
+ }
+
+ if (!traverse(tp, t))
+ return false;
+ }
+ // The 'this' reference is a parameter, too
+ if (AggregateDeclaration ad = fd.isCtorDeclaration() ? null : fd.isThis())
+ {
+ Type tthis = ad.getType().addMod(tf.mod);
+ //printf("\ttthis = %s\n", tthis.toChars());
+ if (!traverseIndirections(tthis, t))
+ return false;
+ }
+
+ return true;
+}
+
+/********************************************
+ * See if pointers from function parameters, mutable globals, or uplevel functions
+ * could leak into return value.
+ * Returns:
+ * true if the function return value is isolated from
+ * any inputs to the function
+ */
+extern (D) bool isReturnIsolated(FuncDeclaration fd)
+{
+ //printf("isReturnIsolated(this: %s)\n", this.toChars);
+ TypeFunction tf = fd.type.toTypeFunction();
+ assert(tf.next);
+
+ Type treti = tf.next;
+ if (tf.isRef)
+ return fd.isTypeIsolatedIndirect(treti); // check influence from parameters
+
+ return fd.isTypeIsolated(treti);
+}
+
+/********************
+ * See if pointers from function parameters, mutable globals, or uplevel functions
+ * could leak into type `t`.
+ * Params:
+ * t = type to check if it is isolated
+ * Returns:
+ * true if `t` is isolated from
+ * any inputs to the function
+ */
+extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t)
+{
+ StringTable!Type parentTypes;
+ const uniqueTypeID = t.getUniqueID();
+ if (uniqueTypeID)
+ {
+ const cacheResultPtr = uniqueTypeID in fd.isTypeIsolatedCache;
+ if (cacheResultPtr !is null)
+ return *cacheResultPtr;
+
+ parentTypes._init();
+ const isIsolated = fd.isTypeIsolated(t, parentTypes);
+ fd.isTypeIsolatedCache[uniqueTypeID] = isIsolated;
+ return isIsolated;
+ }
+ else
+ {
+ parentTypes._init();
+ return fd.isTypeIsolated(t, parentTypes);
+ }
+}
+
+///ditto
+extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t, ref StringTable!Type parentTypes)
+{
+ //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
+
+ t = t.baseElemOf();
+ switch (t.ty)
+ {
+ case Tarray:
+ case Tpointer:
+ return fd.isTypeIsolatedIndirect(t.nextOf()); // go down one level
+
+ case Taarray:
+ case Tclass:
+ return fd.isTypeIsolatedIndirect(t);
+
+ case Tstruct:
+ /* Drill down and check the struct's fields
+ */
+ auto sym = t.toDsymbol(null).isStructDeclaration();
+ const tName = t.toChars.toDString;
+ const entry = parentTypes.insert(tName, t);
+ if (entry == null)
+ {
+ //we've already seen this type in a parent, not isolated
+ return false;
+ }
+ foreach (v; sym.fields)
+ {
+ Type tmi = v.type.addMod(t.mod);
+ //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
+ // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
+ if (!fd.isTypeIsolated(tmi, parentTypes))
+ return false;
+ }
+ return true;
+
+ default:
+ return true;
+ }
+}
+
+/**
+ * Check signature of `pragma(printf)` function, print error if invalid.
+ *
+ * printf/scanf-like functions must be of the form:
+ * extern (C/C++) T printf([parameters...], const(char)* format, ...);
+ * or:
+ * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
+ *
+ * Params:
+ * funcdecl = function to check
+ * f = function type
+ * sc = scope
+ */
+private void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* sc)
+{
+ static bool isPointerToChar(Parameter p)
+ {
+ if (auto tptr = p.type.isTypePointer())
+ {
+ return tptr.next.ty == Tchar;
+ }
+ return false;
+ }
+
+ bool isVa_list(Parameter p)
+ {
+ return p.type.equals(target.va_listType(funcdecl.loc, sc));
+ }
+
+ const nparams = f.parameterList.length;
+ const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars();
+ if (!(f.linkage == LINK.c || f.linkage == LINK.cpp))
+ {
+ .error(funcdecl.loc, "`pragma(%s)` function `%s` must have `extern(C)` or `extern(C++)` linkage,"
+ ~" not `extern(%s)`",
+ p, funcdecl.toChars(), f.linkage.linkageToChars());
+ }
+ if (f.parameterList.varargs == VarArg.variadic)
+ {
+ if (!(nparams >= 1 && isPointerToChar(f.parameterList[nparams - 1])))
+ {
+ .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"
+ ~ " signature `%s %s([parameters...], const(char)*, ...)` not `%s`",
+ p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars());
+ }
+ }
+ else if (f.parameterList.varargs == VarArg.none)
+ {
+ if(!(nparams >= 2 && isPointerToChar(f.parameterList[nparams - 2]) &&
+ isVa_list(f.parameterList[nparams - 1])))
+ .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"~
+ " signature `%s %s([parameters...], const(char)*, va_list)`",
+ p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars());
+ }
+ else
+ {
+ .error(funcdecl.loc, "`pragma(%s)` function `%s` must have C-style variadic `...` or `va_list` parameter",
+ p, funcdecl.toChars());
+ }
+}
+
+/***************************************************
+ * Visit each overloaded function/template in turn, and call dg(s) on it.
+ * Exit when no more, or dg(s) returns nonzero.
+ *
+ * Params:
+ * fstart = symbol to start from
+ * dg = the delegate to be called on the overload
+ * sc = context used to check if symbol is accessible (and therefore visible),
+ * can be null
+ *
+ * Returns:
+ * ==0 continue
+ * !=0 done (and the return value from the last dg() call)
+ */
+extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
+{
+ Dsymbols visited;
+
+ int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
+ {
+ // Detect cyclic calls.
+ if (visited.contains(fstart))
+ return 0;
+ visited.push(fstart);
+
+ Dsymbol next;
+ for (auto d = fstart; d; d = next)
+ {
+ import dmd.access : checkSymbolAccess;
+ if (auto od = d.isOverDeclaration())
+ {
+ /* The scope is needed here to check whether a function in
+ an overload set was added by means of a private alias (or a
+ selective import). If the scope where the alias is created
+ is imported somewhere, the overload set is visible, but the private
+ alias is not.
+ */
+ if (sc)
+ {
+ if (checkSymbolAccess(sc, od))
+ {
+ if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
+ return r;
+ }
+ }
+ else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
+ return r;
+ next = od.overnext;
+ }
+ else if (auto fa = d.isFuncAliasDeclaration())
+ {
+ if (fa.hasOverloads)
+ {
+ if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
+ return r;
+ }
+ else if (auto fd = fa.toAliasFunc())
+ {
+ if (int r = dg(fd))
+ return r;
+ }
+ else
+ {
+ .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
+ break;
+ }
+ next = fa.overnext;
+ }
+ else if (auto ad = d.isAliasDeclaration())
+ {
+ if (sc)
+ {
+ if (checkSymbolAccess(sc, ad))
+ next = ad.toAlias();
+ }
+ else
+ next = ad.toAlias();
+ if (next == ad)
+ break;
+ if (next == fstart)
+ break;
+ }
+ else if (auto td = d.isTemplateDeclaration())
+ {
+ if (int r = dg(td))
+ return r;
+ next = td.overnext;
+ }
+ else if (auto fd = d.isFuncDeclaration())
+ {
+ if (int r = dg(fd))
+ return r;
+ next = fd.overnext;
+ }
+ else if (auto os = d.isOverloadSet())
+ {
+ foreach (ds; os.a)
+ if (int r = dg(ds))
+ return r;
+ }
+ else
+ {
+ .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
+ break;
+ // BUG: should print error message?
+ }
+ }
+ return 0;
+ }
+ return overloadApplyRecurse(fstart, dg, sc);
+}
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index af7b1fa..624738e 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -1,12 +1,12 @@
/**
* Stores command line options and contains other miscellaneous declarations.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/globals.d, _globals.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/globals.d, _globals.d)
* Documentation: https://dlang.org/phobos/dmd_globals.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/globals.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/globals.d
*/
module dmd.globals;
@@ -40,24 +40,6 @@ enum DiagnosticReporting : ubyte
off, /// disable diagnostic
}
-/// In which context checks for assertions, contracts, bounds checks etc. are enabled
-enum CHECKENABLE : ubyte
-{
- _default, /// initial value
- off, /// never do checking
- on, /// always do checking
- safeonly, /// do checking only in @safe functions
-}
-
-/// What should happend when an assertion fails
-enum CHECKACTION : ubyte
-{
- D, /// call D assert on failure
- C, /// call C assert on failure
- halt, /// cause program halt on failure
- context, /// call D assert with the error context on failure
-}
-
/**
Each flag represents a field that can be included in the JSON output.
@@ -80,6 +62,7 @@ enum CppStdRevision : uint
cpp14 = 2014_02,
cpp17 = 2017_03,
cpp20 = 2020_02,
+ cpp23 = 2023_02,
}
/// Trivalent boolean to represent the state of a `revert`able change
@@ -90,6 +73,23 @@ enum FeatureState : ubyte
enabled = 2, /// Specified as `-preview=`
}
+/// Different identifier tables specifiable by CLI
+enum CLIIdentifierTable : ubyte
+{
+ default_ = 0, /// Not specified by user
+ C99 = 1, /// Tables from C99 standard
+ C11 = 2, /// Tables from C11 standard
+ UAX31 = 3, /// Tables from the Unicode Standard Annex 31: UNICODE IDENTIFIERS AND SYNTAX
+ All = 4, /// The least restrictive set of all other tables
+}
+
+/// Specifies the mode for error printing
+enum ErrorPrintMode : ubyte
+{
+ simpleError, // Print errors without squiggles and carets
+ printErrorContext, // Print errors with context (source line and caret)
+}
+
extern(C++) struct Output
{
bool doOutput; // Output is enabled
@@ -134,15 +134,15 @@ extern(C++) struct Verbose
bool complex = true; // identify complex/imaginary type usage
bool vin; // identify 'in' parameters
bool showGaggedErrors; // print gagged errors anyway
- bool printErrorContext; // print errors with the error context (the error line in the source file)
bool logo; // print compiler logo
bool color; // use ANSI colors in console output
bool cov; // generate code coverage data
+ ErrorPrintMode errorPrintMode; // enum for error printing mode
MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages
uint errorLimit = 20;
uint errorSupplementLimit = 6; // Limit the number of supplemental messages for each error (0 means unlimited)
- uint errorSupplementCount()
+ uint errorSupplementCount() @safe
{
if (verbose)
return uint.max;
@@ -152,10 +152,15 @@ extern(C++) struct Verbose
}
}
+extern (C++) struct ImportPathInfo {
+ const(char)* path; // char*'s of where to look for import modules
+}
+
/// Put command line switches in here
extern (C++) struct Param
{
bool obj = true; // write object file
+ bool readStdin; // saw "-" on command line, read source file from stdin
bool multiobj; // break one object file into multiple ones
bool trace; // insert profiling hooks
bool tracegc; // instrument calls to 'new'
@@ -165,7 +170,7 @@ extern (C++) struct Param
bool useInline = false; // inline expand functions
bool release; // build release version
bool preservePaths; // true means don't strip path from source file
- DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled
+ DiagnosticReporting useWarnings = DiagnosticReporting.off; // how compiler warnings are handled
bool cov; // generate code coverage data
ubyte covPercent; // 0..100 code coverage percentage required
bool ctfe_cov = false; // generate coverage data for ctfe
@@ -196,6 +201,8 @@ extern (C++) struct Param
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
// Implementation: https://github.com/dlang/dmd/pull/9817
+ FeatureState safer; // safer by default (more @safe checks in unattributed code)
+ // https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md
FeatureState noSharedAccess; // read/write access to shared memory objects
bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
@@ -217,9 +224,12 @@ extern (C++) struct Param
CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated
+ CLIIdentifierTable dIdentifierTable = CLIIdentifierTable.default_;
+ CLIIdentifierTable cIdentifierTable = CLIIdentifierTable.default_;
+
const(char)[] argv0; // program name
Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings
- Array!(const(char)*) imppath; // array of char*'s of where to look for import modules
+ Array!(ImportPathInfo) imppath; // array of import path information of where to look for import modules
Array!(const(char)*) fileImppath; // array of char*'s of where to look for file import modules
const(char)[] objdir; // .obj/.lib file output directory
const(char)[] objname; // .obj file output name
@@ -234,8 +244,7 @@ extern (C++) struct Param
Output mixinOut; // write expanded mixins for debugging
Output moduleDeps; // Generate `.deps` module dependencies
- uint debuglevel; // debug level
- uint versionlevel; // version level
+ bool debugEnabled; // Global -debug flag (no -debug=XXX) is active
bool run; // run resulting executable
Strings runargs; // arguments for executable
@@ -253,8 +262,15 @@ extern (C++) struct Param
const(char)[] exefile;
const(char)[] mapfile;
+ bool fullyQualifiedObjectFiles; // prepend module names to object files to prevent name conflicts with -od
+
+ // Time tracing
+ bool timeTrace = false; /// Whether profiling of compile time is enabled
+ uint timeTraceGranularityUs = 500; /// In microseconds, minimum event size to report
+ const(char)* timeTraceFile; /// File path of output file
+
///
- bool parsingUnittestsRequired()
+ bool parsingUnittestsRequired() @safe
{
return useUnitTests || ddoc.doOutput || dihdr.doOutput;
}
@@ -277,10 +293,11 @@ extern (C++) struct Global
{
const(char)[] inifilename; /// filename of configuration file as given by `-conf=`, or default value
- string copyright = "Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved";
+ string copyright = "Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved";
string written = "written by Walter Bright";
- Array!(const(char)*) path; /// Array of char*'s which form the import lookup path
+ Array!(ImportPathInfo) path; /// Array of path informations which form the import lookup path
+ Array!(const(char)*) importPaths; /// Array of char*'s which form the import lookup path without metadata
Array!(const(char)*) filePath; /// Array of char*'s which form the file import lookup path
private enum string _version = import("VERSION");
@@ -289,6 +306,7 @@ extern (C++) struct Global
Param params; /// command line parameters
uint errors; /// number of errors reported so far
+ uint deprecations; /// number of deprecations reported so far
uint warnings; /// number of warnings reported so far
uint gag; /// !=0 means gag reporting of errors & warnings
uint gaggedErrors; /// number of errors reported while gagged
@@ -310,7 +328,7 @@ extern (C++) struct Global
ErrorSink errorSink; /// where the error messages go
ErrorSink errorSinkNull; /// where the error messages are ignored
- extern (C++) DArray!ubyte function(FileName, ref const Loc, ref OutBuffer) preprocess;
+ extern (C++) DArray!ubyte function(FileName, Loc, ref OutBuffer) preprocess;
nothrow:
@@ -380,7 +398,16 @@ extern (C++) struct Global
{
compileEnv.vendor = "GNU D";
}
- compileEnv.versionNumber = parseVersionNumber(_version);
+ else version (IN_LLVM)
+ {
+ compileEnv.vendor = "LDC";
+
+ import dmd.console : detectTerminal;
+ params.v.color = detectTerminal();
+ }
+
+ params.v.errorPrintMode = ErrorPrintMode.printErrorContext; // Enable error context globally by default
+ compileEnv.versionNumber = parseVersionNumber(versionString());
/* Initialize date, time, and timestamp
*/
@@ -457,6 +484,17 @@ extern (C++) struct Global
}
/**
+ * Indicate to stateful error sinks that no more errors can be produced.
+ * This is to support error sinks that collect information to produce a
+ * single (say) report.
+ */
+ extern(C++) void plugErrorSinks()
+ {
+ global.errorSink.plugSink();
+ global.errorSinkNull.plugSink();
+ }
+
+ /**
Returns: the version as the number that would be returned for __VERSION__
*/
extern(C++) uint versionNumber() @safe
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index f553ae6..62a575e 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -13,6 +13,7 @@
#include "root/dcompat.h"
#include "root/ctfloat.h"
#include "common/outbuffer.h"
+#include "common/charactertables.h"
#include "root/filename.h"
#include "compiler.h"
@@ -34,7 +35,8 @@ enum
enum class MessageStyle : unsigned char
{
digitalmars, // file(line,column): message
- gnu // file:line:column: message
+ gnu, // file:line:column: message
+ sarif // JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
};
// The state of array bounds checking
@@ -71,7 +73,8 @@ enum CppStdRevision
CppStdRevisionCpp11 = 201103,
CppStdRevisionCpp14 = 201402,
CppStdRevisionCpp17 = 201703,
- CppStdRevisionCpp20 = 202002
+ CppStdRevisionCpp20 = 202002,
+ CppStdRevisionCpp23 = 202302,
};
/// Trivalent boolean to represent the state of a `revert`able change
@@ -82,6 +85,23 @@ enum class FeatureState : unsigned char
enabled = 2, /// Specified as `-preview=`
};
+/// Different identifier tables specifiable by CLI
+enum class CLIIdentifierTable : unsigned char
+{
+ default_ = 0, /// Not specified by user
+ C99 = 1, /// Tables from C99 standard
+ C11 = 2, /// Tables from C11 standard
+ UAX31 = 3, /// Tables from the Unicode Standard Annex 31: UNICODE IDENTIFIERS AND SYNTAX
+ All = 4, /// The least restrictive set of all other tables
+};
+
+/// Specifies the mode for error printing
+enum class ErrorPrintMode : unsigned char
+{
+ simpleError, // Print errors without squiggles and carets
+ printErrorContext, // Print errors with the error line and caret
+};
+
struct Output
{
/// Configuration for the compiler generator
@@ -126,20 +146,29 @@ struct Verbose
d_bool complex = true; // identify complex/imaginary type usage
d_bool vin; // identify 'in' parameters
d_bool showGaggedErrors; // print gagged errors anyway
- d_bool printErrorContext; // print errors with the error context (the error line in the source file)
d_bool logo; // print compiler logo
d_bool color; // use ANSI colors in console output
d_bool cov; // generate code coverage data
+ ErrorPrintMode errorPrintMode; // enum for error printing mode
MessageStyle messageStyle; // style of file/line annotations on messages
unsigned errorLimit;
unsigned errorSupplementLimit; // Limit the number of supplemental messages for each error (0 means unlimited)
unsigned errorSupplementCount();
};
+struct ImportPathInfo
+{
+ const char* path;
+
+ ImportPathInfo() : path(NULL) { }
+ ImportPathInfo(const char* p) : path(p) { }
+};
+
// Put command line switches in here
struct Param
{
d_bool obj; // write object file
+ d_bool readStdin; // read source file from stdin
d_bool multiobj; // break one object file into multiple ones
d_bool trace; // insert profiling hooks
d_bool tracegc; // instrument calls to 'new'
@@ -149,7 +178,7 @@ struct Param
d_bool useInline; // inline expand functions
d_bool release; // build release version
d_bool preservePaths; // true means don't strip path from source file
- Diagnostic warnings;
+ Diagnostic useWarnings;
d_bool cov; // generate code coverage data
unsigned char covPercent; // 0..100 code coverage percentage required
d_bool ctfe_cov; // generate coverage data for ctfe
@@ -179,6 +208,9 @@ struct Param
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
// Implementation: https://github.com/dlang/dmd/pull/9817
+ FeatureState safer; // safer by default (more @safe checks in unattributed code)
+ // https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md
+
FeatureState noSharedAccess; // read/write access to shared memory objects
d_bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
d_bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
@@ -200,9 +232,12 @@ struct Param
CHECKACTION checkAction; // action to take when bounds, asserts or switch defaults are violated
+ CLIIdentifierTable dIdentifierTable;
+ CLIIdentifierTable cIdentifierTable;
+
DString argv0; // program name
Array<const char *> modFileAliasStrings; // array of char*'s of -I module filename alias strings
- Array<const char *> imppath; // array of char*'s of where to look for import modules
+ Array<ImportPathInfo> imppath; // array of import path information of where to look for import modules
Array<const char *> fileImppath; // array of char*'s of where to look for file import modules
DString objdir; // .obj/.lib file output directory
DString objname; // .obj file output name
@@ -217,8 +252,7 @@ struct Param
Output mixinOut; // write expanded mixins for debugging
Output moduleDeps; // Generate `.deps` module dependencies
- unsigned debuglevel; // debug level
- unsigned versionlevel; // version level
+ d_bool debugEnabled; // -debug flag is passed
d_bool run; // run resulting executable
Strings runargs; // arguments for executable
@@ -236,6 +270,10 @@ struct Param
DString resfile;
DString exefile;
DString mapfile;
+ bool fullyQualifiedObjectFiles;
+ bool timeTrace;
+ uint32_t timeTraceGranularityUs;
+ const char* timeTraceFile;
};
struct structalign_t
@@ -273,7 +311,11 @@ struct CompileEnv
DString vendor;
DString timestamp;
d_bool previewIn;
+ d_bool transitionIn;
d_bool ddocOutput;
+ d_bool masm;
+ IdentifierCharLookup cCharLookupTable;
+ IdentifierCharLookup dCharLookupTable;
};
struct Global
@@ -282,14 +324,16 @@ struct Global
const DString copyright;
const DString written;
- Array<const char *> path; // Array of char*'s which form the import lookup path
- Array<const char *> filePath; // Array of char*'s which form the file import lookup path
+ Array<ImportPathInfo> path; // Array of path informations which form the import lookup path
+ Array<const char *> importPaths; // Array of char*'s which form the import lookup path without metadata
+ Array<const char *> filePath; // Array of char*'s which form the file import lookup path
char datetime[26]; /// string returned by ctime()
CompileEnv compileEnv;
Param params;
unsigned errors; // number of errors reported so far
+ unsigned deprecations; // number of deprecations reported so far
unsigned warnings; // number of warnings reported so far
unsigned gag; // !=0 means gag reporting of errors & warnings
unsigned gaggedErrors; // number of errors reported while gagged
@@ -307,7 +351,7 @@ struct Global
ErrorSink* errorSink; // where the error messages go
ErrorSink* errorSinkNull; // where the error messages disappear
- DArray<unsigned char> (*preprocess)(FileName, const Loc&, OutBuffer&);
+ DArray<unsigned char> (*preprocess)(FileName, Loc, OutBuffer&);
/* Start gagging. Return the current number of gagged errors
*/
@@ -327,6 +371,13 @@ struct Global
void _init();
/**
+ * Indicate to stateful error sinks that no more errors can be produced.
+ * This is to support error sinks that collect information to produce a
+ * single (say) report.
+ */
+ void plugErrorSinks();
+
+ /**
Returns: the version as the number that would be returned for __VERSION__
*/
unsigned versionNumber();
@@ -364,43 +415,46 @@ typedef unsigned long long uinteger_t;
#endif
// file location
+struct SourceLoc
+{
+ DString filename;
+ uint32_t line;
+ uint32_t column;
+ uint32_t fileOffset;
+ DString fileContent;
+};
+
struct Loc
{
private:
- unsigned _linnum;
- unsigned _charnum;
- unsigned fileIndex;
+
+ unsigned int index;
+
+#if MARS && defined(__linux__) && defined(__i386__)
+ unsigned int dummy;
+#endif
+
public:
static void set(bool showColumns, MessageStyle messageStyle);
+ static Loc singleFilename(const char* const filename);
static bool showColumns;
static MessageStyle messageStyle;
Loc()
{
- _linnum = 0;
- _charnum = 0;
- fileIndex = 0;
- }
-
- Loc(const char *filename, unsigned linnum, unsigned charnum)
- {
- this->linnum(linnum);
- this->charnum(charnum);
- this->filename(filename);
+ index = 0;
}
uint32_t charnum() const;
- uint32_t charnum(uint32_t num);
uint32_t linnum() const;
- uint32_t linnum(uint32_t num);
const char *filename() const;
- void filename(const char *name);
+ SourceLoc toSourceLoc() const;
const char *toChars(
bool showColumns = Loc::showColumns,
MessageStyle messageStyle = Loc::messageStyle) const;
- bool equals(const Loc& loc) const;
+ bool equals(Loc loc) const;
};
enum class LINK : uint8_t
diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d
index a3a3bd0..ba7c1e9 100644
--- a/gcc/d/dmd/gluelayer.d
+++ b/gcc/d/dmd/gluelayer.d
@@ -3,12 +3,12 @@
*
* This 'glues' either the DMC or GCC back-end to the front-end.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d, _gluelayer.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/gluelayer.d, _gluelayer.d)
* Documentation: https://dlang.org/phobos/dmd_gluelayer.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/gluelayer.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/gluelayer.d
*/
module dmd.gluelayer;
@@ -25,7 +25,7 @@ version (NoBackend)
struct Symbol;
struct code;
struct block;
- struct Blockx;
+ struct BlockState;
struct elem;
struct TYPE;
alias type = TYPE;
@@ -51,9 +51,9 @@ else version (IN_GCC)
}
else
{
- public import dmd.backend.cc : block, Blockx, Symbol;
+ public import dmd.backend.cc : block, BlockState, Symbol;
public import dmd.backend.type : type;
public import dmd.backend.el : elem;
- public import dmd.backend.code_x86 : code;
+ public import dmd.backend.x86.code_x86 : code;
public import dmd.objc_glue : ObjcGlue;
}
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 41da11d..61ff273 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -3,12 +3,12 @@
*
* Also used to convert AST nodes to D code in general, e.g. for error messages or `printf` debugging.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d, _hdrgen.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/hdrgen.d, _hdrgen.d)
* Documentation: https://dlang.org/phobos/dmd_hdrgen.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/hdrgen.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/hdrgen.d
*/
module dmd.hdrgen;
@@ -59,9 +59,12 @@ struct HdrGenState
bool ddoc; /// true if generating Ddoc file
bool fullDump; /// true if generating a full AST dump file
bool importcHdr; /// true if generating a .di file from an ImportC file
+ bool inCAlias; /// Set to prevent ImportC translating typedefs as `alias X = X`
bool doFuncBodies; /// include function bodies in output
bool vcg_ast; /// write out codegen-ast
bool skipConstraints; // skip constraints when doing templates
+ bool showOneMember = true;
+ bool errorMsg; /// true if formatting for inside an error message
bool fullQual; /// fully qualify types when printing
int tpltMember;
@@ -95,6 +98,87 @@ void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf)
toCBuffer(m, buf, hgs);
}
+/**
+ * Convert `o` to a string for error messages.
+ * Params:
+ * e = object to convert
+ * Returns: string representation of `e`
+ */
+const(char)* toErrMsg(const RootObject o)
+{
+ if (auto e = o.isExpression())
+ return toErrMsg(e);
+ if (auto d = o.isDsymbol())
+ return toErrMsg(d);
+ if (auto t = o.isType())
+ return t.toChars();
+ if (auto id = o.isIdentifier())
+ return id.toChars();
+ assert(0);
+}
+
+/// ditto
+const(char)* toErrMsg(const Expression e)
+{
+ HdrGenState hgs;
+ hgs.errorMsg = true;
+ OutBuffer buf;
+ toCBuffer(e, buf, hgs);
+ truncateForError(buf, 60);
+
+ return buf.extractChars();
+}
+
+/// ditto
+const(char)* toErrMsg(const Dsymbol d)
+{
+ if (d.isFuncDeclaration() || d.isTemplateInstance())
+ {
+ if (d.ident && d.ident.toString.startsWith("__") && !d.isCtorDeclaration())
+ {
+ HdrGenState hgs;
+ hgs.errorMsg = true;
+ OutBuffer buf;
+ toCBuffer(cast() d, buf, hgs);
+ truncateForError(buf, 80);
+ return buf.extractChars();
+ }
+ }
+
+ return d.toChars();
+}
+
+/**
+ * Make the content of `buf` fit inline for an error message.
+ * Params:
+ * buf = buffer with text to modify
+ * maxLength = truncate text when it exceeds this length
+ */
+private void truncateForError(ref OutBuffer buf, size_t maxLength)
+{
+ // Remove newlines, escape backticks ` by doubling them
+ for (size_t i = 0; i < buf.length; i++)
+ {
+ if (buf[i] == '\r')
+ buf.remove(i, 1);
+ if (buf[i] == '\n')
+ buf.peekSlice[i] = ' ';
+ if (buf[i] == '`')
+ i = buf.insert(i, "`");
+ }
+
+ // Strip trailing whitespace
+ while (buf.length && buf[$-1] == ' ')
+ buf.setsize(buf.length - 1);
+
+ // Truncate
+ if (buf.length > maxLength)
+ {
+ buf.setsize(maxLength - 3);
+ buf.writestring("...");
+ }
+}
+
/***************************************
* Turn a Statement into a string suitable for printf.
* Leaks memory.
@@ -139,6 +223,42 @@ public const(char)* toChars(const Type t)
return buf.extractChars();
}
+public const(char)* toChars(const Dsymbol d)
+{
+ if (auto td = d.isTemplateDeclaration())
+ {
+ HdrGenState hgs;
+ OutBuffer buf;
+ toCharsMaybeConstraints(td, buf, hgs);
+ return buf.extractChars();
+ }
+
+ if (auto ti = d.isTemplateInstance())
+ {
+ OutBuffer buf;
+ toCBufferInstance(ti, buf);
+ return buf.extractChars();
+ }
+
+ if (auto tm = d.isTemplateMixin())
+ {
+ OutBuffer buf;
+ toCBufferInstance(tm, buf);
+ return buf.extractChars();
+ }
+
+ if (auto tid = d.isTypeInfoDeclaration())
+ {
+ OutBuffer buf;
+ buf.writestring("typeid(");
+ buf.writestring(tid.tinfo.toChars());
+ buf.writeByte(')');
+ return buf.extractChars();
+ }
+
+ return d.ident ? d.ident.toHChars2() : "__anonymous";
+}
+
public const(char)[] toString(const Initializer i)
{
OutBuffer buf;
@@ -304,13 +424,12 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
buf.writenl();
}
- void visitWhile(WhileStatement s)
+ void printConditionAssignment(Parameter p, Expression condition)
{
- buf.writestring("while (");
- if (auto p = s.param)
+ if (p)
{
// Print condition assignment
- StorageClass stc = p.storageClass;
+ STC stc = p.storageClass;
if (!p.type && !stc)
stc = STC.auto_;
if (stcToBuffer(buf, stc))
@@ -321,7 +440,13 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
buf.writestring(p.ident.toString());
buf.writestring(" = ");
}
- s.condition.expressionToBuffer(buf, hgs);
+ condition.expressionToBuffer(buf, hgs);
+ }
+
+ void visitWhile(WhileStatement s)
+ {
+ buf.writestring("while (");
+ printConditionAssignment(s.param, s.condition);
buf.writeByte(')');
buf.writenl();
if (s._body)
@@ -412,10 +537,10 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
{
buf.writestring(Token.toString(s.op));
buf.writestring(" (");
- if (s.prm.type)
- typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
+ if (s.param.type)
+ typeToBuffer(s.param.type, s.param.ident, buf, hgs);
else
- buf.writestring(s.prm.ident.toString());
+ buf.writestring(s.param.ident.toString());
buf.writestring("; ");
s.lwr.expressionToBuffer(buf, hgs);
buf.writestring(" .. ");
@@ -459,20 +584,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
void visitIf(IfStatement s)
{
buf.writestring("if (");
- if (Parameter p = s.prm)
- {
- StorageClass stc = p.storageClass;
- if (!p.type && !stc)
- stc = STC.auto_;
- if (stcToBuffer(buf, stc))
- buf.writeByte(' ');
- if (p.type)
- typeToBuffer(p.type, p.ident, buf, hgs);
- else
- buf.writestring(p.ident.toString());
- buf.writestring(" = ");
- }
- s.condition.expressionToBuffer(buf, hgs);
+ printConditionAssignment(s.param, s.condition);
buf.writeByte(')');
buf.writenl();
if (s.ifbody.isScopeStatement())
@@ -571,21 +683,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h
void visitSwitch(SwitchStatement s)
{
buf.writestring(s.isFinal ? "final switch (" : "switch (");
- if (auto p = s.param)
- {
- // Print condition assignment
- StorageClass stc = p.storageClass;
- if (!p.type && !stc)
- stc = STC.auto_;
- if (stcToBuffer(buf, stc))
- buf.writeByte(' ');
- if (p.type)
- typeToBuffer(p.type, p.ident, buf, hgs);
- else
- buf.writestring(p.ident.toString());
- buf.writestring(" = ");
- }
- s.condition.expressionToBuffer(buf, hgs);
+ printConditionAssignment(s.param, s.condition);
buf.writeByte(')');
buf.writenl();
if (s._body)
@@ -901,10 +999,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
void visitDebugSymbol(DebugSymbol s)
{
buf.writestring("debug = ");
- if (s.ident)
- buf.writestring(s.ident.toString());
- else
- buf.print(s.level);
+ buf.writestring(s.ident.toString());
buf.writeByte(';');
buf.writenl();
}
@@ -912,10 +1007,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
void visitVersionSymbol(VersionSymbol s)
{
buf.writestring("version = ");
- if (s.ident)
- buf.writestring(s.ident.toString());
- else
- buf.print(s.level);
+ buf.writestring(s.ident.toString());
buf.writeByte(';');
buf.writenl();
}
@@ -1189,14 +1281,14 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
void foreachRangeWithoutBody(ForeachRangeStatement s)
{
- /* s.op ( prm ; lwr .. upr )
+ /* s.op ( param ; lwr .. upr )
*/
buf.writestring(Token.toString(s.op));
buf.writestring(" (");
- if (s.prm.type)
- typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
+ if (s.param.type)
+ typeToBuffer(s.param.type, s.param.ident, buf, hgs);
else
- buf.writestring(s.prm.ident.toString());
+ buf.writestring(s.param.ident.toString());
buf.writestring("; ");
s.lwr.expressionToBuffer(buf, hgs);
buf.writestring(" .. ");
@@ -1649,7 +1741,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
{
if (d.storage_class & STC.local)
return;
- if (d.adFlags & d.hidden)
+ if (d.hidden)
return;
buf.writestring("alias ");
if (d.aliassym)
@@ -1686,7 +1778,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
buf.writestring(" = ");
if (stcToBuffer(buf, d.storage_class))
buf.writeByte(' ');
+ hgs.inCAlias = hgs.importcHdr;
typeToBuffer(d.type, null, buf, hgs);
+ hgs.inCAlias = false;
hgs.declstring = false;
}
buf.writeByte(';');
@@ -1717,12 +1811,15 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
void visitFuncDeclaration(FuncDeclaration f)
{
//printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars());
- if (stcToBuffer(buf, f.storage_class))
+
+ // https://issues.dlang.org/show_bug.cgi?id=24891
+ // return/scope storage classes are printed as part of function type
+ if (stcToBuffer(buf, f.storage_class & ~(STC.scope_ | STC.return_ | STC.returnScope)))
buf.writeByte(' ');
+ typeToBuffer(f.type, f.ident, buf, hgs);
auto tf = f.type.isTypeFunction();
- typeToBuffer(tf, f.ident, buf, hgs);
- if (hgs.hdrgen)
+ if (hgs.hdrgen && tf)
{
// if the return type is missing (e.g. ref functions or auto)
// https://issues.dlang.org/show_bug.cgi?id=20090
@@ -1760,7 +1857,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
buf.writestring("__error");
return;
}
- if (f.tok != TOK.reserved)
+ if (f.tok != TOK.reserved && !hgs.errorMsg)
{
buf.writestring(f.kind());
buf.writeByte(' ');
@@ -1777,8 +1874,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
buf.writeByte(' ');
buf.writestring(str);
}
- tf.attributesApply(&printAttribute);
+ if (!hgs.errorMsg)
+ tf.attributesApply(&printAttribute);
CompoundStatement cs = f.fbody.isCompoundStatement();
Statement s1;
@@ -1857,9 +1955,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
if (stcToBuffer(buf, d.storage_class))
buf.writeByte(' ');
buf.writestring("invariant");
- if(auto es = d.fbody.isExpStatement())
+ auto es = d.fbody.isExpStatement();
+ if (es && es.exp && es.exp.op == EXP.assert_)
{
- assert(es.exp && es.exp.op == EXP.assert_);
buf.writestring(" (");
(cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
buf.writestring(");");
@@ -1974,7 +2072,7 @@ void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, re
}
buf.writeByte(')');
- if (td.onemember)
+ if (hgs.showOneMember && td.onemember)
{
if (const fd = td.onemember.isFuncDeclaration())
{
@@ -2255,9 +2353,20 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
buf.writestring(e.ident.toString());
}
- void visitDsymbol(DsymbolExp e)
+ void visitDsymbol(Dsymbol s)
+ {
+ // For -vcg-ast, print internal names such as __invariant, __ctor etc.
+ // This condition is a bit kludge, and can be cleaned up if the
+ // mutual dependency `AST.toChars <> hdrgen.d` gets refactored
+ if (hgs.vcg_ast && s.ident && !s.isTemplateInstance() && !s.isTemplateDeclaration())
+ buf.writestring(s.ident.toChars());
+ else
+ buf.writestring(s.toChars());
+ }
+
+ void visitDsymbolExp(DsymbolExp e)
{
- buf.writestring(e.s.toChars());
+ visitDsymbol(e.s);
}
void visitThis(ThisExp e)
@@ -2362,12 +2471,12 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
// to themselves, need to avoid infinite recursion:
// struct S { this(int){ this.s = &this; } S* s; }
// const foo = new S(0);
- if (e.stageflags & stageToCBuffer)
+ if (e.stageflags & StructLiteralExp.StageFlags.toCBuffer)
buf.writestring("<recursion>");
else
{
const old = e.stageflags;
- e.stageflags |= stageToCBuffer;
+ e.stageflags |= StructLiteralExp.StageFlags.toCBuffer;
argsToBuffer(e.elements, buf, hgs);
e.stageflags = old;
}
@@ -2422,6 +2531,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
buf.writeByte('.');
}
buf.writestring("new ");
+ if (e.placement)
+ {
+ buf.writeByte('(');
+ expToBuffer(e.placement, PREC.assign, buf, hgs);
+ buf.writeByte(')');
+ buf.writeByte(' ');
+ }
typeToBuffer(e.newtype, null, buf, hgs);
if (e.arguments && e.arguments.length)
{
@@ -2439,6 +2555,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
buf.writeByte('.');
}
buf.writestring("new");
+ if (e.placement)
+ {
+ buf.writeByte(' ');
+ buf.writeByte('(');
+ expToBuffer(e.placement, PREC.assign, buf, hgs);
+ buf.writeByte(')');
+ }
buf.writestring(" class ");
if (e.arguments && e.arguments.length)
{
@@ -2453,7 +2576,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
void visitSymOff(SymOffExp e)
{
if (e.offset)
- buf.printf("(& %s%+lld)", e.var.toChars(), e.offset);
+ buf.printf("(& %s + %llu)", e.var.toChars(), e.offset);
else if (e.var.isTypeInfoDeclaration())
buf.writestring(e.var.toChars());
else
@@ -2462,7 +2585,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
void visitVar(VarExp e)
{
- buf.writestring(e.var.toChars());
+ visitDsymbol(e.var);
}
void visitOver(OverExp e)
@@ -2608,9 +2731,9 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
// the `sideeffect.copyToTemp` function.
auto ve = e.e2.isVarExp();
- // not a CommaExp introduced for temporaries, go on
- // the old path
- if (!ve || !(ve.var.storage_class & STC.temp))
+ // Not a CommaExp introduced for temporaries, or -vcg-ast,
+ // print the full comma
+ if (!ve || !(ve.var.storage_class & STC.temp) || hgs.vcg_ast)
{
visitBin(cast(BinExp)e);
return;
@@ -2681,10 +2804,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
void visitDotId(DotIdExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
- if (e.arrow)
- buf.writestring("->");
- else
- buf.writeByte('.');
+ buf.writeByte('.');
buf.writestring(e.ident.toString());
}
@@ -2699,7 +2819,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writeByte('.');
- buf.writestring(e.var.toChars());
+ visitDsymbol(e.var);
}
void visitDotTemplateInstance(DotTemplateInstanceExp e)
@@ -2890,14 +3010,21 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
buf.writestring(e.value.toChars());
}
+ if (e.rvalue)
+ buf.writestring("__rvalue(");
+
+ scope (exit)
+ if (e.rvalue)
+ buf.writeByte(')');
+
switch (e.op)
{
default:
if (auto be = e.isBinExp())
return visitBin(be);
- else if (auto ue = e.isUnaExp())
+ if (auto ue = e.isUnaExp())
return visitUna(ue);
- else if (auto de = e.isDefaultInitExp())
+ if (auto de = e.isDefaultInitExp())
return visitDefaultInit(e.isDefaultInitExp());
return visit(e);
@@ -2907,7 +3034,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
case EXP.float64: return visitReal(e.isRealExp());
case EXP.complex80: return visitComplex(e.isComplexExp());
case EXP.identifier: return visitIdentifier(e.isIdentifierExp());
- case EXP.dSymbol: return visitDsymbol(e.isDsymbolExp());
+ case EXP.dSymbol: return visitDsymbolExp(e.isDsymbolExp());
case EXP.this_: return visitThis(e.isThisExp());
case EXP.super_: return visitSuper(e.isSuperExp());
case EXP.null_: return visitNull(e.isNullExp());
@@ -2931,7 +3058,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
case EXP.typeid_: return visitTypeid(e.isTypeidExp());
case EXP.traits: return visitTraits(e.isTraitsExp());
case EXP.halt: return visitHalt(e.isHaltExp());
- case EXP.is_: return visitIs(e.isExp());
+ case EXP.is_: return visitIs(e.isIsExp());
case EXP.comma: return visitComma(e.isCommaExp());
case EXP.mixin_: return visitMixin(e.isMixinExp());
case EXP.import_: return visitImport(e.isImportExp());
@@ -3018,7 +3145,7 @@ void floatToBuffer(Type type, const real_t value, ref OutBuffer buf, const bool
default:
break;
}
- if (t.isimaginary())
+ if (t.isImaginary())
buf.writeByte('i');
}
}
@@ -3126,20 +3253,14 @@ public:
override void visit(DebugCondition c)
{
buf.writestring("debug (");
- if (c.ident)
- buf.writestring(c.ident.toString());
- else
- buf.print(c.level);
+ buf.writestring(c.ident.toString());
buf.writeByte(')');
}
override void visit(VersionCondition c)
{
buf.writestring("version (");
- if (c.ident)
- buf.writestring(c.ident.toString());
- else
- buf.print(c.level);
+ buf.writestring(c.ident.toString());
buf.writeByte(')');
}
@@ -3176,7 +3297,7 @@ void toCBuffer(const Initializer iz, ref OutBuffer buf, ref HdrGenState hgs)
initializerToBuffer(cast() iz, buf, hgs);
}
-bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe
+bool stcToBuffer(ref OutBuffer buf, STC stc) @safe
{
//printf("stc: %llx\n", stc);
bool result = false;
@@ -3192,6 +3313,12 @@ bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe
stc &= ~(STC.return_ | STC.returninferred);
}
+ // ensure `auto ref` keywords are (almost) adjacent
+ if (stc & STC.auto_)
+ {
+ buf.writestring("auto ");
+ stc &= ~STC.auto_;
+ }
/* Put scope ref return into a standard order
*/
string rrs;
@@ -3201,12 +3328,12 @@ bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe
{
case ScopeRef.None:
case ScopeRef.Scope:
- case ScopeRef.Ref:
case ScopeRef.Return:
break;
case ScopeRef.ReturnScope: rrs = "return scope"; goto L1;
case ScopeRef.ReturnRef: rrs = isout ? "return out" : "return ref"; goto L1;
+ case ScopeRef.Ref: rrs = isout ? "out" : "ref"; goto L1;
case ScopeRef.RefScope: rrs = isout ? "out scope" : "ref scope"; goto L1;
case ScopeRef.ReturnRef_Scope: rrs = isout ? "return out scope" : "return ref scope"; goto L1;
case ScopeRef.Ref_ReturnScope: rrs = isout ? "out return scope" : "ref return scope"; goto L1;
@@ -3236,11 +3363,11 @@ bool stcToBuffer(ref OutBuffer buf, StorageClass stc) @safe
* and return a string representation of it.
* stc is reduced by the one picked.
*/
-string stcToString(ref StorageClass stc) @safe
+string stcToString(ref STC stc) @safe
{
static struct SCstring
{
- StorageClass stc;
+ STC stc;
string id;
}
@@ -3283,7 +3410,7 @@ string stcToString(ref StorageClass stc) @safe
];
foreach (ref entry; table)
{
- const StorageClass tbl = entry.stc;
+ const STC tbl = entry.stc;
assert(tbl & STC.visibleStorageClasses);
if (stc & tbl)
{
@@ -3516,7 +3643,7 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, ref HdrGenState h
if (p.storageClass & STC.auto_)
buf.writestring("auto ");
- StorageClass stc = p.storageClass;
+ STC stc = p.storageClass;
if (p.storageClass & STC.in_)
{
buf.writestring("in ");
@@ -3792,7 +3919,8 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, ref HdrGenSt
}
else if (Expression e = isExpression(oarg))
{
- if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_)
+ if (!(e.type && e.type.isTypeEnum()) && e.op == EXP.int64 || e.op == EXP.float64 ||
+ e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_)
{
toCBuffer(e, buf, hgs);
return;
@@ -3926,15 +4054,15 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
/* Use 'storage class' (prefix) style for attributes
*/
- if (t.mod)
+ if (t.mod && !(hgs.ddoc || hgs.hdrgen))
{
MODtoBuffer(buf, t.mod);
buf.writeByte(' ');
}
- void ignoreReturn(string str)
+ void dg(string str)
{
- if (str != "return")
+ if (str != "return" && str != "scope")
{
// don't write 'ref' for ctors
if ((ident == Id.ctor) && str == "ref")
@@ -3943,7 +4071,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
buf.writeByte(' ');
}
}
- t.attributesApply(&ignoreReturn);
+ t.attributesApply(&dg);
if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
{
@@ -3976,7 +4104,21 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
buf.writeByte(')');
}
parametersToBuffer(t.parameterList, buf, hgs);
- if (t.isreturn)
+ // postfix this attributes are more readable
+ if (t.mod && (hgs.ddoc || hgs.hdrgen))
+ {
+ buf.writeByte(' ');
+ MODtoBuffer(buf, t.mod);
+ }
+ if (t.isReturnScope && !t.isReturnInferred)
+ {
+ buf.writestring(" return scope");
+ }
+ else if (t.isScopeQual && !t.isScopeInferred)
+ {
+ buf.writestring(" scope");
+ }
+ if (t.isReturn && !t.isReturnScope && !t.isReturnInferred)
{
buf.writestring(" return");
}
@@ -4166,7 +4308,7 @@ private void typeToBufferx(Type t, ref OutBuffer buf, ref HdrGenState hgs)
void visitFunction(TypeFunction t)
{
- //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref);
+ //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isRef);
visitFuncIdentWithPostfix(t, null, buf, hgs, false);
}
@@ -4264,13 +4406,23 @@ private void typeToBufferx(Type t, ref OutBuffer buf, ref HdrGenState hgs)
void visitTag(TypeTag t)
{
- if (t.mod & MODFlags.const_)
- buf.writestring("const ");
if (hgs.importcHdr && t.id)
{
+ // https://issues.dlang.org/show_bug.cgi?id=24670
+ // `const` must be parenthesized because it can be a return type
+ if (t.mod & MODFlags.const_)
+ buf.writestring("const(");
+
+ // For C to D translation, `struct S` or `enum S` simply becomes `S`
buf.writestring(t.id.toString());
+
+ if (t.mod & MODFlags.const_)
+ buf.writestring(")");
return;
}
+ // The following produces something like "const enum E : short"
+ if (t.mod & MODFlags.const_)
+ buf.writestring("const ");
buf.writestring(Token.toString(t.tok));
buf.writeByte(' ');
if (t.id)
@@ -4314,6 +4466,11 @@ private void typeToBufferx(Type t, ref OutBuffer buf, ref HdrGenState hgs)
buf.writestring("noreturn");
}
+ if (hgs.importcHdr && !hgs.inCAlias && t.mcache && t.mcache.typedefIdent)
+ {
+ buf.writestring(t.mcache.typedefIdent.toString());
+ return;
+ }
switch (t.ty)
{
@@ -4488,7 +4645,15 @@ string EXPtoString(EXP op)
EXP.declaration : "declaration",
EXP.interval : "interval",
- EXP.loweredAssignExp : "="
+ EXP.loweredAssignExp : "=",
+
+ EXP.thrownException : "CTFE ThrownException",
+ EXP.cantExpression : "<cant>",
+ EXP.voidExpression : "cast(void)0",
+ EXP.showCtfeContext : "<error>",
+ EXP.break_ : "<break>",
+ EXP.continue_ : "<continue>",
+ EXP.goto_ : "<goto>",
];
const p = strings[op];
if (!p)
diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h
index 14793ad..2104b98 100644
--- a/gcc/d/dmd/hdrgen.h
+++ b/gcc/d/dmd/hdrgen.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Dave Fladebo
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d
index 1399ac2..689ef0f 100644
--- a/gcc/d/dmd/iasm.d
+++ b/gcc/d/dmd/iasm.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/iasm.html, Inline Assembler)
*
- * Copyright (C) 2018-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2018-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasm.d, _iasm.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasm.d, _iasm.d)
* Documentation: https://dlang.org/phobos/dmd_iasm.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/iasm.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/iasm.d
*/
module dmd.iasm;
@@ -39,7 +39,7 @@ else
/************************ AsmStatement ***************************************/
-Statement asmSemantic(AsmStatement s, Scope *sc)
+Statement asmSemantic(AsmStatement s, Scope* sc)
{
//printf("AsmStatement.semantic()\n");
@@ -50,7 +50,7 @@ Statement asmSemantic(AsmStatement s, Scope *sc)
return null;
// Assume assembler code takes care of setting the return value
- sc.func.hasReturnExp |= 8;
+ sc.func.hasInlineAsm = true;
version (NoBackend)
{
@@ -89,7 +89,7 @@ Statement asmSemantic(AsmStatement s, Scope *sc)
/************************ CAsmDeclaration ************************************/
-void asmSemantic(CAsmDeclaration ad, Scope *sc)
+void asmSemantic(CAsmDeclaration ad, Scope* sc)
{
version (NoBackend)
{
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
index 4b1b2e7..3d6e6ab 100644
--- a/gcc/d/dmd/iasmgcc.d
+++ b/gcc/d/dmd/iasmgcc.d
@@ -1,12 +1,12 @@
/**
* Inline assembler for the GCC D compiler.
*
- * Copyright (C) 2018-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2018-2025 by The D Language Foundation, All Rights Reserved
* Authors: Iain Buclaw
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d, _iasmgcc.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasmgcc.d, _iasmgcc.d)
* Documentation: https://dlang.org/phobos/dmd_iasmgcc.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/iasmgcc.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/iasmgcc.d
*/
module dmd.iasmgcc;
@@ -29,6 +29,118 @@ import dmd.tokens;
import dmd.statement;
import dmd.statementsem;
+/***********************************
+ * Parse and run semantic analysis on a GccAsmStatement.
+ * Params:
+ * s = gcc asm statement being parsed
+ * sc = the scope where the asm statement is located
+ * Returns:
+ * the completed gcc asm statement, or null if errors occurred
+ */
+public Statement gccAsmSemantic(GccAsmStatement s, Scope* sc)
+{
+ //printf("GccAsmStatement.semantic()\n");
+ const bool doUnittests = global.params.parsingUnittestsRequired();
+ scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink, &global.compileEnv, doUnittests);
+
+ // Make a safe copy of the token list before parsing.
+ Token* toklist = null;
+ Token **ptoklist = &toklist;
+
+ for (Token* token = s.tokens; token; token = token.next)
+ {
+ *ptoklist = p.allocateToken();
+ memcpy(*ptoklist, token, Token.sizeof);
+ ptoklist = &(*ptoklist).next;
+ *ptoklist = null;
+ }
+ p.token = *toklist;
+ p.baseLoc.startLine = s.loc.linnum;
+ p.linnum = s.loc.linnum;
+
+ // Parse the gcc asm statement.
+ const errors = global.errors;
+ s = p.parseGccAsm(s);
+ if (errors != global.errors)
+ return null;
+ s.stc = sc.stc;
+
+ // Fold the instruction template string.
+ s.insn = semanticString(sc, s.insn, "asm instruction template");
+
+ if (s.labels && s.outputargs)
+ error(s.loc, "extended asm statements with labels cannot have output constraints");
+
+ // Analyse all input and output operands.
+ if (s.args)
+ {
+ foreach (i; 0 .. s.args.length)
+ {
+ Expression e = (*s.args)[i];
+ e = e.expressionSemantic(sc);
+ // Check argument is a valid lvalue/rvalue.
+ if (i < s.outputargs)
+ e = e.modifiableLvalue(sc);
+ else if (e.checkValue())
+ e = ErrorExp.get();
+ (*s.args)[i] = e;
+
+ e = (*s.constraints)[i];
+ e = e.expressionSemantic(sc);
+ assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
+ (*s.constraints)[i] = e;
+ }
+ }
+
+ // Analyse all clobbers.
+ if (s.clobbers)
+ {
+ foreach (i; 0 .. s.clobbers.length)
+ {
+ Expression e = (*s.clobbers)[i];
+ e = e.expressionSemantic(sc);
+ assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
+ (*s.clobbers)[i] = e;
+ }
+ }
+
+ // Analyse all goto labels.
+ if (s.labels)
+ {
+ foreach (i; 0 .. s.labels.length)
+ {
+ Identifier ident = (*s.labels)[i];
+ GotoStatement gs = new GotoStatement(s.loc, ident);
+ if (!s.gotos)
+ s.gotos = new GotoStatements();
+ s.gotos.push(gs);
+ gs.statementSemantic(sc);
+ }
+ }
+
+ return s;
+}
+
+/***********************************
+ * Run semantic analysis on an CAsmDeclaration.
+ * Params:
+ * ad = asm declaration
+ * sc = the scope where the asm declaration is located
+ */
+public void gccAsmSemantic(CAsmDeclaration ad, Scope* sc)
+{
+ import dmd.typesem : pointerTo;
+ ad.code = semanticString(sc, ad.code, "asm definition");
+ ad.code.type = ad.code.type.nextOf().pointerTo();
+
+ // Asm definition always needs emitting into the root module.
+ import dmd.dmodule : Module;
+ if (sc._module && sc._module.isRoot())
+ return;
+ if (Module m = Module.rootModule)
+ m.members.push(ad);
+}
+
private:
/***********************************
@@ -143,9 +255,9 @@ Lerror:
* Returns:
* array of parsed clobber expressions
*/
-Expressions *parseExtAsmClobbers(Parser)(Parser p)
+Expressions* parseExtAsmClobbers(Parser)(Parser p)
{
- Expressions *clobbers;
+ Expressions* clobbers;
while (1)
{
@@ -194,9 +306,9 @@ Lerror:
* Returns:
* array of parsed goto labels
*/
-Identifiers *parseExtAsmGotoLabels(Parser)(Parser p)
+Identifiers* parseExtAsmGotoLabels(Parser)(Parser p)
{
- Identifiers *labels;
+ Identifiers* labels;
while (1)
{
@@ -292,117 +404,6 @@ Ldone:
return s;
}
-/***********************************
- * Parse and run semantic analysis on a GccAsmStatement.
- * Params:
- * s = gcc asm statement being parsed
- * sc = the scope where the asm statement is located
- * Returns:
- * the completed gcc asm statement, or null if errors occurred
- */
-public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
-{
- //printf("GccAsmStatement.semantic()\n");
- const bool doUnittests = global.params.parsingUnittestsRequired();
- scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink, &global.compileEnv, doUnittests);
-
- // Make a safe copy of the token list before parsing.
- Token *toklist = null;
- Token **ptoklist = &toklist;
-
- for (Token *token = s.tokens; token; token = token.next)
- {
- *ptoklist = p.allocateToken();
- memcpy(*ptoklist, token, Token.sizeof);
- ptoklist = &(*ptoklist).next;
- *ptoklist = null;
- }
- p.token = *toklist;
- p.scanloc = s.loc;
-
- // Parse the gcc asm statement.
- const errors = global.errors;
- s = p.parseGccAsm(s);
- if (errors != global.errors)
- return null;
- s.stc = sc.stc;
-
- // Fold the instruction template string.
- s.insn = semanticString(sc, s.insn, "asm instruction template");
-
- if (s.labels && s.outputargs)
- error(s.loc, "extended asm statements with labels cannot have output constraints");
-
- // Analyse all input and output operands.
- if (s.args)
- {
- foreach (i; 0 .. s.args.length)
- {
- Expression e = (*s.args)[i];
- e = e.expressionSemantic(sc);
- // Check argument is a valid lvalue/rvalue.
- if (i < s.outputargs)
- e = e.modifiableLvalue(sc);
- else if (e.checkValue())
- e = ErrorExp.get();
- (*s.args)[i] = e;
-
- e = (*s.constraints)[i];
- e = e.expressionSemantic(sc);
- assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
- (*s.constraints)[i] = e;
- }
- }
-
- // Analyse all clobbers.
- if (s.clobbers)
- {
- foreach (i; 0 .. s.clobbers.length)
- {
- Expression e = (*s.clobbers)[i];
- e = e.expressionSemantic(sc);
- assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
- (*s.clobbers)[i] = e;
- }
- }
-
- // Analyse all goto labels.
- if (s.labels)
- {
- foreach (i; 0 .. s.labels.length)
- {
- Identifier ident = (*s.labels)[i];
- GotoStatement gs = new GotoStatement(s.loc, ident);
- if (!s.gotos)
- s.gotos = new GotoStatements();
- s.gotos.push(gs);
- gs.statementSemantic(sc);
- }
- }
-
- return s;
-}
-
-/***********************************
- * Run semantic analysis on an CAsmDeclaration.
- * Params:
- * ad = asm declaration
- * sc = the scope where the asm declaration is located
- */
-public void gccAsmSemantic(CAsmDeclaration ad, Scope *sc)
-{
- import dmd.typesem : pointerTo;
- ad.code = semanticString(sc, ad.code, "asm definition");
- ad.code.type = ad.code.type.nextOf().pointerTo();
-
- // Asm definition always needs emitting into the root module.
- import dmd.dmodule : Module;
- if (sc._module && sc._module.isRoot())
- return;
- if (Module m = Module.rootModule)
- m.members.push(ad);
-}
-
unittest
{
import dmd.mtype : TypeBasic;
@@ -410,7 +411,7 @@ unittest
if (!global.errorSink)
global.errorSink = new ErrorSinkCompiler;
- uint errors = global.startGagging();
+ const errors = global.startGagging();
scope(exit) global.endGagging(errors);
// If this check fails, then Type._init() was called before reaching here,
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index 5ad324d..e1c22f2 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -1,12 +1,12 @@
/**
* Contains the `Id` struct with a list of predefined symbols the compiler knows about.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/id.d, _id.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/id.d, _id.d)
* Documentation: https://dlang.org/phobos/dmd_id.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/id.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/id.d
*/
module dmd.id;
@@ -102,6 +102,8 @@ immutable Msgtable[] msgtable =
{ "ctfe", "__ctfe" },
{ "offset" },
{ "offsetof" },
+ { "bitoffsetof" },
+ { "bitwidth" },
{ "ModuleInfo" },
{ "ClassInfo" },
{ "classinfo" },
@@ -164,6 +166,7 @@ immutable Msgtable[] msgtable =
{ "xopCmp", "__xopCmp" },
{ "xtoHash", "__xtoHash" },
{ "__tmpfordtor" },
+ { "Entry" },
{ "LINE", "__LINE__" },
{ "FILE", "__FILE__" },
@@ -221,60 +224,15 @@ immutable Msgtable[] msgtable =
{ "__LOCAL_SIZE" },
// For operator overloads
- { "uadd", "opPos" },
- { "neg", "opNeg" },
- { "com", "opCom" },
- { "add", "opAdd" },
- { "add_r", "opAdd_r" },
- { "sub", "opSub" },
- { "sub_r", "opSub_r" },
- { "mul", "opMul" },
- { "mul_r", "opMul_r" },
- { "div", "opDiv" },
- { "div_r", "opDiv_r" },
- { "mod", "opMod" },
- { "mod_r", "opMod_r" },
- { "eq", "opEquals" },
- { "cmp", "opCmp" },
- { "iand", "opAnd" },
- { "iand_r", "opAnd_r" },
- { "ior", "opOr" },
- { "ior_r", "opOr_r" },
- { "ixor", "opXor" },
- { "ixor_r", "opXor_r" },
- { "shl", "opShl" },
- { "shl_r", "opShl_r" },
- { "shr", "opShr" },
- { "shr_r", "opShr_r" },
- { "ushr", "opUShr" },
- { "ushr_r", "opUShr_r" },
- { "cat", "opCat" },
- { "cat_r", "opCat_r" },
- { "assign", "opAssign" },
- { "addass", "opAddAssign" },
- { "subass", "opSubAssign" },
- { "mulass", "opMulAssign" },
- { "divass", "opDivAssign" },
- { "modass", "opModAssign" },
- { "andass", "opAndAssign" },
- { "orass", "opOrAssign" },
- { "xorass", "opXorAssign" },
- { "shlass", "opShlAssign" },
- { "shrass", "opShrAssign" },
- { "ushrass", "opUShrAssign" },
- { "catass", "opCatAssign" },
- { "postinc", "opPostInc" },
- { "postdec", "opPostDec" },
- { "index", "opIndex" },
- { "indexass", "opIndexAssign" },
- { "slice", "opSlice" },
- { "sliceass", "opSliceAssign" },
- { "call", "opCall" },
- { "_cast", "opCast" },
- { "opIn" },
- { "opIn_r" },
- { "opStar" },
- { "opDot" },
+ { "opEquals" },
+ { "opCmp" },
+ { "opAssign" },
+ { "opIndex" },
+ { "opIndexAssign" },
+ { "opSlice" },
+ { "opSliceAssign" },
+ { "opCall" },
+ { "opCast" },
{ "opDispatch" },
{ "opDollar" },
{ "opUnary" },
@@ -285,9 +243,6 @@ immutable Msgtable[] msgtable =
{ "opOpAssign" },
{ "opIndexOpAssign" },
{ "opSliceOpAssign" },
- { "pow", "opPow" },
- { "pow_r", "opPow_r" },
- { "powass", "opPowAssign" },
{ "classNew", "new" },
{ "classDelete", "delete" },
@@ -387,6 +342,7 @@ immutable Msgtable[] msgtable =
// Builtin functions
{ "std" },
{ "core" },
+ { "internal" },
{ "config" },
{ "c_complex_float" },
{ "c_complex_double" },
@@ -448,11 +404,14 @@ immutable Msgtable[] msgtable =
{ "outp"},
{ "outpl"},
{ "outpw"},
+ { "builtinsModuleName", "builtins" },
+ { "ctfeWrite", "__ctfeWrite" },
// Traits
{ "isAbstractClass" },
{ "isArithmetic" },
{ "isAssociativeArray" },
+ { "isBitfield" },
{ "isFinalClass" },
{ "isTemplate" },
{ "isPOD" },
@@ -476,9 +435,12 @@ immutable Msgtable[] msgtable =
{ "isRef" },
{ "isOut" },
{ "isLazy" },
+ { "isCOMClass" },
{ "hasMember" },
{ "identifier" },
{ "fullyQualifiedName" },
+ { "getBitfieldOffset" },
+ { "getBitfieldWidth" },
{ "getProtection" },
{ "getVisibility" },
{ "parent" },
@@ -510,6 +472,7 @@ immutable Msgtable[] msgtable =
{ "getLocation" },
{ "hasPostblit" },
{ "hasCopyConstructor" },
+ { "hasMoveConstructor" },
{ "isCopyable" },
{ "toType" },
{ "parameters" },
@@ -529,6 +492,9 @@ immutable Msgtable[] msgtable =
{ "udaMustUse", "mustuse" },
{ "udaStandalone", "standalone" },
+ // Editions
+ { "__edition_latest_do_not_use", },
+
// C names, for undefined identifier error messages
{ "NULL" },
{ "TRUE" },
@@ -553,7 +519,7 @@ immutable Msgtable[] msgtable =
{ "_align", "align" },
{ "aligned" },
{ "__pragma", "pragma" },
- { "builtins", "__builtins" },
+ { "importc_builtins", "__importc_builtins" },
{ "builtin_va_list", "__builtin_va_list" },
{ "builtin_va_arg", "__builtin_va_arg" },
{ "va_list_tag", "__va_list_tag" },
@@ -566,6 +532,7 @@ immutable Msgtable[] msgtable =
{ "define" },
{ "undef" },
{ "ident" },
+ { "packed" },
];
diff --git a/gcc/d/dmd/id.h b/gcc/d/dmd/id.h
index ddc8da2..cab42bf 100644
--- a/gcc/d/dmd/id.h
+++ b/gcc/d/dmd/id.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 2017-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2017-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d
index 8ace310..c213597 100644
--- a/gcc/d/dmd/identifier.d
+++ b/gcc/d/dmd/identifier.d
@@ -1,12 +1,12 @@
/**
* Defines an identifier, which is the name of a `Dsymbol`.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d, _identifier.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/identifier.d, _identifier.d)
* Documentation: https://dlang.org/phobos/dmd_identifier.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/identifier.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/identifier.d
*/
module dmd.identifier;
@@ -108,7 +108,8 @@ nothrow:
const(char)* p = null;
if (this == Id.ctor)
p = "this";
- else if (this == Id.dtor)
+ else if (this == Id.dtor || this == Id.__xdtor || this == Id.__fieldDtor ||
+ this == Id.__aggrDtor || this == Id.cppdtor || this == Id.ticppdtor)
p = "~this";
else if (this == Id.unitTest)
p = "unittest";
@@ -120,6 +121,8 @@ nothrow:
p = "result";
else if (this == Id.returnLabel)
p = "return";
+ else if (this == Id.postblit)
+ p = "this(this)";
else
{
p = toChars();
@@ -211,19 +214,23 @@ nothrow:
* Params:
* prefix = first part of the identifier name.
* loc = source location to use in the identifier name.
+ * parent = (optional) extra part to be used in uniqueness check,
+ * if (prefix1, loc1) == (prefix2, loc2), but
+ * parent1 != parent2, no new name will be generated.
* Returns:
* Identifier (inside Identifier.idPool) with deterministic name based
* on the source location.
*/
- extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc)
+ extern (D) static Identifier generateIdWithLoc(string prefix, Loc loc, string parent = "")
{
// generate `<prefix>_L<line>_C<col>`
+ auto sl = SourceLoc(loc);
OutBuffer idBuf;
idBuf.writestring(prefix);
idBuf.writestring("_L");
- idBuf.print(loc.linnum);
+ idBuf.print(sl.line);
idBuf.writestring("_C");
- idBuf.print(loc.charnum);
+ idBuf.print(sl.column);
/**
* Make sure the identifiers are unique per filename, i.e., per module/mixin
@@ -234,14 +241,21 @@ nothrow:
* https://issues.dlang.org/show_bug.cgi?id=18880
* https://issues.dlang.org/show_bug.cgi?id=18868
* https://issues.dlang.org/show_bug.cgi?id=19058
+ *
+ * It is a bit trickier for lambdas/dgliterals: we want them to be unique per
+ * module/mixin + function/template instantiation context. So we use extra parent
+ * argument for that when dealing with lambdas. We could have added it to prefix
+ * directly, but that would unnecessary lengthen symbols names. See issue:
+ * https://issues.dlang.org/show_bug.cgi?id=23722
*/
- static struct Key { Loc loc; string prefix; }
+ static struct Key { string locKey; string prefix; string parent; }
__gshared uint[Key] counters;
+ string locKey = cast(string) (sl.filename ~ idBuf[]);
static if (__traits(compiles, counters.update(Key.init, () => 0u, (ref uint a) => 0u)))
{
// 2.082+
- counters.update(Key(loc, prefix),
+ counters.update(Key(locKey, prefix, parent),
() => 1u, // insertion
(ref uint counter) // update
{
@@ -253,7 +267,7 @@ nothrow:
}
else
{
- const key = Key(loc, prefix);
+ const key = Key(locKey, prefix, parent);
if (auto pCounter = key in counters)
{
idBuf.writestring("_");
@@ -269,12 +283,12 @@ nothrow:
/********************************************
* Create an identifier in the string table.
*/
- static Identifier idPool(const(char)* s, uint len)
+ static Identifier idPool(scope const(char)* s, uint len)
{
return idPool(s[0 .. len]);
}
- extern (D) static Identifier idPool(const(char)[] s, bool isAnonymous = false)
+ extern (D) static Identifier idPool(scope const(char)[] s, bool isAnonymous = false)
{
auto sv = stringtable.update(s);
auto id = sv.value;
@@ -292,7 +306,7 @@ nothrow:
* s = string for keyword
* value = TOK.xxxx for the keyword
*/
- extern (D) static void idPool(const(char)[] s, TOK value)
+ extern (D) static void idPool(scope const(char)[] s, TOK value)
{
auto sv = stringtable.insert(s, null);
assert(sv);
@@ -315,28 +329,83 @@ nothrow:
/**********************************
* ditto
*/
- extern (D) static bool isValidIdentifier(const(char)[] str) @safe
+ extern (D) static bool isValidIdentifier(const(char)[] str) @trusted
{
+ import dmd.common.charactertables;
+
if (str.length == 0 ||
(str[0] >= '0' && str[0] <= '9')) // beware of isdigit() on signed chars
{
return false;
}
- size_t idx = 0;
- while (idx < str.length)
+ // In a previous implementation this was implemented quite naively,
+ // by utilizing the libc.
+ // However we can do better, by copying the lexer approach to identifier validation.
+
+ const(char)* p = &str[0], pEnd = str.ptr + str.length;
+
+ // handle start characters
{
- dchar dc;
- const s = utf_decodeChar(str, idx, dc);
- if (s ||
- !((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
+ const c = *p;
+
+ if (isidchar(c))
+ p++;
+ else if (c & 0x80)
{
+ size_t countDecoded;
+ dchar decoded;
+
+ if (utf_decodeChar(p[0 .. pEnd - p], countDecoded, decoded) is null ||
+ isAnyStart(decoded))
+ p += countDecoded;
+ else
+ return false;
+ }
+ else
return false;
+ }
+
+ // handle continue characters
+ while(p !is pEnd)
+ {
+ const c = *p;
+
+ if (isidchar(c)) // handles ASCII subset
+ {
+ p++;
+ continue;
}
+ else if (c & 0x80)
+ {
+ size_t countDecoded;
+ dchar decoded;
+
+ if (utf_decodeChar(p[0 .. pEnd - p], countDecoded, decoded) is null ||
+ isAnyContinue(decoded))
+ {
+ p += countDecoded;
+ continue;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
}
+
return true;
}
+ ///
+ unittest
+ {
+ assert(Identifier.isValidIdentifier("tes123_t".ptr));
+ assert(!Identifier.isValidIdentifier("tes123_^t".ptr));
+ assert(Identifier.isValidIdentifier("te123s_ÄŸt".ptr));
+ assert(!Identifier.isValidIdentifier("t^e123s_ÄŸt".ptr));
+ }
+
extern (D) static Identifier lookup(const(char)* s, size_t len)
{
return lookup(s[0 .. len]);
diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h
index 4f26801..eb06c25 100644
--- a/gcc/d/dmd/identifier.h
+++ b/gcc/d/dmd/identifier.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/impcnvtab.d b/gcc/d/dmd/impcnvtab.d
index b899f81..b2ab919 100644
--- a/gcc/d/dmd/impcnvtab.d
+++ b/gcc/d/dmd/impcnvtab.d
@@ -6,12 +6,12 @@
* Specification: $(LINK2 https://dlang.org/spec/type.html#integer-promotions, Integer Promotions),
* $(LINK2 https://dlang.org/spec/type.html#usual-arithmetic-conversions, Usual Arithmetic Conversions).
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d, _impcnvtab.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/impcnvtab.d, _impcnvtab.d)
* Documentation: https://dlang.org/phobos/dmd_impcnvtab.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/impcnvtab.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/impcnvtab.d
*/
module dmd.impcnvtab;
diff --git a/gcc/d/dmd/imphint.d b/gcc/d/dmd/imphint.d
index ea2f13d..382a0f3 100644
--- a/gcc/d/dmd/imphint.d
+++ b/gcc/d/dmd/imphint.d
@@ -3,12 +3,12 @@
*
* For example, prompt to `import std.stdio` when using `writeln`.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d, _imphint.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/imphint.d, _imphint.d)
* Documentation: https://dlang.org/phobos/dmd_imphint.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/imphint.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/imphint.d
*/
module dmd.imphint;
@@ -80,6 +80,8 @@ shared static this()
"writeln": "std.stdio",
"__va_argsave_t": "core.stdc.stdarg",
"__va_list_tag": "core.stdc.stdarg",
+ "InterpolationHeader": "core.interpolation",
+ "InterpolationFooter": "core.interpolation",
];
}
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
index bfbb551..14bd889 100644
--- a/gcc/d/dmd/import.h
+++ b/gcc/d/dmd/import.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -44,6 +44,5 @@ public:
Dsymbol *toAlias() override;
bool overloadInsert(Dsymbol *s) override;
- Import *isImport() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
index ece56c8..2f88a21 100644
--- a/gcc/d/dmd/importc.d
+++ b/gcc/d/dmd/importc.d
@@ -3,12 +3,12 @@
*
* Specification: C11
*
- * Copyright: Copyright (C) 2021-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 2021-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/importc.d, _importc.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/importc.d, _importc.d)
* Documentation: https://dlang.org/phobos/dmd_importc.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/importc.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/importc.d
*/
module dmd.importc;
@@ -41,7 +41,7 @@ import dmd.typesem;
*/
Type cAdjustParamType(Type t, Scope* sc)
{
- if (!(sc.flags & SCOPE.Cfile))
+ if (!sc.inCfile)
return t;
Type tb = t.toBasetype();
@@ -77,7 +77,7 @@ Type cAdjustParamType(Type t, Scope* sc)
Expression arrayFuncConv(Expression e, Scope* sc)
{
//printf("arrayFuncConv() %s\n", e.toChars());
- if (!(sc.flags & SCOPE.Cfile))
+ if (!sc.inCfile)
return e;
auto t = e.type.toBasetype();
@@ -121,7 +121,6 @@ Expression fieldLookup(Expression e, Scope* sc, Identifier id, bool arrow)
if (e.isErrorExp())
return e;
- Dsymbol s;
auto t = e.type;
if (t.isTypePointer())
{
@@ -131,6 +130,7 @@ Expression fieldLookup(Expression e, Scope* sc, Identifier id, bool arrow)
error(e.loc, "since `%s` is a pointer, use `%s->%s` instead of `%s.%s`", pe, pe, id.toChars(), pe, id.toChars());
e = new PtrExp(e.loc, e);
}
+ Dsymbol s;
if (auto ts = t.isTypeStruct())
s = ts.sym.search(e.loc, id, 0);
if (!s)
@@ -154,7 +154,7 @@ Expression fieldLookup(Expression e, Scope* sc, Identifier id, bool arrow)
*/
Expression carraySemantic(ArrayExp ae, Scope* sc)
{
- if (!(sc.flags & SCOPE.Cfile))
+ if (!sc.inCfile)
return null;
auto e1 = ae.e1.expressionSemantic(sc);
@@ -166,7 +166,7 @@ Expression carraySemantic(ArrayExp ae, Scope* sc)
* So, rewrite as an IndexExp if we can.
*/
auto t1 = e1.type.toBasetype();
- if (t1.isTypeDArray() || t1.isTypeSArray())
+ if (t1.isStaticOrDynamicArray())
{
e2 = e2.expressionSemantic(sc).arrayFuncConv(sc);
// C doesn't do array bounds checking, so `true` turns it off
@@ -176,7 +176,7 @@ Expression carraySemantic(ArrayExp ae, Scope* sc)
e1 = e1.arrayFuncConv(sc); // e1 might still be a function call
e2 = e2.expressionSemantic(sc);
auto t2 = e2.type.toBasetype();
- if (t2.isTypeDArray() || t2.isTypeSArray())
+ if (t2.isStaticOrDynamicArray())
{
return new IndexExp(ae.loc, e2, e1, true).expressionSemantic(sc); // swap operands
}
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index 62bd41e..55fb6f3 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -1,12 +1,12 @@
/**
* Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/init.d, _init.d)
* Documentation: https://dlang.org/phobos/dmd_init.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/init.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/init.d
*/
module dmd.init;
@@ -38,6 +38,7 @@ extern (C++) class Initializer : ASTNode
{
Loc loc;
InitKind kind;
+ bool semanticDone = false; /// initializerSemantic has been run on this
override DYNCAST dyncast() const
{
@@ -45,44 +46,44 @@ extern (C++) class Initializer : ASTNode
}
- extern (D) this(const ref Loc loc, InitKind kind) @safe
+ extern (D) this(Loc loc, InitKind kind) @safe
{
this.loc = loc;
this.kind = kind;
}
- final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure
+ final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure @trusted
{
// Use void* cast to skip dynamic casting call
return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null;
}
- final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure
+ final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure @trusted
{
return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null;
}
- final inout(DefaultInitializer) isDefaultInitializer() inout @nogc nothrow pure
+ final inout(DefaultInitializer) isDefaultInitializer() inout @nogc nothrow pure @trusted
{
return kind == InitKind.default_ ? cast(inout DefaultInitializer)cast(void*)this : null;
}
- final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure
+ final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure @trusted
{
return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null;
}
- final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure
+ final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure @trusted
{
return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null;
}
- final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure
+ final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure @trusted
{
return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null;
}
- final inout(CInitializer) isCInitializer() inout @nogc nothrow pure
+ final inout(CInitializer) isCInitializer() inout @nogc nothrow pure @trusted
{
return kind == InitKind.C_ ? cast(inout CInitializer)cast(void*)this : null;
}
@@ -99,7 +100,7 @@ extern (C++) final class VoidInitializer : Initializer
{
Type type; // type that this will initialize to
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, InitKind.void_);
}
@@ -117,7 +118,7 @@ extern (C++) final class DefaultInitializer : Initializer
{
Type type; // type that this will initialize to
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, InitKind.default_);
}
@@ -150,7 +151,7 @@ extern (C++) final class StructInitializer : Initializer
Identifiers field; // of Identifier *'s
Initializers value; // parallel array of Initializer *'s
- extern (D) this(const ref Loc loc)
+ extern (D) this(Loc loc)
{
super(loc, InitKind.struct_);
}
@@ -176,10 +177,9 @@ extern (C++) final class ArrayInitializer : Initializer
Initializers value; // of Initializer *'s
uint dim; // length of array being initialized
Type type; // type that array will be used to initialize
- bool sem; // true if semantic() is run
bool isCarray; // C array semantics
- extern (D) this(const ref Loc loc)
+ extern (D) this(Loc loc)
{
super(loc, InitKind.array);
}
@@ -215,7 +215,7 @@ extern (C++) final class ExpInitializer : Initializer
bool expandTuples;
Expression exp;
- extern (D) this(const ref Loc loc, Expression exp) @safe
+ extern (D) this(Loc loc, Expression exp) @safe
{
super(loc, InitKind.exp);
this.exp = exp;
@@ -256,9 +256,8 @@ extern (C++) final class CInitializer : Initializer
{
DesigInits initializerList; /// initializer-list
Type type; /// type that array will be used to initialize
- bool sem; /// true if semantic() is run
- extern (D) this(const ref Loc loc)
+ extern (D) this(Loc loc)
{
super(loc, InitKind.C_);
}
diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h
index 2485d78..a832b9e 100644
--- a/gcc/d/dmd/init.h
+++ b/gcc/d/dmd/init.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -33,6 +33,7 @@ class Initializer : public ASTNode
public:
Loc loc;
unsigned char kind;
+ d_bool semanticDone;
DYNCAST dyncast() const override { return DYNCAST_INITIALIZER; }
@@ -85,7 +86,6 @@ public:
Initializers value; // of Initializer *'s
unsigned dim; // length of array being initialized
Type *type; // type that array will be used to initialize
- d_bool sem; // true if semantic() is run
d_bool isCarray; // C array semantics
bool isAssociativeArray() const;
@@ -119,13 +119,12 @@ class CInitializer final : public Initializer
public:
DesigInits initializerList;
Type *type; // type that array will be used to initialize
- d_bool sem; // true if semantic() is run
void accept(Visitor *v) override { v->visit(this); }
};
namespace dmd
{
- Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
+ Expression *initializerToExpression(Initializer *init, Type *t = nullptr, const bool isCfile = false);
Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *&tx, NeedInterpret needInterpret);
}
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index b07699e..1ebccf77 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -1,12 +1,12 @@
/**
* Semantic analysis of initializers.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d, _initsem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/initsem.d, _initsem.d)
* Documentation: https://dlang.org/phobos/dmd_initsem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/initsem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/initsem.d
*/
module dmd.initsem;
@@ -41,6 +41,7 @@ import dmd.location;
import dmd.mtype;
import dmd.opover;
import dmd.optimize;
+import dmd.safe : setUnsafe;
import dmd.statement;
import dmd.target;
import dmd.tokens;
@@ -106,6 +107,9 @@ Expression toAssocArrayLiteral(ArrayInitializer ai)
Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret)
{
//printf("initializerSemantic() tx: %p %s\n", tx, tx.toChars());
+ if (init.semanticDone)
+ return init;
+
Type t = tx;
static Initializer err()
@@ -161,7 +165,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
// Convert initializer to Expression `ex`
auto tm = fieldType.addMod(t.mod);
auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret);
- auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
+ auto ex = iz.initializerToExpression(null, sc.inCfile);
if (ex.op != EXP.error)
i.value[j] = iz;
return ex;
@@ -203,11 +207,6 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
const(uint) amax = 0x80000000;
bool errors = false;
//printf("ArrayInitializer::semantic(%s), ai: %s\n", t.toChars(), toChars(i));
- if (i.sem) // if semantic() already run
- {
- return i;
- }
- i.sem = true;
t = t.toBasetype();
switch (t.ty)
{
@@ -305,7 +304,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
}
if (auto tsa = t.isTypeSArray())
{
- if (sc.flags & SCOPE.Cfile && tsa.isIncomplete())
+ if (sc.inCfile && tsa.isIncomplete())
{
// Change to array of known length
auto tn = tsa.next.toBasetype();
@@ -369,7 +368,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
// If the result will be implicitly cast, move the cast into CTFE
// to avoid premature truncation of polysemous types.
// eg real [] x = [1.1, 2.2]; should use real precision.
- if (i.exp.implicitConvTo(t) && !(sc.flags & SCOPE.Cfile))
+ if (i.exp.implicitConvTo(t) && !sc.inCfile)
{
i.exp = i.exp.implicitCastTo(sc, t);
}
@@ -377,7 +376,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
{
return i;
}
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
/* the interpreter turns (char*)"string" into &"string"[0] which then
* it cannot interpret. Resolve that case by doing optimize() first
@@ -440,7 +439,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
Type typeb = se.type.toBasetype();
TY tynto = tb.nextOf().ty;
if (!se.committed &&
- (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
+ typeb.isStaticOrDynamicArray() && tynto.isSomeChar &&
se.numberOfCodeUnits(tynto) < tb.isTypeSArray().dim.toInteger())
{
i.exp = se.castTo(sc, t);
@@ -450,7 +449,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
/* Lop off terminating 0 of initializer for:
* static char s[5] = "hello";
*/
- if (sc.flags & SCOPE.Cfile &&
+ if (sc.inCfile &&
typeb.ty == Tsarray &&
tynto.isSomeChar &&
tb.isTypeSArray().dim.toInteger() + 1 == typeb.isTypeSArray().dim.toInteger())
@@ -463,7 +462,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
* Initialize an array of unknown size with a string.
* Change to static array of known size
*/
- if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
+ if (sc.inCfile && i.exp.isStringExp() &&
tb.isTypeSArray() && tb.isTypeSArray().isIncomplete())
{
StringExp se = i.exp.isStringExp();
@@ -490,7 +489,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
else
i.exp = e.optimize(WANTvalue);
}
- else if (search_function(sd, Id.call))
+ else if (search_function(sd, Id.opCall))
{
/* https://issues.dlang.org/show_bug.cgi?id=1547
*
@@ -500,7 +499,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
* i.exp = typeof(sd).opCall(arguments)
*/
- Expression e = typeDotIdExp(i.loc, sd.type, Id.call);
+ Expression e = typeDotIdExp(i.loc, sd.type, Id.opCall);
e = new CallExp(i.loc, e, i.exp);
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
@@ -549,7 +548,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
{
i.exp = i.exp.implicitCastTo(sc, t);
}
- else if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
+ else if (sc.inCfile && i.exp.isStringExp() &&
tta && (tta.next.ty == Tint8 || tta.next.ty == Tuns8) &&
ti.ty == Tsarray && ti.nextOf().ty == Tchar)
{
@@ -586,7 +585,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
const errors = global.startGagging();
i.exp = i.exp.implicitCastTo(sc, t);
if (global.endGagging(errors))
- error(currExp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars());
+ error(currExp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toErrMsg(), et.toChars(), t.toChars());
}
}
L1:
@@ -692,51 +691,49 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
auto di = ci.initializerList[index];
if (di.designatorList && fieldi != 0)
break; // back to top level
- else
+
+ VarDeclaration field;
+ while (1) // skip field if it overlaps with previously seen fields
{
- VarDeclaration field;
- while (1) // skip field if it overlaps with previously seen fields
- {
- field = sd.fields[fieldi];
- ++fieldi;
- if (!overlaps(field, sd.fields[], si))
- break;
- if (fieldi == nfields)
- break;
- }
- auto tn = field.type.toBasetype();
- auto tnsa = tn.isTypeSArray();
- auto tns = tn.isTypeStruct();
- auto ix = di.initializer;
- if (tnsa && ix.isExpInitializer())
- {
- ExpInitializer ei = ix.isExpInitializer();
- if (ei.exp.isStringExp() && tnsa.nextOf().isintegral())
- {
- si.addInit(field.ident, ei);
- ++index;
- }
- else
- si.addInit(field.ident, subArray(tnsa, index)); // fwd ref of subArray is why subStruct is a template
- }
- else if (tns && ix.isExpInitializer())
+ field = sd.fields[fieldi];
+ ++fieldi;
+ if (!overlaps(field, sd.fields[], si))
+ break;
+ if (fieldi == nfields)
+ break;
+ }
+ auto tn = field.type.toBasetype();
+ auto tnsa = tn.isTypeSArray();
+ auto tns = tn.isTypeStruct();
+ auto ix = di.initializer;
+ if (tnsa && ix.isExpInitializer())
+ {
+ ExpInitializer ei = ix.isExpInitializer();
+ if (ei.exp.isStringExp() && tnsa.nextOf().isIntegral())
{
- /* Disambiguate between an exp representing the entire
- * struct, and an exp representing the first field of the struct
- */
- if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct
- {
- si.addInit(field.ident, initializerSemantic(ix, sc, tn, needInterpret));
- ++index;
- }
- else // field initializers for struct
- si.addInit(field.ident, subStruct(tns, index)); // the first field
+ si.addInit(field.ident, ei);
+ ++index;
}
else
+ si.addInit(field.ident, subArray(tnsa, index)); // fwd ref of subArray is why subStruct is a template
+ }
+ else if (tns && ix.isExpInitializer())
+ {
+ /* Disambiguate between an exp representing the entire
+ * struct, and an exp representing the first field of the struct
+ */
+ if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct
{
- si.addInit(field.ident, ix);
+ si.addInit(field.ident, initializerSemantic(ix, sc, tn, needInterpret));
++index;
}
+ else // field initializers for struct
+ si.addInit(field.ident, subStruct(tns, index)); // the first field
+ }
+ else
+ {
+ si.addInit(field.ident, ix);
+ ++index;
}
}
//printf("subStruct() returns ai: %s, index: %d\n", si.toChars(), cast(int)index);
@@ -774,7 +771,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
else if (tnsa && di.initializer.isExpInitializer())
{
ExpInitializer ei = di.initializer.isExpInitializer();
- if (ei.exp.isStringExp() && tnsa.nextOf().isintegral())
+ if (ei.exp.isStringExp() && tnsa.nextOf().isIntegral())
{
ai.addInit(null, ei);
++index;
@@ -837,103 +834,110 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars());
return err();
}
- else
- {
- if (fieldi == nfields)
- break;
- auto ix = di.initializer;
+ if (fieldi == nfields)
+ break;
- /* If a C initializer is wrapped in a C initializer, with no designators,
- * peel off the outer one
- */
- if (ix.isCInitializer())
+ auto ix = di.initializer;
+
+ /* If a C initializer is wrapped in a C initializer, with no designators,
+ * peel off the outer one
+ */
+ if (ix.isCInitializer())
+ {
+ CInitializer cix = ix.isCInitializer();
+ if (cix.initializerList.length == 1)
{
- CInitializer cix = ix.isCInitializer();
- if (cix.initializerList.length == 1)
+ DesigInit dix = cix.initializerList[0];
+ if (!dix.designatorList)
{
- DesigInit dix = cix.initializerList[0];
- if (!dix.designatorList)
- {
- Initializer inix = dix.initializer;
- if (inix.isCInitializer())
- ix = inix;
- }
+ Initializer inix = dix.initializer;
+ if (inix.isCInitializer())
+ ix = inix;
}
}
+ }
- if (auto cix = ix.isCInitializer())
+ if (auto cix = ix.isCInitializer())
+ {
+ /* ImportC loses the structure from anonymous structs, but this is retained
+ * by the initializer syntax. if a CInitializer has a Designator, it is probably
+ * a nested anonymous struct
+ */
+ int found;
+ foreach (dix; cix.initializerList)
{
- /* ImportC loses the structure from anonymous structs, but this is retained
- * by the initializer syntax. if a CInitializer has a Designator, it is probably
- * a nested anonymous struct
- */
- if (cix.initializerList.length)
+ Designators* dlistx = dix.designatorList;
+ if (!dlistx)
+ continue;
+ if ((*dlistx).length == 1 && (*dlistx)[0].ident)
{
- DesigInit dix = cix.initializerList[0];
- Designators* dlistx = dix.designatorList;
- if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident)
+ auto id = (*dlistx)[0].ident;
+ foreach (k, f; sd.fields[]) // linear search for now
{
- auto id = (*dlistx)[0].ident;
- foreach (k, f; sd.fields[]) // linear search for now
+ if (f.ident == id)
{
- if (f.ident == id)
- {
- fieldi = k;
- si.addInit(id, dix.initializer);
- ++fieldi;
- ++index;
- continue Loop1;
- }
+ fieldi = k;
+ si.addInit(id, dix.initializer);
+ ++fieldi;
+ ++index;
+ ++found;
+ break;
}
}
}
+ else {
+ error(ci.loc, "only 1 designator currently allowed for C struct field initializer `%s`", toChars(ci));
+ }
}
- VarDeclaration field;
- while (1) // skip field if it overlaps with previously seen fields
- {
- field = sd.fields[fieldi];
- ++fieldi;
- if (!overlaps(field, sd.fields[], si))
- break;
- if (fieldi == nfields)
- break;
- }
+ if (found == cix.initializerList.length)
+ continue Loop1;
+ }
- auto tn = field.type.toBasetype();
- auto tnsa = tn.isTypeSArray();
- auto tns = tn.isTypeStruct();
+ VarDeclaration field;
+ while (1) // skip field if it overlaps with previously seen fields
+ {
+ field = sd.fields[fieldi];
+ ++fieldi;
+ if (!overlaps(field, sd.fields[], si))
+ break;
+ if (fieldi == nfields)
+ break;
+ }
- if (tnsa && ix.isExpInitializer())
- {
- ExpInitializer ei = ix.isExpInitializer();
- if (ei.exp.isStringExp() && tnsa.nextOf().isintegral())
- {
- si.addInit(field.ident, ei);
- ++index;
- }
- else
- si.addInit(field.ident, subArray(tnsa, index));
- }
- else if (tns && ix.isExpInitializer())
+ auto tn = field.type.toBasetype();
+ auto tnsa = tn.isTypeSArray();
+ auto tns = tn.isTypeStruct();
+
+ if (tnsa && ix.isExpInitializer())
+ {
+ ExpInitializer ei = ix.isExpInitializer();
+ if (ei.exp.isStringExp() && tnsa.nextOf().isIntegral())
{
- /* Disambiguate between an exp representing the entire
- * struct, and an exp representing the first field of the struct
- */
- if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct
- {
- si.addInit(field.ident, initializerSemantic(ix, sc, tn, needInterpret));
- ++index;
- }
- else // field initializers for struct
- si.addInit(field.ident, subStruct(tns, index)); // the first field
+ si.addInit(field.ident, ei);
+ ++index;
}
else
+ si.addInit(field.ident, subArray(tnsa, index));
+ }
+ else if (tns && ix.isExpInitializer())
+ {
+ /* Disambiguate between an exp representing the entire
+ * struct, and an exp representing the first field of the struct
+ */
+ if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct
{
- si.addInit(field.ident, di.initializer);
+ si.addInit(field.ident, initializerSemantic(ix, sc, tn, needInterpret));
++index;
}
+ else // field initializers for struct
+ si.addInit(field.ident, subStruct(tns, index)); // the first field
+ }
+ else
+ {
+ si.addInit(field.ident, di.initializer);
+ ++index;
}
}
return initializerSemantic(si, sc, t, needInterpret);
@@ -945,7 +949,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
/* If it's an array of integral being initialized by `{ string }`
* replace with `string`
*/
- if (tn.isintegral())
+ if (tn.isIntegral())
{
if (ExpInitializer ei = isBraceExpression())
{
@@ -1008,7 +1012,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
else if (tnsa && di.initializer.isExpInitializer())
{
ExpInitializer ei = di.initializer.isExpInitializer();
- if (ei.exp.isStringExp() && tnsa.nextOf().isintegral())
+ if (ei.exp.isStringExp() && tnsa.nextOf().isIntegral())
{
ai.addInit(null, ei);
++index;
@@ -1050,6 +1054,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
mixin VisitInitializer!Initializer visit;
auto result = visit.VisitInitializer(init);
+ result.semanticDone = true;
return (result !is null) ? result : new ErrorInitializer();
}
@@ -1090,64 +1095,50 @@ Initializer inferType(Initializer init, Scope* sc)
{
//printf("ArrayInitializer::inferType() %s\n", toChars());
Expressions* keys = null;
- Expressions* values;
- if (init.isAssociativeArray())
+ Expressions* values = new Expressions(init.value.length);
+ Initializer no()
{
+ if (keys)
+ error(init.loc, "not an associative array initializer");
+ else
+ error(init.loc, "cannot infer type from array initializer");
+ return new ErrorInitializer();
+ }
+ const bool isAssoc = init.isAssociativeArray();
+ if (isAssoc)
keys = new Expressions(init.value.length);
- values = new Expressions(init.value.length);
- for (size_t i = 0; i < init.value.length; i++)
+ else
+ values.zero();
+
+ for (size_t i = 0; i < init.value.length; i++)
+ {
+ if (isAssoc)
{
Expression e = init.index[i];
if (!e)
- goto Lno;
+ return no();
(*keys)[i] = e;
- Initializer iz = init.value[i];
- if (!iz)
- goto Lno;
- iz = iz.inferType(sc);
- if (iz.isErrorInitializer())
- {
- return iz;
- }
- (*values)[i] = iz.isExpInitializer().exp;
- assert(!(*values)[i].isErrorExp());
}
- Expression e = new AssocArrayLiteralExp(init.loc, keys, values);
- auto ei = new ExpInitializer(init.loc, e);
- return ei.inferType(sc);
- }
- else
- {
- auto elements = new Expressions(init.value.length);
- elements.zero();
- for (size_t i = 0; i < init.value.length; i++)
- {
+ else
assert(!init.index[i]); // already asserted by isAssociativeArray()
- Initializer iz = init.value[i];
- if (!iz)
- goto Lno;
- iz = iz.inferType(sc);
- if (iz.isErrorInitializer())
- {
- return iz;
- }
- (*elements)[i] = iz.isExpInitializer().exp;
- assert(!(*elements)[i].isErrorExp());
+ Initializer iz = init.value[i];
+ if (!iz)
+ return no();
+ iz = iz.inferType(sc);
+ if (iz.isErrorInitializer())
+ {
+ return iz;
}
- Expression e = new ArrayLiteralExp(init.loc, null, elements);
- auto ei = new ExpInitializer(init.loc, e);
- return ei.inferType(sc);
+ (*values)[i] = iz.isExpInitializer().exp;
+ assert(!(*values)[i].isErrorExp());
}
- Lno:
- if (keys)
- {
- error(init.loc, "not an associative array initializer");
- }
- else
- {
- error(init.loc, "cannot infer type from array initializer");
- }
- return new ErrorInitializer();
+
+ Expression e;
+ e = isAssoc
+ ? new AssocArrayLiteralExp(init.loc, keys, values)
+ : new ArrayLiteralExp(init.loc, null, values);
+ auto ei = new ExpInitializer(init.loc, e);
+ return ei.inferType(sc);
}
Initializer visitExp(ExpInitializer init)
@@ -1477,10 +1468,10 @@ private bool hasNonConstPointers(Expression e)
}
if (auto se = ae.e1.isStructLiteralExp())
{
- if (!(se.stageflags & stageSearchPointers))
+ if (!(se.stageflags & StructLiteralExp.StageFlags.searchPointers))
{
const old = se.stageflags;
- se.stageflags |= stageSearchPointers;
+ se.stageflags |= StructLiteralExp.StageFlags.searchPointers;
bool ret = checkArray(se.elements);
se.stageflags = old;
return ret;
@@ -1601,7 +1592,7 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope*
(vd.offset & (target.ptrsize - 1))))
{
if (sc.setUnsafe(false, argLoc,
- "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd))
+ "field `%s.%s` assigning to misaligned pointers", sd, vd))
{
errors = true;
elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
@@ -1639,7 +1630,7 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope*
continue;
}
- elems[fieldi] = doCopyOrMove(sc, ex);
+ elems[fieldi] = doCopyOrMove(sc, ex, null, false);
++fieldi;
}
if (errors)
diff --git a/gcc/d/dmd/inline.d b/gcc/d/dmd/inline.d
index 3e163ae..72f2da4 100644
--- a/gcc/d/dmd/inline.d
+++ b/gcc/d/dmd/inline.d
@@ -4,12 +4,12 @@
* The AST is traversed, and every function call is considered for inlining using `inlinecost.d`.
* The function call is then inlined if this cost is below a threshold.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inline.d, _inline.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/inline.d, _inline.d)
* Documentation: https://dlang.org/phobos/dmd_inline.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/inline.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/inline.d
*/
module dmd.inline;
diff --git a/gcc/d/dmd/intrange.d b/gcc/d/dmd/intrange.d
index 29c8b50..f68e302 100644
--- a/gcc/d/dmd/intrange.d
+++ b/gcc/d/dmd/intrange.d
@@ -1,22 +1,21 @@
/**
* Implement $(LINK2 https://digitalmars.com/articles/b62.html, Value Range Propagation).
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d, _intrange.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/intrange.d, _intrange.d)
* Documentation: https://dlang.org/phobos/dmd_intrange.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/intrange.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/intrange.d
*/
module dmd.intrange;
import core.stdc.stdio;
-import dmd.astenums;
-import dmd.mtype;
-import dmd.expression;
-import dmd.globals;
+import dmd.astenums : Tdchar;
+import dmd.mtype : Type;
+import dmd.globals : uinteger_t;
private uinteger_t copySign(uinteger_t x, bool sign) @safe
{
@@ -70,7 +69,7 @@ struct SignExtendedNumber
}
if (value < a.value)
return -1;
- else if (value > a.value)
+ if (value > a.value)
return 1;
else
return 0;
@@ -122,10 +121,10 @@ struct SignExtendedNumber
SignExtendedNumber opBinary(string op : "+")(SignExtendedNumber rhs)
{
uinteger_t sum = value + rhs.value;
- bool carry = sum < value && sum < rhs.value;
+ const carry = sum < value && sum < rhs.value;
if (negative != rhs.negative)
return SignExtendedNumber(sum, !carry);
- else if (negative)
+ if (negative)
return SignExtendedNumber(carry ? sum : 0, true);
else
return SignExtendedNumber(carry ? ulong.max : sum, false);
@@ -142,7 +141,7 @@ struct SignExtendedNumber
SignExtendedNumber opBinary(string op : "*")(SignExtendedNumber rhs)
{
- // perform *saturated* multiplication, otherwise we may get bogus ranges
+ // perform* saturated* multiplication, otherwise we may get bogus ranges
// like 0x10 * 0x10 == 0x100 == 0.
/* Special handling for zeros:
@@ -155,7 +154,7 @@ struct SignExtendedNumber
{
if (!negative)
return this;
- else if (rhs.negative)
+ if (rhs.negative)
return max();
else
return rhs.value == 0 ? rhs : this;
@@ -249,7 +248,7 @@ struct SignExtendedNumber
// shifts will give huge result.
if (value == 0)
return this;
- else if (rhs.negative)
+ if (rhs.negative)
return extreme(negative);
uinteger_t v = copySign(value, negative);
@@ -278,7 +277,7 @@ struct SignExtendedNumber
{
if (rhs.negative || rhs.value > 63)
return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
- else if (isMinimum())
+ if (isMinimum())
return rhs.value == 0 ? this : SignExtendedNumber(-1UL << (64 - rhs.value), true);
uinteger_t x = value ^ -cast(int)negative;
@@ -317,12 +316,12 @@ struct IntRange
static IntRange fromType(Type type)
{
- return fromType(type, type.isunsigned());
+ return fromType(type, type.isUnsigned());
}
static IntRange fromType(Type type, bool isUnsigned)
{
- if (!type.isintegral() || type.toBasetype().ty == Tvector)
+ if (!type.isIntegral() || type.toBasetype().isTypeVector())
return widest();
uinteger_t mask = type.sizemask();
@@ -444,24 +443,22 @@ struct IntRange
IntRange _cast(Type type)
{
- if (!type.isintegral() || type.toBasetype().ty == Tvector)
+ if (!type.isIntegral() || type.toBasetype().isTypeVector())
return this;
- else if (!type.isunsigned())
+ if (!type.isUnsigned())
return castSigned(type.sizemask());
- else if (type.toBasetype().ty == Tdchar)
+ if (type.toBasetype().ty == Tdchar)
return castDchar();
- else
return castUnsigned(type.sizemask());
}
IntRange castUnsigned(Type type)
{
- if (!type.isintegral() || type.toBasetype().ty == Tvector)
+ if (!type.isIntegral() || type.toBasetype().isTypeVector())
return castUnsigned(ulong.max);
- else if (type.toBasetype().ty == Tdchar)
+ if (type.toBasetype().ty == Tdchar)
return castDchar();
- else
- return castUnsigned(type.sizemask());
+ return castUnsigned(type.sizemask());
}
bool contains(IntRange a) @safe
@@ -479,14 +476,11 @@ struct IntRange
{
if (imax.negative)
return this;
- else if (!imin.negative)
+ if (!imin.negative)
return IntRange(-imax, -imin);
- else
- {
- SignExtendedNumber imaxAbsNeg = -imax;
- return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
- SignExtendedNumber(0));
- }
+ SignExtendedNumber imaxAbsNeg = -imax;
+ return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
+ SignExtendedNumber(0));
}
IntRange unionWith(const ref IntRange other) const @safe
@@ -504,7 +498,7 @@ struct IntRange
union_ = true;
}
- ref const(IntRange) dump(const(char)* funcName, Expression e) const return
+ ref const(IntRange) dump(Exp)(const(char)* funcName, Exp e) const return
{
printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
imin.negative?'-':'+', cast(ulong)imin.value,
@@ -574,13 +568,13 @@ struct IntRange
swap(l, r); // r spans [-1,0]
}
- auto minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
- auto minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
- auto maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
- auto maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
+ const minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ const minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
+ const maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ const maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
- auto min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
- auto max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
+ const min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
+ const max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
auto range = IntRange(min, max);
return range;
@@ -668,7 +662,7 @@ struct IntRange
return widest();
// Don't treat the whole range as divide by 0 if only one end of a range is 0.
- // Issue 15289
+ // https://issues.dlang.org/show_bug.cgi?id=15289
if (rhs.imax.value == 0)
{
rhs.imax.value--;
@@ -682,17 +676,19 @@ struct IntRange
{
return IntRange(imin / rhs.imax, imax / rhs.imin);
}
- else
+ if (rhs.imin.negative && !rhs.imax.negative) // divisor spans [-1, 0, 1]
{
- // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
- SignExtendedNumber[4] bdy;
- bdy[0] = imin / rhs.imin;
- bdy[1] = imin / rhs.imax;
- bdy[2] = imax / rhs.imin;
- bdy[3] = imax / rhs.imax;
-
+ SignExtendedNumber[4] bdy = [-imin, imin, -imax, imax];
return IntRange.fromNumbers4(bdy.ptr);
}
+ // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
+ SignExtendedNumber[4] bdy;
+ bdy[0] = imin / rhs.imin;
+ bdy[1] = imin / rhs.imax;
+ bdy[2] = imax / rhs.imin;
+ bdy[3] = imax / rhs.imax;
+
+ return IntRange.fromNumbers4(bdy.ptr);
}
IntRange opBinary(string op : "%")(IntRange rhs)
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
index f20b3d4..080870a 100644
--- a/gcc/d/dmd/json.d
+++ b/gcc/d/dmd/json.d
@@ -1,12 +1,12 @@
/**
* Code for generating .json descriptions of the module when passing the `-X` flag to dmd.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/json.d, _json.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/json.d, _json.d)
* Documentation: https://dlang.org/phobos/dmd_json.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/json.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/json.d
*/
module dmd.json;
@@ -24,6 +24,7 @@ import dmd.denum;
import dmd.dimport;
import dmd.dmodule;
import dmd.dsymbol;
+import dmd.dsymbolsem : include;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
@@ -40,9 +41,13 @@ import dmd.root.string;
import dmd.target;
import dmd.visitor;
-version(Windows) {
- extern (C) char* getcwd(char* buffer, size_t maxlen);
-} else {
+version(Windows)
+{
+ extern (C) char* _getcwd(char* buffer, size_t maxlen);
+ alias getcwd = _getcwd;
+}
+else
+{
import core.sys.posix.unistd : getcwd;
}
@@ -328,7 +333,7 @@ public:
}
}
- extern(D) void propertyStorageClass(const char[] name, StorageClass stc)
+ extern(D) void propertyStorageClass(const char[] name, STC stc)
{
stc &= STC.visibleStorageClasses;
if (stc)
@@ -345,23 +350,22 @@ public:
}
}
- extern(D) void property(const char[] linename, const char[] charname, const ref Loc loc)
+ extern(D) void property(const char[] linename, const char[] charname, Loc loc)
{
if (loc.isValid())
{
- if (auto filename = loc.filename.toDString)
+ SourceLoc sl = SourceLoc(loc);
+ if (sl.filename.length > 0 && sl.filename != this.filename)
{
- if (filename != this.filename)
- {
- this.filename = filename;
- property("file", filename);
- }
+ this.filename = sl.filename;
+ property("file", sl.filename);
}
- if (loc.linnum)
+
+ if (sl.linnum)
{
- property(linename, loc.linnum);
- if (loc.charnum)
- property(charname, loc.charnum);
+ property(linename, sl.linnum);
+ if (sl.charnum)
+ property(charname, sl.charnum);
}
}
}
@@ -904,7 +908,7 @@ public:
arrayStart();
foreach (importPath; global.params.imppath[])
{
- item(importPath.toDString);
+ item(importPath.path.toDString);
}
arrayEnd();
@@ -990,35 +994,34 @@ void json_generate(ref Modules modules, ref OutBuffer buf)
// of modules representing their syntax.
json.generateModules(modules);
json.removeComma();
+ return;
}
- else
- {
- // Generate the new format which is an object where each
- // output option is its own field.
- json.objectStart();
- if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo)
- {
- json.propertyStart("compilerInfo");
- json.generateCompilerInfo();
- }
- if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo)
- {
- json.propertyStart("buildInfo");
- json.generateBuildInfo();
- }
- if (global.params.jsonFieldFlags & JsonFieldFlags.modules)
- {
- json.propertyStart("modules");
- json.generateModules(modules);
- }
- if (global.params.jsonFieldFlags & JsonFieldFlags.semantics)
- {
- json.propertyStart("semantics");
- json.generateSemantics();
- }
- json.objectEnd();
+ // Generate the new format which is an object where each
+ // output option is its own field.
+
+ json.objectStart();
+ if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo)
+ {
+ json.propertyStart("compilerInfo");
+ json.generateCompilerInfo();
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo)
+ {
+ json.propertyStart("buildInfo");
+ json.generateBuildInfo();
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.modules)
+ {
+ json.propertyStart("modules");
+ json.generateModules(modules);
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.semantics)
+ {
+ json.propertyStart("semantics");
+ json.generateSemantics();
}
+ json.objectEnd();
}
/**
diff --git a/gcc/d/dmd/json.h b/gcc/d/dmd/json.h
index b119c9e..8211509 100644
--- a/gcc/d/dmd/json.h
+++ b/gcc/d/dmd/json.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d
index a1db8d5..9f9fd77 100644
--- a/gcc/d/dmd/lambdacomp.d
+++ b/gcc/d/dmd/lambdacomp.d
@@ -5,12 +5,12 @@
* The serialization is a string which contains the type of the parameters and the string
* represantation of the lambda expression.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lamdbacomp.d, _lambdacomp.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lambdacomp.d, _lambdacomp.d)
* Documentation: https://dlang.org/phobos/dmd_lambdacomp.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/lambdacomp.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/lambdacomp.d
*/
module dmd.lambdacomp;
@@ -26,8 +26,8 @@ import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.expression;
import dmd.func;
-import dmd.dmangle;
import dmd.hdrgen;
+import dmd.mangle;
import dmd.mtype;
import dmd.common.outbuffer;
import dmd.root.rmem;
@@ -240,39 +240,39 @@ public:
auto id = exp.ident.toChars();
// If it's not an argument
- if (!checkArgument(id))
+ if (checkArgument(id))
+ return;
+
+ // we must check what the identifier expression is.
+ Dsymbol scopesym;
+ Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
+
+ // If it's an unknown symbol, consider the function incomparable
+ if (!s)
{
- // we must check what the identifier expression is.
- Dsymbol scopesym;
- Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
- if (s)
- {
- auto v = s.isVarDeclaration();
- // If it's a VarDeclaration, it must be a manifest constant
- if (v && (v.storage_class & STC.manifest))
- {
- v.getConstInitializer.accept(this);
- }
- else if (auto em = s.isEnumDeclaration())
- {
- d = em;
- et = ExpType.EnumDecl;
- }
- else if (auto fd = s.isFuncDeclaration())
- {
- writeMangledName(fd);
- }
- // For anything else, the function is deemed uncomparable
- else
- {
- buf.setsize(0);
- }
- }
- // If it's an unknown symbol, consider the function incomparable
- else
- {
- buf.setsize(0);
- }
+ buf.setsize(0);
+ return;
+ }
+
+ auto v = s.isVarDeclaration();
+ // If it's a VarDeclaration, it must be a manifest constant
+ if (v && (v.storage_class & STC.manifest))
+ {
+ v.getConstInitializer.accept(this);
+ }
+ else if (auto em = s.isEnumDeclaration())
+ {
+ d = em;
+ et = ExpType.EnumDecl;
+ }
+ else if (auto fd = s.isFuncDeclaration())
+ {
+ writeMangledName(fd);
+ }
+ // For anything else, the function is deemed uncomparable
+ else
+ {
+ buf.setsize(0);
}
}
@@ -445,26 +445,28 @@ public:
visitType(p.type);
}
- override void visit(StructLiteralExp e) {
+ override void visit(StructLiteralExp e)
+ {
static if (LOG)
printf("StructLiteralExp: %s\n", e.toChars);
auto ty = cast(TypeStruct)e.stype;
- if (ty)
+ if (!ty)
{
- writeMangledName(ty.sym);
- auto dim = e.elements.length;
- foreach (i; 0..dim)
- {
- auto elem = (*e.elements)[i];
- if (elem)
- elem.accept(this);
- else
- buf.writestring("null_");
- }
- }
- else
buf.setsize(0);
+ return;
+ }
+
+ writeMangledName(ty.sym);
+ auto dim = e.elements.length;
+ foreach (i; 0..dim)
+ {
+ auto elem = (*e.elements)[i];
+ if (elem)
+ elem.accept(this);
+ else
+ buf.writestring("null_");
+ }
}
override void visit(ArrayLiteralExp) { buf.setsize(0); }
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index c9c506e..ed9f7f1 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/lex.html, Lexical)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d, _lexer.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lexer.d, _lexer.d)
* Documentation: https://dlang.org/phobos/dmd_lexer.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/lexer.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/lexer.d
*/
module dmd.lexer;
@@ -22,9 +22,11 @@ import dmd.errorsink;
import dmd.id;
import dmd.identifier;
import dmd.location;
+import dmd.common.smallbuffer;
+import dmd.common.outbuffer;
+import dmd.common.charactertables;
import dmd.root.array;
import dmd.root.ctfloat;
-import dmd.common.outbuffer;
import dmd.root.port;
import dmd.root.rmem;
import dmd.root.utf;
@@ -32,16 +34,13 @@ import dmd.tokens;
nothrow:
-version (DMDLIB)
-{
- version = LocOffset;
-}
-
/***********************************************************
* Values to use for various magic identifiers
*/
struct CompileEnv
{
+ import dmd.common.charactertables;
+
uint versionNumber; /// __VERSION__
const(char)[] date; /// __DATE__
const(char)[] time; /// __TIME__
@@ -49,8 +48,13 @@ struct CompileEnv
const(char)[] timestamp; /// __TIMESTAMP__
bool previewIn; /// `in` means `[ref] scope const`, accepts rvalues
+ bool transitionIn; /// `-transition=in` is active, `in` parameters are listed
bool ddocOutput; /// collect embedded documentation comments
bool masm; /// use MASM inline asm syntax
+
+ // these need a default otherwise tests won't work.
+ IdentifierCharLookup cCharLookupTable; /// C identifier table (set to the lexer by the C parser)
+ IdentifierCharLookup dCharLookupTable; /// D identifier table
}
/***********************************************************
@@ -59,13 +63,17 @@ class Lexer
{
private __gshared OutBuffer stringbuffer;
+ BaseLoc* baseLoc; // Used to generate `scanloc`, which is just an index into this data structure
Loc scanloc; // for error messages
Loc prevloc; // location of token before current
+ int linnum; // current line number
const(char)* p; // current character
Token token;
+ IdentifierCharLookup charLookup; /// Character table for identifiers
+
// For ImportC
bool Ccompile; /// true if compiling ImportC
@@ -121,10 +129,11 @@ class Lexer
ErrorSink errorSink,
const CompileEnv* compileEnv) scope
{
- scanloc = Loc(filename, 1, 1);
// debug printf("Lexer::Lexer(%p)\n", base);
// debug printf("lexer.filename = %s\n", filename);
token = Token.init;
+ this.baseLoc = newBaseLoc(filename, base[0 .. endoffset]);
+ this.linnum = 1;
this.base = base;
this.end = base + endoffset;
p = base + begoffset;
@@ -142,6 +151,8 @@ class Lexer
{
this.compileEnv.versionNumber = 1;
this.compileEnv.vendor = "DLF";
+ this.compileEnv.cCharLookupTable = IdentifierCharLookup.forTable(IdentifierTable.LR);
+ this.compileEnv.dCharLookupTable = IdentifierCharLookup.forTable(IdentifierTable.LR);
}
//initKeywords();
/* If first line starts with '#!', ignore the line
@@ -175,6 +186,11 @@ class Lexer
}
endOfLine();
}
+
+ // setup the identifier table lookup functions
+ // C tables are setup in its parser constructor
+ // Due to us not knowing if we're in C at this point in time.
+ charLookup = this.compileEnv.dCharLookupTable;
}
/***********************
@@ -207,7 +223,9 @@ class Lexer
tokenizeNewlines = true;
inTokenStringConstant = 0;
lastDocLine = 0;
- scanloc = Loc("#defines", 1, 1);
+
+ baseLoc = newBaseLoc("#defines", slice);
+ scanloc = baseLoc.getLoc(0);
}
/**********************************
@@ -301,11 +319,13 @@ class Lexer
*/
final void scan(Token* t)
{
- const lastLine = scanloc.linnum;
+ const lastLine = linnum;
Loc startLoc;
t.blockComment = null;
t.lineComment = null;
+ size_t universalCharacterName4, universalCharacterName8;
+
while (1)
{
t.ptr = p;
@@ -395,10 +415,35 @@ class Lexer
continue; // skip white space
case '\\':
- if (Ccompile && (p[1] == '\r' || p[1] == '\n'))
+ if (Ccompile)
{
- ++p; // ignore \ followed by new line, like VC does
- continue;
+ if (p[1] == '\r' || p[1] == '\n')
+ {
+ ++p; // ignore \ followed by new line, like VC does
+ continue;
+ }
+ else if (p[1] == 'u')
+ {
+ // Universal Character Name (C) 2 byte
+ // \uXXXX
+ // let the main case handling for identifiers process this
+
+ // case_indent will always increment, so subtract to prevent branching on the fast path
+ p--;
+
+ goto case_ident;
+ }
+ else if (p[1] == 'U')
+ {
+ // Universal Character Name (C) 4 byte
+ // \UXXXXXXXX
+ // let the main case handling for identifiers process this
+
+ // case_indent will always increment, so subtract to prevent branching on the fast path
+ p--;
+
+ goto case_ident;
+ }
}
goto default;
@@ -455,7 +500,7 @@ class Lexer
clexerCharConstant(*t, c);
return;
}
- else if (p[1] == '\"') // C wide string literal
+ if (p[1] == '\"') // C wide string literal
{
const c = *p;
++p;
@@ -465,7 +510,7 @@ class Lexer
'd';
return;
}
- else if (p[1] == '8' && p[2] == '\"') // C UTF-8 string literal
+ if (p[1] == '8' && p[2] == '\"') // C UTF-8 string literal
{
p += 2;
escapeStringConstant(t);
@@ -498,14 +543,13 @@ class Lexer
delimitedStringConstant(t);
return;
}
- else if (p[1] == '{')
+ if (p[1] == '{')
{
p++;
tokenStringConstant(t);
return;
}
- else
- goto case_ident;
+ goto case_ident;
case 'i':
if (Ccompile)
goto case_ident;
@@ -515,20 +559,19 @@ class Lexer
escapeStringConstant(t, true);
return;
}
- else if (p[1] == '`')
+ if (p[1] == '`')
{
p++; // skip the i
wysiwygStringConstant(t, true);
return;
}
- else if (p[1] == 'q' && p[2] == '{')
+ if (p[1] == 'q' && p[2] == '{')
{
p += 2; // skip the i and q
tokenStringConstant(t, true);
return;
}
- else
- goto case_ident;
+ goto case_ident;
case '"':
escapeStringConstant(t);
return;
@@ -586,23 +629,161 @@ class Lexer
case '_':
case_ident:
{
- while (1)
+ IdentLoop: while (1)
{
+ // If this is changed, change the decrement in C's universal character name code above
+ // For syntax \uXXXX and \UXXXXXXXX
const c = *++p;
+
+ // Is this the first character of the identifier
+ // For the universal character name this will line up,
+ // for the main switch it won't since it wasn't the first,
+ // for the default it won't either because a decode increments.
+ const isStartCharacter = t.ptr is p;
+
if (isidchar(c))
continue;
- else if (c & 0x80)
+ if (c & 0x80)
{
const s = p;
const u = decodeUTF();
- if (isUniAlpha(u))
- continue;
- error(t.loc, "char 0x%04x not allowed in identifier", u);
+
+ if (isStartCharacter)
+ {
+ if (charLookup.isStart(u))
+ continue;
+ error(t.loc, "character 0x%04x is not allowed as a start character in an identifier", u);
+ }
+ else
+ {
+ if (charLookup.isContinue(u))
+ continue;
+ error(t.loc, "character 0x%04x is not allowed as a continue character in an identifier", u);
+ }
+
p = s;
}
+ else if (Ccompile && c == '\\')
+ {
+ uint times;
+ const s = p;
+ p++;
+
+ if (*p == 'u')
+ {
+ // Universal Character Name (C) 2 byte
+ // \uXXXX
+ p++;
+ times = 4;
+ }
+ else if (*p == 'U')
+ {
+ // Universal Character Name (C) 4 byte
+ // \UXXXXXXXX
+ p++;
+ times = 8;
+ }
+ else
+ {
+ error(t.loc, "char 0x%x is not allowed to follow '\\' expecting a C universal character name in format \\uXXXX or \\UXXXXXXXX with hex digits instead of X with invalid u/U", *p);
+ p = s;
+ break;
+ }
+
+ foreach(_; 0 .. times)
+ {
+ const hc = *p;
+ p++;
+
+ if ((hc >= '0' && hc <= '9') || (hc >= 'a' && hc <= 'f') || (hc >= 'A' && hc <= 'F'))
+ continue;
+
+ error(t.loc, "char 0x%x is not allowed to follow '\\' expecting a C universal character name in format \\uXXXX or \\UXXXXXXXX with hex digits instead of X with invalid hex digit", hc);
+ p = s;
+ break IdentLoop;
+ }
+
+ continue;
+ }
break;
}
- Identifier id = Identifier.idPool((cast(char*)t.ptr)[0 .. p - t.ptr], false);
+
+ Identifier id;
+
+ if (universalCharacterName4 > 0 || universalCharacterName8 > 0)
+ {
+ auto priorValidation = t.ptr[0 .. p - t.ptr];
+ const(char)* priorVPtr = priorValidation.ptr;
+ const possibleLength = (
+ priorValidation.length - (
+ (universalCharacterName4 * 6) +
+ (universalCharacterName8 * 10)
+ )) + (
+ (universalCharacterName4 * 3) +
+ (universalCharacterName8 * 4)
+ );
+
+ char[64] buffer = void;
+ SmallBuffer!char sb = SmallBuffer!char(possibleLength, buffer[]);
+
+ char[] storage = sb.extent;
+ size_t offset;
+
+ while(priorVPtr < &priorValidation[$-1] + 1)
+ {
+ if (*priorVPtr == '\\')
+ {
+ dchar tempDchar = 0;
+ uint times;
+
+ // universal character name (C)
+ if (priorVPtr[1] == 'u')
+ times = 4;
+ else if (priorVPtr[1] == 'U')
+ times = 8;
+ else
+ assert(0, "ICE: Universal character name is 2 or 4 bytes only");
+ priorVPtr += 2;
+
+ foreach(_; 0 .. times)
+ {
+ char c = *++priorVPtr;
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c -= 'a' - 10;
+ else if (c >= 'A' && c <= 'F')
+ c -= 'A' - 10;
+
+ tempDchar <<= 4;
+ tempDchar |= c;
+ }
+
+ utf_encodeChar(&storage[offset], tempDchar);
+ offset += utf_codeLengthChar(tempDchar);
+
+ // Could be an error instead of a warning,
+ // but hey it was written specifically so why worry?
+ if (priorVPtr is priorValidation.ptr)
+ {
+ if (!charLookup.isStart(tempDchar))
+ warning(t.loc, "char 0x%x is not allowed start character for an identifier", tempDchar);
+ }
+ else
+ {
+ if (!charLookup.isContinue(tempDchar))
+ warning(t.loc, "char 0x%x is not allowed continue character for an identifier", tempDchar);
+ }
+ }
+ else
+ storage[offset++] = *++priorVPtr;
+ }
+
+ id = Identifier.idPool(storage[0 .. offset], false);
+ }
+ else
+ id = Identifier.idPool((cast(char*)t.ptr)[0 .. p - t.ptr], false);
+
t.ident = id;
t.value = cast(TOK)id.getValue();
@@ -686,7 +867,7 @@ class Lexer
case 0:
case 0x1A:
error(t.loc, "unterminated /* */ comment");
- p = end;
+ //p = end;
t.loc = loc();
t.value = TOK.endOfFile;
return;
@@ -712,11 +893,11 @@ class Lexer
t.value = TOK.comment;
return;
}
- else if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr)
+ if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr)
{
// if /** but not /**/
getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
- lastDocLine = scanloc.linnum;
+ lastDocLine = linnum;
}
continue;
case '/': // do // style comments
@@ -744,9 +925,9 @@ class Lexer
if (doDocComment && t.ptr[2] == '/')
{
getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
- lastDocLine = scanloc.linnum;
+ lastDocLine = linnum;
}
- p = end;
+ //p = end;
t.loc = loc();
t.value = TOK.endOfFile;
return;
@@ -776,7 +957,7 @@ class Lexer
if (doDocComment && t.ptr[2] == '/')
{
getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
- lastDocLine = scanloc.linnum;
+ lastDocLine = linnum;
}
p++;
endOfLine();
@@ -822,7 +1003,7 @@ class Lexer
case 0:
case 0x1A:
error(t.loc, "unterminated /+ +/ comment");
- p = end;
+ //p = end;
t.loc = loc();
t.value = TOK.endOfFile;
return;
@@ -848,7 +1029,7 @@ class Lexer
{
// if /++ but not /++/
getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
- lastDocLine = scanloc.linnum;
+ lastDocLine = linnum;
}
continue;
}
@@ -1174,9 +1355,11 @@ class Lexer
if (c & 0x80)
{
c = decodeUTF();
- // Check for start of unicode identifier
- if (isUniAlpha(c))
+
+ // Check for start of an identifier
+ if (charLookup.isStart(c))
goto case_ident;
+
if (c == PS || c == LS)
{
endOfLine();
@@ -1281,7 +1464,7 @@ class Lexer
* Returns:
* the escape sequence as a single character
*/
- private dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile, out dchar c2)
+ private dchar escapeSequence(Loc loc, ref const(char)* sequence, bool Ccompile, out dchar c2)
{
const(char)* p = sequence; // cache sequence reference on stack
scope(exit) sequence = p;
@@ -1372,6 +1555,8 @@ class Lexer
if (ndigits != 2 && !utf_isValidDchar(v))
{
error(loc, "invalid UTF character \\U%08x", v);
+ if (v >= 0xD800 && v <= 0xDFFF)
+ errorSupplemental("The code unit is a UTF-16 surrogate, is the escape UTF-16 not a Unicode code point?");
v = '?'; // recover with valid UTF character
}
}
@@ -1688,7 +1873,7 @@ class Lexer
delimright = ']';
else if (c == '<')
delimright = '>';
- else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c)))
+ else if (isalpha(c) || c == '_' || (c >= 0x80 && charLookup.isStart(c)))
{
// Start of identifier; must be a heredoc
Token tok;
@@ -1736,7 +1921,9 @@ class Lexer
}
else if (c == delimright)
goto Ldone;
- if (startline && (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) && hereid)
+
+ // we're looking for a new identifier token
+ if (startline && (isalpha(c) || c == '_' || (c >= 0x80 && charLookup.isStart(c))) && hereid)
{
Token tok;
auto psave = p;
@@ -2384,19 +2571,19 @@ class Lexer
Ldone:
if (errorDigit)
{
- error(token.loc, "%s digit expected, not `%c`", base == 2 ? "binary".ptr :
+ error(scanloc, "%s digit expected, not `%c`", base == 2 ? "binary".ptr :
base == 8 ? "octal".ptr :
"decimal".ptr, errorDigit);
err = true;
}
if (overflow && !err)
{
- error("integer overflow");
+ error(scanloc, "integer overflow");
err = true;
}
if ((base == 2 && !anyBinaryDigitsNoSingleUS) ||
(base == 16 && !anyHexDigitsNoSingleUS))
- error(token.loc, "`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start);
+ error(scanloc, "`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start);
t.unsvalue = n;
@@ -2425,7 +2612,7 @@ class Lexer
goto L1;
case 'l':
f = FLAGS.long_;
- error("lower case integer suffix 'l' is not allowed. Please use 'L' instead");
+ error(scanloc, "lower case integer suffix 'l' is not allowed. Please use 'L' instead");
goto L1;
case 'L':
f = FLAGS.long_;
@@ -2433,7 +2620,7 @@ class Lexer
p++;
if ((flags & f) && !err)
{
- error("repeated integer suffix `%c`", p[-1]);
+ error(scanloc, "repeated integer suffix `%c`", p[-1]);
err = true;
}
flags = cast(FLAGS)(flags | f);
@@ -2447,9 +2634,9 @@ class Lexer
{
if (err)
// can't translate invalid octal value, just show a generic message
- error("octal literals larger than 7 are no longer supported");
+ error(scanloc, "octal literals larger than 7 are no longer supported");
else
- error(token.loc, "octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead",
+ error(scanloc, "octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead",
n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix);
}
TOK result;
@@ -2967,9 +3154,7 @@ class Lexer
final Loc loc() @nogc
{
- scanloc.charnum = cast(ushort)(1 + p - line);
- version (LocOffset)
- scanloc.fileOffset = cast(uint)(p - base);
+ scanloc = baseLoc.getLoc(cast(uint) (p - base));
return scanloc;
}
@@ -2978,16 +3163,26 @@ class Lexer
eSink.error(token.loc, format, args);
}
- void error(T...)(const ref Loc loc, const(char)* format, T args)
+ void error(T...)(Loc loc, const(char)* format, T args)
{
eSink.error(loc, format, args);
}
- void deprecation(T...)(const ref Loc loc, const(char)* format, T args)
+ void errorSupplemental(T...)(const(char)* format, T args)
+ {
+ eSink.errorSupplemental(token.loc, format, args);
+ }
+
+ void deprecation(T...)(Loc loc, const(char)* format, T args)
{
eSink.deprecation(loc, format, args);
}
+ void warning(T...)(Loc loc, const(char)* format, T args)
+ {
+ eSink.warning(loc, format, args);
+ }
+
void deprecation(T...)(const(char)* format, T args)
{
eSink.deprecation(token.loc, format, args);
@@ -3054,7 +3249,6 @@ class Lexer
*/
final void poundLine(ref Token tok, bool linemarker)
{
- auto linnum = this.scanloc.linnum;
const(char)* filespec = null;
bool flags;
@@ -3091,9 +3285,7 @@ class Lexer
case TOK.endOfLine:
if (!inTokenStringConstant)
{
- this.scanloc.linnum = linnum;
- if (filespec)
- this.scanloc.filename = filespec;
+ baseLoc.addSubstitution(cast(uint) (p - base), filespec, linnum);
}
return;
case TOK.file:
@@ -3244,12 +3436,12 @@ class Lexer
if (*q != ct)
break;
}
- /* Remove leading spaces until start of the comment
+ /* Remove leading line feed or space
*/
int linestart = 0;
if (ct == '/')
{
- while (q < qend && (*q == ' ' || *q == '\t'))
+ if (q < qend && *q == ' ')
++q;
}
else if (q < qend)
@@ -3391,10 +3583,11 @@ class Lexer
/**************************
* `p` should be at start of next line
*/
- private void endOfLine() @nogc @safe
+ private void endOfLine() @safe
{
- scanloc.linnum = scanloc.linnum + 1;
+ linnum += 1;
line = p;
+ baseLoc.newLine(cast(uint)(p - base));
}
/****************************
@@ -3416,124 +3609,6 @@ class Lexer
}
}
-
-/******************************* Private *****************************************/
-
-private:
-
-private enum LS = 0x2028; // UTF line separator
-private enum PS = 0x2029; // UTF paragraph separator
-
-/********************************************
- * Do our own char maps
- */
-private static immutable cmtable = ()
-{
- ubyte[256] table;
- foreach (const c; 0 .. table.length)
- {
- if ('0' <= c && c <= '7')
- table[c] |= CMoctal;
- if (c_isxdigit(c))
- table[c] |= CMhex;
- if (c_isalnum(c) || c == '_')
- table[c] |= CMidchar;
-
- switch (c)
- {
- case 'x': case 'X':
- case 'b': case 'B':
- table[c] |= CMzerosecond;
- break;
-
- case '0': .. case '9':
- case 'e': case 'E':
- case 'f': case 'F':
- case 'l': case 'L':
- case 'p': case 'P':
- case 'u': case 'U':
- case 'i':
- case '.':
- case '_':
- table[c] |= CMzerosecond | CMdigitsecond;
- break;
-
- default:
- break;
- }
-
- switch (c)
- {
- case '\\':
- case '\n':
- case '\r':
- case 0:
- case 0x1A:
- case '\'':
- break;
- default:
- if (!(c & 0x80))
- table[c] |= CMsinglechar;
- break;
- }
- }
- return table;
-}();
-
-private
-{
- enum CMoctal = 0x1;
- enum CMhex = 0x2;
- enum CMidchar = 0x4;
- enum CMzerosecond = 0x8;
- enum CMdigitsecond = 0x10;
- enum CMsinglechar = 0x20;
-}
-
-private bool isoctal(const char c) pure @nogc @safe
-{
- return (cmtable[c] & CMoctal) != 0;
-}
-
-private bool ishex(const char c) pure @nogc @safe
-{
- return (cmtable[c] & CMhex) != 0;
-}
-
-private bool isidchar(const char c) pure @nogc @safe
-{
- return (cmtable[c] & CMidchar) != 0;
-}
-
-private bool isZeroSecond(const char c) pure @nogc @safe
-{
- return (cmtable[c] & CMzerosecond) != 0;
-}
-
-private bool isDigitSecond(const char c) pure @nogc @safe
-{
- return (cmtable[c] & CMdigitsecond) != 0;
-}
-
-private bool issinglechar(const char c) pure @nogc @safe
-{
- return (cmtable[c] & CMsinglechar) != 0;
-}
-
-private bool c_isxdigit(const int c) pure @nogc @safe
-{
- return (( c >= '0' && c <= '9') ||
- ( c >= 'a' && c <= 'f') ||
- ( c >= 'A' && c <= 'F'));
-}
-
-private bool c_isalnum(const int c) pure @nogc @safe
-{
- return (( c >= '0' && c <= '9') ||
- ( c >= 'a' && c <= 'z') ||
- ( c >= 'A' && c <= 'Z'));
-}
-
/******************************* Unittest *****************************************/
unittest
@@ -3599,25 +3674,35 @@ unittest
import core.stdc.stdarg;
string expected;
+ string expectedSupplemental;
bool gotError;
- void error(const ref Loc loc, const(char)* format, ...)
+ void verror(Loc loc, const(char)* format, va_list ap)
{
gotError = true;
char[100] buffer = void;
+ auto actual = buffer[0 .. vsnprintf(buffer.ptr, buffer.length, format, ap)];
+ assert(expected == actual);
+ }
+
+ void errorSupplemental(Loc loc, const(char)* format, ...)
+ {
+ gotError = true;
+ char[128] buffer = void;
va_list ap;
va_start(ap, format);
auto actual = buffer[0 .. vsnprintf(buffer.ptr, buffer.length, format, ap)];
va_end(ap);
- assert(expected == actual);
+ assert(expectedSupplemental == actual);
}
}
ErrorSinkTest errorSink = new ErrorSinkTest;
- void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false)
+ void test2(string sequence, string[2] expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false)
{
- errorSink.expected = expectedError;
+ errorSink.expected = expectedError[0];
+ errorSink.expectedSupplemental = expectedError[1];
errorSink.gotError = false;
auto p = cast(const(char)*)sequence.ptr;
Lexer lexer = new Lexer(errorSink);
@@ -3630,6 +3715,11 @@ unittest
assert(expectedScanLength == actualScanLength);
}
+ void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false)
+ {
+ test2(sequence, [expectedError, null], expectedReturnValue, expectedScanLength, Ccompile);
+ }
+
test("c", `undefined escape sequence \c`, 'c', 1);
test("!", `undefined escape sequence \!`, '!', 1);
test("&quot;", `undefined escape sequence \&`, '&', 1, true);
@@ -3648,8 +3738,6 @@ unittest
test("U0001f6" , `escape hex sequence has 6 hex digits instead of 8`, 0x0001f6, 7);
test("U0001f60", `escape hex sequence has 7 hex digits instead of 8`, 0x0001f60, 8);
- test("ud800" , `invalid UTF character \U0000d800`, '?', 5);
- test("udfff" , `invalid UTF character \U0000dfff`, '?', 5);
test("U00110000", `invalid UTF character \U00110000`, '?', 9);
test("xg0" , `undefined escape hex sequence \xg`, 'g', 2);
@@ -3661,6 +3749,9 @@ unittest
test("&quot", `unterminated named entity &quot;`, '?', 5);
test("400", `escape octal sequence \400 is larger than \377`, 0x100, 3);
+
+ test2("uD800", [`invalid UTF character \U0000d800`, `The code unit is a UTF-16 surrogate, is the escape UTF-16 not a Unicode code point?`], '?', 5);
+ test2("uDFFF", [`invalid UTF character \U0000dfff`, `The code unit is a UTF-16 surrogate, is the escape UTF-16 not a Unicode code point?`], '?', 5);
}
unittest
diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d
index ca6805e..393ffb8 100644
--- a/gcc/d/dmd/location.d
+++ b/gcc/d/dmd/location.d
@@ -1,12 +1,12 @@
/**
* Encapsulates file/line/column locations.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/location.d, _location.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/location.d, _location.d)
* Documentation: https://dlang.org/phobos/dmd_location.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/location.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/location.d
*/
module dmd.location;
@@ -16,19 +16,15 @@ import core.stdc.stdio;
import dmd.common.outbuffer;
import dmd.root.array;
import dmd.root.filename;
-
-version (DMDLIB)
-{
- version = LocOffset;
-}
+import dmd.root.string: toDString;
/// How code locations are formatted for diagnostic reporting
enum MessageStyle : ubyte
{
digitalmars, /// filename.d(line): message
gnu, /// filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html
+ sarif /// JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
}
-
/**
A source code location
@@ -37,19 +33,19 @@ debug info etc.
*/
struct Loc
{
- private uint _linnum;
- private uint _charnum;
- private uint fileIndex; // index into filenames[], starting from 1 (0 means no filename)
- version (LocOffset)
- uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0
+ private uint index = 0; // offset into lineTable[]
+
+ // FIXME: This arbitrary size increase is needed to prevent segfault in
+ // runnable/test42.d on Ubuntu x86 when DMD was built with DMD 2.105 .. 2.110
+ // https://github.com/dlang/dmd/pull/20777#issuecomment-2614128849
+ version (DigitalMars) version (linux) version (X86)
+ private uint dummy;
- static immutable Loc initial; /// use for default initialization of const ref Loc's
+ static immutable Loc initial; /// use for default initialization of Loc's
extern (C++) __gshared bool showColumns;
extern (C++) __gshared MessageStyle messageStyle;
- __gshared Array!(const(char)*) filenames;
-
nothrow:
/*******************************
@@ -64,35 +60,34 @@ nothrow:
this.messageStyle = messageStyle;
}
- extern (C++) this(const(char)* filename, uint linnum, uint charnum) @safe
+ /// Returns: a Loc that simply holds a filename, with no line / column info
+ extern (C++) static Loc singleFilename(const char* filename)
{
- this._linnum = linnum;
- this._charnum = charnum;
- this.filename = filename;
+ Loc result;
+ locFileTable ~= new BaseLoc(filename.toDString, null, locIndex, 0, [0]);
+ result.index = locIndex++;
+ return result;
}
/// utf8 code unit index relative to start of line, starting from 1
extern (C++) uint charnum() const @nogc @safe
{
- return _charnum;
- }
-
- /// ditto
- extern (C++) uint charnum(uint num) @nogc @safe
- {
- return _charnum = num;
+ return SourceLoc(this).column;
}
/// line number, starting from 1
- extern (C++) uint linnum() const @nogc @safe
+ extern (C++) uint linnum() const @nogc @trusted
{
- return _linnum;
+ return SourceLoc(this).line;
}
- /// ditto
- extern (C++) uint linnum(uint num) @nogc @safe
+ /// Advance this location to the first column of the next line
+ void nextLine()
{
- return _linnum = num;
+ const i = fileTableIndex(this.index);
+ const j = locFileTable[i].getLineIndex(this.index - locFileTable[i].startIndex);
+ if (j + 1 < locFileTable[i].lines.length)
+ index = locFileTable[i].startIndex + locFileTable[i].lines[j + 1];
}
/***
@@ -100,62 +95,39 @@ nothrow:
*/
extern (C++) const(char)* filename() const @nogc
{
- return fileIndex ? filenames[fileIndex - 1] : null;
- }
+ if (this.index == 0)
+ return null;
- /***
- * Set file name for this location
- * Params:
- * name = file name for location, null for no file name
- */
- extern (C++) void filename(const(char)* name) @trusted
- {
- if (name)
+ const i = fileTableIndex(this.index);
+ if (locFileTable[i].substitutions.length > 0)
{
- //printf("setting %s\n", name);
- filenames.push(name);
- fileIndex = cast(uint)filenames.length;
- assert(fileIndex, "internal compiler error: file name index overflow");
+ const si = locFileTable[i].getSubstitutionIndex(this.index - locFileTable[i].startIndex);
+ const fname = locFileTable[i].substitutions[si].filename;
+ if (fname.length > 0)
+ return fname.ptr;
}
- else
- fileIndex = 0;
+
+ return locFileTable[i].filename.ptr;
}
extern (C++) const(char)* toChars(
bool showColumns = Loc.showColumns,
MessageStyle messageStyle = Loc.messageStyle) const nothrow
{
- OutBuffer buf;
- if (fileIndex)
- {
- buf.writestring(filename);
- }
- if (linnum)
- {
- final switch (messageStyle)
- {
- case MessageStyle.digitalmars:
- buf.writeByte('(');
- buf.print(linnum);
- if (showColumns && charnum)
- {
- buf.writeByte(',');
- buf.print(charnum);
- }
- buf.writeByte(')');
- break;
- case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html
- buf.writeByte(':');
- buf.print(linnum);
- if (showColumns && charnum)
- {
- buf.writeByte(':');
- buf.print(charnum);
- }
- break;
- }
- }
- return buf.extractChars();
+ return SourceLoc(this).toChars(showColumns, messageStyle);
+ }
+
+ /// Returns: byte offset into source file
+ uint fileOffset() const
+ {
+ const i = fileTableIndex(this.index);
+ return this.index - locFileTable[i].startIndex;
+ }
+
+ /// Returns: this location as a SourceLoc
+ extern (C++) SourceLoc toSourceLoc() const @nogc @safe
+ {
+ return SourceLoc(this);
}
/**
@@ -165,11 +137,13 @@ nothrow:
* - Uses case-insensitive comparison on Windows
* - Ignores `charnum` if `Columns` is false.
*/
- extern (C++) bool equals(ref const(Loc) loc) const
+ extern (C++) bool equals(Loc loc) const
{
- return (!showColumns || charnum == loc.charnum) &&
- linnum == loc.linnum &&
- FileName.equals(filename, loc.filename);
+ SourceLoc lhs = SourceLoc(this);
+ SourceLoc rhs = SourceLoc(loc);
+ return (!showColumns || lhs.column == rhs.column) &&
+ lhs.line == rhs.line &&
+ FileName.equals(lhs.filename, rhs.filename);
}
/**
@@ -182,23 +156,13 @@ nothrow:
*/
extern (D) bool opEquals(ref const(Loc) loc) const @trusted nothrow @nogc
{
- import core.stdc.string : strcmp;
-
- return charnum == loc.charnum &&
- linnum == loc.linnum &&
- (filename == loc.filename ||
- (filename && loc.filename && strcmp(filename, loc.filename) == 0));
+ return this.index == loc.index;
}
/// ditto
extern (D) size_t toHash() const @trusted nothrow
{
- import dmd.root.string : toDString;
-
- auto hash = hashOf(linnum);
- hash = hashOf(charnum, hash);
- hash = hashOf(filename.toDString, hash);
- return hash;
+ return hashOf(this.index);
}
/******************
@@ -207,6 +171,302 @@ nothrow:
*/
bool isValid() const pure @safe
{
- return fileIndex != 0;
+ return this.index != 0;
+ }
+}
+
+/**
+ * Format a source location for error messages
+ *
+ * Params:
+ * buf = buffer to write string into
+ * loc = source location to write
+ * showColumns = include column number in message
+ * messageStyle = select error message format
+ */
+void writeSourceLoc(ref OutBuffer buf,
+ SourceLoc loc,
+ bool showColumns,
+ MessageStyle messageStyle) nothrow
+{
+ if (loc.filename.length == 0)
+ return;
+ buf.writestring(loc.filename);
+ if (loc.line == 0)
+ return;
+
+ final switch (messageStyle)
+ {
+ case MessageStyle.digitalmars:
+ buf.writeByte('(');
+ buf.print(loc.line);
+ if (showColumns && loc.column)
+ {
+ buf.writeByte(',');
+ buf.print(loc.column);
+ }
+ buf.writeByte(')');
+ break;
+ case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html
+ buf.writeByte(':');
+ buf.print(loc.line);
+ if (showColumns && loc.column)
+ {
+ buf.writeByte(':');
+ buf.print(loc.column);
+ }
+ break;
+ case MessageStyle.sarif: // https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
+ // No formatting needed here for SARIF
+ break;
}
}
+
+/**
+ * Describes a location in the source code as a file + line number + column number
+ *
+ * While `Loc` is a compact opaque location meant to be stored in the AST,
+ * this struct has simple modifiable fields and is used for printing.
+ */
+struct SourceLoc
+{
+ const(char)[] filename; /// name of source file
+ uint line; /// line number (starts at 1)
+ uint column; /// column number (starts at 1)
+ uint fileOffset; /// byte index into file
+
+ /// Index `fileOffset` into this to to obtain source code context of this location
+ const(char)[] fileContent;
+
+ // aliases for backwards compatibility
+ alias linnum = line;
+ alias charnum = column;
+
+ this(const(char)[] filename, uint line, uint column, uint fileOffset = 0, const(char)[] fileContent = null) nothrow @nogc pure @safe
+ {
+ this.filename = filename;
+ this.line = line;
+ this.column = column;
+ this.fileOffset = fileOffset;
+ this.fileContent = fileContent;
+ }
+
+ this(Loc loc) nothrow @nogc @trusted
+ {
+ if (loc.index == 0 || locFileTable.length == 0)
+ return;
+
+ const i = fileTableIndex(loc.index);
+ this = locFileTable[i].getSourceLoc(loc.index - locFileTable[i].startIndex);
+ }
+
+ extern (C++) const(char)* toChars(
+ bool showColumns = Loc.showColumns,
+ MessageStyle messageStyle = Loc.messageStyle) const nothrow
+ {
+ OutBuffer buf;
+ writeSourceLoc(buf, this, showColumns, messageStyle);
+ return buf.extractChars();
+ }
+
+ bool opEquals(SourceLoc other) const nothrow
+ {
+ return this.filename == other.filename && this.line == other.line && this.column == other.column;
+ }
+
+}
+
+/// Given the `index` of a `Loc`, find the index in `locFileTable` of the corresponding `BaseLoc`
+private size_t fileTableIndex(uint index) nothrow @nogc
+{
+ // To speed up linear find, we cache the last hit and compare that first,
+ // since usually we stay in the same file for some time when resolving source locations.
+ // If it's a different file now, either scan forwards / backwards
+ __gshared size_t lastI = 0; // index of last found hit
+
+ size_t i = lastI;
+ if (index >= locFileTable[i].startIndex)
+ {
+ while (i + 1 < locFileTable.length && index >= locFileTable[i+1].startIndex)
+ i++;
+ }
+ else
+ {
+ while (index < locFileTable[i].startIndex)
+ i--;
+ }
+
+ lastI = i;
+ return i;
+}
+
+/**
+ * Create a new source location map for a file
+ * Params:
+ * filename = source file name
+ * fileContent = content of source file
+ * Returns: new BaseLoc
+ */
+BaseLoc* newBaseLoc(const(char)* filename, const(char)[] fileContent) nothrow
+{
+ locFileTable ~= new BaseLoc(filename.toDString, fileContent, locIndex, 1, [0]);
+ // Careful: the endloc of a FuncDeclaration can
+ // point to 1 past the very last byte in the file, so account for that
+ locIndex += fileContent.length + 1;
+ return locFileTable[$ - 1];
+}
+
+/**
+Mapping from byte offset into source file to line/column numbers
+
+Consider this 4-line 24 byte source file:
+
+---
+app.d
+1 struct S
+2 {
+3 int y;
+4 }
+---
+
+Loc(0) is reserved for null locations, so the first `BaseLoc` gets `startIndex = 1`
+and reserves 25 possible positions. Loc(1) represents the very start of this source
+file, and every next byte gets the next `Loc`, up to Loc(25) which represents the
+location right past the very last `}` character (hence it's 1 more than the file
+size of 24, classic fence post problem!).
+
+The next source file will get `Loc(26) .. Loc(26 + fileSize + 1)` etc.
+
+Now say we know that `int y` has a `Loc(20)` and we want to know the line and column number.
+
+First we find the corresponding `BaseLoc` in `locFileTable`. Since 20 < 26, the first `BaseLoc`
+contains this location. Since `startIndex = 1`, we subtract that to get a file offset 19.
+
+To get the line number from the file offset, we binary search into the `lines` array,
+which contains file offsets where each line starts:
+
+`locFileTable[0].lines == [0, 9, 11, 22, 24]`
+
+We see 14 would be inserted right after `11` at `lines[2]`, so it's line 3 (+1 for 1-indexing).
+Since line 3 starts at file offset 11, and `14 - 11 = 3`, it's column 4 (again, accounting for 1-indexing)
+
+#line and #file directives are handled with a separate array `substitutions` because they're rare,
+and we don't want to penalize memory usage in their absence.
+*/
+struct BaseLoc
+{
+@safe nothrow:
+
+ const(char)[] filename; /// Source file name
+ const(char)[] fileContents; /// Source file contents
+ uint startIndex; /// Subtract this from Loc.index to get file offset
+ int startLine = 1; /// Line number at index 0
+ uint[] lines; /// For each line, the file offset at which it starts. At index 0 there's always a 0 entry.
+ BaseLoc[] substitutions; /// Substitutions from #line / #file directives
+
+ /// Register that a new line starts at `offset` bytes from the start of the source file
+ void newLine(uint offset)
+ {
+ lines ~= offset;
+ }
+
+ /// Construct a `Loc` entry for the start of the source file + `offset` bytes
+ Loc getLoc(uint offset) @nogc
+ {
+ Loc result;
+ result.index = startIndex + offset;
+ return result;
+ }
+
+ /**
+ * Register a new file/line mapping from #file and #line directives
+ * Params:
+ * offset = byte offset in the source file at which the substitution starts
+ * filename = new filename from this point on (null = unchanged)
+ * line = line number from this point on
+ */
+ void addSubstitution(uint offset, const(char)* filename, uint line) @system
+ {
+ auto fname = filename.toDString;
+ if (substitutions.length == 0)
+ substitutions ~= BaseLoc(this.filename, null, 0, 0);
+
+ if (fname.length == 0)
+ fname = substitutions[$ - 1].filename;
+ substitutions ~= BaseLoc(fname, null, offset, cast(int) (line - lines.length + startLine - 2));
+ }
+
+ /// Returns: `loc` modified by substitutions from #file / #line directives
+ SourceLoc substitute(SourceLoc loc) @nogc
+ {
+ if (substitutions.length == 0)
+ return loc;
+
+ const i = getSubstitutionIndex(loc.fileOffset);
+ if (substitutions[i].filename.length > 0)
+ loc.filename = substitutions[i].filename;
+ loc.linnum += substitutions[i].startLine;
+ return loc;
+ }
+
+ /// Resolve an offset into this file to a filename + line + column
+ private SourceLoc getSourceLoc(uint offset) @nogc
+ {
+ const i = getLineIndex(offset);
+ const sl = SourceLoc(filename, cast(int) (i + startLine), cast(int) (1 + offset - lines[i]), offset, fileContents);
+ return substitute(sl);
+ }
+
+ private size_t getSubstitutionIndex(uint offset) @nogc
+ {
+ size_t lo = 0;
+ size_t hi = substitutions.length + -1;
+ size_t mid = 0;
+ while (lo <= hi)
+ {
+ mid = lo + (hi - lo) / 2;
+ if (substitutions[mid].startIndex <= offset)
+ {
+ if (mid == substitutions.length - 1 || substitutions[mid + 1].startIndex > offset)
+ return mid;
+
+ lo = mid + 1;
+ }
+ else
+ {
+ hi = mid - 1;
+ }
+ }
+ assert(0);
+ }
+
+ /// Binary search the index in `this.lines` corresponding to `offset`
+ private size_t getLineIndex(uint offset) @nogc
+ {
+ size_t lo = 0;
+ size_t hi = lines.length + -1;
+ size_t mid = 0;
+ while (lo <= hi)
+ {
+ mid = lo + (hi - lo) / 2;
+ if (lines[mid] <= offset)
+ {
+ if (mid == lines.length - 1 || lines[mid + 1] > offset)
+ return mid;
+
+ lo = mid + 1;
+ }
+ else
+ {
+ hi = mid - 1;
+ }
+ }
+ assert(0);
+ }
+}
+
+// Whenever a new source file is parsed, start the `Loc` from this index (0 is reserved for Loc.init)
+private __gshared uint locIndex = 1;
+
+// Global mapping of Loc indices to source file offset/line/column, see `BaseLoc`
+private __gshared BaseLoc*[] locFileTable;
diff --git a/gcc/d/dmd/mangle.h b/gcc/d/dmd/mangle.h
index de6fa55..97875c5 100644
--- a/gcc/d/dmd/mangle.h
+++ b/gcc/d/dmd/mangle.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/basicmangle.d b/gcc/d/dmd/mangle/basic.d
index 52534fa..263dd5e 100644
--- a/gcc/d/dmd/basicmangle.d
+++ b/gcc/d/dmd/mangle/basic.d
@@ -1,13 +1,13 @@
/**
* Defines the building blocks for creating the mangled names for basic types.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/basicmangle.d, _basicmangle.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/basic.d, _basicmangle.d)
* Documentation: https://dlang.org/phobos/dmd_basicmangle.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/basicmangle.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/mangle/basic.d
*/
-module dmd.basicmangle;
+module dmd.mangle.basic;
import dmd.astenums;
import dmd.common.outbuffer : OutBuffer;
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/mangle/cpp.d
index 0116aa3..7e9f020 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/mangle/cpp.d
@@ -4,24 +4,20 @@
* This is the POSIX side of the implementation.
* It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/cpp.d, _cppmangle.d)
* Documentation: https://dlang.org/phobos/dmd_cppmangle.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cppmangle.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/mangle/cpp.d
*
* References:
* Follows Itanium C++ ABI 1.86 section 5.1
* http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling
* which is where the grammar comments come from.
- *
- * Bugs:
- * https://issues.dlang.org/query.cgi
- * enter `C++, mangling` as the keywords.
*/
-module dmd.cppmangle;
+module dmd.mangle.cpp;
import core.stdc.stdio;
@@ -30,6 +26,7 @@ import dmd.astenums;
import dmd.attrib;
import dmd.declaration;
import dmd.dsymbol;
+import dmd.dsymbolsem : isGNUABITag;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
@@ -49,19 +46,30 @@ import dmd.typesem;
import dmd.visitor;
-// helper to check if an identifier is a C++ operator
-enum CppOperator { Cast, Assign, Eq, Index, Call, Unary, Binary, OpAssign, Unknown }
-package CppOperator isCppOperator(Identifier id)
+// C++ operators
+enum CppOperator { Unknown, Cast, Assign, Eq, Index, Call, Unary, Binary, OpAssign }
+
+/**************
+ * Check if id is a C++ operator
+ * Params:
+ * id = identifier to be checked
+ * Returns:
+ * CppOperator, or Unknown if not a C++ operator
+ */
+package CppOperator isCppOperator(const scope Identifier id)
{
- __gshared const(Identifier)[] operators = null;
- if (!operators)
- operators = [Id._cast, Id.assign, Id.eq, Id.index, Id.call, Id.opUnary, Id.opBinary, Id.opOpAssign];
- foreach (i, op; operators)
- {
- if (op == id)
- return cast(CppOperator)i;
+ with (Id) with (CppOperator)
+ {
+ return (id == opCast) ? Cast :
+ (id == opAssign) ? Assign :
+ (id == opEquals) ? Eq :
+ (id == opIndex) ? Index :
+ (id == opCall) ? Call :
+ (id == opUnary) ? Unary :
+ (id == opBinary) ? Binary :
+ (id == opOpAssign) ? OpAssign :
+ Unknown ;
}
- return CppOperator.Unknown;
}
///
@@ -71,6 +79,8 @@ const(char)* toCppMangleItanium(Dsymbol s)
OutBuffer buf;
scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc);
v.mangleOf(s);
+ if (v.errors)
+ fatal();
return buf.extractChars();
}
@@ -82,6 +92,8 @@ const(char)* cppTypeInfoMangleItanium(Dsymbol s)
buf.writestring("_ZTI"); // "TI" means typeinfo structure
scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc);
v.cpp_mangle_name(s, false);
+ if (v.errors)
+ fatal();
return buf.extractChars();
}
@@ -93,6 +105,8 @@ const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
buf.printf("_ZThn%u_", offset); // "Th" means thunk, "n%u" is the call offset
scope CppMangleVisitor v = new CppMangleVisitor(&buf, fd.loc);
v.mangle_function_encoding(fd);
+ if (v.errors)
+ fatal();
return buf.extractChars();
}
@@ -163,6 +177,7 @@ private final class CppMangleVisitor : Visitor
Objects components; /// array of components available for substitution
OutBuffer* buf; /// append the mangling to buf[]
Loc loc; /// location for use in error messages
+ bool errors; /// failed to mangle properly
/**
* Constructor
@@ -216,7 +231,7 @@ private final class CppMangleVisitor : Visitor
// if so, just pick up the type from the instance
if (!rt)
rt = tf.nextOf();
- if (tf.isref)
+ if (tf.isRef)
rt = rt.referenceTo();
auto prev = this.context.push(tf.nextOf());
scope (exit) this.context.pop(prev);
@@ -420,10 +435,10 @@ private final class CppMangleVisitor : Visitor
// 4. null pointer: std::nullptr_t (since C++11)
if (t.ty == Tvoid || t.ty == Tbool)
return true;
- else if (t.ty == Tnull && global.params.cplusplus >= CppStdRevision.cpp11)
+ if (t.ty == Tnull && global.params.cplusplus >= CppStdRevision.cpp11)
return true;
- else
- return t.isTypeBasic() && (t.isintegral() || t.isreal());
+
+ return t.isTypeBasic() && (t.isIntegral() || t.isReal());
}
/******************************
@@ -466,14 +481,14 @@ private final class CppMangleVisitor : Visitor
else if (TemplateValueParameter tv = tp.isTemplateValueParameter())
{
// <expr-primary> ::= L <type> <value number> E # integer literal
- if (tv.valType.isintegral())
+ if (tv.valType.isIntegral())
{
Expression e = isExpression(o);
assert(e);
buf.writeByte('L');
tv.valType.accept(this);
auto val = e.toUInteger();
- if (!tv.valType.isunsigned() && cast(sinteger_t)val < 0)
+ if (!tv.valType.isUnsigned() && cast(sinteger_t)val < 0)
{
val = -val;
buf.writeByte('n');
@@ -484,7 +499,8 @@ private final class CppMangleVisitor : Visitor
else
{
.error(ti.loc, "%s `%s` internal compiler error: C++ `%s` template value parameter is not supported", ti.kind, ti.toPrettyChars, tv.valType.toChars());
- fatal();
+ errors = true;
+ return;
}
}
else if (tp.isTemplateAliasParameter())
@@ -519,13 +535,13 @@ private final class CppMangleVisitor : Visitor
else
{
.error(ti.loc, "%s `%s` internal compiler error: C++ `%s` template alias parameter is not supported", ti.kind, ti.toPrettyChars, o.toChars());
- fatal();
+ errors = true;
}
}
else if (tp.isTemplateThisParameter())
{
.error(ti.loc, "%s `%s` internal compiler error: C++ `%s` template this parameter is not supported", ti.kind, ti.toPrettyChars, o.toChars());
- fatal();
+ errors = true;
}
else
{
@@ -574,7 +590,8 @@ private final class CppMangleVisitor : Visitor
if (t is null)
{
.error(ti.loc, "%s `%s` internal compiler error: C++ `%s` template value parameter is not supported", ti.kind, ti.toPrettyChars, (*ti.tiargs)[j].toChars());
- fatal();
+ errors = true;
+ return false;
}
t.accept(this);
}
@@ -705,8 +722,7 @@ private final class CppMangleVisitor : Visitor
*/
static Dsymbol getInstance(Dsymbol s)
{
- Dsymbol p = s.toParent();
- if (p)
+ if (Dsymbol p = s.toParent())
{
if (TemplateInstance ti = p.isTemplateInstance())
return ti;
@@ -807,8 +823,7 @@ private final class CppMangleVisitor : Visitor
return buf.writestring("St");
auto si = getInstance(s);
- Dsymbol p = getQualifier(si);
- if (p)
+ if (Dsymbol p = getQualifier(si))
{
if (isStd(p))
{
@@ -1012,7 +1027,8 @@ private final class CppMangleVisitor : Visitor
if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared)))
{
.error(d.loc, "%s `%s` internal compiler error: C++ static non-`__gshared` non-`extern` variables not supported", d.kind, d.toPrettyChars);
- fatal();
+ errors = true;
+ return;
}
Dsymbol p = d.toParent();
if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE"
@@ -1086,13 +1102,13 @@ private final class CppMangleVisitor : Visitor
buf.writestring(ctor.isCpCtor ? "C2" : "C1");
else if (d.isAggregateDtor())
buf.writestring("D1");
- else if (d.ident && d.ident == Id.assign)
+ else if (d.ident && d.ident == Id.opAssign)
buf.writestring("aS");
- else if (d.ident && d.ident == Id.eq)
+ else if (d.ident && d.ident == Id.opEquals)
buf.writestring("eq");
- else if (d.ident && d.ident == Id.index)
+ else if (d.ident && d.ident == Id.opIndex)
buf.writestring("ix");
- else if (d.ident && d.ident == Id.call)
+ else if (d.ident && d.ident == Id.opCall)
buf.writestring("cl");
else
source_name(d, true);
@@ -1348,7 +1364,8 @@ private final class CppMangleVisitor : Visitor
// Static arrays in D are passed by value; no counterpart in C++
.error(loc, "internal compiler error: unable to pass static array `%s` to extern(C++) function, use pointer instead",
t.toChars());
- fatal();
+ errors = true;
+ return;
}
auto prev = this.context.push({
TypeFunction tf;
@@ -1386,7 +1403,7 @@ private final class CppMangleVisitor : Visitor
else
p = "";
.error(loc, "internal compiler error: %stype `%s` cannot be mapped to C++\n", p, t.toChars());
- fatal(); //Fatal, because this error should be handled in frontend
+ errors = true; //Fatal, because this error should be handled in frontend
}
/****************************
@@ -1729,7 +1746,7 @@ extern(C++):
* Ds char16_t
* u <source-name> # vendor extended type
*/
- if (t.isimaginary() || t.iscomplex())
+ if (t.isImaginary() || t.isComplex())
{
// https://issues.dlang.org/show_bug.cgi?id=22806
// Complex and imaginary types are represented in the same way as
@@ -1740,7 +1757,7 @@ extern(C++):
append(t);
CV_qualifiers(t);
- if (t.isimaginary())
+ if (t.isImaginary())
buf.writeByte('G'); // 'G' means imaginary
else
buf.writeByte('C'); // 'C' means complex
@@ -1895,7 +1912,7 @@ extern(C++):
if (t.linkage == LINK.c)
buf.writeByte('Y');
Type tn = t.next;
- if (t.isref)
+ if (t.isRef)
tn = tn.referenceTo();
tn.accept(this);
mangleFunctionParameters(t.parameterList);
@@ -1922,21 +1939,21 @@ extern(C++):
//printf("enum id = '%s'\n", id.toChars());
if (id == Id.__c_long)
return writeBasicType(t, 0, 'l');
- else if (id == Id.__c_ulong)
+ if (id == Id.__c_ulong)
return writeBasicType(t, 0, 'm');
- else if (id == Id.__c_char)
+ if (id == Id.__c_char)
return writeBasicType(t, 0, 'c');
- else if (id == Id.__c_wchar_t)
+ if (id == Id.__c_wchar_t)
return writeBasicType(t, 0, 'w');
- else if (id == Id.__c_longlong)
+ if (id == Id.__c_longlong)
return writeBasicType(t, 0, 'x');
- else if (id == Id.__c_ulonglong)
+ if (id == Id.__c_ulonglong)
return writeBasicType(t, 0, 'y');
- else if (id == Id.__c_complex_float)
+ if (id == Id.__c_complex_float)
return Type.tcomplex32.accept(this);
- else if (id == Id.__c_complex_double)
+ if (id == Id.__c_complex_double)
return Type.tcomplex64.accept(this);
- else if (id == Id.__c_complex_real)
+ if (id == Id.__c_complex_real)
return Type.tcomplex80.accept(this);
doSymbol(t);
@@ -2175,7 +2192,7 @@ private extern(C++) final class ComponentVisitor : Visitor
/// Set to the result of the comparison
private bool result;
- public this(RootObject base) @safe
+ public this(RootObject base) @trusted
{
switch (base.dyncast())
{
@@ -2345,8 +2362,7 @@ private bool isNamespaceEqual (CPPNamespaceDeclaration a, Nspace b, size_t idx =
// We need to see if there's more ident enclosing
if (auto pb = b.toParent().isNspace())
return isNamespaceEqual(a.cppnamespace, pb);
- else
- return a.cppnamespace is null;
+ return a.cppnamespace is null;
}
/// Returns:
@@ -2413,7 +2429,7 @@ private struct ABITagContainer
foreach (exp; *s.userAttribDecl.atts)
{
- if (UserAttributeDeclaration.isGNUABITag(exp))
+ if (isGNUABITag(exp))
return (*exp.isStructLiteralExp().elements)[0]
.isArrayLiteralExp();
}
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/mangle/package.d
index 33428de..3ad2c7d 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/mangle/package.d
@@ -3,16 +3,16 @@
*
* Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/package.d, _dmangle.d)
* Documentation: https://dlang.org/phobos/dmd_dmangle.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmangle.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/mangle/package.d
* References: https://dlang.org/blog/2017/12/20/ds-newfangled-name-mangling/
*/
-module dmd.dmangle;
+module dmd.mangle;
/******************************************************************************
@@ -70,14 +70,16 @@ void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
}
/// Returns: `true` if the given character is a valid mangled character
-package bool isValidMangling(dchar c) nothrow
+package(dmd) bool isValidMangling(dchar c) nothrow
{
+ import dmd.common.charactertables;
+
return
c >= 'A' && c <= 'Z' ||
c >= 'a' && c <= 'z' ||
c >= '0' && c <= '9' ||
c != 0 && strchr("$%().:?@[]_", c) ||
- isUniAlpha(c);
+ isAnyIdentifierCharacter(c);
}
// valid mangled characters
@@ -137,7 +139,7 @@ import core.stdc.string;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
-import dmd.basicmangle;
+import dmd.mangle.basic;
import dmd.dclass;
import dmd.declaration;
import dmd.dinterpret;
@@ -147,6 +149,7 @@ import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.id;
import dmd.identifier;
@@ -355,31 +358,31 @@ void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret, r
if (ta.purity)
buf.writestring("Na");
- if (ta.isnothrow)
+ if (ta.isNothrow)
buf.writestring("Nb");
- if (ta.isref)
+ if (ta.isRef)
buf.writestring("Nc");
- if (ta.isproperty)
+ if (ta.isProperty)
buf.writestring("Nd");
- if (ta.isnogc)
+ if (ta.isNogc)
buf.writestring("Ni");
// `return scope` must be in that order
- if (ta.isreturnscope && !ta.isreturninferred)
+ if (ta.isReturnScope && !ta.isReturnInferred)
{
buf.writestring("NjNl");
}
else
{
// when return ref, the order is `scope return`
- if (ta.isScopeQual && !ta.isscopeinferred)
+ if (ta.isScopeQual && !ta.isScopeInferred)
buf.writestring("Nl");
- if (ta.isreturn && !ta.isreturninferred)
+ if (ta.isReturn && !ta.isReturnInferred)
buf.writestring("Nj");
}
- if (ta.islive)
+ if (ta.isLive)
buf.writestring("Nm");
switch (ta.trust)
@@ -448,7 +451,7 @@ void mangleParameter(Parameter p, ref OutBuffer buf, ref Backref backref)
switch (stc & ((STC.IOR | STC.lazy_) & ~STC.constscoperef))
{
- case 0:
+ case STC.none:
break;
case STC.in_:
buf.writeByte('I');
@@ -827,7 +830,7 @@ public:
continue;
}
// Now that we know it is not an alias, we MUST obtain a value
- uint olderr = global.errors;
+ const olderr = global.errors;
ea = ea.ctfeInterpret();
if (ea.op == EXP.error || olderr != global.errors)
continue;
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index 379e8e6..e178014 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -28,6 +28,14 @@ enum PKG
PKGpackage // already determined that's an actual package
};
+enum class Edition : unsigned char
+{
+ none = 0u,
+ legacy = 1u,
+ v2024 = 2u,
+ latest = 2u,
+};
+
class Package : public ScopeDsymbol
{
public:
@@ -39,8 +47,6 @@ public:
bool equals(const RootObject * const o) const override;
- Package *isPackage() override final { return this; }
-
bool isAncestorPackageOf(const Package * const pkg) const;
void accept(Visitor *v) override { v->visit(this); }
@@ -75,6 +81,7 @@ public:
FileType filetype; // source file type
d_bool hasAlwaysInlines; // contains references to functions that must be inlined
d_bool isPackageFile; // if it is a package.d
+ Edition edition; // language edition that this module is compiled with
Package *pkg; // if isPackageFile is true, the Package that contains this package.d
Strings contentImportedFiles; // array of files whose content was imported
int needmoduleinfo;
@@ -100,11 +107,9 @@ public:
Modules aimports; // all imported modules
- unsigned debuglevel; // debug level
Identifiers *debugids; // debug identifiers
Identifiers *debugidsNot; // forward referenced debug identifiers
- unsigned versionlevel; // version level
Identifiers *versionids; // version identifiers
Identifiers *versionidsNot; // forward referenced version identifiers
@@ -116,10 +121,10 @@ public:
static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
static const char *find(const char *filename);
- static Module *load(const Loc &loc, Identifiers *packages, Identifier *ident);
+ static Module *load(Loc loc, Identifiers *packages, Identifier *ident);
const char *kind() const override;
- bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise.
+ bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise.
Module *parse(); // syntactic parse
int needModuleInfo();
bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all) override;
@@ -151,7 +156,6 @@ public:
void *ctfe_cov; // stores coverage information from ctfe
- Module *isModule() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 715ee12..a3e1a8c 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -1,12 +1,12 @@
/**
* Defines a D type.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mtype.d, _mtype.d)
* Documentation: https://dlang.org/phobos/dmd_mtype.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mtype.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/mtype.d
*/
module dmd.mtype;
@@ -30,7 +30,7 @@ import dmd.dtemplate;
import dmd.enumsem;
import dmd.errors;
import dmd.expression;
-import dmd.funcsem;
+import dmd.dsymbolsem : determineSize;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -58,6 +58,11 @@ static if (__VERSION__ < 2095)
private alias StringValueType = StringValue!Type;
}
+private auto X(T, U)(T m, U n)
+{
+ return (m << 4) | n;
+}
+
/***************************
* Return !=0 if modfrom can be implicitly converted to modto
*/
@@ -67,10 +72,6 @@ bool MODimplicitConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe
return true;
//printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
- auto X(T, U)(T m, U n)
- {
- return ((m << 4) | n);
- }
switch (X(modfrom & ~MODFlags.shared_, modto & ~MODFlags.shared_))
{
@@ -98,11 +99,6 @@ MATCH MODmethodConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe
if (MODimplicitConv(modfrom, modto))
return MATCH.constant;
- auto X(T, U)(T m, U n)
- {
- return ((m << 4) | n);
- }
-
switch (X(modfrom, modto))
{
case X(0, MODFlags.wild):
@@ -236,9 +232,9 @@ unittest
/************************************
* Convert MODxxxx to STCxxx
*/
-StorageClass ModToStc(uint mod) pure nothrow @nogc @safe
+STC ModToStc(uint mod) pure nothrow @nogc @safe
{
- StorageClass stc = 0;
+ STC stc = STC.none;
if (mod & MODFlags.immutable_)
stc |= STC.immutable_;
if (mod & MODFlags.const_)
@@ -303,13 +299,16 @@ extern (C++) abstract class Type : ASTNode
Type wcto; // MODFlags.wildconst
Type swto; // MODFlags.shared_ | MODFlags.wild
Type swcto; // MODFlags.shared_ | MODFlags.wildconst
+ Type pto; // merged pointer to this type
+ Type rto; // reference to this type
+ Type arrayof; // array of this type
+
+ // ImportC: store the name of the typedef resolving to this type
+ // So `uint8_t x;` will be printed as `uint8_t x;` and not as the resolved `ubyte x;`
+ Identifier typedefIdent;
}
Mcache* mcache;
- Type pto; // merged pointer to this type
- Type rto; // reference to this type
- Type arrayof; // array of this type
-
TypeInfoDeclaration vtinfo; // TypeInfo object for this Type
void* ctype; // for back end
@@ -520,7 +519,7 @@ extern (C++) abstract class Type : ASTNode
static Type merge(Type t)
{
- import dmd.basicmangle : tyToDecoBuffer;
+ import dmd.mangle.basic : tyToDecoBuffer;
OutBuffer buf;
buf.reserve(3);
@@ -533,12 +532,9 @@ extern (C++) abstract class Type : ASTNode
auto sv = t.stringtable.update(buf[]);
if (sv.value)
return sv.value;
- else
- {
- t.deco = cast(char*)sv.toDchars();
- sv.value = t;
- return t;
- }
+ t.deco = cast(char*)sv.toDchars();
+ sv.value = t;
+ return t;
}
for (size_t i = 0; basetab[i] != Terror; i++)
@@ -597,6 +593,14 @@ extern (C++) abstract class Type : ASTNode
tsize_t = basic[isLP64 ? Tuns64 : Tuns32];
tptrdiff_t = basic[isLP64 ? Tint64 : Tint32];
thash_t = tsize_t;
+
+ static if (__VERSION__ == 2081)
+ {
+ // Related issue: https://issues.dlang.org/show_bug.cgi?id=19134
+ // D 2.081.x regressed initializing class objects at compile time.
+ // As a workaround initialize this global at run-time instead.
+ TypeTuple.empty = new TypeTuple();
+ }
}
/**
@@ -610,20 +614,9 @@ extern (C++) abstract class Type : ASTNode
stringtable = stringtable.init;
}
- final uinteger_t size()
- {
- return size(Loc.initial);
- }
-
- uinteger_t size(const ref Loc loc)
- {
- error(loc, "no size for type `%s`", toChars());
- return SIZE_INVALID;
- }
-
uint alignsize()
{
- return cast(uint)size(Loc.initial);
+ return cast(uint)size(this, Loc.initial);
}
/*********************************
@@ -649,43 +642,43 @@ extern (C++) abstract class Type : ASTNode
return buf.extractChars();
}
- bool isintegral()
+ bool isIntegral()
{
return false;
}
// real, imaginary, or complex
- bool isfloating()
+ bool isFloating()
{
return false;
}
- bool isreal()
+ bool isReal()
{
return false;
}
- bool isimaginary()
+ bool isImaginary()
{
return false;
}
- bool iscomplex()
+ bool isComplex()
{
return false;
}
- bool isscalar()
+ bool isScalar()
{
return false;
}
- bool isunsigned()
+ bool isUnsigned()
{
return false;
}
- bool isscope()
+ bool isScopeClass()
{
return false;
}
@@ -713,7 +706,7 @@ extern (C++) abstract class Type : ASTNode
*/
bool isBoolean()
{
- return isscalar();
+ return isScalar();
}
final bool isConst() const nothrow pure @nogc @safe
@@ -772,9 +765,6 @@ extern (C++) abstract class Type : ASTNode
memcpy(cast(void*)t, cast(void*)this, sz);
// t.mod = NULL; // leave mod unchanged
t.deco = null;
- t.arrayof = null;
- t.pto = null;
- t.rto = null;
t.vtinfo = null;
t.ctype = null;
t.mcache = null;
@@ -1118,70 +1108,71 @@ extern (C++) abstract class Type : ASTNode
* Apply STCxxxx bits to existing type.
* Use *before* semantic analysis is run.
*/
- extern (D) final Type addSTC(StorageClass stc)
+ extern (D) final Type addSTC(STC stc)
{
Type t = this;
if (t.isImmutable())
{
+ return t;
}
else if (stc & STC.immutable_)
{
t = t.makeImmutable();
+ return t;
}
- else
+
+ if ((stc & STC.shared_) && !t.isShared())
{
- if ((stc & STC.shared_) && !t.isShared())
+ if (t.isWild())
+ {
+ if (t.isConst())
+ t = t.makeSharedWildConst();
+ else
+ t = t.makeSharedWild();
+ }
+ else
+ {
+ if (t.isConst())
+ t = t.makeSharedConst();
+ else
+ t = t.makeShared();
+ }
+ }
+ if ((stc & STC.const_) && !t.isConst())
+ {
+ if (t.isShared())
{
if (t.isWild())
- {
- if (t.isConst())
- t = t.makeSharedWildConst();
- else
- t = t.makeSharedWild();
- }
+ t = t.makeSharedWildConst();
else
- {
- if (t.isConst())
- t = t.makeSharedConst();
- else
- t = t.makeShared();
- }
+ t = t.makeSharedConst();
}
- if ((stc & STC.const_) && !t.isConst())
+ else
{
- if (t.isShared())
- {
- if (t.isWild())
- t = t.makeSharedWildConst();
- else
- t = t.makeSharedConst();
- }
+ if (t.isWild())
+ t = t.makeWildConst();
else
- {
- if (t.isWild())
- t = t.makeWildConst();
- else
- t = t.makeConst();
- }
+ t = t.makeConst();
}
- if ((stc & STC.wild) && !t.isWild())
+ }
+ if ((stc & STC.wild) && !t.isWild())
+ {
+ if (t.isShared())
{
- if (t.isShared())
- {
- if (t.isConst())
- t = t.makeSharedWildConst();
- else
- t = t.makeSharedWild();
- }
+ if (t.isConst())
+ t = t.makeSharedWildConst();
else
- {
- if (t.isConst())
- t = t.makeWildConst();
- else
- t = t.makeWild();
- }
+ t = t.makeSharedWild();
+ }
+ else
+ {
+ if (t.isConst())
+ t = t.makeWildConst();
+ else
+ t = t.makeWild();
}
}
+
return t;
}
@@ -1285,40 +1276,6 @@ extern (C++) abstract class Type : ASTNode
return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this;
}
- /********************************
- * Determine if 'this' can be implicitly converted
- * to type 'to'.
- * Returns:
- * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
- */
- MATCH implicitConvTo(Type to)
- {
- //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- if (this.equals(to))
- return MATCH.exact;
- return MATCH.nomatch;
- }
-
- /*******************************
- * Determine if converting 'this' to 'to' is an identity operation,
- * a conversion to const operation, or the types aren't the same.
- * Returns:
- * MATCH.exact 'this' == 'to'
- * MATCH.constant 'to' is const
- * MATCH.nomatch conversion to mutable or invariant
- */
- MATCH constConv(Type to)
- {
- //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to.toChars());
- if (equals(to))
- return MATCH.exact;
- if (ty == to.ty && MODimplicitConv(mod, to.mod))
- return MATCH.constant;
- return MATCH.nomatch;
- }
-
/***************************************
* Compute MOD bits matching `this` argument type to wild parameter type.
* Params:
@@ -1334,21 +1291,19 @@ extern (C++) abstract class Type : ASTNode
{
if (isImmutable())
return MODFlags.immutable_;
- else if (isWildConst())
+ if (isWildConst())
{
if (t.isWildConst())
return MODFlags.wild;
- else
- return MODFlags.wildconst;
+ return MODFlags.wildconst;
}
- else if (isWild())
+ if (isWild())
return MODFlags.wild;
- else if (isConst())
+ if (isConst())
return MODFlags.const_;
- else if (isMutable())
+ if (isMutable())
return MODFlags.mutable;
- else
- assert(0);
+ assert(0);
}
return 0;
}
@@ -1372,7 +1327,7 @@ extern (C++) abstract class Type : ASTNode
* Use when we prefer the default initializer to be a literal,
* rather than a global immutable variable.
*/
- Expression defaultInitLiteral(const ref Loc loc)
+ Expression defaultInitLiteral(Loc loc)
{
static if (LOGDEFAULTINIT)
{
@@ -1381,12 +1336,6 @@ extern (C++) abstract class Type : ASTNode
return defaultInit(this, loc);
}
- // if initializer is 0
- bool isZeroInit(const ref Loc loc)
- {
- return false; // assume not
- }
-
/***************************************
* Return !=0 if the type or any of its subtypes is wild.
*/
@@ -1412,7 +1361,7 @@ extern (C++) abstract class Type : ASTNode
* Returns:
* true if so
*/
- bool hasSystemFields()
+ bool hasUnsafeBitpatterns()
{
return false;
}
@@ -1446,33 +1395,6 @@ extern (C++) abstract class Type : ASTNode
return t;
}
- /*******************************************
- * Compute number of elements for a (possibly multidimensional) static array,
- * or 1 for other types.
- * Params:
- * loc = for error message
- * Returns:
- * number of elements, uint.max on overflow
- */
- final uint numberOfElems(const ref Loc loc)
- {
- //printf("Type::numberOfElems()\n");
- uinteger_t n = 1;
- Type tb = this;
- while ((tb = tb.toBasetype()).ty == Tsarray)
- {
- bool overflow = false;
- n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow);
- if (overflow || n >= uint.max)
- {
- error(loc, "static array `%s` size overflowed to %llu", toChars(), cast(ulong)n);
- return uint.max;
- }
- tb = (cast(TypeSArray)tb).next;
- }
- return cast(uint)n;
- }
-
/****************************************
* Return the mask that an integral type will
* fit into.
@@ -1574,7 +1496,7 @@ extern (C++) abstract class Type : ASTNode
}
}
- final pure inout nothrow @nogc @safe
+ final pure inout nothrow @nogc @trusted
{
inout(TypeError) isTypeError() { return ty == Terror ? cast(typeof(return))this : null; }
inout(TypeVector) isTypeVector() { return ty == Tvector ? cast(typeof(return))this : null; }
@@ -1599,6 +1521,8 @@ extern (C++) abstract class Type : ASTNode
inout(TypeTraits) isTypeTraits() { return ty == Ttraits ? cast(typeof(return))this : null; }
inout(TypeNoreturn) isTypeNoreturn() { return ty == Tnoreturn ? cast(typeof(return))this : null; }
inout(TypeTag) isTypeTag() { return ty == Ttag ? cast(typeof(return))this : null; }
+
+ extern (D) bool isStaticOrDynamicArray() const { return ty == Tarray || ty == Tsarray; }
}
override void accept(Visitor v)
@@ -1648,12 +1572,7 @@ extern (C++) final class TypeError : Type
return this;
}
- override uinteger_t size(const ref Loc loc)
- {
- return SIZE_INVALID;
- }
-
- override Expression defaultInitLiteral(const ref Loc loc)
+ override Expression defaultInitLiteral(Loc loc)
{
return ErrorExp.get();
}
@@ -1687,10 +1606,10 @@ extern (C++) abstract class TypeNext : Type
/*******************************
* For TypeFunction, nextOf() can return NULL if the function return
- * type is meant to be inferred, and semantic() hasn't yet ben run
+ * type is meant to be inferred, and semantic() hasn't yet been run
* on the function. After semantic(), it must no longer be NULL.
*/
- override final Type nextOf()
+ override final Type nextOf() @safe
{
return next;
}
@@ -1890,35 +1809,6 @@ extern (C++) abstract class TypeNext : Type
return t;
}
- override MATCH constConv(Type to)
- {
- //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to.toChars());
- if (equals(to))
- return MATCH.exact;
-
- if (!(ty == to.ty && MODimplicitConv(mod, to.mod)))
- return MATCH.nomatch;
-
- Type tn = to.nextOf();
- if (!(tn && next.ty == tn.ty))
- return MATCH.nomatch;
-
- MATCH m;
- if (to.isConst()) // whole tail const conversion
- {
- // Recursive shared level check
- m = next.constConv(tn);
- if (m == MATCH.exact)
- m = MATCH.constant;
- }
- else
- {
- //printf("\tnext => %s, to.next => %s\n", next.toChars(), tn.toChars());
- m = next.equals(tn) ? MATCH.constant : MATCH.nomatch;
- }
- return m;
- }
-
override final MOD deduceWild(Type t, bool isRef)
{
if (ty == Tfunction)
@@ -2108,236 +1998,50 @@ extern (C++) final class TypeBasic : Type
return this;
}
- override uinteger_t size(const ref Loc loc)
- {
- uint size;
- //printf("TypeBasic::size()\n");
- switch (ty)
- {
- case Tint8:
- case Tuns8:
- size = 1;
- break;
-
- case Tint16:
- case Tuns16:
- size = 2;
- break;
-
- case Tint32:
- case Tuns32:
- case Tfloat32:
- case Timaginary32:
- size = 4;
- break;
-
- case Tint64:
- case Tuns64:
- case Tfloat64:
- case Timaginary64:
- size = 8;
- break;
-
- case Tfloat80:
- case Timaginary80:
- size = target.realsize;
- break;
-
- case Tcomplex32:
- size = 8;
- break;
-
- case Tcomplex64:
- case Tint128:
- case Tuns128:
- size = 16;
- break;
-
- case Tcomplex80:
- size = target.realsize * 2;
- break;
-
- case Tvoid:
- //size = Type::size(); // error message
- size = 1;
- break;
-
- case Tbool:
- size = 1;
- break;
-
- case Tchar:
- size = 1;
- break;
-
- case Twchar:
- size = 2;
- break;
-
- case Tdchar:
- size = 4;
- break;
-
- default:
- assert(0);
- }
- //printf("TypeBasic::size() = %d\n", size);
- return size;
- }
-
override uint alignsize()
{
return target.alignsize(this);
}
- override bool isintegral()
+ override bool isIntegral()
{
- //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
+ //printf("TypeBasic::isIntegral('%s') x%x\n", toChars(), flags);
return (flags & TFlags.integral) != 0;
}
- override bool isfloating()
+ override bool isFloating()
{
return (flags & TFlags.floating) != 0;
}
- override bool isreal()
+ override bool isReal()
{
return (flags & TFlags.real_) != 0;
}
- override bool isimaginary()
+ override bool isImaginary()
{
return (flags & TFlags.imaginary) != 0;
}
- override bool iscomplex()
+ override bool isComplex()
{
return (flags & TFlags.complex) != 0;
}
- override bool isscalar()
+ override bool isScalar()
{
return (flags & (TFlags.integral | TFlags.floating)) != 0;
}
- override bool isunsigned()
+ override bool isUnsigned()
{
return (flags & TFlags.unsigned) != 0;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
- if (this == to)
- return MATCH.exact;
-
- if (ty == to.ty)
- {
- if (mod == to.mod)
- return MATCH.exact;
- else if (MODimplicitConv(mod, to.mod))
- return MATCH.constant;
- else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching
- return MATCH.constant;
- else
- return MATCH.convert;
- }
-
- if (ty == Tvoid || to.ty == Tvoid)
- return MATCH.nomatch;
- if (to.ty == Tbool)
- return MATCH.nomatch;
-
- TypeBasic tob;
- if (to.ty == Tvector && to.deco)
- {
- TypeVector tv = cast(TypeVector)to;
- tob = tv.elementType();
- }
- else if (auto te = to.isTypeEnum())
- {
- EnumDeclaration ed = te.sym;
- if (ed.isSpecial())
- {
- /* Special enums that allow implicit conversions to them
- * with a MATCH.convert
- */
- tob = to.toBasetype().isTypeBasic();
- }
- else
- return MATCH.nomatch;
- }
- else
- tob = to.isTypeBasic();
- if (!tob)
- return MATCH.nomatch;
-
- if (flags & TFlags.integral)
- {
- // Disallow implicit conversion of integers to imaginary or complex
- if (tob.flags & (TFlags.imaginary | TFlags.complex))
- return MATCH.nomatch;
-
- // If converting from integral to integral
- if (tob.flags & TFlags.integral)
- {
- const sz = size(Loc.initial);
- const tosz = tob.size(Loc.initial);
-
- /* Can't convert to smaller size
- */
- if (sz > tosz)
- return MATCH.nomatch;
- /* Can't change sign if same size
- */
- //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
- // return MATCH.nomatch;
- }
- }
- else if (flags & TFlags.floating)
- {
- // Disallow implicit conversion of floating point to integer
- if (tob.flags & TFlags.integral)
- return MATCH.nomatch;
-
- assert(tob.flags & TFlags.floating || to.ty == Tvector);
-
- // Disallow implicit conversion from complex to non-complex
- if (flags & TFlags.complex && !(tob.flags & TFlags.complex))
- return MATCH.nomatch;
-
- // Disallow implicit conversion of real or imaginary to complex
- if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex)
- return MATCH.nomatch;
-
- // Disallow implicit conversion to-from real and imaginary
- if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary)))
- return MATCH.nomatch;
- }
- return MATCH.convert;
- }
-
- override bool isZeroInit(const ref Loc loc)
+ override bool hasUnsafeBitpatterns()
{
- switch (ty)
- {
- case Tchar:
- case Twchar:
- case Tdchar:
- case Timaginary32:
- case Timaginary64:
- case Timaginary80:
- case Tfloat32:
- case Tfloat64:
- case Tfloat80:
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- return false; // no
- default:
- return true; // yes
- }
+ return ty == Tbool;
}
// For eliminating dynamic_cast
@@ -2383,35 +2087,30 @@ extern (C++) final class TypeVector : Type
return new TypeVector(basetype.syntaxCopy());
}
- override uinteger_t size(const ref Loc loc)
- {
- return basetype.size();
- }
-
override uint alignsize()
{
return cast(uint)basetype.size();
}
- override bool isintegral()
+ override bool isIntegral()
{
- //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
- return basetype.nextOf().isintegral();
+ //printf("TypeVector::isIntegral('%s') x%x\n", toChars(), flags);
+ return basetype.nextOf().isIntegral();
}
- override bool isfloating()
+ override bool isFloating()
{
- return basetype.nextOf().isfloating();
+ return basetype.nextOf().isFloating();
}
- override bool isscalar()
+ override bool isScalar()
{
- return basetype.nextOf().isscalar();
+ return basetype.nextOf().isScalar();
}
- override bool isunsigned()
+ override bool isUnsigned()
{
- return basetype.nextOf().isunsigned();
+ return basetype.nextOf().isUnsigned();
}
override bool isBoolean()
@@ -2419,30 +2118,7 @@ extern (C++) final class TypeVector : Type
return false;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
- if (this == to)
- return MATCH.exact;
- if (to.ty != Tvector)
- return MATCH.nomatch;
-
- TypeVector tv = cast(TypeVector)to;
- assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray);
-
- // Can't convert to a vector which has different size.
- if (basetype.size() != tv.basetype.size())
- return MATCH.nomatch;
-
- // Allow conversion to void[]
- if (tv.basetype.nextOf().ty == Tvoid)
- return MATCH.convert;
-
- // Otherwise implicitly convertible only if basetypes are.
- return basetype.implicitConvTo(tv.basetype);
- }
-
- override Expression defaultInitLiteral(const ref Loc loc)
+ override Expression defaultInitLiteral(Loc loc)
{
//printf("TypeVector::defaultInitLiteral()\n");
assert(basetype.ty == Tsarray);
@@ -2462,11 +2138,6 @@ extern (C++) final class TypeVector : Type
return tb;
}
- override bool isZeroInit(const ref Loc loc)
- {
- return basetype.isZeroInit(loc);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2532,22 +2203,6 @@ extern (C++) final class TypeSArray : TypeArray
return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0;
}
- override uinteger_t size(const ref Loc loc)
- {
- //printf("TypeSArray::size()\n");
- const n = numberOfElems(loc);
- const elemsize = baseElemOf().size(loc);
- bool overflow = false;
- const sz = mulu(n, elemsize, overflow);
- if (overflow || sz >= uint.max)
- {
- if (elemsize != SIZE_INVALID && n != uint.max)
- error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz);
- return SIZE_INVALID;
- }
- return sz;
- }
-
override uint alignsize()
{
return next.alignsize();
@@ -2559,86 +2214,12 @@ extern (C++) final class TypeSArray : TypeArray
return nty.isSomeChar;
}
- override bool isZeroInit(const ref Loc loc)
- {
- return next.isZeroInit(loc);
- }
-
override structalign_t alignment()
{
return next.alignment();
}
- override MATCH constConv(Type to)
- {
- if (auto tsa = to.isTypeSArray())
- {
- if (!dim.equals(tsa.dim))
- return MATCH.nomatch;
- }
- return TypeNext.constConv(to);
- }
-
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
- if (auto ta = to.isTypeDArray())
- {
- if (!MODimplicitConv(next.mod, ta.next.mod))
- return MATCH.nomatch;
-
- /* Allow conversion to void[]
- */
- if (ta.next.ty == Tvoid)
- {
- return MATCH.convert;
- }
-
- MATCH m = next.constConv(ta.next);
- if (m > MATCH.nomatch)
- {
- return MATCH.convert;
- }
- return MATCH.nomatch;
- }
- if (auto tsa = to.isTypeSArray())
- {
- if (this == to)
- return MATCH.exact;
-
- if (dim.equals(tsa.dim))
- {
- MATCH m = next.implicitConvTo(tsa.next);
-
- /* Allow conversion to non-interface base class.
- */
- if (m == MATCH.convert &&
- next.ty == Tclass)
- {
- if (auto toc = tsa.next.isTypeClass)
- {
- if (!toc.sym.isInterfaceDeclaration)
- return MATCH.convert;
- }
- }
-
- /* Since static arrays are value types, allow
- * conversions from const elements to non-const
- * ones, just like we allow conversion from const int
- * to int.
- */
- if (m >= MATCH.constant)
- {
- if (mod != to.mod)
- m = MATCH.constant;
- return m;
- }
- }
- }
- return MATCH.nomatch;
- }
-
- override Expression defaultInitLiteral(const ref Loc loc)
+ override Expression defaultInitLiteral(Loc loc)
{
static if (LOGDEFAULTINIT)
{
@@ -2657,9 +2238,9 @@ extern (C++) final class TypeSArray : TypeArray
return ae;
}
- override bool hasSystemFields()
+ override bool hasUnsafeBitpatterns()
{
- return next.hasSystemFields();
+ return next.hasUnsafeBitpatterns();
}
override bool hasVoidInitPointers()
@@ -2723,12 +2304,6 @@ extern (C++) final class TypeDArray : TypeArray
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- //printf("TypeDArray::size()\n");
- return target.ptrsize * 2;
- }
-
override uint alignsize()
{
// A DArray consists of two ptr-sized values, so align it on pointer size
@@ -2742,45 +2317,11 @@ extern (C++) final class TypeDArray : TypeArray
return nty.isSomeChar;
}
- override bool isZeroInit(const ref Loc loc)
- {
- return true;
- }
-
override bool isBoolean()
{
return true;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
- if (equals(to))
- return MATCH.exact;
-
- if (auto ta = to.isTypeDArray())
- {
- if (!MODimplicitConv(next.mod, ta.next.mod))
- return MATCH.nomatch; // not const-compatible
-
- /* Allow conversion to void[]
- */
- if (next.ty != Tvoid && ta.next.ty == Tvoid)
- {
- return MATCH.convert;
- }
-
- MATCH m = next.constConv(ta.next);
- if (m > MATCH.nomatch)
- {
- if (m == MATCH.exact && mod != to.mod)
- m = MATCH.constant;
- return m;
- }
- }
- return Type.implicitConvTo(to);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2822,57 +2363,11 @@ extern (C++) final class TypeAArray : TypeArray
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
- override bool isZeroInit(const ref Loc loc)
- {
- return true;
- }
-
override bool isBoolean()
{
return true;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
- if (equals(to))
- return MATCH.exact;
-
- if (auto ta = to.isTypeAArray())
- {
- if (!MODimplicitConv(next.mod, ta.next.mod))
- return MATCH.nomatch; // not const-compatible
-
- if (!MODimplicitConv(index.mod, ta.index.mod))
- return MATCH.nomatch; // not const-compatible
-
- MATCH m = next.constConv(ta.next);
- MATCH mi = index.constConv(ta.index);
- if (m > MATCH.nomatch && mi > MATCH.nomatch)
- {
- return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch;
- }
- }
- return Type.implicitConvTo(to);
- }
-
- override MATCH constConv(Type to)
- {
- if (auto taa = to.isTypeAArray())
- {
- MATCH mindex = index.constConv(taa.index);
- MATCH mkey = next.constConv(taa.next);
- // Pick the worst match
- return mkey < mindex ? mkey : mindex;
- }
- return Type.constConv(to);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2909,68 +2404,7 @@ extern (C++) final class TypePointer : TypeNext
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars());
- if (equals(to))
- return MATCH.exact;
-
- // Only convert between pointers
- auto tp = to.isTypePointer();
- if (!tp)
- return MATCH.nomatch;
-
- assert(this.next);
- assert(tp.next);
-
- // Conversion to void*
- if (tp.next.ty == Tvoid)
- {
- // Function pointer conversion doesn't check constness?
- if (this.next.ty == Tfunction)
- return MATCH.convert;
-
- if (!MODimplicitConv(next.mod, tp.next.mod))
- return MATCH.nomatch; // not const-compatible
-
- return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
- }
-
- // Conversion between function pointers
- if (auto thisTf = this.next.isTypeFunction())
- return thisTf.implicitPointerConv(tp.next);
-
- // Default, no implicit conversion between the pointer targets
- MATCH m = next.constConv(tp.next);
-
- if (m == MATCH.exact && mod != to.mod)
- m = MATCH.constant;
- return m;
- }
-
- override MATCH constConv(Type to)
- {
- if (next.ty == Tfunction)
- {
- if (to.nextOf() && next.equals((cast(TypeNext)to).next))
- return Type.constConv(to);
- else
- return MATCH.nomatch;
- }
- return TypeNext.constConv(to);
- }
-
- override bool isscalar()
- {
- return true;
- }
-
- override bool isZeroInit(const ref Loc loc)
+ override bool isScalar()
{
return true;
}
@@ -3007,16 +2441,6 @@ extern (C++) final class TypeReference : TypeNext
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
- override bool isZeroInit(const ref Loc loc)
- {
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3050,20 +2474,21 @@ extern (C++) final class TypeFunction : TypeNext
// getters and setters are generated for them
private extern (D) static struct BitFields
{
- bool isnothrow; /// nothrow
- bool isnogc; /// is @nogc
- bool isproperty; /// can be called without parentheses
- bool isref; /// returns a reference
- bool isreturn; /// 'this' is returned by ref
+ bool isNothrow; /// nothrow
+ bool isNogc; /// is @nogc
+ bool isProperty; /// can be called without parentheses
+ bool isRef; /// returns a reference
+ bool isReturn; /// 'this' is returned by ref
bool isScopeQual; /// 'this' is scope
- bool isreturninferred; /// 'this' is return from inference
- bool isscopeinferred; /// 'this' is scope from inference
- bool islive; /// is @live
+ bool isReturnInferred; /// 'this' is return from inference
+ bool isScopeInferred; /// 'this' is scope from inference
+ bool isLive; /// is @live
bool incomplete; /// return type or default arguments removed
bool isInOutParam; /// inout on the parameters
bool isInOutQual; /// inout on the qualifier
- bool isctor; /// the function is a constructor
- bool isreturnscope; /// `this` is returned by value
+ bool isCtor; /// the function is a constructor
+ bool isReturnScope; /// `this` is returned by value
+ bool isRvalue; /// returned reference should be treated as rvalue
}
import dmd.common.bitfields : generateBitFields;
@@ -3075,7 +2500,7 @@ extern (C++) final class TypeFunction : TypeNext
byte inuse;
ArgumentList inferenceArguments; // function arguments to determine `auto ref` in type semantic
- extern (D) this(ParameterList pl, Type treturn, LINK linkage, StorageClass stc = 0) @safe
+ extern (D) this(ParameterList pl, Type treturn, LINK linkage, STC stc = STC.none) @safe
{
super(Tfunction, treturn);
//if (!treturn) *(char*)0=0;
@@ -3087,26 +2512,28 @@ extern (C++) final class TypeFunction : TypeNext
if (stc & STC.pure_)
this.purity = PURE.fwdref;
if (stc & STC.nothrow_)
- this.isnothrow = true;
+ this.isNothrow = true;
if (stc & STC.nogc)
- this.isnogc = true;
+ this.isNogc = true;
if (stc & STC.property)
- this.isproperty = true;
+ this.isProperty = true;
if (stc & STC.live)
- this.islive = true;
+ this.isLive = true;
if (stc & STC.ref_)
- this.isref = true;
+ this.isRef = true;
if (stc & STC.return_)
- this.isreturn = true;
+ this.isReturn = true;
if (stc & STC.returnScope)
- this.isreturnscope = true;
+ this.isReturnScope = true;
if (stc & STC.returninferred)
- this.isreturninferred = true;
+ this.isReturnInferred = true;
if (stc & STC.scope_)
this.isScopeQual = true;
if (stc & STC.scopeinferred)
- this.isscopeinferred = true;
+ this.isScopeInferred = true;
+ if (stc & STC.rvalue)
+ this.isRvalue = true;
this.trust = TRUST.default_;
if (stc & STC.safe)
@@ -3117,9 +2544,9 @@ extern (C++) final class TypeFunction : TypeNext
this.trust = TRUST.trusted;
}
- static TypeFunction create(Parameters* parameters, Type treturn, ubyte varargs, LINK linkage, StorageClass stc = 0) @safe
+ static TypeFunction create(Parameters* parameters, Type treturn, ubyte varargs, LINK linkage, StorageClass stc = STC.none) @safe
{
- return new TypeFunction(ParameterList(parameters, cast(VarArg)varargs), treturn, linkage, stc);
+ return new TypeFunction(ParameterList(parameters, cast(VarArg)varargs), treturn, linkage, cast(STC) stc);
}
override const(char)* kind() const
@@ -3132,22 +2559,23 @@ extern (C++) final class TypeFunction : TypeNext
Type treturn = next ? next.syntaxCopy() : null;
auto t = new TypeFunction(parameterList.syntaxCopy(), treturn, linkage);
t.mod = mod;
- t.isnothrow = isnothrow;
- t.isnogc = isnogc;
- t.islive = islive;
+ t.isNothrow = isNothrow;
+ t.isNogc = isNogc;
+ t.isLive = isLive;
t.purity = purity;
- t.isproperty = isproperty;
- t.isref = isref;
- t.isreturn = isreturn;
- t.isreturnscope = isreturnscope;
+ t.isProperty = isProperty;
+ t.isRef = isRef;
+ t.isReturn = isReturn;
+ t.isReturnScope = isReturnScope;
t.isScopeQual = isScopeQual;
- t.isreturninferred = isreturninferred;
- t.isscopeinferred = isscopeinferred;
+ t.isReturnInferred = isReturnInferred;
+ t.isScopeInferred = isScopeInferred;
+ t.isRvalue = isRvalue;
t.isInOutParam = isInOutParam;
t.isInOutQual = isInOutQual;
t.trust = trust;
t.inferenceArguments = inferenceArguments;
- t.isctor = isctor;
+ t.isCtor = isCtor;
return t;
}
@@ -3170,18 +2598,25 @@ extern (C++) final class TypeFunction : TypeNext
* Returns:
* true if D-style variadic
*/
- bool isDstyleVariadic() const pure nothrow
+ bool isDstyleVariadic() const pure nothrow @safe
{
return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
}
- extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args)
+ /*********************************
+ * Append error message to buf.
+ * Input:
+ * buf = message sink
+ * format = printf format
+ */
+ extern(C) static void getMatchError(ref OutBuffer buf, const(char)* format, ...)
{
if (global.gag && !global.params.v.showGaggedErrors)
- return null;
- OutBuffer buf;
- buf.printf(format, args);
- return buf.extractChars();
+ return;
+ va_list ap;
+ va_start(ap, format);
+ buf.vprintf(format, ap);
+ va_end(ap);
}
/********************************
@@ -3190,10 +2625,10 @@ extern (C++) final class TypeFunction : TypeNext
*
* Params:
* argumentList = array of function arguments
- * pMessage = address to store error message, or `null`
+ * buf = if not null, append error message to it
* Returns: re-ordered argument list, or `null` on error
*/
- extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, const(char)** pMessage)
+ extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, OutBuffer* buf)
{
Expression[] args = argumentList.arguments ? (*argumentList.arguments)[] : null;
Identifier[] names = argumentList.names ? (*argumentList.names)[] : null;
@@ -3217,8 +2652,8 @@ extern (C++) final class TypeFunction : TypeNext
const pi = findParameterIndex(name);
if (pi == -1)
{
- if (pMessage)
- *pMessage = getMatchError("no parameter named `%s`", name.toChars());
+ if (buf)
+ getMatchError(*buf, "no parameter named `%s`", name.toChars());
return null;
}
ci = pi;
@@ -3228,8 +2663,8 @@ extern (C++) final class TypeFunction : TypeNext
if (!isVariadic)
{
// Without named args, let the caller diagnose argument overflow
- if (hasNamedArgs && pMessage)
- *pMessage = getMatchError("argument `%s` goes past end of parameter list", arg.toChars());
+ if (hasNamedArgs && buf)
+ getMatchError(*buf, "argument `%s` goes past end of parameter list", arg.toChars());
return null;
}
while (ci >= newArgs.length)
@@ -3238,8 +2673,8 @@ extern (C++) final class TypeFunction : TypeNext
if ((*newArgs)[ci])
{
- if (pMessage)
- *pMessage = getMatchError("parameter `%s` assigned twice", parameterList[ci].toChars());
+ if (buf)
+ getMatchError(*buf, "parameter `%s` assigned twice", parameterList[ci].toChars());
return null;
}
(*newArgs)[ci++] = arg;
@@ -3257,8 +2692,8 @@ extern (C++) final class TypeFunction : TypeNext
if (this.incomplete)
continue;
- if (pMessage)
- *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
+ if (buf)
+ getMatchError(*buf, "missing argument for parameter #%d: `%s`",
i + 1, parameterToChars(parameterList[i], this, false));
return null;
}
@@ -3272,87 +2707,6 @@ extern (C++) final class TypeFunction : TypeNext
return newArgs;
}
- /+
- + Checks whether this function type is convertible to ` to`
- + when used in a function pointer / delegate.
- +
- + Params:
- + to = target type
- +
- + Returns:
- + MATCH.nomatch: `to` is not a covaraint function
- + MATCH.convert: `to` is a covaraint function
- + MATCH.exact: `to` is identical to this function
- +/
- private MATCH implicitPointerConv(Type to)
- {
- assert(to);
-
- if (this.equals(to))
- return MATCH.constant;
-
- if (this.covariant(to) == Covariant.yes)
- {
- Type tret = this.nextOf();
- Type toret = to.nextOf();
- if (tret.ty == Tclass && toret.ty == Tclass)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=10219
- * Check covariant interface return with offset tweaking.
- * interface I {}
- * class C : Object, I {}
- * I function() dg = function C() {} // should be error
- */
- int offset = 0;
- if (toret.isBaseOf(tret, &offset) && offset != 0)
- return MATCH.nomatch;
- }
- return MATCH.convert;
- }
-
- return MATCH.nomatch;
- }
-
- /** Extends TypeNext.constConv by also checking for matching attributes **/
- override MATCH constConv(Type to)
- {
- // Attributes need to match exactly, otherwise it's an implicit conversion
- if (this.ty != to.ty || !this.attributesEqual(cast(TypeFunction) to))
- return MATCH.nomatch;
-
- return super.constConv(to);
- }
-
- extern (D) bool checkRetType(const ref Loc loc)
- {
- Type tb = next.toBasetype();
- if (tb.ty == Tfunction)
- {
- error(loc, "functions cannot return a function");
- next = Type.terror;
- }
- if (tb.ty == Ttuple)
- {
- error(loc, "functions cannot return a sequence (use `std.typecons.Tuple`)");
- next = Type.terror;
- }
- if (!isref && (tb.ty == Tstruct || tb.ty == Tsarray))
- {
- if (auto ts = tb.baseElemOf().isTypeStruct())
- {
- if (!ts.sym.members)
- {
- error(loc, "functions cannot return opaque type `%s` by value", tb.toChars());
- next = Type.terror;
- }
- }
- }
- if (tb.ty == Terror)
- return true;
- return false;
- }
-
-
/// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
bool iswild() const pure nothrow @safe @nogc
{
@@ -3373,9 +2727,9 @@ extern (C++) final class TypeFunction : TypeNext
return (this.trust == other.trust ||
(trustSystemEqualsDefault && this.trust <= TRUST.system && other.trust <= TRUST.system)) &&
this.purity == other.purity &&
- this.isnothrow == other.isnothrow &&
- this.isnogc == other.isnogc &&
- this.islive == other.islive;
+ this.isNothrow == other.isNothrow &&
+ this.isNogc == other.isNogc &&
+ this.isLive == other.isLive;
}
override void accept(Visitor v)
@@ -3434,44 +2788,11 @@ extern (C++) final class TypeDelegate : TypeNext
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize * 2;
- }
-
override uint alignsize()
{
return target.ptrsize;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- if (this.equals(to))
- return MATCH.exact;
-
- if (auto toDg = to.isTypeDelegate())
- {
- MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next);
-
- // Retain the old behaviour for this refactoring
- // Should probably be changed to constant to match function pointers
- if (m > MATCH.convert)
- m = MATCH.convert;
-
- return m;
- }
-
- return MATCH.nomatch;
- }
-
- override bool isZeroInit(const ref Loc loc)
- {
- return true;
- }
-
override bool isBoolean()
{
return true;
@@ -3487,7 +2808,7 @@ extern (C++) final class TypeDelegate : TypeNext
* This is a shell containing a TraitsExp that can be
* either resolved to a type or to a symbol.
*
- * The point is to allow AliasDeclarationY to use `__traits()`, see https://issues.dlang.org/show_bug.cgi?id=7804.
+ * The point is to allow AliasDeclarationY to use `__traits()`, see $(LINK https://issues.dlang.org/show_bug.cgi?id=7804).
*/
extern (C++) final class TypeTraits : Type
{
@@ -3497,7 +2818,7 @@ extern (C++) final class TypeTraits : Type
/// Cached type/symbol after semantic analysis.
RootObject obj;
- final extern (D) this(const ref Loc loc, TraitsExp exp) @safe
+ final extern (D) this(Loc loc, TraitsExp exp) @safe
{
super(Ttraits);
this.loc = loc;
@@ -3521,11 +2842,6 @@ extern (C++) final class TypeTraits : Type
{
v.visit(this);
}
-
- override uinteger_t size(const ref Loc loc)
- {
- return SIZE_INVALID;
- }
}
/******
@@ -3539,7 +2855,7 @@ extern (C++) final class TypeMixin : Type
Expressions* exps;
RootObject obj; // cached result of semantic analysis.
- extern (D) this(const ref Loc loc, Expressions* exps) @safe
+ extern (D) this(Loc loc, Expressions* exps) @safe
{
super(Tmixin);
this.loc = loc;
@@ -3635,12 +2951,6 @@ extern (C++) abstract class TypeQualified : Type
idents.push(e);
}
- override uinteger_t size(const ref Loc loc)
- {
- error(this.loc, "size of type `%s` is not known", toChars());
- return SIZE_INVALID;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3653,16 +2963,13 @@ extern (C++) final class TypeIdentifier : TypeQualified
{
Identifier ident;
- // The symbol representing this identifier, before alias resolution
- Dsymbol originalSymbol;
-
- extern (D) this(const ref Loc loc, Identifier ident)
+ extern (D) this(Loc loc, Identifier ident)
{
super(Tident, loc);
this.ident = ident;
}
- static TypeIdentifier create(const ref Loc loc, Identifier ident)
+ static TypeIdentifier create(Loc loc, Identifier ident)
{
return new TypeIdentifier(loc, ident);
}
@@ -3693,7 +3000,7 @@ extern (C++) final class TypeInstance : TypeQualified
{
TemplateInstance tempinst;
- extern (D) this(const ref Loc loc, TemplateInstance tempinst)
+ extern (D) this(Loc loc, TemplateInstance tempinst)
{
super(Tinstance, loc);
this.tempinst = tempinst;
@@ -3726,7 +3033,7 @@ extern (C++) final class TypeTypeof : TypeQualified
Expression exp;
int inuse;
- extern (D) this(const ref Loc loc, Expression exp)
+ extern (D) this(Loc loc, Expression exp)
{
super(Ttypeof, loc);
this.exp = exp;
@@ -3746,14 +3053,6 @@ extern (C++) final class TypeTypeof : TypeQualified
return t;
}
- override uinteger_t size(const ref Loc loc)
- {
- if (exp.type)
- return exp.type.size(loc);
- else
- return TypeQualified.size(loc);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3764,7 +3063,7 @@ extern (C++) final class TypeTypeof : TypeQualified
*/
extern (C++) final class TypeReturn : TypeQualified
{
- extern (D) this(const ref Loc loc)
+ extern (D) this(Loc loc)
{
super(Treturn, loc);
}
@@ -3812,11 +3111,6 @@ extern (C++) final class TypeStruct : Type
return "struct";
}
- override uinteger_t size(const ref Loc loc)
- {
- return sym.size(loc);
- }
-
override uint alignsize()
{
sym.size(Loc.initial); // give error for forward references
@@ -3839,7 +3133,7 @@ extern (C++) final class TypeStruct : Type
* Use when we prefer the default initializer to be a literal,
* rather than a global immutable variable.
*/
- override Expression defaultInitLiteral(const ref Loc loc)
+ override Expression defaultInitLiteral(Loc loc)
{
static if (LOGDEFAULTINIT)
{
@@ -3882,20 +3176,13 @@ extern (C++) final class TypeStruct : Type
/* Copy from the initializer symbol for larger symbols,
* otherwise the literals expressed as code get excessively large.
*/
- if (size(loc) > target.ptrsize * 4 && !needsNested())
+ if (size(this, loc) > target.ptrsize * 4 && !needsNested())
structinit.useStaticInit = true;
structinit.type = this;
return structinit;
}
- override bool isZeroInit(const ref Loc loc)
- {
- // Determine zeroInit here, as this can be called before semantic2
- sym.determineSize(sym.loc);
- return sym.zeroInit;
- }
-
override bool isAssignable()
{
bool assignable = true;
@@ -3976,11 +3263,11 @@ extern (C++) final class TypeStruct : Type
return sym.hasVoidInitPointers;
}
- override bool hasSystemFields()
+ override bool hasUnsafeBitpatterns()
{
sym.size(Loc.initial); // give error for forward references
sym.determineTypeProperties();
- return sym.hasSystemFields;
+ return sym.hasUnsafeBitpatterns;
}
override bool hasInvariant()
@@ -3990,97 +3277,6 @@ extern (C++) final class TypeStruct : Type
return sym.hasInvariant() || sym.hasFieldWithInvariant;
}
- extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
- {
- MATCH m;
-
- if (ty == to.ty && sym == (cast(TypeStruct)to).sym)
- {
- m = MATCH.exact; // exact match
- if (mod != to.mod)
- {
- m = MATCH.constant;
- if (MODimplicitConv(mod, to.mod))
- {
- }
- else
- {
- /* Check all the fields. If they can all be converted,
- * allow the conversion.
- */
- uint offset = ~0; // dead-store to prevent spurious warning
- for (size_t i = 0; i < sym.fields.length; i++)
- {
- VarDeclaration v = sym.fields[i];
- if (i == 0)
- {
- }
- else if (v.offset == offset)
- {
- if (m > MATCH.nomatch)
- continue;
- }
- else
- {
- if (m == MATCH.nomatch)
- return m;
- }
-
- // 'from' type
- Type tvf = v.type.addMod(mod);
-
- // 'to' type
- Type tv = v.type.addMod(to.mod);
-
- // field match
- MATCH mf = tvf.implicitConvTo(tv);
- //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), mf);
-
- if (mf == MATCH.nomatch)
- return mf;
- if (mf < m) // if field match is worse
- m = mf;
- offset = v.offset;
- }
- }
- }
- }
- return m;
- }
-
- extern (D) MATCH implicitConvToThroughAliasThis(Type to)
- {
- MATCH m;
- if (!(ty == to.ty && sym == (cast(TypeStruct)to).sym) && sym.aliasthis && !(att & AliasThisRec.tracing))
- {
- if (auto ato = aliasthisOf(this))
- {
- att = cast(AliasThisRec)(att | AliasThisRec.tracing);
- m = ato.implicitConvTo(to);
- att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
- }
- else
- m = MATCH.nomatch; // no match
- }
- return m;
- }
-
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars());
- MATCH m = implicitConvToWithoutAliasThis(to);
- return m ? m : implicitConvToThroughAliasThis(to);
- }
-
- override MATCH constConv(Type to)
- {
- if (equals(to))
- return MATCH.exact;
- if (ty == to.ty && sym == (cast(TypeStruct)to).sym && MODimplicitConv(mod, to.mod))
- return MATCH.constant;
- return MATCH.nomatch;
- }
-
override MOD deduceWild(Type t, bool isRef)
{
if (ty == t.ty && sym == (cast(TypeStruct)t).sym)
@@ -4129,11 +3325,6 @@ extern (C++) final class TypeEnum : Type
return this;
}
- override uinteger_t size(const ref Loc loc)
- {
- return sym.getMemtype(loc).size(loc);
- }
-
Type memType()
{
return sym.getMemtype(Loc.initial);
@@ -4147,39 +3338,39 @@ extern (C++) final class TypeEnum : Type
return t.alignsize();
}
- override bool isintegral()
+ override bool isIntegral()
{
- return memType().isintegral();
+ return memType().isIntegral();
}
- override bool isfloating()
+ override bool isFloating()
{
- return memType().isfloating();
+ return memType().isFloating();
}
- override bool isreal()
+ override bool isReal()
{
- return memType().isreal();
+ return memType().isReal();
}
- override bool isimaginary()
+ override bool isImaginary()
{
- return memType().isimaginary();
+ return memType().isImaginary();
}
- override bool iscomplex()
+ override bool isComplex()
{
- return memType().iscomplex();
+ return memType().isComplex();
}
- override bool isscalar()
+ override bool isScalar()
{
- return memType().isscalar();
+ return memType().isScalar();
}
- override bool isunsigned()
+ override bool isUnsigned()
{
- return memType().isunsigned();
+ return memType().isUnsigned();
}
override bool isBoolean()
@@ -4212,28 +3403,6 @@ extern (C++) final class TypeEnum : Type
return memType().needsNested();
}
- override MATCH implicitConvTo(Type to)
- {
- MATCH m;
- //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars());
- if (ty == to.ty && sym == (cast(TypeEnum)to).sym)
- m = (mod == to.mod) ? MATCH.exact : MATCH.constant;
- else if (sym.getMemtype(Loc.initial).implicitConvTo(to))
- m = MATCH.convert; // match with conversions
- else
- m = MATCH.nomatch; // no match
- return m;
- }
-
- override MATCH constConv(Type to)
- {
- if (equals(to))
- return MATCH.exact;
- if (ty == to.ty && sym == (cast(TypeEnum)to).sym && MODimplicitConv(mod, to.mod))
- return MATCH.constant;
- return MATCH.nomatch;
- }
-
extern (D) Type toBasetype2()
{
if (!sym.members && !sym.memtype)
@@ -4242,19 +3411,14 @@ extern (C++) final class TypeEnum : Type
return tb.castMod(mod); // retain modifier bits from 'this'
}
- override bool isZeroInit(const ref Loc loc)
- {
- return sym.getDefaultValue(loc).toBool().hasValue(false);
- }
-
override bool hasVoidInitPointers()
{
return memType().hasVoidInitPointers();
}
- override bool hasSystemFields()
+ override bool hasUnsafeBitpatterns()
{
- return memType().hasSystemFields();
+ return memType().hasUnsafeBitpatterns();
}
override bool hasInvariant()
@@ -4292,11 +3456,6 @@ extern (C++) final class TypeClass : Type
return "class";
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
override TypeClass syntaxCopy()
{
return this;
@@ -4307,65 +3466,6 @@ extern (C++) final class TypeClass : Type
return sym;
}
- extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
- {
- ClassDeclaration cdto = to.isClassHandle();
- MATCH m = constConv(to);
- if (m > MATCH.nomatch)
- return m;
-
- if (cdto && cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod))
- {
- //printf("'to' is base\n");
- return MATCH.convert;
- }
- return MATCH.nomatch;
- }
-
- extern (D) MATCH implicitConvToThroughAliasThis(Type to)
- {
- MATCH m;
- if (sym.aliasthis && !(att & AliasThisRec.tracing))
- {
- if (auto ato = aliasthisOf(this))
- {
- att = cast(AliasThisRec)(att | AliasThisRec.tracing);
- m = ato.implicitConvTo(to);
- att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
- }
- }
- return m;
- }
-
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars());
- MATCH m = implicitConvToWithoutAliasThis(to);
- return m ? m : implicitConvToThroughAliasThis(to);
- }
-
- override MATCH constConv(Type to)
- {
- if (equals(to))
- return MATCH.exact;
- if (ty == to.ty && sym == (cast(TypeClass)to).sym && MODimplicitConv(mod, to.mod))
- return MATCH.constant;
-
- /* Conversion derived to const(base)
- */
- int offset = 0;
- if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod))
- {
- // Disallow:
- // derived to base
- // inout(derived) to inout(base)
- if (!to.isMutable() && !to.isWild())
- return MATCH.convert;
- }
-
- return MATCH.nomatch;
- }
-
override MOD deduceWild(Type t, bool isRef)
{
ClassDeclaration cd = t.isClassHandle();
@@ -4387,12 +3487,7 @@ extern (C++) final class TypeClass : Type
return wm;
}
- override bool isZeroInit(const ref Loc loc)
- {
- return true;
- }
-
- override bool isscope()
+ override bool isScopeClass()
{
return sym.stack;
}
@@ -4413,7 +3508,10 @@ extern (C++) final class TypeClass : Type
extern (C++) final class TypeTuple : Type
{
// 'logically immutable' cached global - don't modify!
- __gshared TypeTuple empty = new TypeTuple();
+ static if (__VERSION__ == 2081)
+ __gshared TypeTuple empty; // See comment in Type._init
+ else
+ __gshared TypeTuple empty = new TypeTuple();
Parameters* arguments; // types making up the tuple
@@ -4443,17 +3541,19 @@ extern (C++) final class TypeTuple : Type
extern (D) this(Expressions* exps)
{
super(Ttuple);
- auto arguments = new Parameters(exps ? exps.length : 0);
- if (exps)
+ if (!exps)
{
- for (size_t i = 0; i < exps.length; i++)
- {
- Expression e = (*exps)[i];
- if (e.type.ty == Ttuple)
- error(e.loc, "cannot form sequence of sequences");
- auto arg = new Parameter(e.loc, STC.undefined_, e.type, null, null, null);
- (*arguments)[i] = arg;
- }
+ this.arguments = new Parameters(0);
+ return;
+ }
+ auto arguments = new Parameters(exps.length);
+
+ for (size_t i = 0; i < exps.length; i++)
+ {
+ Expression e = (*exps)[i];
+ assert(e.type.ty != Ttuple);
+ auto arg = new Parameter(e.loc, STC.none, e.type, null, null, null);
+ (*arguments)[i] = arg;
}
this.arguments = arguments;
//printf("TypeTuple() %p, %s\n", this, toChars());
@@ -4477,15 +3577,15 @@ extern (C++) final class TypeTuple : Type
{
super(Ttuple);
arguments = new Parameters();
- arguments.push(new Parameter(Loc.initial, 0, t1, null, null, null));
+ arguments.push(new Parameter(Loc.initial, STC.none, t1, null, null, null));
}
extern (D) this(Type t1, Type t2)
{
super(Ttuple);
arguments = new Parameters();
- arguments.push(new Parameter(Loc.initial, 0, t1, null, null, null));
- arguments.push(new Parameter(Loc.initial, 0, t2, null, null, null));
+ arguments.push(new Parameter(Loc.initial, STC.none, t1, null, null, null));
+ arguments.push(new Parameter(Loc.initial, STC.none, t2, null, null, null));
}
static TypeTuple create() @safe
@@ -4539,29 +3639,6 @@ extern (C++) final class TypeTuple : Type
return false;
}
- override MATCH implicitConvTo(Type to)
- {
- if (this == to)
- return MATCH.exact;
- if (auto tt = to.isTypeTuple())
- {
- if (arguments.length == tt.arguments.length)
- {
- MATCH m = MATCH.exact;
- for (size_t i = 0; i < tt.arguments.length; i++)
- {
- Parameter arg1 = (*arguments)[i];
- Parameter arg2 = (*tt.arguments)[i];
- MATCH mi = arg1.type.implicitConvTo(arg2.type);
- if (mi < m)
- m = mi;
- }
- return m;
- }
- }
- return MATCH.nomatch;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4623,36 +3700,11 @@ extern (C++) final class TypeNull : Type
return this;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- MATCH m = Type.implicitConvTo(to);
- if (m != MATCH.nomatch)
- return m;
-
- // NULL implicitly converts to any pointer type or dynamic array
- //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
- {
- Type tb = to.toBasetype();
- if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate)
- return MATCH.constant;
- }
-
- return MATCH.nomatch;
- }
-
override bool isBoolean()
{
return true;
}
- override uinteger_t size(const ref Loc loc)
- {
- return tvoidptr.size(loc);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4680,38 +3732,11 @@ extern (C++) final class TypeNoreturn : Type
return this;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- if (this.equals(to))
- return MATCH.exact;
-
- // Different qualifiers?
- if (to.ty == Tnoreturn)
- return MATCH.constant;
-
- // Implicitly convertible to any type
- return MATCH.convert;
- }
-
- override MATCH constConv(Type to)
- {
- // Either another noreturn or conversion to any type
- return this.implicitConvTo(to);
- }
-
override bool isBoolean()
{
return true; // bottom type can be implicitly converted to any other type
}
- override uinteger_t size(const ref Loc loc)
- {
- return 0;
- }
-
override uint alignsize()
{
return 0;
@@ -4745,7 +3770,7 @@ extern (C++) final class TypeTag : Type
/// struct S { int a; } s1, *s2;
MOD mod; /// modifiers to apply after type is resolved (only MODFlags.const_ at the moment)
- extern (D) this(const ref Loc loc, TOK tok, Identifier id, structalign_t packalign, Type base, Dsymbols* members) @safe
+ extern (D) this(Loc loc, TOK tok, Identifier id, structalign_t packalign, Type base, Dsymbols* members) @safe
{
//printf("TypeTag ctor %s %p\n", id ? id.toChars() : "null".ptr, this);
super(Ttag);
@@ -4785,11 +3810,11 @@ extern (C++) struct ParameterList
{
/// The raw (unexpanded) formal parameters, possibly containing tuples.
Parameters* parameters;
- StorageClass stc; // storage class of ...
+ STC stc; // storage class of ...
VarArg varargs = VarArg.none;
bool hasIdentifierList; // true if C identifier-list style
- this(Parameters* parameters, VarArg varargs = VarArg.none, StorageClass stc = 0) @safe
+ this(Parameters* parameters, VarArg varargs = VarArg.none, STC stc = STC.none) @safe
{
this.parameters = parameters;
this.varargs = varargs;
@@ -4846,7 +3871,8 @@ extern (C++) struct ParameterList
foreach (_, p1; cast() this)
{
auto p2 = other[idx++];
- if (!p2 || p1 != p2) {
+ if (!p2 || p1 != p2)
+ {
diff = true;
break;
}
@@ -4887,13 +3913,13 @@ extern (C++) final class Parameter : ASTNode
import dmd.attrib : UserAttributeDeclaration;
Loc loc;
- StorageClass storageClass;
+ STC storageClass;
Type type;
Identifier ident;
Expression defaultArg;
UserAttributeDeclaration userAttribDecl; // user defined attributes
- extern (D) this(const ref Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe
+ extern (D) this(Loc loc, STC storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe
{
this.loc = loc;
this.type = type;
@@ -4903,9 +3929,9 @@ extern (C++) final class Parameter : ASTNode
this.userAttribDecl = userAttribDecl;
}
- static Parameter create(const ref Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe
+ static Parameter create(Loc loc, StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl) @safe
{
- return new Parameter(loc, storageClass, type, ident, defaultArg, userAttribDecl);
+ return new Parameter(loc, cast(STC) storageClass, type, ident, defaultArg, userAttribDecl);
}
Parameter syntaxCopy()
@@ -4925,7 +3951,7 @@ extern (C++) final class Parameter : ASTNode
Type isLazyArray()
{
Type tb = type.toBasetype();
- if (tb.ty == Tsarray || tb.ty == Tarray)
+ if (tb.isStaticOrDynamicArray())
{
Type tel = (cast(TypeArray)tb).next.toBasetype();
if (auto td = tel.isTypeDelegate())
@@ -5035,7 +4061,7 @@ extern (C++) final class Parameter : ASTNode
/***************************************
* Expands tuples in args in depth first order. Calls
- * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter.
+ * dg(void* ctx, size_t argidx, Parameter* arg) for each Parameter.
* If dg returns !=0, stops and returns that value else returns 0.
* Use this function to avoid the O(N + N^2/2) complexity of
* calculating dim and calling N times getNth.
@@ -5117,21 +4143,21 @@ extern (C++) final class Parameter : ASTNode
bool isCovariant(bool returnByRef, const Parameter p)
const pure nothrow @nogc @safe
{
- ulong thisSTC = this.storageClass;
- ulong otherSTC = p.storageClass;
+ STC thisSTC = this.storageClass;
+ STC otherSTC = p.storageClass;
if (thisSTC & STC.constscoperef)
thisSTC |= STC.scope_;
if (otherSTC & STC.constscoperef)
otherSTC |= STC.scope_;
- const mask = STC.ref_ | STC.out_ | STC.lazy_ | (((thisSTC | otherSTC) & STC.constscoperef) ? STC.in_ : 0);
+ const mask = STC.ref_ | STC.out_ | STC.lazy_ | (((thisSTC | otherSTC) & STC.constscoperef) ? STC.in_ : STC.none);
if ((thisSTC & mask) != (otherSTC & mask))
return false;
return isCovariantScope(returnByRef, thisSTC, otherSTC);
}
- extern (D) static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
+ extern (D) static bool isCovariantScope(bool returnByRef, STC from, STC to) pure nothrow @nogc @safe
{
// Workaround for failing covariance when finding a common type of delegates,
// some of which have parameters with inferred scope
@@ -5260,19 +4286,19 @@ void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTforma
{
if (tf.purity)
dg("pure");
- if (tf.isnothrow)
+ if (tf.isNothrow)
dg("nothrow");
- if (tf.isnogc)
+ if (tf.isNogc)
dg("@nogc");
- if (tf.isproperty)
+ if (tf.isProperty)
dg("@property");
- if (tf.isref)
+ if (tf.isRef)
dg("ref");
- if (tf.isreturn && !tf.isreturninferred)
+ if (tf.isReturn && !tf.isReturnInferred)
dg("return");
- if (tf.isScopeQual && !tf.isscopeinferred)
+ if (tf.isScopeQual && !tf.isScopeInferred)
dg("scope");
- if (tf.islive)
+ if (tf.isLive)
dg("@live");
TRUST trustAttrib = tf.trust;
@@ -5294,10 +4320,10 @@ void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTforma
AggregateDeclaration isAggregate(Type t)
{
t = t.toBasetype();
- if (t.ty == Tclass)
- return (cast(TypeClass)t).sym;
- if (t.ty == Tstruct)
- return (cast(TypeStruct)t).sym;
+ if (auto tc = t.isTypeClass())
+ return tc.sym;
+ if (auto ts = t.isTypeStruct())
+ return ts.sym;
return null;
}
@@ -5312,27 +4338,27 @@ AggregateDeclaration isAggregate(Type t)
bool isIndexableNonAggregate(Type t)
{
t = t.toBasetype();
- return (t.ty == Tpointer || t.ty == Tsarray || t.ty == Tarray || t.ty == Taarray ||
+ return (t.ty == Tpointer || t.isStaticOrDynamicArray() || t.ty == Taarray ||
t.ty == Ttuple || t.ty == Tvector);
}
/***************************************
* Computes how a parameter may be returned.
- * Shrinking the representation is necessary because StorageClass is so wide
+ * Shrinking the representation is necessary because STC is so wide
* Params:
* stc = storage class of parameter
* Returns:
* value from enum ScopeRef
*/
-ScopeRef buildScopeRef(StorageClass stc) pure nothrow @nogc @safe
+ScopeRef buildScopeRef(STC stc) pure nothrow @nogc @safe
{
if (stc & STC.out_)
stc |= STC.ref_; // treat `out` and `ref` the same
ScopeRef result;
- final switch (stc & (STC.ref_ | STC.scope_ | STC.return_))
+ switch (stc & (STC.ref_ | STC.scope_ | STC.return_))
{
- case 0: result = ScopeRef.None; break;
+ case STC.none: result = ScopeRef.None; break;
/* can occur in case test/compilable/testsctreturn.d
* related to https://issues.dlang.org/show_bug.cgi?id=20149
@@ -5350,6 +4376,8 @@ ScopeRef buildScopeRef(StorageClass stc) pure nothrow @nogc @safe
result = stc & STC.returnScope ? ScopeRef.Ref_ReturnScope
: ScopeRef.ReturnRef_Scope;
break;
+ default:
+ assert(0);
}
return result;
}
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index ad64b12..4d1938f 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -42,7 +42,7 @@ typedef struct TYPE type;
namespace dmd
{
- Type *typeSemantic(Type *t, const Loc &loc, Scope *sc);
+ Type *typeSemantic(Type *t, Loc loc, Scope *sc);
Type *merge(Type *type);
}
@@ -146,9 +146,6 @@ public:
MOD mod; // modifiers MODxxxx
char *deco;
void* mcache;
- Type *pto; // merged pointer to this type
- Type *rto; // reference to this type
- Type *arrayof; // array of this type
TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type
type *ctype; // for back end
@@ -228,20 +225,18 @@ public:
char *toPrettyChars(bool QualifyTypes = false);
static void _init();
- uinteger_t size();
- virtual uinteger_t size(const Loc &loc);
virtual unsigned alignsize();
void modToBuffer(OutBuffer& buf) const;
char *modToChars() const;
- virtual bool isintegral();
- virtual bool isfloating(); // real, imaginary, or complex
- virtual bool isreal();
- virtual bool isimaginary();
- virtual bool iscomplex();
- virtual bool isscalar();
- virtual bool isunsigned();
- virtual bool isscope();
+ virtual bool isIntegral();
+ virtual bool isFloating(); // real, imaginary, or complex
+ virtual bool isReal();
+ virtual bool isImaginary();
+ virtual bool isComplex();
+ virtual bool isScalar();
+ virtual bool isUnsigned();
+ virtual bool isScopeClass();
virtual bool isString();
virtual bool isAssignable();
virtual bool isBoolean();
@@ -266,17 +261,14 @@ public:
virtual Type *makeSharedWildConst();
virtual Type *makeMutable();
Type *toBasetype();
- virtual MATCH implicitConvTo(Type *to);
- virtual MATCH constConv(Type *to);
virtual unsigned char deduceWild(Type *t, bool isRef);
virtual ClassDeclaration *isClassHandle();
virtual structalign_t alignment();
- virtual Expression *defaultInitLiteral(const Loc &loc);
- virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
+ virtual Expression *defaultInitLiteral(Loc loc);
virtual int hasWild() const;
virtual bool hasVoidInitPointers();
- virtual bool hasSystemFields();
+ virtual bool hasUnsafeBitpatterns();
virtual bool hasInvariant();
virtual Type *nextOf();
Type *baseElemOf();
@@ -323,8 +315,7 @@ public:
const char *kind() override;
TypeError *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
- Expression *defaultInitLiteral(const Loc &loc) override;
+ Expression *defaultInitLiteral(Loc loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -344,7 +335,6 @@ public:
Type *makeSharedWild() override final;
Type *makeSharedWildConst() override final;
Type *makeMutable() override final;
- MATCH constConv(Type *to) override;
unsigned char deduceWild(Type *t, bool isRef) override final;
void transitive();
void accept(Visitor *v) override { v->visit(this); }
@@ -358,17 +348,14 @@ public:
const char *kind() override;
TypeBasic *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
- bool isintegral() override;
- bool isfloating() override;
- bool isreal() override;
- bool isimaginary() override;
- bool iscomplex() override;
- bool isscalar() override;
- bool isunsigned() override;
- MATCH implicitConvTo(Type *to) override;
- bool isZeroInit(const Loc &loc) override;
+ bool isIntegral() override;
+ bool isFloating() override;
+ bool isReal() override;
+ bool isImaginary() override;
+ bool isComplex() override;
+ bool isScalar() override;
+ bool isUnsigned() override;
// For eliminating dynamic_cast
TypeBasic *isTypeBasic() override;
@@ -383,17 +370,14 @@ public:
static TypeVector *create(Type *basetype);
const char *kind() override;
TypeVector *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
- bool isintegral() override;
- bool isfloating() override;
- bool isscalar() override;
- bool isunsigned() override;
+ bool isIntegral() override;
+ bool isFloating() override;
+ bool isScalar() override;
+ bool isUnsigned() override;
bool isBoolean() override;
- MATCH implicitConvTo(Type *to) override;
- Expression *defaultInitLiteral(const Loc &loc) override;
+ Expression *defaultInitLiteral(Loc loc) override;
TypeBasic *elementType();
- bool isZeroInit(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -413,15 +397,11 @@ public:
const char *kind() override;
TypeSArray *syntaxCopy() override;
bool isIncomplete();
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
bool isString() override;
- bool isZeroInit(const Loc &loc) override;
structalign_t alignment() override;
- MATCH constConv(Type *to) override;
- MATCH implicitConvTo(Type *to) override;
- Expression *defaultInitLiteral(const Loc &loc) override;
- bool hasSystemFields() override;
+ Expression *defaultInitLiteral(Loc loc) override;
+ bool hasUnsafeBitpatterns() override;
bool hasVoidInitPointers() override;
bool hasInvariant() override;
bool needsDestruction() override;
@@ -437,12 +417,9 @@ class TypeDArray final : public TypeArray
public:
const char *kind() override;
TypeDArray *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
bool isString() override;
- bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
- MATCH implicitConvTo(Type *to) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -456,11 +433,7 @@ public:
static TypeAArray *create(Type *t, Type *index);
const char *kind() override;
TypeAArray *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
- bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
- MATCH implicitConvTo(Type *to) override;
- MATCH constConv(Type *to) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -471,11 +444,7 @@ public:
static TypePointer *create(Type *t);
const char *kind() override;
TypePointer *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
- MATCH implicitConvTo(Type *to) override;
- MATCH constConv(Type *to) override;
- bool isscalar() override;
- bool isZeroInit(const Loc &loc) override;
+ bool isScalar() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -485,8 +454,6 @@ class TypeReference final : public TypeNext
public:
const char *kind() override;
TypeReference *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
- bool isZeroInit(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -499,7 +466,7 @@ enum RET
enum class TRUST : unsigned char
{
default_ = 0,
- system = 1, // @system (same as TRUSTdefault)
+ system = 1, // @system (same as TRUST.default_ unless feature "safer" is enabled)
trusted = 2, // @trusted
safe = 3 // @safe
};
@@ -528,7 +495,7 @@ public:
Expression *defaultArg;
UserAttributeDeclaration *userAttribDecl; // user defined attributes
- static Parameter *create(const Loc &loc, StorageClass storageClass, Type *type, Identifier *ident,
+ static Parameter *create(Loc loc, StorageClass storageClass, Type *type, Identifier *ident,
Expression *defaultArg, UserAttributeDeclaration *userAttribDecl);
Parameter *syntaxCopy();
Type *isLazyArray();
@@ -574,28 +541,27 @@ public:
bool hasLazyParameters();
bool isDstyleVariadic() const;
- MATCH constConv(Type *to) override;
-
- bool isnothrow() const;
- void isnothrow(bool v);
- bool isnogc() const;
- void isnogc(bool v);
- bool isproperty() const;
- void isproperty(bool v);
- bool isref() const;
- void isref(bool v);
- bool isreturn() const;
- void isreturn(bool v);
- bool isreturnscope() const;
- void isreturnscope(bool v);
+
+ bool isNothrow() const;
+ void isNothrow(bool v);
+ bool isNogc() const;
+ void isNogc(bool v);
+ bool isProperty() const;
+ void isProperty(bool v);
+ bool isRef() const;
+ void isRef(bool v);
+ bool isReturn() const;
+ void isReturn(bool v);
+ bool isReturnScope() const;
+ void isReturnScope(bool v);
bool isScopeQual() const;
void isScopeQual(bool v);
- bool isreturninferred() const;
- void isreturninferred(bool v);
- bool isscopeinferred() const;
- void isscopeinferred(bool v);
- bool islive() const;
- void islive(bool v);
+ bool isReturnInferred() const;
+ void isReturnInferred(bool v);
+ bool isScopeInferred() const;
+ void isScopeInferred(bool v);
+ bool isLive() const;
+ void isLive(bool v);
bool incomplete() const;
void incomplete(bool v);
bool isInOutParam() const;
@@ -615,10 +581,7 @@ public:
static TypeDelegate *create(TypeFunction *t);
const char *kind() override;
TypeDelegate *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
- MATCH implicitConvTo(Type *to) override;
- bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -634,7 +597,6 @@ class TypeTraits final : public Type
const char *kind() override;
TypeTraits *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -657,7 +619,6 @@ public:
// representing ident.ident!tiargs.ident. ... etc.
Objects idents;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -666,9 +627,8 @@ class TypeIdentifier final : public TypeQualified
{
public:
Identifier *ident;
- Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution
- static TypeIdentifier *create(const Loc &loc, Identifier *ident);
+ static TypeIdentifier *create(Loc loc, Identifier *ident);
const char *kind() override;
TypeIdentifier *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -694,7 +654,6 @@ public:
const char *kind() override;
TypeTypeof *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -727,22 +686,18 @@ public:
static TypeStruct *create(StructDeclaration *sym);
const char *kind() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
TypeStruct *syntaxCopy() override;
structalign_t alignment() override;
- Expression *defaultInitLiteral(const Loc &loc) override;
- bool isZeroInit(const Loc &loc) override;
+ Expression *defaultInitLiteral(Loc loc) override;
bool isAssignable() override;
bool isBoolean() override;
bool needsDestruction() override;
bool needsCopyOrPostblit() override;
bool needsNested() override;
bool hasVoidInitPointers() override;
- bool hasSystemFields() override;
+ bool hasUnsafeBitpatterns() override;
bool hasInvariant() override;
- MATCH implicitConvTo(Type *to) override;
- MATCH constConv(Type *to) override;
unsigned char deduceWild(Type *t, bool isRef) override;
void accept(Visitor *v) override { v->visit(this); }
@@ -755,27 +710,23 @@ public:
const char *kind() override;
TypeEnum *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
- Type *memType(const Loc &loc);
- bool isintegral() override;
- bool isfloating() override;
- bool isreal() override;
- bool isimaginary() override;
- bool iscomplex() override;
- bool isscalar() override;
- bool isunsigned() override;
+ Type *memType(Loc loc);
+ bool isIntegral() override;
+ bool isFloating() override;
+ bool isReal() override;
+ bool isImaginary() override;
+ bool isComplex() override;
+ bool isScalar() override;
+ bool isUnsigned() override;
bool isBoolean() override;
bool isString() override;
bool isAssignable() override;
bool needsDestruction() override;
bool needsCopyOrPostblit() override;
bool needsNested() override;
- MATCH implicitConvTo(Type *to) override;
- MATCH constConv(Type *to) override;
- bool isZeroInit(const Loc &loc) override;
bool hasVoidInitPointers() override;
- bool hasSystemFields() override;
+ bool hasUnsafeBitpatterns() override;
bool hasInvariant() override;
Type *nextOf() override;
@@ -790,14 +741,10 @@ public:
CPPMANGLE cppmangle;
const char *kind() override;
- uinteger_t size(const Loc &loc) override;
TypeClass *syntaxCopy() override;
ClassDeclaration *isClassHandle() override;
- MATCH implicitConvTo(Type *to) override;
- MATCH constConv(Type *to) override;
unsigned char deduceWild(Type *t, bool isRef) override;
- bool isZeroInit(const Loc &loc) override;
- bool isscope() override;
+ bool isScopeClass() override;
bool isBoolean() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -838,10 +785,8 @@ public:
const char *kind() override;
TypeNull *syntaxCopy() override;
- MATCH implicitConvTo(Type *to) override;
bool isBoolean() override;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -850,10 +795,7 @@ class TypeNoreturn final : public Type
public:
const char *kind() override;
TypeNoreturn *syntaxCopy() override;
- MATCH implicitConvTo(Type* to) override;
- MATCH constConv(Type* to) override;
bool isBoolean() override;
- uinteger_t size(const Loc& loc) override;
unsigned alignsize() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -877,9 +819,10 @@ namespace dmd
// return the symbol to which type t resolves
Dsymbol *toDsymbol(Type *t, Scope *sc);
bool equivalent(Type *src, Type *t);
- Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);
+ Covariant covariant(Type *, Type *, StorageClass * = nullptr, bool = false);
bool isBaseOf(Type *tthis, Type *t, int *poffset);
- Type *trySemantic(Type *type, const Loc &loc, Scope *sc);
+ bool isZeroInit(Type *t, Loc loc = Loc());
+ Type *trySemantic(Type *type, Loc loc, Scope *sc);
Type *pointerTo(Type *type);
Type *referenceTo(Type *type);
Type *merge2(Type *type);
@@ -902,4 +845,8 @@ namespace dmd
Type *addMod(Type *type, MOD mod);
Type *addStorageClass(Type *type, StorageClass stc);
Type *substWildTo(Type *type, unsigned mod);
+ uinteger_t size(Type *type);
+ uinteger_t size(Type *type, Loc loc);
+ MATCH implicitConvTo(Type* from, Type* to);
+ MATCH constConv(Type* from, Type* to);
}
diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d
index c2fa5fb..fab9723 100644
--- a/gcc/d/dmd/mustuse.d
+++ b/gcc/d/dmd/mustuse.d
@@ -1,11 +1,11 @@
/**
* Compile-time checks associated with the @mustuse attribute.
*
- * Copyright: Copyright (C) 2022-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 2022-2025 by The D Language Foundation, All Rights Reserved
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d, _mustuse.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mustuse.d, _mustuse.d)
* Documentation: https://dlang.org/phobos/dmd_mustuse.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mustuse.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/mustuse.d
*/
module dmd.mustuse;
@@ -111,26 +111,13 @@ private bool isAssignmentOpId(Identifier id)
{
import dmd.id : Id;
- return id == Id.assign
- || id == Id.addass
- || id == Id.subass
- || id == Id.mulass
- || id == Id.divass
- || id == Id.modass
- || id == Id.andass
- || id == Id.orass
- || id == Id.xorass
- || id == Id.shlass
- || id == Id.shrass
- || id == Id.ushrass
- || id == Id.catass
- || id == Id.indexass
- || id == Id.slice
- || id == Id.sliceass
+ return id == Id.opAssign
+ || id == Id.opIndexAssign
+ || id == Id.opSlice
+ || id == Id.opSliceAssign
|| id == Id.opOpAssign
|| id == Id.opIndexOpAssign
- || id == Id.opSliceOpAssign
- || id == Id.powass;
+ || id == Id.opSliceOpAssign;
}
/**
@@ -202,7 +189,7 @@ private bool isIncrementOrDecrement(Expression e)
*/
private bool hasMustUseAttribute(Dsymbol sym, Scope* sc)
{
- import dmd.attrib : foreachUda;
+ import dmd.attribsem : foreachUda;
bool result = false;
diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d
index 9e45e45..f1494a4 100644
--- a/gcc/d/dmd/nogc.d
+++ b/gcc/d/dmd/nogc.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/function.html#nogc-functions, No-GC Functions)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d, _nogc.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/nogc.d, _nogc.d)
* Documentation: https://dlang.org/phobos/dmd_nogc.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nogc.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/nogc.d
*/
module dmd.nogc;
@@ -18,17 +18,24 @@ import core.stdc.stdio;
import dmd.aggregate;
import dmd.astenums;
import dmd.declaration;
+import dmd.common.outbuffer;
+import dmd.dmodule;
import dmd.dscope;
import dmd.dtemplate : isDsymbol;
+import dmd.dsymbol : PASS;
import dmd.errors;
import dmd.expression;
import dmd.func;
import dmd.globals;
import dmd.init;
+import dmd.location;
import dmd.mtype;
-import dmd.postordervisitor;
+import dmd.rootobject : RootObject, DYNCAST;
+import dmd.semantic2;
+import dmd.semantic3;
import dmd.tokens;
import dmd.visitor;
+import dmd.visitor.postorder;
/**************************************
* Look for GC-allocations
@@ -40,6 +47,7 @@ public:
FuncDeclaration f;
bool checkOnly; // don't print errors
bool err;
+ bool nogcExceptions; // -preview=dip1008 enabled
extern (D) this(FuncDeclaration f) scope @safe
{
@@ -73,20 +81,19 @@ public:
* Register that expression `e` requires the GC
* Params:
* e = expression that uses GC
- * format = error message when `e` is used in a `@nogc` function.
- * Must contain format strings "`@nogc` %s `%s`" referring to the function.
+ * msg = error message when `e` is used in a `@nogc` function.
* Returns: `true` if `err` was set, `false` if it's not in a `@nogc` and not checkonly (-betterC)
*/
- private bool setGC(Expression e, const(char)* format)
+ private bool setGC(Expression e, const(char)* msg)
{
if (checkOnly)
{
err = true;
return true;
}
- if (f.setGC(e.loc, format))
+ if (f.setGC(e.loc, msg))
{
- error(e.loc, format, f.kind(), f.toPrettyChars());
+ error(e.loc, "%s causes a GC allocation in `@nogc` %s `%s`", msg, f.kind(), f.toChars());
err = true;
return true;
}
@@ -104,7 +111,7 @@ public:
auto fd = stripHookTraceImpl(e.f);
if (fd.ident == Id._d_arraysetlengthT)
{
- if (setGC(e, "setting `length` in `@nogc` %s `%s` may cause a GC allocation"))
+ if (setGC(e, "setting this array's `length`"))
return;
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
}
@@ -114,7 +121,7 @@ public:
{
if (e.type.ty != Tarray || !e.elements || !e.elements.length || e.onstack)
return;
- if (setGC(e, "array literal in `@nogc` %s `%s` may cause a GC allocation"))
+ if (setGC(e, "this array literal"))
return;
f.printGCUsage(e.loc, "array literal may cause a GC allocation");
}
@@ -123,13 +130,15 @@ public:
{
if (!e.keys.length)
return;
- if (setGC(e, "associative array literal in `@nogc` %s `%s` may cause a GC allocation"))
+ if (setGC(e, "this associative array literal"))
return;
f.printGCUsage(e.loc, "associative array literal may cause a GC allocation");
}
override void visit(NewExp e)
{
+ if (e.placement)
+ return; // placement new doesn't use the GC
if (e.member && !e.member.isNogc() && f.setGC(e.loc, null))
{
// @nogc-ness is already checked in NewExp::semantic
@@ -137,10 +146,10 @@ public:
}
if (e.onstack)
return;
- if (global.params.ehnogc && e.thrownew)
+ if (nogcExceptions && e.thrownew)
return; // separate allocator is called for this, not the GC
- if (setGC(e, "cannot use `new` in `@nogc` %s `%s`"))
+ if (setGC(e, "allocating with `new`"))
return;
f.printGCUsage(e.loc, "`new` causes a GC allocation");
}
@@ -163,7 +172,7 @@ public:
Type t1b = e.e1.type.toBasetype();
if (e.modifiable && t1b.ty == Taarray)
{
- if (setGC(e, "assigning an associative array element in `@nogc` %s `%s` may cause a GC allocation"))
+ if (setGC(e, "assigning this associative array element"))
return;
f.printGCUsage(e.loc, "assigning an associative array element may cause a GC allocation");
}
@@ -173,7 +182,7 @@ public:
{
if (e.e1.op == EXP.arrayLength)
{
- if (setGC(e, "setting `length` in `@nogc` %s `%s` may cause a GC allocation"))
+ if (setGC(e, "setting this array's `length`"))
return;
f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
}
@@ -186,14 +195,14 @@ public:
err = true;
return;
}
- if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`"))
+ if (setGC(e, "appending to this array with operator `~=`"))
return;
f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
}
override void visit(CatExp e)
{
- if (setGC(e, "cannot use operator `~` in `@nogc` %s `%s`"))
+ if (setGC(e, "concatenating with operator `~`"))
return;
f.printGCUsage(e.loc, "operator `~` may cause a GC allocation");
}
@@ -201,7 +210,7 @@ public:
Expression checkGC(Scope* sc, Expression e)
{
- if (sc.flags & SCOPE.ctfeBlock) // ignore GC in ctfe blocks
+ if (sc.ctfeBlock) // ignore GC in ctfe blocks
return e;
/* If betterC, allow GC to happen in non-CTFE code.
@@ -211,13 +220,14 @@ Expression checkGC(Scope* sc, Expression e)
const betterC = !global.params.useGC;
FuncDeclaration f = sc.func;
if (e && e.op != EXP.error && f && sc.intypeof != 1 &&
- (!(sc.flags & SCOPE.ctfe) || betterC) &&
+ (!sc.ctfe || betterC) &&
(f.type.ty == Tfunction &&
- (cast(TypeFunction)f.type).isnogc || f.nogcInprocess || global.params.v.gc) &&
- !(sc.flags & SCOPE.debug_))
+ (cast(TypeFunction)f.type).isNogc || f.nogcInprocess || global.params.v.gc) &&
+ !sc.debug_)
{
scope NOGCVisitor gcv = new NOGCVisitor(f);
gcv.checkOnly = betterC;
+ gcv.nogcExceptions = sc.previews.dip1008;
walkPostorder(e, gcv);
if (gcv.err)
{
@@ -234,6 +244,18 @@ Expression checkGC(Scope* sc, Expression e)
return e;
}
+extern (D) void printGCUsage(FuncDeclaration fd, Loc loc, const(char)* warn)
+{
+ if (!global.params.v.gc)
+ return;
+
+ Module m = fd.getModule();
+ if (m && m.isRoot() && !fd.inUnittest())
+ {
+ message(loc, "vgc: %s", warn);
+ }
+}
+
/**
* Removes `_d_HookTraceImpl` if found from `fd`.
* This is needed to be able to find hooks that are called though the hook's `*Trace` wrapper.
@@ -244,7 +266,6 @@ private FuncDeclaration stripHookTraceImpl(FuncDeclaration fd)
{
import dmd.id : Id;
import dmd.dsymbol : Dsymbol;
- import dmd.rootobject : RootObject, DYNCAST;
if (fd.ident != Id._d_HookTraceImpl)
return fd;
@@ -256,3 +277,76 @@ private FuncDeclaration stripHookTraceImpl(FuncDeclaration fd)
assert(s, "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
return s.isFuncDeclaration;
}
+
+/**************************************
+ * The function is doing something that may allocate with the GC,
+ * so mark it as not nogc (not no-how).
+ *
+ * Params:
+ * fd = function
+ * loc = location of GC action
+ * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
+ * args = arguments to format string
+ *
+ * Returns:
+ * true if function is marked as @nogc, meaning a user error occurred
+ */
+extern (D) bool setGC(FuncDeclaration fd, Loc loc, const(char)* fmt, RootObject[] args...)
+{
+ //printf("setGC() %s\n", toChars());
+ if (fd.nogcInprocess && fd.semanticRun < PASS.semantic3 && fd._scope)
+ {
+ fd.semantic2(fd._scope);
+ fd.semantic3(fd._scope);
+ }
+
+ if (fd.nogcInprocess)
+ {
+ fd.nogcInprocess = false;
+ if (fmt)
+ fd.nogcViolation = new AttributeViolation(loc, fmt, args); // action that requires GC
+ else if (args.length > 0)
+ {
+ if (auto sa = args[0].isDsymbol())
+ {
+ if (FuncDeclaration fd2 = sa.isFuncDeclaration())
+ {
+ fd.nogcViolation = new AttributeViolation(loc, fd2); // call to non-@nogc function
+ }
+ }
+ }
+
+ fd.type.toTypeFunction().isNogc = false;
+ if (fd.fes)
+ fd.fes.func.setGC(Loc.init, null, null);
+ }
+ else if (fd.isNogc())
+ return true;
+ return false;
+}
+
+/**************************************
+ * The function calls non-`@nogc` function f, mark it as not nogc.
+ * Params:
+ * fd = function doin the call
+ * f = function being called
+ * Returns:
+ * true if function is marked as @nogc, meaning a user error occurred
+ */
+extern (D) bool setGCCall(FuncDeclaration fd, FuncDeclaration f)
+{
+ return fd.setGC(fd.loc, null, f);
+}
+
+ bool isNogc(FuncDeclaration fd)
+{
+ //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
+ if (fd.nogcInprocess)
+ fd.setGC(fd.loc, null);
+ return fd.type.toTypeFunction().isNogc;
+}
+
+extern (D) bool isNogcBypassingInference(FuncDeclaration fd)
+{
+ return !fd.nogcInprocess && fd.isNogc();
+}
diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d
index 52c2b79..0c93f0e 100644
--- a/gcc/d/dmd/nspace.d
+++ b/gcc/d/dmd/nspace.d
@@ -36,12 +36,12 @@
* are valid D identifier.
*
* See_Also: https://github.com/dlang/dmd/pull/10031
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/nspace.d, _nspace.d)
* Documentation: https://dlang.org/phobos/dmd_nspace.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nspace.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/nspace.d
*/
module dmd.nspace;
@@ -62,10 +62,11 @@ extern (C++) final class Nspace : ScopeDsymbol
*/
Expression identExp;
- extern (D) this(const ref Loc loc, Identifier ident, Expression identExp, Dsymbols* members)
+ extern (D) this(Loc loc, Identifier ident, Expression identExp, Dsymbols* members)
{
super(loc, ident);
//printf("Nspace::Nspace(ident = %s)\n", ident.toChars());
+ this.dsym = DSYM.nspace;
this.members = members;
this.identExp = identExp;
}
@@ -88,11 +89,6 @@ extern (C++) final class Nspace : ScopeDsymbol
return "namespace";
}
- override inout(Nspace) isNspace() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h
index cbee2fb..7b4c302 100644
--- a/gcc/d/dmd/nspace.h
+++ b/gcc/d/dmd/nspace.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -23,6 +23,5 @@ class Nspace final : public ScopeDsymbol
Nspace *syntaxCopy(Dsymbol *s) override;
bool hasPointers() override;
const char *kind() const override;
- Nspace *isNspace() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d
index 0a59815..099f811 100644
--- a/gcc/d/dmd/ob.d
+++ b/gcc/d/dmd/ob.d
@@ -1,12 +1,13 @@
/**
* Flow analysis for Ownership/Borrowing
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ob.d, _ob.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ob.d, _ob.d)
* Documentation: https://dlang.org/phobos/dmd_escape.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ob.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/ob.d
+ * References: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md Argument Ownership and Function Calls
*/
module dmd.ob;
@@ -29,9 +30,10 @@ import dmd.dtemplate;
import dmd.errors;
import dmd.escape;
import dmd.expression;
-import dmd.foreachvar;
+
import dmd.func;
import dmd.globals;
+import dmd.hdrgen;
import dmd.identifier;
import dmd.init;
import dmd.location;
@@ -40,7 +42,9 @@ import dmd.printast;
import dmd.statement;
import dmd.stmtstate;
import dmd.tokens;
+import dmd.typesem;
import dmd.visitor;
+import dmd.visitor.foreachvar;
import dmd.root.bitarray;
import dmd.common.outbuffer;
@@ -226,6 +230,8 @@ struct PtrVarState
* are being merged
* Params:
* pvs = path to be merged with `this`
+ * vi = variable's index into gen[]
+ * gen = array of variable states
*/
void combine(ref PtrVarState pvs, size_t vi, PtrVarState[] gen)
{
@@ -280,6 +286,9 @@ struct PtrVarState
}
/***********************
+ * Print a bracketed list of all the variables that depend on 'this'
+ * Params:
+ * vars = variables that depend on 'this'
*/
void print(VarDeclaration[] vars)
{
@@ -370,7 +379,7 @@ void toObNodes(ref ObNodes obnodes, Statement s)
return ob;
}
- // block_goto(blx, BCgoto, null)
+ // block_goto(blx, BC.goto_, null)
ObNode* gotoNextNode()
{
return gotoNextNodeIs(newNode());
@@ -846,7 +855,7 @@ void toObNodes(ref ObNodes obnodes, Statement s)
case STMT.Mixin:
case STMT.Peel:
case STMT.Synchronized:
- debug printf("s: %s\n", s.toChars());
+ debug printf("s: %s\n", toChars(s));
assert(0); // should have been rewritten
}
}
@@ -1113,8 +1122,8 @@ bool isTrackableVar(VarDeclaration v)
/* Assume types with a destructor are doing their own tracking,
* such as being a ref counted type
*/
- if (v.needsScopeDtor())
- return false;
+// if (v.needsScopeDtor())
+// return false;
/* Not tracking function parameters that are not mutable
*/
@@ -1231,7 +1240,8 @@ void allocStates(ref ObState obstate)
*/
bool isBorrowedPtr(VarDeclaration v)
{
- return v.isScope() && !v.isowner && v.type.nextOf().isMutable();
+ return v.isScope() && !v.isowner &&
+ v.type.hasPointersToMutableFields();
}
/******************************
@@ -1241,7 +1251,7 @@ bool isBorrowedPtr(VarDeclaration v)
*/
bool isReadonlyPtr(VarDeclaration v)
{
- return v.isScope() && !v.type.nextOf().isMutable();
+ return v.isScope() && !v.type.hasPointersToMutableFields();
}
/***************************************
@@ -1251,7 +1261,7 @@ void genKill(ref ObState obstate, ObNode* ob)
{
enum log = false;
if (log)
- printf("-----------computeGenKill()-----------\n");
+ printf("-----------computeGenKill() %d -----------\n", ob.index);
/***************
* Assigning result of expression `e` to variable `v`.
@@ -1274,8 +1284,6 @@ void genKill(ref ObState obstate, ObNode* ob)
pvs.state = PtrState.Owner;
pvs.deps.zero();
- EscapeByResults er;
- escapeByValue(e, &er, true);
bool any = false; // if any variables are assigned to v
void by(VarDeclaration r)
@@ -1305,10 +1313,7 @@ void genKill(ref ObState obstate, ObNode* ob)
}
}
- foreach (VarDeclaration v2; er.byvalue)
- by(v2);
- foreach (VarDeclaration v2; er.byref)
- by(v2);
+ escapeLive(e, &by);
/* Make v an Owner for initializations like:
* scope v = malloc();
@@ -1331,7 +1336,7 @@ void genKill(ref ObState obstate, ObNode* ob)
}
}
- void dgReadVar(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable)
+ void dgReadVar(Loc loc, ObNode* ob, VarDeclaration v, bool mutable)
{
if (log)
printf("dgReadVar() %s %d\n", v.toChars(), mutable);
@@ -1346,12 +1351,12 @@ void genKill(ref ObState obstate, ObNode* ob)
{
alias visit = typeof(super).visit;
extern (D) void delegate(ObNode*, VarDeclaration, Expression, bool) dgWriteVar;
- extern (D) void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar;
+ extern (D) void delegate(Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar;
ObNode* ob;
ObState* obstate;
extern (D) this(void delegate(ObNode*, VarDeclaration, Expression, bool) dgWriteVar,
- void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar,
+ void delegate(Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar,
ObNode* ob, ref ObState obstate) scope
{
this.dgWriteVar = dgWriteVar;
@@ -1435,6 +1440,41 @@ void genKill(ref ObState obstate, ObNode* ob)
assert(t.ty == Tdelegate);
tf = t.nextOf().isTypeFunction();
assert(tf);
+
+ }
+
+ if (auto dve = ce.e1.isDotVarExp())
+ {
+ if (!t.isTypeDelegate() && dve.e1.isVarExp())
+ {
+ //printf("dve: %s\n", dve.toChars());
+
+ void byf(VarDeclaration v)
+ {
+ //printf("byf v: %s\n", v.ident.toChars());
+ if (!isTrackableVar(v))
+ return;
+
+ const vi = obstate.vars.find(v);
+ if (vi == size_t.max)
+ return;
+
+ auto fd = dve.var.isFuncDeclaration();
+ if (fd && fd.storage_class & STC.scope_)
+ {
+ // borrow
+ obstate.varStack.push(vi);
+ obstate.mutableStack.push(isMutableRef(dve.e1.type.toBasetype()));
+ }
+ else
+ {
+ // move (i.e. consume arg)
+ makeUndefined(vi, ob.gen);
+ }
+ }
+
+ escapeLive(dve.e1, &byf);
+ }
}
// j=1 if _arguments[] is first argument
@@ -1450,14 +1490,13 @@ void genKill(ref ObState obstate, ObNode* ob)
Parameter p = tf.parameterList[i - j];
auto pt = p.type.toBasetype();
- EscapeByResults er;
- escapeByValue(arg, &er, true);
if (!(p.storageClass & STC.out_ && arg.isVarExp()))
arg.accept(this);
void by(VarDeclaration v)
{
+ //printf("by v: %s\n", v.ident.toChars());
if (!isTrackableVar(v))
return;
@@ -1484,18 +1523,12 @@ void genKill(ref ObState obstate, ObNode* ob)
}
}
- foreach (VarDeclaration v2; er.byvalue)
- by(v2);
- foreach (VarDeclaration v2; er.byref)
- by(v2);
+ escapeLive(arg, &by);
}
else // variadic args
{
arg.accept(this);
- EscapeByResults er;
- escapeByValue(arg, &er, true);
-
void byv(VarDeclaration v)
{
if (!isTrackableVar(v))
@@ -1517,10 +1550,7 @@ void genKill(ref ObState obstate, ObNode* ob)
makeUndefined(vi, ob.gen);
}
- foreach (VarDeclaration v2; er.byvalue)
- byv(v2);
- foreach (VarDeclaration v2; er.byref)
- byv(v2);
+ escapeLive(arg, &byv);
}
}
@@ -1653,7 +1683,7 @@ void genKill(ref ObState obstate, ObNode* ob)
override void visit(ArrayLiteralExp e)
{
Type tb = e.type.toBasetype();
- if (tb.ty == Tsarray || tb.ty == Tarray)
+ if (tb.isStaticOrDynamicArray())
{
if (e.basis)
e.basis.accept(this);
@@ -1693,6 +1723,8 @@ void genKill(ref ObState obstate, ObNode* ob)
override void visit(NewExp e)
{
+ if (e.placement)
+ e.placement.accept(this);
if (e.arguments)
{
foreach (ex; *e.arguments)
@@ -1721,6 +1753,15 @@ void genKill(ref ObState obstate, ObNode* ob)
}
foreachExp(ob, ob.exp);
+
+ if (log)
+ {
+ printf(" gen:\n");
+ foreach (i, ref pvs2; ob.gen[])
+ {
+ printf(" %s: ", obstate.vars[i].toChars()); pvs2.print(obstate.vars[]);
+ }
+ }
}
/***************************************
@@ -1946,6 +1987,25 @@ void doDataFlowAnalysis(ref ObState obstate)
/***************************************
+ * Check for escaping variables using DIP1000's `escapeByValue`, with `live` set to `true`
+ * Params:
+ * e = expression to check
+ * onVar = gets called for each variable escaped through `e`, either by value or by ref
+ */
+void escapeLive(Expression e, scope void delegate(VarDeclaration) onVar)
+{
+ scope EscapeByResults er = EscapeByResults(
+ (VarDeclaration v, bool) => onVar(v),
+ onVar,
+ (FuncDeclaration f, bool) {},
+ (Expression e, bool) {},
+ true,
+ );
+
+ escapeByValue(e, er);
+}
+
+/***************************************
* Check for Ownership/Borrowing errors.
*/
void checkObErrors(ref ObState obstate)
@@ -1976,8 +2036,6 @@ void checkObErrors(ref ObState obstate)
}
pvs.deps.zero();
- EscapeByResults er;
- escapeByValue(e, &er, true);
void by(VarDeclaration r) // `v` = `r`
{
@@ -2015,10 +2073,7 @@ void checkObErrors(ref ObState obstate)
}
}
- foreach (VarDeclaration v2; er.byvalue)
- by(v2);
- foreach (VarDeclaration v2; er.byref)
- by(v2);
+ escapeLive(e, &by);
}
else
{
@@ -2032,7 +2087,7 @@ void checkObErrors(ref ObState obstate)
}
}
- void dgReadVar(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[] gen)
+ void dgReadVar(Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[] gen)
{
if (log) printf("dgReadVar() %s\n", v.toChars());
const vi = obstate.vars.find(v);
@@ -2050,12 +2105,12 @@ void checkObErrors(ref ObState obstate)
{
alias visit = typeof(super).visit;
extern (D) void delegate(ObNode*, PtrVarState[], VarDeclaration, Expression) dgWriteVar;
- extern (D) void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar;
+ extern (D) void delegate(Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar;
PtrVarState[] cpvs;
ObNode* ob;
ObState* obstate;
- extern (D) this(void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar,
+ extern (D) this(void delegate(Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar,
void delegate(ObNode*, PtrVarState[], VarDeclaration, Expression) dgWriteVar,
PtrVarState[] cpvs, ObNode* ob, ref ObState obstate) scope
{
@@ -2157,8 +2212,6 @@ void checkObErrors(ref ObState obstate)
if (!(p.storageClass & STC.out_ && arg.isVarExp()))
arg.accept(this);
- EscapeByResults er;
- escapeByValue(arg, &er, true);
void by(VarDeclaration v)
{
@@ -2192,18 +2245,11 @@ void checkObErrors(ref ObState obstate)
}
}
- foreach (VarDeclaration v2; er.byvalue)
- by(v2);
- foreach (VarDeclaration v2; er.byref)
- by(v2);
+ escapeLive(arg, &by);
}
else // variadic args
{
arg.accept(this);
-
- EscapeByResults er;
- escapeByValue(arg, &er, true);
-
void byv(VarDeclaration v)
{
if (!isTrackableVar(v))
@@ -2231,10 +2277,7 @@ void checkObErrors(ref ObState obstate)
}
}
- foreach (VarDeclaration v2; er.byvalue)
- byv(v2);
- foreach (VarDeclaration v2; er.byref)
- byv(v2);
+ escapeLive(arg, &byv);
}
}
@@ -2383,7 +2426,7 @@ void checkObErrors(ref ObState obstate)
override void visit(ArrayLiteralExp e)
{
Type tb = e.type.toBasetype();
- if (tb.ty == Tsarray || tb.ty == Tarray)
+ if (tb.isStaticOrDynamicArray())
{
if (e.basis)
e.basis.accept(this);
@@ -2423,6 +2466,9 @@ void checkObErrors(ref ObState obstate)
override void visit(NewExp e)
{
+ if (e.placement)
+ e.placement.accept(this);
+
if (e.arguments)
{
foreach (ex; *e.arguments)
@@ -2460,7 +2506,7 @@ void checkObErrors(ref ObState obstate)
{
static if (log)
{
- printf("%d: %s\n", obi, ob.exp ? ob.exp.toChars() : "".ptr);
+ printf("%d: %s\n", cast(int) obi, ob.exp ? ob.exp.toChars() : "".ptr);
printf(" input:\n");
foreach (i, ref pvs; ob.input[])
{
@@ -2490,7 +2536,9 @@ void checkObErrors(ref ObState obstate)
if (s1 != s2 && (s1 == PtrState.Owner || s2 == PtrState.Owner))
{
auto v = obstate.vars[i];
- .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, PtrStateToChars(s1), PtrStateToChars(s2));
+ // Don't worry about non-pointers
+ if (hasPointers(v.type))
+ .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, PtrStateToChars(s1), PtrStateToChars(s2));
}
pvs1.combine(*pvs2, i, ob.gen);
}
@@ -2522,9 +2570,6 @@ void checkObErrors(ref ObState obstate)
if (ob.obtype == ObType.retexp)
{
- EscapeByResults er;
- escapeByValue(ob.exp, &er, true);
-
void by(VarDeclaration r) // `r` is the rvalue
{
const ri = obstate.vars.find(r);
@@ -2552,11 +2597,7 @@ void checkObErrors(ref ObState obstate)
}
}
}
-
- foreach (VarDeclaration v2; er.byvalue)
- by(v2);
- foreach (VarDeclaration v2; er.byref)
- by(v2);
+ escapeLive(ob.exp, &by);
}
if (ob.obtype == ObType.return_ || ob.obtype == ObType.retexp)
@@ -2649,6 +2690,9 @@ void makeChildrenUndefined(size_t vi, PtrVarState[] gen)
/********************
* Recursively make Undefined vi undefined and all who list vi as a dependency
+ * Params:
+ * vi = variable's index
+ * gen = array of the states of variables
*/
void makeUndefined(size_t vi, PtrVarState[] gen)
{
diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d
index 2f36d5d..32878b5 100644
--- a/gcc/d/dmd/objc.d
+++ b/gcc/d/dmd/objc.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/objc_interface.html, Interfacing to Objective-C)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/objc.d, _objc.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/objc.d, _objc.d)
* Documentation: https://dlang.org/phobos/dmd_objc.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/objc.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/objc.d
*/
module dmd.objc;
@@ -17,11 +17,11 @@ import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.attrib;
+import dmd.attribsem;
import dmd.cond;
import dmd.dclass;
import dmd.declaration;
import dmd.denum;
-import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
import dmd.dstruct;
@@ -37,6 +37,7 @@ import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.location;
+import dmd.mangle;
import dmd.mtype;
import dmd.root.array;
import dmd.common.outbuffer;
@@ -92,39 +93,66 @@ struct ObjcSelector
return sel;
}
+ static const(char)[] toPascalCase(const(char)[] id) {
+ OutBuffer buf;
+ char firstChar = id[0];
+ if (firstChar >= 'a' && firstChar <= 'z')
+ firstChar = cast(char)(firstChar - 'a' + 'A');
+
+ buf.writeByte(firstChar);
+ buf.writestring(id[1..$]);
+ return cast(const(char)[])buf.extractSlice(false);
+ }
+
extern (C++) static ObjcSelector* create(FuncDeclaration fdecl)
{
OutBuffer buf;
- TypeFunction ftype = cast(TypeFunction)fdecl.type;
+ auto ftype = cast(TypeFunction)fdecl.type;
const id = fdecl.ident.toString();
const nparams = ftype.parameterList.length;
+
// Special case: property setter
- if (ftype.isproperty && nparams == 1)
+ if (ftype.isProperty && nparams == 1)
{
- // rewrite "identifier" as "setIdentifier"
- char firstChar = id[0];
- if (firstChar >= 'a' && firstChar <= 'z')
- firstChar = cast(char)(firstChar - 'a' + 'A');
- buf.writestring("set");
- buf.writeByte(firstChar);
- buf.write(id[1 .. id.length - 1]);
+
+ // Special case: "isXYZ:"
+ if (id.length >= 2 && id[0..2] == "is")
+ {
+ buf.writestring("set");
+ buf.write(toPascalCase(id[2..$]));
+ }
+ else
+ {
+ buf.writestring("set");
+ buf.write(toPascalCase(id));
+ }
buf.writeByte(':');
goto Lcomplete;
}
+
// write identifier in selector
buf.write(id[]);
- // add mangled type and colon for each parameter
- if (nparams)
+
+ // To make it easier to match the selectors of objects nicely,
+ // the implementation has been replaced so that the parameter name followed by a colon
+ // is used instead.
+ // eg. void myFunction(int a, int b, int c) would be mangled to a selector as `myFunction:b:c:
+ if (nparams > 1)
{
- buf.writeByte('_');
- foreach (i, fparam; ftype.parameterList)
+ buf.writeByte(':');
+ foreach(i; 1..nparams)
{
- mangleToBuffer(fparam.type, buf);
+ buf.write(ftype.parameterList[i].ident.toString());
buf.writeByte(':');
}
}
+ else if (nparams == 1)
+ {
+ buf.writeByte(':');
+ }
Lcomplete:
buf.writeByte('\0');
+
// the slice is not expected to include a terminating 0
return lookup(cast(const(char)*)buf[].ptr, buf.length - 1, nparams);
}
@@ -564,13 +592,23 @@ extern(C++) private final class Supported : Objc
return 0;
});
+
+ // Avoid attempting to generate selectors for template instances.
+ if (fd.parent && fd.parent.isTemplateInstance())
+ return;
+
+ // No selector declared, generate one.
+ if (fd._linkage == LINK.objc && !fd.objc.selector)
+ {
+ fd.objc.selector = ObjcSelector.create(fd);
+ }
}
override void validateSelector(FuncDeclaration fd)
{
if (!fd.objc.selector)
return;
- TypeFunction tf = cast(TypeFunction)fd.type;
+ auto tf = cast(TypeFunction)fd.type;
if (fd.objc.selector.paramCount != tf.parameterList.parameters.length)
.error(fd.loc, "%s `%s` number of colons in Objective-C selector must match number of parameters", fd.kind, fd.toPrettyChars);
if (fd.parent && fd.parent.isTemplateInstance())
@@ -676,8 +714,8 @@ extern(C++) private final class Supported : Objc
{
if (cd.classKind == ClassKind.objc && fd.isStatic && !cd.objc.isMeta)
return cd.objc.metaclass;
- else
- return cd;
+
+ return cd;
}
override void addToClassMethodList(FuncDeclaration fd, ClassDeclaration cd) const
@@ -767,11 +805,10 @@ extern(C++) private final class Supported : Objc
{
if (classDeclaration.baseClass)
return getRuntimeMetaclass(classDeclaration.baseClass);
- else
- return classDeclaration;
+
+ return classDeclaration;
}
- else
- return classDeclaration.objc.metaclass;
+ return classDeclaration.objc.metaclass;
}
override void addSymbols(AttribDeclaration attribDeclaration,
diff --git a/gcc/d/dmd/objc.h b/gcc/d/dmd/objc.h
index 0390115..af6f2e4 100644
--- a/gcc/d/dmd/objc.h
+++ b/gcc/d/dmd/objc.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 2015-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2015-2025 by The D Language Foundation, All Rights Reserved
* written by Michel Fortin
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index 70eeaff..7baaeaa 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/operatoroverloading.html, Operator Overloading)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/opover.d, _opover.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/opover.d, _opover.d)
* Documentation: https://dlang.org/phobos/dmd_opover.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/opover.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/opover.d
*/
module dmd.opover;
@@ -29,6 +29,7 @@ import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -70,81 +71,54 @@ bool isCommutative(EXP op) @safe
return false;
}
-/***********************************
- * Get Identifier for operator overload.
- */
-private Identifier opId(Expression e)
+/// Returns: whether `op` can be overloaded with `opBinary`
+private bool hasOpBinary(EXP op) pure @safe
{
- switch (e.op)
+ switch (op)
{
- case EXP.uadd: return Id.uadd;
- case EXP.negate: return Id.neg;
- case EXP.tilde: return Id.com;
- case EXP.cast_: return Id._cast;
- case EXP.in_: return Id.opIn;
- case EXP.plusPlus: return Id.postinc;
- case EXP.minusMinus: return Id.postdec;
- case EXP.add: return Id.add;
- case EXP.min: return Id.sub;
- case EXP.mul: return Id.mul;
- case EXP.div: return Id.div;
- case EXP.mod: return Id.mod;
- case EXP.pow: return Id.pow;
- case EXP.leftShift: return Id.shl;
- case EXP.rightShift: return Id.shr;
- case EXP.unsignedRightShift: return Id.ushr;
- case EXP.and: return Id.iand;
- case EXP.or: return Id.ior;
- case EXP.xor: return Id.ixor;
- case EXP.concatenate: return Id.cat;
- case EXP.assign: return Id.assign;
- case EXP.addAssign: return Id.addass;
- case EXP.minAssign: return Id.subass;
- case EXP.mulAssign: return Id.mulass;
- case EXP.divAssign: return Id.divass;
- case EXP.modAssign: return Id.modass;
- case EXP.powAssign: return Id.powass;
- case EXP.leftShiftAssign: return Id.shlass;
- case EXP.rightShiftAssign: return Id.shrass;
- case EXP.unsignedRightShiftAssign: return Id.ushrass;
- case EXP.andAssign: return Id.andass;
- case EXP.orAssign: return Id.orass;
- case EXP.xorAssign: return Id.xorass;
- case EXP.concatenateAssign: return Id.catass;
- case EXP.equal: return Id.eq;
- case EXP.lessThan:
- case EXP.lessOrEqual:
- case EXP.greaterThan:
- case EXP.greaterOrEqual: return Id.cmp;
- case EXP.array: return Id.index;
- case EXP.star: return Id.opStar;
- default: assert(0);
+ case EXP.add: return true;
+ case EXP.min: return true;
+ case EXP.mul: return true;
+ case EXP.div: return true;
+ case EXP.mod: return true;
+ case EXP.and: return true;
+ case EXP.or: return true;
+ case EXP.xor: return true;
+ case EXP.leftShift: return true;
+ case EXP.rightShift: return true;
+ case EXP.unsignedRightShift: return true;
+ case EXP.concatenate: return true;
+ case EXP.pow: return true;
+ case EXP.in_: return true;
+ default: return false;
}
}
-/***********************************
- * Get Identifier for reverse operator overload,
- * `null` if not supported for this operator.
- */
-private Identifier opId_r(Expression e)
+/**
+ * Remove the = from op=, e.g. += becomes +
+ *
+ * Params:
+ * op = tag for a binary assign operator
+ * Returns: the corresponding binary operator, or `op` if it wasn't an assign operator
+*/
+private EXP stripAssignOp(EXP op)
{
- switch (e.op)
+ switch (op)
{
- case EXP.in_: return Id.opIn_r;
- case EXP.add: return Id.add_r;
- case EXP.min: return Id.sub_r;
- case EXP.mul: return Id.mul_r;
- case EXP.div: return Id.div_r;
- case EXP.mod: return Id.mod_r;
- case EXP.pow: return Id.pow_r;
- case EXP.leftShift: return Id.shl_r;
- case EXP.rightShift: return Id.shr_r;
- case EXP.unsignedRightShift:return Id.ushr_r;
- case EXP.and: return Id.iand_r;
- case EXP.or: return Id.ior_r;
- case EXP.xor: return Id.ixor_r;
- case EXP.concatenate: return Id.cat_r;
- default: return null;
+ case EXP.addAssign: return EXP.add;
+ case EXP.minAssign: return EXP.min;
+ case EXP.mulAssign: return EXP.mul;
+ case EXP.divAssign: return EXP.div;
+ case EXP.modAssign: return EXP.mod;
+ case EXP.andAssign: return EXP.and;
+ case EXP.orAssign: return EXP.or;
+ case EXP.xorAssign: return EXP.xor;
+ case EXP.leftShiftAssign: return EXP.leftShift;
+ case EXP.rightShiftAssign: return EXP.rightShift;
+ case EXP.unsignedRightShiftAssign: return EXP.unsignedRightShift;
+ case EXP.concatenateAssign: return EXP.concatenate;
+ case EXP.powAssign: return EXP.pow;
+ default: return op;
}
}
@@ -153,53 +127,7 @@ private Identifier opId_r(Expression e)
*/
Objects* opToArg(Scope* sc, EXP op)
{
- /* Remove the = from op=
- */
- switch (op)
- {
- case EXP.addAssign:
- op = EXP.add;
- break;
- case EXP.minAssign:
- op = EXP.min;
- break;
- case EXP.mulAssign:
- op = EXP.mul;
- break;
- case EXP.divAssign:
- op = EXP.div;
- break;
- case EXP.modAssign:
- op = EXP.mod;
- break;
- case EXP.andAssign:
- op = EXP.and;
- break;
- case EXP.orAssign:
- op = EXP.or;
- break;
- case EXP.xorAssign:
- op = EXP.xor;
- break;
- case EXP.leftShiftAssign:
- op = EXP.leftShift;
- break;
- case EXP.rightShiftAssign:
- op = EXP.rightShift;
- break;
- case EXP.unsignedRightShiftAssign:
- op = EXP.unsignedRightShift;
- break;
- case EXP.concatenateAssign:
- op = EXP.concatenate;
- break;
- case EXP.powAssign:
- op = EXP.pow;
- break;
- default:
- break;
- }
- Expression e = new StringExp(Loc.initial, EXPtoString(op));
+ Expression e = new StringExp(Loc.initial, EXPtoString(stripAssignOp(op)));
e = e.expressionSemantic(sc);
auto tiargs = new Objects();
tiargs.push(e);
@@ -207,7 +135,7 @@ Objects* opToArg(Scope* sc, EXP op)
}
// Try alias this on first operand
-private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinExp e)
+Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinExp e, Type[2] aliasThisStop)
{
if (!ad || !ad.aliasthis)
return null;
@@ -215,35 +143,29 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE
/* Rewrite (e1 op e2) as:
* (e1.aliasthis op e2)
*/
- if (isRecursiveAliasThis(e.att1, e.e1.type))
+ if (isRecursiveAliasThis(aliasThisStop[0], e.e1.type))
return null;
//printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
BinExp be = cast(BinExp)e.copy();
// Resolve 'alias this' but in case of assigment don't resolve properties yet
// because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2'
- bool findOnly = (e.op == EXP.assign);
+ bool findOnly = e.isAssignExp() !is null;
be.e1 = resolveAliasThis(sc, e.e1, true, findOnly);
if (!be.e1)
return null;
- Expression result;
- if (be.op == EXP.concatenateAssign)
- result = be.op_overload(sc);
- else
- result = be.trySemantic(sc);
-
- return result;
+ return be.trySemanticAliasThis(sc, aliasThisStop);
}
// Try alias this on second operand
-private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinExp e)
+Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinExp e, Type[2] aliasThisStop)
{
if (!ad || !ad.aliasthis)
return null;
/* Rewrite (e1 op e2) as:
* (e1 op e2.aliasthis)
*/
- if (isRecursiveAliasThis(e.att2, e.e2.type))
+ if (isRecursiveAliasThis(aliasThisStop[1], e.e2.type))
return null;
//printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
BinExp be = cast(BinExp)e.copy();
@@ -251,1168 +173,995 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
if (!be.e2)
return null;
- Expression result;
- if (be.op == EXP.concatenateAssign)
- result = be.op_overload(sc);
- else
- result = be.trySemantic(sc);
-
- return result;
+ return be.trySemanticAliasThis(sc, aliasThisStop);
}
-/************************************
- * Operator overload.
- * Check for operator overload, if so, replace
- * with function call.
- * Params:
- * e = expression with operator
- * sc = context
- * pop = if not null, is set to the operator that was actually overloaded,
- * which may not be `e.op`. Happens when operands are reversed to
- * match an overload
- * Returns:
- * `null` if not an operator overload,
- * otherwise the lowered expression
- */
-Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
+Expression opOverloadUnary(UnaExp e, Scope* sc)
{
- Expression visit(Expression e)
- {
- assert(0);
- }
-
- Expression visitUna(UnaExp e)
+ if (auto ae = e.e1.isArrayExp())
+ {
+ ae.e1 = ae.e1.expressionSemantic(sc);
+ ae.e1 = resolveProperties(sc, ae.e1);
+ Expression ae1old = ae.e1;
+ const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].isIntervalExp());
+ IntervalExp ie = null;
+ if (maybeSlice && ae.arguments.length)
{
- //printf("UnaExp::op_overload() (%s)\n", e.toChars());
- Expression result;
- if (auto ae = e.e1.isArrayExp())
- {
- ae.e1 = ae.e1.expressionSemantic(sc);
- ae.e1 = resolveProperties(sc, ae.e1);
- Expression ae1old = ae.e1;
- const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
- IntervalExp ie = null;
- if (maybeSlice && ae.arguments.length)
- {
- ie = (*ae.arguments)[0].isIntervalExp();
- }
- Type att = null; // first cyclic `alias this` type
- while (true)
- {
- if (ae.e1.op == EXP.error)
- {
- return ae.e1;
- }
- Expression e0 = null;
- Expression ae1save = ae.e1;
- ae.lengthVar = null;
- Type t1b = ae.e1.type.toBasetype();
- AggregateDeclaration ad = isAggregate(t1b);
- if (!ad)
- break;
- if (search_function(ad, Id.opIndexUnary))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, &e0);
- if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
- goto Lfallback;
- if (result.op == EXP.error)
- return result;
- /* Rewrite op(a[arguments]) as:
- * a.opIndexUnary!(op)(arguments)
- */
- Expressions* a = ae.arguments.copy();
- Objects* tiargs = opToArg(sc, e.op);
- result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexUnary, tiargs);
- result = new CallExp(e.loc, result, a);
- if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)()
- result = result.trySemantic(sc);
- else
- result = result.expressionSemantic(sc);
- if (result)
- {
- return Expression.combine(e0, result);
- }
- }
- Lfallback:
- if (maybeSlice && search_function(ad, Id.opSliceUnary))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, ie, &e0);
- if (result.op == EXP.error)
- return result;
- /* Rewrite op(a[i..j]) as:
- * a.opSliceUnary!(op)(i, j)
- */
- auto a = new Expressions();
- if (ie)
- {
- a.push(ie.lwr);
- a.push(ie.upr);
- }
- Objects* tiargs = opToArg(sc, e.op);
- result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceUnary, tiargs);
- result = new CallExp(e.loc, result, a);
- result = result.expressionSemantic(sc);
- result = Expression.combine(e0, result);
- return result;
- }
- // Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
- {
- /* Rewrite op(a[arguments]) as:
- * op(a.aliasthis[arguments])
- */
- ae.e1 = resolveAliasThis(sc, ae1save, true);
- if (ae.e1)
- continue;
- }
- break;
- }
- ae.e1 = ae1old; // recovery
- ae.lengthVar = null;
- }
- e.e1 = e.e1.expressionSemantic(sc);
- e.e1 = resolveProperties(sc, e.e1);
- Type att = null; // first cyclic `alias this` type
- while (1)
- {
- if (e.e1.op == EXP.error)
- {
- return e.e1;
- }
-
- AggregateDeclaration ad = isAggregate(e.e1.type);
- if (!ad)
- break;
-
- Dsymbol fd = null;
- /* Rewrite as:
- * e1.opUnary!(op)()
- */
- fd = search_function(ad, Id.opUnary);
- if (fd)
- {
- Objects* tiargs = opToArg(sc, e.op);
- result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs);
- result = new CallExp(e.loc, result);
- result = result.expressionSemantic(sc);
- return result;
- }
- // D1-style operator overloads, deprecated
- if (e.op != EXP.prePlusPlus && e.op != EXP.preMinusMinus)
- {
- auto id = opId(e);
- fd = search_function(ad, id);
- if (fd)
- {
- // @@@DEPRECATED_2.110@@@.
- // Deprecated in 2.088, made an error in 2.100
- error(e.loc, "`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
- return ErrorExp.get();
- }
- }
- // Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type))
- {
- /* Rewrite op(e1) as:
- * op(e1.aliasthis)
- */
- //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars());
- if (auto e1 = resolveAliasThis(sc, e.e1, true))
- {
- e.e1 = e1;
- continue;
- }
- break;
- }
- break;
- }
- return result;
+ ie = (*ae.arguments)[0].isIntervalExp();
}
-
- Expression visitArray(ArrayExp ae)
+ Type att = null; // first cyclic `alias this` type
+ while (true)
{
- //printf("ArrayExp::op_overload() (%s)\n", ae.toChars());
- ae.e1 = ae.e1.expressionSemantic(sc);
- ae.e1 = resolveProperties(sc, ae.e1);
- Expression ae1old = ae.e1;
- const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
- IntervalExp ie = null;
- if (maybeSlice && ae.arguments.length)
+ if (ae.e1.isErrorExp())
{
- ie = (*ae.arguments)[0].isIntervalExp();
+ return ae.e1;
}
- Expression result;
- Type att = null; // first cyclic `alias this` type
- while (true)
- {
- if (ae.e1.op == EXP.error)
- {
- return ae.e1;
- }
- Expression e0 = null;
- Expression ae1save = ae.e1;
- ae.lengthVar = null;
- Type t1b = ae.e1.type.toBasetype();
- AggregateDeclaration ad = isAggregate(t1b);
- if (!ad)
- {
- // If the non-aggregate expression ae.e1 is indexable or sliceable,
- // convert it to the corresponding concrete expression.
- if (isIndexableNonAggregate(t1b) || ae.e1.op == EXP.type)
- {
- // Convert to SliceExp
- if (maybeSlice)
- {
- result = new SliceExp(ae.loc, ae.e1, ie);
- result = result.expressionSemantic(sc);
- return result;
- }
- // Convert to IndexExp
- if (ae.arguments.length == 1)
- {
- result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]);
- result = result.expressionSemantic(sc);
- return result;
- }
- }
- break;
- }
- if (search_function(ad, Id.index))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, &e0);
- if (!result) // a[i..j] might be: a.opSlice(i, j)
- goto Lfallback;
- if (result.op == EXP.error)
- return result;
- /* Rewrite e1[arguments] as:
- * e1.opIndex(arguments)
- */
- Expressions* a = ae.arguments.copy();
- result = new DotIdExp(ae.loc, ae.e1, Id.index);
- result = new CallExp(ae.loc, result, a);
- if (maybeSlice) // a[] might be: a.opSlice()
- result = result.trySemantic(sc);
- else
- result = result.expressionSemantic(sc);
- if (result)
- {
- return Expression.combine(e0, result);
- }
- }
- Lfallback:
- if (maybeSlice && ae.e1.op == EXP.type)
- {
- result = new SliceExp(ae.loc, ae.e1, ie);
- result = result.expressionSemantic(sc);
- result = Expression.combine(e0, result);
- return result;
- }
- if (maybeSlice && search_function(ad, Id.slice))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, ie, &e0);
+ Expression ae1save = ae.e1;
+ ae.lengthVar = null;
- if (result.op == EXP.error)
- {
- if (!e0 && !search_function(ad, Id.dollar)) {
- ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars());
- }
- return result;
- }
- /* Rewrite a[i..j] as:
- * a.opSlice(i, j)
- */
- auto a = new Expressions();
- if (ie)
- {
- a.push(ie.lwr);
- a.push(ie.upr);
- }
- result = new DotIdExp(ae.loc, ae.e1, Id.slice);
- result = new CallExp(ae.loc, result, a);
- result = result.expressionSemantic(sc);
- result = Expression.combine(e0, result);
- return result;
- }
- // Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
- {
- //printf("att arr e1 = %s\n", this.e1.type.toChars());
- /* Rewrite op(a[arguments]) as:
- * op(a.aliasthis[arguments])
- */
- ae.e1 = resolveAliasThis(sc, ae1save, true);
- if (ae.e1)
- continue;
- }
+ AggregateDeclaration ad = isAggregate(ae.e1.type);
+ if (!ad)
break;
- }
- ae.e1 = ae1old; // recovery
- ae.lengthVar = null;
- return result;
- }
- /***********************************************
- * This is mostly the same as UnaryExp::op_overload(), but has
- * a different rewrite.
- */
- Expression visitCast(CastExp e, Type att = null)
- {
- //printf("CastExp::op_overload() (%s)\n", e.toChars());
- Expression result;
- AggregateDeclaration ad = isAggregate(e.e1.type);
- if (ad)
+ if (search_function(ad, Id.opIndexUnary))
{
- Dsymbol fd = null;
- /* Rewrite as:
- * e1.opCast!(T)()
+ Expression e0;
+ // Deal with $
+ Expression ae2 = resolveOpDollar(sc, ae, e0);
+ if (!ae2) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
+ goto Lfallback;
+ if (ae2.isErrorExp())
+ return ae2;
+ /* Rewrite op(a[arguments]) as:
+ * a.opIndexUnary!(op)(arguments)
*/
- fd = search_function(ad, Id._cast);
- if (fd)
- {
- version (all)
- {
- // Backwards compatibility with D1 if opCast is a function, not a template
- if (fd.isFuncDeclaration())
- {
- // Rewrite as: e1.opCast()
- return build_overload(e.loc, sc, e.e1, null, fd);
- }
- }
- auto tiargs = new Objects();
- tiargs.push(e.to);
- result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs);
- result = new CallExp(e.loc, result);
+ Expression result = dotTemplateCall(ae.e1, Id.opIndexUnary, opToArg(sc, e.op), (*ae.arguments)[]);
+ if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)()
+ result = result.trySemantic(sc);
+ else
result = result.expressionSemantic(sc);
- return result;
- }
- // Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type))
- {
- /* Rewrite op(e1) as:
- * op(e1.aliasthis)
- */
- if (auto e1 = resolveAliasThis(sc, e.e1, true))
- {
- result = e.copy();
- (cast(UnaExp)result).e1 = e1;
- result = visitCast(result.isCastExp(), att);
- return result;
- }
- }
- }
- return result;
- }
- Expression visitBin(BinExp e)
- {
- //printf("BinExp::op_overload() (%s)\n", e.toChars());
- Identifier id = opId(e);
- Identifier id_r = opId_r(e);
- int argsset = 0;
- AggregateDeclaration ad1 = isAggregate(e.e1.type);
- AggregateDeclaration ad2 = isAggregate(e.e2.type);
- if (e.op == EXP.assign && ad1 == ad2)
- {
- StructDeclaration sd = ad1.isStructDeclaration();
- if (sd &&
- (!sd.hasIdentityAssign ||
- /* Do a blit if we can and the rvalue is something like .init,
- * where a postblit is not necessary.
- */
- (sd.hasBlitAssign && !e.e2.isLvalue())))
- {
- /* This is bitwise struct assignment. */
- return null;
- }
- }
- Dsymbol s = null;
- Dsymbol s_r = null;
- Objects* tiargs = null;
- if (e.op == EXP.plusPlus || e.op == EXP.minusMinus)
- {
- // Bug4099 fix
- if (ad1 && search_function(ad1, Id.opUnary))
- return null;
+ if (result)
+ return Expression.combine(e0, result);
}
- if (e.op != EXP.equal && e.op != EXP.notEqual && e.op != EXP.assign && e.op != EXP.plusPlus && e.op != EXP.minusMinus)
+ Lfallback:
+ if (maybeSlice && search_function(ad, Id.opSliceUnary))
{
- /* Try opBinary and opBinaryRight
+ // Deal with $
+ Expression e0;
+ auto ae2 = resolveOpDollar(sc, ae, ie, e0);
+ if (ae2.isErrorExp())
+ return ae2;
+ /* Rewrite op(a[i..j]) as:
+ * a.opSliceUnary!(op)(i, j)
*/
- if (ad1)
- {
- s = search_function(ad1, Id.opBinary);
- if (s && !s.isTemplateDeclaration())
- {
- error(e.e1.loc, "`%s.opBinary` isn't a template", e.e1.toChars());
- return ErrorExp.get();
- }
- }
- if (ad2)
- {
- s_r = search_function(ad2, Id.opBinaryRight);
- if (s_r && !s_r.isTemplateDeclaration())
- {
- error(e.e2.loc, "`%s.opBinaryRight` isn't a template", e.e2.toChars());
- return ErrorExp.get();
- }
- if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778
- s_r = null;
- }
- // Set tiargs, the template argument list, which will be the operator string
- if (s || s_r)
- {
- id = Id.opBinary;
- id_r = Id.opBinaryRight;
- tiargs = opToArg(sc, e.op);
- }
- }
- if (!s && !s_r)
- {
- // Try the D1-style operators, deprecated
- if (ad1 && id)
- {
- s = search_function(ad1, id);
- if (s && id != Id.assign)
- {
- // @@@DEPRECATED_2.110@@@.
- // Deprecated in 2.088, made an error in 2.100
- if (id == Id.postinc || id == Id.postdec)
- error(e.loc, "`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
- else
- error(e.loc, "`%s` is obsolete. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
- return ErrorExp.get();
- }
- }
- if (ad2 && id_r)
- {
- s_r = search_function(ad2, id_r);
- // https://issues.dlang.org/show_bug.cgi?id=12778
- // If both x.opBinary(y) and y.opBinaryRight(x) found,
- // and they are exactly same symbol, x.opBinary(y) should be preferred.
- if (s_r && s_r == s)
- s_r = null;
- if (s_r)
- {
- // @@@DEPRECATED_2.110@@@.
- // Deprecated in 2.088, made an error in 2.100
- error(e.loc, "`%s` is obsolete. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr);
- return ErrorExp.get();
- }
- }
+ Expression result = ie ?
+ dotTemplateCall(ae.e1, Id.opSliceUnary, opToArg(sc, e.op), ie.lwr, ie.upr) :
+ dotTemplateCall(ae.e1, Id.opSliceUnary, opToArg(sc, e.op));
+
+ return Expression.combine(e0, result.expressionSemantic(sc));
}
- Expressions* args1 = new Expressions();
- Expressions* args2 = new Expressions();
- if (s || s_r)
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
{
- /* Try:
- * a.opfunc(b)
- * b.opfunc_r(a)
- * and see which is better.
+ /* Rewrite op(a[arguments]) as:
+ * op(a.aliasthis[arguments])
*/
- args1.setDim(1);
- (*args1)[0] = e.e1;
- expandTuples(args1);
- args2.setDim(1);
- (*args2)[0] = e.e2;
- expandTuples(args2);
- argsset = 1;
- MatchAccumulator m;
- if (s)
- {
- functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2));
- if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
- {
- return ErrorExp.get();
- }
- }
- FuncDeclaration lastf = m.lastf;
- if (s_r)
- {
- functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1));
- if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
- {
- return ErrorExp.get();
- }
- }
- if (m.count > 1)
- {
- // Error, ambiguous
- error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
- }
- else if (m.last == MATCH.nomatch)
- {
- if (tiargs)
- goto L1;
- m.lastf = null;
- }
- if (e.op == EXP.plusPlus || e.op == EXP.minusMinus)
- {
- // Kludge because operator overloading regards e++ and e--
- // as unary, but it's implemented as a binary.
- // Rewrite (e1 ++ e2) as e1.postinc()
- // Rewrite (e1 -- e2) as e1.postdec()
- return build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s);
- }
- else if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch)
- {
- // Rewrite (e1 op e2) as e1.opfunc(e2)
- return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
- }
- else
- {
- // Rewrite (e1 op e2) as e2.opfunc_r(e1)
- return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
- }
- }
- L1:
- version (all)
- {
- // Retained for D1 compatibility
- if (isCommutative(e.op) && !tiargs)
- {
- s = null;
- s_r = null;
- if (ad1 && id_r)
- {
- s_r = search_function(ad1, id_r);
- }
- if (ad2 && id)
- {
- s = search_function(ad2, id);
- if (s && s == s_r) // https://issues.dlang.org/show_bug.cgi?id=12778
- s = null;
- }
- if (s || s_r)
- {
- /* Try:
- * a.opfunc_r(b)
- * b.opfunc(a)
- * and see which is better.
- */
- if (!argsset)
- {
- args1.setDim(1);
- (*args1)[0] = e.e1;
- expandTuples(args1);
- args2.setDim(1);
- (*args2)[0] = e.e2;
- expandTuples(args2);
- }
- MatchAccumulator m;
- if (s_r)
- {
- functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2));
- if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
- {
- return ErrorExp.get();
- }
- }
- FuncDeclaration lastf = m.lastf;
- if (s)
- {
- functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1));
- if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
- {
- return ErrorExp.get();
- }
- }
- if (m.count > 1)
- {
- // Error, ambiguous
- error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
- }
- else if (m.last == MATCH.nomatch)
- {
- m.lastf = null;
- }
-
- if (lastf && m.lastf == lastf || !s && m.last == MATCH.nomatch)
- {
- // Rewrite (e1 op e2) as e1.opfunc_r(e2)
- return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r);
- }
- else
- {
- // Rewrite (e1 op e2) as e2.opfunc(e1)
- Expression result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s);
- // When reversing operands of comparison operators,
- // need to reverse the sense of the op
- if (pop)
- *pop = reverseRelation(e.op);
- return result;
- }
- }
- }
+ ae.e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae.e1)
+ continue;
}
+ break;
+ }
+ ae.e1 = ae1old; // recovery
+ ae.lengthVar = null;
+ }
+ e.e1 = e.e1.expressionSemantic(sc);
+ e.e1 = resolveProperties(sc, e.e1);
+ Type att = null; // first cyclic `alias this` type
+ while (1)
+ {
+ if (e.e1.isErrorExp())
+ {
+ return e.e1;
+ }
- Expression rewrittenLhs;
- if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
- {
- if (Expression result = checkAliasThisForLhs(ad1, sc, e))
- {
- /* https://issues.dlang.org/show_bug.cgi?id=19441
- *
- * alias this may not be used for partial assignment.
- * If a struct has a single member which is aliased this
- * directly or aliased to a ref getter function that returns
- * the mentioned member, then alias this may be
- * used since the object will be fully initialised.
- * If the struct is nested, the context pointer is considered
- * one of the members, hence the `ad1.fields.length == 2 && ad1.vthis`
- * condition.
- */
- if (result.op != EXP.assign)
- return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)`
+ AggregateDeclaration ad = isAggregate(e.e1.type);
+ if (!ad)
+ break;
- auto ae = result.isAssignExp();
- if (ae.e1.op != EXP.dotVariable)
- return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2`
+ /* Rewrite as:
+ * e1.opUnary!(op)()
+ */
+ if (Dsymbol fd = search_function(ad, Id.opUnary))
+ return dotTemplateCall(e.e1, Id.opUnary, opToArg(sc, e.op)).expressionSemantic(sc);
- auto dve = ae.e1.isDotVarExp();
- if (auto ad = dve.var.isMember2())
- {
- // i.e: Rewrote `e1 = e2` -> `e1.some.var = e2`
- // Ensure that `var` is the only field member in `ad`
- if (ad.fields.length == 1 || (ad.fields.length == 2 && ad.vthis))
- {
- if (dve.var == ad.aliasthis.sym)
- return result;
- }
- }
- rewrittenLhs = ae.e1;
- }
- }
- if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
- {
- if (Expression result = checkAliasThisForRhs(ad2, sc, e))
- return result;
- }
- if (rewrittenLhs)
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type))
+ {
+ /* Rewrite op(e1) as:
+ * op(e1.aliasthis)
+ */
+ //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars());
+ if (auto e1 = resolveAliasThis(sc, e.e1, true))
{
- error(e.loc, "cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`",
- e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars());
- return ErrorExp.get();
+ e.e1 = e1;
+ continue;
}
- return null;
+ break;
}
- Expression visitEqual(EqualExp e)
+ // For ++ and --, rewrites to += and -= are also tried, so don't error yet
+ if (!e.isPreExp())
{
- //printf("EqualExp::op_overload() (%s)\n", e.toChars());
- Type t1 = e.e1.type.toBasetype();
- Type t2 = e.e2.type.toBasetype();
+ error(e.loc, "operator `%s` is not defined for `%s`", EXPtoString(e.op).ptr, ad.toChars());
+ errorSupplemental(ad.loc, "perhaps overload the operator with `auto opUnary(string op : \"%s\")() {}`",
+ EXPtoString(e.op).ptr);
+ return ErrorExp.get();
+ }
- /* Array equality is handled by expressionSemantic() potentially
- * lowering to object.__equals(), which takes care of overloaded
- * operators for the element types.
- */
- if ((t1.ty == Tarray || t1.ty == Tsarray) &&
- (t2.ty == Tarray || t2.ty == Tsarray))
- {
- return null;
- }
+ break;
+ }
+ return null;
+}
- /* Check for class equality with null literal or typeof(null).
- */
- if (t1.ty == Tclass && e.e2.op == EXP.null_ ||
- t2.ty == Tclass && e.e1.op == EXP.null_)
- {
- error(e.loc, "use `%s` instead of `%s` when comparing with `null`",
- EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr,
- EXPtoString(e.op).ptr);
- return ErrorExp.get();
- }
- if (t1.ty == Tclass && t2.ty == Tnull ||
- t1.ty == Tnull && t2.ty == Tclass)
+Expression opOverloadArray(ArrayExp ae, Scope* sc)
+{
+ ae.e1 = ae.e1.expressionSemantic(sc);
+ ae.e1 = resolveProperties(sc, ae.e1);
+ Expression ae1old = ae.e1;
+ const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].isIntervalExp());
+ IntervalExp ie = null;
+ if (maybeSlice && ae.arguments.length)
+ {
+ ie = (*ae.arguments)[0].isIntervalExp();
+ }
+ Type att = null; // first cyclic `alias this` type
+ while (true)
+ {
+ if (ae.e1.isErrorExp())
+ {
+ return ae.e1;
+ }
+ Expression e0 = null;
+ Expression ae1save = ae.e1;
+ ae.lengthVar = null;
+ Type t1b = ae.e1.type.toBasetype();
+ AggregateDeclaration ad = isAggregate(t1b);
+ if (!ad)
+ {
+ // If the non-aggregate expression ae.e1 is indexable or sliceable,
+ // convert it to the corresponding concrete expression.
+ if (isIndexableNonAggregate(t1b) || ae.e1.isTypeExp())
{
- // Comparing a class with typeof(null) should not call opEquals
- return null;
- }
+ // Convert to SliceExp
+ if (maybeSlice)
+ return new SliceExp(ae.loc, ae.e1, ie).expressionSemantic(sc);
- /* Check for class equality.
+ // Convert to IndexExp
+ if (ae.arguments.length == 1)
+ return new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]).expressionSemantic(sc);
+ }
+ break;
+ }
+ if (search_function(ad, Id.opIndex))
+ {
+ // Deal with $
+ auto ae2 = resolveOpDollar(sc, ae, e0);
+ if (!ae2) // a[i..j] might be: a.opSlice(i, j)
+ goto Lfallback;
+ if (ae2.isErrorExp())
+ return ae2;
+ /* Rewrite e1[arguments] as:
+ * e1.opIndex(arguments)
*/
- if (t1.ty == Tclass && t2.ty == Tclass)
- {
- ClassDeclaration cd1 = t1.isClassHandle();
- ClassDeclaration cd2 = t2.isClassHandle();
- if (!(cd1.classKind == ClassKind.cpp || cd2.classKind == ClassKind.cpp))
- {
- /* Rewrite as:
- * .object.opEquals(e1, e2)
- */
- if (!ClassDeclaration.object)
- {
- error(e.loc, "cannot compare classes for equality because `object.Object` was not declared");
- return null;
- }
-
- Expression e1x = e.e1;
- Expression e2x = e.e2;
+ Expressions* a = ae.arguments.copy();
+ Expression result = new DotIdExp(ae.loc, ae.e1, Id.opIndex);
+ result = new CallExp(ae.loc, result, a);
+ if (maybeSlice) // a[] might be: a.opSlice()
+ result = result.trySemantic(sc);
+ else
+ result = result.expressionSemantic(sc);
- /* The explicit cast is necessary for interfaces
- * https://issues.dlang.org/show_bug.cgi?id=4088
- */
- Type to = ClassDeclaration.object.getType();
- if (cd1.isInterfaceDeclaration())
- e1x = new CastExp(e.loc, e.e1, t1.isMutable() ? to : to.constOf());
- if (cd2.isInterfaceDeclaration())
- e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf());
-
- Expression result = new IdentifierExp(e.loc, Id.empty);
- result = new DotIdExp(e.loc, result, Id.object);
- result = new DotIdExp(e.loc, result, Id.eq);
- result = new CallExp(e.loc, result, e1x, e2x);
- if (e.op == EXP.notEqual)
- result = new NotExp(e.loc, result);
- result = result.expressionSemantic(sc);
- return result;
- }
- }
+ if (result)
+ return Expression.combine(e0, result);
+ }
+ Lfallback:
+ if (maybeSlice && ae.e1.isTypeExp())
+ {
+ Expression result = new SliceExp(ae.loc, ae.e1, ie);
+ result = result.expressionSemantic(sc);
+ return Expression.combine(e0, result);
+ }
+ if (maybeSlice && search_function(ad, Id.opSlice))
+ {
+ // Deal with $
+ auto ae2 = resolveOpDollar(sc, ae, ie, e0);
- if (Expression result = compare_overload(e, sc, Id.eq, null))
+ if (ae2.isErrorExp())
{
- if (lastComma(result).op == EXP.call && e.op == EXP.notEqual)
- {
- result = new NotExp(result.loc, result);
- result = result.expressionSemantic(sc);
- }
- return result;
- }
+ if (!e0 && !search_function(ad, Id.dollar))
+ ad.loc.errorSupplemental("perhaps define `opDollar` for `%s`", ad.toChars());
- /* Check for pointer equality.
- */
- if (t1.ty == Tpointer || t2.ty == Tpointer)
- {
- /* Rewrite:
- * ptr1 == ptr2
- * as:
- * ptr1 is ptr2
- *
- * This is just a rewriting for deterministic AST representation
- * as the backend input.
- */
- auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
- Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2);
- return r.expressionSemantic(sc);
+ return ae2;
}
-
- /* Check for struct equality without opEquals.
+ /* Rewrite a[i..j] as:
+ * a.opSlice(i, j)
*/
- if (t1.ty == Tstruct && t2.ty == Tstruct)
+ auto a = new Expressions();
+ if (ie)
{
- auto sd = t1.isTypeStruct().sym;
- if (sd != t2.isTypeStruct().sym)
- return null;
-
- import dmd.clone : needOpEquals;
- if (global.params.fieldwise != FeatureState.enabled && !needOpEquals(sd))
- {
- // Use bitwise equality.
- auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
- Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2);
- return r.expressionSemantic(sc);
- }
-
- /* Do memberwise equality.
- * https://dlang.org/spec/expression.html#equality_expressions
- * Rewrite:
- * e1 == e2
- * as:
- * e1.tupleof == e2.tupleof
- *
- * If sd is a nested struct, and if it's nested in a class, it will
- * also compare the parent class's equality. Otherwise, compares
- * the identity of parent context through void*.
- */
- e = e.copy().isEqualExp();
- e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof);
- e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof);
-
- auto sc2 = sc.push();
- sc2.flags |= SCOPE.noaccesscheck;
- Expression r = e.expressionSemantic(sc2);
- sc2.pop();
- return r;
+ a.push(ie.lwr);
+ a.push(ie.upr);
}
-
- /* Check for tuple equality.
+ Expression result = new DotIdExp(ae.loc, ae.e1, Id.opSlice);
+ result = new CallExp(ae.loc, result, a);
+ result = result.expressionSemantic(sc);
+ return Expression.combine(e0, result);
+ }
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
+ {
+ //printf("att arr e1 = %s\n", this.e1.type.toChars());
+ /* Rewrite op(a[arguments]) as:
+ * op(a.aliasthis[arguments])
*/
- if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple)
- {
- auto tup1 = e.e1.isTupleExp();
- auto tup2 = e.e2.isTupleExp();
- size_t dim = tup1.exps.length;
- if (dim != tup2.exps.length)
- {
- error(e.loc, "mismatched sequence lengths, `%d` and `%d`",
- cast(int)dim, cast(int)tup2.exps.length);
- return ErrorExp.get();
- }
+ ae.e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae.e1)
+ continue;
+ }
+ break;
+ }
+ ae.e1 = ae1old; // recovery
+ ae.lengthVar = null;
+ return null;
+}
- Expression result;
- if (dim == 0)
- {
- // zero-length tuple comparison should always return true or false.
- result = IntegerExp.createBool(e.op == EXP.equal);
- }
- else
- {
- for (size_t i = 0; i < dim; i++)
- {
- auto ex1 = (*tup1.exps)[i];
- auto ex2 = (*tup2.exps)[i];
- auto eeq = new EqualExp(e.op, e.loc, ex1, ex2);
-
- if (!result)
- result = eeq;
- else if (e.op == EXP.equal)
- result = new LogicalExp(e.loc, EXP.andAnd, result, eeq);
- else
- result = new LogicalExp(e.loc, EXP.orOr, result, eeq);
- }
- assert(result);
- }
- result = Expression.combine(tup1.e0, tup2.e0, result);
- result = result.expressionSemantic(sc);
+/***********************************************
+ * This is mostly the same as opOverloadUnary but has
+ * a different rewrite.
+ */
+Expression opOverloadCast(CastExp e, Scope* sc, Type att = null)
+{
+ AggregateDeclaration ad = isAggregate(e.e1.type);
+ if (!ad)
+ return null;
- return result;
+ // Rewrite as: e1.opCast!(T)()
+ if (Dsymbol fd = search_function(ad, Id.opCast))
+ {
+ version (all)
+ {
+ // Backwards compatibility with D1 if opCast is a function, not a template
+ if (fd.isFuncDeclaration())
+ {
+ // Rewrite as: e1.opCast()
+ return build_overload(e.loc, sc, e.e1, null, fd);
}
- return null;
}
-
- Expression visitCmp(CmpExp e)
+ auto tiargs = new Objects();
+ tiargs.push(e.to);
+ return dotTemplateCall(e.e1, Id.opCast, tiargs).expressionSemantic(sc);
+ }
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type))
+ {
+ // Rewrite `e1.opCast()` as `e1.aliasthis.opCast()`
+ if (auto e1 = resolveAliasThis(sc, e.e1, true))
{
- //printf("CmpExp:: () (%s)\n", e.toChars());
- return compare_overload(e, sc, Id.cmp, pop);
+ CastExp result = e.copy().isCastExp();
+ result.e1 = e1;
+ return result.opOverloadCast(sc, att);
}
+ }
+ return null;
+}
- /*********************************
- * Operator overloading for op=
- */
- Expression visitBinAssign(BinAssignExp e)
+// When no operator overload functions are found for `e`, recursively try with `alias this`
+// Returns: `null` when still no overload found, otherwise resolved lowering
+Expression binAliasThis(BinExp e, Scope* sc, Type[2] aliasThisStop)
+{
+ AggregateDeclaration ad1 = isAggregate(e.e1.type);
+ AggregateDeclaration ad2 = isAggregate(e.e2.type);
+ Expression rewrittenLhs;
+ if (!(e.isAssignExp && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
+ {
+ if (Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop))
{
- //printf("BinAssignExp::op_overload() (%s)\n", e.toChars());
- if (auto ae = e.e1.isArrayExp())
- {
- ae.e1 = ae.e1.expressionSemantic(sc);
- ae.e1 = resolveProperties(sc, ae.e1);
- Expression ae1old = ae.e1;
- const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
- IntervalExp ie = null;
- if (maybeSlice && ae.arguments.length)
- {
- ie = (*ae.arguments)[0].isIntervalExp();
- }
- Type att = null; // first cyclic `alias this` type
- while (true)
- {
- if (ae.e1.op == EXP.error)
- {
- return ae.e1;
- }
- Expression e0 = null;
- Expression ae1save = ae.e1;
- ae.lengthVar = null;
- Type t1b = ae.e1.type.toBasetype();
- AggregateDeclaration ad = isAggregate(t1b);
- if (!ad)
- break;
- if (search_function(ad, Id.opIndexOpAssign))
- {
- // Deal with $
- Expression result = resolveOpDollar(sc, ae, &e0);
- if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
- goto Lfallback;
- if (result.op == EXP.error)
- return result;
- result = e.e2.expressionSemantic(sc);
- if (result.op == EXP.error)
- return result;
- e.e2 = result;
- /* Rewrite a[arguments] op= e2 as:
- * a.opIndexOpAssign!(op)(e2, arguments)
- */
- Expressions* a = ae.arguments.copy();
- a.insert(0, e.e2);
- Objects* tiargs = opToArg(sc, e.op);
- result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexOpAssign, tiargs);
- result = new CallExp(e.loc, result, a);
- if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2)
- result = result.trySemantic(sc);
- else
- result = result.expressionSemantic(sc);
- if (result)
- {
- return Expression.combine(e0, result);
- }
- }
- Lfallback:
- if (maybeSlice && search_function(ad, Id.opSliceOpAssign))
- {
- // Deal with $
- Expression result = resolveOpDollar(sc, ae, ie, &e0);
- if (result.op == EXP.error)
- return result;
- result = e.e2.expressionSemantic(sc);
- if (result.op == EXP.error)
- return result;
- e.e2 = result;
- /* Rewrite (a[i..j] op= e2) as:
- * a.opSliceOpAssign!(op)(e2, i, j)
- */
- auto a = new Expressions();
- a.push(e.e2);
- if (ie)
- {
- a.push(ie.lwr);
- a.push(ie.upr);
- }
- Objects* tiargs = opToArg(sc, e.op);
- result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceOpAssign, tiargs);
- result = new CallExp(e.loc, result, a);
- result = result.expressionSemantic(sc);
- result = Expression.combine(e0, result);
- return result;
- }
- // Didn't find it. Forward to aliasthis
- if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
- {
- /* Rewrite (a[arguments] op= e2) as:
- * a.aliasthis[arguments] op= e2
- */
- ae.e1 = resolveAliasThis(sc, ae1save, true);
- if (ae.e1)
- continue;
- }
- break;
- }
- ae.e1 = ae1old; // recovery
- ae.lengthVar = null;
- }
- Expression result = e.binSemanticProp(sc);
- if (result)
- return result;
- // Don't attempt 'alias this' if an error occurred
- if (e.e1.type.ty == Terror || e.e2.type.ty == Terror)
- {
- return ErrorExp.get();
- }
- Identifier id = opId(e);
- Expressions* args2 = new Expressions();
- AggregateDeclaration ad1 = isAggregate(e.e1.type);
- Dsymbol s = null;
- Objects* tiargs = null;
- /* Try opOpAssign
+ /* https://issues.dlang.org/show_bug.cgi?id=19441
+ *
+ * alias this may not be used for partial assignment.
+ * If a struct has a single member which is aliased this
+ * directly or aliased to a ref getter function that returns
+ * the mentioned member, then alias this may be
+ * used since the object will be fully initialised.
+ * If the struct is nested, the context pointer is considered
+ * one of the members, hence the `ad1.fields.length == 2 && ad1.vthis`
+ * condition.
*/
- if (ad1)
- {
- s = search_function(ad1, Id.opOpAssign);
- if (s && !s.isTemplateDeclaration())
- {
- error(e.loc, "`%s.opOpAssign` isn't a template", e.e1.toChars());
- return ErrorExp.get();
- }
- }
- // Set tiargs, the template argument list, which will be the operator string
- if (s)
- {
- id = Id.opOpAssign;
- tiargs = opToArg(sc, e.op);
- }
+ auto ae = result.isAssignExp();
+ if (!ae)
+ return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)`
- // Try D1-style operator overload, deprecated
- if (!s && ad1 && id)
- {
- s = search_function(ad1, id);
- if (s)
- {
- // @@@DEPRECATED_2.110@@@.
- // Deprecated in 2.088, made an error in 2.100
- scope char[] op = EXPtoString(e.op).dup;
- op[$-1] = '\0'; // remove trailing `=`
- error(e.loc, "`%s` is obsolete. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr);
- return ErrorExp.get();
- }
- }
+ auto dve = ae.e1.isDotVarExp();
+ if (!dve)
+ return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2`
- if (s)
+ if (auto ad = dve.var.isMember2())
{
- /* Try:
- * a.opOpAssign(b)
- */
- args2.setDim(1);
- (*args2)[0] = e.e2;
- expandTuples(args2);
- MatchAccumulator m;
- functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2));
- if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
- {
- return ErrorExp.get();
- }
- if (m.count > 1)
- {
- // Error, ambiguous
- error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
- }
- else if (m.last == MATCH.nomatch)
+ // i.e: Rewrote `e1 = e2` -> `e1.some.var = e2`
+ // Ensure that `var` is the only field member in `ad`
+ if (ad.fields.length == 1 || (ad.fields.length == 2 && ad.vthis))
{
- if (tiargs)
- goto L1;
- m.lastf = null;
+ if (dve.var == ad.aliasthis.sym)
+ return result;
}
- // Rewrite (e1 op e2) as e1.opOpAssign(e2)
- return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
}
- L1:
- result = checkAliasThisForLhs(ad1, sc, e);
- if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs
- return result;
+ rewrittenLhs = ae.e1;
+ }
+ }
+ if (!(e.isAssignExp && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
+ {
+ if (Expression result = checkAliasThisForRhs(ad2, sc, e, aliasThisStop))
+ return result;
+ }
+ if (rewrittenLhs)
+ {
+ error(e.loc, "cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`",
+ e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars());
+ return ErrorExp.get();
+ }
+ return null;
+}
- return checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
+Expression opOverloadAssign(AssignExp e, Scope* sc, Type[2] aliasThisStop)
+{
+ AggregateDeclaration ad1 = isAggregate(e.e1.type);
+ AggregateDeclaration ad2 = isAggregate(e.e2.type);
+ if (ad1 == ad2)
+ {
+ StructDeclaration sd = ad1.isStructDeclaration();
+ if (sd &&
+ (!sd.hasIdentityAssign ||
+ /* Do a blit if we can and the rvalue is something like .init,
+ * where a postblit is not necessary.
+ */
+ (sd.hasBlitAssign && !e.e2.isLvalue())))
+ {
+ /* This is bitwise struct assignment. */
+ return null;
}
+ }
+ Dsymbol s = search_function(ad1, Id.opAssign);
- if (pop)
- *pop = e.op;
+ bool choseReverse;
+ if (auto result = pickBestBinaryOverload(sc, null, s, null, e, choseReverse))
+ return result;
- switch (e.op)
- {
- case EXP.cast_ : return visitCast(e.isCastExp());
- case EXP.array : return visitArray(e.isArrayExp());
+ return binAliasThis(e, sc, aliasThisStop);
+}
- case EXP.notEqual :
- case EXP.equal : return visitEqual(e.isEqualExp());
+Expression opOverloadBinary(BinExp e, Scope* sc, Type[2] aliasThisStop)
+{
+ if (Expression err = binSemanticProp(e, sc))
+ return err;
- case EXP.lessOrEqual :
- case EXP.greaterThan :
- case EXP.greaterOrEqual:
- case EXP.lessThan : return visitCmp(cast(CmpExp)e);
+ AggregateDeclaration ad1 = isAggregate(e.e1.type);
+ AggregateDeclaration ad2 = isAggregate(e.e2.type);
- default:
- if (auto ex = e.isBinAssignExp()) return visitBinAssign(ex);
- if (auto ex = e.isBinExp()) return visitBin(ex);
- if (auto ex = e.isUnaExp()) return visitUna(ex);
- return visit(e);
+ // Try opBinary and opBinaryRight
+ Dsymbol s = search_function(ad1, Id.opBinary);
+ if (s && !s.isTemplateDeclaration())
+ {
+ error(e.e1.loc, "`%s.opBinary` isn't a template", e.e1.toChars());
+ return ErrorExp.get();
+ }
+
+ Dsymbol s_r = search_function(ad2, Id.opBinaryRight);
+ if (s_r && !s_r.isTemplateDeclaration())
+ {
+ error(e.e2.loc, "`%s.opBinaryRight` isn't a template", e.e2.toChars());
+ return ErrorExp.get();
}
+ if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778
+ s_r = null;
+
+ bool choseReverse;
+ if (auto result = pickBestBinaryOverload(sc, opToArg(sc, e.op), s, s_r, e, choseReverse))
+ return result;
+
+ return binAliasThis(e, sc, aliasThisStop);
}
-/******************************************
- * Common code for overloading of EqualExp and CmpExp
+/**
+ * If applicable, print an error relating to implementing / fixing `opBinary` functions.
+ * Params:
+ * e = binary operation
+ * sc = scope to try `opBinary!""` semantic in for error messages
+ * Returns: `true` when an error related to `opBinary` was printed
*/
-private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop)
+bool suggestBinaryOverloads(BinExp e, Scope* sc)
{
- //printf("BinExp::compare_overload(id = %s) %s\n", id.toChars(), e.toChars());
+ if (!e.op.hasOpBinary)
+ return false;
+
AggregateDeclaration ad1 = isAggregate(e.e1.type);
AggregateDeclaration ad2 = isAggregate(e.e2.type);
- Dsymbol s = null;
- Dsymbol s_r = null;
+
if (ad1)
{
- s = search_function(ad1, id);
+ if (Dsymbol s = search_function(ad1, Id.opBinary))
+ {
+ // This expressionSemantic will fail, otherwise operator overloading would have succeeded before
+ dotTemplateCall(e.e1, Id.opBinary, opToArg(sc, e.op), e.e2).expressionSemantic(sc);
+ errorSupplemental(s.loc, "`opBinary` defined here");
+ return true;
+ }
+ error(e.loc, "operator `%s` is not defined for type `%s`", EXPtoString(e.op).ptr, e.e1.type.toChars);
+ errorSupplemental(ad1.loc, "perhaps overload the operator with `auto opBinary(string op : \"%s\")(%s rhs) {}`", EXPtoString(e.op).ptr, e.e2.type.toChars);
+ return true;
}
- if (ad2)
+ else if (ad2)
{
- s_r = search_function(ad2, id);
- if (s == s_r)
- s_r = null;
+ if (Dsymbol s_r = search_function(ad1, Id.opBinaryRight))
+ {
+ dotTemplateCall(e.e2, Id.opBinaryRight, opToArg(sc, e.op), e.e1).expressionSemantic(sc);
+ errorSupplemental(s_r.loc, "`opBinaryRight` defined here");
+ return true;
+ }
+ error(e.loc, "operator `%s` is not defined for type `%s`", EXPtoString(e.op).ptr, e.e2.type.toChars);
+ errorSupplemental(ad2.loc, "perhaps overload the operator with `auto opBinaryRight(string op : \"%s\")(%s rhs) {}`", EXPtoString(e.op).ptr, e.e1.type.toChars);
+ return true;
}
- Objects* tiargs = null;
- if (s || s_r)
+ return false;
+}
+
+/**
+ * If applicable, print an error relating to implementing / fixing `opOpAssign` or `opUnary` functions.
+ * Params:
+ * exp = binary operation
+ * sc = scope to try `opOpAssign!""` semantic in for error messages
+ * parent = if `exp` was lowered from this `PreExp` or `PostExp`, mention `opUnary` as well
+ * Returns: `true` when an error related to `opOpAssign` was printed
+ */
+bool suggestOpOpAssign(BinAssignExp exp, Scope* sc, Expression parent)
+{
+ auto ad = isAggregate(exp.e1.type);
+ if (!ad)
+ return false;
+
+ if (parent && (parent.isPreExp() || parent.isPostExp()))
+ {
+ error(exp.loc, "operator `%s` not supported for `%s` of type `%s`", EXPtoString(parent.op).ptr, exp.e1.toChars(), ad.toChars());
+ errorSupplemental(ad.loc,
+ "perhaps implement `auto opUnary(string op : \"%s\")() {}`"~
+ " or `auto opOpAssign(string op : \"%s\")(int) {}`",
+ EXPtoString(stripAssignOp(parent.op)).ptr,
+ EXPtoString(stripAssignOp(exp.op)).ptr
+ );
+ return true;
+ }
+
+ if (const s = search_function(ad, Id.opOpAssign))
+ {
+ // This expressionSemantic will fail, otherwise operator overloading would have succeeded before
+ dotTemplateCall(exp.e1, Id.opOpAssign, opToArg(sc, exp.op), exp.e2).expressionSemantic(sc);
+ }
+ else
+ {
+ error(exp.loc, "operator `%s` not supported for `%s` of type `%s`", EXPtoString(exp.op).ptr, exp.e1.toChars(), ad.toChars());
+ errorSupplemental(ad.loc, "perhaps implement `auto opOpAssign(string op : \"%s\")(%s) {}`",
+ EXPtoString(stripAssignOp(exp.op)).ptr, exp.e2.type.toChars());
+ }
+ return true;
+}
+
+// Helper to construct e.id!tiargs(args), e.g. `lhs.opBinary!"+"(rhs)`
+private Expression dotTemplateCall(Expression e, Identifier id, Objects* tiargs, Expression[] args...)
+{
+ auto ti = new DotTemplateInstanceExp(e.loc, e, id, tiargs);
+ auto expressions = new Expressions();
+ expressions.pushSlice(args);
+ return new CallExp(e.loc, ti, expressions);
+}
+
+Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop)
+{
+ Type t1 = e.e1.type.toBasetype();
+ Type t2 = e.e2.type.toBasetype();
+
+ /* Array equality is handled by expressionSemantic() potentially
+ * lowering to object.__equals(), which takes care of overloaded
+ * operators for the element types.
+ */
+ if (t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray())
+ {
+ return null;
+ }
+
+ /* Check for class equality with null literal or typeof(null).
+ */
+ if (t1.isTypeClass() && e.e2.isNullExp() ||
+ t2.isTypeClass() && e.e1.isNullExp())
+ {
+ error(e.loc, "use `%s` instead of `%s` when comparing with `null`",
+ EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr,
+ EXPtoString(e.op).ptr);
+ return ErrorExp.get();
+ }
+ if (t1.isTypeClass() && t2.isTypeNull() ||
+ t1.isTypeNull() && t2.isTypeClass())
+ {
+ // Comparing a class with typeof(null) should not call opEquals
+ return null;
+ }
+
+ /* Check for class equality.
+ */
+ if (t1.isTypeClass() && t2.isTypeClass())
+ {
+ ClassDeclaration cd1 = t1.isClassHandle();
+ ClassDeclaration cd2 = t2.isClassHandle();
+ if (!(cd1.classKind == ClassKind.cpp || cd2.classKind == ClassKind.cpp))
+ {
+ /* Rewrite as:
+ * .object.opEquals(e1, e2)
+ */
+ if (!ClassDeclaration.object)
+ {
+ error(e.loc, "cannot compare classes for equality because `object.Object` was not declared");
+ return null;
+ }
+
+ Expression e1x = e.e1;
+ Expression e2x = e.e2;
+
+ /* The explicit cast is necessary for interfaces
+ * https://issues.dlang.org/show_bug.cgi?id=4088
+ */
+ Type to = ClassDeclaration.object.getType();
+ if (cd1.isInterfaceDeclaration())
+ e1x = new CastExp(e.loc, e.e1, t1.isMutable() ? to : to.constOf());
+ if (cd2.isInterfaceDeclaration())
+ e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf());
+
+ Expression result = new IdentifierExp(e.loc, Id.empty);
+ result = new DotIdExp(e.loc, result, Id.object);
+ result = new DotIdExp(e.loc, result, Id.opEquals);
+ result = new CallExp(e.loc, result, e1x, e2x);
+ if (e.op == EXP.notEqual)
+ result = new NotExp(e.loc, result);
+ result = result.expressionSemantic(sc);
+ return result;
+ }
+ }
+
+ EXP cmpOp;
+ if (Expression result = compare_overload(e, sc, Id.opEquals, cmpOp, aliasThisStop))
{
- /* Try:
- * a.opEquals(b)
- * b.opEquals(a)
- * and see which is better.
+ if (lastComma(result).isCallExp() && e.op == EXP.notEqual)
+ {
+ result = new NotExp(result.loc, result);
+ result = result.expressionSemantic(sc);
+ }
+ return result;
+ }
+
+ /* Check for pointer equality.
+ */
+ if (t1.isTypePointer() || t2.isTypePointer())
+ {
+ /* Rewrite:
+ * ptr1 == ptr2
+ * as:
+ * ptr1 is ptr2
+ *
+ * This is just a rewriting for deterministic AST representation
+ * as the backend input.
*/
- Expressions* args1 = new Expressions(1);
- (*args1)[0] = e.e1;
- expandTuples(args1);
- Expressions* args2 = new Expressions(1);
- (*args2)[0] = e.e2;
- expandTuples(args2);
- MatchAccumulator m;
- if (0 && s && s_r)
+ auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
+ Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2);
+ return r.expressionSemantic(sc);
+ }
+
+ /* Check for struct equality without opEquals.
+ */
+ if (t1.isTypeStruct() && t2.isTypeStruct())
+ {
+ auto sd = t1.isTypeStruct().sym;
+ if (sd != t2.isTypeStruct().sym)
+ return null;
+
+ import dmd.clone : needOpEquals;
+ if (!sc.previews.fieldwise && !needOpEquals(sd))
{
- printf("s : %s\n", s.toPrettyChars());
- printf("s_r: %s\n", s_r.toPrettyChars());
+ // Use bitwise equality.
+ auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
+ Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2);
+ return r.expressionSemantic(sc);
}
- if (s)
+
+ /* Do memberwise equality.
+ * https://dlang.org/spec/expression.html#equality_expressions
+ * Rewrite:
+ * e1 == e2
+ * as:
+ * e1.tupleof == e2.tupleof
+ *
+ * If sd is a nested struct, and if it's nested in a class, it will
+ * also compare the parent class's equality. Otherwise, compares
+ * the identity of parent context through void*.
+ */
+ e = e.copy().isEqualExp();
+ e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof);
+ e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof);
+
+ auto sc2 = sc.push();
+ sc2.noAccessCheck = true;
+ Expression r = e.expressionSemantic(sc2);
+ sc2.pop();
+ return r;
+ }
+
+ /* Check for tuple equality.
+ */
+ auto tup1 = e.e1.isTupleExp();
+ auto tup2 = e.e2.isTupleExp();
+ if (tup1 && tup2)
+ {
+ size_t dim = tup1.exps.length;
+ if (dim != tup2.exps.length)
{
- functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2));
- if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
- return ErrorExp.get();
+ error(e.loc, "mismatched sequence lengths, `%d` and `%d`",
+ cast(int)dim, cast(int)tup2.exps.length);
+ return ErrorExp.get();
}
- FuncDeclaration lastf = m.lastf;
- int count = m.count;
- if (s_r)
+
+ Expression result;
+ if (dim == 0)
{
- functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1));
- if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
- return ErrorExp.get();
+ // zero-length tuple comparison should always return true or false.
+ result = IntegerExp.createBool(e.op == EXP.equal);
}
- if (m.count > 1)
+ else
{
- /* The following if says "not ambiguous" if there's one match
- * from s and one from s_r, in which case we pick s.
- * This doesn't follow the spec, but is a workaround for the case
- * where opEquals was generated from templates and we cannot figure
- * out if both s and s_r came from the same declaration or not.
- * The test case is:
- * import std.typecons;
- * void main() {
- * assert(tuple("has a", 2u) == tuple("has a", 1));
- * }
- */
- if (!(m.lastf == lastf && m.count == 2 && count == 1))
+ for (size_t i = 0; i < dim; i++)
{
- // Error, ambiguous
- error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
+ auto ex1 = (*tup1.exps)[i];
+ auto ex2 = (*tup2.exps)[i];
+ auto eeq = new EqualExp(e.op, e.loc, ex1, ex2);
+
+ if (!result)
+ result = eeq;
+ else if (e.op == EXP.equal)
+ result = new LogicalExp(e.loc, EXP.andAnd, result, eeq);
+ else
+ result = new LogicalExp(e.loc, EXP.orOr, result, eeq);
}
+ assert(result);
}
- else if (m.last == MATCH.nomatch)
+ result = Expression.combine(tup1.e0, tup2.e0, result);
+ result = result.expressionSemantic(sc);
+
+ return result;
+ }
+ return null;
+}
+
+Expression opOverloadCmp(CmpExp exp, Scope* sc, Type[2] aliasThisStop)
+{
+ //printf("CmpExp:: () (%s)\n", e.toChars());
+ EXP cmpOp = exp.op;
+ auto e = compare_overload(exp, sc, Id.opCmp, cmpOp, aliasThisStop);
+ if (!e)
+ return null;
+
+ if (!e.type.isScalar() && e.type.equals(exp.e1.type))
+ {
+ error(e.loc, "recursive `opCmp` expansion");
+ return ErrorExp.get();
+ }
+ if (!e.isCallExp())
+ return e;
+
+ Type t1 = exp.e1.type.toBasetype();
+ Type t2 = exp.e2.type.toBasetype();
+ if (!t1.isTypeClass() || !t2.isTypeClass())
+ {
+ return new CmpExp(cmpOp, exp.loc, e, IntegerExp.literal!0).expressionSemantic(sc);
+ }
+
+ // Lower to object.__cmp(e1, e2)
+ Expression cl = new IdentifierExp(exp.loc, Id.empty);
+ cl = new DotIdExp(exp.loc, cl, Id.object);
+ cl = new DotIdExp(exp.loc, cl, Id.__cmp);
+ cl = cl.expressionSemantic(sc);
+
+ auto arguments = new Expressions();
+ // Check if op_overload found a better match by calling e2.opCmp(e1)
+ // If the operands were swapped, then the result must be reversed
+ // e1.opCmp(e2) == -e2.opCmp(e1)
+ // cmpop takes care of this
+ if (exp.op == cmpOp)
+ {
+ arguments.push(exp.e1);
+ arguments.push(exp.e2);
+ }
+ else
+ {
+ // Use better match found by op_overload
+ arguments.push(exp.e2);
+ arguments.push(exp.e1);
+ }
+
+ cl = new CallExp(e.loc, cl, arguments);
+ cl = new CmpExp(cmpOp, exp.loc, cl, new IntegerExp(0));
+ return cl.expressionSemantic(sc);
+}
+
+/*********************************
+ * Operator overloading for op=
+ */
+Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisStop)
+{
+ if (auto ae = e.e1.isArrayExp())
+ {
+ ae.e1 = ae.e1.expressionSemantic(sc);
+ ae.e1 = resolveProperties(sc, ae.e1);
+ Expression ae1old = ae.e1;
+ const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].isIntervalExp());
+ IntervalExp ie = null;
+ if (maybeSlice && ae.arguments.length)
{
- m.lastf = null;
+ ie = (*ae.arguments)[0].isIntervalExp();
}
- Expression result;
- if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch)
+ Type att = null; // first cyclic `alias this` type
+ while (true)
{
- // Rewrite (e1 op e2) as e1.opfunc(e2)
- result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
+ if (ae.e1.isErrorExp())
+ return ae.e1;
+
+ Expression e0 = null;
+ Expression ae1save = ae.e1;
+ ae.lengthVar = null;
+ AggregateDeclaration ad = isAggregate(ae.e1.type);
+ if (!ad)
+ break;
+ if (search_function(ad, Id.opIndexOpAssign))
+ {
+ // Deal with $
+ Expression ae2 = resolveOpDollar(sc, ae, e0);
+ if (!ae2) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
+ goto Lfallback;
+ if (ae2.isErrorExp())
+ return ae2;
+ e.e2 = e.e2.expressionSemantic(sc);
+ if (e.e2.isErrorExp())
+ return e.e2;
+
+ /* Rewrite a[arguments] op= e2 as:
+ * a.opIndexOpAssign!(op)(e2, arguments)
+ */
+ Expressions* a = ae.arguments.copy();
+ a.insert(0, e.e2);
+ Expression result = dotTemplateCall(ae.e1, Id.opIndexOpAssign, opToArg(sc, e.op), (*a)[]);
+ if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2)
+ result = result.trySemantic(sc);
+ else
+ result = result.expressionSemantic(sc);
+
+ if (result)
+ return Expression.combine(e0, result);
+ }
+ Lfallback:
+ if (maybeSlice && search_function(ad, Id.opSliceOpAssign))
+ {
+ // Deal with $
+ Expression ae2 = resolveOpDollar(sc, ae, ie, e0);
+ if (ae2.isErrorExp())
+ return ae2;
+
+ e.e2 = e.e2.expressionSemantic(sc);
+ if (e.e2.isErrorExp())
+ return e.e2;
+
+ /* Rewrite (a[i..j] op= e2) as:
+ * a.opSliceOpAssign!(op)(e2, i, j)
+ */
+ auto result = ie ?
+ dotTemplateCall(ae.e1, Id.opSliceOpAssign, opToArg(sc, e.op), e.e2, ie.lwr, ie.upr) :
+ dotTemplateCall(ae.e1, Id.opSliceOpAssign, opToArg(sc, e.op), e.e2);
+
+ return Expression.combine(e0, result.expressionSemantic(sc));
+ }
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
+ {
+ /* Rewrite (a[arguments] op= e2) as:
+ * a.aliasthis[arguments] op= e2
+ */
+ ae.e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae.e1)
+ continue;
+ }
+ break;
}
- else
+ ae.e1 = ae1old; // recovery
+ ae.lengthVar = null;
+ }
+
+ if (Expression result = e.binSemanticProp(sc))
+ return result;
+
+ // Don't attempt 'alias this' if an error occurred
+ if (e.e1.type.isTypeError() || e.e2.type.isTypeError())
+ return ErrorExp.get();
+
+ AggregateDeclaration ad1 = isAggregate(e.e1.type);
+ Dsymbol s = search_function(ad1, Id.opOpAssign);
+ if (s && !s.isTemplateDeclaration())
+ {
+ error(e.loc, "`%s.opOpAssign` isn't a template", e.e1.toChars());
+ return ErrorExp.get();
+ }
+
+ bool choseReverse;
+ if (auto res = pickBestBinaryOverload(sc, opToArg(sc, e.op), s, null, e, choseReverse))
+ return res;
+
+ Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop);
+ if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs
+ return result;
+
+ return checkAliasThisForRhs(isAggregate(e.e2.type), sc, e, aliasThisStop);
+}
+
+/**
+Given symbols `s` and `s_r`, try to instantiate `e.e1.s!tiargs(e.e2)` and `e.e2.s_r!tiargs(e.e1)`,
+and return the one with the best match level.
+
+Params:
+ sc = scope
+ tiargs = (optional) template arguments to instantiate symbols with
+ s = (optional) symbol of straightforward template (e.g. opBinary)
+ s_r = (optional) symbol of reversed template (e.g. opBinaryRight)
+ e = binary expression being overloaded, supplying arguments to the function calls
+ choseReverse = set to true when `s_r` was chosen instead of `s`
+Returns:
+ Resulting operator overload function call, or `null` if neither symbol worked
+*/
+private Expression pickBestBinaryOverload(Scope* sc, Objects* tiargs, Dsymbol s, Dsymbol s_r, BinExp e, out bool choseReverse)
+{
+ if (!s && !s_r)
+ return null;
+
+ Expressions* args1 = new Expressions(1);
+ (*args1)[0] = e.e1;
+ expandTuples(args1);
+ Expressions* args2 = new Expressions(1);
+ (*args2)[0] = e.e2;
+ expandTuples(args2);
+ MatchAccumulator m;
+
+ if (s)
+ {
+ functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2), null);
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
+ return ErrorExp.get();
+ }
+ FuncDeclaration lastf = m.lastf;
+ int count = m.count;
+ if (s_r)
+ {
+ functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1), null);
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
+ return ErrorExp.get();
+ }
+ if (m.count > 1)
+ {
+ /* The following if says "not ambiguous" if there's one match
+ * from s and one from s_r, in which case we pick s.
+ * This doesn't follow the spec, but is a workaround for the case
+ * where opEquals was generated from templates and we cannot figure
+ * out if both s and s_r came from the same declaration or not.
+ * The test case is:
+ * import std.typecons;
+ * void main() {
+ * assert(tuple("has a", 2u) == tuple("has a", 1));
+ * }
+ */
+ if (!(m.lastf == lastf && m.count == 2 && count == 1))
{
- // Rewrite (e1 op e2) as e2.opfunc_r(e1)
- result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
- // When reversing operands of comparison operators,
- // need to reverse the sense of the op
- if (pop)
- *pop = reverseRelation(e.op);
+ // Error, ambiguous
+ error(e.loc, "overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
}
- return result;
}
+ else if (m.last == MATCH.nomatch)
+ {
+ if (tiargs)
+ return null;
+ m.lastf = null;
+ }
+
+ if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch)
+ {
+ choseReverse = false;
+ // Rewrite (e1 op e2) as e1.opfunc(e2)
+ return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
+ }
+ else
+ {
+ choseReverse = true;
+ // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+ return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
+ }
+}
+
+/******************************************
+ * Common code for overloading of EqualExp and CmpExp
+ */
+private Expression compare_overload(BinExp e, Scope* sc, Identifier id, ref EXP cmpOp, Type[2] aliasThisStop)
+{
+ //printf("BinExp::compare_overload(id = %s) %s\n", id.toChars(), e.toChars());
+ AggregateDeclaration ad1 = isAggregate(e.e1.type);
+ AggregateDeclaration ad2 = isAggregate(e.e2.type);
+ Dsymbol s = search_function(ad1, id);
+ Dsymbol s_r = search_function(ad2, id);
+
+ if (s == s_r)
+ s_r = null;
+
+ bool choseReverse;
+ if (auto res = pickBestBinaryOverload(sc, null, s, s_r, e, choseReverse))
+ {
+ if (choseReverse)
+ cmpOp = reverseRelation(e.op);
+ return res;
+ }
+
/*
* https://issues.dlang.org/show_bug.cgi?id=16657
* at this point, no matching opEquals was found for structs,
* so we should not follow the alias this comparison code.
*/
- if ((e.op == EXP.equal || e.op == EXP.notEqual) && ad1 == ad2)
+ if (e.isEqualExp() && ad1 == ad2)
+ return null;
+ Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop);
+ if (result)
+ return result;
+
+ result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e, aliasThisStop);
+ if (result)
+ return result;
+
+ if (s || s_r)
return null;
- Expression result = checkAliasThisForLhs(ad1, sc, e);
- return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
+
+ Expression suggestOverloading(Expression other, AggregateDeclaration ad)
+ {
+ error(e.loc, "no operator `%s` for type `%s`", EXPtoString(e.op).ptr, ad.toChars);
+ string op = e.isEqualExp() ? "bool" : "int";
+ errorSupplemental(ad.loc, "perhaps overload it with `%.*s %s(%s other) const {}`", op.fTuple.expand, id.toChars, other.type.toChars);
+ return ErrorExp.get();
+ }
+
+ // Classes have opCmp and opEquals defined in `Object` to fall back on already
+ if (ad1 && ad1.isStructDeclaration)
+ return suggestOverloading(e.e2, ad1);
+ if (ad2 && ad2.isStructDeclaration)
+ return suggestOverloading(e.e1, ad2);
+
+ return null;
}
/***********************************
* Utility to build a function call out of this reference and argument.
*/
-Expression build_overload(const ref Loc loc, Scope* sc, Expression ethis, Expression earg, Dsymbol d)
+Expression build_overload(Loc loc, Scope* sc, Expression ethis, Expression earg, Dsymbol d)
{
assert(d);
Expression e;
- Declaration decl = d.isDeclaration();
- if (decl)
+ if (Declaration decl = d.isDeclaration())
e = new DotVarExp(loc, ethis, decl, false);
else
e = new DotIdExp(loc, ethis, d.ident);
@@ -1426,17 +1175,17 @@ Expression build_overload(const ref Loc loc, Scope* sc, Expression ethis, Expres
*/
Dsymbol search_function(ScopeDsymbol ad, Identifier funcid)
{
- Dsymbol s = ad.search(Loc.initial, funcid);
- if (s)
+ if (!ad)
+ return null;
+ if (Dsymbol s = ad.search(Loc.initial, funcid))
{
//printf("search_function: s = '%s'\n", s.kind());
Dsymbol s2 = s.toAlias();
//printf("search_function: s2 = '%s'\n", s2.kind());
FuncDeclaration fd = s2.isFuncDeclaration();
- if (fd && fd.type.ty == Tfunction)
+ if (fd && fd.type.isTypeFunction())
return fd;
- TemplateDeclaration td = s2.isTemplateDeclaration();
- if (td)
+ if (TemplateDeclaration td = s2.isTemplateDeclaration())
return td;
}
return null;
@@ -1465,7 +1214,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
aggr = aggr.expressionSemantic(sc);
aggr = resolveProperties(sc, aggr);
aggr = aggr.optimize(WANTvalue);
- if (!aggr.type || aggr.op == EXP.error)
+ if (!aggr.type || aggr.isErrorExp())
return false;
Type tab = aggr.type.toBasetype();
switch (tab.ty)
@@ -1479,8 +1228,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
case Tclass:
case Tstruct:
{
- AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym
- : tab.isTypeStruct().sym;
+ AggregateDeclaration ad = isAggregate(tab);
if (!sliced)
{
sapply = search_function(ad, isForeach ? Id.apply : Id.applyReverse);
@@ -1570,11 +1318,11 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
// Determine ethis for sapply
Expression ethis;
Type tab = fes.aggr.type.toBasetype();
- if (tab.ty == Tclass || tab.ty == Tstruct)
+ if (tab.isTypeClass() || tab.isTypeStruct())
ethis = fes.aggr;
else
{
- assert(tab.ty == Tdelegate && fes.aggr.op == EXP.delegate_);
+ assert(tab.isTypeDelegate() && fes.aggr.isDelegateExp());
ethis = fes.aggr.isDelegateExp().e1;
}
@@ -1614,7 +1362,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
}
p = (*fes.parameters)[1];
}
- if (!p.type && tab.ty != Ttuple)
+ if (!p.type && !tab.isTypeTuple())
{
p.type = tab.nextOf(); // value type
p.type = p.type.addStorageClass(p.storageClass);
@@ -1646,8 +1394,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
case Tclass:
case Tstruct:
{
- AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym
- : tab.isTypeStruct().sym;
+ AggregateDeclaration ad = isAggregate(tab);
if (fes.parameters.length == 1)
{
if (!p.type)
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 2c89a58..66b8c6a 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -1,12 +1,12 @@
/**
* Perform constant folding.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d, _optimize.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/optimize.d, _optimize.d)
* Documentation: https://dlang.org/phobos/dmd_optimize.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/optimize.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/optimize.d
*/
module dmd.optimize;
@@ -84,7 +84,7 @@ Expression expandVar(int result, VarDeclaration v)
{
Type tb = v.type.toBasetype();
if (v.storage_class & STC.manifest ||
- tb.isscalar() ||
+ tb.isScalar() ||
((result & WANTexpand) && (tb.ty != Tsarray && tb.ty != Tstruct)))
{
if (v._init)
@@ -110,7 +110,7 @@ Expression expandVar(int result, VarDeclaration v)
}
if (ei.op == EXP.construct || ei.op == EXP.blit)
{
- AssignExp ae = cast(AssignExp)ei;
+ auto ae = cast(AssignExp)ei;
ei = ae.e2;
if (ei.isConst() == 1)
{
@@ -183,31 +183,29 @@ private Expression fromConstInitializer(int result, Expression e1)
{
//printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars());
//static int xx; if (xx++ == 10) assert(0);
+ auto ve = e1.isVarExp();
+ if (!ve)
+ return e1;
+
Expression e = e1;
- if (auto ve = e1.isVarExp())
+ VarDeclaration v = ve.var.isVarDeclaration();
+ e = expandVar(result, v);
+ if (!e)
+ return e1;
+
+ // If it is a comma expression involving a declaration, we mustn't
+ // perform a copy -- we'd get two declarations of the same variable.
+ // See https://issues.dlang.org/show_bug.cgi?id=4465.
+ if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp())
+ e = e1;
+ else if (e.type != e1.type && e1.type && e1.type.ty != Tident)
{
- VarDeclaration v = ve.var.isVarDeclaration();
- e = expandVar(result, v);
- if (e)
- {
- // If it is a comma expression involving a declaration, we mustn't
- // perform a copy -- we'd get two declarations of the same variable.
- // See https://issues.dlang.org/show_bug.cgi?id=4465.
- if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp())
- e = e1;
- else if (e.type != e1.type && e1.type && e1.type.ty != Tident)
- {
- // Type 'paint' operation
- e = e.copy();
- e.type = e1.type;
- }
- e.loc = e1.loc;
- }
- else
- {
- e = e1;
- }
+ // Type 'paint' operation
+ e = e.copy();
+ e.type = e1.type;
}
+ e.loc = e1.loc;
+
return e;
}
@@ -372,10 +370,10 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
void visitStructLiteral(StructLiteralExp e)
{
- if (e.stageflags & stageOptimize)
+ if (e.stageflags & StructLiteralExp.StageFlags.optimize)
return;
const old = e.stageflags;
- e.stageflags |= stageOptimize;
+ e.stageflags |= StructLiteralExp.StageFlags.optimize;
if (e.elements)
{
foreach (ref ex; (*e.elements)[])
@@ -753,6 +751,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
void visitNew(NewExp e)
{
+ expOptimize(e.placement, WANTvalue);
expOptimize(e.thisexp, WANTvalue);
// Optimize parameters
if (e.arguments)
@@ -1004,7 +1003,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
}
}
- extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift)
+ extern (D) void shift_optimize(BinExp e, UnionExp function(Loc, Type, Expression, Expression) shift)
{
if (binOptimize(e, result))
return;
@@ -1071,7 +1070,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
if (binOptimize(e, result))
return;
// All negative integral powers are illegal.
- if (e.e1.type.isintegral() && (e.e2.op == EXP.int64) && cast(sinteger_t)e.e2.toInteger() < 0)
+ if (e.e1.type.isIntegral() && (e.e2.op == EXP.int64) && cast(sinteger_t)e.e2.toInteger() < 0)
{
error(e.loc, "cannot raise `%s` to a negative integer power. Did you mean `(cast(real)%s)^^%s` ?", e.e1.type.toBasetype().toChars(), e.e1.toChars(), e.e2.toChars());
return errorReturn();
@@ -1080,7 +1079,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
if (e.e2.op == EXP.float64 && e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal()))
{
// This only applies to floating point, or positive integral powers.
- if (e.e1.type.isfloating() || cast(sinteger_t)e.e2.toInteger() >= 0)
+ if (e.e1.type.isFloating() || cast(sinteger_t)e.e2.toInteger() >= 0)
e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64);
}
if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
@@ -1238,18 +1237,21 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
if (expOptimize(e.e1, WANTvalue))
return;
const oror = e.op == EXP.orOr;
- if (e.e1.toBool().hasValue(oror))
+ void returnE_e1()
{
- // Replace with (e1, oror)
- ret = IntegerExp.createBool(oror);
- ret = Expression.combine(e.e1, ret);
- if (e.type.toBasetype().ty == Tvoid)
+ ret = e.e1;
+ if (!e.e1.type.equals(e.type))
{
- ret = new CastExp(e.loc, ret, Type.tvoid);
+ ret = new CastExp(e.loc, ret, e.type);
ret.type = e.type;
+ ret = optimize(ret, result, false);
}
- ret = optimize(ret, result, false);
- return;
+ }
+ if (e.e1.toBool().hasValue(oror))
+ {
+ // e_true || e2 -> e_true
+ // e_false && e2 -> e_false
+ return returnE_e1();
}
expOptimize(e.e2, WANTvalue);
if (e.e1.isConst())
@@ -1263,6 +1265,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
}
else if (e1Opt.hasValue(!oror))
{
+
if (e.type.toBasetype().ty == Tvoid)
ret = e.e2;
else
@@ -1272,6 +1275,29 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
}
}
}
+ else if (e.e2.isConst())
+ {
+ const e2Opt = e.e2.toBool();
+ if (e2Opt.hasValue(oror))
+ {
+ // e1 || true -> (e1, true)
+ // e1 && false -> (e1, false)
+ ret = IntegerExp.createBool(oror);
+ ret = Expression.combine(e.e1, ret);
+ if (e.type.toBasetype().ty == Tvoid)
+ {
+ ret = new CastExp(e.loc, ret, Type.tvoid);
+ ret.type = e.type;
+ }
+ ret = optimize(ret, result, false);
+ }
+ else if (e2Opt.hasValue(!oror))
+ {
+ // e1 || false -> e1
+ // e1 && true -> e1
+ return returnE_e1();
+ }
+ }
}
void visitCmp(CmpExp e)
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 646c4b7..e68017c 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/grammar.html, D Grammar)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/parse.d, _parse.d)
* Documentation: https://dlang.org/phobos/dmd_parse.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parse.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/parse.d
*/
module dmd.parse;
@@ -49,14 +49,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
bool doUnittests; // parse unittest blocks
}
- bool transitionIn = false; /// `-transition=in` is active, `in` parameters are listed
-
/*********************
* Use this constructor for string mixins.
* Input:
* loc = location in source file of mixin
*/
- extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment,
+ extern (D) this(Loc loc, AST.Module _module, const(char)[] input, bool doDocComment,
ErrorSink errorSink, const CompileEnv* compileEnv, const bool doUnittests) scope
{
//printf("Parser::Parser()1 %d\n", doUnittests);
@@ -110,43 +108,44 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
parseModuleAttributes(msg, isdeprecated);
// ModuleDeclaration leads off
- if (token.value == TOK.module_)
+ if (token.value != TOK.module_)
+ return true;
+
+ const loc = token.loc;
+ nextToken();
+
+ /* parse ModuleFullyQualifiedName
+ * https://dlang.org/spec/module.html#ModuleFullyQualifiedName
+ */
+
+ if (token.value != TOK.identifier)
{
- const loc = token.loc;
- nextToken();
+ error("identifier expected following `module`");
+ return false;
+ }
- /* parse ModuleFullyQualifiedName
- * https://dlang.org/spec/module.html#ModuleFullyQualifiedName
- */
+ Identifier[] a;
+ Identifier id = token.ident;
+ while (nextToken() == TOK.dot)
+ {
+ a ~= id;
+ nextToken();
if (token.value != TOK.identifier)
{
- error("identifier expected following `module`");
+ error("identifier expected following `package`");
return false;
}
+ id = token.ident;
+ }
- Identifier[] a;
- Identifier id = token.ident;
+ md = new AST.ModuleDeclaration(loc, a, id, msg, isdeprecated);
- while (nextToken() == TOK.dot)
- {
- a ~= id;
- nextToken();
- if (token.value != TOK.identifier)
- {
- error("identifier expected following `package`");
- return false;
- }
- id = token.ident;
- }
-
- md = new AST.ModuleDeclaration(loc, a, id, msg, isdeprecated);
+ if (token.value != TOK.semicolon)
+ error("`;` expected following module declaration instead of `%s`", token.toChars());
+ nextToken();
+ addComment(mod, comment);
- if (token.value != TOK.semicolon)
- error("`;` expected following module declaration instead of `%s`", token.toChars());
- nextToken();
- addComment(mod, comment);
- }
return true;
}
@@ -233,6 +232,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
else
{
+ static if (is(typeof(mod.edition)))
+ if (exps && exps.length > 0)
+ if (auto id = (*exps)[0].isIdentifierExp())
+ if (id.ident == Id.__edition_latest_do_not_use)
+ {
+ mod.edition = Edition.latest;
+ continue;
+ }
+
udas = AST.UserAttributeDeclaration.concat(udas, exps);
}
if (stc)
@@ -319,7 +327,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
pAttrs.comment = token.blockComment.ptr;
}
AST.Visibility.Kind prot;
- StorageClass stc;
+ STC stc;
AST.Condition condition;
linkage = linksave;
@@ -528,12 +536,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
// Workaround 14894. Add an empty unittest declaration to keep
// the number of symbols in this scope independent of -unittest.
- s = new AST.UnitTestDeclaration(loc, token.loc, STC.undefined_, null);
+ s = new AST.UnitTestDeclaration(loc, token.loc, STC.none, null);
}
break;
case TOK.new_:
- s = parseNew(pAttrs);
+ s = parseNewDeclaration(pAttrs);
break;
case TOK.colon:
@@ -642,6 +650,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.auto_:
stc = STC.auto_;
+ if (peekNext() == TOK.ref_)
+ stc |= STC.autoref;
goto Lstc;
case TOK.scope_:
@@ -734,7 +744,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
a = parseBlock(pLastDecl, pAttrs);
auto stc2 = getStorageClass!AST(pAttrs);
- if (stc2 != STC.undefined_)
+ if (stc2 != STC.none)
{
s = new AST.StorageClassDeclaration(scdLoc, stc2, a);
}
@@ -922,22 +932,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
const attrLoc = token.loc;
- nextToken();
-
- AST.Expression e = null; // default
- if (token.value == TOK.leftParenthesis)
- {
- nextToken();
- e = parseAssignExp();
- check(TOK.rightParenthesis);
- }
+ AST.Expression e = parseAlign();
if (pAttrs.setAlignment)
{
if (e)
error("redundant alignment attribute `align(%s)`", e.toChars());
else
- error("redundant alignment attribute `align`");
+ error("redundant alignment attribute `align(default)`");
}
pAttrs.setAlignment = true;
@@ -1039,6 +1041,30 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
continue;
+ // The following are all errors, the cases are just for better error messages than the default case
+ case TOK.return_:
+ case TOK.goto_:
+ case TOK.break_:
+ case TOK.continue_:
+ error("`%s` statement must be inside function scope", token.toChars());
+ goto Lerror;
+ case TOK.asm_:
+ case TOK.do_:
+ case TOK.for_:
+ case TOK.foreach_:
+ case TOK.foreach_reverse_:
+ case TOK.if_:
+ case TOK.switch_:
+ case TOK.try_:
+ case TOK.while_:
+ error("`%s` statement must be inside function scope", token.toChars());
+ if (peekNext() == TOK.leftParenthesis || peekNext() == TOK.leftCurly)
+ {
+ parseStatement(0);
+ s = null;
+ continue;
+ }
+ goto Lerror;
default:
error("declaration expected, not `%s`", token.toChars());
Lerror:
@@ -1075,7 +1101,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* Starts with token on the first ident.
* Ends with scanner past closing ';'
*/
- private AST.Dsymbols* parseAutoDeclarations(StorageClass storageClass, const(char)* comment)
+ private AST.Dsymbols* parseAutoDeclarations(STC storageClass, const(char)* comment)
{
//printf("parseAutoDeclarations\n");
auto a = new AST.Dsymbols();
@@ -1190,9 +1216,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* Returns:
* The combination of both storage classes (`orig | added`).
*/
- private StorageClass appendStorageClass(StorageClass orig, StorageClass added)
+ private STC appendStorageClass(STC orig, STC added)
{
- void checkConflictSTCGroup(bool at = false)(StorageClass group)
+ void checkConflictSTCGroup(bool at = false)(STC group)
{
if (added & group && orig & group & ((orig & group) - 1))
error(
@@ -1282,13 +1308,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* If the attribute is builtin, the return value will be non-zero.
* Otherwise, 0 is returned, and `pudas` will be appended to.
*/
- private StorageClass parseAttribute(ref AST.Expressions* udas)
+ private STC parseAttribute(ref AST.Expressions* udas)
{
nextToken();
if (token.value == TOK.identifier)
{
// If we find a builtin attribute, we're done, return immediately.
- if (StorageClass stc = isBuiltinAtAttribute(token.ident))
+ if (STC stc = isBuiltinAtAttribute(token.ident))
return stc;
// Allow identifier, template instantiation, or function call
@@ -1306,10 +1332,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (udas is null)
udas = new AST.Expressions();
udas.push(exp);
- return 0;
+ return STC.none;
}
- AST.Expression templateArgToExp(RootObject o, const ref Loc loc)
+ AST.Expression templateArgToExp(RootObject o, Loc loc)
{
switch (o.dyncast)
{
@@ -1333,7 +1359,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
auto args = parseTemplateArgumentList();
foreach (arg; *args)
udas.push(templateArgToExp(arg, token.loc));
- return 0;
+ return STC.none;
}
if (auto o = parseTemplateSingleArgument())
@@ -1341,7 +1367,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (udas is null)
udas = new AST.Expressions();
udas.push(templateArgToExp(o, token.loc));
- return 0;
+ return STC.none;
}
if (token.isKeyword())
@@ -1349,17 +1375,17 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
else
error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token.toChars());
- return 0;
+ return STC.none;
}
/***********************************************
* Parse const/immutable/shared/inout/nothrow/pure postfix
*/
- private StorageClass parsePostfix(StorageClass storageClass, AST.Expressions** pudas)
+ private STC parsePostfix(STC storageClass, AST.Expressions** pudas)
{
while (1)
{
- StorageClass stc;
+ STC stc;
switch (token.value)
{
case TOK.const_:
@@ -1396,6 +1422,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
stc = STC.scope_;
break;
+ case TOK.rvalue:
+ stc = STC.rvalue;
+ break;
+
case TOK.at:
{
AST.Expressions* udas = null;
@@ -1432,16 +1462,16 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
}
- private StorageClass parseTypeCtor()
+ private STC parseTypeCtor()
{
- StorageClass storageClass = STC.undefined_;
+ STC storageClass = STC.none;
while (1)
{
if (peekNext() == TOK.leftParenthesis)
return storageClass;
- StorageClass stc;
+ STC stc;
switch (token.value)
{
case TOK.const_:
@@ -1502,28 +1532,26 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value != TOK.identifier)
{
error("identifier expected following `template`");
- goto Lerr;
+ return null;
}
id = token.ident;
nextToken();
tpl = parseTemplateParameterList();
if (!tpl)
- goto Lerr;
+ return null;
constraint = parseConstraint();
if (token.value != TOK.leftCurly)
{
error("`{` expected after template parameter list, not `%s`", token.toChars()); /* } */
- goto Lerr;
+ nextToken();
+ return null;
}
decldefs = parseBlock(null);
tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
return tempdecl;
-
- Lerr:
- return null;
}
/******************************************
@@ -1696,19 +1724,28 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* mixin Foo;
* mixin Foo!(args);
* mixin a.b.c!(args).Foo!(args);
- * mixin Foo!(args) identifier;
* mixin typeof(expr).identifier!(args);
+ * mixin Foo!(args) identifier;
+ * mixin identifier = Foo!(args);
*/
private AST.Dsymbol parseMixin()
{
AST.TemplateMixin tm;
- Identifier id;
+ Identifier id, name;
AST.Objects* tiargs;
//printf("parseMixin()\n");
const locMixin = token.loc;
nextToken(); // skip 'mixin'
+ // mixin Identifier = MixinTemplateName TemplateArguments;
+ if (token.value == TOK.identifier && peekNext() == TOK.assign)
+ {
+ name = token.ident;
+ nextToken();
+ nextToken();
+ }
+
auto loc = token.loc;
AST.TypeQualified tqual = null;
if (token.value == TOK.dot)
@@ -1771,14 +1808,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
}
- id = null;
- if (token.value == TOK.identifier)
+ // mixin MixinTemplateName TemplateArguments Identifier;
+ if (!name && token.value == TOK.identifier)
{
- id = token.ident;
+ name = token.ident;
nextToken();
}
- tm = new AST.TemplateMixin(locMixin, id, tqual, tiargs);
+ tm = new AST.TemplateMixin(locMixin, name, tqual, tiargs);
if (token.value != TOK.semicolon)
error("`;` expected after `mixin`");
nextToken();
@@ -2135,11 +2172,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
if (id == Id.Windows)
return returnLinkage(LINK.windows);
- else if (id == Id.D)
+ if (id == Id.D)
return returnLinkage(LINK.d);
- else if (id == Id.System)
+ if (id == Id.System)
return returnLinkage(LINK.system);
- else if (id == Id.Objective) // Looking for tokens "Objective-C"
+ if (id == Id.Objective) // Looking for tokens "Objective-C"
{
if (token.value != TOK.min)
return invalidLinkage();
@@ -2246,17 +2283,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
if (token.value == TOK.identifier)
s = new AST.DebugSymbol(token.loc, token.ident);
- else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
- {
- // @@@DEPRECATED_2.111@@@
- // Deprecated in 2.101, remove in 2.111
- deprecation("`debug = <integer>` is deprecated, use debug identifiers instead");
-
- s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
- }
else
{
- error("identifier or integer expected, not `%s`", token.toChars());
+ error("identifier expected, not `%s`", token.toChars());
s = null;
}
nextToken();
@@ -2271,7 +2300,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
*/
private AST.Condition parseDebugCondition()
{
- uint level = 1;
Identifier id = null;
Loc loc = token.loc;
@@ -2281,21 +2309,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.identifier)
id = token.ident;
- else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
- {
- // @@@DEPRECATED_2.111@@@
- // Deprecated in 2.101, remove in 2.111
- deprecation("`debug( <integer> )` is deprecated, use debug identifiers instead");
-
- level = cast(uint)token.unsvalue;
- }
else
- error("identifier or integer expected inside `debug(...)`, not `%s`", token.toChars());
+ error("identifier expected inside `debug(...)`, not `%s`", token.toChars());
loc = token.loc;
nextToken();
check(TOK.rightParenthesis);
}
- return new AST.DebugCondition(loc, mod, level, id);
+ return new AST.DebugCondition(loc, mod, id);
}
/**************************************
@@ -2307,16 +2327,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
if (token.value == TOK.identifier)
s = new AST.VersionSymbol(token.loc, token.ident);
- else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
- {
- // @@@DEPRECATED_2.111@@@
- // Deprecated in 2.101, remove in 2.111
- deprecation("`version = <integer>` is deprecated, use version identifiers instead");
- s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
- }
else
{
- error("identifier or integer expected, not `%s`", token.toChars());
+ error("identifier expected, not `%s`", token.toChars());
s = null;
}
nextToken();
@@ -2331,7 +2344,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
*/
private AST.Condition parseVersionCondition()
{
- uint level = 1;
Identifier id = null;
Loc loc;
@@ -2346,26 +2358,18 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
loc = token.loc;
if (token.value == TOK.identifier)
id = token.ident;
- else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
- {
- // @@@DEPRECATED_2.111@@@
- // Deprecated in 2.101, remove in 2.111
- deprecation("`version( <integer> )` is deprecated, use version identifiers instead");
-
- level = cast(uint)token.unsvalue;
- }
else if (token.value == TOK.unittest_)
id = Identifier.idPool(Token.toString(TOK.unittest_));
else if (token.value == TOK.assert_)
id = Identifier.idPool(Token.toString(TOK.assert_));
else
- error("identifier or integer expected inside `version(...)`, not `%s`", token.toChars());
+ error("identifier expected inside `version(...)`, not `%s`", token.toChars());
nextToken();
check(TOK.rightParenthesis);
}
else
error("(condition) expected following `version`");
- return new AST.VersionCondition(loc, mod, level, id);
+ return new AST.VersionCondition(loc, mod, id);
}
/***********************************************
@@ -2411,7 +2415,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
AST.Expressions* udas = null;
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
nextToken();
if (token.value == TOK.leftParenthesis && peekNext() == TOK.this_ && peekNext2() == TOK.rightParenthesis)
@@ -2462,7 +2466,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (stc & STC.static_)
error(loc, "constructor cannot be static");
}
- else if (StorageClass ss = stc & (STC.shared_ | STC.static_)) // this()
+ else if (STC ss = stc & (STC.shared_ | STC.static_)) // this()
{
if (ss == STC.static_)
error(loc, "use `static this()` to declare a static constructor");
@@ -2472,7 +2476,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.Expression constraint = tpl ? parseConstraint() : null;
- AST.Type tf = new AST.TypeFunction(parameterList, null, linkage, stc); // RetrunType -> auto
+ AST.Type tf = new AST.TypeFunction(parameterList, null, linkage, stc); // ReturnType -> auto
tf = tf.addSTC(stc);
auto f = new AST.CtorDeclaration(loc, Loc.initial, stc, tf);
@@ -2504,7 +2508,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
AST.Expressions* udas = null;
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
nextToken();
check(TOK.this_);
@@ -2512,7 +2516,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
check(TOK.rightParenthesis);
stc = parsePostfix(stc, &udas);
- if (StorageClass ss = stc & (STC.shared_ | STC.static_))
+ if (STC ss = stc & (STC.shared_ | STC.static_))
{
if (ss == STC.static_)
error(loc, "use `static ~this()` to declare a static destructor");
@@ -2540,7 +2544,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
//Expressions *udas = NULL;
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
nextToken();
nextToken();
@@ -2552,7 +2556,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
error(loc, "use `shared static this()` to declare a shared static constructor");
else if (stc & STC.static_)
appendStorageClass(stc, STC.static_); // complaint for the redundancy
- else if (StorageClass modStc = stc & STC.TYPECTOR)
+ else if (STC modStc = stc & STC.TYPECTOR)
{
OutBuffer buf;
AST.stcToBuffer(buf, modStc);
@@ -2574,7 +2578,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
AST.Expressions* udas = null;
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
nextToken();
nextToken();
@@ -2587,7 +2591,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
error(loc, "use `shared static ~this()` to declare a shared static destructor");
else if (stc & STC.static_)
appendStorageClass(stc, STC.static_); // complaint for the redundancy
- else if (StorageClass modStc = stc & STC.TYPECTOR)
+ else if (STC modStc = stc & STC.TYPECTOR)
{
OutBuffer buf;
AST.stcToBuffer(buf, modStc);
@@ -2615,7 +2619,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
//Expressions *udas = NULL;
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
nextToken();
nextToken();
@@ -2624,9 +2628,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
check(TOK.rightParenthesis);
stc = parsePostfix(stc & ~STC.TYPECTOR, null) | stc;
- if (StorageClass ss = stc & (STC.shared_ | STC.static_))
+ if (STC ss = stc & (STC.shared_ | STC.static_))
appendStorageClass(stc, ss); // complaint for the redundancy
- else if (StorageClass modStc = stc & STC.TYPECTOR)
+ else if (STC modStc = stc & STC.TYPECTOR)
{
OutBuffer buf;
AST.stcToBuffer(buf, modStc);
@@ -2648,7 +2652,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
AST.Expressions* udas = null;
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
nextToken();
nextToken();
@@ -2658,9 +2662,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
check(TOK.rightParenthesis);
stc = parsePostfix(stc & ~STC.TYPECTOR, &udas) | stc;
- if (StorageClass ss = stc & (STC.shared_ | STC.static_))
+ if (STC ss = stc & (STC.shared_ | STC.static_))
appendStorageClass(stc, ss); // complaint for the redundancy
- else if (StorageClass modStc = stc & STC.TYPECTOR)
+ else if (STC modStc = stc & STC.TYPECTOR)
{
OutBuffer buf;
AST.stcToBuffer(buf, modStc);
@@ -2689,7 +2693,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
private AST.Dsymbol parseInvariant(PrefixAttributes!AST* pAttrs)
{
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
nextToken();
if (token.value == TOK.leftParenthesis) // optional () or invariant (expression);
@@ -2731,7 +2735,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
private AST.Dsymbol parseUnitTest(PrefixAttributes!AST* pAttrs)
{
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
nextToken();
@@ -2770,44 +2774,19 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* @disable new();
* Current token is 'new'.
*/
- private AST.Dsymbol parseNew(PrefixAttributes!AST* pAttrs)
+ private AST.Dsymbol parseNewDeclaration(PrefixAttributes!AST* pAttrs)
{
const loc = token.loc;
- StorageClass stc = getStorageClass!AST(pAttrs);
+ STC stc = getStorageClass!AST(pAttrs);
if (!(stc & STC.disable))
{
error("`new` allocator must be annotated with `@disabled`");
}
nextToken();
-
- /* @@@DEPRECATED_2.108@@@
- * After deprecation period (2.108), remove all code in the version(all) block.
- */
- version (all)
- {
- auto parameterList = parseParameterList(null); // parameterList ignored
- if (parameterList.parameters.length > 0 || parameterList.varargs != VarArg.none)
- deprecation("`new` allocator with non-empty parameter list is deprecated");
- auto f = new AST.NewDeclaration(loc, stc);
- if (token.value != TOK.semicolon)
- {
- deprecation("`new` allocator with function definition is deprecated");
- parseContracts(f); // body ignored
- f.fbody = null;
- f.fensures = null;
- f.frequires = null;
- }
- else
- nextToken();
- return f;
- }
- else
- {
- check(TOK.leftParenthesis);
- check(TOK.rightParenthesis);
- check(TOK.semicolon);
- return new AST.NewDeclaration(loc, stc);
- }
+ check(TOK.leftParenthesis);
+ check(TOK.rightParenthesis);
+ check(TOK.semicolon);
+ return new AST.NewDeclaration(loc, stc);
}
/**********************************************
@@ -2817,7 +2796,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
auto parameters = new AST.Parameters();
VarArg varargs = VarArg.none;
- StorageClass varargsStc;
+ STC varargsStc;
// Attributes allowed for ...
enum VarArgsStc = STC.const_ | STC.immutable_ | STC.shared_ | STC.scope_ | STC.return_ | STC.returnScope;
@@ -2827,8 +2806,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
Identifier ai = null;
AST.Type at;
- StorageClass storageClass = 0;
- StorageClass stc;
+ STC storageClass = STC.none;
+ STC stc;
AST.Expression ae;
AST.Expressions* udas = null;
for (; 1; nextToken())
@@ -2880,7 +2859,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.at:
{
AST.Expressions* exps = null;
- StorageClass stc2 = parseAttribute(exps);
+ STC stc2 = parseAttribute(exps);
if (stc2 & atAttrGroup)
{
error("`@%s` attribute for function parameter is not supported", token.toChars());
@@ -2897,7 +2876,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
// Don't call nextToken again.
}
case TOK.in_:
- if (transitionIn)
+ if (compileEnv.transitionIn)
eSink.message(scanloc, "Usage of 'in' on parameter");
stc = STC.in_;
if (compileEnv.previewIn)
@@ -2926,6 +2905,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.auto_:
stc = STC.auto_;
+ if (peekNext() == TOK.ref_)
+ stc |= STC.autoref;
goto L2;
case TOK.return_:
@@ -2943,8 +2924,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
// if stcx is not a power of 2
if (stcx & (stcx - 1) && !(stcx == (STC.in_ | STC.ref_)))
error("incompatible parameter storage classes");
- //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_)))
- //error("scope cannot be ref or out");
+
+ // Deprecated in 2.111
+ if ((storageClass & STC.auto_) && (storageClass & STC.ref_) && !(storageClass & STC.autoref))
+ deprecation("`auto` and `ref` storage classes should be adjacent");
const tv = peekNext();
Loc loc;
@@ -2982,7 +2965,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.at)
{
AST.Expressions* exps = null;
- StorageClass stc2 = parseAttribute(exps);
+ STC stc2 = parseAttribute(exps);
if (stc2 & atAttrGroup)
{
error("`@%s` attribute for function parameter is not supported", token.toChars());
@@ -3080,7 +3063,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
Identifier ident = null;
AST.Expressions* udas;
- StorageClass stc;
+ STC stc;
AST.Expression deprecationMessage;
enum attributeErrorMessage = "`%s` is not a valid attribute for enum members";
Lattrs:
@@ -3089,7 +3072,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
switch (token.value)
{
case TOK.at:
- if (StorageClass _stc = parseAttribute(udas))
+ if (STC _stc = parseAttribute(udas))
{
if (_stc == STC.disable)
stc |= _stc;
@@ -3476,7 +3459,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
name = _alias;
_alias = null;
}
- s.addAlias(name, _alias);
+ if (s.isstatic)
+ error(loc, "static import `%s` cannot have an import bind list", s.toPrettyChars());
+ if (!s.aliasId)
+ s.ident = null; // make it an anonymous import
+ s.names.push(name);
+ s.aliases.push(_alias);
}
while (token.value == TOK.comma);
break; // no comma-separated imports of this form
@@ -3515,7 +3503,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* shared inout type
* shared inout const type
*/
- StorageClass stc = 0;
+ STC stc = STC.none;
while (1)
{
switch (token.value)
@@ -3999,7 +3987,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
auto parameterList = parseParameterList(null);
- StorageClass stc = parsePostfix(STC.undefined_, null);
+ STC stc = parsePostfix(STC.none, null);
auto tf = new AST.TypeFunction(parameterList, t, linkage, stc);
if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild | STC.return_))
{
@@ -4035,7 +4023,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* Reference: https://dlang.org/spec/declaration.html#Declarator
*/
private AST.Type parseDeclarator(AST.Type t, ref int palt, Identifier* pident,
- AST.TemplateParameters** tpl = null, StorageClass storageClass = 0,
+ AST.TemplateParameters** tpl = null, STC storageClass = STC.none,
bool* pdisable = null, AST.Expressions** pudas = null)
{
//printf("parseDeclarator(tpl = %p)\n", tpl);
@@ -4176,7 +4164,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
/* Parse const/immutable/shared/inout/nothrow/pure/return postfix
*/
// merge prefix storage classes
- StorageClass stc = parsePostfix(storageClass, pudas);
+ STC stc = parsePostfix(storageClass, pudas);
AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, stc);
tf = tf.addSTC(stc);
@@ -4203,11 +4191,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return ts;
}
- private void parseStorageClasses(ref StorageClass storage_class, ref LINK link,
+ private void parseStorageClasses(ref STC storage_class, ref LINK link,
ref bool setAlignment, ref AST.Expression ealign, ref AST.Expressions* udas,
out Loc linkloc)
{
- StorageClass stc;
+ STC stc;
bool sawLinkage = false; // seen a linkage declaration
linkloc = Loc.initial;
@@ -4250,6 +4238,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.auto_:
stc = STC.auto_;
+ if (peekNext() == TOK.ref_)
+ stc |= STC.autoref;
goto L1;
case TOK.scope_:
@@ -4341,14 +4331,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
case TOK.align_:
{
- nextToken();
setAlignment = true;
- if (token.value == TOK.leftParenthesis)
- {
- nextToken();
- ealign = parseExpression();
- check(TOK.rightParenthesis);
- }
+ ealign = parseAlign();
continue;
}
default:
@@ -4358,6 +4342,27 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
}
+ /**
+ * Parse `align` or `align(n)`
+ * Returns:
+ * expression `n` if it is present, or `null` otherwise.
+ */
+ private AST.Expression parseAlign()
+ {
+ assert(token.value == TOK.align_);
+ AST.Expression e = null;
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ if (token.value == TOK.default_)
+ nextToken();
+ else
+ e = parseAssignExp();
+ check(TOK.rightParenthesis);
+ }
+ return e;
+ }
/**********************************
* Parse Declarations.
* These can be:
@@ -4368,7 +4373,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
*/
private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment)
{
- StorageClass storage_class = STC.undefined_;
+ STC storage_class = STC.none;
LINK link = linkage;
Loc linkloc = this.linkLoc;
bool setAlignment = false;
@@ -4499,7 +4504,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (pAttrs)
{
storage_class |= pAttrs.storageClass;
- //pAttrs.storageClass = STC.undefined_;
+ //pAttrs.storageClass = STC.none;
}
AST.Type tfirst = null;
@@ -4530,7 +4535,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (ident)
checkCstyleTypeSyntax(loc, t, alt, ident);
else if (!isThis && (t != AST.Type.terror))
- noIdentifierForDeclarator(t);
+ noIdentifierForDeclarator(t, token);
if (isAliasDeclaration)
{
@@ -4592,6 +4597,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
default:
error("semicolon expected to close `alias` declaration, not `%s`", token.toChars());
+ nextToken();
break;
}
}
@@ -4604,9 +4610,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.Expression constraint = null;
//printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class);
- auto f = new AST.FuncDeclaration(loc, Loc.initial, ident, storage_class | (disable ? STC.disable : 0), t);
+ auto f = new AST.FuncDeclaration(loc, Loc.initial, ident, storage_class | (disable ? STC.disable : STC.none), t);
if (pAttrs)
- pAttrs.storageClass = STC.undefined_;
+ pAttrs.storageClass = STC.none;
if (tpl)
constraint = parseConstraint();
AST.Dsymbol s = parseContracts(f, !!tpl);
@@ -4642,7 +4648,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
auto tempdecl = new AST.TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
s = tempdecl;
- StorageClass stc2 = STC.undefined_;
+ STC stc2 = STC.none;
if (storage_class & STC.static_)
{
assert(f.storage_class & STC.static_);
@@ -4655,7 +4661,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
f.storage_class &= ~STC.deprecated_;
stc2 |= STC.deprecated_;
}
- if (stc2 != STC.undefined_)
+ if (stc2 != STC.none)
{
auto ax = new AST.Dsymbols();
ax.push(s);
@@ -4695,7 +4701,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
auto v = new AST.VarDeclaration(loc, t, ident, _init);
v.storage_class = storage_class;
if (pAttrs)
- pAttrs.storageClass = STC.undefined_;
+ pAttrs.storageClass = STC.none;
s = v;
}
@@ -4755,11 +4761,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return a;
}
- /// Report an error that a declaration of type `t` is missing an identifier
+ /// Report an error that a declaration of type `t` is missing an identifier and got `tok` instead
/// The parser is expected to sit on the next token after the type.
- private void noIdentifierForDeclarator(AST.Type t)
+ private void noIdentifierForDeclarator(AST.Type t, Token tok)
{
- error("no identifier for declarator `%s`", t.toChars());
+ error("variable name expected after type `%s`, not `%s`", t.toChars(), tok.toChars);
+
// A common mistake is to use a reserved keyword as an identifier, e.g. `in` or `out`
if (token.isKeyword)
{
@@ -4809,7 +4816,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
Loc linkloc = this.linkLoc;
AST.Expressions* udas;
LINK link = linkage;
- StorageClass storage_class = STC.undefined_;
+ STC storage_class = STC.none;
AST.Expression ealign;
bool setAlignment = false;
@@ -4867,7 +4874,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return;
hasParsedAttributes = true;
udas = null;
- storage_class = STC.undefined_;
+ storage_class = STC.none;
link = linkage;
linkloc = this.linkLoc;
setAlignment = false;
@@ -4882,7 +4889,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.Dsymbol s;
bool attributesAppended;
- const StorageClass funcStc = parseTypeCtor();
+ const STC funcStc = parseTypeCtor();
Token* tk;
// function literal?
if (token.value == TOK.function_ ||
@@ -5037,6 +5044,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
default:
error("semicolon expected to close `alias` declaration, not `%s`", token.toChars());
+ nextToken();
break;
}
break;
@@ -5054,7 +5062,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.TemplateParameters* tpl = null;
AST.ParameterList parameterList;
AST.Type tret = null;
- StorageClass stc = 0;
+ STC stc = STC.none;
TOK save = TOK.reserved;
switch (token.value)
@@ -5070,7 +5078,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
// function auto ref (parameters) { statements... }
// delegate auto ref (parameters) { statements... }
- stc = STC.auto_ | STC.ref_;
+ stc = STC.auto_ | STC.ref_ | STC.autoref;
nextToken();
}
else
@@ -5112,7 +5120,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
// auto ref (parameters) => expression
// auto ref (parameters) { statements... }
- stc = STC.auto_ | STC.ref_;
+ stc = STC.auto_ | STC.ref_ | STC.autoref;
nextToken();
}
else
@@ -5133,7 +5141,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
// (parameters) { statements... }
parameterList = parseParameterList(&tpl);
stc = parsePostfix(stc, null);
- if (StorageClass modStc = stc & STC.TYPECTOR)
+ if (STC modStc = stc & STC.TYPECTOR)
{
if (save == TOK.function_)
{
@@ -5222,7 +5230,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
error("missing `do { ... }` after `in` or `out`");
const returnloc = token.loc;
nextToken();
- f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
+ if (f.isCtorDeclaration)
+ f.fbody = new AST.ExpStatement(returnloc, parseExpression());
+ else
+ f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
f.endloc = token.loc;
check(TOK.semicolon);
break;
@@ -5374,9 +5385,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
error("template constraint must follow parameter lists and attributes");
else
error("cannot use function constraints for non-template functions. Use `static if` instead");
+
+ parseConstraint();
}
else
+ {
error("semicolon expected following function declaration, not `%s`", token.toChars());
+ nextToken();
+ }
}
break;
}
@@ -5395,7 +5411,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
*/
private void checkDanglingElse(Loc elseloc)
{
- if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0)
+ if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.isValid)
{
eSink.warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
}
@@ -5473,8 +5489,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.Type at;
Loc aloc;
- StorageClass storageClass = 0;
- StorageClass stc = 0;
+ STC storageClass = STC.none;
+ STC stc = STC.none;
Lagain:
if (stc)
{
@@ -5560,7 +5576,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
at = parseType(&ai);
if (!ai)
- noIdentifierForDeclarator(at);
+ noIdentifierForDeclarator(at, token);
Larg:
auto p = new AST.Parameter(aloc, storageClass, at, ai, null, null);
parameters.push(p);
@@ -5643,7 +5659,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
/***
- * Parse an assignment condition for if or while statements.
+ * Parse an assignment condition for `if`, `switch` or `while` statements.
*
* Returns:
* The variable that is declared inside the condition
@@ -5651,8 +5667,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
AST.Parameter parseAssignCondition()
{
AST.Parameter param = null;
- StorageClass storageClass = 0;
- StorageClass stc = 0;
+ STC storageClass = STC.none;
+ STC stc = STC.none;
Lwhile:
while (1)
{
@@ -5669,6 +5685,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.auto_:
stc = STC.auto_;
+ if (peekNext() == TOK.ref_)
+ stc |= STC.autoref;
break;
case TOK.const_:
@@ -5833,7 +5851,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.plusPlus:
case TOK.minusMinus:
case TOK.new_:
- case TOK.delete_:
case TOK.delegate_:
case TOK.function_:
case TOK.typeid_:
@@ -5845,6 +5862,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.moduleString:
case TOK.functionString:
case TOK.prettyFunction:
+ case TOK.rvalue:
Lexp:
{
AST.Expression exp = parseExpression();
@@ -5960,9 +5978,18 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
goto Lexp;
goto case;
+ // FunctionLiteral `auto ref (`
+ case TOK.auto_:
+ if (peekNext() == TOK.ref_ && peekNext2() == TOK.leftParenthesis)
+ goto Lexp;
+ goto Ldeclaration;
+ case TOK.ref_:
+ if (peekNext() == TOK.leftParenthesis)
+ goto Lexp;
+ goto Ldeclaration;
+
case TOK.alias_:
case TOK.const_:
- case TOK.auto_:
case TOK.abstract_:
case TOK.extern_:
case TOK.align_:
@@ -5972,7 +5999,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.deprecated_:
case TOK.nothrow_:
case TOK.pure_:
- case TOK.ref_:
case TOK.gshared:
case TOK.at:
case TOK.struct_:
@@ -6261,12 +6287,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.assign)
{
if (auto ds = parseDebugSpecification())
- {
- if (ds.ident)
- eSink.error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars);
- else
- eSink.error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars);
- }
+ eSink.error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars);
+
break;
}
cond = parseDebugCondition();
@@ -6277,12 +6299,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.assign)
{
if (auto vs = parseVersionSpecification())
- {
- if (vs.ident)
- eSink.error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars);
- else
- eSink.error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars);
- }
+ eSink.error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars);
+
break;
}
cond = parseVersionCondition();
@@ -6772,7 +6790,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
case TOK.identifier:
{
-
if (commaExpected)
error("comma expected separating field initializers");
const t = peek(&token);
@@ -6806,6 +6823,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
default:
if (commaExpected)
error("comma expected separating field initializers");
+ const t = peek(&token);
+ if (t.value == TOK.colon)
+ {
+ error("incorrect syntax for associative array, expected `[]`, found `{}`");
+ while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
+ {
+ nextToken();
+ }
+ if (token.value == TOK.rightCurly)
+ {
+ nextToken();
+ }
+ break;
+ }
auto value = parseInitializer();
_is.addInit(null, value);
commaExpected = true;
@@ -6978,7 +7009,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
Loc labelloc;
nextToken();
- StorageClass stc = parsePostfix(STC.undefined_, null); // optional FunctionAttributes
+ STC stc = parsePostfix(STC.none, null); // optional FunctionAttributes
if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild))
error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks");
@@ -8370,6 +8401,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
e = new AST.TypeidExp(loc, o);
break;
}
+ case TOK.rvalue:
+ {
+ nextToken();
+ check(TOK.leftParenthesis, "`__rvalue`");
+ e = parseAssignExp();
+ e.rvalue = true;
+ check(TOK.rightParenthesis);
+ break;
+ }
case TOK.traits:
{
/* __traits(identifier, args...)
@@ -8607,7 +8647,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
error("expression expected, not `%s`", token.toChars());
Lerr:
// Anything for e, as long as it's not NULL
- e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
+ e = AST.ErrorExp.get();
nextToken();
break;
}
@@ -8671,15 +8711,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
e = new AST.ComExp(loc, e);
break;
- case TOK.delete_:
- // @@@DEPRECATED_2.109@@@
- // Use of `delete` keyword has been an error since 2.099.
- // Remove from the parser after 2.109.
- nextToken();
- e = parseUnaryExp();
- e = new AST.DeleteExp(loc, e, false);
- break;
-
case TOK.cast_: // cast(type) expression
{
nextToken();
@@ -8746,7 +8777,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.const_:
case TOK.immutable_: // immutable(type)(arguments) / immutable(type).init
{
- StorageClass stc = parseTypeCtor();
+ STC stc = parseTypeCtor();
AST.Type t = parseBasicType();
t = t.addSTC(stc);
@@ -8797,7 +8828,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
case TOK.dot:
case TOK.plusPlus:
case TOK.minusMinus:
- case TOK.delete_:
case TOK.new_:
case TOK.leftParenthesis:
case TOK.identifier:
@@ -9462,12 +9492,31 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
/*******************************************
+ * Params:
+ * thisexp = If not null, it is the `this` reference for the creation
+ * of an inner class.
+ * https://dlang.org/spec/class.html#nested-explicit
+ * https://dlang.org/spec/expression.html#postfix_expressions
+ * If null, then it is a NewExpression.
+ * https://dlang.org/spec/expression.html#NewExpression
+ * Returns:
+ * NewExpression
*/
private AST.Expression parseNewExp(AST.Expression thisexp)
{
const loc = token.loc;
- nextToken();
+ nextToken(); // skip past `new`
+
+ // parse PlacementExpression if any
+ AST.Expression placement;
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ placement = parseAssignExp();
+ check(TOK.rightParenthesis);
+ }
+
AST.Expressions* arguments = null;
AST.Identifiers* names = null;
@@ -9503,7 +9552,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false);
- auto e = new AST.NewAnonClassExp(loc, thisexp, cd, arguments);
+ auto e = new AST.NewAnonClassExp(loc, placement, thisexp, cd, arguments);
return e;
}
@@ -9527,7 +9576,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
parseNamedArguments(arguments, names);
}
- auto e = new AST.NewExp(loc, thisexp, t, arguments, names);
+ auto e = new AST.NewExp(loc, placement, thisexp, t, arguments, names);
return e;
}
@@ -9555,7 +9604,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* Returns:
* storage class for attribute, 0 if not
*/
- static StorageClass isBuiltinAtAttribute(Identifier ident)
+ static STC isBuiltinAtAttribute(Identifier ident)
{
return (ident == Id.property) ? STC.property :
(ident == Id.nogc) ? STC.nogc :
@@ -9565,10 +9614,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
(ident == Id.live) ? STC.live :
(ident == Id.future) ? STC.future :
(ident == Id.disable) ? STC.disable :
- 0;
+ STC.none;
}
- enum StorageClass atAttrGroup =
+ enum STC atAttrGroup =
STC.property |
STC.nogc |
STC.safe |
@@ -9580,9 +9629,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
void usageOfBodyKeyword()
{
- version (none) // disable obsolete warning
+ if (mod.edition >= Edition.v2024)
{
- eSink.warning(token.loc, "usage of identifer `body` as a keyword is obsolete. Use `do` instead.");
+ eSink.error(token.loc, "usage of identifer `body` as a keyword is obsolete. Use `do` instead.");
}
}
}
@@ -9732,6 +9781,7 @@ immutable PREC[EXP.max + 1] precedence =
EXP.assign : PREC.assign,
EXP.construct : PREC.assign,
EXP.blit : PREC.assign,
+ EXP.loweredAssignExp : PREC.assign,
EXP.addAssign : PREC.assign,
EXP.minAssign : PREC.assign,
EXP.concatenateAssign : PREC.assign,
@@ -9764,7 +9814,7 @@ enum ParseStatementFlags : int
struct PrefixAttributes(AST)
{
- StorageClass storageClass;
+ STC storageClass;
AST.Expression depmsg;
LINK link;
AST.Visibility visibility;
@@ -9816,13 +9866,13 @@ private enum CARRAYDECL = 1;
/*****************************
* Destructively extract storage class from pAttrs.
*/
-private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
+private STC getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
{
- StorageClass stc = STC.undefined_;
+ STC stc = STC.none;
if (pAttrs)
{
stc = pAttrs.storageClass;
- pAttrs.storageClass = STC.undefined_;
+ pAttrs.storageClass = STC.none;
}
return stc;
}
diff --git a/gcc/d/dmd/postordervisitor.d b/gcc/d/dmd/postordervisitor.d
deleted file mode 100644
index fe189d4..0000000
--- a/gcc/d/dmd/postordervisitor.d
+++ /dev/null
@@ -1,153 +0,0 @@
-/**
- * A depth-first visitor for expressions.
- *
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
- * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
- * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/apply.d, _apply.d)
- * Documentation: https://dlang.org/phobos/dmd_apply.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/apply.d
- */
-
-module dmd.postordervisitor;
-
-import dmd.arraytypes;
-import dmd.dtemplate;
-import dmd.expression;
-import dmd.root.array;
-import dmd.visitor;
-
-bool walkPostorder(Expression e, StoppableVisitor v)
-{
- scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v);
- e.accept(pv);
- return v.stop;
-}
-
-/**************************************
- * An Expression tree walker that will visit each Expression e in the tree,
- * in depth-first evaluation order, and call fp(e,param) on it.
- * fp() signals whether the walking continues with its return value:
- * Returns:
- * 0 continue
- * 1 done
- * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
- * Creating an iterator for this would be much more complex.
- */
-private extern (C++) final class PostorderExpressionVisitor : StoppableVisitor
-{
- alias visit = typeof(super).visit;
-public:
- StoppableVisitor v;
-
- extern (D) this(StoppableVisitor v) scope @safe
- {
- this.v = v;
- }
-
- bool doCond(Expression e)
- {
- if (!stop && e)
- e.accept(this);
- return stop;
- }
-
- extern(D) bool doCond(Expression[] e)
- {
- for (size_t i = 0; i < e.length && !stop; i++)
- doCond(e[i]);
- return stop;
- }
-
- bool applyTo(Expression e)
- {
- e.accept(v);
- stop = v.stop;
- return true;
- }
-
- override void visit(Expression e)
- {
- applyTo(e);
- }
-
- override void visit(NewExp e)
- {
- //printf("NewExp::apply(): %s\n", toChars());
- doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
- }
-
- override void visit(NewAnonClassExp e)
- {
- //printf("NewAnonClassExp::apply(): %s\n", toChars());
- doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
- }
-
- override void visit(TypeidExp e)
- {
- doCond(isExpression(e.obj)) || applyTo(e);
- }
-
- override void visit(UnaExp e)
- {
- doCond(e.e1) || applyTo(e);
- }
-
- override void visit(BinExp e)
- {
- doCond(e.e1) || doCond(e.e2) || applyTo(e);
- }
-
- override void visit(AssertExp e)
- {
- //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
- doCond(e.e1) || doCond(e.msg) || applyTo(e);
- }
-
- override void visit(CallExp e)
- {
- //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
- doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e);
- }
-
- override void visit(ArrayExp e)
- {
- //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
- doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e);
- }
-
- override void visit(SliceExp e)
- {
- doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e);
- }
-
- override void visit(ArrayLiteralExp e)
- {
- doCond(e.basis) || doCond(e.elements.peekSlice()) || applyTo(e);
- }
-
- override void visit(AssocArrayLiteralExp e)
- {
- doCond(e.keys.peekSlice()) || doCond(e.values.peekSlice()) || applyTo(e);
- }
-
- override void visit(StructLiteralExp e)
- {
- if (e.stageflags & stageApply)
- return;
- const old = e.stageflags;
- e.stageflags |= stageApply;
- doCond(e.elements.peekSlice()) || applyTo(e);
- e.stageflags = old;
- }
-
- override void visit(TupleExp e)
- {
- doCond(e.e0) || doCond(e.exps.peekSlice()) || applyTo(e);
- }
-
- override void visit(CondExp e)
- {
- doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e);
- }
-}
diff --git a/gcc/d/dmd/pragmasem.d b/gcc/d/dmd/pragmasem.d
index b52b551..4459774 100644
--- a/gcc/d/dmd/pragmasem.d
+++ b/gcc/d/dmd/pragmasem.d
@@ -6,9 +6,9 @@
* Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/pragmasem.d, _pragmasem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/pragmasem.d, _pragmasem.d)
* Documentation: https://dlang.org/phobos/dmd_pragmasem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/pragmasem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/pragmasem.d
*/
module dmd.pragmasem;
@@ -21,6 +21,7 @@ import dmd.attrib;
import dmd.dinterpret;
import dmd.dscope;
import dmd.dsymbol;
+import dmd.dsymbolsem : include;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
@@ -40,10 +41,10 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc)
{
import dmd.aggregate;
import dmd.common.outbuffer;
- import dmd.dmangle;
import dmd.dmodule;
import dmd.dsymbolsem;
import dmd.identifier;
+ import dmd.mangle : isValidMangling;
import dmd.root.rmem;
import dmd.root.utf;
import dmd.target;
@@ -67,6 +68,8 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc)
}
version (all)
{
+ import dmd.common.charactertables;
+
/* Note: D language specification should not have any assumption about backend
* implementation. Ideally pragma(mangle) can accept a string of any content.
*
@@ -94,7 +97,7 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc)
.error(pd.loc, "%s `%s` %.*s", pd.kind, pd.toPrettyChars, cast(int)msg.length, msg.ptr);
break;
}
- if (!isUniAlpha(c))
+ if (!isAnyIdentifierCharacter(c))
{
.error(pd.loc, "%s `%s` char `0x%04x` not allowed in mangled name", pd.kind, pd.toPrettyChars, c);
break;
@@ -508,10 +511,9 @@ package PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args)
const opt = e.toBool();
if (opt.isEmpty())
return PINLINE.default_;
- else if (opt.get())
+ if (opt.get())
return PINLINE.always;
- else
- return PINLINE.never;
+ return PINLINE.never;
}
/**
@@ -555,32 +557,17 @@ private uint setMangleOverride(Dsymbol s, const(char)[] sym)
private bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args)
{
import dmd.tokens;
+ import dmd.common.outbuffer;
if (!args)
return true;
- foreach (arg; *args)
- {
- sc = sc.startCTFE();
- auto e = arg.expressionSemantic(sc);
- e = resolveProperties(sc, e);
- sc = sc.endCTFE();
- // pragma(msg) is allowed to contain types as well as expressions
- e = ctfeInterpretForPragmaMsg(e);
- if (e.op == EXP.error)
- {
- errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars());
- return false;
- }
- if (auto se = e.toStringExp())
- {
- const slice = se.toUTF8(sc).peekString();
- fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr);
- }
- else
- fprintf(stderr, "%s", e.toChars());
- }
- fprintf(stderr, "\n");
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, args, loc, "while evaluating `pragma(msg, %s)`", false))
+ return false;
+
+ buf.writestring("\n");
+ fprintf(stderr, "%s", buf.extractChars);
return true;
}
diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d
index 02dc653..5e4c9f7 100644
--- a/gcc/d/dmd/printast.d
+++ b/gcc/d/dmd/printast.d
@@ -1,12 +1,12 @@
/**
* Provides an AST printer for debugging.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/printast.d, _printast.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/printast.d, _printast.d)
* Documentation: https://dlang.org/phobos/dmd_printast.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/printast.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/printast.d
*/
module dmd.printast;
@@ -51,6 +51,12 @@ extern (C++) final class PrintASTVisitor : Visitor
printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "");
}
+ override void visit(IdentifierExp e)
+ {
+ printIndent(indent);
+ printf("Identifier `%s` %s\n", e.ident.toChars(), e.type ? e.type.toChars() : "");
+ }
+
override void visit(IntegerExp e)
{
printIndent(indent);
diff --git a/gcc/d/dmd/root/aav.d b/gcc/d/dmd/root/aav.d
index 8929679..014d4a5 100644
--- a/gcc/d/dmd/root/aav.d
+++ b/gcc/d/dmd/root/aav.d
@@ -1,12 +1,12 @@
/**
* Associative array implementation.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d, root/_aav.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/aav.d, root/_aav.d)
* Documentation: https://dlang.org/phobos/dmd_root_aav.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/aav.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/aav.d
*/
module dmd.root.aav;
diff --git a/gcc/d/dmd/root/array.d b/gcc/d/dmd/root/array.d
index 8135577..a80fc80 100644
--- a/gcc/d/dmd/root/array.d
+++ b/gcc/d/dmd/root/array.d
@@ -2,12 +2,12 @@
/**
* Dynamic array implementation.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/array.d, root/_array.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/array.d, root/_array.d)
* Documentation: https://dlang.org/phobos/dmd_root_array.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/array.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/array.d
*/
module dmd.root.array;
@@ -52,7 +52,7 @@ public:
~this() pure nothrow
{
debug (stomp) memset(data.ptr, 0xFF, data.length);
- if (data.ptr != &smallarray[0])
+ if (data.ptr && data.ptr != &smallarray[0])
mem.xfree(data.ptr);
}
///returns elements comma separated in []
diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h
index 3e28804..6b761cf 100644
--- a/gcc/d/dmd/root/array.h
+++ b/gcc/d/dmd/root/array.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2011-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -26,7 +26,7 @@ struct Array
public:
Array()
{
- data.ptr = NULL;
+ data.ptr = nullptr;
length = 0;
data.length = 0;
}
@@ -86,7 +86,7 @@ struct Array
if (nentries <= SMALLARRAYCAP)
{
data.length = SMALLARRAYCAP;
- data.ptr = SMALLARRAYCAP ? &smallarray[0] : NULL;
+ data.ptr = SMALLARRAYCAP ? &smallarray[0] : nullptr;
}
else
{
diff --git a/gcc/d/dmd/root/bitarray.d b/gcc/d/dmd/root/bitarray.d
index c32d59e..b5adaa8 100644
--- a/gcc/d/dmd/root/bitarray.d
+++ b/gcc/d/dmd/root/bitarray.d
@@ -1,12 +1,12 @@
/**
* Implementation of a bit array.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d, root/_bitarray.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/bitarray.d, root/_bitarray.d)
* Documentation: https://dlang.org/phobos/dmd_root_array.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/bitarray.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/bitarray.d
*/
module dmd.root.bitarray;
diff --git a/gcc/d/dmd/root/bitarray.h b/gcc/d/dmd/root/bitarray.h
index 2a82703..c50247f 100644
--- a/gcc/d/dmd/root/bitarray.h
+++ b/gcc/d/dmd/root/bitarray.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 2011-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -15,7 +15,7 @@ struct BitArray
{
BitArray()
: len(0)
- , ptr(NULL)
+ , ptr(nullptr)
{}
~BitArray()
diff --git a/gcc/d/dmd/root/complex.d b/gcc/d/dmd/root/complex.d
index de4c8d34..777c103 100644
--- a/gcc/d/dmd/root/complex.d
+++ b/gcc/d/dmd/root/complex.d
@@ -1,12 +1,12 @@
/**
* Implements a complex number type.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/complex.d, _complex.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/complex.d, _complex.d)
* Documentation: https://dlang.org/phobos/dmd_root_complex.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/complex.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/complex.d
*/
module dmd.root.complex;
diff --git a/gcc/d/dmd/root/complex_t.h b/gcc/d/dmd/root/complex_t.h
index 8134f9e..58a0705 100644
--- a/gcc/d/dmd/root/complex_t.h
+++ b/gcc/d/dmd/root/complex_t.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/root/ctfloat.d b/gcc/d/dmd/root/ctfloat.d
index 70446066..eb3b71c 100644
--- a/gcc/d/dmd/root/ctfloat.d
+++ b/gcc/d/dmd/root/ctfloat.d
@@ -1,12 +1,12 @@
/**
* Collects functions for compile-time floating-point calculations.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d, root/_ctfloat.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/ctfloat.d, root/_ctfloat.d)
* Documentation: https://dlang.org/phobos/dmd_root_ctfloat.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/ctfloat.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/ctfloat.d
*/
module dmd.root.ctfloat;
diff --git a/gcc/d/dmd/root/ctfloat.h b/gcc/d/dmd/root/ctfloat.h
index ba8b447..815839c 100644
--- a/gcc/d/dmd/root/ctfloat.h
+++ b/gcc/d/dmd/root/ctfloat.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/root/dcompat.h b/gcc/d/dmd/root/dcompat.h
index db2b2c6..1c89b57 100644
--- a/gcc/d/dmd/root/dcompat.h
+++ b/gcc/d/dmd/root/dcompat.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -18,7 +18,7 @@ struct DArray
size_t length;
T *ptr;
- DArray() : length(0), ptr(NULL) { }
+ DArray() : length(0), ptr(nullptr) { }
DArray(size_t length_in, T *ptr_in)
: length(length_in), ptr(ptr_in) { }
diff --git a/gcc/d/dmd/root/dsystem.h b/gcc/d/dmd/root/dsystem.h
index 49404b7..df343dc 100644
--- a/gcc/d/dmd/root/dsystem.h
+++ b/gcc/d/dmd/root/dsystem.h
@@ -1,5 +1,5 @@
/* dsystem.h -- Get common system includes from the host.
- * Copyright (C) 2018-2024 Free Software Foundation, Inc.
+ * Copyright (C) 2018-2025 Free Software Foundation, Inc.
*
* GCC is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d
index a4362e1..2046e59 100644
--- a/gcc/d/dmd/root/file.d
+++ b/gcc/d/dmd/root/file.d
@@ -1,12 +1,12 @@
/**
* Read a file from disk and store it in memory.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/file.d, root/_file.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/file.d, root/_file.d)
* Documentation: https://dlang.org/phobos/dmd_root_file.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/file.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/file.d
*/
module dmd.root.file;
@@ -19,11 +19,13 @@ import core.sys.posix.fcntl;
import core.sys.posix.unistd;
import core.sys.windows.winbase;
import core.sys.windows.winnt;
+
import dmd.root.filename;
import dmd.root.rmem;
import dmd.root.string;
import dmd.common.file;
+import dmd.common.outbuffer;
import dmd.common.smallbuffer;
nothrow:
@@ -76,62 +78,52 @@ struct File
}
nothrow:
- /// Read the full content of a file.
- static ReadResult read(const(char)[] name)
+ /** Read the full content of a file, and append it to `buffer`
+ * Params:
+ * name = name of file
+ * buffer = file contents appended to it
+ * Returns:
+ * false = success, true = failed
+ */
+ static bool read(const char[] name, ref OutBuffer buffer)
{
- ReadResult result;
+ enum Success = false;
+ enum Failure = true;
version (Posix)
{
- size_t size;
- stat_t buf;
- ssize_t numread;
- //printf("File::read('%s')\n",name);
+ //printf("File::read('%.*s')\n", cast(int)name.length, name.ptr);
int fd = name.toCStringThen!(slice => open(slice.ptr, O_RDONLY));
if (fd == -1)
{
//perror("\topen error");
- return result;
+ return Failure;
}
//printf("\tfile opened\n");
- if (fstat(fd, &buf))
+ stat_t statbuf;
+ if (fstat(fd, &statbuf))
{
//perror("\tfstat error");
close(fd);
- return result;
+ return Failure;
}
- size = cast(size_t)buf.st_size;
- ubyte* buffer = cast(ubyte*)mem.xmalloc_noscan(size + 4);
- numread = .read(fd, buffer, size);
+ size_t size = cast(size_t)statbuf.st_size;
+ auto buf = buffer.allocate(size);
+ ssize_t numread = .read(fd, buf.ptr, size);
if (numread != size)
{
//perror("\tread error");
- goto err2;
+ close(fd);
+ return Failure;
}
if (close(fd) == -1)
{
//perror("\tclose error");
- goto err;
+ return Failure;
}
- // Always store a wchar ^Z past end of buffer so scanner has a
- // sentinel, although ^Z got obselete, so fill with two 0s and add
- // two more so lexer doesn't read pass the buffer.
- buffer[size .. size + 4] = 0;
-
- result.success = true;
- result.buffer.data = buffer[0 .. size];
- return result;
- err2:
- close(fd);
- err:
- mem.xfree(buffer);
- return result;
}
else version (Windows)
{
- DWORD size;
- DWORD numread;
-
// work around Windows file path length limitation
// (see documentation for extendedPathThen).
HANDLE h = name.extendedPathThen!
@@ -143,32 +135,24 @@ nothrow:
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
null));
if (h == INVALID_HANDLE_VALUE)
- return result;
- size = GetFileSize(h, null);
- ubyte* buffer = cast(ubyte*)mem.xmalloc_noscan(size + 4);
- if (ReadFile(h, buffer, size, &numread, null) != TRUE)
- goto err2;
- if (numread != size)
- goto err2;
+ return Failure;
+ DWORD size = GetFileSize(h, null);
+ auto buf = buffer.allocate(size);
+ DWORD numread;
+ if (ReadFile(h, buf.ptr, size, &numread, null) != TRUE ||
+ numread != size)
+ {
+ CloseHandle(h);
+ return Failure;
+ }
if (!CloseHandle(h))
- goto err;
- // Always store a wchar ^Z past end of buffer so scanner has a
- // sentinel, although ^Z got obselete, so fill with two 0s and add
- // two more so lexer doesn't read pass the buffer.
- buffer[size .. size + 4] = 0;
- result.success = true;
- result.buffer.data = buffer[0 .. size];
- return result;
- err2:
- CloseHandle(h);
- err:
- mem.xfree(buffer);
- return result;
+ return Failure;
}
else
{
- assert(0);
+ static assert(0);
}
+ return Success;
}
/// Write a file, returning `true` on success.
diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d
index d9f1a04..5ad0775 100644
--- a/gcc/d/dmd/root/filename.d
+++ b/gcc/d/dmd/root/filename.d
@@ -1,18 +1,19 @@
/**
* Encapsulate path and file names.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.d, root/_filename.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/filename.d, root/_filename.d)
* Documentation: https://dlang.org/phobos/dmd_root_filename.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/filename.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/filename.d
*/
module dmd.root.filename;
import core.stdc.ctype;
import core.stdc.errno;
+import core.stdc.stdio;
import core.stdc.string;
import dmd.common.file;
@@ -41,7 +42,8 @@ version (Windows)
extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc;
extern (Windows) void SetLastError(DWORD) nothrow @nogc;
- extern (C) char* getcwd(char* buffer, size_t maxlen) nothrow;
+ extern (C) char* _getcwd(char* buffer, size_t maxlen) nothrow;
+ alias getcwd = _getcwd;
}
version (CRuntime_Glibc)
@@ -270,6 +272,20 @@ nothrow:
}
/********************************
+ * Slice of file name without extension.
+ * Params:
+ * filename = file name
+ * Returns:
+ * the slice
+ */
+ extern (D) static const(char)[] sansExt(const char[] filename) @safe
+ {
+ auto e = ext(filename);
+ size_t length = e.length;
+ return filename[0 .. filename.length - (length ? length + 1 : 0)]; // +1 for .
+ }
+
+ /********************************
* Return filename name excluding path (read-only).
*/
extern (C++) static const(char)* name(const(char)* str) pure @nogc
@@ -452,17 +468,15 @@ nothrow:
assert(buildPath("a/", "bb", "ccc") == "a/bb/ccc");
}
- // Split a path into an Array of paths
- extern (C++) static Strings* splitPath(const(char)* path)
+ // Split a path and append the results to `array`
+ extern (C++) static void appendSplitPath(const(char)* path, ref Strings array)
{
- auto array = new Strings();
int sink(const(char)* p) nothrow
{
array.push(p);
return 0;
}
splitPath(&sink, path);
- return array;
}
/****
@@ -578,13 +592,13 @@ nothrow:
/***************************
* Free returned value with FileName::free()
*/
- extern (C++) static const(char)* defaultExt(const(char)* name, const(char)* ext)
+ extern (C++) static const(char)* defaultExt(const(char)* name, const(char)* ext) pure
{
return defaultExt(name.toDString, ext.toDString).ptr;
}
/// Ditto
- extern (D) static const(char)[] defaultExt(const char[] name, const char[] ext)
+ extern (D) static const(char)[] defaultExt(const char[] name, const char[] ext) pure
{
auto e = FileName.ext(name);
if (e.length) // it already has an extension
@@ -602,13 +616,13 @@ nothrow:
/***************************
* Free returned value with FileName::free()
*/
- extern (C++) static const(char)* forceExt(const(char)* name, const(char)* ext)
+ extern (C++) static const(char)* forceExt(const(char)* name, const(char)* ext) pure
{
return forceExt(name.toDString, ext.toDString).ptr;
}
/// Ditto
- extern (D) static const(char)[] forceExt(const char[] name, const char[] ext)
+ extern (D) static const(char)[] forceExt(const char[] name, const char[] ext) pure
{
if (auto e = FileName.ext(name))
return addExt(name[0 .. $ - e.length - 1], ext);
@@ -846,6 +860,7 @@ nothrow:
{
if (!name.length)
return 0;
+ //static int count; printf("count: %d %.*s\n", ++count, cast(int)name.length, name.ptr);
version (Posix)
{
stat_t st;
@@ -862,10 +877,9 @@ nothrow:
const dw = GetFileAttributesW(&wname[0]);
if (dw == -1)
return 0;
- else if (dw & FILE_ATTRIBUTE_DIRECTORY)
+ if (dw & FILE_ATTRIBUTE_DIRECTORY)
return 2;
- else
- return 1;
+ return 1;
});
}
else
@@ -1087,7 +1101,7 @@ nothrow:
return str.ptr;
}
- const(char)[] toString() const pure nothrow @nogc @trusted
+ const(char)[] toString() const pure nothrow @nogc @safe
{
return str;
}
diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h
index e8c8b11..4f78221 100644
--- a/gcc/d/dmd/root/filename.h
+++ b/gcc/d/dmd/root/filename.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -22,7 +22,7 @@ public:
static FileName create(const char *name);
static bool equals(const char *name1, const char *name2);
static bool absolute(const char *name);
- static const char *toAbsolute(const char *name, const char *base = NULL);
+ static const char *toAbsolute(const char *name, const char *base = nullptr);
static const char *ext(const char *);
const char *ext();
static const char *removeExt(const char *str);
@@ -31,7 +31,7 @@ public:
static const char *path(const char *);
static const char *combine(const char *path, const char *name);
- static Strings *splitPath(const char *path);
+ static void appendSplitPath(const char *path, Strings& array);
static const char *defaultExt(const char *name, const char *ext);
static const char *forceExt(const char *name, const char *ext);
static bool equalsExt(const char *name, const char *ext);
diff --git a/gcc/d/dmd/root/hash.d b/gcc/d/dmd/root/hash.d
index 441620e..d327f4b 100644
--- a/gcc/d/dmd/root/hash.d
+++ b/gcc/d/dmd/root/hash.d
@@ -1,12 +1,12 @@
/**
* Hash functions for arbitrary binary data.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Martin Nowak, Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d, root/_hash.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/hash.d, root/_hash.d)
* Documentation: https://dlang.org/phobos/dmd_root_hash.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/hash.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/hash.d
*/
module dmd.root.hash;
diff --git a/gcc/d/dmd/root/longdouble.d b/gcc/d/dmd/root/longdouble.d
index 1f73fb7..d9f5c0e 100644
--- a/gcc/d/dmd/root/longdouble.d
+++ b/gcc/d/dmd/root/longdouble.d
@@ -1,6 +1,6 @@
/**
* 80-bit floating point value implementation if the C/D compiler does not support them natively.
- * Copyright (C) 2021-2024 Free Software Foundation, Inc.
+ * Copyright (C) 2021-2025 Free Software Foundation, Inc.
*
* GCC is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -43,7 +43,7 @@ pure:
extern (D) longdouble opAssign(T)(T r)
if (is (T : longdouble))
{
- this.realvalue = r.realvalue;
+ this.realvalue = r.realvalue;
return this;
}
diff --git a/gcc/d/dmd/root/optional.d b/gcc/d/dmd/root/optional.d
index e7d0e1e..2b518eb 100644
--- a/gcc/d/dmd/root/optional.d
+++ b/gcc/d/dmd/root/optional.d
@@ -1,12 +1,12 @@
/**
* Implementation of an 'Optional' type
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.d, root/_optional.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/optional.d, root/_optional.d)
* Documentation: https://dlang.org/phobos/dmd_root_optional.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/optional.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/optional.d
*/
module dmd.root.optional;
diff --git a/gcc/d/dmd/root/optional.h b/gcc/d/dmd/root/optional.h
index a92dedd..12891f8 100644
--- a/gcc/d/dmd/root/optional.h
+++ b/gcc/d/dmd/root/optional.h
@@ -3,12 +3,12 @@
/**
* Optional implementation.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.h, root/_optional.h)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/optional.h, root/_optional.h)
* Documentation: https://dlang.org/phobos/dmd_root_optional.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/optional.h
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/optional.h
*/
#include "dcompat.h" // for d_bool
diff --git a/gcc/d/dmd/root/port.d b/gcc/d/dmd/root/port.d
index ee846bd..5fd8080 100644
--- a/gcc/d/dmd/root/port.d
+++ b/gcc/d/dmd/root/port.d
@@ -1,12 +1,12 @@
/**
* Portable routines for functions that have different implementations on different platforms.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d, root/_port.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/port.d, root/_port.d)
* Documentation: https://dlang.org/phobos/dmd_root_port.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/port.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/port.d
*/
module dmd.root.port;
diff --git a/gcc/d/dmd/root/port.h b/gcc/d/dmd/root/port.h
index 6c7dddd..dfb56b0 100644
--- a/gcc/d/dmd/root/port.h
+++ b/gcc/d/dmd/root/port.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/root/region.d b/gcc/d/dmd/root/region.d
index a9fab16..a8efbca 100644
--- a/gcc/d/dmd/root/region.d
+++ b/gcc/d/dmd/root/region.d
@@ -1,12 +1,12 @@
/**
* Region storage allocator implementation.
*
- * Copyright: Copyright (C) 2019-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 2019-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d, root/_region.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/region.d, root/_region.d)
* Documentation: https://dlang.org/phobos/dmd_root_region.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/region.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/region.d
*/
module dmd.root.region;
diff --git a/gcc/d/dmd/root/rmem.d b/gcc/d/dmd/root/rmem.d
index 1965207..32d22d3 100644
--- a/gcc/d/dmd/root/rmem.d
+++ b/gcc/d/dmd/root/rmem.d
@@ -1,12 +1,12 @@
/**
* Allocate memory using `malloc` or the GC depending on the configuration.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d, root/_rmem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/rmem.d, root/_rmem.d)
* Documentation: https://dlang.org/phobos/dmd_root_rmem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/rmem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/rmem.d
*/
module dmd.root.rmem;
@@ -149,6 +149,7 @@ enum CHUNK_SIZE = (256 * 4096 - 64);
__gshared size_t heapleft = 0;
__gshared void* heapp;
+__gshared size_t heapTotal = 0; // Total amount of memory allocated using malloc
extern (D) void* allocmemoryNoFree(size_t m_size) nothrow @nogc
{
@@ -167,11 +168,13 @@ extern (D) void* allocmemoryNoFree(size_t m_size) nothrow @nogc
if (m_size > CHUNK_SIZE)
{
+ heapTotal += m_size;
return Mem.check(malloc(m_size));
}
heapleft = CHUNK_SIZE;
heapp = Mem.check(malloc(CHUNK_SIZE));
+ heapTotal += CHUNK_SIZE;
goto L1;
}
@@ -318,7 +321,7 @@ Params:
Returns: A null-terminated copy of the input array.
*/
-extern (D) char[] xarraydup(const(char)[] s) pure nothrow
+extern (D) char[] xarraydup(scope const(char)[] s) pure nothrow
{
if (!s)
return null;
diff --git a/gcc/d/dmd/root/rmem.h b/gcc/d/dmd/root/rmem.h
index 09c0fc0..b6645ec 100644
--- a/gcc/d/dmd/root/rmem.h
+++ b/gcc/d/dmd/root/rmem.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/root/speller.d b/gcc/d/dmd/root/speller.d
index ae09cba..a215110 100644
--- a/gcc/d/dmd/root/speller.d
+++ b/gcc/d/dmd/root/speller.d
@@ -3,12 +3,12 @@
*
* Does not have any dependencies on the rest of DMD.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/speller.d, root/_speller.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/speller.d, root/_speller.d)
* Documentation: https://dlang.org/phobos/dmd_root_speller.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/speller.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/speller.d
*/
module dmd.root.speller;
diff --git a/gcc/d/dmd/root/string.d b/gcc/d/dmd/root/string.d
index e82b0d2..369a79b 100644
--- a/gcc/d/dmd/root/string.d
+++ b/gcc/d/dmd/root/string.d
@@ -1,15 +1,18 @@
/**
* Contains various string related functions.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/string.d, root/_string.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/string.d, root/_string.d)
* Documentation: https://dlang.org/phobos/dmd_root_string.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/string.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/string.d
*/
module dmd.root.string;
+import core.stdc.string;
+import dmd.root.rmem;
+
/// Slices a `\0`-terminated C-string, excluding the terminator
inout(char)[] toDString (inout(char)* s) pure nothrow @nogc
{
@@ -17,6 +20,27 @@ inout(char)[] toDString (inout(char)* s) pure nothrow @nogc
return s ? s[0 .. strlen(s)] : null;
}
+private struct FTuple(T...)
+{
+ T expand;
+}
+
+/// Returns: a (length, ptr) tuple for passing a D string to `printf`-style functions with the format string `%.*s`
+auto fTuple(const(char)[] str)
+{
+ return FTuple!(int, const(char)*)(cast(int) str.length, str.ptr);
+}
+
+///
+unittest
+{
+ import core.stdc.stdio: snprintf;
+ char[6] buf = '.';
+ const(char)[] str = "cutoff"[0..4];
+ snprintf(buf.ptr, buf.length, "%.*s", str.fTuple.expand);
+ assert(buf[] == "cuto\0.");
+}
+
/**
Compare two slices for equality, in a case-insensitive way
@@ -87,6 +111,23 @@ unittest
assert(null.toCStringThen!((v) => v == "\0"));
}
+/*********************************************
+ * Convert a D string to a C string by allocating memory,
+ * copying it, and adding a terminating 0.
+ * Params:
+ * s = string to copy
+ * Result:
+ * 0-terminated copy of s
+ */
+char[] toCString(scope const(char)[] s) nothrow
+{
+ const length = s.length;
+ char* p = cast(char*)mem.xmalloc_noscan(length + 1);
+ memcpy(p, s.ptr, length);
+ p[length] = 0;
+ return p[0 .. length];
+}
+
/**
* Strips one leading line terminator of the given string.
*
@@ -274,6 +315,15 @@ do
return true;
}
+///ditto
+nothrow @nogc pure @safe
+bool startsWith(scope const(char)[] str, scope const(char)[] prefix)
+{
+ if (str.length < prefix.length)
+ return false;
+ return str[0 .. prefix.length] == prefix;
+}
+
///
@system pure nothrow @nogc
unittest
@@ -286,3 +336,184 @@ unittest
assert(ptr.startsWith("123"));
assert(!ptr.startsWith("1234"));
}
+
+/**********************************
+ * Take `text` and turn it into an InputRange that emits
+ * slices into `text` for each line.
+ * Params:
+ * text = array of characters
+ * Returns:
+ * InputRange accessing `text` as a sequence of lines
+ * Reference:
+ * `std.string.splitLines()`
+ */
+auto splitLines(const char[] text)
+{
+ struct Range
+ {
+ @safe:
+ @nogc:
+ nothrow:
+ pure:
+ private:
+
+ const char[] text;
+ size_t index; // index of start of line
+ size_t eolIndex; // index of end of line before newline characters
+ size_t nextIndex; // index past end of line
+
+ public this(const char[] text)
+ {
+ this.text = text;
+ this.index = 0;
+ this.eolIndex = 0;
+ this.nextIndex = 0;
+ }
+
+ public bool empty() { advance(); return index >= text.length; }
+
+ public void popFront() { advance(); index = nextIndex; }
+
+ public const(char)[] front()
+ {
+ advance();
+ if (index > eolIndex || index >= text.length)
+ return "";
+
+ return text[index .. eolIndex];
+ }
+
+ private void advance()
+ {
+ if (index != nextIndex) // if already advanced
+ return;
+
+ for (size_t i = index; i < text.length; ++i)
+ {
+ switch (text[i])
+ {
+ case '\v', '\f', '\n':
+ eolIndex = i;
+ nextIndex = i + 1;
+ return;
+
+ case '\r':
+ if (i + 1 < text.length && text[i + 1] == '\n') // decode "\r\n"
+ {
+ eolIndex = i;
+ nextIndex = i + 2;
+ return;
+ }
+ eolIndex = i;
+ nextIndex = i + 1;
+ return;
+
+ /* Manually decode:
+ * NEL is C2 85
+ */
+ case 0xC2:
+ if (i + 1 < text.length && text[i + 1] == 0x85)
+ {
+ eolIndex = i;
+ nextIndex = i + 2;
+ return;
+ }
+ break;
+
+ /* Manually decode:
+ * lineSep is E2 80 A8
+ * paraSep is E2 80 A9
+ */
+ case 0xE2:
+ if (i + 2 < text.length &&
+ text[i + 1] == 0x80 &&
+ (text[i + 2] == 0xA8 || text[i + 2] == 0xA9)
+ )
+ {
+ eolIndex = i;
+ nextIndex = i + 3;
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // No newline found; set indices to the end of the text
+ eolIndex = text.length;
+ nextIndex = text.length;
+ }
+ }
+
+ return Range(text);
+}
+
+private struct FindSplit
+{
+@nogc nothrow pure @safe:
+ const(char)[][3] elem;
+
+ ref const(char)[] opIndex(size_t i) scope return { return elem[i]; }
+ bool opCast() const scope { return elem[1].length > 0; }
+}
+
+/**
+Find a substring in a string and split the string into before and after parts.
+Params:
+ str = string to look into
+ needle = substring to find in str (must not be empty)
+Returns:
+ a `FindSplit` object that casts to `true` iff `needle` was found inside `str`.
+ In that case, `split[1]` is the needle, and `split[0]`/`split[2]` are before/after the needle.
+*/
+FindSplit findSplit(return scope const(char)[] str, scope const(char)[] needle) @safe
+{
+ if (needle.length > str.length)
+ return FindSplit([str, null, null]);
+
+ foreach (i; 0 .. str.length - needle.length + 1)
+ {
+ if (str[i .. i+needle.length] == needle[])
+ return FindSplit([ str[0 .. i], str[i .. i+needle.length], str[i+needle.length .. $] ]);
+ }
+ return FindSplit([str, null, null]);
+}
+
+unittest
+{
+ auto s = findSplit("a b c", "c");
+ assert(s[0] == "a b ");
+ assert(s[1] == "c");
+ assert(s[2] == "");
+ auto s1 = findSplit("a b c", "b");
+ assert(s1[0] == "a ");
+ assert(s1[1] == "b");
+ assert(s1[2] == " c");
+ assert(!findSplit("a b c", "d"));
+ assert(!findSplit("", "d"));
+}
+
+/**
+Find a string inbetween two substrings
+Params:
+ str = string to look into
+ l = substring to find on the left
+ r = substring to find on the right
+Returns:
+ substring of `str` inbetween `l` and `r`
+*/
+const(char)[] findBetween(const(char)[] str, const(char)[] l, const(char)[] r) @safe
+{
+ if (auto s0 = str.findSplit(l))
+ if (auto s1 = s0[2].findSplit(r))
+ return s1[0];
+ return null;
+}
+
+unittest
+{
+ assert(findBetween("a b c", "a ", " c") == "b");
+ assert(findBetween("a b c", "a ", " d") == null);
+}
diff --git a/gcc/d/dmd/root/stringtable.d b/gcc/d/dmd/root/stringtable.d
index 1fba919..c7a2c8c 100644
--- a/gcc/d/dmd/root/stringtable.d
+++ b/gcc/d/dmd/root/stringtable.d
@@ -1,12 +1,12 @@
/**
* A specialized associative array with string keys stored in a variable length structure.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d, root/_stringtable.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/stringtable.d, root/_stringtable.d)
* Documentation: https://dlang.org/phobos/dmd_root_stringtable.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/stringtable.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/stringtable.d
*/
module dmd.root.stringtable;
diff --git a/gcc/d/dmd/root/utf.d b/gcc/d/dmd/root/utf.d
index 7d732f2..5b2c42f 100644
--- a/gcc/d/dmd/root/utf.d
+++ b/gcc/d/dmd/root/utf.d
@@ -1,12 +1,12 @@
/**
* Functions related to UTF encoding.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/utf.d, _utf.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/utf.d, _utf.d)
* Documentation: https://dlang.org/phobos/dmd_root_utf.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/utf.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/root/utf.d
*/
module dmd.root.utf;
@@ -27,281 +27,6 @@ bool utf_isValidDchar(dchar c)
return false;
}
-/*******************************
- * Return !=0 if unicode alpha.
- * Use table from C99 Appendix D.
- */
-bool isUniAlpha(dchar c)
-{
- static immutable wchar[2][] ALPHA_TABLE =
- [
- [0x00AA, 0x00AA],
- [0x00B5, 0x00B5],
- [0x00B7, 0x00B7],
- [0x00BA, 0x00BA],
- [0x00C0, 0x00D6],
- [0x00D8, 0x00F6],
- [0x00F8, 0x01F5],
- [0x01FA, 0x0217],
- [0x0250, 0x02A8],
- [0x02B0, 0x02B8],
- [0x02BB, 0x02BB],
- [0x02BD, 0x02C1],
- [0x02D0, 0x02D1],
- [0x02E0, 0x02E4],
- [0x037A, 0x037A],
- [0x0386, 0x0386],
- [0x0388, 0x038A],
- [0x038C, 0x038C],
- [0x038E, 0x03A1],
- [0x03A3, 0x03CE],
- [0x03D0, 0x03D6],
- [0x03DA, 0x03DA],
- [0x03DC, 0x03DC],
- [0x03DE, 0x03DE],
- [0x03E0, 0x03E0],
- [0x03E2, 0x03F3],
- [0x0401, 0x040C],
- [0x040E, 0x044F],
- [0x0451, 0x045C],
- [0x045E, 0x0481],
- [0x0490, 0x04C4],
- [0x04C7, 0x04C8],
- [0x04CB, 0x04CC],
- [0x04D0, 0x04EB],
- [0x04EE, 0x04F5],
- [0x04F8, 0x04F9],
- [0x0531, 0x0556],
- [0x0559, 0x0559],
- [0x0561, 0x0587],
- [0x05B0, 0x05B9],
- [0x05BB, 0x05BD],
- [0x05BF, 0x05BF],
- [0x05C1, 0x05C2],
- [0x05D0, 0x05EA],
- [0x05F0, 0x05F2],
- [0x0621, 0x063A],
- [0x0640, 0x0652],
- [0x0660, 0x0669],
- [0x0670, 0x06B7],
- [0x06BA, 0x06BE],
- [0x06C0, 0x06CE],
- [0x06D0, 0x06DC],
- [0x06E5, 0x06E8],
- [0x06EA, 0x06ED],
- [0x06F0, 0x06F9],
- [0x0901, 0x0903],
- [0x0905, 0x0939],
- [0x093D, 0x094D],
- [0x0950, 0x0952],
- [0x0958, 0x0963],
- [0x0966, 0x096F],
- [0x0981, 0x0983],
- [0x0985, 0x098C],
- [0x098F, 0x0990],
- [0x0993, 0x09A8],
- [0x09AA, 0x09B0],
- [0x09B2, 0x09B2],
- [0x09B6, 0x09B9],
- [0x09BE, 0x09C4],
- [0x09C7, 0x09C8],
- [0x09CB, 0x09CD],
- [0x09DC, 0x09DD],
- [0x09DF, 0x09E3],
- [0x09E6, 0x09F1],
- [0x0A02, 0x0A02],
- [0x0A05, 0x0A0A],
- [0x0A0F, 0x0A10],
- [0x0A13, 0x0A28],
- [0x0A2A, 0x0A30],
- [0x0A32, 0x0A33],
- [0x0A35, 0x0A36],
- [0x0A38, 0x0A39],
- [0x0A3E, 0x0A42],
- [0x0A47, 0x0A48],
- [0x0A4B, 0x0A4D],
- [0x0A59, 0x0A5C],
- [0x0A5E, 0x0A5E],
- [0x0A66, 0x0A6F],
- [0x0A74, 0x0A74],
- [0x0A81, 0x0A83],
- [0x0A85, 0x0A8B],
- [0x0A8D, 0x0A8D],
- [0x0A8F, 0x0A91],
- [0x0A93, 0x0AA8],
- [0x0AAA, 0x0AB0],
- [0x0AB2, 0x0AB3],
- [0x0AB5, 0x0AB9],
- [0x0ABD, 0x0AC5],
- [0x0AC7, 0x0AC9],
- [0x0ACB, 0x0ACD],
- [0x0AD0, 0x0AD0],
- [0x0AE0, 0x0AE0],
- [0x0AE6, 0x0AEF],
- [0x0B01, 0x0B03],
- [0x0B05, 0x0B0C],
- [0x0B0F, 0x0B10],
- [0x0B13, 0x0B28],
- [0x0B2A, 0x0B30],
- [0x0B32, 0x0B33],
- [0x0B36, 0x0B39],
- [0x0B3D, 0x0B43],
- [0x0B47, 0x0B48],
- [0x0B4B, 0x0B4D],
- [0x0B5C, 0x0B5D],
- [0x0B5F, 0x0B61],
- [0x0B66, 0x0B6F],
- [0x0B82, 0x0B83],
- [0x0B85, 0x0B8A],
- [0x0B8E, 0x0B90],
- [0x0B92, 0x0B95],
- [0x0B99, 0x0B9A],
- [0x0B9C, 0x0B9C],
- [0x0B9E, 0x0B9F],
- [0x0BA3, 0x0BA4],
- [0x0BA8, 0x0BAA],
- [0x0BAE, 0x0BB5],
- [0x0BB7, 0x0BB9],
- [0x0BBE, 0x0BC2],
- [0x0BC6, 0x0BC8],
- [0x0BCA, 0x0BCD],
- [0x0BE7, 0x0BEF],
- [0x0C01, 0x0C03],
- [0x0C05, 0x0C0C],
- [0x0C0E, 0x0C10],
- [0x0C12, 0x0C28],
- [0x0C2A, 0x0C33],
- [0x0C35, 0x0C39],
- [0x0C3E, 0x0C44],
- [0x0C46, 0x0C48],
- [0x0C4A, 0x0C4D],
- [0x0C60, 0x0C61],
- [0x0C66, 0x0C6F],
- [0x0C82, 0x0C83],
- [0x0C85, 0x0C8C],
- [0x0C8E, 0x0C90],
- [0x0C92, 0x0CA8],
- [0x0CAA, 0x0CB3],
- [0x0CB5, 0x0CB9],
- [0x0CBE, 0x0CC4],
- [0x0CC6, 0x0CC8],
- [0x0CCA, 0x0CCD],
- [0x0CDE, 0x0CDE],
- [0x0CE0, 0x0CE1],
- [0x0CE6, 0x0CEF],
- [0x0D02, 0x0D03],
- [0x0D05, 0x0D0C],
- [0x0D0E, 0x0D10],
- [0x0D12, 0x0D28],
- [0x0D2A, 0x0D39],
- [0x0D3E, 0x0D43],
- [0x0D46, 0x0D48],
- [0x0D4A, 0x0D4D],
- [0x0D60, 0x0D61],
- [0x0D66, 0x0D6F],
- [0x0E01, 0x0E3A],
- [0x0E40, 0x0E5B],
- [0x0E81, 0x0E82],
- [0x0E84, 0x0E84],
- [0x0E87, 0x0E88],
- [0x0E8A, 0x0E8A],
- [0x0E8D, 0x0E8D],
- [0x0E94, 0x0E97],
- [0x0E99, 0x0E9F],
- [0x0EA1, 0x0EA3],
- [0x0EA5, 0x0EA5],
- [0x0EA7, 0x0EA7],
- [0x0EAA, 0x0EAB],
- [0x0EAD, 0x0EAE],
- [0x0EB0, 0x0EB9],
- [0x0EBB, 0x0EBD],
- [0x0EC0, 0x0EC4],
- [0x0EC6, 0x0EC6],
- [0x0EC8, 0x0ECD],
- [0x0ED0, 0x0ED9],
- [0x0EDC, 0x0EDD],
- [0x0F00, 0x0F00],
- [0x0F18, 0x0F19],
- [0x0F20, 0x0F33],
- [0x0F35, 0x0F35],
- [0x0F37, 0x0F37],
- [0x0F39, 0x0F39],
- [0x0F3E, 0x0F47],
- [0x0F49, 0x0F69],
- [0x0F71, 0x0F84],
- [0x0F86, 0x0F8B],
- [0x0F90, 0x0F95],
- [0x0F97, 0x0F97],
- [0x0F99, 0x0FAD],
- [0x0FB1, 0x0FB7],
- [0x0FB9, 0x0FB9],
- [0x10A0, 0x10C5],
- [0x10D0, 0x10F6],
- [0x1E00, 0x1E9B],
- [0x1EA0, 0x1EF9],
- [0x1F00, 0x1F15],
- [0x1F18, 0x1F1D],
- [0x1F20, 0x1F45],
- [0x1F48, 0x1F4D],
- [0x1F50, 0x1F57],
- [0x1F59, 0x1F59],
- [0x1F5B, 0x1F5B],
- [0x1F5D, 0x1F5D],
- [0x1F5F, 0x1F7D],
- [0x1F80, 0x1FB4],
- [0x1FB6, 0x1FBC],
- [0x1FBE, 0x1FBE],
- [0x1FC2, 0x1FC4],
- [0x1FC6, 0x1FCC],
- [0x1FD0, 0x1FD3],
- [0x1FD6, 0x1FDB],
- [0x1FE0, 0x1FEC],
- [0x1FF2, 0x1FF4],
- [0x1FF6, 0x1FFC],
- [0x203F, 0x2040],
- [0x207F, 0x207F],
- [0x2102, 0x2102],
- [0x2107, 0x2107],
- [0x210A, 0x2113],
- [0x2115, 0x2115],
- [0x2118, 0x211D],
- [0x2124, 0x2124],
- [0x2126, 0x2126],
- [0x2128, 0x2128],
- [0x212A, 0x2131],
- [0x2133, 0x2138],
- [0x2160, 0x2182],
- [0x3005, 0x3007],
- [0x3021, 0x3029],
- [0x3041, 0x3093],
- [0x309B, 0x309C],
- [0x30A1, 0x30F6],
- [0x30FB, 0x30FC],
- [0x3105, 0x312C],
- [0x4E00, 0x9FA5],
- [0xAC00, 0xD7A3]
- ];
-
- size_t high = ALPHA_TABLE.length - 1;
- // Shortcut search if c is out of range
- size_t low = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0;
- // Binary search
- while (low <= high)
- {
- const size_t mid = low + ((high - low) >> 1);
- if (c < ALPHA_TABLE[mid][0])
- high = mid - 1;
- else if (ALPHA_TABLE[mid][1] < c)
- low = mid + 1;
- else
- {
- assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]);
- return true;
- }
- }
- return false;
-}
-
/**
* Returns the code length of c in code units.
*/
diff --git a/gcc/d/dmd/rootobject.d b/gcc/d/dmd/rootobject.d
index 7c926fe..71b36a4 100644
--- a/gcc/d/dmd/rootobject.d
+++ b/gcc/d/dmd/rootobject.d
@@ -1,12 +1,12 @@
/**
* Provide the root object that AST classes in dmd inherit from.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: Walter Bright, https://www.digitalmars.com
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/rootobject.d, _rootobject.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/rootobject.d, _rootobject.d)
* Documentation: https://dlang.org/phobos/dmd_rootobject.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/rootobject.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/rootobject.d
*/
module dmd.rootobject;
diff --git a/gcc/d/dmd/rootobject.h b/gcc/d/dmd/rootobject.h
index 718a54f..330d2c9 100644
--- a/gcc/d/dmd/rootobject.h
+++ b/gcc/d/dmd/rootobject.h
@@ -1,5 +1,5 @@
-/* Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+/* Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index 1e5fb47..3be9efe 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/function.html#function-safety, Function Safety)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/safe.d, _safe.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/safe.d, _safe.d)
* Documentation: https://dlang.org/phobos/dmd_safe.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/safe.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/safe.d
*/
module dmd.safe;
@@ -17,17 +17,27 @@ import core.stdc.stdio;
import dmd.aggregate;
import dmd.astenums;
+import dmd.common.outbuffer;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem : determineSize;
+import dmd.errors;
import dmd.expression;
+import dmd.func;
+import dmd.funcsem : isRootTraitsCompilesScope;
+import dmd.globals : FeatureState, global;
import dmd.id;
import dmd.identifier;
+import dmd.location;
import dmd.mtype;
+import dmd.rootobject;
+import dmd.root.string : fTuple;
import dmd.target;
import dmd.tokens;
-import dmd.typesem : hasPointers, arrayOf;
-import dmd.func : setUnsafe, setUnsafePreview;
+import dmd.typesem : hasPointers, arrayOf, size;
/*************************************************************
* Check for unsafe access in @safe code:
@@ -49,92 +59,103 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
//printf("checkUnsafeAccess(e: '%s', readonly: %d, printmsg: %d)\n", e.toChars(), readonly, printmsg);
if (e.op != EXP.dotVariable)
return false;
- DotVarExp dve = cast(DotVarExp)e;
- if (VarDeclaration v = dve.var.isVarDeclaration())
- {
- if (!sc.func)
- return false;
- auto ad = v.isMember2();
- if (!ad)
- return false;
+ auto dve = cast(DotVarExp)e;
+ VarDeclaration v = dve.var.isVarDeclaration();
+ if (!v)
+ return false;
+ if (!sc.func)
+ return false;
+ auto ad = v.isMember2();
+ if (!ad)
+ return false;
- import dmd.globals : global;
- if (v.isSystem())
- {
- if (sc.setUnsafePreview(global.params.systemVariables, !printmsg, e.loc,
- "cannot access `@system` field `%s.%s` in `@safe` code", ad, v))
- return true;
- }
+ if (v.isSystem())
+ {
+ if (sc.setUnsafePreview(sc.previews.systemVariables, !printmsg, e.loc,
+ "accessing `@system` field `%s.%s`", ad, v))
+ return true;
+ }
- // This branch shouldn't be here, but unfortunately calling `ad.determineSize`
- // breaks code with circular reference errors. Specifically, test23589.d fails
- if (ad.sizeok != Sizeok.done && !sc.func.isSafeBypassingInference())
- return false;
+ // This branch shouldn't be here, but unfortunately calling `ad.determineSize`
+ // breaks code with circular reference errors. Specifically, test23589.d fails
+ if (ad.sizeok != Sizeok.done && !sc.func.isSafeBypassingInference())
+ return false;
- // needed to set v.overlapped and v.overlapUnsafe
- if (ad.sizeok != Sizeok.done)
- ad.determineSize(ad.loc);
+ // needed to set v.overlapped and v.overlapUnsafe
+ if (ad.sizeok != Sizeok.done)
+ ad.determineSize(ad.loc);
- const hasPointers = v.type.hasPointers();
- if (hasPointers)
+ import dmd.globals : FeatureState;
+ const hasPointers = v.type.hasPointers();
+ if (hasPointers)
+ {
+ if (v.overlapped)
{
- if (v.overlapped)
+ if (sc.func.isSafeBypassingInference() && sc.setUnsafe(!printmsg, e.loc,
+ "accessing overlapped field `%s.%s` with pointers", ad, v))
{
- if (sc.func.isSafeBypassingInference() && sc.setUnsafe(!printmsg, e.loc,
- "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v))
- {
- return true;
- }
- else
- {
- import dmd.globals : FeatureState;
- // @@@DEPRECATED_2.116@@@
- // https://issues.dlang.org/show_bug.cgi?id=20655
- // Inferring `@system` because of union access breaks code,
- // so make it a deprecation safety violation as of 2.106
- // To turn into an error, remove `isSafeBypassingInference` check in the
- // above if statement and remove the else branch
- sc.setUnsafePreview(FeatureState.default_, !printmsg, e.loc,
- "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v);
- }
+ return true;
}
- }
-
- if (v.type.hasInvariant())
- {
- if (v.overlapped)
+ else
{
- if (sc.setUnsafe(!printmsg, e.loc,
- "field `%s.%s` cannot access structs with invariants in `@safe` code that overlap other fields",
- ad, v))
- return true;
+ // @@@DEPRECATED_2.116@@@
+ // https://issues.dlang.org/show_bug.cgi?id=20655
+ // Inferring `@system` because of union access breaks code,
+ // so make it a deprecation safety violation as of 2.106
+ // To turn into an error, remove `isSafeBypassingInference` check in the
+ // above if statement and remove the else branch
+ sc.setUnsafePreview(FeatureState.default_, !printmsg, e.loc,
+ "accessing overlapped field `%s.%s` with pointers", ad, v);
}
}
+ }
- if (readonly || !e.type.isMutable())
- return false;
-
- if (hasPointers && v.type.toBasetype().ty != Tstruct)
+ if (v.type.hasInvariant())
+ {
+ if (v.overlapped)
{
- if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize ||
- (v.offset & (target.ptrsize - 1))))
- {
- if (sc.setUnsafe(!printmsg, e.loc,
- "field `%s.%s` cannot modify misaligned pointers in `@safe` code", ad, v))
- return true;
- }
+ if (sc.setUnsafe(!printmsg, e.loc,
+ "accessing overlapped field `%s.%s` with a structs invariant",
+ ad, v))
+ return true;
}
+ }
+
+ // @@@DEPRECATED_2.119@@@
+ // https://issues.dlang.org/show_bug.cgi?id=24477
+ // Should probably be turned into an error in a new edition
+ if (v.type.hasUnsafeBitpatterns() && v.overlapped && sc.setUnsafePreview(
+ FeatureState.default_, !printmsg, e.loc,
+ "accessing overlapped field `%s.%s` with unsafe bit patterns", ad, v)
+ )
+ {
+ return true;
+ }
- if (v.overlapUnsafe)
+ if (readonly || !e.type.isMutable())
+ return false;
+
+ if (hasPointers && v.type.toBasetype().ty != Tstruct)
+ {
+ if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize) ||
+ (v.offset & (target.ptrsize - 1)))
{
if (sc.setUnsafe(!printmsg, e.loc,
- "field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes",
- ad, v))
- {
+ "modifying misaligned pointers through field `%s.%s`", ad, v))
return true;
- }
}
}
+
+ if (v.overlapUnsafe)
+ {
+ if (sc.setUnsafe(!printmsg, e.loc,
+ "modifying field `%s.%s` which overlaps with fields with other storage classes",
+ ad, v))
+ {
+ return true;
+ }
+ }
+
return false;
}
@@ -145,10 +166,11 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
* e = expression to be cast
* tfrom = type of e
* tto = type to cast e to
+ * msg = reason why cast is unsafe or deprecated
* Returns:
- * true if @safe
+ * true if @safe or deprecated
*/
-bool isSafeCast(Expression e, Type tfrom, Type tto)
+bool isSafeCast(Expression e, Type tfrom, Type tto, ref string msg)
{
// Implicit conversions are always safe
if (tfrom.implicitConvTo(tto))
@@ -160,22 +182,42 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
auto tfromb = tfrom.toBasetype();
auto ttob = tto.toBasetype();
+ // Casting to void* is always safe, https://github.com/dlang/dmd/issues/20514
+ if (ttob.isTypePointer() && ttob.nextOf().toBasetype().ty == Tvoid)
+ return true;
+
if (ttob.ty == Tclass && tfromb.ty == Tclass)
{
ClassDeclaration cdfrom = tfromb.isClassHandle();
ClassDeclaration cdto = ttob.isClassHandle();
-
int offset;
+
+ if (cdfrom == cdto)
+ goto Lsame;
+
if (!cdfrom.isBaseOf(cdto, &offset) &&
!((cdfrom.isInterfaceDeclaration() || cdto.isInterfaceDeclaration())
&& cdfrom.classKind == ClassKind.d && cdto.classKind == ClassKind.d))
+ {
+ msg = "Source object type is incompatible with target type";
return false;
+ }
+ // no RTTI
if (cdfrom.isCPPinterface() || cdto.isCPPinterface())
+ {
+ msg = "No dynamic type information for extern(C++) classes";
return false;
+ }
+ if (cdfrom.classKind == ClassKind.cpp || cdto.classKind == ClassKind.cpp)
+ msg = "No dynamic type information for extern(C++) classes";
+ Lsame:
if (!MODimplicitConv(tfromb.mod, ttob.mod))
+ {
+ msg = "Incompatible type qualifier";
return false;
+ }
return true;
}
@@ -199,22 +241,52 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
{
if (ttob.ty == Tarray && e.op == EXP.arrayLiteral)
return true;
+ msg = "`void` data may contain pointers and target element type is mutable";
return false;
}
// If the struct is opaque we don't know about the struct members then the cast becomes unsafe
- if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members ||
- tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members)
+ if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members)
+ {
+ msg = "Target element type is opaque";
+ return false;
+ }
+ if (tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members)
+ {
+ msg = "Source element type is opaque";
return false;
+ }
+
+ if (e.op != EXP.arrayLiteral)
+ {
+ // For bool, only 0 and 1 are safe values
+ // Runtime array cast reinterprets data
+ if (ttobn.ty == Tbool && tfromn.ty != Tbool)
+ msg = "Source element may have bytes which are not 0 or 1";
+ else if (ttobn.hasUnsafeBitpatterns())
+ msg = "Target element type has unsafe bit patterns";
+
+ // Can't alias a bool pointer with a non-bool pointer
+ if (ttobn.ty != Tbool && tfromn.ty == Tbool && ttobn.isMutable())
+ msg = "Target element could be assigned a byte which is not 0 or 1";
+ else if (tfromn.hasUnsafeBitpatterns() && ttobn.isMutable())
+ msg = "Source element type has unsafe bit patterns and target element type is mutable";
+ }
const frompointers = tfromn.hasPointers();
const topointers = ttobn.hasPointers();
if (frompointers && !topointers && ttobn.isMutable())
+ {
+ msg = "Target element type is mutable and source element type contains a pointer";
return false;
+ }
if (!frompointers && topointers)
+ {
+ msg = "Target element type contains a pointer";
return false;
+ }
if (!topointers &&
ttobn.ty != Tfunction && tfromn.ty != Tfunction &&
@@ -224,6 +296,7 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
return true;
}
}
+ msg = "Source type is incompatible with target type containing a pointer";
return false;
}
@@ -242,9 +315,245 @@ bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag)
if (!(flag & DotExpFlag.noDeref)) // this use is attempting a dereference
{
if (id == Id.ptr)
- return sc.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e);
- else
- return sc.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id);
+ return sc.setUnsafe(false, e.loc, "using `%s.ptr` (instead of `&%s[0])`", e, e);
+ return sc.setUnsafe(false, e.loc, "using `%s.%s`", e, id);
+ }
+ return false;
+}
+
+/**************************************
+ * Safer D adds safety checks to functions with the default
+ * trust setting.
+ */
+bool isSaferD(FuncDeclaration fd)
+{
+ return fd.type.toTypeFunction().trust == TRUST.default_ && fd.saferD;
+}
+
+bool isSafe(FuncDeclaration fd)
+{
+ if (fd.safetyInprocess)
+ setFunctionToUnsafe(fd);
+ return fd.type.toTypeFunction().trust == TRUST.safe;
+}
+
+extern (D) bool isSafeBypassingInference(FuncDeclaration fd)
+{
+ return !(fd.safetyInprocess) && fd.isSafe();
+}
+
+bool isTrusted(FuncDeclaration fd)
+{
+ if (fd.safetyInprocess)
+ setFunctionToUnsafe(fd);
+ return fd.type.toTypeFunction().trust == TRUST.trusted;
+}
+
+/*****************************************************
+ * Report safety violation for function `fd`, or squirrel away
+ * error message in fd.safetyViolation if needed later.
+ * Call when `fd` was just inferred to be @system OR
+ * `fd` was @safe and an tried something unsafe.
+ * Params:
+ * fd = function we're gonna rat on
+ * gag = suppress error message (used in escape.d)
+ * loc = location of error
+ * format = printf-style format string
+ * args = arguments for %s format specifier
+ */
+extern (D) void reportSafeError(FuncDeclaration fd, bool gag, Loc loc,
+ const(char)* format, RootObject[] args...)
+{
+ if (fd.type.toTypeFunction().trust == TRUST.system) // function was just inferred to be @system
+ {
+ if (format)
+ {
+ fd.safetyViolation = new AttributeViolation(loc, format, args);
+ }
+ else if (args.length > 0)
+ {
+ if (FuncDeclaration fd2 = (cast(Dsymbol) args[0]).isFuncDeclaration())
+ {
+ fd.safetyViolation = new AttributeViolation(loc, fd2); // call to non-@nogc function
+ }
+ }
+ }
+ else if (fd.isSafe() || fd.isSaferD())
+ {
+ if (!gag && format)
+ {
+ OutBuffer buf;
+ buf.writestring(AttributeViolation(loc, format, args).action);
+ if (fd.isSafe())
+ buf.writestring(" is not allowed in a `@safe` function");
+ else
+ {
+ version (IN_GCC)
+ buf.writestring(" is not allowed in a function with default safety with `-fpreview=safer`");
+ else
+ buf.writestring(" is not allowed in a function with default safety with `-preview=safer`");
+ }
+ .error(loc, "%s", buf.extractChars());
+ }
+ }
+}
+
+
+/**********************************************
+ * Function is doing something unsafe. If inference
+ * is in process, commit the function to be @system.
+ * Params:
+ * fd = the naughty function
+ * Returns:
+ * true if this is a safe function and so an error OR is inferred to be @system,
+ * false otherwise.
+ */
+extern (D) bool setFunctionToUnsafe(FuncDeclaration fd)
+{
+ if (fd.safetyInprocess)
+ {
+ fd.safetyInprocess = false;
+ fd.type.toTypeFunction().trust = TRUST.system;
+
+ if (fd.fes)
+ setFunctionToUnsafe(fd.fes.func);
+ return true;
+ }
+ else if (fd.isSafe() || fd.isSaferD())
+ return true;
+ return false;
+}
+
+
+/**************************************
+ * The function is calling `@system` function `f`, so mark it as unsafe.
+ *
+ * Params:
+ * fd = caller
+ * f = function being called (needed for diagnostic of inferred functions)
+ * Returns: whether there's a safe error
+ */
+extern (D) bool setUnsafeCall(FuncDeclaration fd, FuncDeclaration f)
+{
+ if (setFunctionToUnsafe(fd))
+ {
+ reportSafeError(fd, false, f.loc, null, f, null);
+ return fd.isSafe();
+ }
+ return false;
+}
+
+/**************************************
+ * A statement / expression in this scope is not `@safe`,
+ * so mark the enclosing function as `@system`
+ *
+ * Params:
+ * sc = scope that the unsafe statement / expression is in
+ * gag = surpress error message (used in escape.d)
+ * loc = location of error
+ * format = printf-style format string
+ * args = arguments for format string
+ * Returns: whether there is a safe error
+ */
+bool setUnsafe(Scope* sc, bool gag, Loc loc, const(char)* format, RootObject[] args...)
+{
+ if (sc.intypeof)
+ return false; // typeof(cast(int*)0) is safe
+
+ if (sc.debug_) // debug {} scopes are permissive
+ return false;
+
+ if (!sc.func)
+ {
+ if (sc.varDecl)
+ {
+ if (sc.varDecl.storage_class & STC.safe)
+ {
+ string action = AttributeViolation(loc, format, args).action;
+ .error(loc, "%.*s can't initialize `@safe` variable `%s`", action.fTuple.expand, sc.varDecl.toChars());
+ return true;
+ }
+ else if (!(sc.varDecl.storage_class & STC.trusted))
+ {
+ sc.varDecl.storage_class |= STC.system;
+ sc.varDecl.systemInferred = true;
+ }
+ }
+ return false;
+ }
+
+
+ if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
+ {
+ if (sc.func.isSafeBypassingInference())
+ {
+ // Message wil be gagged, but still call error() to update global.errors and for
+ // -verrors=spec
+ string action = AttributeViolation(loc, format, args).action;
+ .error(loc, "%.*s is not allowed in a `@safe` function", action.fTuple.expand);
+ return true;
+ }
+ return false;
+ }
+
+ if (setFunctionToUnsafe(sc.func))
+ {
+ if (format || args.length > 0)
+ {
+ reportSafeError(sc.func, gag, loc, format, args);
+ }
+ return sc.func.isSafe(); // it is only an error if in an @safe function
}
return false;
}
+
+/***************************************
+ * Like `setUnsafe`, but for safety errors still behind preview switches
+ *
+ * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
+ * the behavior changes based on the setting:
+ *
+ * - In case of `-revert=fs`, it does nothing.
+ * - In case of `-preview=fs`, it's the same as `setUnsafe`
+ * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
+ *
+ * Params:
+ * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
+ * fs = feature state from the preview flag
+ * gag = surpress error message
+ * loc = location of error
+ * format = printf-style format string
+ * args = arguments for format string
+ * Returns: whether an actual safe error (not deprecation) occured
+ */
+bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* format, RootObject[] args...)
+{
+ //printf("setUnsafePreview() fs:%d %s\n", fs, fmt);
+ assert(format);
+ with (FeatureState) final switch (fs)
+ {
+ case disabled:
+ return false;
+
+ case enabled:
+ return sc.setUnsafe(gag, loc, format, args);
+
+ case default_:
+ if (!sc.func)
+ return false;
+ if (sc.func.isSafeBypassingInference())
+ {
+ if (!gag && !sc.isDeprecated())
+ {
+ string action = AttributeViolation(loc, format, args).action;
+ deprecation(loc, "%.*s will become `@system` in a future release", action.fTuple.expand);
+ }
+ }
+ else if (!sc.func.safetyViolation)
+ {
+ import dmd.func : AttributeViolation;
+ sc.func.safetyViolation = new AttributeViolation(loc, format, args);
+ }
+ return false;
+ }
+}
diff --git a/gcc/d/dmd/sapply.d b/gcc/d/dmd/sapply.d
deleted file mode 100644
index 340fbad..0000000
--- a/gcc/d/dmd/sapply.d
+++ /dev/null
@@ -1,179 +0,0 @@
-/**
- * Provides a depth-first statement visitor.
- *
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
- * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
- * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sparse.d, _sparse.d)
- * Documentation: https://dlang.org/phobos/dmd_sapply.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/sapply.d
- */
-
-module dmd.sapply;
-
-import dmd.statement;
-import dmd.visitor;
-
-bool walkPostorder(Statement s, StoppableVisitor v)
-{
- scope PostorderStatementVisitor pv = new PostorderStatementVisitor(v);
- s.accept(pv);
- return v.stop;
-}
-
-/**************************************
- * A Statement tree walker that will visit each Statement s in the tree,
- * in depth-first evaluation order, and call fp(s,param) on it.
- * fp() signals whether the walking continues with its return value:
- * Returns:
- * 0 continue
- * 1 done
- * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
- * Creating an iterator for this would be much more complex.
- */
-private extern (C++) final class PostorderStatementVisitor : StoppableVisitor
-{
- alias visit = typeof(super).visit;
-public:
- StoppableVisitor v;
-
- extern (D) this(StoppableVisitor v) scope @safe
- {
- this.v = v;
- }
-
- bool doCond(Statement s)
- {
- if (!stop && s)
- s.accept(this);
- return stop;
- }
-
- bool applyTo(Statement s)
- {
- s.accept(v);
- stop = v.stop;
- return true;
- }
-
- override void visit(Statement s)
- {
- applyTo(s);
- }
-
- override void visit(PeelStatement s)
- {
- doCond(s.s) || applyTo(s);
- }
-
- override void visit(CompoundStatement s)
- {
- for (size_t i = 0; i < s.statements.length; i++)
- if (doCond((*s.statements)[i]))
- return;
- applyTo(s);
- }
-
- override void visit(UnrolledLoopStatement s)
- {
- for (size_t i = 0; i < s.statements.length; i++)
- if (doCond((*s.statements)[i]))
- return;
- applyTo(s);
- }
-
- override void visit(ScopeStatement s)
- {
- doCond(s.statement) || applyTo(s);
- }
-
- override void visit(WhileStatement s)
- {
- doCond(s._body) || applyTo(s);
- }
-
- override void visit(DoStatement s)
- {
- doCond(s._body) || applyTo(s);
- }
-
- override void visit(ForStatement s)
- {
- doCond(s._init) || doCond(s._body) || applyTo(s);
- }
-
- override void visit(ForeachStatement s)
- {
- doCond(s._body) || applyTo(s);
- }
-
- override void visit(ForeachRangeStatement s)
- {
- doCond(s._body) || applyTo(s);
- }
-
- override void visit(IfStatement s)
- {
- doCond(s.ifbody) || doCond(s.elsebody) || applyTo(s);
- }
-
- override void visit(PragmaStatement s)
- {
- doCond(s._body) || applyTo(s);
- }
-
- override void visit(SwitchStatement s)
- {
- doCond(s._body) || applyTo(s);
- }
-
- override void visit(CaseStatement s)
- {
- doCond(s.statement) || applyTo(s);
- }
-
- override void visit(DefaultStatement s)
- {
- doCond(s.statement) || applyTo(s);
- }
-
- override void visit(SynchronizedStatement s)
- {
- doCond(s._body) || applyTo(s);
- }
-
- override void visit(WithStatement s)
- {
- doCond(s._body) || applyTo(s);
- }
-
- override void visit(TryCatchStatement s)
- {
- if (doCond(s._body))
- return;
- for (size_t i = 0; i < s.catches.length; i++)
- if (doCond((*s.catches)[i].handler))
- return;
- applyTo(s);
- }
-
- override void visit(TryFinallyStatement s)
- {
- doCond(s._body) || doCond(s.finalbody) || applyTo(s);
- }
-
- override void visit(ScopeGuardStatement s)
- {
- doCond(s.statement) || applyTo(s);
- }
-
- override void visit(DebugStatement s)
- {
- doCond(s.statement) || applyTo(s);
- }
-
- override void visit(LabelStatement s)
- {
- doCond(s.statement) || applyTo(s);
- }
-}
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index f36a14b..b57d77d 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -40,33 +40,15 @@ enum class CSX : uint16_t
halt = 0x20, // assert(0)
};
-enum class SCOPE
+enum class Contract : uint8_t
{
- // Flags that would not be inherited beyond scope nesting
- ctor = 0x0001, // constructor type
- noaccesscheck = 0x0002, // don't do access checks
- condition = 0x0004, // inside static if/assert condition
- debug_ = 0x0008, // inside debug conditional
-
- // Flags that would be inherited beyond scope nesting
- constraint = 0x0010, // inside template constraint
- invariant_ = 0x0020, // inside invariant code
- require = 0x0040, // inside in contract code
- ensure = 0x0060, // inside out contract code
- contract = 0x0060, // [mask] we're inside contract code
- ctfe = 0x0080, // inside a ctfe-only expression
- compile = 0x0100, // inside __traits(compile)
- ignoresymbolvisibility = 0x0200, // ignore symbol visibility (Bugzilla 15907)
-
- Cfile = 0x0800, // C semantics apply
- free = 0x8000, // is on free list
- fullinst = 0x10000, // fully instantiate templates
- ctfeBlock = 0x20000, // inside a `if (__ctfe)` block
- dip1000 = 0x40000, // dip1000 errors enabled for this scope
- dip25 = 0x80000, // dip25 errors enabled for this scope
+ none = 0u,
+ invariant_ = 1u,
+ require = 2u,
+ ensure = 3u,
};
-struct Scope
+struct Scope final
{
Scope *enclosing; // enclosing Scope
@@ -76,10 +58,10 @@ struct Scope
VarDeclaration *varDecl; // variable we are in during semantic2
Dsymbol *parent; // parent to use
LabelStatement *slabel; // enclosing labelled statement
- SwitchStatement *sw; // enclosing switch statement
+ SwitchStatement *switchStatement; // enclosing switch statement
Statement *tryBody; // enclosing _body of TryCatchStatement or TryFinallyStatement
- TryFinallyStatement *tf; // enclosing try finally statement
- ScopeGuardStatement *os; // enclosing scope(xxx) statement
+ TryFinallyStatement *tryFinally; // enclosing try finally statement
+ ScopeGuardStatement *scopeGuard; // enclosing scope(xxx) statement
Statement *sbreak; // enclosing statement that supports "break"
Statement *scontinue; // enclosing statement that supports "continue"
ForeachStatement *fes; // if nested function for ForeachStatement, this is it
@@ -120,7 +102,35 @@ struct Scope
DeprecatedDeclaration *depdecl; // customized deprecation message
- unsigned flags;
+ uint16_t flags;
+ uint16_t previews; // state of preview switches
+
+ bool ctor() const;
+ bool ctor(bool v);
+ bool noAccessCheck() const;
+ bool noAccessCheck(bool v);
+ bool condition() const;
+ bool condition(bool v);
+ bool debug_() const;
+ bool debug_(bool v);
+ bool inTemplateConstraint() const;
+ bool inTemplateConstraint(bool v);
+ Contract contract() const;
+ Contract contract(Contract v);
+ bool ctfe() const;
+ bool ctfe(bool v);
+ bool traitsCompiles() const;
+ bool traitsCompiles(bool v);
+ bool ignoresymbolvisibility() const;
+ bool ignoresymbolvisibility(bool v);
+ bool inCfile() const;
+ bool inCfile(bool v);
+ bool canFree() const;
+ bool canFree(bool v);
+ bool fullinst() const;
+ bool fullinst(bool v);
+ bool ctfeBlock() const;
+ bool ctfeBlock(bool v);
UserAttributeDeclaration *userAttribDecl; // user defined attributes
@@ -130,6 +140,7 @@ struct Scope
AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value,
// do not set wasRead for it
+ StructDeclaration *argStruct; // elimiate recursion when looking for rvalue construction
- Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol *&pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
+ Dsymbol *search(Loc loc, Identifier *ident, Dsymbol *&pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
};
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index f5ce0c0..1c58e63 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -1,12 +1,12 @@
/**
* Performs the semantic2 stage, which deals with initializer expressions.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d, _semantic2.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic2.d, _semantic2.d)
* Documentation: https://dlang.org/phobos/dmd_semantic2.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic2.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/semantic2.d
*/
module dmd.semantic2;
@@ -21,6 +21,7 @@ import dmd.astcodegen;
import dmd.astenums;
import dmd.attrib;
import dmd.blockexit;
+import dmd.timetrace;
import dmd.clone;
import dmd.dcast;
import dmd.dclass;
@@ -40,6 +41,7 @@ import dmd.escape;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.id;
import dmd.identifier;
@@ -55,6 +57,7 @@ import dmd.parse;
import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.root.rmem;
+import dmd.root.string : toDString;
import dmd.rootobject;
import dmd.root.utf;
import dmd.sideeffect;
@@ -117,43 +120,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
else if (result)
return;
- if (sa.msgs)
- {
- OutBuffer msgbuf;
- for (size_t i = 0; i < sa.msgs.length; i++)
- {
- Expression e = (*sa.msgs)[i];
- sc = sc.startCTFE();
- e = e.expressionSemantic(sc);
- e = resolveProperties(sc, e);
- sc = sc.endCTFE();
- e = ctfeInterpretForPragmaMsg(e);
- if (e.op == EXP.error)
- {
- errorSupplemental(sa.loc, "while evaluating `static assert` argument `%s`", (*sa.msgs)[i].toChars());
- return;
- }
- StringExp se = e.toStringExp();
- if (se)
- {
- const slice = se.toUTF8(sc).peekString();
- // Hack to keep old formatting to avoid changing error messages everywhere
- if (sa.msgs.length == 1)
- msgbuf.printf("\"%.*s\"", cast(int)slice.length, slice.ptr);
- else
- msgbuf.printf("%.*s", cast(int)slice.length, slice.ptr);
- }
- else
- msgbuf.printf("%s", e.toChars());
- }
- error(sa.loc, "static assert: %s", msgbuf.extractChars());
- }
- else
- error(sa.loc, "static assert: `%s` is false", sa.exp.toChars());
- if (sc.tinst)
- sc.tinst.printInstantiationTrace();
- if (!global.gag)
- fatal();
+ staticAssertFail(sa, sc);
}
override void visit(TemplateInstance tempinst)
@@ -179,11 +146,9 @@ private extern(C++) final class Semantic2Visitor : Visitor
sc.tinst = tempinst;
sc.minst = tempinst.minst;
- int needGagging = (tempinst.gagged && !global.gag);
- uint olderrors = global.errors;
- int oldGaggedErrors = -1; // dead-store to prevent spurious warning
- if (needGagging)
- oldGaggedErrors = global.startGagging();
+ const needGagging = (tempinst.gagged && !global.gag);
+ const olderrors = global.errors;
+ const oldGaggedErrors = needGagging ? global.startGagging() : -1;
for (size_t i = 0; i < tempinst.members.length; i++)
{
@@ -263,7 +228,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
return;
}
- UserAttributeDeclaration.checkGNUABITag(vd, vd._linkage);
+ checkGNUABITag(vd, vd._linkage);
if (vd._init && !vd.toParent().isFuncDeclaration())
{
@@ -281,7 +246,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
// https://issues.dlang.org/show_bug.cgi?id=14166
// https://issues.dlang.org/show_bug.cgi?id=20417
// Don't run CTFE for the temporary variables inside typeof or __traits(compiles)
- vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret);
+ vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.traitsCompiles ? INITnointerpret : INITinterpret);
lowerStaticAAs(vd, sc);
vd.inuse--;
}
@@ -314,7 +279,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
if (e.op == EXP.assocArrayLiteral)
{
- AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
+ auto ae = cast(AssocArrayLiteralExp)e;
return arrayHasInvalidEnumInitializer(ae.values) ||
arrayHasInvalidEnumInitializer(ae.keys);
}
@@ -329,7 +294,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
{
// Cannot initialize a thread-local class or pointer to struct variable with a literal
// that itself is a thread-local reference and would need dynamic initialization also.
- if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared())
+ if (vd.type.ty == Tclass && vd.type.isMutable() && !vd.type.isShared())
{
ExpInitializer ei = vd._init.isExpInitializer();
if (ei && ei.exp.op == EXP.classReference)
@@ -392,6 +357,9 @@ private extern(C++) final class Semantic2Visitor : Visitor
assert(fd.semanticRun <= PASS.semantic2);
fd.semanticRun = PASS.semantic2;
+ timeTraceBeginEvent(TimeTraceEventType.sema2);
+ scope(exit) timeTraceEndEvent(TimeTraceEventType.sema2, fd);
+
//printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr);
// Only check valid functions which have a body to avoid errors
@@ -501,7 +469,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
return;
TypeFunction f = cast(TypeFunction) fd.type;
- UserAttributeDeclaration.checkGNUABITag(fd, fd._linkage);
+ checkGNUABITag(fd, fd._linkage);
//semantic for parameters' UDAs
foreach (i, param; f.parameterList)
{
@@ -535,7 +503,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
printf("+Nspace::semantic2('%s')\n", ns.toChars());
scope(exit) printf("-Nspace::semantic2('%s')\n", ns.toChars());
}
- UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
+ checkGNUABITag(ns, LINK.cpp);
if (!ns.members)
return;
@@ -593,7 +561,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
override void visit(CPPNamespaceDeclaration decl)
{
- UserAttributeDeclaration.checkGNUABITag(decl, LINK.cpp);
+ checkGNUABITag(decl, LINK.cpp);
visit(cast(AttribDeclaration)decl);
}
@@ -620,7 +588,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
}
// Handles compiler-recognized `core.attribute.gnuAbiTag`
- if (UserAttributeDeclaration.isGNUABITag(e))
+ if (isGNUABITag(e))
doGNUABITagSemantic(e, lastTag);
}
}
@@ -642,8 +610,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
return;
}
- UserAttributeDeclaration.checkGNUABITag(
- ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
+ checkGNUABITag(ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
auto sc2 = ad.newScope(sc);
@@ -750,8 +717,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
*/
private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag)
{
- import dmd.dmangle;
-
+ import dmd.mangle : isValidMangling;
// When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
if (e.op == EXP.type)
{
@@ -886,5 +852,62 @@ private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor
loweredExp = loweredExp.ctfeInterpret();
aaExp.lowering = loweredExp;
+
+ semanticTypeInfo(sc, loweredExp.type);
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=24602
+ // TODO: Is this intionally not visited by SemanticTimeTransitiveVisitor?
+ override void visit(ClassReferenceExp crExp)
+ {
+ this.visit(crExp.value);
+ }
+}
+
+/**
+ * Given a static assert with a failing condition, print an error
+ * Params:
+ * sa = Static assert with failing condition
+ * sc = scope for evaluating assert message and printing context
+ */
+void staticAssertFail(StaticAssert sa, Scope* sc)
+{
+ if (sa.msgs)
+ {
+ OutBuffer msgbuf;
+ for (size_t i = 0; i < sa.msgs.length; i++)
+ {
+ Expression e = (*sa.msgs)[i];
+ sc = sc.startCTFE();
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+ e = ctfeInterpretForPragmaMsg(e);
+ if (e.op == EXP.error)
+ {
+ errorSupplemental(sa.loc, "while evaluating `static assert` argument `%s`", (*sa.msgs)[i].toChars());
+ if (!global.gag)
+ fatal();
+ return;
+ }
+ if (StringExp se = e.toStringExp())
+ {
+ const slice = se.toUTF8(sc).peekString();
+ // Hack to keep old formatting to avoid changing error messages everywhere
+ if (sa.msgs.length == 1)
+ msgbuf.printf("\"%.*s\"", cast(int)slice.length, slice.ptr);
+ else
+ msgbuf.printf("%.*s", cast(int)slice.length, slice.ptr);
+ }
+ else
+ msgbuf.printf("%s", e.toChars());
+ }
+ error(sa.loc, "static assert: %s", msgbuf.extractChars());
}
+ else
+ error(sa.loc, "static assert: `%s` is false", sa.exp.toChars());
+ if (sc.tinst)
+ sc.tinst.printInstantiationTrace();
+ if (!global.gag)
+ fatal();
}
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 882d1a9..a24af7b 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -1,12 +1,12 @@
/**
* Performs the semantic3 stage, which deals with function bodies.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d, _semantic3.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic3.d, _semantic3.d)
* Documentation: https://dlang.org/phobos/dmd_semantic3.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic3.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/semantic3.d
*/
module dmd.semantic3;
@@ -119,16 +119,14 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc.tinst = tempinst;
sc.minst = tempinst.minst;
- int needGagging = (tempinst.gagged && !global.gag);
- uint olderrors = global.errors;
- int oldGaggedErrors = -1; // dead-store to prevent spurious warning
+ bool needGagging = tempinst.gagged && !global.gag;
+ const olderrors = global.errors;
+ const oldGaggedErrors = needGagging ? global.startGagging() : -1;
/* If this is a gagged instantiation, gag errors.
* Future optimisation: If the results are actually needed, errors
* would already be gagged, so we don't really need to run semantic
* on the members.
*/
- if (needGagging)
- oldGaggedErrors = global.startGagging();
for (size_t i = 0; i < tempinst.members.length; i++)
{
@@ -171,7 +169,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc = sc.push(tmix.argsym);
sc = sc.push(tmix);
- uint olderrors = global.errors;
+ const olderrors = global.errors;
for (size_t i = 0; i < tmix.members.length; i++)
{
@@ -221,6 +219,11 @@ private extern(C++) final class Semantic3Visitor : Visitor
override void visit(FuncDeclaration funcdecl)
{
//printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", funcdecl.kind(), funcdecl.toChars(), sc);
+ import dmd.timetrace;
+ import dmd.root.string : toDString;
+ timeTraceBeginEvent(TimeTraceEventType.sema3);
+ scope (exit) timeTraceEndEvent(TimeTraceEventType.sema3, funcdecl);
+
/* Determine if function should add `return 0;`
*/
bool addReturn0()
@@ -229,7 +232,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
auto f = funcdecl.type.isTypeFunction();
// C11 5.1.2.2.3
- if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32)
+ if (sc.inCfile && funcdecl.isCMain() && f.next.ty == Tint32)
return true;
return f.next.ty == Tvoid && (funcdecl.isMain() || funcdecl.isCMain());
@@ -267,7 +270,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
//{ static int x; if (++x == 2) *(char*)0=0; }
//printf("\tlinkage = %d\n", sc.linkage);
- if (funcdecl.ident == Id.assign && !funcdecl.inuse)
+ if (funcdecl.ident == Id.opAssign && !funcdecl.inuse)
{
if (funcdecl.storage_class & STC.inference)
{
@@ -275,7 +278,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
* For generated opAssign function, any errors
* from its body need to be gagged.
*/
- uint oldErrors = global.startGagging();
+ const oldErrors = global.startGagging();
++funcdecl.inuse;
funcdecl.semantic3(sc);
--funcdecl.inuse;
@@ -290,11 +293,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
}
- //printf(" sc.incontract = %d\n", (sc.flags & SCOPE.contract));
+ //printf(" sc.incontract = %d\n", sc.contract);
if (funcdecl.semanticRun >= PASS.semantic3)
return;
funcdecl.semanticRun = PASS.semantic3;
funcdecl.hasSemantic3Errors = false;
+ funcdecl.saferD = sc.previews.safer;
if (!funcdecl.type || funcdecl.type.ty != Tfunction)
return;
@@ -308,13 +312,13 @@ private extern(C++) final class Semantic3Visitor : Visitor
return;
}
- uint oldErrors = global.errors;
+ const oldErrors = global.errors;
auto fds = FuncDeclSem3(funcdecl,sc);
fds.checkInContractOverrides();
// Remember whether we need to generate an 'out' contract.
- immutable bool needEnsure = FuncDeclaration.needsFensure(funcdecl);
+ immutable bool needEnsure = funcdecl.needsFensure();
if (funcdecl.fbody || funcdecl.frequires || needEnsure)
{
@@ -334,7 +338,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc2.ctorflow.callSuper = CSX.none;
sc2.sbreak = null;
sc2.scontinue = null;
- sc2.sw = null;
+ sc2.switchStatement = null;
sc2.fes = funcdecl.fes;
sc2.linkage = funcdecl.isCsymbol() ? LINK.c : LINK.d;
sc2.stc &= STC.flowThruFunction;
@@ -342,9 +346,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc2.explicitVisibility = 0;
sc2.aligndecl = null;
if (funcdecl.ident != Id.require && funcdecl.ident != Id.ensure)
- sc2.flags = sc.flags & ~SCOPE.contract;
- sc2.tf = null;
- sc2.os = null;
+ {
+ sc2.copyFlagsFrom(sc);
+ sc2.contract = Contract.none;
+ }
+ sc2.tryFinally = null;
+ sc2.scopeGuard = null;
sc2.inLoop = false;
sc2.inDefaultArg = false;
sc2.userAttribDecl = null;
@@ -373,7 +380,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
if (!sc.intypeof)
{
if (fld.tok == TOK.delegate_)
- .error(funcdecl.loc, "%s `%s` cannot be %s members", funcdecl.kind, funcdecl.toPrettyChars, ad.kind());
+ .error(funcdecl.loc, "%s `%s` cannot be %s members", funcdecl.kind, funcdecl.toErrMsg, ad.kind());
else
fld.tok = TOK.function_;
}
@@ -424,9 +431,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
.error(funcdecl.loc, "%s `%s` `object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars);
else
.error(funcdecl.loc, "%s `%s` `object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars);
- fatal();
+ funcdecl.errors = true;
}
+ }
+ if (!funcdecl.errors && f.linkage == LINK.d)
+ {
// Declare _arguments[]
funcdecl.v_arguments = new VarDeclaration(funcdecl.loc, Type.typeinfotypelist.type, Id._arguments_typeinfo, null);
funcdecl.v_arguments.storage_class |= STC.temp | STC.parameter;
@@ -442,7 +452,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc2.insert(_arguments);
_arguments.parent = funcdecl;
}
- if (f.linkage == LINK.d || f.parameterList.length)
+ if (!funcdecl.errors && (f.linkage == LINK.d || f.parameterList.length))
{
// Declare _argptr
Type t = target.va_listType(funcdecl.loc, sc);
@@ -468,7 +478,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
foreach (i, fparam; f.parameterList)
{
Identifier id = fparam.ident;
- StorageClass stc = 0;
+ STC stc = STC.none;
if (!id)
{
/* Generate identifier for un-named parameter,
@@ -540,8 +550,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
Statement fpreinv = null;
if (funcdecl.addPreInvariant())
{
- Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
- if (e)
+ if (Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis))
fpreinv = new ExpStatement(Loc.initial, e);
}
@@ -549,8 +558,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
Statement fpostinv = null;
if (funcdecl.addPostInvariant())
{
- Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
- if (e)
+ if (Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis))
fpostinv = new ExpStatement(Loc.initial, e);
}
@@ -601,7 +609,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
}
- bool inferRef = (f.isref && (funcdecl.storage_class & STC.auto_));
+ bool inferRef = (f.isRef && (funcdecl.storage_class & STC.auto_));
funcdecl.fbody = funcdecl.fbody.statementSemantic(sc2);
if (!funcdecl.fbody)
@@ -645,12 +653,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
funcdecl.returns.remove(i);
continue;
}
- if (inferRef && f.isref && !exp.type.constConv(f.next)) // https://issues.dlang.org/show_bug.cgi?id=13336
- f.isref = false;
+ if (inferRef && f.isRef && !exp.type.constConv(f.next)) // https://issues.dlang.org/show_bug.cgi?id=13336
+ f.isRef = false;
i++;
}
}
- if (f.isref) // Function returns a reference
+ if (f.isRef) // Function returns a reference
{
if (funcdecl.storage_class & STC.auto_)
funcdecl.storage_class &= ~STC.auto_;
@@ -757,8 +765,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
funcdecl.buildEnsureRequire();
// Check for errors related to 'nothrow'.
- const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow ? global.errorSink : null);
- if (f.isnothrow && blockexit & BE.throw_)
+ const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isNothrow ? global.errorSink : null);
+ if (f.isNothrow && blockexit & BE.throw_)
error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.hasCatches))
@@ -773,7 +781,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
{
if (funcdecl.type == f)
f = cast(TypeFunction)f.copy();
- f.isnothrow = !(blockexit & BE.throw_);
+ f.isNothrow = !(blockexit & BE.throw_);
}
if (funcdecl.fbody.isErrorStatement())
@@ -790,7 +798,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
Statement s = new ReturnStatement(funcdecl.loc, null);
s = s.statementSemantic(sc2);
funcdecl.fbody = new CompoundStatement(funcdecl.loc, funcdecl.fbody, s);
- funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
+ funcdecl.hasMultipleReturnExp = funcdecl.hasReturnExp;
+ funcdecl.hasReturnExp = true;
}
}
else if (funcdecl.fes)
@@ -801,7 +810,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
Expression e = IntegerExp.literal!0;
Statement s = new ReturnStatement(Loc.initial, e);
funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s);
- funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
+ funcdecl.hasMultipleReturnExp = funcdecl.hasReturnExp;
+ funcdecl.hasReturnExp = true;
}
assert(!funcdecl.returnLabel);
}
@@ -816,8 +826,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
else
{
- const(bool) inlineAsm = (funcdecl.hasReturnExp & 8) != 0;
- if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !inlineAsm && !(sc.flags & SCOPE.Cfile))
+ if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !funcdecl.hasInlineAsm && !sc.inCfile)
{
if (!funcdecl.hasReturnExp)
.error(funcdecl.loc, "%s `%s` has no `return` statement, but is expected to return a value of type `%s`", funcdecl.kind, funcdecl.toPrettyChars, f.next.toChars());
@@ -906,36 +915,66 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
}
- const hasCopyCtor = exp.type.ty == Tstruct && (cast(TypeStruct)exp.type).sym.hasCopyCtor;
- // if a copy constructor is present, the return type conversion will be handled by it
- if (!(hasCopyCtor && exp.isLvalue()))
+ // Function returns a reference
+ if (f.isRef)
{
- if (f.isref && !MODimplicitConv(exp.type.mod, tret.mod) && !tret.isTypeSArray())
+ if (!MODimplicitConv(exp.type.mod, tret.mod) && !tret.isTypeSArray())
error(exp.loc, "expression `%s` of type `%s` is not implicitly convertible to return type `ref %s`",
exp.toChars(), exp.type.toChars(), tret.toChars());
else
exp = exp.implicitCastTo(sc2, tret);
- }
- if (f.isref)
- {
- // Function returns a reference
exp = exp.toLvalue(sc2, "`ref` return");
- checkReturnEscapeRef(sc2, exp, false);
+ checkReturnEscapeRef(*sc2, exp, false);
exp = exp.optimize(WANTvalue, /*keepLvalue*/ true);
}
else
{
+ // if a copy constructor is present, the return type conversion will be handled by it
+ const hasCopyCtor = exp.type.ty == Tstruct && (cast(TypeStruct)exp.type).sym.hasCopyCtor;
+ if (!hasCopyCtor || !exp.isLvalue())
+ {
+ const errors = global.startGagging();
+ auto implicitlyCastedExp = exp.implicitCastTo(sc2, tret);
+ global.endGagging(errors);
+
+ // <https://github.com/dlang/dmd/issues/20888>
+ if (implicitlyCastedExp.isErrorExp())
+ {
+ auto types = toAutoQualChars(exp.type, tret);
+ error(
+ exp.loc,
+ "return value `%s` of type `%s` does not match return type `%s`"
+ ~ ", and cannot be implicitly converted",
+ exp.toErrMsg(),
+ types[0],
+ types[1],
+ );
+
+ if (const func = exp.type.isFunction_Delegate_PtrToFunction())
+ if (func.next.equals(tret))
+ errorSupplemental(
+ exp.loc,
+ "Did you intend to call the %s?",
+ (exp.type.isPtrToFunction())
+ ? "function pointer"
+ : exp.type.kind
+ );
+ }
+
+ exp = implicitlyCastedExp;
+ }
+
exp = exp.optimize(WANTvalue);
/* https://issues.dlang.org/show_bug.cgi?id=10789
* If NRVO is not possible, all returned lvalues should call their postblits.
*/
if (!funcdecl.isNRVO())
- exp = doCopyOrMove(sc2, exp, f.next);
+ exp = doCopyOrMove(sc2, exp, f.next, true, true);
if (tret.hasPointers())
- checkReturnEscape(sc2, exp, false);
+ checkReturnEscape(*sc2, exp, false);
}
exp = checkGC(sc2, exp);
@@ -967,7 +1006,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc2 = sc2.pop();
}
- if (global.params.inclusiveInContracts)
+ if (sc.previews.inclusiveInContracts)
{
funcdecl.frequire = funcdecl.mergeFrequireInclusivePreview(
funcdecl.frequire, funcdecl.fdrequireParams);
@@ -984,7 +1023,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
/* Do the semantic analysis on the [in] preconditions and
* [out] postconditions.
*/
- immutable bool isnothrow = f.isnothrow && !funcdecl.nothrowInprocess;
+ immutable bool isNothrow = f.isNothrow && !funcdecl.nothrowInprocess;
if (freq)
{
/* frequire is composed of the [in] contracts
@@ -993,24 +1032,21 @@ private extern(C++) final class Semantic3Visitor : Visitor
sym.parent = sc2.scopesym;
sym.endlinnum = funcdecl.endloc.linnum;
sc2 = sc2.push(sym);
- sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.require;
+ sc2.contract = Contract.require;
// BUG: need to error if accessing out parameters
// BUG: need to disallow returns
// BUG: verify that all in and ref parameters are read
freq = freq.statementSemantic(sc2);
- // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
const blockExit = freq.blockExit(funcdecl, null);
if (blockExit & BE.throw_)
{
- if (isnothrow)
- // @@@DEPRECATED_2.111@@@
- // Deprecated in 2.101, can be made an error in 2.111
- deprecation(funcdecl.loc, "`%s`: `in` contract may throw but function is marked as `nothrow`",
+ if (isNothrow)
+ error(funcdecl.loc, "`%s`: `in` contract may throw but function is marked as `nothrow`",
funcdecl.toPrettyChars());
else if (funcdecl.nothrowInprocess)
- f.isnothrow = false;
+ f.isNothrow = false;
}
funcdecl.hasNoEH = false;
@@ -1038,7 +1074,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
sc2 = scout; //push
- sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.ensure;
+ sc2.contract = Contract.ensure;
// BUG: need to disallow returns and throws
@@ -1047,17 +1083,14 @@ private extern(C++) final class Semantic3Visitor : Visitor
fens = fens.statementSemantic(sc2);
- // @@@DEPRECATED_2.111@@@ - pass `isnothrow` instead of `false` to print a more detailed error msg`
const blockExit = fens.blockExit(funcdecl, null);
if (blockExit & BE.throw_)
{
- if (isnothrow)
- // @@@DEPRECATED_2.111@@@
- // Deprecated in 2.101, can be made an error in 2.111
- deprecation(funcdecl.loc, "`%s`: `out` contract may throw but function is marked as `nothrow`",
+ if (isNothrow)
+ error(funcdecl.loc, "`%s`: `out` contract may throw but function is marked as `nothrow`",
funcdecl.toPrettyChars());
else if (funcdecl.nothrowInprocess)
- f.isnothrow = false;
+ f.isNothrow = false;
}
funcdecl.hasNoEH = false;
@@ -1174,32 +1207,31 @@ private extern(C++) final class Semantic3Visitor : Visitor
{
if (v.isReference() || (v.storage_class & STC.lazy_))
continue;
- if (v.needsScopeDtor())
- {
- v.storage_class |= STC.nodtor;
- if (!paramsNeedDtor)
- continue;
-
- // same with ExpStatement.scopeCode()
- Statement s = new DtorExpStatement(Loc.initial, v.edtor, v);
+ if (!v.needsScopeDtor())
+ continue;
+ v.storage_class |= STC.nodtor;
+ if (!paramsNeedDtor)
+ continue;
- s = s.statementSemantic(sc2);
+ // same with ExpStatement.scopeCode()
+ Statement s = new DtorExpStatement(Loc.initial, v.edtor, v);
- const blockexit = s.blockExit(funcdecl, isnothrow ? global.errorSink : null);
- if (blockexit & BE.throw_)
- {
- funcdecl.hasNoEH = false;
- if (isnothrow)
- error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
- else if (funcdecl.nothrowInprocess)
- f.isnothrow = false;
- }
+ s = s.statementSemantic(sc2);
- if (sbody.blockExit(funcdecl, f.isnothrow ? global.errorSink : null) == BE.fallthru)
- sbody = new CompoundStatement(Loc.initial, sbody, s);
- else
- sbody = new TryFinallyStatement(Loc.initial, sbody, s);
+ const blockexit = s.blockExit(funcdecl, isNothrow ? global.errorSink : null);
+ if (blockexit & BE.throw_)
+ {
+ funcdecl.hasNoEH = false;
+ if (isNothrow)
+ error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
+ else if (funcdecl.nothrowInprocess)
+ f.isNothrow = false;
}
+
+ if (sbody.blockExit(funcdecl, f.isNothrow ? global.errorSink : null) == BE.fallthru)
+ sbody = new CompoundStatement(Loc.initial, sbody, s);
+ else
+ sbody = new TryFinallyStatement(Loc.initial, sbody, s);
}
}
// from this point on all possible 'throwers' are checked
@@ -1209,8 +1241,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
{
/* Wrap the entire function body in a synchronized statement
*/
- ClassDeclaration cd = funcdecl.toParentDecl().isClassDeclaration();
- if (cd)
+ if (ClassDeclaration cd = funcdecl.toParentDecl().isClassDeclaration())
{
if (target.libraryObjectMonitors(funcdecl, sbody))
{
@@ -1303,7 +1334,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
funcdecl.nogcInprocess = false;
if (funcdecl.type == f)
f = cast(TypeFunction)f.copy();
- f.isnogc = true;
+ f.isNogc = true;
}
finishScopeParamInference(funcdecl, f);
@@ -1317,8 +1348,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
{
sc = sc.push();
if (funcdecl.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665
- f.isctor = true;
- sc.stc = 0;
+ f.isCtor = true;
+ sc.stc = STC.none;
sc.linkage = funcdecl._linkage; // https://issues.dlang.org/show_bug.cgi?id=8496
funcdecl.type = f.typeSemantic(funcdecl.loc, sc);
sc = sc.pop();
@@ -1332,7 +1363,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
// Don't allow D `immutable` and `shared` types to be interfaced with C++
if (type.isImmutable() || type.isShared())
return true;
- else if (Type cpptype = target.cpp.parameterType(type))
+ if (Type cpptype = target.cpp.parameterType(type))
type = cpptype;
if (origType is null)
@@ -1374,7 +1405,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
if (isCppNonMappableType(f.next.toBasetype()))
{
- .error(funcdecl.loc, "%s `%s` cannot return type `%s` because its linkage is `extern(C++)`", funcdecl.kind, funcdecl.toPrettyChars, f.next.toChars());
+ .error(funcdecl.loc, "%s `%s` cannot return type `%s` because its linkage is `extern(C++)`", funcdecl.kind, funcdecl.toErrMsg(), f.next.toChars());
if (f.next.isTypeDArray())
errorSupplemental(funcdecl.loc, "slices are specific to D and do not have a counterpart representation in C++", f.next.toChars());
funcdecl.errors = true;
@@ -1383,7 +1414,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
{
if (isCppNonMappableType(param.type.toBasetype(), param))
{
- .error(funcdecl.loc, "%s `%s` cannot have parameter of type `%s` because its linkage is `extern(C++)`", funcdecl.kind, funcdecl.toPrettyChars, param.type.toChars());
+ .error(funcdecl.loc, "%s `%s` cannot have parameter of type `%s` because its linkage is `extern(C++)`", funcdecl.kind, funcdecl.toErrMsg(), param.type.toChars());
if (param.type.toBasetype().isTypeSArray())
errorSupplemental(funcdecl.loc, "perhaps use a `%s*` type instead",
param.type.nextOf().mutableOf().unSharedOf().toChars());
@@ -1393,8 +1424,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
// Do live analysis
- if (global.params.useDIP1021 && funcdecl.fbody && funcdecl.type.ty != Terror &&
- funcdecl.type.isTypeFunction().islive)
+ if (sc.previews.dip1021 && funcdecl.fbody && funcdecl.type.ty != Terror &&
+ funcdecl.type.isTypeFunction().isLive)
{
oblive(funcdecl);
}
@@ -1431,7 +1462,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
*/
AggregateDeclaration ad = ctor.isMemberDecl();
if (!ctor.fbody || !ad || !ad.fieldDtor ||
- global.params.dtorFields == FeatureState.disabled || !global.params.useExceptions || ctor.type.toTypeFunction.isnothrow)
+ global.params.dtorFields == FeatureState.disabled || !global.params.useExceptions || ctor.type.toTypeFunction.isNothrow)
return visit(cast(FuncDeclaration)ctor);
/* Generate:
@@ -1444,16 +1475,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
auto sexp = new ExpStatement(ctor.loc, ce);
auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc);
- // @@@DEPRECATED_2.106@@@
- // Allow negligible attribute violations to allow for a smooth
- // transition. Remove this after the usual deprecation period
- // after 2.106.
if (global.params.dtorFields == FeatureState.default_)
{
auto ctf = cast(TypeFunction) ctor.type;
auto dtf = cast(TypeFunction) ad.fieldDtor.type;
- const ngErr = ctf.isnogc && !dtf.isnogc;
+ const ngErr = ctf.isNogc && !dtf.isNogc;
const puErr = ctf.purity && !dtf.purity;
const saErr = ctf.trust == TRUST.safe && dtf.trust <= TRUST.system;
@@ -1462,13 +1489,13 @@ private extern(C++) final class Semantic3Visitor : Visitor
// storage_class is apparently not set for dtor & ctor
OutBuffer ob;
stcToBuffer(ob,
- (ngErr ? STC.nogc : 0) |
- (puErr ? STC.pure_ : 0) |
- (saErr ? STC.system : 0)
+ (ngErr ? STC.nogc : STC.none) |
+ (puErr ? STC.pure_ : STC.none) |
+ (saErr ? STC.system : STC.none)
);
- ctor.loc.deprecation("`%s` has stricter attributes than its destructor (`%s`)", ctor.toPrettyChars(), ob.peekChars());
- ctor.loc.deprecationSupplemental("The destructor will be called if an exception is thrown");
- ctor.loc.deprecationSupplemental("Either make the constructor `nothrow` or adjust the field destructors");
+ ctor.loc.error("`%s` has stricter attributes than its destructor (`%s`)", ctor.toPrettyChars(), ob.peekChars());
+ ctor.loc.errorSupplemental("The destructor will be called if an exception is thrown");
+ ctor.loc.errorSupplemental("Either make the constructor `nothrow` or adjust the field destructors");
ce.ignoreAttributes = true;
}
@@ -1642,7 +1669,7 @@ void semanticTypeInfoMembers(StructDeclaration sd)
sd.xeq._scope &&
sd.xeq.semanticRun < PASS.semantic3done)
{
- uint errors = global.startGagging();
+ const errors = global.startGagging();
sd.xeq.semantic3(sd.xeq._scope);
if (global.endGagging(errors))
sd.xeq = sd.xerreq;
@@ -1652,7 +1679,7 @@ void semanticTypeInfoMembers(StructDeclaration sd)
sd.xcmp._scope &&
sd.xcmp.semanticRun < PASS.semantic3done)
{
- uint errors = global.startGagging();
+ const errors = global.startGagging();
sd.xcmp.semantic3(sd.xcmp._scope);
if (global.endGagging(errors))
sd.xcmp = sd.xerrcmp;
@@ -1687,3 +1714,72 @@ void semanticTypeInfoMembers(StructDeclaration sd)
sd.dtor.semantic3(sd.dtor._scope);
}
}
+
+/***********************************************
+ * Check that the function contains any closure.
+ * If it's @nogc, report suitable errors.
+ * This is mostly consistent with FuncDeclaration::needsClosure().
+ *
+ * Returns:
+ * true if any errors occur.
+ */
+extern (D) bool checkClosure(FuncDeclaration fd)
+{
+ //printf("checkClosure() %s\n", toPrettyChars());
+ if (!fd.needsClosure())
+ return false;
+
+ if (fd.setGC(fd.loc, "allocating a closure for `%s()`", fd))
+ {
+ .error(fd.loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", fd.kind, fd.toPrettyChars(), fd.toChars());
+ if (global.gag) // need not report supplemental errors
+ return true;
+ }
+ else if (!global.params.useGC)
+ {
+ .error(fd.loc, "%s `%s` is `-betterC` yet allocates closure for `%s()` with the GC", fd.kind, fd.toPrettyChars(), fd.toChars());
+ if (global.gag) // need not report supplemental errors
+ return true;
+ }
+ else
+ {
+ fd.printGCUsage(fd.loc, "using closure causes GC allocation");
+ return false;
+ }
+
+ FuncDeclarations a;
+ foreach (v; fd.closureVars)
+ {
+ foreach (f; v.nestedrefs)
+ {
+ assert(f !is fd);
+
+ LcheckAncestorsOfANestedRef:
+ for (Dsymbol s = f; s && s !is fd; s = s.toParentP(fd))
+ {
+ auto fx = s.isFuncDeclaration();
+ if (!fx)
+ continue;
+ if (fx.isThis() ||
+ fx.tookAddressOf ||
+ checkEscapingSiblings(fx, fd))
+ {
+ foreach (f2; a)
+ {
+ if (f2 == f)
+ break LcheckAncestorsOfANestedRef;
+ }
+ a.push(f);
+ .errorSupplemental(f.loc, "%s `%s` closes over variable `%s`",
+ f.kind, f.toErrMsg(), v.toChars());
+ if (v.ident != Id.This)
+ .errorSupplemental(v.loc, "`%s` declared here", v.toChars());
+
+ break LcheckAncestorsOfANestedRef;
+ }
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d
index 1d4745a..5984466 100644
--- a/gcc/d/dmd/sideeffect.d
+++ b/gcc/d/dmd/sideeffect.d
@@ -1,12 +1,12 @@
/**
* Find side-effects of expressions.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d, _sideeffect.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/sideeffect.d, _sideeffect.d)
* Documentation: https://dlang.org/phobos/dmd_sideeffect.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/sideeffect.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/sideeffect.d
*/
module dmd.sideeffect;
@@ -18,15 +18,17 @@ import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
+import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.init;
import dmd.mtype;
-import dmd.postordervisitor;
import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
+import dmd.visitor.postorder;
/**************************************************
* Front-end expression rewriting should create temporary variables for
@@ -112,7 +114,7 @@ int callSideEffectLevel(FuncDeclaration f)
return 0;
assert(f.type.ty == Tfunction);
TypeFunction tf = cast(TypeFunction)f.type;
- if (!tf.isnothrow)
+ if (!tf.isNothrow)
return 0;
final switch (f.isPure())
{
@@ -122,7 +124,7 @@ int callSideEffectLevel(FuncDeclaration f)
return 0;
case PURE.const_:
- return mutabilityOfType(tf.isref, tf.next) == 2 ? 2 : 1;
+ return mutabilityOfType(tf.isRef, tf.next) == 2 ? 2 : 1;
}
}
@@ -137,7 +139,7 @@ int callSideEffectLevel(Type t)
assert(t.ty == Tfunction);
tf = cast(TypeFunction)t;
}
- if (!tf.isnothrow) // function can throw
+ if (!tf.isNothrow) // function can throw
return 0;
tf.purityLevel();
@@ -151,7 +153,7 @@ int callSideEffectLevel(Type t)
}
if (purity == PURE.const_)
- return mutabilityOfType(tf.isref, tf.next) == 2 ? 2 : 1;
+ return mutabilityOfType(tf.isRef, tf.next) == 2 ? 2 : 1;
return 0;
}
@@ -345,12 +347,13 @@ bool discardValue(Expression e)
BinExp tmp = e.isBinExp();
assert(tmp);
- error(e.loc, "the result of the equality expression `%s` is discarded", e.toChars());
+ error(e.loc, "the result of the equality expression `%s` is discarded", e.toErrMsg());
bool seenSideEffect = false;
foreach(expr; [tmp.e1, tmp.e2])
{
- if (hasSideEffect(expr)) {
- errorSupplemental(expr.loc, "note that `%s` may have a side effect", expr.toChars());
+ if (hasSideEffect(expr))
+ {
+ errorSupplemental(expr.loc, "note that `%s` may have a side effect", expr.toErrMsg());
seenSideEffect |= true;
}
}
@@ -358,7 +361,7 @@ bool discardValue(Expression e)
default:
break;
}
- error(e.loc, "`%s` has no effect", e.toChars());
+ error(e.loc, "`%s` has no effect", e.toErrMsg());
return true;
}
@@ -371,7 +374,7 @@ bool discardValue(Expression e)
* Returns:
* Newly created temporary variable.
*/
-VarDeclaration copyToTemp(StorageClass stc, const char[] name, Expression e)
+VarDeclaration copyToTemp(STC stc, const char[] name, Expression e)
{
assert(name[0] == '_' && name[1] == '_');
auto vd = new VarDeclaration(e.loc, e.type,
@@ -407,10 +410,10 @@ Expression extractSideEffect(Scope* sc, const char[] name,
* https://issues.dlang.org/show_bug.cgi?id=17145
*/
if (!alwaysCopy &&
- ((sc.flags & SCOPE.ctfe) ? !hasSideEffect(e) : isTrivialExp(e)))
+ (sc.ctfe ? !hasSideEffect(e) : isTrivialExp(e)))
return e;
- auto vd = copyToTemp(0, name, e);
+ auto vd = copyToTemp(STC.none, name, e);
vd.storage_class |= e.isLvalue() ? STC.ref_ : STC.rvalue;
e0 = Expression.combine(e0, new DeclarationExp(vd.loc, vd)
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index a79b78a..2ade0a9 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statement.d, _statement.d)
* Documentation: https://dlang.org/phobos/dmd_statement.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/statement.d
*/
module dmd.statement;
@@ -19,7 +19,6 @@ import core.stdc.stdio;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
-import dmd.errors;
import dmd.cond;
import dmd.declaration;
import dmd.dsymbol;
@@ -30,10 +29,10 @@ import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.rootobject;
-import dmd.sapply;
import dmd.staticassert;
import dmd.tokens;
import dmd.visitor;
+import dmd.visitor.postorder;
/***********************************************************
* Specification: https://dlang.org/spec/statement.html
@@ -48,7 +47,7 @@ extern (C++) abstract class Statement : ASTNode
return DYNCAST.statement;
}
- final extern (D) this(const ref Loc loc, STMT stmt) @safe
+ final extern (D) this(Loc loc, STMT stmt) @safe
{
this.loc = loc;
this.stmt = stmt;
@@ -267,57 +266,58 @@ extern (C++) abstract class Statement : ASTNode
pure nothrow @nogc
inout(ReturnStatement) endsWithReturnStatement() inout { return null; }
- final pure inout nothrow @nogc @safe:
-
- /********************
- * A cheaper method of doing downcasting of Statements.
- * Returns:
- * the downcast statement if it can be downcasted, otherwise `null`
- */
- inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; }
- inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; }
- inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; }
- inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; }
- inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; }
- inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; }
- inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; }
- inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; }
- inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; }
- inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; }
- inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; }
- inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; }
- inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; }
- inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
- inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; }
- inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; }
- inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; }
- inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; }
- inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; }
- inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; }
- inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; }
- inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; }
- inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; }
- inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; }
- inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; }
- inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; }
- inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; }
- inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; }
- inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; }
- inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; }
- inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; }
- inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; }
- inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
- inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
- inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
- inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; }
- inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; }
- inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; }
- inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; }
- inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; }
- inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; }
- inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; }
- inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; }
- inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; }
+ final pure inout nothrow @nogc @trusted
+ {
+ /********************
+ * A cheaper method of doing downcasting of Statements.
+ * Returns:
+ * the downcast statement if it can be downcasted, otherwise `null`
+ */
+ inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; }
+ inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; }
+ inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; }
+ inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; }
+ inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; }
+ inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; }
+ inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; }
+ inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; }
+ inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; }
+ inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; }
+ inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; }
+ inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; }
+ inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; }
+ inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
+ inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; }
+ inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; }
+ inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; }
+ inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; }
+ inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; }
+ inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; }
+ inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; }
+ inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; }
+ inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; }
+ inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; }
+ inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; }
+ inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; }
+ inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; }
+ inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; }
+ inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; }
+ inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; }
+ inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; }
+ inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; }
+ inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
+ inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
+ inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
+ inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; }
+ inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; }
+ inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; }
+ inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; }
+ inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; }
+ inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; }
+ inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; }
+ inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; }
+ inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; }
+ }
}
/***********************************************************
@@ -371,25 +371,25 @@ extern (C++) class ExpStatement : Statement
{
Expression exp;
- final extern (D) this(const ref Loc loc, Expression exp) @safe
+ final extern (D) this(Loc loc, Expression exp) @safe
{
super(loc, STMT.Exp);
this.exp = exp;
}
- final extern (D) this(const ref Loc loc, Expression exp, STMT stmt) @safe
+ final extern (D) this(Loc loc, Expression exp, STMT stmt) @safe
{
super(loc, stmt);
this.exp = exp;
}
- final extern (D) this(const ref Loc loc, Dsymbol declaration) @safe
+ final extern (D) this(Loc loc, Dsymbol declaration) @safe
{
super(loc, STMT.Exp);
this.exp = new DeclarationExp(loc, declaration);
}
- static ExpStatement create(const ref Loc loc, Expression exp) @safe
+ static ExpStatement create(Loc loc, Expression exp) @safe
{
return new ExpStatement(loc, exp);
}
@@ -412,7 +412,7 @@ extern (C++) final class DtorExpStatement : ExpStatement
// Wraps an expression that is the destruction of 'var'
VarDeclaration var;
- extern (D) this(const ref Loc loc, Expression exp, VarDeclaration var) @safe
+ extern (D) this(Loc loc, Expression exp, VarDeclaration var) @safe
{
super(loc, exp, STMT.DtorExp);
this.var = var;
@@ -437,14 +437,14 @@ extern (C++) final class MixinStatement : Statement
{
Expressions* exps;
- extern (D) this(const ref Loc loc, Expression exp)
+ extern (D) this(Loc loc, Expression exp)
{
Expressions* exps = new Expressions();
exps.push(exp);
this(loc, exps);
}
- extern (D) this(const ref Loc loc, Expressions* exps) @safe
+ extern (D) this(Loc loc, Expressions* exps) @safe
{
super(loc, STMT.Mixin);
this.exps = exps;
@@ -475,13 +475,13 @@ extern (C++) class CompoundStatement : Statement
* loc = Instantiation information
* statements = An array of `Statement`s, that will referenced by this class
*/
- final extern (D) this(const ref Loc loc, Statements* statements) @safe
+ final extern (D) this(Loc loc, Statements* statements) @safe
{
super(loc, STMT.Compound);
this.statements = statements;
}
- final extern (D) this(const ref Loc loc, Statements* statements, STMT stmt) @safe
+ final extern (D) this(Loc loc, Statements* statements, STMT stmt) @safe
{
super(loc, stmt);
this.statements = statements;
@@ -495,7 +495,7 @@ extern (C++) class CompoundStatement : Statement
* sts = A variadic array of `Statement`s, that will copied in this class
* The entries themselves will not be copied.
*/
- final extern (D) this(const ref Loc loc, Statement[] sts...)
+ final extern (D) this(Loc loc, Statement[] sts...)
{
super(loc, STMT.Compound);
statements = new Statements();
@@ -504,7 +504,7 @@ extern (C++) class CompoundStatement : Statement
statements.push(s);
}
- static CompoundStatement create(const ref Loc loc, Statement s1, Statement s2)
+ static CompoundStatement create(Loc loc, Statement s1, Statement s2)
{
return new CompoundStatement(loc, s1, s2);
}
@@ -553,7 +553,7 @@ extern (C++) class CompoundStatement : Statement
*/
extern (C++) final class CompoundDeclarationStatement : CompoundStatement
{
- extern (D) this(const ref Loc loc, Statements* statements) @safe
+ extern (D) this(Loc loc, Statements* statements) @safe
{
super(loc, statements, STMT.CompoundDeclaration);
}
@@ -577,7 +577,7 @@ extern (C++) final class UnrolledLoopStatement : Statement
{
Statements* statements;
- extern (D) this(const ref Loc loc, Statements* statements) @safe
+ extern (D) this(Loc loc, Statements* statements) @safe
{
super(loc, STMT.UnrolledLoop);
this.statements = statements;
@@ -611,7 +611,7 @@ extern (C++) final class ScopeStatement : Statement
Statement statement;
Loc endloc; // location of closing curly bracket
- extern (D) this(const ref Loc loc, Statement statement, Loc endloc) @safe
+ extern (D) this(Loc loc, Statement statement, Loc endloc) @safe
{
super(loc, STMT.Scope);
this.statement = statement;
@@ -661,7 +661,7 @@ extern (C++) final class ForwardingStatement : Statement
/// The wrapped statement.
Statement statement;
- extern (D) this(const ref Loc loc, ForwardingScopeDsymbol sym, Statement statement) @safe
+ extern (D) this(Loc loc, ForwardingScopeDsymbol sym, Statement statement) @safe
{
super(loc, STMT.Forwarding);
this.sym = sym;
@@ -669,7 +669,7 @@ extern (C++) final class ForwardingStatement : Statement
this.statement = statement;
}
- extern (D) this(const ref Loc loc, Statement statement) @safe
+ extern (D) this(Loc loc, Statement statement) @safe
{
auto sym = new ForwardingScopeDsymbol();
sym.symtab = new DsymbolTable();
@@ -698,7 +698,7 @@ extern (C++) final class WhileStatement : Statement
Statement _body;
Loc endloc; // location of closing curly bracket
- extern (D) this(const ref Loc loc, Expression condition, Statement _body, Loc endloc, Parameter param = null) @safe
+ extern (D) this(Loc loc, Expression condition, Statement _body, Loc endloc, Parameter param = null) @safe
{
super(loc, STMT.While);
this.condition = condition;
@@ -740,7 +740,7 @@ extern (C++) final class DoStatement : Statement
Expression condition;
Loc endloc; // location of ';' after while
- extern (D) this(const ref Loc loc, Statement _body, Expression condition, Loc endloc) @safe
+ extern (D) this(Loc loc, Statement _body, Expression condition, Loc endloc) @safe
{
super(loc, STMT.Do);
this._body = _body;
@@ -788,7 +788,7 @@ extern (C++) final class ForStatement : Statement
// treat that label as referring to this loop.
Statement relatedLabeled;
- extern (D) this(const ref Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) @safe
+ extern (D) this(Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) @safe
{
super(loc, STMT.For);
this._init = _init;
@@ -849,7 +849,7 @@ extern (C++) final class ForeachStatement : Statement
Statements* cases; // put breaks, continues, gotos and returns here
ScopeStatements* gotos; // forward referenced goto's go here
- extern (D) this(const ref Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) @safe
+ extern (D) this(Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) @safe
{
super(loc, STMT.Foreach);
this.op = op;
@@ -890,7 +890,7 @@ extern (C++) final class ForeachStatement : Statement
extern (C++) final class ForeachRangeStatement : Statement
{
TOK op; // TOK.foreach_ or TOK.foreach_reverse_
- Parameter prm; // loop index variable
+ Parameter param; // loop index variable
Expression lwr;
Expression upr;
Statement _body;
@@ -898,11 +898,11 @@ extern (C++) final class ForeachRangeStatement : Statement
VarDeclaration key;
- extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc) @safe
+ extern (D) this(Loc loc, TOK op, Parameter param, Expression lwr, Expression upr, Statement _body, Loc endloc) @safe
{
super(loc, STMT.ForeachRange);
this.op = op;
- this.prm = prm;
+ this.param = param;
this.lwr = lwr;
this.upr = upr;
this._body = _body;
@@ -911,7 +911,7 @@ extern (C++) final class ForeachRangeStatement : Statement
override ForeachRangeStatement syntaxCopy()
{
- return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc);
+ return new ForeachRangeStatement(loc, op, param.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc);
}
override bool hasBreak() const pure nothrow
@@ -935,17 +935,17 @@ extern (C++) final class ForeachRangeStatement : Statement
*/
extern (C++) final class IfStatement : Statement
{
- Parameter prm;
+ Parameter param;
Expression condition;
Statement ifbody;
Statement elsebody;
VarDeclaration match; // for MatchExpression results
Loc endloc; // location of closing curly bracket
- extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) @safe
+ extern (D) this(Loc loc, Parameter param, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) @safe
{
super(loc, STMT.If);
- this.prm = prm;
+ this.param = param;
this.condition = condition;
this.ifbody = ifbody;
this.elsebody = elsebody;
@@ -955,7 +955,7 @@ extern (C++) final class IfStatement : Statement
override IfStatement syntaxCopy()
{
return new IfStatement(loc,
- prm ? prm.syntaxCopy() : null,
+ param ? param.syntaxCopy() : null,
condition.syntaxCopy(),
ifbody ? ifbody.syntaxCopy() : null,
elsebody ? elsebody.syntaxCopy() : null,
@@ -987,7 +987,7 @@ extern (C++) final class ConditionalStatement : Statement
Statement ifbody;
Statement elsebody;
- extern (D) this(const ref Loc loc, Condition condition, Statement ifbody, Statement elsebody) @safe
+ extern (D) this(Loc loc, Condition condition, Statement ifbody, Statement elsebody) @safe
{
super(loc, STMT.Conditional);
this.condition = condition;
@@ -1022,7 +1022,7 @@ extern (C++) final class StaticForeachStatement : Statement
{
StaticForeach sfe;
- extern (D) this(const ref Loc loc, StaticForeach sfe) @safe
+ extern (D) this(Loc loc, StaticForeach sfe) @safe
{
super(loc, STMT.StaticForeach);
this.sfe = sfe;
@@ -1048,7 +1048,7 @@ extern (C++) final class PragmaStatement : Statement
Expressions* args; // array of Expression's
Statement _body;
- extern (D) this(const ref Loc loc, const Identifier ident, Expressions* args, Statement _body) @safe
+ extern (D) this(Loc loc, const Identifier ident, Expressions* args, Statement _body) @safe
{
super(loc, STMT.Pragma);
this.ident = ident;
@@ -1106,12 +1106,12 @@ extern (C++) final class SwitchStatement : Statement
bool hasVars; /// true if has variable case values
DefaultStatement sdefault; /// default:
Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion
- TryFinallyStatement tf; /// set if in the 'finally' block of a TryFinallyStatement
+ TryFinallyStatement tryFinally; /// set if in the 'finally' block of a TryFinallyStatement
GotoCaseStatements gotoCases; /// array of unresolved GotoCaseStatement's
CaseStatements* cases; /// array of CaseStatement's
VarDeclaration lastVar; /// last observed variable declaration in this statement
- extern (D) this(const ref Loc loc, Parameter param, Expression condition, Statement _body, bool isFinal, Loc endloc)
+ extern (D) this(Loc loc, Parameter param, Expression condition, Statement _body, bool isFinal, Loc endloc)
{
super(loc, STMT.Switch);
this.param = param;
@@ -1154,7 +1154,7 @@ extern (C++) final class CaseStatement : Statement
VarDeclaration lastVar;
void* extra; // for use by Statement_toIR()
- extern (D) this(const ref Loc loc, Expression exp, Statement statement) @safe
+ extern (D) this(Loc loc, Expression exp, Statement statement) @safe
{
super(loc, STMT.Case);
this.exp = exp;
@@ -1181,7 +1181,7 @@ extern (C++) final class CaseRangeStatement : Statement
Expression last;
Statement statement;
- extern (D) this(const ref Loc loc, Expression first, Expression last, Statement statement) @safe
+ extern (D) this(Loc loc, Expression first, Expression last, Statement statement) @safe
{
super(loc, STMT.CaseRange);
this.first = first;
@@ -1209,7 +1209,7 @@ extern (C++) final class DefaultStatement : Statement
VarDeclaration lastVar;
- extern (D) this(const ref Loc loc, Statement statement) @safe
+ extern (D) this(Loc loc, Statement statement) @safe
{
super(loc, STMT.Default);
this.statement = statement;
@@ -1233,7 +1233,7 @@ extern (C++) final class GotoDefaultStatement : Statement
{
SwitchStatement sw;
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, STMT.GotoDefault);
}
@@ -1258,7 +1258,7 @@ extern (C++) final class GotoCaseStatement : Statement
CaseStatement cs; // case statement it resolves to
- extern (D) this(const ref Loc loc, Expression exp) @safe
+ extern (D) this(Loc loc, Expression exp) @safe
{
super(loc, STMT.GotoCase);
this.exp = exp;
@@ -1281,12 +1281,12 @@ extern (C++) final class SwitchErrorStatement : Statement
{
Expression exp;
- extern (D) this(const ref Loc loc) @safe
+ extern (D) this(Loc loc) @safe
{
super(loc, STMT.SwitchError);
}
- final extern (D) this(const ref Loc loc, Expression exp) @safe
+ final extern (D) this(Loc loc, Expression exp) @safe
{
super(loc, STMT.SwitchError);
this.exp = exp;
@@ -1306,7 +1306,7 @@ extern (C++) final class ReturnStatement : Statement
Expression exp;
size_t caseDim;
- extern (D) this(const ref Loc loc, Expression exp) @safe
+ extern (D) this(Loc loc, Expression exp) @safe
{
super(loc, STMT.Return);
this.exp = exp;
@@ -1335,7 +1335,7 @@ extern (C++) final class BreakStatement : Statement
{
Identifier ident;
- extern (D) this(const ref Loc loc, Identifier ident) @safe
+ extern (D) this(Loc loc, Identifier ident) @safe
{
super(loc, STMT.Break);
this.ident = ident;
@@ -1359,7 +1359,7 @@ extern (C++) final class ContinueStatement : Statement
{
Identifier ident;
- extern (D) this(const ref Loc loc, Identifier ident) @safe
+ extern (D) this(Loc loc, Identifier ident) @safe
{
super(loc, STMT.Continue);
this.ident = ident;
@@ -1384,7 +1384,7 @@ extern (C++) final class SynchronizedStatement : Statement
Expression exp;
Statement _body;
- extern (D) this(const ref Loc loc, Expression exp, Statement _body) @safe
+ extern (D) this(Loc loc, Expression exp, Statement _body) @safe
{
super(loc, STMT.Synchronized);
this.exp = exp;
@@ -1422,7 +1422,7 @@ extern (C++) final class WithStatement : Statement
VarDeclaration wthis;
Loc endloc;
- extern (D) this(const ref Loc loc, Expression exp, Statement _body, Loc endloc) @safe
+ extern (D) this(Loc loc, Expression exp, Statement _body, Loc endloc) @safe
{
super(loc, STMT.With);
this.exp = exp;
@@ -1451,7 +1451,7 @@ extern (C++) final class TryCatchStatement : Statement
Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
- extern (D) this(const ref Loc loc, Statement _body, Catches* catches) @safe
+ extern (D) this(Loc loc, Statement _body, Catches* catches) @safe
{
super(loc, STMT.TryCatch);
this._body = _body;
@@ -1495,7 +1495,7 @@ extern (C++) final class Catch : RootObject
// was generated by the compiler, wasn't present in source code
bool internalCatch;
- extern (D) this(const ref Loc loc, Type type, Identifier ident, Statement handler) @safe
+ extern (D) this(Loc loc, Type type, Identifier ident, Statement handler) @safe
{
//printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars());
this.loc = loc;
@@ -1523,7 +1523,7 @@ extern (C++) final class TryFinallyStatement : Statement
Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
bool bodyFallsThru; /// true if _body falls through to finally
- extern (D) this(const ref Loc loc, Statement _body, Statement finalbody) @safe
+ extern (D) this(Loc loc, Statement _body, Statement finalbody) @safe
{
super(loc, STMT.TryFinally);
this._body = _body;
@@ -1531,7 +1531,7 @@ extern (C++) final class TryFinallyStatement : Statement
this.bodyFallsThru = true; // assume true until statementSemantic()
}
- static TryFinallyStatement create(const ref Loc loc, Statement _body, Statement finalbody) @safe
+ static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody) @safe
{
return new TryFinallyStatement(loc, _body, finalbody);
}
@@ -1565,7 +1565,7 @@ extern (C++) final class ScopeGuardStatement : Statement
TOK tok;
Statement statement;
- extern (D) this(const ref Loc loc, TOK tok, Statement statement) @safe
+ extern (D) this(Loc loc, TOK tok, Statement statement) @safe
{
super(loc, STMT.ScopeGuard);
this.tok = tok;
@@ -1593,7 +1593,7 @@ extern (C++) final class ThrowStatement : Statement
// was generated by the compiler, wasn't present in source code
bool internalThrow;
- extern (D) this(const ref Loc loc, Expression exp) @safe
+ extern (D) this(Loc loc, Expression exp) @safe
{
super(loc, STMT.Throw);
this.exp = exp;
@@ -1618,7 +1618,7 @@ extern (C++) final class DebugStatement : Statement
{
Statement statement;
- extern (D) this(const ref Loc loc, Statement statement) @safe
+ extern (D) this(Loc loc, Statement statement) @safe
{
super(loc, STMT.Debug);
this.statement = statement;
@@ -1648,7 +1648,7 @@ extern (C++) final class GotoStatement : Statement
VarDeclaration lastVar;
bool inCtfeBlock; /// set if goto is inside an `if (__ctfe)` block
- extern (D) this(const ref Loc loc, Identifier ident) @safe
+ extern (D) this(Loc loc, Identifier ident) @safe
{
super(loc, STMT.Goto);
this.ident = ident;
@@ -1682,7 +1682,7 @@ extern (C++) final class LabelStatement : Statement
bool breaks; // someone did a 'break ident'
bool inCtfeBlock; // inside a block dominated by `if (__ctfe)`
- extern (D) this(const ref Loc loc, Identifier ident, Statement statement) @safe
+ extern (D) this(Loc loc, Identifier ident, Statement statement) @safe
{
super(loc, STMT.Label);
this.ident = ident;
@@ -1713,9 +1713,9 @@ extern (C++) final class LabelDsymbol : Dsymbol
// can be removed if generic error message deduplication is implemented
bool duplicated;
- extern (D) this(Identifier ident, const ref Loc loc = Loc.initial) @safe
+ extern (D) this(Identifier ident, Loc loc = Loc.initial) @safe
{
- super(loc, ident);
+ super(DSYM.labelDsymbol, loc, ident);
}
static LabelDsymbol create(Identifier ident) @safe
@@ -1743,13 +1743,13 @@ extern (C++) class AsmStatement : Statement
Token* tokens;
bool caseSensitive; // for register names
- extern (D) this(const ref Loc loc, Token* tokens) @safe
+ extern (D) this(Loc loc, Token* tokens) @safe
{
super(loc, STMT.Asm);
this.tokens = tokens;
}
- extern (D) this(const ref Loc loc, Token* tokens, STMT stmt) @safe
+ extern (D) this(Loc loc, Token* tokens, STMT stmt) @safe
{
super(loc, stmt);
this.tokens = tokens;
@@ -1777,7 +1777,7 @@ extern (C++) final class InlineAsmStatement : AsmStatement
bool refparam; // true if function parameter is referenced
bool naked; // true if function is to be naked
- extern (D) this(const ref Loc loc, Token* tokens) @safe
+ extern (D) this(Loc loc, Token* tokens) @safe
{
super(loc, tokens, STMT.InlineAsm);
}
@@ -1799,7 +1799,7 @@ extern (C++) final class InlineAsmStatement : AsmStatement
*/
extern (C++) final class GccAsmStatement : AsmStatement
{
- StorageClass stc; // attributes of the asm {} block
+ STC stc; // attributes of the asm {} block
Expression insn; // string expression that is the template for assembler code
Expressions* args; // input and output operands of the statement
uint outputargs; // of the operands in 'args', the number of output operands
@@ -1809,7 +1809,7 @@ extern (C++) final class GccAsmStatement : AsmStatement
Identifiers* labels; // list of goto labels
GotoStatements* gotos; // of the goto labels, the equivalent statements they represent
- extern (D) this(const ref Loc loc, Token* tokens) @safe
+ extern (D) this(Loc loc, Token* tokens) @safe
{
super(loc, tokens, STMT.GccAsm);
}
@@ -1830,9 +1830,9 @@ extern (C++) final class GccAsmStatement : AsmStatement
*/
extern (C++) final class CompoundAsmStatement : CompoundStatement
{
- StorageClass stc; // postfix attributes like nothrow/pure/@trusted
+ STC stc; // postfix attributes like nothrow/pure/@trusted
- extern (D) this(const ref Loc loc, Statements* statements, StorageClass stc) @safe
+ extern (D) this(Loc loc, Statements* statements, STC stc) @safe
{
super(loc, statements, STMT.CompoundAsm);
this.stc = stc;
@@ -1856,7 +1856,7 @@ extern (C++) final class ImportStatement : Statement
{
Dsymbols* imports; // Array of Import's
- extern (D) this(const ref Loc loc, Dsymbols* imports) @safe
+ extern (D) this(Loc loc, Dsymbols* imports) @safe
{
super(loc, STMT.Import);
this.imports = imports;
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index ea80e51..5f962b2 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -119,40 +119,40 @@ public:
bool hasCode();
virtual Statement *last();
- virtual ReturnStatement *endsWithReturnStatement() { return NULL; }
-
- ErrorStatement *isErrorStatement() { return stmt == STMTerror ? (ErrorStatement*)this : NULL; }
- ScopeStatement *isScopeStatement() { return stmt == STMTscope ? (ScopeStatement*)this : NULL; }
- ExpStatement *isExpStatement() { return stmt == STMTexp ? (ExpStatement*)this : NULL; }
- CompoundStatement *isCompoundStatement() { return stmt == STMTcompound ? (CompoundStatement*)this : NULL; }
- ReturnStatement *isReturnStatement() { return stmt == STMTreturn ? (ReturnStatement*)this : NULL; }
- IfStatement *isIfStatement() { return stmt == STMTif ? (IfStatement*)this : NULL; }
- ConditionalStatement *isConditionalStatement() { return stmt == STMTconditional ? (ConditionalStatement*)this : NULL; }
- StaticForeachStatement *isStaticForeachStatement() { return stmt == STMTstaticForeach ? (StaticForeachStatement*)this : NULL; }
- CaseStatement *isCaseStatement() { return stmt == STMTcase ? (CaseStatement*)this : NULL; }
- DefaultStatement *isDefaultStatement() { return stmt == STMTdefault ? (DefaultStatement*)this : NULL; }
- LabelStatement *isLabelStatement() { return stmt == STMTlabel ? (LabelStatement*)this : NULL; }
- GotoDefaultStatement *isGotoDefaultStatement() { return stmt == STMTgotoDefault ? (GotoDefaultStatement*)this : NULL; }
- GotoCaseStatement *isGotoCaseStatement() { return stmt == STMTgotoCase ? (GotoCaseStatement*)this : NULL; }
- BreakStatement *isBreakStatement() { return stmt == STMTbreak ? (BreakStatement*)this : NULL; }
- DtorExpStatement *isDtorExpStatement() { return stmt == STMTdtorExp ? (DtorExpStatement*)this : NULL; }
- MixinStatement *isMixinStatement() { return stmt == STMTmixin ? (MixinStatement*)this : NULL; }
- ForwardingStatement *isForwardingStatement() { return stmt == STMTforwarding ? (ForwardingStatement*)this : NULL; }
- DoStatement *isDoStatement() { return stmt == STMTdo ? (DoStatement*)this : NULL; }
- ForStatement *isForStatement() { return stmt == STMTfor ? (ForStatement*)this : NULL; }
- ForeachStatement *isForeachStatement() { return stmt == STMTforeach ? (ForeachStatement*)this : NULL; }
- SwitchStatement *isSwitchStatement() { return stmt == STMTswitch ? (SwitchStatement*)this : NULL; }
- ContinueStatement *isContinueStatement() { return stmt == STMTcontinue ? (ContinueStatement*)this : NULL; }
- WithStatement *isWithStatement() { return stmt == STMTwith ? (WithStatement*)this : NULL; }
- TryCatchStatement *isTryCatchStatement() { return stmt == STMTtryCatch ? (TryCatchStatement*)this : NULL; }
- ThrowStatement *isThrowStatement() { return stmt == STMTthrow ? (ThrowStatement*)this : NULL; }
- DebugStatement *isDebugStatement() { return stmt == STMTdebug ? (DebugStatement*)this : NULL; }
- TryFinallyStatement *isTryFinallyStatement() { return stmt == STMTtryFinally ? (TryFinallyStatement*)this : NULL; }
- ScopeGuardStatement *isScopeGuardStatement() { return stmt == STMTscopeGuard ? (ScopeGuardStatement*)this : NULL; }
- SwitchErrorStatement *isSwitchErrorStatement() { return stmt == STMTswitchError ? (SwitchErrorStatement*)this : NULL; }
- UnrolledLoopStatement *isUnrolledLoopStatement() { return stmt == STMTunrolledLoop ? (UnrolledLoopStatement*)this : NULL; }
- ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : NULL; }
- CompoundDeclarationStatement *isCompoundDeclarationStatement() { return stmt == STMTcompoundDeclaration ? (CompoundDeclarationStatement*)this : NULL; }
+ virtual ReturnStatement *endsWithReturnStatement() { return nullptr; }
+
+ ErrorStatement *isErrorStatement() { return stmt == STMTerror ? (ErrorStatement*)this : nullptr; }
+ ScopeStatement *isScopeStatement() { return stmt == STMTscope ? (ScopeStatement*)this : nullptr; }
+ ExpStatement *isExpStatement() { return stmt == STMTexp ? (ExpStatement*)this : nullptr; }
+ CompoundStatement *isCompoundStatement() { return stmt == STMTcompound ? (CompoundStatement*)this : nullptr; }
+ ReturnStatement *isReturnStatement() { return stmt == STMTreturn ? (ReturnStatement*)this : nullptr; }
+ IfStatement *isIfStatement() { return stmt == STMTif ? (IfStatement*)this : nullptr; }
+ ConditionalStatement *isConditionalStatement() { return stmt == STMTconditional ? (ConditionalStatement*)this : nullptr; }
+ StaticForeachStatement *isStaticForeachStatement() { return stmt == STMTstaticForeach ? (StaticForeachStatement*)this : nullptr; }
+ CaseStatement *isCaseStatement() { return stmt == STMTcase ? (CaseStatement*)this : nullptr; }
+ DefaultStatement *isDefaultStatement() { return stmt == STMTdefault ? (DefaultStatement*)this : nullptr; }
+ LabelStatement *isLabelStatement() { return stmt == STMTlabel ? (LabelStatement*)this : nullptr; }
+ GotoDefaultStatement *isGotoDefaultStatement() { return stmt == STMTgotoDefault ? (GotoDefaultStatement*)this : nullptr; }
+ GotoCaseStatement *isGotoCaseStatement() { return stmt == STMTgotoCase ? (GotoCaseStatement*)this : nullptr; }
+ BreakStatement *isBreakStatement() { return stmt == STMTbreak ? (BreakStatement*)this : nullptr; }
+ DtorExpStatement *isDtorExpStatement() { return stmt == STMTdtorExp ? (DtorExpStatement*)this : nullptr; }
+ MixinStatement *isMixinStatement() { return stmt == STMTmixin ? (MixinStatement*)this : nullptr; }
+ ForwardingStatement *isForwardingStatement() { return stmt == STMTforwarding ? (ForwardingStatement*)this : nullptr; }
+ DoStatement *isDoStatement() { return stmt == STMTdo ? (DoStatement*)this : nullptr; }
+ ForStatement *isForStatement() { return stmt == STMTfor ? (ForStatement*)this : nullptr; }
+ ForeachStatement *isForeachStatement() { return stmt == STMTforeach ? (ForeachStatement*)this : nullptr; }
+ SwitchStatement *isSwitchStatement() { return stmt == STMTswitch ? (SwitchStatement*)this : nullptr; }
+ ContinueStatement *isContinueStatement() { return stmt == STMTcontinue ? (ContinueStatement*)this : nullptr; }
+ WithStatement *isWithStatement() { return stmt == STMTwith ? (WithStatement*)this : nullptr; }
+ TryCatchStatement *isTryCatchStatement() { return stmt == STMTtryCatch ? (TryCatchStatement*)this : nullptr; }
+ ThrowStatement *isThrowStatement() { return stmt == STMTthrow ? (ThrowStatement*)this : nullptr; }
+ DebugStatement *isDebugStatement() { return stmt == STMTdebug ? (DebugStatement*)this : nullptr; }
+ TryFinallyStatement *isTryFinallyStatement() { return stmt == STMTtryFinally ? (TryFinallyStatement*)this : nullptr; }
+ ScopeGuardStatement *isScopeGuardStatement() { return stmt == STMTscopeGuard ? (ScopeGuardStatement*)this : nullptr; }
+ SwitchErrorStatement *isSwitchErrorStatement() { return stmt == STMTswitchError ? (SwitchErrorStatement*)this : nullptr; }
+ UnrolledLoopStatement *isUnrolledLoopStatement() { return stmt == STMTunrolledLoop ? (UnrolledLoopStatement*)this : nullptr; }
+ ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : nullptr; }
+ CompoundDeclarationStatement *isCompoundDeclarationStatement() { return stmt == STMTcompoundDeclaration ? (CompoundDeclarationStatement*)this : nullptr; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -181,7 +181,7 @@ class ExpStatement : public Statement
public:
Expression *exp;
- static ExpStatement *create(const Loc &loc, Expression *exp);
+ static ExpStatement *create(Loc loc, Expression *exp);
ExpStatement *syntaxCopy() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -213,7 +213,7 @@ class CompoundStatement : public Statement
public:
Statements *statements;
- static CompoundStatement *create(const Loc &loc, Statement *s1, Statement *s2);
+ static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2);
CompoundStatement *syntaxCopy() override;
ReturnStatement *endsWithReturnStatement() override final;
Statement *last() override final;
@@ -346,7 +346,7 @@ class ForeachRangeStatement final : public Statement
{
public:
TOK op; // TOKforeach or TOKforeach_reverse
- Parameter *prm; // loop index variable
+ Parameter *param; // loop index variable
Expression *lwr;
Expression *upr;
Statement *_body;
@@ -364,7 +364,7 @@ public:
class IfStatement final : public Statement
{
public:
- Parameter *prm;
+ Parameter *param;
Expression *condition;
Statement *ifbody;
Statement *elsebody;
@@ -613,7 +613,7 @@ public:
Statement *tryBody; // set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
d_bool bodyFallsThru; // true if _body falls through to finally
- static TryFinallyStatement *create(const Loc &loc, Statement *body, Statement *finalbody);
+ static TryFinallyStatement *create(Loc loc, Statement *body, Statement *finalbody);
TryFinallyStatement *syntaxCopy() override;
bool hasBreak() const override;
bool hasContinue() const override;
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 1bf36e3..0c9b6be 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d, _statementsem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statementsem.d, _statementsem.d)
* Documentation: https://dlang.org/phobos/dmd_statementsem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statementsem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/statementsem.d
*/
module dmd.statementsem;
@@ -57,6 +57,7 @@ import dmd.opover;
import dmd.parse;
import dmd.common.outbuffer;
import dmd.root.string;
+import dmd.safe : isSafe, isSaferD, setUnsafe;
import dmd.semantic2;
import dmd.sideeffect;
import dmd.statement;
@@ -82,13 +83,13 @@ version (DMDLIB)
*/
private Identifier fixupLabelName(Scope* sc, Identifier ident)
{
- uint flags = (sc.flags & SCOPE.contract);
+ Contract c = sc.contract;
const id = ident.toString();
- if (flags && flags != SCOPE.invariant_ &&
+ if (c != Contract.none && c != Contract.invariant_ &&
!(id.length >= 2 && id[0] == '_' && id[1] == '_')) // does not start with "__"
{
OutBuffer buf;
- buf.writestring(flags == SCOPE.require ? "__in_" : "__out_");
+ buf.writestring(c == Contract.require ? "__in_" : "__out_");
buf.writestring(ident.toString());
ident = Identifier.idPool(buf[]);
@@ -123,7 +124,7 @@ private LabelStatement checkLabeledLoop(Scope* sc, Statement statement) @safe
*/
private Expression checkAssignmentAsCondition(Expression e, Scope* sc)
{
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
return e;
auto ec = lastComma(e);
if (ec.op == EXP.assign)
@@ -134,7 +135,16 @@ private Expression checkAssignmentAsCondition(Expression e, Scope* sc)
return e;
}
-// Performs semantic analysis in Statement AST nodes
+/**
+ * Performs semantic analysis in Statement AST nodes
+ *
+ * Params:
+ * s = statement to perform semantic analysis on
+ * sc = scope in which statement resides
+ *
+ * Returns: statement `s` after semantic analysis.
+ * Can be `null`, for example with `pragma(msg, "")`
+ */
Statement statementSemantic(Statement s, Scope* sc)
{
import dmd.compiler;
@@ -205,7 +215,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
if (checkMustUse(s.exp, sc))
s.exp = ErrorExp.get();
- if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp))
+ if (!sc.inCfile && discardValue(s.exp))
s.exp = ErrorExp.get();
s.exp = s.exp.optimize(WANTvalue);
@@ -663,7 +673,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
const olderrors = global.startGagging();
discardValue(fs.increment);
if (global.endGagging(olderrors))
- deprecation(fs.increment.loc, "`%s` has no effect", fs.increment.toChars());
+ deprecation(fs.increment.loc, "`%s` has no effect", fs.increment.toErrMsg());
if (checkNonAssignmentArrayOp(fs.increment))
fs.increment = ErrorExp.get();
fs.increment = fs.increment.optimize(WANTvalue);
@@ -778,14 +788,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
Dsymbol sapplyOld = sapply; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors
- /* Check for inference errors
- */
+ /* Check for inference errors and apply mutability checks inline */
if (!inferApplyArgTypes(fs, sc, sapply))
{
- /**
- Try and extract the parameter count of the opApply callback function, e.g.:
- int opApply(int delegate(int, float)) => 2 args
- */
bool foundMismatch = false;
size_t foreachParamCount = 0;
if (sapplyOld)
@@ -805,6 +810,19 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
auto tf = fparam.type.nextOf().isTypeFunction();
foreachParamCount = tf.parameterList.length;
foundMismatch = true;
+
+ // Mutability check
+ if (fs.aggr && fs.aggr.type && fd.type && fs.aggr.type.isConst() && !fd.type.isConst())
+ {
+ // First error: The call site
+ error(fs.loc, "mutable method `%s.%s` is not callable using a `const` object",
+ fd.parent ? fd.parent.toPrettyChars() : "unknown", fd.toChars());
+
+ // Second error: Suggest how to fix
+ errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
+
+ return setError();
+ }
}
}
}
@@ -823,6 +841,24 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
return setError();
}
+ // If inference succeeds, proceed with post-checks
+ if (sapply && sapply.isFuncDeclaration())
+ {
+ FuncDeclaration fd = sapply.isFuncDeclaration();
+
+ if (fs.aggr && fs.aggr.type && fd.type && fs.aggr.type.isConst() && !fd.type.isConst())
+ {
+ // First error: The call site
+ error(fs.loc, "mutable method `%s.%s` is not callable using a `const` object",
+ fd.parent ? fd.parent.toPrettyChars() : "unknown", fd.toChars());
+
+ // Second error: Suggest how to fix
+ errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
+
+ return setError();
+ }
+ }
+
Type tab = fs.aggr.type.toBasetype();
if (tab.ty == Ttuple) // don't generate new scope for tuple loops
@@ -975,7 +1011,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (dim == 2)
{
Type tindex = (*fs.parameters)[0].type;
- if (!tindex.isintegral())
+ if (!tindex.isIntegral())
{
error(fs.loc, "foreach: key cannot be of non-integral type `%s`", tindex.toChars());
return retError();
@@ -989,7 +1025,18 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
(tn.ty != tv.ty && tn.ty.isSomeChar && tv.ty.isSomeChar)) &&
!Type.tsize_t.implicitConvTo(tindex))
{
- deprecation(fs.loc, "foreach: loop index implicitly converted from `size_t` to `%s`",
+ bool err = true;
+ if (tab.isTypeDArray())
+ {
+ // check if overflow is possible
+ const maxLen = IntRange.fromType(tindex).imax.value + 1;
+ if (auto ale = fs.aggr.isArrayLiteralExp())
+ err = ale.elements.length > maxLen;
+ else if (auto se = fs.aggr.isSliceExp())
+ err = !(se.upr && se.upr.isConst() && se.upr.toInteger() <= maxLen);
+ }
+ if (err)
+ deprecation(fs.loc, "foreach: loop index implicitly converted from `size_t` to `%s`",
tindex.toChars());
}
}
@@ -1253,7 +1300,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
else
{
- r = copyToTemp(0, "__r", fs.aggr);
+ r = copyToTemp(STC.none, "__r", fs.aggr);
r.dsymbolSemantic(sc);
_init = new ExpStatement(loc, r);
if (vinit)
@@ -1298,7 +1345,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (auto ftt = tfront.toBasetype().isTypeFunction())
{
tfront = tfront.toBasetype().nextOf();
- if (!ftt.isref)
+ if (!ftt.isRef)
{
// .front() does not return a ref. We ignore ref on foreach arg.
// see https://issues.dlang.org/show_bug.cgi?id=11934
@@ -1370,7 +1417,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
p.type = p.type.addStorageClass(sc).typeSemantic(loc, sc2);
if (!exp.implicitConvTo(p.type))
{
- error(fs.loc, "cannot implicilty convert range element of type `%s` to variable `%s` of type `%s`",
+ error(fs.loc, "cannot implicitly convert tuple element of type `%s` to variable `%s` of type `%s`",
exp.type.toChars(), p.toChars(), p.type.toChars());
return retError();
}
@@ -1398,7 +1445,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
case Tdelegate:
if (fs.op == TOK.foreach_reverse_)
- deprecation(fs.loc, "cannot use `foreach_reverse` with a delegate");
+ error(fs.loc, "cannot use `foreach_reverse` with a delegate");
return retStmt(apply());
case Terror:
return retError();
@@ -1433,25 +1480,25 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
return setError();
}
- if (fs.prm.type)
+ if (fs.param.type)
{
- fs.prm.type = fs.prm.type.typeSemantic(loc, sc);
- fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass);
- fs.lwr = fs.lwr.implicitCastTo(sc, fs.prm.type);
+ fs.param.type = fs.param.type.typeSemantic(loc, sc);
+ fs.param.type = fs.param.type.addStorageClass(fs.param.storageClass);
+ fs.lwr = fs.lwr.implicitCastTo(sc, fs.param.type);
- if (fs.upr.implicitConvTo(fs.prm.type) || (fs.prm.storageClass & STC.ref_))
+ if (fs.upr.implicitConvTo(fs.param.type) || (fs.param.storageClass & STC.ref_))
{
- fs.upr = fs.upr.implicitCastTo(sc, fs.prm.type);
+ fs.upr = fs.upr.implicitCastTo(sc, fs.param.type);
}
else
{
- // See if upr-1 fits in prm.type
+ // See if upr-1 fits in param.type
Expression limit = new MinExp(loc, fs.upr, IntegerExp.literal!1);
limit = limit.expressionSemantic(sc);
limit = limit.optimize(WANTvalue);
- if (!limit.implicitConvTo(fs.prm.type))
+ if (!limit.implicitConvTo(fs.param.type))
{
- fs.upr = fs.upr.implicitCastTo(sc, fs.prm.type);
+ fs.upr = fs.upr.implicitCastTo(sc, fs.param.type);
}
}
}
@@ -1464,26 +1511,26 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
{
/* Just picking the first really isn't good enough.
*/
- fs.prm.type = fs.lwr.type;
+ fs.param.type = fs.lwr.type;
}
else if (fs.lwr.type == fs.upr.type)
{
/* Same logic as CondExp ?lwr:upr
*/
- fs.prm.type = fs.lwr.type;
+ fs.param.type = fs.lwr.type;
}
else
{
scope AddExp ea = new AddExp(loc, fs.lwr, fs.upr);
if (typeCombine(ea, sc))
return setError();
- fs.prm.type = ea.type;
+ fs.param.type = ea.type;
fs.lwr = ea.e1;
fs.upr = ea.e2;
}
- fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass);
+ fs.param.type = fs.param.type.addStorageClass(fs.param.storageClass);
}
- if (fs.prm.type.ty == Terror || fs.lwr.op == EXP.error || fs.upr.op == EXP.error)
+ if (fs.param.type.ty == Terror || fs.lwr.op == EXP.error || fs.upr.op == EXP.error)
{
return setError();
}
@@ -1528,7 +1575,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (fs.op == TOK.foreach_reverse_)
{
cond = new PostExp(EXP.minusMinus, loc, new VarExp(loc, fs.key));
- if (fs.prm.type.isscalar())
+ if (fs.param.type.isScalar())
{
// key-- > tmp
cond = new CmpExp(EXP.greaterThan, loc, cond, new VarExp(loc, tmp));
@@ -1541,7 +1588,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
else
{
- if (fs.prm.type.isscalar())
+ if (fs.param.type.isScalar())
{
// key < tmp
cond = new CmpExp(EXP.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
@@ -1560,30 +1607,30 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
//increment = new AddAssignExp(loc, new VarExp(loc, fs.key), IntegerExp.literal!1);
increment = new PreExp(EXP.prePlusPlus, loc, new VarExp(loc, fs.key));
}
- if ((fs.prm.storageClass & STC.ref_) && fs.prm.type.equals(fs.key.type))
+ if ((fs.param.storageClass & STC.ref_) && fs.param.type.equals(fs.key.type))
{
fs.key.range = null;
- auto v = new AliasDeclaration(loc, fs.prm.ident, fs.key);
+ auto v = new AliasDeclaration(loc, fs.param.ident, fs.key);
fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body);
}
else
{
- ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs.key), fs.prm.type));
- auto v = new VarDeclaration(loc, fs.prm.type, fs.prm.ident, ie);
- v.storage_class |= STC.temp | STC.foreach_ | (fs.prm.storageClass & STC.ref_);
+ ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs.key), fs.param.type));
+ auto v = new VarDeclaration(loc, fs.param.type, fs.param.ident, ie);
+ v.storage_class |= STC.temp | STC.foreach_ | (fs.param.storageClass & STC.ref_);
fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body);
- if (fs.key.range && !fs.prm.type.isMutable())
+ if (fs.key.range && !fs.param.type.isMutable())
{
/* Limit the range of the key to the specified range
*/
v.range = new IntRange(fs.key.range.imin, fs.key.range.imax - SignExtendedNumber(1));
}
}
- if (fs.prm.storageClass & STC.ref_)
+ if (fs.param.storageClass & STC.ref_)
{
- if (fs.key.type.constConv(fs.prm.type) == MATCH.nomatch)
+ if (fs.key.type.constConv(fs.param.type) == MATCH.nomatch)
{
- error(fs.loc, "argument type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), fs.prm.type.toChars());
+ error(fs.loc, "argument type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), fs.param.type.toChars());
return setError();
}
}
@@ -1606,15 +1653,15 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
sym.parent = sc.scopesym;
sym.endlinnum = ifs.endloc.linnum;
Scope* scd = sc.push(sym);
- if (ifs.prm)
+ if (ifs.param)
{
- /* Declare prm, which we will set to be the
+ /* Declare param, which we will set to be the
* result of condition.
*/
auto ei = new ExpInitializer(ifs.loc, ifs.condition);
- ifs.match = new VarDeclaration(ifs.loc, ifs.prm.type, ifs.prm.ident, ei);
+ ifs.match = new VarDeclaration(ifs.loc, ifs.param.type, ifs.param.ident, ei);
ifs.match.parent = scd.func;
- ifs.match.storage_class |= ifs.prm.storageClass;
+ ifs.match.storage_class |= ifs.param.storageClass;
ifs.match.dsymbolSemantic(scd);
auto de = new DeclarationExp(ifs.loc, ifs.match);
@@ -1650,8 +1697,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (checkNonAssignmentArrayOp(ifs.condition))
ifs.condition = ErrorExp.get();
- // Convert to boolean after declaring prm so this works:
- // if (S prm = S()) {}
+ // Convert to boolean after declaring param so this works:
+ // if (S param = S()) {}
// where S is a struct that defines opCast!bool.
ifs.condition = ifs.condition.toBoolean(scd);
@@ -1686,7 +1733,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (ifs.isIfCtfeBlock())
{
Scope* scd2 = scd.push();
- scd2.flags |= SCOPE.ctfeBlock;
+ scd2.ctfeBlock = true;
ifs.ifbody = ifs.ifbody.semanticNoScope(scd2);
scd2.pop();
}
@@ -1722,11 +1769,10 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// This feature allows a limited form of conditional compilation.
if (cs.condition.include(sc))
{
- DebugCondition dc = cs.condition.isDebugCondition();
- if (dc)
+ if (DebugCondition dc = cs.condition.isDebugCondition())
{
sc = sc.push();
- sc.flags |= SCOPE.debug_;
+ sc.debug_ = true;
cs.ifbody = cs.ifbody.statementSemantic(sc);
sc.pop();
}
@@ -1767,7 +1813,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
//printf("SwitchStatement::semantic(%p)\n", ss);
ss.tryBody = sc.tryBody;
- ss.tf = sc.tf;
+ ss.tryFinally = sc.tryFinally;
if (ss.cases)
{
result = ss; // already run
@@ -1827,7 +1873,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
break;
}
ss.condition = integralPromotions(ss.condition, sc);
- if (!ss.condition.isErrorExp() && ss.condition.type.isintegral())
+ if (!ss.condition.isErrorExp() && ss.condition.type.isIntegral())
break;
auto ad = isAggregate(ss.condition.type);
@@ -1861,7 +1907,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
sc = sc.push();
sc.sbreak = ss;
- sc.sw = ss;
+ sc.switchStatement = ss;
ss.cases = new CaseStatements();
const inLoopSave = sc.inLoop;
@@ -1888,9 +1934,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
for (Scope* scx = sc; scx; scx = scx.enclosing)
{
- if (!scx.sw)
+ if (!scx.switchStatement)
continue;
- foreach (cs; *scx.sw.cases)
+ foreach (cs; *scx.switchStatement.cases)
{
if (cs.exp.equals(gcs.exp))
{
@@ -1949,11 +1995,11 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
needswitcherror = true;
}
- ss.hasDefault = sc.sw.sdefault ||
- !(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe);
+ ss.hasDefault = sc.switchStatement.sdefault ||
+ !(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe || sc.func.isSaferD);
if (!ss.hasDefault)
{
- if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !(sc.flags & SCOPE.Cfile))
+ if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !sc.inCfile)
error(ss.loc, "`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`");
// Generate runtime error if the default is hit
@@ -1961,7 +2007,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
CompoundStatement cs;
Statement s;
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
{
s = new BreakStatement(ss.loc, null); // default for C is `default: break;`
}
@@ -2003,16 +2049,16 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
s = new ExpStatement(ss.loc, new HaltExp(ss.loc));
a.reserve(2);
- sc.sw.sdefault = new DefaultStatement(ss.loc, s);
+ sc.switchStatement.sdefault = new DefaultStatement(ss.loc, s);
a.push(ss._body);
if (ss._body.blockExit(sc.func, null) & BE.fallthru)
a.push(new BreakStatement(Loc.initial, null));
- a.push(sc.sw.sdefault);
+ a.push(sc.switchStatement.sdefault);
cs = new CompoundStatement(ss.loc, a);
ss._body = cs;
}
- if (!(sc.flags & SCOPE.Cfile) && ss.checkLabel())
+ if (!sc.inCfile && ss.checkLabel())
{
sc.pop();
return setError();
@@ -2052,7 +2098,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// Make a copy of all the cases so that qsort doesn't scramble the actual
// data we pass to codegen (the order of the cases in the switch).
- CaseStatements *csCopy = (*ss.cases).copy();
+ CaseStatements* csCopy = (*ss.cases).copy();
if (numcases)
{
@@ -2104,7 +2150,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
void visitCase(CaseStatement cs)
{
- SwitchStatement sw = sc.sw;
+ SwitchStatement sw = sc.switchStatement;
bool errors = false;
//printf("CaseStatement::semantic() %s\n", toChars());
@@ -2135,7 +2181,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
{
VarDeclaration v = ve.var.isVarDeclaration();
Type t = cs.exp.type.toBasetype();
- if (v && (t.isintegral() || t.ty == Tclass))
+ if (v && (t.isIntegral() || t.ty == Tclass))
{
/* Flag that we need to do special code generation
* for this, i.e. generate a sequence of if-then-else
@@ -2160,9 +2206,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
*/
for (Scope* scx = sc; scx; scx = scx.enclosing)
{
- if (scx.enclosing && scx.enclosing.sw == sw)
+ if (scx.enclosing && scx.enclosing.switchStatement == sw)
continue;
- assert(scx.sw == sw);
+ assert(scx.switchStatement == sw);
Dsymbol pscopesym;
if (!scx.search(cs.exp.loc, v.ident, pscopesym))
@@ -2217,12 +2263,12 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
i++;
}
- if (sc.sw.tf != sc.tf)
+ if (sc.switchStatement.tryFinally != sc.tryFinally)
{
error(cs.loc, "`switch` and `case` are in different `finally` blocks");
errors = true;
}
- if (sc.sw.tryBody != sc.tryBody)
+ if (sc.switchStatement.tryBody != sc.tryBody)
{
error(cs.loc, "case cannot be in different `try` block level from `switch`");
errors = true;
@@ -2250,7 +2296,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
void visitCaseRange(CaseRangeStatement crs)
{
- SwitchStatement sw = sc.sw;
+ SwitchStatement sw = sc.switchStatement;
if (sw is null)
{
error(crs.loc, "case range not in `switch` statement");
@@ -2288,7 +2334,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
uinteger_t fval = crs.first.toInteger();
uinteger_t lval = crs.last.toInteger();
- if ((crs.first.type.isunsigned() && fval > lval) || (!crs.first.type.isunsigned() && cast(sinteger_t)fval > cast(sinteger_t)lval))
+ if ((crs.first.type.isUnsigned() && fval > lval) || (!crs.first.type.isUnsigned() && cast(sinteger_t)fval > cast(sinteger_t)lval))
{
error(crs.loc, "first `case %s` is greater than last `case %s`", crs.first.toChars(), crs.last.toChars());
errors = true;
@@ -2335,26 +2381,26 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
{
//printf("DefaultStatement::semantic()\n");
bool errors = false;
- if (sc.sw)
+ if (sc.switchStatement)
{
- if (sc.sw.sdefault)
+ if (sc.switchStatement.sdefault)
{
error(ds.loc, "`switch` statement already has a default");
errors = true;
}
- sc.sw.sdefault = ds;
+ sc.switchStatement.sdefault = ds;
- if (sc.sw.tf != sc.tf)
+ if (sc.switchStatement.tryFinally != sc.tryFinally)
{
error(ds.loc, "`switch` and `default` are in different `finally` blocks");
errors = true;
}
- if (sc.sw.tryBody != sc.tryBody)
+ if (sc.switchStatement.tryBody != sc.tryBody)
{
error(ds.loc, "default cannot be in different `try` block level from `switch`");
errors = true;
}
- if (sc.sw.isFinal)
+ if (sc.switchStatement.isFinal)
{
error(ds.loc, "`default` statement not allowed in `final switch` statement");
errors = true;
@@ -2380,7 +2426,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
/* https://dlang.org/spec/statement.html#goto-statement
*/
- gds.sw = sc.sw;
+ gds.sw = sc.switchStatement;
if (!gds.sw)
{
error(gds.loc, "`goto default` not in `switch` statement");
@@ -2399,7 +2445,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
/* https://dlang.org/spec/statement.html#goto-statement
*/
- if (!sc.sw)
+ if (!sc.switchStatement)
{
error(gcs.loc, "`goto case` not in `switch` statement");
return setError();
@@ -2408,13 +2454,13 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (gcs.exp)
{
gcs.exp = gcs.exp.expressionSemantic(sc);
- gcs.exp = gcs.exp.implicitCastTo(sc, sc.sw.condition.type);
+ gcs.exp = gcs.exp.implicitCastTo(sc, sc.switchStatement.condition.type);
gcs.exp = gcs.exp.optimize(WANTvalue);
if (gcs.exp.op == EXP.error)
return setError();
}
- sc.sw.gotoCases.push(gcs);
+ sc.switchStatement.gotoCases.push(gcs);
result = gcs;
}
@@ -2423,7 +2469,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
/* https://dlang.org/spec/statement.html#return-statement
*/
- //printf("ReturnStatement.dsymbolSemantic() %p, %s\n", rs, rs.toChars());
+ //printf("ReturnStatement.dsymbolSemantic() %s\n", toChars(rs));
FuncDeclaration fd = sc.parent.isFuncDeclaration();
if (fd.fes)
@@ -2459,31 +2505,31 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
Type tret = tf.next;
Type tbret = tret ? tret.toBasetype() : null;
- bool inferRef = (tf.isref && (fd.storage_class & STC.auto_));
+ bool inferRef = (tf.isRef && (fd.storage_class & STC.auto_));
Expression e0 = null;
bool errors = false;
- if (sc.flags & SCOPE.contract)
+ if (sc.contract)
{
error(rs.loc, "`return` statements cannot be in contracts");
errors = true;
}
- if (sc.os)
+ if (sc.scopeGuard)
{
// @@@DEPRECATED_2.112@@@
// Deprecated in 2.100, transform into an error in 2.112
- if (sc.os.tok == TOK.onScopeFailure)
+ if (sc.scopeGuard.tok == TOK.onScopeFailure)
{
deprecation(rs.loc, "`return` statements cannot be in `scope(failure)` bodies.");
deprecationSupplemental(rs.loc, "Use try-catch blocks for this purpose");
}
else
{
- error(rs.loc, "`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok));
+ error(rs.loc, "`return` statements cannot be in `%s` bodies", Token.toChars(sc.scopeGuard.tok));
errors = true;
}
}
- if (sc.tf)
+ if (sc.tryFinally)
{
error(rs.loc, "`return` statements cannot be in `finally` bodies");
errors = true;
@@ -2504,7 +2550,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
else if (rs.exp)
{
- fd.hasReturnExp |= (fd.hasReturnExp & 1 ? 16 : 1);
+ fd.hasMultipleReturnExp = fd.hasReturnExp;
+ fd.hasReturnExp = true;
FuncLiteralDeclaration fld = fd.isFuncLiteralDeclaration();
if (tret)
@@ -2515,7 +2562,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
rs.exp = rs.exp.expressionSemantic(sc);
rs.exp = rs.exp.arrayFuncConv(sc);
// If we're returning by ref, allow the expression to be `shared`
- const returnSharedRef = (tf.isref && (fd.inferRetType || tret.isShared()));
+ const returnSharedRef = (tf.isRef && (fd.inferRetType || tret.isShared()));
rs.exp.checkSharedAccess(sc, returnSharedRef);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
@@ -2566,7 +2613,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
//errors = true;
}
if (global.endGagging(olderrors))
- deprecation(rs.exp.loc, "`%s` has no effect", rs.exp.toChars());
+ deprecation(rs.exp.loc, "`%s` has no effect", rs.exp.toErrMsg());
/* Replace:
* return exp;
@@ -2633,13 +2680,13 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
void turnOffRef(scope void delegate() supplemental)
{
- tf.isref = false; // return by value
- tf.isreturn = false; // ignore 'return' attribute, whether explicit or inferred
+ tf.isRef = false; // return by value
+ tf.isReturn = false; // ignore 'return' attribute, whether explicit or inferred
fd.storage_class &= ~STC.return_;
// If we previously assumed the function could be ref when
// checking for `shared`, make sure we were right
- if (global.params.noSharedAccess == FeatureState.enabled && rs.exp.type.isShared())
+ if (sc.previews.noSharedAccess && rs.exp.type.isShared())
{
.error(fd.loc, "%s `%s` function returns `shared` but cannot be inferred `ref`", fd.kind, fd.toPrettyChars);
supplemental();
@@ -2652,11 +2699,11 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
*/
Scope* sc2 = sc.push();
sc2.eSink = global.errorSinkNull;
- bool err = checkReturnEscapeRef(sc2, rs.exp, true);
+ bool err = checkReturnEscapeRef(*sc2, rs.exp, true);
sc2.pop();
if (err)
- turnOffRef(() { checkReturnEscapeRef(sc, rs.exp, false); });
+ turnOffRef(() { checkReturnEscapeRef(*sc, rs.exp, false); });
else if (!rs.exp.type.constConv(tf.next))
turnOffRef(
() => rs.loc.errorSupplemental("cannot implicitly convert `%s` of type `%s` to `%s`",
@@ -2706,7 +2753,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// https://issues.dlang.org/show_bug.cgi?id=23914
if (inferRef && !resType.isTypeNoreturn()) // deduce 'auto ref'
- tf.isref = false;
+ tf.isRef = false;
if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return
{
@@ -2863,7 +2910,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
Statement s = ls.statement;
if (!s || !s.hasBreak())
error(bs.loc, "label `%s` has no `break`", bs.ident.toChars());
- else if (ls.tf != sc.tf)
+ else if (ls.tf != sc.tryFinally)
error(bs.loc, "cannot break out of `finally` block");
else
{
@@ -2879,9 +2926,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
else if (!sc.sbreak)
{
- if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ if (sc.scopeGuard && sc.scopeGuard.tok != TOK.onScopeFailure)
{
- error(bs.loc, "`break` is not allowed inside `%s` bodies", Token.toChars(sc.os.tok));
+ error(bs.loc, "`break` is not allowed inside `%s` bodies", Token.toChars(sc.scopeGuard.tok));
}
else if (sc.fes)
{
@@ -2951,7 +2998,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
Statement s = ls.statement;
if (!s || !s.hasContinue())
error(cs.loc, "label `%s` has no `continue`", cs.ident.toChars());
- else if (ls.tf != sc.tf)
+ else if (ls.tf != sc.tryFinally)
error(cs.loc, "cannot continue out of `finally` block");
else
{
@@ -2966,9 +3013,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
else if (!sc.scontinue)
{
- if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ if (sc.scopeGuard && sc.scopeGuard.tok != TOK.onScopeFailure)
{
- error(cs.loc, "`continue` is not allowed inside `%s` bodies", Token.toChars(sc.os.tok));
+ error(cs.loc, "`continue` is not allowed inside `%s` bodies", Token.toChars(sc.scopeGuard.tok));
}
else if (sc.fes)
{
@@ -3018,8 +3065,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
*/
if (!ClassDeclaration.object)
{
- error(ss.loc, "missing or corrupt object.d");
- fatal();
+ ObjectNotFound(ss.loc, Id.Object);
+ return setError();
}
Type t = ClassDeclaration.object.type;
@@ -3036,14 +3083,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
* _d_monitorenter(tmp);
* try { body } finally { _d_monitorexit(tmp); }
*/
- auto tmp = copyToTemp(0, "__sync", ss.exp);
+ auto tmp = copyToTemp(STC.none, "__sync", ss.exp);
tmp.dsymbolSemantic(sc);
auto cs = new Statements();
cs.push(new ExpStatement(ss.loc, tmp));
auto args = new Parameters();
- args.push(new Parameter(Loc.initial, 0, ClassDeclaration.object.type, null, null, null));
+ args.push(new Parameter(Loc.initial, STC.none, ClassDeclaration.object.type, null, null, null));
FuncDeclaration fdenter = FuncDeclaration.genCfunc(args, Type.tvoid, Id.monitorenter);
Expression e = new CallExp(ss.loc, fdenter, new VarExp(ss.loc, tmp));
@@ -3085,7 +3132,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
cs.push(new ExpStatement(ss.loc, v));
auto enterArgs = new Parameters();
- enterArgs.push(new Parameter(Loc.initial, 0, t.pointerTo(), null, null, null));
+ enterArgs.push(new Parameter(Loc.initial, STC.none, t.pointerTo(), null, null, null));
FuncDeclaration fdenter = FuncDeclaration.genCfunc(enterArgs, Type.tvoid, Id.criticalenter, STC.nothrow_);
Expression e = new AddrExp(ss.loc, tmpExp);
@@ -3095,7 +3142,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
cs.push(new ExpStatement(ss.loc, e));
auto exitArgs = new Parameters();
- exitArgs.push(new Parameter(Loc.initial, 0, t, null, null, null));
+ exitArgs.push(new Parameter(Loc.initial, STC.none, t, null, null, null));
FuncDeclaration fdexit = FuncDeclaration.genCfunc(exitArgs, Type.tvoid, Id.criticalexit, STC.nothrow_);
e = new CallExp(ss.loc, fdexit, tmpExp);
@@ -3182,7 +3229,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
* }
* }
*/
- auto tmp = copyToTemp(0, "__withtmp", ws.exp);
+ auto tmp = copyToTemp(STC.none, "__withtmp", ws.exp);
tmp.dsymbolSemantic(sc);
auto es = new ExpStatement(ws.loc, tmp);
ws.exp = new VarExp(ws.loc, tmp);
@@ -3320,7 +3367,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
/* If catch exception type is derived from Exception
*/
if (c.type.toBasetype().implicitConvTo(ClassDeclaration.exception.type) &&
- (!c.handler || !c.handler.comeFrom()) && !(sc.flags & SCOPE.debug_))
+ (!c.handler || !c.handler.comeFrom()) && !sc.debug_)
{
// Remove c from the array of catches
tcs.catches.remove(i);
@@ -3344,7 +3391,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
tfs._body = tfs._body.semanticScope(sc, null, null, tfs);
sc = sc.push();
- sc.tf = tfs;
+ sc.tryFinally = tfs;
sc.sbreak = null;
sc.scontinue = null; // no break or continue out of finally block
tfs.finalbody = tfs.finalbody.semanticNoScope(sc);
@@ -3397,13 +3444,13 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
// so the generated catch block cannot be placed in finally block.
// See also Catch::semantic.
- if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ if (sc.scopeGuard && sc.scopeGuard.tok != TOK.onScopeFailure)
{
// If enclosing is scope(success) or scope(exit), this will be placed in finally block.
- error(oss.loc, "cannot put `%s` statement inside `%s`", Token.toChars(oss.tok), Token.toChars(sc.os.tok));
+ error(oss.loc, "cannot put `%s` statement inside `%s`", Token.toChars(oss.tok), Token.toChars(sc.scopeGuard.tok));
return setError();
}
- if (sc.tf)
+ if (sc.tryFinally)
{
error(oss.loc, "cannot put `%s` statement inside `finally` block", Token.toChars(oss.tok));
return setError();
@@ -3411,8 +3458,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
sc = sc.push();
- sc.tf = null;
- sc.os = oss;
+ sc.tryFinally = null;
+ sc.scopeGuard = oss;
if (oss.tok != TOK.onScopeFailure)
{
// Jump out from scope(failure) block is allowed.
@@ -3448,8 +3495,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (ds.statement)
{
sc = sc.push();
- sc.flags |= SCOPE.debug_;
+ sc.debug_ = true;
ds.statement = ds.statement.statementSemantic(sc);
+ debugThrowWalker(ds.statement);
sc.pop();
}
result = ds.statement;
@@ -3466,10 +3514,10 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
gs.ident = fixupLabelName(sc, gs.ident);
gs.label = fd.searchLabel(gs.ident, gs.loc);
gs.tryBody = sc.tryBody;
- gs.tf = sc.tf;
- gs.os = sc.os;
+ gs.tf = sc.tryFinally;
+ gs.os = sc.scopeGuard;
gs.lastVar = sc.lastVar;
- gs.inCtfeBlock = (sc.flags & SCOPE.ctfeBlock) != 0;
+ gs.inCtfeBlock = sc.ctfeBlock;
if (!gs.label.statement && sc.fes)
{
@@ -3493,7 +3541,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
fd.gotos = new GotoStatements();
fd.gotos.push(gs);
}
- else if (!(sc.flags & SCOPE.Cfile) && gs.checkLabel())
+ else if (!sc.inCfile && gs.checkLabel())
return setError();
result = gs;
@@ -3506,10 +3554,10 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
ls.ident = fixupLabelName(sc, ls.ident);
ls.tryBody = sc.tryBody;
- ls.tf = sc.tf;
- ls.os = sc.os;
+ ls.tf = sc.tryFinally;
+ ls.os = sc.scopeGuard;
ls.lastVar = sc.lastVar;
- ls.inCtfeBlock = (sc.flags & SCOPE.ctfeBlock) != 0;
+ ls.inCtfeBlock = sc.ctfeBlock;
LabelDsymbol ls2 = fd.searchLabel(ls.ident, ls.loc);
if (ls2.statement && !ls2.duplicated)
@@ -3531,6 +3579,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
ls2.statement = ls;
sc = sc.push();
+ sc.lastVar = sc.enclosing.lastVar;
sc.scopesym = sc.enclosing.scopesym;
sc.ctorflow.orCSX(CSX.label);
@@ -3538,6 +3587,10 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
sc.slabel = ls;
if (ls.statement)
ls.statement = ls.statement.statementSemantic(sc);
+
+ //issue 24534: lastVar may have been updated in the nested scope
+ sc.enclosing.lastVar = sc.lastVar;
+
sc.pop();
result = ls;
@@ -3580,9 +3633,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
assert(sc.func);
- if (!(cas.stc & STC.pure_) && sc.func.setImpure(cas.loc, "`asm` statement is assumed to be impure - mark it with `pure` if it is not"))
+ if (!(cas.stc & STC.pure_) && sc.func.setImpure(cas.loc, "executing an `asm` statement without `pure` annotation"))
error(cas.loc, "`asm` statement is assumed to be impure - mark it with `pure` if it is not");
- if (!(cas.stc & STC.nogc) && sc.func.setGC(cas.loc, "`asm` statement in %s `%s` is assumed to use the GC - mark it with `@nogc` if it does not"))
+ if (!(cas.stc & STC.nogc) && sc.func.setGC(cas.loc, "executing an `asm` statement without `@nogc` annotation"))
error(cas.loc, "`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
// @@@DEPRECATED_2.114@@@
// change deprecation() to error(), add `else` and remove `| STC.safe`
@@ -3591,7 +3644,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
deprecation(cas.loc, "`asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead");
if (!(cas.stc & (STC.trusted | STC.safe)))
{
- sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
+ sc.setUnsafe(false, cas.loc, "executing an `asm` statement without `@trusted` annotation");
}
sc.pop();
@@ -3653,7 +3706,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
*
* Returns: true if the `throw` is valid, or false if an error was found
*/
-public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
+public bool throwSemantic(Loc loc, ref Expression exp, Scope* sc)
{
if (!global.params.useExceptions)
{
@@ -3670,9 +3723,6 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
return false;
}
- if (FuncDeclaration fd = sc.parent.isFuncDeclaration())
- fd.hasReturnExp |= 2;
-
if (auto ne = exp.isNewExp())
{
ne.thrownew = true;
@@ -3690,7 +3740,7 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
exp.loc.deprecation("cannot throw object of qualified type `%s`", exp.type.toChars());
//return false;
}
- checkThrowEscape(sc, exp, false);
+ checkThrowEscape(*sc, exp, false);
ClassDeclaration cd = exp.type.toBasetype().isClassHandle();
if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null)))
@@ -3807,11 +3857,11 @@ private extern(D) Expression applyArray(ForeachStatement fs, Expression flde,
auto params = new Parameters();
params.push(new Parameter(Loc.initial, STC.in_, tn.arrayOf(), null, null, null));
auto dgparams = new Parameters();
- dgparams.push(new Parameter(Loc.initial, 0, Type.tvoidptr, null, null, null));
+ dgparams.push(new Parameter(Loc.initial, STC.none, Type.tvoidptr, null, null, null));
if (dim == 2)
- dgparams.push(new Parameter(Loc.initial, 0, Type.tvoidptr, null, null, null));
+ dgparams.push(new Parameter(Loc.initial, STC.none, Type.tvoidptr, null, null, null));
dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d));
- params.push(new Parameter(Loc.initial, 0, dgty, null, null, null));
+ params.push(new Parameter(Loc.initial, STC.none, dgty, null, null, null));
fdapply = FuncDeclaration.genCfunc(params, Type.tint32, fdname.ptr);
if (tab.isTypeSArray())
@@ -3872,14 +3922,14 @@ private extern(D) Expression applyAssocArray(ForeachStatement fs, Expression fld
if (!fdapply[i])
{
auto params = new Parameters();
- params.push(new Parameter(Loc.initial, 0, Type.tvoid.pointerTo(), null, null, null));
+ params.push(new Parameter(Loc.initial, STC.none, Type.tvoid.pointerTo(), null, null, null));
params.push(new Parameter(Loc.initial, STC.const_, Type.tsize_t, null, null, null));
auto dgparams = new Parameters();
- dgparams.push(new Parameter(Loc.initial, 0, Type.tvoidptr, null, null, null));
+ dgparams.push(new Parameter(Loc.initial, STC.none, Type.tvoidptr, null, null, null));
if (dim == 2)
- dgparams.push(new Parameter(Loc.initial, 0, Type.tvoidptr, null, null, null));
+ dgparams.push(new Parameter(Loc.initial, STC.none, Type.tvoidptr, null, null, null));
fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d));
- params.push(new Parameter(Loc.initial, 0, fldeTy[i], null, null, null));
+ params.push(new Parameter(Loc.initial, STC.none, fldeTy[i], null, null, null));
fdapply[i] = FuncDeclaration.genCfunc(params, Type.tint32, i ? Id._aaApply2 : Id._aaApply);
}
@@ -3905,7 +3955,7 @@ private extern(D) Expression applyAssocArray(ForeachStatement fs, Expression fld
return ec;
}
-private extern(D) Statement loopReturn(Expression e, Statements* cases, const ref Loc loc)
+private extern(D) Statement loopReturn(Expression e, Statements* cases, Loc loc)
{
if (!cases.length)
{
@@ -3950,19 +4000,19 @@ private FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFuncti
auto params = new Parameters();
foreach (i, p; *fs.parameters)
{
- StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_);
+ STC stc = STC.ref_ | (p.storageClass & STC.scope_);
Identifier id;
p.type = p.type.typeSemantic(fs.loc, sc);
p.type = p.type.addStorageClass(p.storageClass);
if (tfld)
{
- Parameter prm = tfld.parameterList[i];
- //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars());
- stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_);
- if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_))
+ Parameter param = tfld.parameterList[i];
+ //printf("\tparam = %s%s\n", (param.storageClass&STC.ref_?"ref ":"").ptr, param.ident.toChars());
+ stc = (param.storageClass & STC.ref_) | (p.storageClass & STC.scope_);
+ if ((p.storageClass & STC.ref_) != (param.storageClass & STC.ref_))
{
- if (!(prm.storageClass & STC.ref_))
+ if (!(param.storageClass & STC.ref_))
{
error(fs.loc, "`foreach`: cannot make `%s` `ref`", p.ident.toChars());
return null;
@@ -3994,7 +4044,7 @@ private FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFuncti
}
// https://issues.dlang.org/show_bug.cgi?id=13840
// Throwable nested function inside nothrow function is acceptable.
- StorageClass stc = mergeFuncAttrs(STC.safe | STC.pure_ | STC.nogc, fs.func);
+ STC stc = mergeFuncAttrs(STC.safe | STC.pure_ | STC.nogc, fs.func);
auto tf = new TypeFunction(ParameterList(params), Type.tint32, LINK.d, stc);
fs.cases = new Statements();
fs.gotos = new ScopeStatements();
@@ -4013,13 +4063,13 @@ void catchSemantic(Catch c, Scope* sc)
{
//printf("Catch::semantic(%s)\n", ident.toChars());
- if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ if (sc.scopeGuard && sc.scopeGuard.tok != TOK.onScopeFailure)
{
// If enclosing is scope(success) or scope(exit), this will be placed in finally block.
- error(c.loc, "cannot put `catch` statement inside `%s`", Token.toChars(sc.os.tok));
+ error(c.loc, "cannot put `catch` statement inside `%s`", Token.toChars(sc.scopeGuard.tok));
c.errors = true;
}
- if (sc.tf)
+ if (sc.tryFinally)
{
/* This is because the _d_local_unwind() gets the stack munged
* up on this. The workaround is to place any try-catches into
@@ -4059,7 +4109,7 @@ void catchSemantic(Catch c, Scope* sc)
return;
}
- StorageClass stc;
+ STC stc;
auto cd = c.type.toBasetype().isClassHandle();
if (!cd)
{
@@ -4075,7 +4125,7 @@ void catchSemantic(Catch c, Scope* sc)
}
if (!c.internalCatch)
{
- if (sc.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code"))
+ if (sc.setUnsafe(false, c.loc, "catching C++ class objects"))
c.errors = true;
}
}
@@ -4087,18 +4137,18 @@ void catchSemantic(Catch c, Scope* sc)
else if (!c.internalCatch && ClassDeclaration.exception &&
cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) &&
sc.setUnsafe(false, c.loc,
- "can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type))
+ "catching class objects derived from `%s` instead of `Exception`", c.type))
{
c.errors = true;
}
- else if (global.params.ehnogc)
+ else if (sc.previews.dip1008)
{
stc |= STC.scope_;
}
// DIP1008 requires destruction of the Throwable, even if the user didn't specify an identifier
auto ident = c.ident;
- if (!ident && global.params.ehnogc)
+ if (!ident && sc.previews.dip1008)
ident = Identifier.generateAnonymousId("var");
if (ident)
@@ -4108,7 +4158,7 @@ void catchSemantic(Catch c, Scope* sc)
c.var.dsymbolSemantic(sc);
sc.insert(c.var);
- if (global.params.ehnogc && stc & STC.scope_)
+ if (sc.previews.dip1008 && stc & STC.scope_)
{
/* Add a destructor for c.var
* try { handler } finally { if (!__ctfe) _d_delThrowable(var); }
@@ -4216,7 +4266,7 @@ Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St
* sexception: x = true;
* sfinally: if (!x) statement;
*/
- auto v = copyToTemp(0, "__os", IntegerExp.createBool(false));
+ auto v = copyToTemp(STC.none, "__os", IntegerExp.createBool(false));
v.dsymbolSemantic(sc);
sentry = new ExpStatement(statement.loc, v);
@@ -4367,7 +4417,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState
}
p.type = p.type.typeSemantic(loc, sc);
- if (!p.type.isintegral())
+ if (!p.type.isIntegral())
{
error(fs.loc, "foreach: key cannot be of non-integral type `%s`",
p.type.toChars());
@@ -4409,7 +4459,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState
* Returns:
* `true` iff the declaration was successful.
*/
- bool declareVariable(StorageClass storageClass, Type type, Identifier ident, Expression e, Type t)
+ bool declareVariable(STC storageClass, Type type, Identifier ident, Expression e, Type t)
{
if (storageClass & (STC.out_ | STC.lazy_) ||
storageClass & STC.ref_ && !te)
@@ -4550,7 +4600,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState
{ // expand tuples into multiple `static foreach` variables.
assert(e && !t);
auto ident = Identifier.generateId("__value");
- declareVariable(0, e.type, ident, e, null);
+ declareVariable(STC.none, e.type, ident, e, null);
import dmd.cond: StaticForeach;
auto field = Identifier.idPool(StaticForeach.tupleFieldName.ptr,StaticForeach.tupleFieldName.length);
Expression access = new DotIdExp(loc, e, field);
@@ -4720,7 +4770,6 @@ private Statements* flatten(Statement statement, Scope* sc)
if (dc)
{
s = new DebugStatement(cs.loc, cs.ifbody);
- debugThrowWalker(cs.ifbody);
}
else
s = cs.ifbody;
@@ -4787,7 +4836,7 @@ private Statements* flatten(Statement statement, Scope* sc)
OutBuffer buf;
- if (expressionsToString(buf, sc, cs.exps))
+ if (expressionsToString(buf, sc, cs.exps, cs.loc, null, true))
return errorStatements();
const errors = global.errors;
@@ -4795,9 +4844,9 @@ private Statements* flatten(Statement statement, Scope* sc)
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
const bool doUnittests = global.params.parsingUnittestsRequired();
- auto loc = adjustLocForMixin(str, cs.loc, global.params.mixinOut);
- scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
- p.transitionIn = global.params.v.vin;
+ scope p = new Parser!ASTCodegen(sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
+ adjustLocForMixin(str, cs.loc, *p.baseLoc, global.params.mixinOut);
+ p.linnum = p.baseLoc.startLine;
p.nextToken();
auto a = new Statements();
@@ -4892,7 +4941,8 @@ Params:
*/
private void debugThrowWalker(Statement s)
{
-
+ if (!s)
+ return;
extern(C++) final class DebugWalker : SemanticTimeTransitiveVisitor
{
alias visit = SemanticTimeTransitiveVisitor.visit;
diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d
index 08780ca..52ded55 100644
--- a/gcc/d/dmd/staticassert.d
+++ b/gcc/d/dmd/staticassert.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/version.html#static-assert, Static Assert)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d, _staticassert.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/staticassert.d, _staticassert.d)
* Documentation: https://dlang.org/phobos/dmd_staticassert.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/staticassert.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/staticassert.d
*/
module dmd.staticassert;
@@ -28,17 +28,17 @@ extern (C++) final class StaticAssert : Dsymbol
Expression exp;
Expressions* msgs;
- extern (D) this(const ref Loc loc, Expression exp, Expression msg)
+ extern (D) this(Loc loc, Expression exp, Expression msg)
{
- super(loc, Id.empty);
+ super(DSYM.staticAssert, loc, Id.empty);
this.exp = exp;
this.msgs = new Expressions(1);
(*this.msgs)[0] = msg;
}
- extern (D) this(const ref Loc loc, Expression exp, Expressions* msgs)
+ extern (D) this(Loc loc, Expression exp, Expressions* msgs)
{
- super(loc, Id.empty);
+ super(DSYM.staticAssert, loc, Id.empty);
this.exp = exp;
this.msgs = msgs;
}
@@ -49,23 +49,11 @@ extern (C++) final class StaticAssert : Dsymbol
return new StaticAssert(loc, exp.syntaxCopy(), msgs ? Expression.arraySyntaxCopy(msgs) : null);
}
- override bool oneMember(out Dsymbol ps, Identifier ident)
- {
- //printf("StaticAssert::oneMember())\n");
- ps = null;
- return true;
- }
-
override const(char)* kind() const
{
return "static assert";
}
- override inout(StaticAssert) isStaticAssert() inout
- {
- return this;
- }
-
override void accept(Visitor v)
{
v.visit(this);
diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h
index ed76de0..1ef7285 100644
--- a/gcc/d/dmd/staticassert.h
+++ b/gcc/d/dmd/staticassert.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -21,8 +21,6 @@ public:
Expressions *msg;
StaticAssert *syntaxCopy(Dsymbol *s) override;
- bool oneMember(Dsymbol *&ps, Identifier *ident) override;
const char *kind() const override;
- StaticAssert *isStaticAssert() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d
index 3ab6885..c2e87c7 100644
--- a/gcc/d/dmd/staticcond.d
+++ b/gcc/d/dmd/staticcond.d
@@ -1,12 +1,12 @@
/**
* Lazily evaluate static conditions for `static if`, `static assert` and template constraints.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d, _staticcond.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/staticcond.d, _staticcond.d)
* Documentation: https://dlang.org/phobos/dmd_staticcond.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/staticcond.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/staticcond.d
*/
module dmd.staticcond;
diff --git a/gcc/d/dmd/stmtstate.d b/gcc/d/dmd/stmtstate.d
index e1ed165..1c1fd08 100644
--- a/gcc/d/dmd/stmtstate.d
+++ b/gcc/d/dmd/stmtstate.d
@@ -1,12 +1,12 @@
/**
* Used to help transform statement AST into flow graph.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d, _stmtstate.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/stmtstate.d, _stmtstate.d)
* Documentation: https://dlang.org/phobos/dmd_stmtstate.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/stmtstate.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/stmtstate.d
*/
module dmd.stmtstate;
diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d
index cff1d2e..46926cd 100644
--- a/gcc/d/dmd/target.d
+++ b/gcc/d/dmd/target.d
@@ -15,17 +15,20 @@
* - $(LINK2 https://github.com/ldc-developers/ldc, LDC repository)
* - $(LINK2 https://github.com/D-Programming-GDC/gcc, GDC repository)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/target.d, _target.d)
* Documentation: https://dlang.org/phobos/dmd_target.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/target.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/target.d
*/
module dmd.target;
-import dmd.globals : Param, CHECKENABLE;
+import core.stdc.stdio;
+
+import dmd.astenums : CHECKENABLE;
+import dmd.globals : Param;
enum CPU : ubyte
{
@@ -111,7 +114,9 @@ extern (C++) struct Target
/// Architecture name
const(char)[] architectureName;
CPU cpu; // CPU instruction set to target
+ bool isAArch64; // generate 64 bit Arm code
bool isX86_64; // generate 64 bit code for x86_64; true by default for 64 bit dmd
+ bool isX86; // generate 32 bit Intel x86 code
bool isLP64; // pointers are 64 bits
// Environmental
@@ -119,7 +124,6 @@ extern (C++) struct Target
const(char)[] lib_ext; /// extension for static library files
const(char)[] dll_ext; /// extension for dynamic library files
bool run_noext; /// allow -run sources without extensions
- bool omfobj; // for Win32: write OMF object files instead of MsCoff
/**
* Values representing all properties for floating point types
*/
@@ -190,7 +194,7 @@ extern (C++) struct Target
* Returns:
* `Type` that represents `va_list`.
*/
- extern (C++) Type va_listType(const ref Loc loc, Scope* sc);
+ extern (C++) Type va_listType(Loc loc, Scope* sc);
/**
* Checks whether the target supports a vector type.
@@ -263,7 +267,7 @@ extern (C++) struct Target
* Returns:
* Expression for the requested targetInfo
*/
- extern (C++) Expression getTargetInfo(const(char)* name, const ref Loc loc);
+ extern (C++) Expression getTargetInfo(const(char)* name, Loc loc);
/**
* Params:
@@ -297,11 +301,12 @@ extern (C++) struct Target
*/
struct TargetC
{
+ import dmd.declaration : BitFieldDeclaration;
+
enum Runtime : ubyte
{
Unspecified,
Bionic,
- DigitalMars,
Glibc,
Microsoft,
Musl,
@@ -313,7 +318,6 @@ struct TargetC
enum BitFieldStyle : ubyte
{
Unspecified,
- DM, /// Digital Mars 32 bit C compiler
MS, /// Microsoft 32 and 64 bit C compilers
/// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
/// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
@@ -329,6 +333,14 @@ struct TargetC
ubyte wchar_tsize; /// size of a C `wchar_t` type
Runtime runtime; /// vendor of the C runtime to link against
BitFieldStyle bitFieldStyle; /// different C compilers do it differently
+
+ /**
+ * Indicates whether the specified bit-field contributes to the alignment
+ * of the containing aggregate.
+ * E.g., (not all) ARM ABIs do NOT ignore anonymous (incl. 0-length)
+ * bit-fields.
+ */
+ extern (C++) bool contributesToAggregateAlignment(BitFieldDeclaration bfd);
}
////////////////////////////////////////////////////////////////////////////////
@@ -345,9 +357,8 @@ struct TargetCPP
enum Runtime : ubyte
{
Unspecified,
- Clang,
- DigitalMars,
- Gcc,
+ LLVM,
+ GNU,
Microsoft,
Sun
}
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index 1209505..5965609 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 2013-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2013-2025 by The D Language Foundation, All Rights Reserved
* written by Iain Buclaw
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -16,6 +16,7 @@
#include "globals.h"
#include "tokens.h"
+class BitFieldDeclaration;
class ClassDeclaration;
class Dsymbol;
class Expression;
@@ -50,7 +51,6 @@ struct TargetC
{
Unspecified,
Bionic,
- DigitalMars,
Glibc,
Microsoft,
Musl,
@@ -62,7 +62,6 @@ struct TargetC
enum class BitFieldStyle : unsigned char
{
Unspecified,
- DM, // Digital Mars 32 bit C compiler
MS, // Microsoft 32 and 64 bit C compilers
// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
@@ -79,6 +78,8 @@ struct TargetC
uint8_t wchar_tsize; // size of a C 'wchar_t' type
Runtime runtime;
BitFieldStyle bitFieldStyle; // different C compilers do it differently
+
+ bool contributesToAggregateAlignment(BitFieldDeclaration *bfd);
};
struct TargetCPP
@@ -86,9 +87,8 @@ struct TargetCPP
enum class Runtime : unsigned char
{
Unspecified,
- Clang,
- DigitalMars,
- Gcc,
+ LLVM,
+ GNU,
Microsoft,
Sun
};
@@ -156,7 +156,9 @@ struct Target
DString architectureName; // name of the platform architecture (e.g. X86_64)
CPU cpu; // CPU instruction set to target
+ d_bool isAArch64; // generate 64 bit Arm code
d_bool isX86_64; // generate 64 bit code for x86_64; true by default for 64 bit dmd
+ d_bool isX86; // generate 32 bit Intel x86 code
d_bool isLP64; // pointers are 64 bits
// Environmental
@@ -164,7 +166,6 @@ struct Target
DString lib_ext; /// extension for static library files
DString dll_ext; /// extension for dynamic library files
d_bool run_noext; /// allow -run sources without extensions
- d_bool omfobj; /// for Win32: write OMF object files instead of COFF
template <typename T>
struct FPTypeProperties
@@ -196,15 +197,15 @@ public:
// Type sizes and support.
unsigned alignsize(Type *type);
unsigned fieldalign(Type *type);
- Type *va_listType(const Loc &loc, Scope *sc); // get type of va_list
+ Type *va_listType(Loc loc, Scope *sc); // get type of va_list
int isVectorTypeSupported(int sz, Type *type);
- bool isVectorOpSupported(Type *type, EXP op, Type *t2 = NULL);
+ bool isVectorOpSupported(Type *type, EXP op, Type *t2 = nullptr);
// ABI and backend.
LINK systemLinkage();
TypeTuple *toArgTypes(Type *t);
bool isReturnOnStack(TypeFunction *tf, bool needsThis);
bool preferPassByRef(Type *t);
- Expression *getTargetInfo(const char* name, const Loc& loc);
+ Expression *getTargetInfo(const char* name, Loc loc);
bool isCalleeDestroyingArgs(TypeFunction* tf);
bool libraryObjectMonitors(FuncDeclaration *fd, Statement *fbody);
bool supportsLinkerDirective() const;
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index bccec1a..5576965 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -77,13 +77,10 @@ public:
TemplateDeclaration *syntaxCopy(Dsymbol *) override;
bool overloadInsert(Dsymbol *s) override;
- bool hasStaticCtorOrDtor() override;
const char *kind() const override;
- const char *toChars() const override;
Visibility visible() override;
- TemplateDeclaration *isTemplateDeclaration() override { return this; }
bool isDeprecated() const override;
bool isOverloadable() const override;
@@ -128,14 +125,11 @@ public:
virtual bool declareParameter(Scope *sc) = 0;
virtual void print(RootObject *oarg, RootObject *oded) = 0;
virtual RootObject *specialization() = 0;
- virtual RootObject *defaultArg(const Loc &instLoc, Scope *sc) = 0;
+ virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0;
virtual bool hasDefaultArg() = 0;
DYNCAST dyncast() const override { return DYNCAST_TEMPLATEPARAMETER; }
- /* Create dummy argument based on parameter.
- */
- virtual RootObject *dummyArg() = 0;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -153,9 +147,8 @@ public:
bool declareParameter(Scope *sc) override final;
void print(RootObject *oarg, RootObject *oded) override final;
RootObject *specialization() override final;
- RootObject *defaultArg(const Loc &instLoc, Scope *sc) override final;
+ RootObject *defaultArg(Loc instLoc, Scope *sc) override final;
bool hasDefaultArg() override final;
- RootObject *dummyArg() override final;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -185,9 +178,8 @@ public:
bool declareParameter(Scope *sc) override;
void print(RootObject *oarg, RootObject *oded) override;
RootObject *specialization() override;
- RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
+ RootObject *defaultArg(Loc instLoc, Scope *sc) override;
bool hasDefaultArg() override;
- RootObject *dummyArg() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -206,9 +198,8 @@ public:
bool declareParameter(Scope *sc) override;
void print(RootObject *oarg, RootObject *oded) override;
RootObject *specialization() override;
- RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
+ RootObject *defaultArg(Loc instLoc, Scope *sc) override;
bool hasDefaultArg() override;
- RootObject *dummyArg() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -223,9 +214,8 @@ public:
bool declareParameter(Scope *sc) override;
void print(RootObject *oarg, RootObject *oded) override;
RootObject *specialization() override;
- RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
+ RootObject *defaultArg(Loc instLoc, Scope *sc) override;
bool hasDefaultArg() override;
- RootObject *dummyArg() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -278,15 +268,12 @@ public:
TemplateInstance *syntaxCopy(Dsymbol *) override;
Dsymbol *toAlias() override final; // resolve real symbol
const char *kind() const override;
- bool oneMember(Dsymbol *&ps, Identifier *ident) override;
- const char *toChars() const override;
const char* toPrettyCharsHelper() override final;
Identifier *getIdent() override final;
bool isDiscardable();
bool needsCodegen();
- TemplateInstance *isTemplateInstance() override final { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
@@ -297,11 +284,8 @@ public:
TemplateMixin *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
- bool oneMember(Dsymbol *&ps, Identifier *ident) override;
bool hasPointers() override;
- const char *toChars() const override;
- TemplateMixin *isTemplateMixin() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d
index f2dc50e..561181a 100644
--- a/gcc/d/dmd/templateparamsem.d
+++ b/gcc/d/dmd/templateparamsem.d
@@ -1,12 +1,12 @@
/**
* Semantic analysis of template parameters.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d, _templateparamsem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templateparamsem.d, _templateparamsem.d)
* Documentation: https://dlang.org/phobos/dmd_templateparamsem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templateparamsem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/templateparamsem.d
*/
module dmd.templateparamsem;
@@ -170,7 +170,7 @@ RootObject aliasParameterSemantic(Loc loc, Scope* sc, RootObject o, TemplatePara
Dsymbol s = ta.toDsymbol(sc);
if (s)
return s;
- else if (TypeInstance ti = ta.isTypeInstance())
+ if (TypeInstance ti = ta.isTypeInstance())
{
Type t;
const errors = global.errors;
@@ -183,14 +183,13 @@ RootObject aliasParameterSemantic(Loc loc, Scope* sc, RootObject o, TemplatePara
// see https://issues.dlang.org/show_bug.cgi?id=16472
if (t)
return t.typeSemantic(loc, sc);
- else if (ea)
+ if (ea)
{
return eaCTFE();
}
- else if (s)
+ if (s)
return s;
- else
- assert(0);
+ assert(0);
}
else
return ta.typeSemantic(loc, sc);
diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d
index bd3cd89..e5efce4 100644
--- a/gcc/d/dmd/templatesem.d
+++ b/gcc/d/dmd/templatesem.d
@@ -1,12 +1,12 @@
/**
* Template semantics.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templatesem.d, _templatesem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templatesem.d, _templatesem.d)
* Documentation: https://dlang.org/phobos/dmd_templatesem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templatesem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/templatesem.d
*/
module dmd.templatesem;
@@ -23,7 +23,6 @@ import dmd.dcast;
import dmd.dclass;
import dmd.declaration;
import dmd.dinterpret;
-import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
@@ -56,6 +55,8 @@ import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
+alias funcLeastAsSpecialized = dmd.funcsem.leastAsSpecialized;
+
/************************************
* Perform semantic analysis on template.
* Params:
@@ -107,7 +108,7 @@ void templateDeclarationSemantic(Scope* sc, TemplateDeclaration tempdecl)
tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_);
tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_);
- UserAttributeDeclaration.checkGNUABITag(tempdecl, sc.linkage);
+ checkGNUABITag(tempdecl, sc.linkage);
if (!tempdecl.isstatic)
{
@@ -119,7 +120,7 @@ void templateDeclarationSemantic(Scope* sc, TemplateDeclaration tempdecl)
auto paramsym = new ScopeDsymbol();
paramsym.parent = tempdecl.parent;
Scope* paramscope = sc.push(paramsym);
- paramscope.stc = 0;
+ paramscope.stc = STC.none;
if (global.params.ddoc.doOutput)
{
@@ -152,7 +153,7 @@ void templateDeclarationSemantic(Scope* sc, TemplateDeclaration tempdecl)
/* Calculate TemplateParameter.dependent
*/
- TemplateParameters tparams = TemplateParameters(1);
+ auto tparams = TemplateParameters(1);
for (size_t i = 0; i < tempdecl.parameters.length; i++)
{
TemplateParameter tp = (*tempdecl.parameters)[i];
@@ -352,7 +353,7 @@ MATCH matchWithInstance(Scope* sc, TemplateDeclaration td, TemplateInstance ti,
// Resolve parameter types and 'auto ref's.
tf.inferenceArguments = argumentList;
- uint olderrors = global.startGagging();
+ const olderrors = global.startGagging();
fd.type = tf.typeSemantic(td.loc, paramscope);
global.endGagging(olderrors);
if (fd.type.ty != Tfunction)
@@ -455,7 +456,7 @@ bool evaluateConstraint(TemplateDeclaration td, TemplateInstance ti, Scope* sc,
// (previously, this was immediately before calling evalStaticCondition), so the
// semantic pass knows not to issue deprecation warnings for these throw-away decls.
// https://issues.dlang.org/show_bug.cgi?id=21831
- scx.flags |= SCOPE.constraint;
+ scx.inTemplateConstraint = true;
assert(!ti.symtab);
if (fd)
@@ -602,7 +603,7 @@ Scope* createScopeForTemplateParameters(TemplateDeclaration td, TemplateInstance
paramscope.tinst = ti;
paramscope.minst = sc.minst;
paramscope.callsc = sc;
- paramscope.stc = 0;
+ paramscope.stc = STC.none;
return paramscope;
}
@@ -622,7 +623,7 @@ MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td, TemplateDeclaration
enum LOG_LEASTAS = 0;
static if (LOG_LEASTAS)
{
- printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
+ printf("%s.leastAsSpecialized(%s)\n", td.toChars(), td2.toChars());
}
/* This works by taking the template parameters to this template
@@ -904,7 +905,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat
// Match attributes of tthis against attributes of fd
if (fd.type && !fd.isCtorDeclaration() && !(td._scope.stc & STC.static_))
{
- StorageClass stc = td._scope.stc | fd.storage_class2;
+ STC stc = td._scope.stc | fd.storage_class2;
// Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
Dsymbol p = td.parent;
while (p.isTemplateDeclaration() || p.isTemplateInstance())
@@ -1251,7 +1252,13 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat
//printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
RootObject oarg = farg;
- if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
+
+ if (farg.isFuncExp())
+ {
+ // When assigning an untyped (void) lambda `x => y` to a `(F)(ref F)` parameter,
+ // we don't want to deduce type void creating a void parameter
+ }
+ else if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
{
/* Allow expressions that have CT-known boundaries and type [] to match with [dim]
*/
@@ -1335,10 +1342,10 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat
* We also save/restore sc.func.flags to avoid messing up
* attribute inference in the evaluation.
*/
- const oldflags = sc.func ? sc.func.flags : 0;
+ const oldflags = sc.func ? sc.func.saveFlags : 0;
auto e = resolveAliasThis(sc, farg, true);
if (sc.func)
- sc.func.flags = oldflags;
+ sc.func.restoreFlags(oldflags);
if (e)
{
farg = e;
@@ -1355,7 +1362,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat
{
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
}
- else if (global.params.rvalueRefParam == FeatureState.enabled)
+ else if (sc.previews.rvalueRefParam)
{
// Allow implicit conversion to ref
}
@@ -1418,9 +1425,9 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat
Expression e;
Type t;
Dsymbol s;
- Scope *sco;
+ Scope* sco;
- uint errors = global.startGagging();
+ const errors = global.startGagging();
/* ref: https://issues.dlang.org/show_bug.cgi?id=11118
* The parameter isn't part of the template
* ones, let's try to find it in the
@@ -1727,7 +1734,7 @@ FuncDeclaration doHeaderInstantiation(TemplateDeclaration td, TemplateInstance t
{
// For constructors, emitting return type is necessary for
// isReturnIsolated() in functionResolve.
- tf.isctor = true;
+ tf.isCtor = true;
Dsymbol parent = td.toParentDecl();
Type tret;
@@ -1745,7 +1752,7 @@ FuncDeclaration doHeaderInstantiation(TemplateDeclaration td, TemplateInstance t
}
tf.next = tret;
if (ad && ad.isStructDeclaration())
- tf.isref = 1;
+ tf.isRef = 1;
//printf("tf = %s\n", tf.toChars());
}
else
@@ -1883,23 +1890,22 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
{
version (none)
{
- printf("functionResolve() dstart = %s\n", dstart.toChars());
- printf(" tiargs:\n");
- if (tiargs)
+ printf("functionResolve() dstart: %s (", dstart.toChars());
+ for (size_t i = 0; i < (tiargs ? (*tiargs).length : 0); i++)
{
- for (size_t i = 0; i < tiargs.length; i++)
- {
- RootObject arg = (*tiargs)[i];
- printf("\t%s\n", arg.toChars());
- }
+ if (i) printf(", ");
+ RootObject arg = (*tiargs)[i];
+ printf("%s", arg.toChars());
}
- printf(" fargs:\n");
- for (size_t i = 0; i < (fargs ? fargs.length : 0); i++)
+ printf(")(");
+ for (size_t i = 0; i < (argumentList.arguments ? (*argumentList.arguments).length : 0); i++)
{
- Expression arg = (*fargs)[i];
- printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
+ if (i) printf(", ");
+ Expression arg = (*argumentList.arguments)[i];
+ printf("%s %s", arg.type.toChars(), arg.toChars());
//printf("\tty = %d\n", arg.type.ty);
}
+ printf(")\n");
//printf("stc = %llx\n", dstart._scope.stc);
//printf("match:t/f = %d/%d\n", ta_last, m.last);
}
@@ -1938,7 +1944,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
//printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
auto tf = fd.type.isTypeFunction();
- int prop = tf.isproperty ? 1 : 2;
+ int prop = tf.isProperty ? 1 : 2;
if (property == 0)
property = prop;
else if (property != prop)
@@ -1986,7 +1992,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
tf.mod = tthis_fd.mod;
}
const(char)* failMessage;
- MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc);
+ MATCH mfa = callMatch(fd, tf, tthis_fd, argumentList, 0, errorHelper, sc);
//printf("test1: mfa = %d\n", mfa);
if (failMessage)
errorHelper(failMessage);
@@ -2021,8 +2027,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
* This is because f() is "more specialized."
*/
{
- MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names);
- MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names);
+ MATCH c1 = funcLeastAsSpecialized(fd, m.lastf, argumentList.names);
+ MATCH c2 = funcLeastAsSpecialized(m.lastf, fd, argumentList.names);
//printf("c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) return firstIsBetter();
if (c1 < c2) return 0;
@@ -2191,7 +2197,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
auto tf = fd.type.isTypeFunction();
- MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc);
+ MATCH mfa = callMatch(fd, tf, tthis_fd, argumentList, 0, null, sc);
if (mfa < m.last)
return 0;
@@ -2293,16 +2299,16 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
// Disambiguate by tf.callMatch
auto tf1 = fd.type.isTypeFunction();
auto tf2 = m.lastf.type.isTypeFunction();
- MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc);
- MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc);
+ MATCH c1 = callMatch(fd, tf1, tthis_fd, argumentList, 0, null, sc);
+ MATCH c2 = callMatch(m.lastf, tf2, tthis_best, argumentList, 0, null, sc);
//printf("2: c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
}
{
// Disambiguate by picking the most specialized FunctionDeclaration
- MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names);
- MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names);
+ MATCH c1 = funcLeastAsSpecialized(fd, m.lastf, argumentList.names);
+ MATCH c2 = funcLeastAsSpecialized(m.lastf, fd, argumentList.names);
//printf("3: c1 = %d, c2 = %d\n", c1, c2);
if (c1 > c2) goto Ltd;
if (c1 < c2) goto Ltd_best;
@@ -2397,7 +2403,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
if (m.lastf.type.ty == Terror)
goto Lerror;
auto tf = m.lastf.type.isTypeFunction();
- if (!tf.callMatch(tthis_best, argumentList, 0, null, sc))
+ if (callMatch(m.lastf, tf, tthis_best, argumentList, 0, null, sc) == MATCH.nomatch)
goto Lnomatch;
/* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
@@ -2427,3 +2433,70 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
m.last = MATCH.nomatch;
}
}
+/* Create dummy argument based on parameter.
+ */
+private RootObject dummyArg(TemplateParameter tp)
+{
+ scope v = new DummyArgVisitor();
+ tp.accept(v);
+ return v.result;
+}
+private extern(C++) class DummyArgVisitor : Visitor
+{
+ RootObject result;
+
+ alias visit = typeof(super).visit;
+ override void visit(TemplateTypeParameter ttp)
+ {
+ Type t = ttp.specType;
+ if (t)
+ {
+ result = t;
+ return;
+ }
+ // Use this for alias-parameter's too (?)
+ if (!ttp.tdummy)
+ ttp.tdummy = new TypeIdentifier(ttp.loc, ttp.ident);
+ result = ttp.tdummy;
+ }
+
+ override void visit(TemplateValueParameter tvp)
+ {
+ Expression e = tvp.specValue;
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ // Create a dummy value
+ auto pe = cast(void*)tvp.valType in tvp.edummies;
+ if (pe)
+ {
+ result = *pe;
+ return;
+ }
+
+ e = tvp.valType.defaultInit(Loc.initial);
+ tvp.edummies[cast(void*)tvp.valType] = e;
+ result = e;
+ }
+
+ override void visit(TemplateAliasParameter tap)
+ {
+ RootObject s = tap.specAlias;
+ if (s)
+ {
+ result = s;
+ return;
+ }
+ if (!tap.sdummy)
+ tap.sdummy = new Dsymbol(DSYM.dsymbol);
+ result = tap.sdummy;
+ }
+
+ override void visit(TemplateTupleParameter tap)
+ {
+ result = null;
+ }
+}
diff --git a/gcc/d/dmd/timetrace.d b/gcc/d/dmd/timetrace.d
new file mode 100644
index 0000000..742dde0
--- /dev/null
+++ b/gcc/d/dmd/timetrace.d
@@ -0,0 +1,82 @@
+/**
+Compilation time tracing, -ftime-trace.
+
+The time trace profile is output in the Chrome Trace Event Format, described
+here: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+
+This file is originally from LDC (the LLVM D compiler).
+
+Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
+Authors: Johan Engelen, Max Haughton, Dennis Korpel
+License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/timetrace.d, common/_timetrace.d)
+Documentation: https://dlang.org/phobos/dmd_common_timetrace.html
+Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/timetrace.d
+*/
+module dmd.timetrace;
+
+import dmd.dsymbol;
+import dmd.expression;
+
+/**
+ * Start a new time trace event
+ *
+ * Details of the event will be passed as delegates to `timeTraceEndEvent` so
+ * they're only generated when the event is actually written.
+ *
+ * Params:
+ * eventType = what compilation stage the event belongs to
+ * (redundant with the eventType of `timeTraceEndEvent` but used by GDC)
+ */
+extern (C++)
+void timeTraceBeginEvent(TimeTraceEventType eventType)
+{
+}
+
+/**
+ * End a time tracing event, optionally updating the event name and details
+ * with a delegate. Delegates are used to prevent spending time on string
+ * generation when an event is too small to be generated anyway.
+ *
+ * Params:
+ * eventType = what compilation stage the event belongs to
+ * sym = Dsymbol which was analyzed, used to generate 'name' and 'detail'
+ * e = Expression which was analyzed, used to generate 'name' and 'detail'
+ * detail = custom lazy string for 'detail' of event
+ */
+extern (C++)
+void timeTraceEndEvent(TimeTraceEventType eventType)
+{
+}
+
+/// ditto
+void timeTraceEndEvent(TimeTraceEventType eventType, Dsymbol sym, scope const(char)[] delegate() detail = null)
+{
+ return timeTraceEndEvent(eventType);
+}
+
+/// ditto
+extern (C++)
+void timeTraceEndEvent(TimeTraceEventType eventType, Expression e)
+{
+ return timeTraceEndEvent(eventType);
+}
+
+/// Identifies which compilation stage the event is associated to
+enum TimeTraceEventType
+{
+ generic,
+ parseGeneral,
+ parse,
+ semaGeneral,
+ sema1Import,
+ sema1Module,
+ sema2,
+ sema3,
+ ctfe,
+ ctfeCall,
+ codegenGlobal,
+ codegenModule,
+ codegenFunction,
+ link,
+}
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
index da4a3ee..a106207 100644
--- a/gcc/d/dmd/tokens.d
+++ b/gcc/d/dmd/tokens.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/lex.html#tokens, Tokens)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d, _tokens.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/tokens.d, _tokens.d)
* Documentation: https://dlang.org/phobos/dmd_tokens.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/tokens.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/tokens.d
*/
module dmd.tokens;
@@ -27,6 +27,9 @@ enum TOK : ubyte
{
reserved,
+ // if this list changes, update
+ // tokens.h, ../tests/cxxfrontend.cc and ../../test/unit/lexer/location_offset.d to match
+
// Other
leftParenthesis,
rightParenthesis,
@@ -45,7 +48,6 @@ enum TOK : ubyte
false_,
throw_,
new_,
- delete_,
variable,
slice,
version_,
@@ -249,6 +251,7 @@ enum TOK : ubyte
wchar_tLiteral,
endOfLine, // \n, \r, \u2028, \u2029
whitespace,
+ rvalue,
// C only keywords
inline,
@@ -425,6 +428,7 @@ enum EXP : ubyte
interval,
loweredAssignExp,
+ rvalue,
}
enum FirstCKeyword = TOK.inline;
@@ -432,8 +436,10 @@ enum FirstCKeyword = TOK.inline;
// Assert that all token enum members have consecutive values and
// that none of them overlap
static assert(() {
- foreach (idx, enumName; __traits(allMembers, TOK)) {
- static if (idx != __traits(getMember, TOK, enumName)) {
+ foreach (idx, enumName; __traits(allMembers, TOK))
+ {
+ static if (idx != __traits(getMember, TOK, enumName))
+ {
pragma(msg, "Error: Expected TOK.", enumName, " to be ", idx, " but is ", __traits(getMember, TOK, enumName));
static assert(0);
}
@@ -454,7 +460,6 @@ private immutable TOK[] keywords =
TOK.false_,
TOK.cast_,
TOK.new_,
- TOK.delete_,
TOK.throw_,
TOK.module_,
TOK.pragma_,
@@ -556,6 +561,7 @@ private immutable TOK[] keywords =
TOK.prettyFunction,
TOK.shared_,
TOK.immutable_,
+ TOK.rvalue,
// C only keywords
TOK.inline,
@@ -674,12 +680,12 @@ extern (C++) struct Token
TOK.false_: "false",
TOK.cast_: "cast",
TOK.new_: "new",
- TOK.delete_: "delete",
TOK.throw_: "throw",
TOK.module_: "module",
TOK.pragma_: "pragma",
TOK.typeof_: "typeof",
TOK.typeid_: "typeid",
+ TOK.rvalue: "__rvalue",
TOK.template_: "template",
TOK.void_: "void",
TOK.int8: "byte",
@@ -921,13 +927,18 @@ nothrow:
return 0;
}
- extern(D) void appendInterpolatedPart(const ref OutBuffer buf) {
+ extern(D) void appendInterpolatedPart(const ref OutBuffer buf)
+ {
appendInterpolatedPart(cast(const(char)*)buf[].ptr, buf.length);
}
- extern(D) void appendInterpolatedPart(const(char)[] str) {
+
+ extern(D) void appendInterpolatedPart(const(char)[] str)
+ {
appendInterpolatedPart(str.ptr, str.length);
}
- extern(D) void appendInterpolatedPart(const(char)* ptr, size_t length) {
+
+ extern(D) void appendInterpolatedPart(const(char)* ptr, size_t length)
+ {
assert(value == TOK.interpolated);
if (interpolatedSet is null)
interpolatedSet = new InterpolatedSet;
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
index ef91001..ecbcc02 100644
--- a/gcc/d/dmd/tokens.h
+++ b/gcc/d/dmd/tokens.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -54,7 +54,6 @@ enum class TOK : unsigned char
false_,
throw_,
new_,
- delete_,
variable,
slice,
version_,
@@ -258,6 +257,7 @@ enum class TOK : unsigned char
wchar_tLiteral,
endOfLine, // \n, \r, \u2028, \u2029
whitespace,
+ rvalue,
// C only keywords
inline_,
@@ -476,7 +476,7 @@ struct Token
Identifier *ident;
};
- Token() : next(NULL) {}
+ Token() : next(nullptr) {}
const char *toChars() const;
static const char *toChars(TOK value);
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index be7aa99..127a89d 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -3,12 +3,12 @@
*
* Specification: $(LINK2 https://dlang.org/spec/traits.html, Traits)
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/traits.d, _traits.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/traits.d, _traits.d)
* Documentation: https://dlang.org/phobos/dmd_traits.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/traits.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/traits.d
*/
module dmd.traits;
@@ -20,12 +20,12 @@ import dmd.arraytypes;
import dmd.astcodegen;
import dmd.astenums;
import dmd.attrib;
+import dmd.attribsem;
import dmd.canthrow;
import dmd.dclass;
import dmd.declaration;
import dmd.dimport;
import dmd.dinterpret;
-import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
import dmd.dsymbol;
@@ -42,6 +42,7 @@ import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.location;
+import dmd.mangle : decoToType;
import dmd.mtype;
import dmd.nogc;
import dmd.optimize;
@@ -337,7 +338,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
const save = sc.stc;
if (e.ident == Id.isDeprecated)
sc.stc |= STC.deprecated_;
- if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 1))
+ Scope* sc2 = sc.startCTFE();
+ scope(exit) { sc2.endCTFE(); }
+ if (!TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1))
{
sc.stc = save;
return ErrorExp.get();
@@ -443,23 +446,23 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
if (e.ident == Id.isArithmetic)
{
- return isTypeX(t => t.isintegral() || t.isfloating());
+ return isTypeX(t => t.isIntegral() || t.isFloating());
}
if (e.ident == Id.isFloating)
{
- return isTypeX(t => t.isfloating());
+ return isTypeX(t => t.isFloating());
}
if (e.ident == Id.isIntegral)
{
- return isTypeX(t => t.isintegral());
+ return isTypeX(t => t.isIntegral());
}
if (e.ident == Id.isScalar)
{
- return isTypeX(t => t.isscalar());
+ return isTypeX(t => t.isScalar());
}
if (e.ident == Id.isUnsigned)
{
- return isTypeX(t => t.isunsigned());
+ return isTypeX(t => t.isUnsigned());
}
if (e.ident == Id.isAssociativeArray)
{
@@ -467,7 +470,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
if (e.ident == Id.isDeprecated)
{
- if (isTypeX(t => t.iscomplex() || t.isimaginary()).toBool().hasValue(true))
+ if (isTypeX(t => t.isComplex() || t.isImaginary()).toBool().hasValue(true))
return True();
return isDsymX(t => t.isDeprecated());
}
@@ -481,13 +484,19 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
if (e.ident == Id.isAbstractClass)
{
- return isTypeX(t => t.toBasetype().isTypeClass() &&
- t.toBasetype().isTypeClass().sym.isAbstract());
+ return isTypeX((t)
+ {
+ auto c = t.toBasetype().isTypeClass();
+ return c && c.sym.isAbstract();
+ });
}
if (e.ident == Id.isFinalClass)
{
- return isTypeX(t => t.toBasetype().isTypeClass() &&
- (t.toBasetype().isTypeClass().sym.storage_class & STC.final_) != 0);
+ return isTypeX((t)
+ {
+ const c = t.toBasetype().isTypeClass();
+ return c && (c.sym.storage_class & STC.final_) != 0;
+ });
}
if (e.ident == Id.isTemplate)
{
@@ -502,6 +511,17 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
sm => sm.isTemplateDeclaration() !is null) != 0;
});
}
+ if (e.ident == Id.isBitfield)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isDsymX((s)
+ {
+ s = s.toAlias();
+ return s.isBitFieldDeclaration() !is null;
+ });
+ }
if (e.ident == Id.isPOD)
{
if (dim != 1)
@@ -524,7 +544,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
return True();
}
- if (e.ident == Id.hasCopyConstructor || e.ident == Id.hasPostblit)
+ if (e.ident == Id.hasCopyConstructor ||
+ e.ident == Id.hasMoveConstructor ||
+ e.ident == Id.hasPostblit)
{
if (dim != 1)
return dimError(1);
@@ -542,8 +564,14 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
auto ts = tb.isTypeStruct();
if (auto sd = ts ? ts.sym : null)
{
- return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False())
- : (sd.hasCopyCtor ? True() : False());
+ bool result;
+ if (e.ident == Id.hasPostblit)
+ result = sd.postblit !is null;
+ else if (e.ident == Id. hasCopyConstructor)
+ result = sd.hasCopyCtor;
+ else
+ result = sd.hasMoveCtor;
+ return result ? True() : False();
}
return False();
}
@@ -681,6 +709,25 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
return isDeclX(d => (d.storage_class & STC.lazy_) != 0);
}
+ if (e.ident == Id.isCOMClass)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbol(o);
+ AggregateDeclaration agg;
+
+ if (!s || ((agg = s.isAggregateDeclaration()) is null))
+ {
+ error(e.loc, "argument to `__traits(isCOMClass, %s)` is not a declaration", o.toChars());
+ return ErrorExp.get();
+ }
+
+ if (ClassDeclaration cd = agg.isClassDeclaration())
+ return cd.com ? True() : False();
+ return False();
+ }
if (e.ident == Id.identifier)
{
// Get identifier for symbol as a string literal
@@ -724,7 +771,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
return dimError(1);
Scope* sc2 = sc.push();
- sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
+ sc2.copyFlagsFrom(sc);
+ sc2.noAccessCheck = true;
+ sc2.ignoresymbolvisibility = true;
bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
sc2.pop();
if (!ok)
@@ -754,13 +803,52 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
return se.expressionSemantic(sc);
}
+ if (e.ident == Id.getBitfieldOffset || e.ident == Id.getBitfieldWidth)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbolWithoutExpCtx(o);
+ if (!s)
+ {
+ error(e.loc, "bitfield symbol expected not `%s`", o.toChars());
+ return ErrorExp.get();
+ }
+
+ auto vd = s.toAlias.isVarDeclaration();
+ if (!vd || !(vd.storage_class & STC.field))
+ {
+ error(e.loc, "bitfield symbol expected not %s `%s`", s.kind, s.toPrettyChars);
+ return ErrorExp.get();
+ }
+
+ uint fieldWidth;
+ uint bitOffset;
+ if (auto bf = vd.isBitFieldDeclaration())
+ {
+ fieldWidth = bf.fieldWidth;
+ bitOffset = bf.bitOffset;
+ }
+ else // just a regular field
+ {
+ const sz = size(vd.type);
+ assert(sz < uint.max / 8); // overflow check
+ fieldWidth = cast(uint)sz * 8;
+ bitOffset = 0;
+ }
+ uint value = e.ident == Id.getBitfieldOffset ? bitOffset : fieldWidth;
+ return new IntegerExp(e.loc, value, Type.tuns32);
+ }
if (e.ident == Id.getProtection || e.ident == Id.getVisibility)
{
if (dim != 1)
return dimError(1);
Scope* sc2 = sc.push();
- sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
+ sc2.copyFlagsFrom(sc);
+ sc2.noAccessCheck = true;
+ sc2.ignoresymbolvisibility = true;
bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
sc2.pop();
if (!ok)
@@ -991,7 +1079,8 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
doSemantic:
// ignore symbol visibility and disable access checks for these traits
Scope* scx = sc.push();
- scx.flags |= SCOPE.ignoresymbolvisibility | SCOPE.noaccesscheck;
+ scx.ignoresymbolvisibility = true;
+ scx.noAccessCheck = true;
scope (exit) scx.pop();
if (e.ident == Id.hasMember)
@@ -1013,7 +1102,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
e.ident == Id.getVirtualMethods ||
e.ident == Id.getOverloads)
{
- uint errors = global.errors;
+ const errors = global.errors;
Expression eorig = ex;
ex = ex.expressionSemantic(scx);
if (errors < global.errors)
@@ -1245,7 +1334,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
// @@@DEPRECATION 2.100.2
if (auto td = s.isTemplateDeclaration())
{
- if (td.overnext || td.overroot)
+ if (td.overnext)
{
deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", td.ident.toChars());
deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from");
@@ -1434,7 +1523,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
if (!fparams.parameters)
return ErrorExp.get();
- StorageClass stc;
+ STC stc;
// Set stc to storage class of the ith parameter
auto ex = isExpression((*e.args)[1]);
@@ -1721,11 +1810,15 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
foreach (o; *e.args)
{
- uint errors = global.startGagging();
+ const errors = global.startGagging();
Scope* sc2 = sc.push();
sc2.tinst = null;
sc2.minst = null; // this is why code for these are not emitted to object file
- sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst;
+ sc2.copyFlagsFrom(sc);
+ sc2.ctfe = false;
+ sc2.condition = false;
+ sc2.traitsCompiles = true;
+ sc2.fullinst = true;
bool err = false;
@@ -1752,7 +1845,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
if (sc2.func && sc2.func.type.isTypeFunction())
{
const tf = sc2.func.type.isTypeFunction();
- err |= tf.isnothrow && canThrow(ex, sc2.func, null);
+ err |= tf.isNothrow && canThrow(ex, sc2.func, null);
}
ex = checkGC(sc2, ex);
if (ex.op == EXP.error)
@@ -1962,9 +2055,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
return dimError(1);
auto arg0 = (*e.args)[0];
Dsymbol s = getDsymbolWithoutExpCtx(arg0);
- if (!s || !s.loc.isValid())
+ if (!s || !s.loc.isValid() || s.isModule())
{
- error(e.loc, "can only get the location of a symbol, not `%s`", arg0.toChars());
+ error(e.loc, "can only get the location of a symbol, not `%s`", s ? s.toPrettyChars() : arg0.toChars());
return ErrorExp.get();
}
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index b2b9e38..d4c7a58 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1,12 +1,12 @@
/**
* Semantic analysis for D types.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typesem.d, _typesem.d)
* Documentation: https://dlang.org/phobos/dmd_typesem.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/typesem.d
*/
module dmd.typesem;
@@ -28,7 +28,6 @@ import dmd.declaration;
import dmd.denum;
import dmd.dimport;
import dmd.dinterpret;
-import dmd.dmangle;
import dmd.dmodule;
import dmd.dscope;
import dmd.dstruct;
@@ -53,6 +52,8 @@ import dmd.initsem;
import dmd.location;
import dmd.visitor;
import dmd.mtype;
+import dmd.mangle;
+import dmd.nogc;
import dmd.objc;
import dmd.opover;
import dmd.optimize;
@@ -82,7 +83,7 @@ import dmd.tokens;
* ps = set if s[oindex] is a Dsymbol, otherwise null
* oindex = index into s
*/
-private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
+private void resolveTupleIndex(Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
{
auto tup = s.isTupleDeclaration();
@@ -152,7 +153,7 @@ private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expr
* ps = set if symbol otherwise null
* typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
*/
-private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
+private void resolveHelper(TypeQualified mt, Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
{
version (none)
@@ -229,13 +230,13 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
}
Type t = s.getType(); // type symbol, type alias, or type tuple?
- uint errorsave = global.errors;
+ const errorsave = global.errors;
SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports;
Dsymbol sm = s.searchX(loc, sc, id, flags);
if (sm)
{
- if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+ if (!sc.ignoresymbolvisibility && !symbolIsVisible(sc, sm))
{
.error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
sm = null;
@@ -387,7 +388,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
* Returns:
* symbol found, NULL if not
*/
-private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags)
+private Dsymbol searchX(Dsymbol dsym, Loc loc, Scope* sc, RootObject id, SearchOptFlags flags)
{
//printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
Dsymbol s = dsym.toAlias();
@@ -473,12 +474,12 @@ bool isCopyable(Type t)
* Otherwise, when the type has const/inout indirections, returns 1.
*
* Params:
- * isref = if true, check `ref t`; otherwise, check just `t`
+ * isRef = if true, check `ref t`; otherwise, check just `t`
* t = the type that is being checked
*/
-int mutabilityOfType(bool isref, Type t)
+int mutabilityOfType(bool isRef, Type t)
{
- if (isref)
+ if (isRef)
{
if (t.mod & MODFlags.immutable_)
return 2;
@@ -614,13 +615,13 @@ Expression typeToExpression(Type t)
* loc = The source location.
* sc = scope of the type
*/
-extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
+extern (D) bool checkComplexTransition(Type type, Loc loc, Scope* sc)
{
if (sc.isDeprecated())
return false;
// Don't complain if we're inside a template constraint
// https://issues.dlang.org/show_bug.cgi?id=21831
- if (sc.flags & SCOPE.constraint)
+ if (sc.inTemplateConstraint)
return false;
Type t = type.baseElemOf();
@@ -631,9 +632,9 @@ extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
return false;
- if (t.isimaginary() || t.iscomplex())
+ if (t.isImaginary() || t.isComplex())
{
- if (sc.flags & SCOPE.Cfile)
+ if (sc.inCfile)
return true; // complex/imaginary not deprecated in C code
Type rt;
switch (t.ty)
@@ -660,7 +661,7 @@ extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
// Deprecated in 2.097 - Can be made an error from 2.117.
// The deprecation period is longer than usual as `cfloat`,
// `cdouble`, and `creal` were quite widely used.
- if (t.iscomplex())
+ if (t.isComplex())
{
deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
type.toChars(), rt.toChars());
@@ -680,6 +681,7 @@ extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
* 'args' are being matched to function type 'tf'
* Determine match level.
* Params:
+ * fd = function being called, if a symbol
* tf = function type
* tthis = type of `this` pointer, null if not member function
* argumentList = arguments to function call
@@ -689,9 +691,10 @@ extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
* Returns:
* MATCHxxxx
*/
-extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null)
+extern (D) MATCH callMatch(FuncDeclaration fd, TypeFunction tf, Type tthis, ArgumentList argumentList,
+ int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null)
{
- //printf("TypeFunction::callMatch() %s\n", tf.toChars());
+ //printf("callMatch() fd: %s, tf: %s\n", fd ? fd.ident.toChars() : "null", toChars(tf));
MATCH match = MATCH.exact; // assume exact match
ubyte wildmatch = 0;
@@ -752,13 +755,14 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
}
const(char)* failMessage;
const(char)** pMessage = errorHelper ? &failMessage : null;
- auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
+ OutBuffer buf;
+ auto resolvedArgs = tf.resolveNamedArgs(argumentList, errorHelper ? &buf : null);
Expression[] args;
if (!resolvedArgs)
{
- if (failMessage)
+ if (buf.length)
{
- errorHelper(failMessage);
+ errorHelper(buf.peekChars());
return MATCH.nomatch;
}
@@ -818,7 +822,12 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
Expression arg = args[u];
if (!arg)
continue; // default argument
- m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);
+ m = argumentMatchParameter(fd, tf, p, arg, wildmatch, flag, sc, pMessage);
+ if (failMessage)
+ {
+ buf.reset();
+ buf.writestring(failMessage);
+ }
}
else if (p.defaultArg)
continue;
@@ -835,7 +844,9 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
L1:
if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
{
- auto trailingArgs = args[u .. $];
+ Expression[] trailingArgs;
+ if (args.length >= u)
+ trailingArgs = args[u .. $];
if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
return vmatch < match ? vmatch : match;
// Error message was already generated in `matchTypeSafeVarArgs`
@@ -843,15 +854,17 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
errorHelper(failMessage);
return MATCH.nomatch;
}
- if (pMessage && u >= args.length)
- *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`",
- u + 1, parameterToChars(p, tf, false));
- // If an error happened previously, `pMessage` was already filled
- else if (pMessage && !*pMessage)
- *pMessage = tf.getParamError(args[u], p);
-
if (errorHelper)
- errorHelper(*pMessage);
+ {
+ if (u >= args.length)
+ TypeFunction.getMatchError(buf, "missing argument for parameter #%d: `%s`",
+ u + 1, parameterToChars(p, tf, false));
+ // If an error happened previously, `pMessage` was already filled
+ else if (buf.length == 0)
+ buf.writestring(tf.getParamError(args[u], p));
+
+ errorHelper(buf.peekChars());
+ }
return MATCH.nomatch;
}
if (m < match)
@@ -861,7 +874,9 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
if (errorHelper && !parameterList.varargs && args.length > nparams)
{
// all parameters had a match, but there are surplus args
- errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length));
+ OutBuffer buf2;
+ TypeFunction.getMatchError(buf2, "expected %d argument(s), not %d", nparams, args.length);
+ errorHelper(buf2.extractChars());
return MATCH.nomatch;
}
//printf("match = %d\n", match);
@@ -874,14 +889,15 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
*
* This is done by seeing if a call to the copy constructor can be made:
* ```
- * typeof(tprm) __copytmp;
- * copytmp.__copyCtor(arg);
+ * typeof(tprm) __copytemp;
+ * copytemp.__copyCtor(arg);
* ```
*/
private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
{
- auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
+ //printf("isCopyConstructorCallable() argStruct: %s arg: %s tprm: %s\n", argStruct.toChars(), toChars(arg), toChars(tprm));
+ auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytemp"), null);
tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
tmp.dsymbolSemantic(sc);
Expression ve = new VarExp(arg.loc, tmp);
@@ -891,66 +907,74 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
if (dmd.expressionsem.trySemantic(e, sc))
return true;
- if (pMessage)
+ if (!pMessage)
+ return false;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=22202
+ *
+ * If a function was deduced by semantic on the CallExp,
+ * it means that resolveFuncCall completed succesfully.
+ * Therefore, there exists a callable copy constructor,
+ * however, it cannot be called because scope constraints
+ * such as purity, safety or nogc.
+ */
+ OutBuffer buf;
+ auto callExp = e.isCallExp();
+
+ bool nocpctor()
{
- /* https://issues.dlang.org/show_bug.cgi?id=22202
- *
- * If a function was deduced by semantic on the CallExp,
- * it means that resolveFuncCall completed succesfully.
- * Therefore, there exists a callable copy constructor,
- * however, it cannot be called because scope constraints
- * such as purity, safety or nogc.
- */
- OutBuffer buf;
- auto callExp = e.isCallExp();
- if (auto f = callExp.f)
- {
- char[] s;
- if (!f.isPure && sc.func.setImpure())
- s ~= "pure ";
- if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
- s ~= "@safe ";
- if (!f.isNogc && sc.func.setGC(arg.loc, null))
- s ~= "nogc ";
- if (f.isDisabled() && !f.isGenerated())
- {
- /* https://issues.dlang.org/show_bug.cgi?id=24301
- * Copy constructor is explicitly disabled
- */
- buf.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`",
- f.type.toChars());
- }
- else if (s)
- {
- s[$-1] = '\0';
- buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
- }
- else if (f.isGenerated() && f.isDisabled())
- {
- /* https://issues.dlang.org/show_bug.cgi?id=23097
- * Compiler generated copy constructor failed.
- */
- buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
- argStruct.toChars());
- }
- else
- {
- /* Although a copy constructor may exist, no suitable match was found.
- * i.e: `inout` constructor creates `const` object, not mutable.
- * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
- */
- goto Lnocpctor;
- }
- }
- else
- {
- Lnocpctor:
- buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
- argStruct.toChars(), arg.type.toChars(), tprm.toChars());
- }
+ buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
+ argStruct.toChars(), arg.type.toChars(), tprm.toChars());
+ *pMessage = buf.extractChars();
+ return false;
+ }
+ auto f = callExp.f;
+ if (!f)
+ return nocpctor();
+
+ if (f.isDisabled() && !f.isGenerated())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=24301
+ * Copy constructor is explicitly disabled
+ */
+ buf.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`",
+ f.type.toChars());
*pMessage = buf.extractChars();
+ return false;
}
+
+ bool bpure = !f.isPure && sc.func.setImpure(arg.loc, null);
+ bool bsafe = !f.isSafe() && !f.isTrusted() && sc.setUnsafe(false, arg.loc, null);
+ bool bnogc = !f.isNogc && sc.func.setGC(arg.loc, null);
+ if (bpure | bsafe | bnogc)
+ {
+ const nullptr = "".ptr;
+ buf.printf("`%s` copy constructor cannot be called from a `%s%s%s` context",
+ f.type.toChars(),
+ bpure ? "pure " .ptr : nullptr,
+ bsafe ? "@safe ".ptr : nullptr,
+ bnogc ? "nogc" .ptr : nullptr);
+ }
+ else if (f.isGenerated() && f.isDisabled())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=23097
+ * Compiler generated copy constructor failed.
+ */
+ buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
+ argStruct.toChars());
+ }
+ else
+ {
+ /* Although a copy constructor may exist, no suitable match was found.
+ * i.e: `inout` constructor creates `const` object, not mutable.
+ * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
+ */
+ return nocpctor();
+ }
+
+ *pMessage = buf.extractChars();
+
return false;
}
@@ -959,25 +983,28 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
*
* This function is called by `TypeFunction.callMatch` while iterating over
* the list of parameter. Here we check if `arg` is a match for `p`,
- * which is mostly about checking if `arg.type` converts to `p`'s type
+ * which is mostly about checking if `arg.type` converts to type of `p`
* and some check about value reference.
*
* Params:
+ * fd = the function being called if symbol, null if not
* tf = The `TypeFunction`, only used for error reporting
* p = The parameter of `tf` being matched
* arg = Argument being passed (bound) to `p`
* wildmatch = Wild (`inout`) matching level, derived from the full argument list
- * flag = A non-zero value means we're doing a partial ordering check
+ * flag = A non-zero value means we are doing a partial ordering check
* (no value semantic check)
* sc = Scope we are in
* pMessage = A buffer to write the error in, or `null`
*
* Returns: Whether `trailingArgs` match `p`.
*/
-private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
+private extern(D) MATCH argumentMatchParameter (FuncDeclaration fd, TypeFunction tf, Parameter p,
Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
{
- //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
+ static if (0)
+ printf("argumentMatchParameter() sc: %p, fd: %s, tf: %s, p: %s, arg: %s, arg.type: %s\n",
+ sc, fd ? fd.ident.toChars() : "null", tf.toChars(), parameterToChars(p, tf, false), arg.toChars(), arg.type.toChars());
MATCH m;
Type targ = arg.type;
Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
@@ -992,18 +1019,47 @@ private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
else
{
const isRef = p.isReference();
- StructDeclaration argStruct, prmStruct;
- // first look for a copy constructor
- if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
+ StructDeclaration argStruct, prmStruct;
+ if (targ.ty == Tstruct && tprm.ty == Tstruct)
{
// if the argument and the parameter are of the same unqualified struct type
argStruct = (cast(TypeStruct)targ).sym;
prmStruct = (cast(TypeStruct)tprm).sym;
+
+ /* if both a copy constructor and move constructor exist, then match
+ * the lvalue to the copy constructor only and the rvalue to the move constructor
+ * only
+ */
+ if (argStruct == prmStruct && fd)
+ {
+ if (auto cfd = fd.isCtorDeclaration())
+ {
+ /* Get struct that constructor is making
+ */
+
+ auto t1 = cfd.type.toBasetype();
+ auto t2 = t1.nextOf();
+ auto t3 = t2.isTypeStruct();
+ if (t3)
+ {
+ auto ctorStruct = t3.sym;
+// StructDeclaration ctorStruct = cfd.type.toBasetype().nextOf().isTypeStruct().sym;
+
+ if (prmStruct == ctorStruct && ctorStruct.hasCopyCtor && ctorStruct.hasMoveCtor)
+ {
+ if (cfd.isCpCtor && !arg.isLvalue())
+ return MATCH.nomatch; // copy constructor is only for lvalues
+ if (cfd.isMoveCtor && arg.isLvalue())
+ return MATCH.nomatch; // move constructor is only for rvalues
+ }
+ }
+ }
+ }
}
// check if the copy constructor may be called to copy the argument
- if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
+ if (arg.isLvalue() && !isRef && argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
{
if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
return MATCH.nomatch;
@@ -1012,106 +1068,107 @@ private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
else
{
import dmd.dcast : cimplicitConvTo;
- m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
+ m = (sc && sc.inCfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
}
}
// Non-lvalues do not match ref or out parameters
- if (p.isReference())
- {
- // https://issues.dlang.org/show_bug.cgi?id=13783
- // Don't use toBasetype() to handle enum types.
- Type ta = targ;
- Type tp = tprm;
- //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
+ if (!p.isReference())
+ return m;
- if (m && !arg.isLvalue())
- {
- if (p.storageClass & STC.out_)
- {
- if (pMessage) *pMessage = tf.getParamError(arg, p);
- return MATCH.nomatch;
- }
+ // https://issues.dlang.org/show_bug.cgi?id=13783
+ // Don't use toBasetype() to handle enum types.
+ Type ta = targ;
+ Type tp = tprm;
+ //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
- if (arg.op == EXP.string_ && tp.ty == Tsarray)
- {
- if (ta.ty != Tsarray)
- {
- Type tn = tp.nextOf().castMod(ta.nextOf().mod);
- dinteger_t dim = (cast(StringExp)arg).len;
- ta = tn.sarrayOf(dim);
- }
- }
- else if (arg.op == EXP.slice && tp.ty == Tsarray)
- {
- // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
- if (ta.ty != Tsarray)
- {
- Type tn = ta.nextOf();
- dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
- ta = tn.sarrayOf(dim);
- }
- }
- else if (p.storageClass & STC.constscoperef)
- {
- // Allow converting a literal to an `in` which is `ref`
- if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
- {
- Type tn = tp.nextOf();
- dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
- ta = tn.sarrayOf(dim);
- }
+ if (m && !arg.isLvalue())
+ {
+ if (p.storageClass & STC.out_)
+ {
+ if (pMessage) *pMessage = tf.getParamError(arg, p);
+ return MATCH.nomatch;
+ }
- // Need to make this a rvalue through a temporary
- m = MATCH.convert;
- }
- else if (global.params.rvalueRefParam != FeatureState.enabled ||
- p.storageClass & STC.out_ ||
- !arg.type.isCopyable()) // can't copy to temp for ref parameter
+ if (arg.op == EXP.string_ && tp.ty == Tsarray)
+ {
+ if (ta.ty != Tsarray)
{
- if (pMessage) *pMessage = tf.getParamError(arg, p);
- return MATCH.nomatch;
+ Type tn = tp.nextOf().castMod(ta.nextOf().mod);
+ dinteger_t dim = (cast(StringExp)arg).len;
+ ta = tn.sarrayOf(dim);
}
- else
+ }
+ else if (arg.op == EXP.slice && tp.ty == Tsarray)
+ {
+ // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+ if (ta.ty != Tsarray)
{
- /* in functionParameters() we'll convert this
- * rvalue into a temporary
- */
- m = MATCH.convert;
+ Type tn = ta.nextOf();
+ dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
+ ta = tn.sarrayOf(dim);
}
}
-
- /* If the match is not already perfect or if the arg
- is not a lvalue then try the `alias this` chain
- see https://issues.dlang.org/show_bug.cgi?id=15674
- and https://issues.dlang.org/show_bug.cgi?id=21905
- */
- if (ta != tp || !arg.isLvalue())
+ else if (p.storageClass & STC.constscoperef)
{
- Type firsttab = ta.toBasetype();
- while (1)
+ // Allow converting a literal to an `in` which is `ref`
+ if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
{
- Type tab = ta.toBasetype();
- Type tat = tab.aliasthisOf();
- if (!tat || !tat.implicitConvTo(tprm))
- break;
- if (tat == tab || tat == firsttab)
- break;
- ta = tat;
+ Type tn = tp.nextOf();
+ dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
+ ta = tn.sarrayOf(dim);
}
- }
- /* A ref variable should work like a head-const reference.
- * e.g. disallows:
- * ref T <- an lvalue of const(T) argument
- * ref T[dim] <- an lvalue of const(T[dim]) argument
- */
- if (!ta.constConv(tp))
+ // Need to make this a rvalue through a temporary
+ m = MATCH.convert;
+ }
+ else if (!(sc && sc.previews.rvalueRefParam) ||
+ p.storageClass & STC.out_ ||
+ !arg.type.isCopyable()) // can't copy to temp for ref parameter
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
+ else
+ {
+ /* in functionParameters() we'll convert this
+ * rvalue into a temporary
+ */
+ m = MATCH.convert;
+ }
}
+
+ /* If the match is not already perfect or if the arg
+ is not a lvalue then try the `alias this` chain
+ see https://issues.dlang.org/show_bug.cgi?id=15674
+ and https://issues.dlang.org/show_bug.cgi?id=21905
+ */
+ if (ta != tp || !arg.isLvalue())
+ {
+ Type firsttab = ta.toBasetype();
+ while (1)
+ {
+ Type tab = ta.toBasetype();
+ Type tat = tab.aliasthisOf();
+ if (!tat || !tat.implicitConvTo(tprm))
+ break;
+ if (tat == tab || tat == firsttab)
+ break;
+ ta = tat;
+ }
+ }
+
+ /* A ref variable should work like a head-const reference.
+ * e.g. disallows:
+ * ref T <- an lvalue of const(T) argument
+ * ref T[dim] <- an lvalue of const(T[dim]) argument
+ */
+ if (!ta.constConv(tp))
+ {
+ if (pMessage) *pMessage = tf.getParamError(arg, p);
+ return MATCH.nomatch;
+ }
+
return m;
}
@@ -1130,7 +1187,7 @@ private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter pa
// only mention rvalue if it's relevant
const rv = !arg.isLvalue() && par.isReference();
buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
- rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
+ rv ? "rvalue ".ptr : "".ptr, arg.toErrMsg(), at,
parameterToChars(par, tf, qual));
return buf.extractChars();
}
@@ -1162,8 +1219,12 @@ private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
if (sz != trailingArgs.length)
{
if (pMessage)
- *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
+ {
+ OutBuffer buf;
+ TypeFunction.getMatchError(buf, "expected %llu variadic argument(s), not %zu",
sz, trailingArgs.length);
+ *pMessage = buf.extractChars();
+ }
return MATCH.nomatch;
}
goto case Tarray;
@@ -1282,6 +1343,326 @@ bool hasPointers(Type t)
}
}
+/**************************************
+ * Returns an indirect type one step from t.
+ */
+Type getIndirection(Type t)
+{
+ t = t.baseElemOf();
+ if (t.ty == Tarray || t.ty == Tpointer)
+ return t.nextOf().toBasetype();
+ if (t.ty == Taarray || t.ty == Tclass)
+ return t;
+ if (t.ty == Tstruct)
+ return t.hasPointers() ? t : null; // TODO
+
+ // should consider TypeDelegate?
+ return null;
+}
+
+uinteger_t size(Type t)
+{
+ return size(t, Loc.initial);
+}
+
+uinteger_t size(Type t, Loc loc)
+{
+
+ uinteger_t visitType(Type t)
+ {
+ error(loc, "no size for type `%s`", t.toChars());
+ return SIZE_INVALID;
+ }
+
+ uinteger_t visitBasic(TypeBasic t)
+ {
+ uint size;
+ //printf("TypeBasic::size()\n");
+ switch (t.ty)
+ {
+ case Tint8:
+ case Tuns8:
+ size = 1;
+ break;
+
+ case Tint16:
+ case Tuns16:
+ size = 2;
+ break;
+
+ case Tint32:
+ case Tuns32:
+ case Tfloat32:
+ case Timaginary32:
+ size = 4;
+ break;
+
+ case Tint64:
+ case Tuns64:
+ case Tfloat64:
+ case Timaginary64:
+ size = 8;
+ break;
+
+ case Tfloat80:
+ case Timaginary80:
+ size = target.realsize;
+ break;
+
+ case Tcomplex32:
+ size = 8;
+ break;
+
+ case Tcomplex64:
+ case Tint128:
+ case Tuns128:
+ size = 16;
+ break;
+
+ case Tcomplex80:
+ size = target.realsize * 2;
+ break;
+
+ case Tvoid:
+ //size = Type::size(); // error message
+ size = 1;
+ break;
+
+ case Tbool:
+ size = 1;
+ break;
+
+ case Tchar:
+ size = 1;
+ break;
+
+ case Twchar:
+ size = 2;
+ break;
+
+ case Tdchar:
+ size = 4;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ //printf("TypeBasic::size() = %d\n", size);
+ return size;
+ }
+
+ uinteger_t visitSArray(TypeSArray t)
+ {
+ //printf("TypeSArray::size()\n");
+ const n = t.numberOfElems(loc);
+ const elemsize = t.baseElemOf().size(loc);
+ bool overflow = false;
+ const sz = mulu(n, elemsize, overflow);
+ if (overflow || sz >= uint.max)
+ {
+ if (elemsize != SIZE_INVALID && n != uint.max)
+ error(loc, "static array `%s` size overflowed to %lld", t.toChars(), cast(long)sz);
+ return SIZE_INVALID;
+ }
+ return sz;
+
+ }
+
+ uinteger_t visitTypeQualified(TypeQualified t)
+ {
+ if (t.ty == Ttypeof)
+ {
+ auto type = (cast(TypeTypeof)t).exp.type;
+ if (type)
+ return type.size(loc);
+ }
+
+ error(t.loc, "size of type `%s` is not known", t.toChars());
+ return SIZE_INVALID;
+ }
+
+ switch(t.ty)
+ {
+ default: return t.isTypeBasic() ? visitBasic(t.isTypeBasic()) : visitType(t);
+ case Ttraits:
+ case Terror: return SIZE_INVALID;
+ case Tvector: return t.isTypeVector().basetype.size();
+ case Tsarray: return visitSArray(t.isTypeSArray());
+ case Tdelegate:
+ case Tarray: return target.ptrsize * 2;
+ case Tpointer:
+ case Treference:
+ case Tclass:
+ case Taarray: return target.ptrsize;
+ case Tident:
+ case Tinstance:
+ case Ttypeof:
+ case Treturn: return visitTypeQualified(cast(TypeQualified)t);
+ case Tstruct: return t.isTypeStruct().sym.size(loc);
+ case Tenum: return t.isTypeEnum().sym.getMemtype(loc).size(loc);
+ case Tnull: return t.tvoidptr.size(loc);
+ case Tnoreturn: return 0;
+ }
+}
+
+/*******************************
+ * Determine if converting 'this' to 'to' is an identity operation,
+ * a conversion to const operation, or the types aren't the same.
+ * Returns:
+ * MATCH.exact 'this' == 'to'
+ * MATCH.constant 'to' is const
+ * MATCH.nomatch conversion to mutable or invariant
+ */
+MATCH constConv(Type from, Type to)
+{
+ MATCH visitType(Type from)
+ {
+ //printf("Type::constConv(this = %s, to = %s)\n", from.toChars(), to.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+ if (from.ty == to.ty && MODimplicitConv(from.mod, to.mod))
+ return MATCH.constant;
+ return MATCH.nomatch;
+ }
+
+ MATCH visitNext(TypeNext from)
+ {
+ //printf("TypeNext::constConv from = %s, to = %s\n", from.toChars(), to.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ if (!(from.ty == to.ty && MODimplicitConv(from.mod, to.mod)))
+ return MATCH.nomatch;
+
+ Type tn = to.nextOf();
+ if (!(tn && from.next.ty == tn.ty))
+ return MATCH.nomatch;
+
+ MATCH m;
+ if (to.isConst()) // whole tail const conversion
+ {
+ // Recursive shared level check
+ m = from.next.constConv(tn);
+ if (m == MATCH.exact)
+ m = MATCH.constant;
+ }
+ else
+ {
+ //printf("\tnext => %s, to.next => %s\n", from.next.toChars(), tn.toChars());
+ m = from.next.equals(tn) ? MATCH.constant : MATCH.nomatch;
+ }
+ return m;
+ }
+
+ MATCH visitSArray(TypeSArray from)
+ {
+ if (auto tsa = to.isTypeSArray())
+ {
+ if (!from.dim.equals(tsa.dim))
+ return MATCH.nomatch;
+ }
+ return visitNext(from);
+ }
+
+ MATCH visitAArray(TypeAArray from)
+ {
+ if (auto taa = to.isTypeAArray())
+ {
+ MATCH mindex = from.index.constConv(taa.index);
+ MATCH mkey = from.next.constConv(taa.next);
+ // Pick the worst match
+ return mkey < mindex ? mkey : mindex;
+ }
+ return visitType(from);
+ }
+
+ MATCH visitPointer(TypePointer from)
+ {
+ if (from.next.ty == Tfunction)
+ {
+ if (to.nextOf() && from.next.equals((cast(TypeNext)to).next))
+ return visitType(from);
+ else
+ return MATCH.nomatch;
+ }
+ return visitNext(from);
+ }
+
+ MATCH visitFunction(TypeFunction from)
+ {
+ // Attributes need to match exactly, otherwise it's an implicit conversion
+ if (from.ty != to.ty || !from.attributesEqual(cast(TypeFunction) to))
+ return MATCH.nomatch;
+
+ return visitNext(from);
+ }
+
+ MATCH visitStruct(TypeStruct from)
+ {
+ if (from.equals(to))
+ return MATCH.exact;
+ if (from.ty == to.ty && from.sym == (cast(TypeStruct)to).sym && MODimplicitConv(from.mod, to.mod))
+ return MATCH.constant;
+ return MATCH.nomatch;
+ }
+
+ MATCH visitEnum(TypeEnum from)
+ {
+ if (from.equals(to))
+ return MATCH.exact;
+ if (from.ty == to.ty && from.sym == (cast(TypeEnum)to).sym && MODimplicitConv(from.mod, to.mod))
+ return MATCH.constant;
+ return MATCH.nomatch;
+ }
+
+ MATCH visitClass(TypeClass from)
+ {
+ if (from.equals(to))
+ return MATCH.exact;
+ if (from.ty == to.ty && from.sym == (cast(TypeClass)to).sym && MODimplicitConv(from.mod, to.mod))
+ return MATCH.constant;
+
+ /* Conversion derived to const(base)
+ */
+ int offset = 0;
+ if (to.isBaseOf(from, &offset) && offset == 0 && MODimplicitConv(from.mod, to.mod))
+ {
+ // Disallow:
+ // derived to base
+ // inout(derived) to inout(base)
+ if (!to.isMutable() && !to.isWild())
+ return MATCH.convert;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ MATCH visitNoreturn(TypeNoreturn from)
+ {
+ // Either another noreturn or conversion to any type
+ return from.implicitConvTo(to);
+ }
+
+ switch(from.ty)
+ {
+ default: return visitType(from);
+ case Tsarray: return visitSArray(from.isTypeSArray());
+ case Taarray: return visitAArray(from.isTypeAArray());
+ case Treference:
+ case Tdelegate:
+ case Tslice:
+ case Tarray: return visitNext(cast(TypeNext)from);
+ case Tpointer: return visitPointer(from.isTypePointer());
+ case Tfunction: return visitFunction(from.isTypeFunction());
+ case Tstruct: return visitStruct(from.isTypeStruct());
+ case Tenum: return visitEnum(from.isTypeEnum());
+ case Tclass: return visitClass(from.isTypeClass());
+ case Tnoreturn: return visitNoreturn(from.isTypeNoreturn());
+ }
+}
+
+
/******************************************
* Perform semantic analysis on a type.
* Params:
@@ -1292,7 +1673,7 @@ bool hasPointers(Type t)
* `Type` with completed semantic analysis, `Terror` if errors
* were encountered
*/
-Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
+Type typeSemantic(Type type, Loc loc, Scope* sc)
{
static Type error()
{
@@ -1316,7 +1697,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
Type visitComplex(TypeBasic t)
{
- if (!(sc.flags & SCOPE.Cfile))
+ if (!sc.inCfile)
return visitType(t);
auto tc = getComplexLibraryType(loc, sc, t.ty);
@@ -1490,7 +1871,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
default:
break;
}
- if (tbn.isscope())
+ if (tbn.isScopeClass())
{
.error(loc, "cannot have array of scope `%s`", tbn.toChars());
return error();
@@ -1524,7 +1905,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
default:
break;
}
- if (tn.isscope())
+ if (tn.isScopeClass())
{
.error(loc, "cannot have array of scope `%s`", tn.toChars());
return error();
@@ -1644,7 +2025,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
else if (sd.xeq == sd.xerreq)
{
- if (search_function(sd, Id.eq))
+ if (search_function(sd, Id.opEquals))
{
.error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars());
}
@@ -1656,7 +2037,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
else if (!sd.xhash)
{
- if (search_function(sd, Id.eq))
+ if (search_function(sd, Id.opEquals))
{
.error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars());
}
@@ -1686,7 +2067,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
if (!ClassDeclaration.object)
{
- .error(Loc.initial, "missing or corrupt object.d");
+ ObjectNotFound(Loc.initial, cd.ident);
return error();
}
@@ -1694,9 +2075,9 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
__gshared FuncDeclaration fcmp = null;
__gshared FuncDeclaration fhash = null;
if (!feq)
- feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration();
+ feq = search_function(ClassDeclaration.object, Id.opEquals).isFuncDeclaration();
if (!fcmp)
- fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration();
+ fcmp = search_function(ClassDeclaration.object, Id.opCmp).isFuncDeclaration();
if (!fhash)
fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration();
assert(fcmp && feq && fhash);
@@ -1730,7 +2111,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
default:
break;
}
- if (mtype.next.isscope())
+ if (mtype.next.isScopeClass())
{
.error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
return error();
@@ -1830,23 +2211,23 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
if (sc.stc & STC.pure_)
tf.purity = PURE.fwdref;
if (sc.stc & STC.nothrow_)
- tf.isnothrow = true;
+ tf.isNothrow = true;
if (sc.stc & STC.nogc)
- tf.isnogc = true;
+ tf.isNogc = true;
if (sc.stc & STC.ref_)
- tf.isref = true;
+ tf.isRef = true;
if (sc.stc & STC.return_)
- tf.isreturn = true;
+ tf.isReturn = true;
if (sc.stc & STC.returnScope)
- tf.isreturnscope = true;
+ tf.isReturnScope = true;
if (sc.stc & STC.returninferred)
- tf.isreturninferred = true;
+ tf.isReturnInferred = true;
if (sc.stc & STC.scope_)
tf.isScopeQual = true;
if (sc.stc & STC.scopeinferred)
- tf.isscopeinferred = true;
+ tf.isScopeInferred = true;
-// if (tf.isreturn && !tf.isref)
+// if (tf.isReturn && !tf.isRef)
// tf.isScopeQual = true; // return by itself means 'return scope'
if (tf.trust == TRUST.default_)
@@ -1860,9 +2241,9 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
if (sc.stc & STC.property)
- tf.isproperty = true;
+ tf.isProperty = true;
if (sc.stc & STC.live)
- tf.islive = true;
+ tf.isLive = true;
tf.linkage = sc.linkage;
if (tf.linkage == LINK.system)
@@ -1896,7 +2277,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
tf.next = tf.next.typeSemantic(loc, sc);
sc = sc.pop();
errors |= tf.checkRetType(loc);
- if (tf.next.isscope() && !tf.isctor)
+ if (tf.next.isScopeClass() && !tf.isCtor)
{
.error(loc, "functions cannot return `scope %s`", tf.next.toChars());
errors = true;
@@ -1904,9 +2285,9 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
if (tf.next.hasWild())
wildreturn = true;
- if (tf.isreturn && !tf.isref && !tf.next.hasPointers())
+ if (tf.isReturn && !tf.isRef && !tf.next.hasPointers())
{
- tf.isreturn = false;
+ tf.isReturn = false;
}
}
@@ -1948,14 +2329,13 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
{
const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
.error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
- e.toChars(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
+ e.toErrMsg(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
}
e = e.implicitCastTo(sc, fparam.type);
// default arg must be an lvalue
if (isRefOrOut && !isAuto &&
- !(fparam.storageClass & STC.constscoperef) &&
- global.params.rvalueRefParam != FeatureState.enabled)
+ !(fparam.storageClass & STC.constscoperef) && !sc.previews.rvalueRefParam)
e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from");
fparam.defaultArg = e;
@@ -1968,7 +2348,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
/* Create a scope for evaluating the default arguments for the parameters
*/
Scope* argsc = sc.push();
- argsc.stc = 0; // don't inherit storage class
+ argsc.stc = STC.none; // don't inherit storage class
argsc.visibility = Visibility(Visibility.Kind.public_);
argsc.func = null;
@@ -2024,12 +2404,12 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
// https://issues.dlang.org/show_bug.cgi?id=12744
// If the storage classes of narg
// conflict with the ones in fparam, it's ignored.
- StorageClass stc = fparam.storageClass | narg.storageClass;
- StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
- StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
+ STC stc = fparam.storageClass | narg.storageClass;
+ STC stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
+ STC stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
if (stc1 && stc2 && stc1 != stc2)
{
- OutBuffer buf1; stcToBuffer(buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0));
+ OutBuffer buf1; stcToBuffer(buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : STC.none));
OutBuffer buf2; stcToBuffer(buf2, stc2);
.error(loc, "incompatible parameter storage classes `%s` and `%s`",
@@ -2113,10 +2493,17 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
errors = true;
}
- const bool isTypesafeVariadic = i + 1 == dim &&
- tf.parameterList.varargs == VarArg.typesafe &&
- (t.isTypeDArray() || t.isTypeClass());
- if (isTypesafeVariadic)
+ const bool isTypesafeVariadic = i + 1 == dim && tf.parameterList.varargs == VarArg.typesafe;
+ const bool isStackAllocatedVariadic = isTypesafeVariadic && (t.isTypeDArray() || t.isTypeClass());
+
+ if (isTypesafeVariadic && t.isTypeClass())
+ {
+ // Deprecated in 2.111, kept as a legacy feature for compatibility (currently no plan to turn it into an error)
+ .deprecation(loc, "typesafe variadic parameters with a `class` type (`%s %s...`) are deprecated",
+ t.isTypeClass().sym.ident.toChars(), fparam.toChars());
+ }
+
+ if (isStackAllocatedVariadic)
{
/* typesafe variadic arguments are constructed on the stack, so must be `scope`
*/
@@ -2129,7 +2516,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
{
if (!(fparam.storageClass & STC.scope_))
fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
- if (tf.isref)
+ if (tf.isRef)
{
}
else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid)
@@ -2138,7 +2525,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
}
- if (isTypesafeVariadic)
+ if (isStackAllocatedVariadic)
{
/* This is because they can be constructed on the stack
* https://dlang.org/spec/function.html#typesafe_variadic_functions
@@ -2287,14 +2674,14 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
tf.isInOutParam = (wildparams & 1) != 0;
tf.isInOutQual = (wildparams & 2) != 0;
- if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
+ if (tf.isProperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
{
.error(loc, "properties can only have zero, one, or two parameter");
errors = true;
}
if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
- !(sc.flags & SCOPE.Cfile))
+ !sc.inCfile)
{
.error(loc, "variadic functions with non-D linkage must have at least one parameter");
errors = true;
@@ -2356,53 +2743,49 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
//printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
return t.addMod(mtype.mod);
}
- else
- {
- if (s)
- {
- auto td = s.isTemplateDeclaration;
- if (td && td.onemember && td.onemember.isAggregateDeclaration)
- .error(loc, "template %s `%s` is used as a type without instantiation"
- ~ "; to instantiate it use `%s!(arguments)`",
- s.kind, s.toPrettyChars, s.ident.toChars);
- else
- .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
- //assert(0);
- }
- else if (e.op == EXP.variable) // special case: variable is used as a type
- {
- /*
- N.B. This branch currently triggers for the following code
- template test(x* x)
- {
- }
- i.e. the compiler prints "variable x is used as a type"
- which isn't a particularly good error message (x is a variable?).
- */
- Dsymbol varDecl = mtype.toDsymbol(sc);
- const(Loc) varDeclLoc = varDecl.getLoc();
- Module varDeclModule = varDecl.getModule(); //This can be null
-
- .error(loc, "variable `%s` is used as a type", mtype.toChars());
- //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
- if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
+ if (s)
+ {
+ auto td = s.isTemplateDeclaration;
+ if (td && td.onemember && td.onemember.isAggregateDeclaration)
+ .error(loc, "template %s `%s` is used as a type without instantiation"
+ ~ "; to instantiate it use `%s!(arguments)`",
+ s.kind, s.toPrettyChars, s.ident.toChars);
+ else
+ .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
+ //assert(0);
+ }
+ else if (e.op == EXP.variable) // special case: variable is used as a type
+ {
+ /*
+ N.B. This branch currently triggers for the following code
+ template test(x* x)
{
- const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
- .errorSupplemental(
- varDeclModuleImportLoc,
- "variable `%s` is imported here from: `%s`",
- varDecl.toChars,
- varDeclModule.toPrettyChars,
- );
+
}
+ i.e. the compiler prints "variable x is used as a type"
+ which isn't a particularly good error message (x is a variable?).
+ */
+ Dsymbol varDecl = mtype.toDsymbol(sc);
+ Module varDeclModule = varDecl.getModule(); //This can be null
- .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
+ .error(loc, "variable `%s` is used as a type", mtype.toChars());
+ //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
+ if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
+ {
+ .errorSupplemental(
+ varDeclModule.loc,
+ "variable `%s` is imported here from: `%s`",
+ varDecl.toChars,
+ varDeclModule.toPrettyChars,
+ );
}
- else
- .error(loc, "`%s` is used as a type", mtype.toChars());
- return error();
+
+ .errorSupplemental(varDecl.loc, "variable `%s` is declared here", varDecl.toChars);
}
+ else
+ .error(loc, "`%s` is used as a type", mtype.toChars());
+ return error();
}
Type visitInstance(TypeInstance mtype)
@@ -2602,8 +2985,14 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
Type visitTag(TypeTag mtype)
{
//printf("TypeTag.semantic() %s\n", mtype.toChars());
- Type returnType(Type t)
- {
+ Type returnType(TypeTag tt)
+ {
+ Type t = tt.resolved;
+ // To make const checking work, the const STC needs to be added:
+ // t = t.resolved.addSTC(mtype.mod.ModToStc);
+ // However, this currently fails compilable/test22875.i
+ // Apparently there's some aliasing going on, where mutable
+ // versions of the type also get const applied to them.
return t.deco ? t : t.merge();
}
@@ -2611,7 +3000,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
{
/* struct S s, *p;
*/
- return returnType(mtype.resolved.addSTC(mtype.mod));
+ return returnType(mtype);
}
/* Find the current scope by skipping tag scopes.
@@ -2684,7 +3073,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
{
mtype.id = Identifier.generateId("__tag"[]);
declareTag();
- return returnType(mtype.resolved.addSTC(mtype.mod));
+ return returnType(mtype);
}
/* look for pre-existing declaration
@@ -2697,7 +3086,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
if (mtype.tok == TOK.enum_ && !mtype.members)
.error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
declareTag();
- return returnType(mtype.resolved.addSTC(mtype.mod));
+ return returnType(mtype);
}
/* A redeclaration only happens if both declarations are in
@@ -2752,7 +3141,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
else
{
/* struct S { int a; };
- * struct S *s;
+ * struct S* s;
*/
}
mtype.resolved = sd.type;
@@ -2783,21 +3172,21 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
mtype.tok == TOK.struct_ && s.isStructDeclaration())
{
/* struct S;
- * { struct S *s; }
+ * { struct S* s; }
*/
mtype.resolved = s.isStructDeclaration().type;
}
else
{
/* union S;
- * { struct S *s; }
+ * { struct S* s; }
*/
.error(mtype.loc, "redeclaring `%s %s` as `%s %s`",
s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars());
declareTag();
}
}
- return returnType(mtype.resolved.addSTC(mtype.mod));
+ return returnType(mtype);
}
switch (type.ty)
@@ -2829,7 +3218,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
}
-Type trySemantic(Type type, const ref Loc loc, Scope* sc)
+Type trySemantic(Type type, Loc loc, Scope* sc)
{
//printf("+trySemantic(%s) %d\n", toChars(), global.errors);
@@ -2877,9 +3266,19 @@ Type merge(Type type)
case Tsarray:
// prevents generating the mangle if the array dim is not yet known
- if (!type.isTypeSArray().dim.isIntegerExp())
- return type;
- goto default;
+ if (auto ie = type.isTypeSArray().dim.isIntegerExp())
+ {
+ // After TypeSemantic, the length is always converted to size_t, but the parser
+ // usually generates regular integer types (e.g. in cast(const ubyte[2])) which
+ // it may try to merge, which then leads to failing implicit conversions as 2LU != 2
+ // according to Expression.equals. Only merge array types with size_t lengths for now.
+ // https://github.com/dlang/dmd/issues/21179
+ if (ie.type != Type.tsize_t)
+ return type;
+
+ goto default;
+ }
+ return type;
case Tenum:
break;
@@ -2896,37 +3295,36 @@ Type merge(Type type)
}
//printf("merge(%s)\n", toChars());
- if (!type.deco)
- {
- OutBuffer buf;
- buf.reserve(32);
+ if (type.deco)
+ return type;
- mangleToBuffer(type, buf);
+ OutBuffer buf;
+ buf.reserve(32);
- auto sv = type.stringtable.update(buf[]);
- if (sv.value)
- {
- Type t = sv.value;
- debug
- {
- import core.stdc.stdio;
- if (!t.deco)
- printf("t = %s\n", t.toChars());
- }
- assert(t.deco);
- //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
- return t;
- }
- else
+ mangleToBuffer(type, buf);
+
+ auto sv = type.stringtable.update(buf[]);
+ if (sv.value)
+ {
+ Type t = sv.value;
+ debug
{
- Type t = stripDefaultArgs(type);
- sv.value = t;
- type.deco = t.deco = cast(char*)sv.toDchars();
- //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
- return t;
+ import core.stdc.stdio;
+ if (!t.deco)
+ printf("t = %s\n", t.toChars());
}
+ assert(t.deco);
+ //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
+ return t;
+ }
+ else
+ {
+ Type t = stripDefaultArgs(type);
+ sv.value = t;
+ type.deco = t.deco = cast(char*)sv.toDchars();
+ //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
+ return t;
}
- return type;
}
/*************************************
@@ -2965,7 +3363,7 @@ Type merge2(Type type)
* Returns:
* expression representing the property, or null if not a property and (flag & 1)
*/
-Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag,
+Expression getProperty(Type t, Scope* scope_, Loc loc, Identifier ident, int flag,
Expression src = null)
{
Expression visitType(Type mt)
@@ -2980,14 +3378,14 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
const sz = mt.size(loc);
if (sz == SIZE_INVALID)
return ErrorExp.get();
- e = new IntegerExp(loc, sz, Type.tsize_t);
+ return new IntegerExp(loc, sz, Type.tsize_t);
}
else if (ident == Id.__xalignof)
{
const explicitAlignment = mt.alignment();
const naturalAlignment = mt.alignsize();
const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
- e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
+ return new IntegerExp(loc, actualAlignment, Type.tsize_t);
}
else if (ident == Id._init)
{
@@ -2997,13 +3395,14 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
{
e.isStructLiteralExp().useStaticInit = true;
}
+ return e;
}
else if (ident == Id._mangleof)
{
if (!mt.deco)
{
error(loc, "forward reference of type `%s.mangleof`", mt.toChars());
- e = ErrorExp.get();
+ return ErrorExp.get();
}
else
{
@@ -3012,6 +3411,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
sc.eSink = global.errorSink;
e = e.expressionSemantic(&sc);
}
+ return e;
}
else if (ident == Id.stringof)
{
@@ -3020,53 +3420,98 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
Scope sc;
sc.eSink = global.errorSink;
e = e.expressionSemantic(&sc);
+ return e;
}
else if (flag && mt != Type.terror)
{
return null;
}
+
+ Dsymbol s = null;
+ if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
+ s = mt.toDsymbol(null);
+ if (s)
+ s = s.search_correct(ident);
+ if (s && !symbolIsVisible(scope_, s))
+ s = null;
+
+ if (mt == Type.terror)
+ return ErrorExp.get();
+
+ if (s)
+ error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
+ else if (ident == Id.opCall && mt.ty == Tclass)
+ error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
+
+ else if (const n = importHint(ident.toString()))
+ error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
else
{
- Dsymbol s = null;
- if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
- s = mt.toDsymbol(null);
- if (s)
- s = s.search_correct(ident);
- if (s && !symbolIsVisible(scope_, s))
- s = null;
- if (mt != Type.terror)
- {
- if (s)
- error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
- else if (ident == Id.call && mt.ty == Tclass)
- error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
-
- else if (const n = importHint(ident.toString()))
- error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
- else
+ if (src)
+ {
+ error(loc, "no property `%s` for `%s` of type `%s`",
+ ident.toChars(), src.toChars(), mt.toPrettyChars(true));
+ auto s2 = scope_.search_correct(ident);
+ // UFCS
+ if (s2 && s2.isFuncDeclaration)
{
- if (src)
- error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true));
+ if (s2.ident == ident)
+ {
+ errorSupplemental(s2.loc, "cannot call %s `%s` with UFCS because it is not declared at module scope",
+ s2.kind(), s2.toChars());
+ }
else
- error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
+ errorSupplemental(s2.loc, "did you mean %s `%s`?",
+ s2.kind(), s2.toChars());
+ }
+ else if (src.type.ty == Tpointer)
+ {
+ // structPtr.field
+ auto tn = (cast(TypeNext) src.type).nextOf();
+ if (auto as = tn.isAggregate())
+ {
+ if (auto s3 = as.search_correct(ident))
+ {
+ errorSupplemental(s3.loc, "did you mean %s `%s`?",
+ s3.kind(), s3.toChars());
+ }
+ }
+ }
+ }
+ else
+ error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
- if (auto dsym = mt.toDsymbol(scope_))
+ if (auto dsym = mt.toDsymbol(scope_))
+ {
+ if (auto sym = dsym.isAggregateDeclaration())
+ {
+ if (!sym.members)
{
- if (auto sym = dsym.isAggregateDeclaration())
+ errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
+ return ErrorExp.get();
+ }
+
+ if (auto fd = search_function(sym, Id.opDispatch))
+ {
+ if (auto td = fd.isTemplateDeclaration())
{
- if (auto fd = search_function(sym, Id.opDispatch))
- errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
- else if (!sym.members)
- errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
+ e = mt.defaultInitLiteral(loc);
+ auto se = new StringExp(e.loc, ident.toString());
+ auto tiargs = new Objects();
+ tiargs.push(se);
+ auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs);
+ dti.ti.tempdecl = td;
+ dti.dotTemplateSemanticProp(scope_, DotExpFlag.none);
+ return ErrorExp.get();
}
- errorSupplemental(dsym.loc, "%s `%s` defined here",
- dsym.kind, dsym.toChars());
}
}
+ errorSupplemental(dsym.loc, "%s `%s` defined here",
+ dsym.kind, dsym.toChars());
}
- e = ErrorExp.get();
}
- return e;
+
+ return ErrorExp.get();
}
Expression visitError(TypeError)
@@ -3088,7 +3533,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
Expression floatValue(real_t r)
{
- if (mt.isreal() || mt.isimaginary())
+ if (mt.isReal() || mt.isImaginary())
return new RealExp(loc, r, mt);
else
{
@@ -3427,7 +3872,7 @@ private void resolveExp(Expression exp, out Type t, out Expression e, out Dsymbo
* ps = is set if t is a symbol
* intypeid = true if in type id
*/
-void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
+void resolve(Type mt, Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
{
void returnExp(Expression e)
{
@@ -3734,7 +4179,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
// compile time sequences are valid types
!mt.exp.type.isTypeTuple())
{
- if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof
+ if (!sc.inCfile && // in (extended) C typeof may be used on types as with sizeof
mt.exp.checkType())
goto Lerr;
@@ -4063,6 +4508,10 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
*/
Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag)
{
+ enum LOGDOTEXP = false;
+ if (LOGDOTEXP)
+ printf("dotExp()\n");
+
Expression visitType(Type mt)
{
VarDeclaration v = null;
@@ -4083,7 +4532,9 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
}
if (v)
{
- if (ident == Id.offsetof)
+ if (ident == Id.offsetof ||
+ ident == Id.bitoffsetof ||
+ ident == Id.bitwidth)
{
v.dsymbolSemantic(null);
if (v.isField())
@@ -4093,7 +4544,20 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
ad.size(e.loc);
if (ad.sizeok != Sizeok.done)
return ErrorExp.get();
- return new IntegerExp(e.loc, v.offset, Type.tsize_t);
+ uint value;
+ if (ident == Id.offsetof)
+ value = v.offset;
+ else // Id.bitoffsetof || Id.bitwidth
+ {
+ auto bf = v.isBitFieldDeclaration();
+ if (bf)
+ {
+ value = ident == Id.bitoffsetof ? bf.bitOffset : bf.fieldWidth;
+ }
+ else
+ error(v.loc, "`%s` is not a bitfield, cannot apply `%s`", v.toChars(), ident.toChars());
+ }
+ return new IntegerExp(e.loc, value, Type.tsize_t);
}
}
else if (ident == Id._init)
@@ -4314,7 +4778,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
{
if (e.op == EXP.type)
{
- error(e.loc, "`%s` is not an expression", e.toChars());
+ error(e.loc, "`%s` is not an expression", e.toErrMsg());
return ErrorExp.get();
}
else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
@@ -4363,7 +4827,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
}
if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
{
- error(e.loc, "`%s` is not an expression", e.toChars());
+ error(e.loc, "`%s` is not an expression", e.toErrMsg());
return ErrorExp.get();
}
if (ident == Id.length)
@@ -4413,8 +4877,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen);
TypeFunction tf = fd_aaLen.type.toTypeFunction();
tf.purity = PURE.const_;
- tf.isnothrow = true;
- tf.isnogc = false;
+ tf.isNothrow = true;
+ tf.isNogc = false;
}
Expression ev = new VarExp(e.loc, fd_aaLen, false);
e = new CallExp(e.loc, ev, e);
@@ -4466,7 +4930,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
/***************************************
* `ident` was not found as a member of `mt`.
- * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
+ * Attempt to use overloaded opDispatch() or `alias this`.
* If that fails, forward to visitType().
* Params:
* mt = class or struct
@@ -4512,6 +4976,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
ident != Id._mangleof &&
ident != Id.stringof &&
ident != Id.offsetof &&
+ ident != Id.bitoffsetof &&
+ ident != Id.bitwidth &&
// https://issues.dlang.org/show_bug.cgi?id=15045
// Don't forward special built-in member functions.
ident != Id.ctor &&
@@ -4520,21 +4986,6 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
ident != Id.postblit &&
ident != Id.__xpostblit)
{
- /* Look for overloaded opDot() to see if we should forward request
- * to it.
- */
- if (auto fd = search_function(sym, Id.opDot))
- {
- /* Rewrite e.ident as:
- * e.opDot().ident
- */
- e = build_overload(e.loc, sc, e, null, fd);
- // @@@DEPRECATED_2.110@@@.
- // Deprecated in 2.082, made an error in 2.100.
- error(e.loc, "`opDot` is obsolete. Use `alias this`");
- return ErrorExp.get();
- }
-
/* Look for overloaded opDispatch to see if we should forward request
* to it.
*/
@@ -4558,7 +5009,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
* e.g.
* template opDispatch(name) if (isValid!name) { ... }
*/
- uint errors = gagError ? global.startGagging() : 0;
+ const errors = gagError ? global.startGagging() : 0;
e = dti.dotTemplateSemanticProp(sc, DotExpFlag.none);
if (gagError && global.endGagging(errors))
e = null;
@@ -4576,7 +5027,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
*/
auto die = new DotIdExp(e.loc, alias_e, ident);
- auto errors = gagError ? 0 : global.startGagging();
+ const errors = gagError ? 0 : global.startGagging();
auto exp = die.dotIdSemanticProp(sc, gagError);
if (!gagError)
{
@@ -4606,7 +5057,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
assert(e.op != EXP.dot);
// https://issues.dlang.org/show_bug.cgi?id=14010
- if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
+ if (!sc.inCfile && ident == Id._mangleof)
{
return mt.getProperty(sc, e.loc, ident, flag & 1);
}
@@ -4618,7 +5069,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
/* Create a TupleExp out of the fields of the struct e:
* (e.field0, e.field1, e.field2, ...)
*/
- e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
+ e = e.expressionSemantic(sc); // do this before turning on noAccessCheck
if (!mt.sym.determineFields())
{
@@ -4648,26 +5099,59 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
e = new TupleExp(e.loc, e0, exps);
Scope* sc2 = sc.push();
- sc2.flags |= SCOPE.noaccesscheck;
+ sc2.noAccessCheck = true;
e = e.expressionSemantic(sc2);
sc2.pop();
return e;
}
- immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
+ immutable flags = sc.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
L1:
if (!s)
{
return noMember(mt, sc, e, ident, flag);
}
- if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
+ if (!sc.ignoresymbolvisibility && !symbolIsVisible(sc, s))
{
return noMember(mt, sc, e, ident, flag);
}
// check before alias resolution; the alias itself might be deprecated!
- if (s.isAliasDeclaration)
+ if (auto ad = s.isAliasDeclaration)
+ {
s.checkDeprecated(e.loc, sc);
+
+ // Fix for https://github.com/dlang/dmd/issues/20610
+ if (ad.originalType)
+ {
+ if (auto tid = ad.originalType.isTypeIdentifier())
+ {
+ if (tid.idents.length)
+ {
+ static if (0)
+ {
+ printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ printf("AliasDeclaration: %s\n", ad.toChars());
+ if (ad.aliassym)
+ printf("aliassym: %s\n", ad.aliassym.toChars());
+ printf("tid type: %s\n", toChars(tid));
+ }
+ /* Rewrite e.s as e.(tid.ident).(tid.idents)
+ */
+ Expression die = new DotIdExp(e.loc, e, tid.ident);
+ foreach (id; tid.idents) // maybe use typeToExpressionHelper()
+ die = new DotIdExp(e.loc, die, cast(Identifier)id);
+ /* Ambiguous syntax, only way to disambiguate it to try it
+ */
+ die = dmd.expressionsem.trySemantic(die, sc);
+ if (die && die.isDotVarExp()) // shrink wrap around DotVarExp()
+ {
+ return die;
+ }
+ }
+ }
+ }
+ }
s = s.toAlias();
if (auto em = s.isEnumMember())
@@ -4770,7 +5254,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
Declaration d = s.isDeclaration();
if (!d)
{
- error(e.loc, "`%s.%s` is not a declaration", e.toChars(), ident.toChars());
+ error(e.loc, "`%s.%s` is not a declaration", e.toErrMsg(), ident.toChars());
return ErrorExp.get();
}
@@ -4898,7 +5382,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
/* Create a TupleExp
*/
- e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
+ e = e.expressionSemantic(sc); // do this before turning on noAccessCheck
mt.sym.size(e.loc); // do semantic of type
@@ -4928,13 +5412,13 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
e = new TupleExp(e.loc, e0, exps);
Scope* sc2 = sc.push();
- sc2.flags |= SCOPE.noaccesscheck;
+ sc2.noAccessCheck = true;
e = e.expressionSemantic(sc2);
sc2.pop();
return e;
}
- SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
+ SearchOptFlags flags = sc.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
L1:
@@ -5087,7 +5571,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
return noMember(mt, sc, e, ident, flag & 1);
}
- if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
+ if (!sc.ignoresymbolvisibility && !symbolIsVisible(sc, s))
{
return noMember(mt, sc, e, ident, flag);
}
@@ -5203,7 +5687,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
Declaration d = s.isDeclaration();
if (!d)
{
- error(e.loc, "`%s.%s` is not a declaration", e.toChars(), ident.toChars());
+ error(e.loc, "`%s.%s` is not a declaration", e.toErrMsg(), ident.toChars());
return ErrorExp.get();
}
@@ -5362,6 +5846,74 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
}
}
+// if initializer is 0
+bool isZeroInit(Type t, Loc loc)
+{
+ bool visitType(Type _)
+ {
+ return false; // assume not
+ }
+
+ bool visitBasic(TypeBasic t)
+ {
+ switch (t.ty)
+ {
+ case Tchar:
+ case Twchar:
+ case Tdchar:
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ return false; // no
+ default:
+ return true; // yes
+ }
+ }
+
+ bool visitVector(TypeVector t)
+ {
+ return t.basetype.isZeroInit(loc);
+ }
+
+ bool visitSArray(TypeSArray t)
+ {
+ return t.next.isZeroInit(loc);
+ }
+
+ bool visitStruct(TypeStruct t)
+ {
+ // Determine zeroInit here, as this can be called before semantic2
+ t.sym.determineSize(t.sym.loc);
+ return t.sym.zeroInit;
+ }
+
+ bool visitEnum(TypeEnum t)
+ {
+ return t.sym.getDefaultValue(loc).toBool().hasValue(false);
+ }
+
+ switch(t.ty)
+ {
+ default: return t.isTypeBasic() ? visitBasic(cast(TypeBasic)t) : visitType(t);
+ case Tvector: return visitVector(t.isTypeVector());
+ case Tsarray: return visitSArray(t.isTypeSArray());
+ case Taarray:
+ case Tarray:
+ case Treference:
+ case Tdelegate:
+ case Tclass:
+ case Tpointer: return true;
+ case Tstruct: return visitStruct(t.isTypeStruct());
+ case Tenum: return visitEnum(t.isTypeEnum());
+ }
+}
+
/************************
* Get the default initialization expression for a type.
@@ -5373,7 +5925,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
* Returns:
* The initialization expression for the type.
*/
-Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
+Expression defaultInit(Type mt, Loc loc, const bool isCfile = false)
{
Expression visitBasic(TypeBasic mt)
{
@@ -5590,7 +6142,7 @@ Dsymbol toDsymbol(Type type, Scope* sc)
Dsymbol visitIdentifier(TypeIdentifier type)
{
- //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
+ //printf("TypeIdentifier::toDsymbol('%s')\n", toChars(type));
if (!sc)
return null;
@@ -5602,7 +6154,6 @@ Dsymbol toDsymbol(Type type, Scope* sc)
s = t.toDsymbol(sc);
if (e)
s = getDsymbol(e);
-
return s;
}
@@ -5655,7 +6206,7 @@ Dsymbol toDsymbol(Type type, Scope* sc)
/************************************
* Add storage class modifiers to type.
*/
-Type addStorageClass(Type type, StorageClass stc)
+Type addStorageClass(Type type, STC stc)
{
Type visitType(Type t)
{
@@ -5681,43 +6232,43 @@ Type addStorageClass(Type type, StorageClass stc)
//printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
TypeFunction t = visitType(tf_src).toTypeFunction();
if ((stc & STC.pure_ && !t.purity) ||
- (stc & STC.nothrow_ && !t.isnothrow) ||
- (stc & STC.nogc && !t.isnogc) ||
+ (stc & STC.nothrow_ && !t.isNothrow) ||
+ (stc & STC.nogc && !t.isNogc) ||
(stc & STC.scope_ && !t.isScopeQual) ||
(stc & STC.safe && t.trust < TRUST.trusted))
{
// Klunky to change these
- auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0);
+ auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, STC.none);
tf.mod = t.mod;
tf.inferenceArguments = tf_src.inferenceArguments;
tf.purity = t.purity;
- tf.isnothrow = t.isnothrow;
- tf.isnogc = t.isnogc;
- tf.isproperty = t.isproperty;
- tf.isref = t.isref;
- tf.isreturn = t.isreturn;
- tf.isreturnscope = t.isreturnscope;
+ tf.isNothrow = t.isNothrow;
+ tf.isNogc = t.isNogc;
+ tf.isProperty = t.isProperty;
+ tf.isRef = t.isRef;
+ tf.isReturn = t.isReturn;
+ tf.isReturnScope = t.isReturnScope;
tf.isScopeQual = t.isScopeQual;
- tf.isreturninferred = t.isreturninferred;
- tf.isscopeinferred = t.isscopeinferred;
+ tf.isReturnInferred = t.isReturnInferred;
+ tf.isScopeInferred = t.isScopeInferred;
tf.trust = t.trust;
tf.isInOutParam = t.isInOutParam;
tf.isInOutQual = t.isInOutQual;
- tf.isctor = t.isctor;
+ tf.isCtor = t.isCtor;
if (stc & STC.pure_)
tf.purity = PURE.fwdref;
if (stc & STC.nothrow_)
- tf.isnothrow = true;
+ tf.isNothrow = true;
if (stc & STC.nogc)
- tf.isnogc = true;
+ tf.isNogc = true;
if (stc & STC.safe)
tf.trust = TRUST.safe;
if (stc & STC.scope_)
{
tf.isScopeQual = true;
if (stc & STC.scopeinferred)
- tf.isscopeinferred = true;
+ tf.isScopeInferred = true;
}
tf.deco = tf.merge().deco;
@@ -5750,7 +6301,7 @@ Type addStorageClass(Type type, StorageClass stc)
* Complex!float, Complex!double, Complex!real or null for error
*/
-Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
+Type getComplexLibraryType(Loc loc, Scope* sc, TY ty)
{
// singleton
__gshared Type complex_float;
@@ -5818,7 +6369,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
* Returns:
* An enum value of either `Covariant.yes` or a reason it's not covariant.
*/
-Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
+Covariant covariant(Type src, Type t, STC* pstc = null, bool cppCovariant = false)
{
version (none)
{
@@ -5828,8 +6379,8 @@ Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovaria
printf("mod = %x, %x\n", src.mod, t.mod);
}
if (pstc)
- *pstc = 0;
- StorageClass stc = 0;
+ *pstc = STC.none;
+ STC stc = STC.none;
bool notcovariant = false;
@@ -5889,7 +6440,7 @@ Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovaria
goto Ldistinct;
}
Lcov:
- notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
+ notcovariant |= !fparam1.isCovariant(t1.isRef, fparam2);
/* https://issues.dlang.org/show_bug.cgi?id=23135
* extern(C++) mutable parameters are not covariant with const.
@@ -5949,7 +6500,7 @@ Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovaria
}
else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
{
- if (t1.isref && t2.isref)
+ if (t1.isRef && t2.isRef)
{
// Treat like pointers to t1n and t2n
if (t1n.constConv(t2n) < MATCH.constant)
@@ -5974,31 +6525,31 @@ Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovaria
goto Lnotcovariant;
Lcovariant:
- if (t1.isref != t2.isref)
+ if (t1.isRef != t2.isRef)
goto Lnotcovariant;
- if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
+ if (!t1.isRef && (t1.isScopeQual || t2.isScopeQual))
{
- StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
- StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
- if (t1.isreturn)
+ STC stc1 = t1.isScopeQual ? STC.scope_ : STC.none;
+ STC stc2 = t2.isScopeQual ? STC.scope_ : STC.none;
+ if (t1.isReturn)
{
stc1 |= STC.return_;
if (!t1.isScopeQual)
stc1 |= STC.ref_;
}
- if (t2.isreturn)
+ if (t2.isReturn)
{
stc2 |= STC.return_;
if (!t2.isScopeQual)
stc2 |= STC.ref_;
}
- if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
+ if (!Parameter.isCovariantScope(t1.isRef, stc1, stc2))
goto Lnotcovariant;
}
// We can subtract 'return ref' from 'this', but cannot add it
- else if (t1.isreturn && !t2.isreturn)
+ else if (t1.isReturn && !t2.isReturn)
goto Lnotcovariant;
/* https://issues.dlang.org/show_bug.cgi?id=23135
@@ -6031,10 +6582,10 @@ Lcovariant:
if (!t1.purity && t2.purity)
stc |= STC.pure_;
- if (!t1.isnothrow && t2.isnothrow)
+ if (!t1.isNothrow && t2.isNothrow)
stc |= STC.nothrow_;
- if (!t1.isnogc && t2.isnogc)
+ if (!t1.isNogc && t2.isNogc)
stc |= STC.nogc;
/* Can convert safe/trusted to system
@@ -6078,7 +6629,7 @@ Lnotcovariant:
* Returns:
* storage class with STC.scope_ or STC.return_ OR'd in
*/
-StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null,
+STC parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null,
bool indirect = false)
{
//printf("parameterStorageClass(p: %s)\n", p.toChars());
@@ -6093,7 +6644,7 @@ StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, Var
/* If haven't inferred the return type yet, can't infer storage classes
*/
- if (!tf.nextOf() || !tf.isnothrow())
+ if (!tf.nextOf() || !tf.isNothrow())
return stc;
tf.purityLevel();
@@ -6173,7 +6724,7 @@ StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, Var
// Check escaping through return value
Type tret = tf.nextOf().toBasetype();
- if (tf.isref || tret.hasPointers())
+ if (tf.isRef || tret.hasPointers())
{
return stc | STC.scope_ | STC.return_ | STC.returnScope;
}
@@ -6211,30 +6762,32 @@ Type pointerTo(Type type)
{
if (type.ty == Terror)
return type;
- if (!type.pto)
+ auto mcache = type.getMcache();
+ if (!mcache.pto)
{
Type t = new TypePointer(type);
if (type.ty == Tfunction)
{
t.deco = t.merge().deco;
- type.pto = t;
+ mcache.pto = t;
}
else
- type.pto = t.merge();
+ mcache.pto = t.merge();
}
- return type.pto;
+ return mcache.pto;
}
Type referenceTo(Type type)
{
if (type.ty == Terror)
return type;
- if (!type.rto)
+ auto mcache = type.getMcache();
+ if (!mcache.rto)
{
Type t = new TypeReference(type);
- type.rto = t.merge();
+ mcache.rto = t.merge();
}
- return type.rto;
+ return mcache.rto;
}
// Make corresponding static array type without semantic
@@ -6252,12 +6805,13 @@ Type arrayOf(Type type)
{
if (type.ty == Terror)
return type;
- if (!type.arrayof)
+ auto mcache = type.getMcache();
+ if (!mcache.arrayof)
{
Type t = new TypeDArray(type);
- type.arrayof = t.merge();
+ mcache.arrayof = t.merge();
}
- return type.arrayof;
+ return mcache.arrayof;
}
/********************************
@@ -6509,6 +7063,39 @@ Type sharedWildConstOf(Type type)
return t;
}
+Type nakedOf(Type type)
+{
+ //printf("Type::nakedOf() %p, %s\n", type, type.toChars());
+ if (type.mod == 0)
+ return type;
+ if (type.mcache) with(type.mcache)
+ {
+ // the cache has the naked type at the "identity" position, try to find it
+ if (cto && cto.mod == 0)
+ return cto;
+ if (ito && ito.mod == 0)
+ return ito;
+ if (sto && sto.mod == 0)
+ return sto;
+ if (scto && scto.mod == 0)
+ return scto;
+ if (wto && wto.mod == 0)
+ return wto;
+ if (wcto && wcto.mod == 0)
+ return wcto;
+ if (swto && swto.mod == 0)
+ return swto;
+ if (swcto && swcto.mod == 0)
+ return swcto;
+ }
+ Type t = type.nullAttributes();
+ t.mod = 0;
+ t = t.merge();
+ t.fixTo(type);
+ //printf("\t%p %s\n", t, t.toChars());
+ return t;
+}
+
Type unqualify(Type type, uint m)
{
Type t = type.mutableOf().unSharedOf();
@@ -6687,7 +7274,7 @@ Type substWildTo(Type type, uint mod)
t = new TypeSArray(t, (cast(TypeSArray)type).dim.syntaxCopy());
else if (type.ty == Taarray)
{
- t = new TypeAArray(t, (cast(TypeAArray)type).index.syntaxCopy());
+ t = new TypeAArray(t, (cast(TypeAArray)type).index.substWildTo(mod));
}
else if (type.ty == Tdelegate)
{
@@ -6770,21 +7357,21 @@ Type substWildTo(Type type, uint mod)
// Similar to TypeFunction.syntaxCopy;
auto t = new TypeFunction(ParameterList(params, tf.parameterList.varargs), tret, tf.linkage);
t.mod = ((tf.mod & MODFlags.wild) ? (tf.mod & ~MODFlags.wild) | MODFlags.const_ : tf.mod);
- t.isnothrow = tf.isnothrow;
- t.isnogc = tf.isnogc;
+ t.isNothrow = tf.isNothrow;
+ t.isNogc = tf.isNogc;
t.purity = tf.purity;
- t.isproperty = tf.isproperty;
- t.isref = tf.isref;
- t.isreturn = tf.isreturn;
- t.isreturnscope = tf.isreturnscope;
+ t.isProperty = tf.isProperty;
+ t.isRef = tf.isRef;
+ t.isReturn = tf.isReturn;
+ t.isReturnScope = tf.isReturnScope;
t.isScopeQual = tf.isScopeQual;
- t.isreturninferred = tf.isreturninferred;
- t.isscopeinferred = tf.isscopeinferred;
+ t.isReturnInferred = tf.isReturnInferred;
+ t.isScopeInferred = tf.isScopeInferred;
t.isInOutParam = false;
t.isInOutQual = false;
t.trust = tf.trust;
t.inferenceArguments = tf.inferenceArguments;
- t.isctor = tf.isctor;
+ t.isCtor = tf.isCtor;
return t.merge();
}
@@ -6951,11 +7538,173 @@ bool isRecursiveAliasThis(ref Type att, Type t)
auto tb = t.toBasetype();
if (att && tb.equivalent(att))
return true;
- else if (!att && tb.checkAliasThisRec())
+ if (!att && tb.checkAliasThisRec())
att = tb;
return false;
}
+MATCH implicitConvToWithoutAliasThis(TypeStruct from, Type to)
+{
+ //printf("TypeStruct::implicitConvToWithoutAliasThis(%s => %s)\n", toChars(), to.toChars());
+
+ auto tos = to.isTypeStruct();
+ if (!(tos && from.sym == tos.sym))
+ return MATCH.nomatch;
+
+ if (from.mod == to.mod)
+ return MATCH.exact;
+
+ if (MODimplicitConv(from.mod, to.mod))
+ return MATCH.constant;
+
+ /* Check all the fields. If they can all be converted,
+ * allow the conversion.
+ */
+ MATCH m = MATCH.constant;
+ uint offset = ~0; // must never match a field offset
+ foreach (v; from.sym.fields[])
+ {
+ /* Why are we only looking at the first member of a union?
+ * The check should check for overlap of v with the previous field,
+ * not just starting at the same point
+ */
+ if (!global.params.fixImmutableConv && v.offset == offset) // v is at same offset as previous field
+ continue; // ignore
+
+ Type tvf = v.type.addMod(from.mod); // from type
+ Type tvt = v.type.addMod(to.mod); // to type
+
+ // field match
+ MATCH mf = tvf.implicitConvTo(tvt);
+ //printf("\t%s => %s, match = %d\n", v.type.toChars(), tvt.toChars(), mf);
+
+ if (mf == MATCH.nomatch)
+ return MATCH.nomatch;
+ if (mf < m) // if field match is worse
+ m = mf;
+ offset = v.offset;
+ }
+ return m;
+}
+
+MATCH implicitConvToWithoutAliasThis(TypeClass from, Type to)
+{
+ ClassDeclaration cdto = to.isClassHandle();
+ MATCH m = constConv(from, to);
+ if (m > MATCH.nomatch)
+ return m;
+
+ if (cdto && cdto.isBaseOf(from.sym, null) && MODimplicitConv(from.mod, to.mod))
+ {
+ //printf("'to' is base\n");
+ return MATCH.convert;
+ }
+ return MATCH.nomatch;
+}
+
+MATCH implicitConvToThroughAliasThis(TypeClass from, Type to)
+{
+ MATCH m;
+ if (from.sym.aliasthis && !(from.att & AliasThisRec.tracing))
+ {
+ if (auto ato = aliasthisOf(from))
+ {
+ from.att = cast(AliasThisRec)(from.att | AliasThisRec.tracing);
+ m = ato.implicitConvTo(to);
+ from.att = cast(AliasThisRec)(from.att & ~AliasThisRec.tracing);
+ }
+ }
+ return m;
+}
+
+MATCH implicitConvToThroughAliasThis(TypeStruct from, Type to)
+{
+ auto tos = to.isTypeStruct();
+ if (!(tos && from.sym == tos.sym) &&
+ from.sym.aliasthis &&
+ !(from.att & AliasThisRec.tracing))
+ {
+ if (auto ato = aliasthisOf(from))
+ {
+ from.att = cast(AliasThisRec)(from.att | AliasThisRec.tracing);
+ MATCH m = ato.implicitConvTo(to);
+ from.att = cast(AliasThisRec)(from.att & ~AliasThisRec.tracing);
+ return m;
+ }
+ }
+ return MATCH.nomatch;
+}
+
+/*******************************************
+ * Compute number of elements for a (possibly multidimensional) static array,
+ * or 1 for other types.
+ * Params:
+ * t = static array type
+ * loc = for error message
+ * Returns:
+ * number of elements, uint.max on overflow
+ */
+uint numberOfElems(Type t, Loc loc)
+{
+ //printf("Type::numberOfElems()\n");
+ uinteger_t n = 1;
+ Type tb = t;
+ while ((tb = tb.toBasetype()).ty == Tsarray)
+ {
+ bool overflow = false;
+ n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow);
+ if (overflow || n >= uint.max)
+ {
+ error(loc, "static array `%s` size overflowed to %llu", t.toChars(), cast(ulong)n);
+ return uint.max;
+ }
+ tb = (cast(TypeSArray)tb).next;
+ }
+ return cast(uint)n;
+}
+
+bool checkRetType(TypeFunction tf, Loc loc)
+{
+ Type tb = tf.next.toBasetype();
+ if (tb.ty == Tfunction)
+ {
+ error(loc, "functions cannot return a function");
+ tf.next = Type.terror;
+ }
+ if (tb.ty == Ttuple)
+ {
+ error(loc, "functions cannot return a sequence (use `std.typecons.Tuple`)");
+ tf.next = Type.terror;
+ }
+ if (!tf.isRef && (tb.ty == Tstruct || tb.ty == Tsarray))
+ {
+ if (auto ts = tb.baseElemOf().isTypeStruct())
+ {
+ if (!ts.sym.members)
+ {
+ error(loc, "functions cannot return opaque type `%s` by value", tb.toChars());
+ tf.next = Type.terror;
+ }
+ }
+ }
+ if (tb.ty == Terror)
+ return true;
+ return false;
+}
+
+/// Returns: whether `t` is a struct/class/enum without a body
+bool isOpaqueType(Type t)
+{
+ if (auto te = t.isTypeEnum())
+ return te.sym.members is null;
+ if (auto ts = t.isTypeStruct())
+ return ts.sym.members is null;
+ if (auto tc = t.isTypeClass())
+ return tc.sym.members is null;
+ return false;
+}
+
+
/******************************* Private *****************************************/
private:
@@ -7077,8 +7826,7 @@ Type stripDefaultArgs(Type t)
{
foreach (i, p; *parameters)
{
- Parameter ps = stripParameter(p);
- if (ps)
+ if (Parameter ps = stripParameter(p))
{
// Replace params with a copy we can modify
Parameters* nparams = new Parameters(parameters.length);
@@ -7155,11 +7903,11 @@ Type stripDefaultArgs(Type t)
* Returns:
* corresponding value of .max/.min
*/
-Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
+Expression getMaxMinValue(EnumDeclaration ed, Loc loc, Identifier id)
{
//printf("EnumDeclaration::getMaxValue()\n");
- static Expression pvalToResult(Expression e, const ref Loc loc)
+ static Expression pvalToResult(Expression e, Loc loc)
{
if (e.op != EXP.error)
{
@@ -7194,7 +7942,7 @@ Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
.error(loc, "%s `%s` is opaque and has no `.%s`", ed.kind, ed.toPrettyChars, id.toChars(), id.toChars());
return errorReturn();
}
- if (!(ed.memtype && ed.memtype.isintegral()))
+ if (!(ed.memtype && ed.memtype.isIntegral()))
{
.error(loc, "%s `%s` has no `.%s` property because base type `%s` is not an integral type", ed.kind, ed.toPrettyChars, id.toChars(),
id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
@@ -7266,10 +8014,10 @@ Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
* Return:
* null if error, else RootObject AST as parsed
*/
-RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
+RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
{
OutBuffer buf;
- if (expressionsToString(buf, sc, tm.exps))
+ if (expressionsToString(buf, sc, tm.exps, tm.loc, null, true))
return null;
const errors = global.errors;
@@ -7277,9 +8025,9 @@ RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
buf.writeByte(0);
const str = buf.extractSlice()[0 .. len];
const bool doUnittests = global.params.parsingUnittestsRequired();
- auto locm = adjustLocForMixin(str, loc, global.params.mixinOut);
- scope p = new Parser!ASTCodegen(locm, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
- p.transitionIn = global.params.v.vin;
+ scope p = new Parser!ASTCodegen(sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
+ adjustLocForMixin(str, loc, *p.baseLoc, global.params.mixinOut);
+ p.linnum = p.baseLoc.startLine;
p.nextToken();
//printf("p.loc.linnum = %d\n", p.loc.linnum);
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index a319832..1c7ed32 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -1,12 +1,12 @@
/**
* Generate `TypeInfo` objects, which are needed for run-time introspection of types.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d, _typinf.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typinf.d, _typinf.d)
* Documentation: https://dlang.org/phobos/dmd_typinf.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typinf.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/typinf.d
*/
module dmd.typinf;
@@ -22,6 +22,7 @@ import dmd.expression;
import dmd.globals;
import dmd.location;
import dmd.mtype;
+import dmd.typesem;
import core.stdc.stdio;
/****************************************************
@@ -35,14 +36,14 @@ import core.stdc.stdio;
* Returns:
* true if `TypeInfo` was generated and needs compiling to object file
*/
-bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
+bool genTypeInfo(Expression e, Loc loc, Type torig, Scope* sc)
{
// printf("genTypeInfo() %s\n", torig.toChars());
// Even when compiling without `useTypeInfo` (e.g. -betterC) we should
// still be able to evaluate `TypeInfo` at compile-time, just not at runtime.
// https://issues.dlang.org/show_bug.cgi?id=18472
- if (!sc || !(sc.flags & SCOPE.ctfe))
+ if (!sc || !sc.ctfe)
{
if (!global.params.useTypeInfo)
{
@@ -67,6 +68,9 @@ bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
import dmd.typesem : merge2;
Type t = torig.merge2(); // do this since not all Type's are merge'd
+ if (t.ty == Taarray)
+ t = makeNakedAssociativeArray(cast(TypeAArray)t);
+
bool needsCodegen = false;
if (!t.vtinfo)
{
@@ -79,7 +83,7 @@ bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
else if (t.isWild())
t.vtinfo = TypeInfoWildDeclaration.create(t);
else
- t.vtinfo = getTypeInfoDeclaration(t);
+ t.vtinfo = getTypeInfoDeclaration(t, sc);
assert(t.vtinfo);
// ClassInfos are generated as part of ClassDeclaration codegen
@@ -100,13 +104,12 @@ bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
* loc = the location for reporting line nunbers in errors
* t = the type to get the type of the `TypeInfo` object for
* sc = the scope
- * genObjCode = if true, object code will be generated for the obtained TypeInfo
* Returns:
* The type of the `TypeInfo` object associated with `t`
*/
-extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc, bool genObjCode = true);
+extern (C++) Type getTypeInfoType(Loc loc, Type t, Scope* sc);
-private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
+private TypeInfoDeclaration getTypeInfoDeclaration(Type t, Scope* sc)
{
//printf("Type::getTypeInfoDeclaration() %s\n", t.toChars());
switch (t.ty)
@@ -118,7 +121,7 @@ private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
case Tsarray:
return TypeInfoStaticArrayDeclaration.create(t);
case Taarray:
- return TypeInfoAssociativeArrayDeclaration.create(t);
+ return getTypeInfoAssocArrayDeclaration(cast(TypeAArray)t, sc);
case Tstruct:
return TypeInfoStructDeclaration.create(t);
case Tvector:
@@ -142,6 +145,70 @@ private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
}
}
+/******************************************
+ * Instantiate TypeInfoAssociativeArrayDeclaration and fill
+ * the entry with TypeInfo_AssociativeArray.Entry!(t.index, t.next)
+ *
+ * Params:
+ * t = TypeAArray to generate TypeInfo_AssociativeArray for
+ * sc = context
+ * Returns:
+ * a TypeInfoAssociativeArrayDeclaration with field entry initialized
+ */
+TypeInfoDeclaration getTypeInfoAssocArrayDeclaration(TypeAArray t, Scope* sc)
+{
+ import dmd.arraytypes;
+ import dmd.expressionsem;
+ import dmd.id;
+
+ assert(sc); // must not be called in the code generation phase
+
+ auto ti = TypeInfoAssociativeArrayDeclaration.create(t);
+ t.vtinfo = ti; // assign it early to avoid recursion in expressionSemantic
+ Loc loc = t.loc;
+ auto tiargs = new Objects();
+ tiargs.push(t.index); // always called with naked types
+ tiargs.push(t.next);
+
+ Expression id = new IdentifierExp(loc, Id.empty);
+ id = new DotIdExp(loc, id, Id.object);
+ id = new DotIdExp(loc, id, Id.TypeInfo_AssociativeArray);
+ auto tempinst = new DotTemplateInstanceExp(loc, id, Id.Entry, tiargs);
+ auto e = expressionSemantic(tempinst, sc);
+ assert(e.type);
+ ti.entry = e.type;
+ if (auto ts = ti.entry.isTypeStruct())
+ {
+ ts.sym.requestTypeInfo = true;
+ if (auto tmpl = ts.sym.isInstantiated())
+ tmpl.minst = sc._module.importedFrom; // ensure it get's emitted
+ }
+ getTypeInfoType(loc, ti.entry, sc);
+ assert(ti.entry.vtinfo);
+
+ return ti;
+}
+
+/******************************************
+ * Find or create a TypeAArray with index and next without
+ * any head modifiers, tail `inout` is replaced with `const`
+ *
+ * Params:
+ * t = TypeAArray to convert
+ * Returns:
+ * t = found type
+ */
+Type makeNakedAssociativeArray(TypeAArray t)
+{
+ Type tindex = t.index.toBasetype().nakedOf().substWildTo(MODFlags.const_);
+ Type tnext = t.next.toBasetype().nakedOf().substWildTo(MODFlags.const_);
+ if (tindex == t.index && tnext == t.next)
+ return t;
+
+ t = new TypeAArray(tnext, tindex);
+ return t.merge();
+}
+
/**************************************************
* Returns:
* true if any part of type t is speculative.
diff --git a/gcc/d/dmd/typinf.h b/gcc/d/dmd/typinf.h
index dd9572a..c34494d 100644
--- a/gcc/d/dmd/typinf.h
+++ b/gcc/d/dmd/typinf.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -14,12 +14,16 @@
class Expression;
class Type;
+class TypeAArray;
+class TypeInfoDeclaration;
struct Scope;
namespace dmd
{
- bool genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc);
+ bool genTypeInfo(Expression *e, Loc loc, Type *torig, Scope *sc);
bool isSpeculativeType(Type *t);
bool builtinTypeInfo(Type *t);
+ Type *makeNakedAssociativeArray(TypeAArray *t);
+ TypeInfoDeclaration *getTypeInfoAssocArrayDeclaration(TypeAArray *t, Scope *sc);
}
-Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc, bool genObjCode = true);
+Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
index 72d8036..bfa197a 100644
--- a/gcc/d/dmd/utils.d
+++ b/gcc/d/dmd/utils.d
@@ -1,12 +1,12 @@
/**
* This module defines some utility functions for DMD.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utils.d, _utils.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/utils.d, _utils.d)
* Documentation: https://dlang.org/phobos/dmd_utils.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/utils.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/utils.d
*/
module dmd.utils;
@@ -52,16 +52,18 @@ const(char)* toWinPath(const(char)* src)
* Params:
* loc = The line number information from where the call originates
* filename = Path to file
+ * buf = append contents of file to
+ * Returns:
+ * true on failure
*/
-Buffer readFile(Loc loc, const(char)[] filename)
+bool readFile(Loc loc, const(char)[] filename, ref OutBuffer buf)
{
- auto result = File.read(filename);
- if (!result.success)
+ if (File.read(filename, buf))
{
error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr);
- fatal();
+ return true;
}
- return Buffer(result.extractSlice());
+ return false;
}
@@ -122,7 +124,7 @@ bool ensurePathToNameExists(Loc loc, const(char)[] name)
* buf = Buffer to write the escaped path to
* fname = Path to escape
*/
-void escapePath(OutBuffer* buf, const(char)* fname)
+void escapePath(OutBuffer* buf, const(char)* fname) pure
{
while (1)
{
@@ -144,78 +146,6 @@ void escapePath(OutBuffer* buf, const(char)* fname)
}
/**
- * Takes a path, and make it compatible with GNU Makefile format.
- *
- * GNU make uses a weird quoting scheme for white space.
- * A space or tab preceded by 2N+1 backslashes represents N backslashes followed by space;
- * a space or tab preceded by 2N backslashes represents N backslashes at the end of a file name;
- * and backslashes in other contexts should not be doubled.
- *
- * Params:
- * buf = Buffer to write the escaped path to
- * fname = Path to escape
- */
-void writeEscapedMakePath(ref OutBuffer buf, const(char)* fname)
-{
- uint slashes;
-
- while (*fname)
- {
- switch (*fname)
- {
- case '\\':
- slashes++;
- break;
- case '$':
- buf.writeByte('$');
- goto default;
- case ' ':
- case '\t':
- while (slashes--)
- buf.writeByte('\\');
- goto case;
- case '#':
- buf.writeByte('\\');
- goto default;
- case ':':
- // ':' not escaped on Windows because it can
- // create problems with absolute paths (e.g. C:\Project)
- version (Windows) {}
- else
- {
- buf.writeByte('\\');
- }
- goto default;
- default:
- slashes = 0;
- break;
- }
-
- buf.writeByte(*fname);
- fname++;
- }
-}
-
-///
-unittest
-{
- version (Windows)
- {
- enum input = `C:\My Project\file#4$.ext`;
- enum expected = `C:\My\ Project\file\#4$$.ext`;
- }
- else
- {
- enum input = `/foo\bar/weird$.:name#\ with spaces.ext`;
- enum expected = `/foo\bar/weird$$.\:name\#\\\ with\ spaces.ext`;
- }
-
- OutBuffer buf;
- buf.writeEscapedMakePath(input);
- assert(buf[] == expected);
-}
-
-/**
* Convert string to integer.
*
* Params:
@@ -307,7 +237,7 @@ bool parseDigits(T)(ref T val, const(char)[] p, const T max = T.max)
* size = 1 for ubyte[], 2 for ushort[], 4 for uint[], 8 for ulong[]
* Returns: copy of `data`, with bytes shuffled if compiled for `version(LittleEndian)`
*/
-ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size)
+ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size) @safe
{
ubyte[] impl(T)()
{
diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h
index dd83fd6..1200b2e 100644
--- a/gcc/d/dmd/version.h
+++ b/gcc/d/dmd/version.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* written by Walter Bright
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
@@ -15,25 +15,17 @@
class DebugSymbol final : public Dsymbol
{
public:
- unsigned level;
-
DebugSymbol *syntaxCopy(Dsymbol *) override;
- const char *toChars() const override;
const char *kind() const override;
- DebugSymbol *isDebugSymbol() override;
void accept(Visitor *v) override { v->visit(this); }
};
class VersionSymbol final : public Dsymbol
{
public:
- unsigned level;
-
VersionSymbol *syntaxCopy(Dsymbol *) override;
- const char *toChars() const override;
const char *kind() const override;
- VersionSymbol *isVersionSymbol() override;
void accept(Visitor *v) override { v->visit(this); }
};
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index ab5cba6..94fd294 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -1,6 +1,6 @@
/* Compiler implementation of the D programming language
- * Copyright (C) 2013-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 2013-2025 by The D Language Foundation, All Rights Reserved
* https://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* https://www.boost.org/LICENSE_1_0.txt
diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/visitor/foreachvar.d
index 53b3c04..80611d6 100644
--- a/gcc/d/dmd/foreachvar.d
+++ b/gcc/d/dmd/visitor/foreachvar.d
@@ -1,15 +1,15 @@
/**
* Utility to visit every variable in an expression.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d, _foreachvar.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/foreachvar.d, _foreachvar.d)
* Documentation: https://dlang.org/phobos/dmd_foreachvar.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/foreachvar.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/visitor/foreachvar.d
*/
-module dmd.foreachvar;
+module dmd.visitor.foreachvar;
import core.stdc.stdio;
import core.stdc.stdlib;
@@ -24,7 +24,6 @@ import dmd.dstruct;
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.dtemplate;
-import dmd.errors;
import dmd.expression;
import dmd.func;
import dmd.id;
@@ -32,13 +31,13 @@ import dmd.identifier;
import dmd.init;
import dmd.initsem;
import dmd.mtype;
-import dmd.postordervisitor;
import dmd.printast;
import dmd.root.array;
import dmd.rootobject;
import dmd.statement;
import dmd.tokens;
import dmd.visitor;
+import dmd.visitor.postorder;
/*********************************************
* Visit each Expression in e, and call dgVar() on each variable declared in it.
diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor/package.d
index abfd8ca..50b5a54 100644
--- a/gcc/d/dmd/visitor.d
+++ b/gcc/d/dmd/visitor/package.d
@@ -1,23 +1,21 @@
/**
* Provides a visitor class visiting all AST nodes present in the compiler.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/visitor.d, _visitor.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/package.d, _visitor.d)
* Documentation: https://dlang.org/phobos/dmd_visitor.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/visitor.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/visitor/package.d
*/
module dmd.visitor;
import dmd.astcodegen;
-import dmd.astenums;
-import dmd.parsetimevisitor;
import dmd.tokens;
-import dmd.transitivevisitor;
-import dmd.expression;
import dmd.rootobject;
+import dmd.visitor.parsetime;
+import dmd.visitor.transitive;
/**
* Classic Visitor class which implements visit methods for all the AST
@@ -151,10 +149,11 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor
{
// CTFE can generate struct literals that contain an AddrExp pointing to themselves,
// need to avoid infinite recursion.
- if (!(e.stageflags & stageToCBuffer))
+ alias flag = ASTCodegen.StructLiteralExp.StageFlags.toCBuffer;
+ if (!(e.stageflags & flag))
{
const old = e.stageflags;
- e.stageflags |= stageToCBuffer;
+ e.stageflags |= flag;
foreach (el; *e.elements)
if (el)
el.accept(this);
@@ -162,6 +161,11 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor
}
}
+ override void visit(ASTCodegen.ClassReferenceExp e)
+ {
+ e.value.accept(this);
+ }
+
override void visit(ASTCodegen.CompoundLiteralExp e)
{
if (e.initializer)
@@ -245,7 +249,7 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor
override void visit(ASTCodegen.LoweredAssignExp e)
{
e.lowering.accept(this);
- visit(cast(AssignExp)e);
+ visit(cast(ASTCodegen.AssignExp)e);
}
}
diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/visitor/parsetime.d
index c03f78d..914ca41 100644
--- a/gcc/d/dmd/parsetimevisitor.d
+++ b/gcc/d/dmd/visitor/parsetime.d
@@ -7,7 +7,7 @@
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parsetimevisitor.d
*/
-module dmd.parsetimevisitor;
+module dmd.visitor.parsetime;
/** Basic and dumm visitor which implements a visit method for each AST node
* implemented in AST. This visitor is the parent of strict, transitive
diff --git a/gcc/d/dmd/permissivevisitor.d b/gcc/d/dmd/visitor/permissive.d
index 5d7f3fc..ef1f279 100644
--- a/gcc/d/dmd/permissivevisitor.d
+++ b/gcc/d/dmd/visitor/permissive.d
@@ -5,9 +5,9 @@
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/permissivevisitor.d
*/
-module dmd.permissivevisitor;
+module dmd.visitor.permissive;
-import dmd.parsetimevisitor;
+import dmd.visitor.parsetime;
/** PermissiveVisitor overrides all the visit methods in the parent class
* that assert(0) in order to facilitate the traversal of subsets of the AST.
diff --git a/gcc/d/dmd/visitor/postorder.d b/gcc/d/dmd/visitor/postorder.d
new file mode 100644
index 0000000..22549da
--- /dev/null
+++ b/gcc/d/dmd/visitor/postorder.d
@@ -0,0 +1,318 @@
+/**
+ * A depth-first visitor for expressions and statements.
+ *
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/postorder.d, _apply.d)
+ * Documentation: https://dlang.org/phobos/dmd_apply.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/visitor/postorder.d
+ */
+
+module dmd.visitor.postorder;
+
+import dmd.dtemplate;
+import dmd.expression;
+import dmd.root.array;
+import dmd.statement;
+import dmd.visitor;
+
+bool walkPostorder(Expression e, StoppableVisitor v)
+{
+ scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v);
+ e.accept(pv);
+ return v.stop;
+}
+
+bool walkPostorder(Statement s, StoppableVisitor v)
+{
+ scope PostorderStatementVisitor pv = new PostorderStatementVisitor(v);
+ s.accept(pv);
+ return v.stop;
+}
+
+private:
+/**************************************
+ * An Expression tree walker that will visit each Expression e in the tree,
+ * in depth-first evaluation order, and call fp(e,param) on it.
+ * fp() signals whether the walking continues with its return value:
+ * Returns:
+ * 0 continue
+ * 1 done
+ * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
+ * Creating an iterator for this would be much more complex.
+ */
+extern (C++) final class PostorderExpressionVisitor : StoppableVisitor
+{
+ alias visit = typeof(super).visit;
+public:
+ StoppableVisitor v;
+
+ extern (D) this(StoppableVisitor v) scope @safe
+ {
+ this.v = v;
+ }
+
+ bool doCond(Expression e)
+ {
+ if (!stop && e)
+ e.accept(this);
+ return stop;
+ }
+
+ extern(D) bool doCond(Expression[] e)
+ {
+ for (size_t i = 0; i < e.length && !stop; i++)
+ doCond(e[i]);
+ return stop;
+ }
+
+ bool applyTo(Expression e)
+ {
+ e.accept(v);
+ stop = v.stop;
+ return true;
+ }
+
+ override void visit(Expression e)
+ {
+ applyTo(e);
+ }
+
+ override void visit(NewExp e)
+ {
+ //printf("NewExp::apply(): %s\n", toChars());
+ doCond(e.placement) || doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
+ }
+
+ override void visit(NewAnonClassExp e)
+ {
+ //printf("NewAnonClassExp::apply(): %s\n", toChars());
+ doCond(e.placement) || doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e);
+ }
+
+ override void visit(TypeidExp e)
+ {
+ doCond(isExpression(e.obj)) || applyTo(e);
+ }
+
+ override void visit(UnaExp e)
+ {
+ doCond(e.e1) || applyTo(e);
+ }
+
+ override void visit(BinExp e)
+ {
+ doCond(e.e1) || doCond(e.e2) || applyTo(e);
+ }
+
+ override void visit(AssertExp e)
+ {
+ //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e.e1) || doCond(e.msg) || applyTo(e);
+ }
+
+ override void visit(CallExp e)
+ {
+ //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e);
+ }
+
+ override void visit(ArrayExp e)
+ {
+ //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e);
+ }
+
+ override void visit(SliceExp e)
+ {
+ doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e);
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ doCond(e.basis) || doCond(e.elements.peekSlice()) || applyTo(e);
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ doCond(e.keys.peekSlice()) || doCond(e.values.peekSlice()) || applyTo(e);
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ if (e.stageflags & StructLiteralExp.StageFlags.apply)
+ return;
+ const old = e.stageflags;
+ e.stageflags |= StructLiteralExp.StageFlags.apply;
+ doCond(e.elements.peekSlice()) || applyTo(e);
+ e.stageflags = old;
+ }
+
+ override void visit(TupleExp e)
+ {
+ doCond(e.e0) || doCond(e.exps.peekSlice()) || applyTo(e);
+ }
+
+ override void visit(CondExp e)
+ {
+ doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e);
+ }
+}
+
+/**************************************
+ * A Statement tree walker that will visit each Statement s in the tree,
+ * in depth-first evaluation order, and call fp(s,param) on it.
+ * fp() signals whether the walking continues with its return value:
+ * Returns:
+ * 0 continue
+ * 1 done
+ * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
+ * Creating an iterator for this would be much more complex.
+ */
+extern (C++) final class PostorderStatementVisitor : StoppableVisitor
+{
+ alias visit = typeof(super).visit;
+public:
+ StoppableVisitor v;
+
+ extern (D) this(StoppableVisitor v) scope @safe
+ {
+ this.v = v;
+ }
+
+ bool doCond(Statement s)
+ {
+ if (!stop && s)
+ s.accept(this);
+ return stop;
+ }
+
+ bool applyTo(Statement s)
+ {
+ s.accept(v);
+ stop = v.stop;
+ return true;
+ }
+
+ override void visit(Statement s)
+ {
+ applyTo(s);
+ }
+
+ override void visit(PeelStatement s)
+ {
+ doCond(s.s) || applyTo(s);
+ }
+
+ override void visit(CompoundStatement s)
+ {
+ for (size_t i = 0; i < s.statements.length; i++)
+ if (doCond((*s.statements)[i]))
+ return;
+ applyTo(s);
+ }
+
+ override void visit(UnrolledLoopStatement s)
+ {
+ for (size_t i = 0; i < s.statements.length; i++)
+ if (doCond((*s.statements)[i]))
+ return;
+ applyTo(s);
+ }
+
+ override void visit(ScopeStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(WhileStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(DoStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(ForStatement s)
+ {
+ doCond(s._init) || doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(ForeachStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(ForeachRangeStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(IfStatement s)
+ {
+ doCond(s.ifbody) || doCond(s.elsebody) || applyTo(s);
+ }
+
+ override void visit(PragmaStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(SwitchStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(CaseStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(SynchronizedStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(WithStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(TryCatchStatement s)
+ {
+ if (doCond(s._body))
+ return;
+ for (size_t i = 0; i < s.catches.length; i++)
+ if (doCond((*s.catches)[i].handler))
+ return;
+ applyTo(s);
+ }
+
+ override void visit(TryFinallyStatement s)
+ {
+ doCond(s._body) || doCond(s.finalbody) || applyTo(s);
+ }
+
+ override void visit(ScopeGuardStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(DebugStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(LabelStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+}
diff --git a/gcc/d/dmd/statement_rewrite_walker.d b/gcc/d/dmd/visitor/statement_rewrite_walker.d
index 221c502..25e4c73 100644
--- a/gcc/d/dmd/statement_rewrite_walker.d
+++ b/gcc/d/dmd/visitor/statement_rewrite_walker.d
@@ -1,15 +1,15 @@
/**
* Provides a visitor for statements that allows rewriting the currently visited node.
*
- * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Copyright: Copyright (C) 1999-2025 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d, _statement_rewrite_walker.d)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/compiler/src/dmd/visitor/statement_rewrite_walker.d, _statement_rewrite_walker.d)
* Documentation: https://dlang.org/phobos/dmd_statement_rewrite_walker.html
- * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement_rewrite_walker.d
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/compiler/src/dmd/visitor/statement_rewrite_walker.d
*/
-module dmd.statement_rewrite_walker;
+module dmd.visitor.statement_rewrite_walker;
import core.stdc.stdio;
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/visitor/transitive.d
index bf1d38e..89c2332 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/visitor/transitive.d
@@ -3,10 +3,10 @@
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/transitivevisitor.d
*/
-module dmd.transitivevisitor;
+module dmd.visitor.transitive;
import dmd.astenums;
-import dmd.permissivevisitor;
+import dmd.visitor.permissive;
import dmd.tokens;
import dmd.rootobject;
@@ -26,7 +26,7 @@ extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST
* is used for semantic time AST node traversal, so in order to not duplicate the code,
* the template mixin is used.
*/
-package mixin template ParseVisitMethods(AST)
+package(dmd.visitor) mixin template ParseVisitMethods(AST)
{
import dmd.root.array;
@@ -153,8 +153,8 @@ package mixin template ParseVisitMethods(AST)
override void visit(AST.ForeachRangeStatement s)
{
//printf("Visiting ForeachRangeStatement\n");
- if (s.prm.type)
- visitType(s.prm.type);
+ if (s.param.type)
+ visitType(s.param.type);
s.lwr.accept(this);
s.upr.accept(this);
if (s._body)
@@ -174,8 +174,8 @@ package mixin template ParseVisitMethods(AST)
override void visit(AST.IfStatement s)
{
//printf("Visiting IfStatement\n");
- if (s.prm && s.prm.type)
- visitType(s.prm.type);
+ if (s.param && s.param.type)
+ visitType(s.param.type);
s.condition.accept(this);
s.ifbody.accept(this);
if (s.elsebody)
@@ -854,7 +854,7 @@ package mixin template ParseVisitMethods(AST)
override void visit(AST.FuncLiteralDeclaration f)
{
//printf("Visiting FuncLiteralDeclaration\n");
- if (f.type.ty == Terror)
+ if (f.type.isTypeError())
return;
auto tf = f.type.isTypeFunction();
if (!f.inferRetType && tf.next)
@@ -994,6 +994,8 @@ package mixin template ParseVisitMethods(AST)
override void visit(AST.NewExp e)
{
//printf("Visiting NewExp\n");
+ if (e.placement)
+ e.placement.accept(this);
if (e.thisexp)
e.thisexp.accept(this);
visitType(e.newtype);
@@ -1003,6 +1005,8 @@ package mixin template ParseVisitMethods(AST)
override void visit(AST.NewAnonClassExp e)
{
//printf("Visiting NewAnonClassExp\n");
+ if (e.placement)
+ e.placement.accept(this);
if (e.thisexp)
e.thisexp.accept(this);
visitArgs(e.arguments.peekSlice());
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index d055e0b..268a176 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -1,5 +1,5 @@
/* expr.cc -- Lower D frontend expressions to GCC trees.
- Copyright (C) 2015-2024 Free Software Foundation, Inc.
+ Copyright (C) 2015-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -295,14 +295,14 @@ public:
this->result_ = d_convert (build_ctype (e->type),
build_boolop (code, t1, t2));
}
- else if (tb1->isfloating () && tb1->ty != TY::Tvector)
+ else if (tb1->isFloating () && tb1->ty != TY::Tvector)
{
/* For floating-point values, identity is defined as the bits in the
operands being identical. */
tree t1 = d_save_expr (build_expr (e->e1));
tree t2 = d_save_expr (build_expr (e->e2));
- if (!tb1->iscomplex ())
+ if (!tb1->isComplex ())
this->result_ = build_float_identity (code, t1, t2);
else
{
@@ -388,7 +388,7 @@ public:
e1.length == e2.length && memcmp(e1.ptr, e2.ptr, size) == 0;
Or when generating a NE expression:
e1.length != e2.length || memcmp(e1.ptr, e2.ptr, size) != 0; */
- if ((t1elem->isintegral () || t1elem->ty == TY::Tvoid
+ if ((t1elem->isIntegral () || t1elem->ty == TY::Tvoid
|| (t1elem->ty == TY::Tstruct
&& !t1elem->isTypeStruct ()->sym->xeq))
&& t1elem->ty == t2elem->ty)
@@ -414,7 +414,8 @@ public:
if (t1elem->ty != TY::Tstruct
|| identity_compare_p (t1elem->isTypeStruct ()->sym))
{
- tree size = size_mult_expr (t1len, size_int (t1elem->size ()));
+ tree size =
+ size_mult_expr (t1len, size_int (dmd::size (t1elem)));
result = build_memcmp_call (t1ptr, t2ptr, size);
result = build_boolop (code, result, integer_zero_node);
@@ -442,7 +443,7 @@ public:
The frontend should have already guaranteed that static arrays
have same size. */
if (tb1->ty == TY::Tsarray && tb2->ty == TY::Tsarray)
- gcc_assert (tb1->size () == tb2->size ());
+ gcc_assert (dmd::size (tb1) == dmd::size (tb2));
else
{
tree tlencmp = build_boolop (code, t1len, t2len);
@@ -620,8 +621,8 @@ public:
{
case EXP::add:
case EXP::min:
- if ((e->e1->type->isreal () && e->e2->type->isimaginary ())
- || (e->e1->type->isimaginary () && e->e2->type->isreal ()))
+ if ((e->e1->type->isReal () && e->e2->type->isImaginary ())
+ || (e->e1->type->isImaginary () && e->e2->type->isReal ()))
{
/* If the result is complex, then we can shortcut binary_op.
Frontend should have already validated types and sizes. */
@@ -631,7 +632,7 @@ public:
if (e->op == EXP::min)
t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2);
- if (e->e1->type->isreal ())
+ if (e->e1->type->isReal ())
this->result_ = complex_expr (build_ctype (e->type), t1, t2);
else
this->result_ = complex_expr (build_ctype (e->type), t2, t1);
@@ -661,12 +662,12 @@ public:
}
}
- code = e->e1->type->isintegral ()
+ code = e->e1->type->isIntegral ()
? TRUNC_DIV_EXPR : RDIV_EXPR;
break;
case EXP::mod:
- code = e->e1->type->isfloating ()
+ code = e->e1->type->isFloating ()
? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
break;
@@ -750,12 +751,12 @@ public:
break;
case EXP::divAssign:
- code = e->e1->type->isintegral ()
+ code = e->e1->type->isIntegral ()
? TRUNC_DIV_EXPR : RDIV_EXPR;
break;
case EXP::modAssign:
- code = e->e1->type->isfloating ()
+ code = e->e1->type->isFloating ()
? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
break;
@@ -917,7 +918,7 @@ public:
if (integer_zerop (t2))
{
tree size = size_mult_expr (d_array_length (t1),
- size_int (etype->size ()));
+ size_int (dmd::size (etype)));
result = build_memset_call (d_array_ptr (t1), size);
}
else
@@ -943,7 +944,8 @@ public:
tree t2ptr = d_array_ptr (t2);
/* Generate: memcpy(to, from, size) */
- tree size = size_mult_expr (t1len, size_int (etype->size ()));
+ tree size =
+ size_mult_expr (t1len, size_int (dmd::size (etype)));
tree result = build_memcpy_call (t1ptr, t2ptr, size);
/* Insert check that array lengths match and do not overlap. */
@@ -986,7 +988,7 @@ public:
{
/* Generate: _d_arraycopy() */
this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3,
- size_int (etype->size ()),
+ size_int (dmd::size (etype)),
d_array_convert (e->e2),
d_array_convert (e->e1));
}
@@ -1024,7 +1026,6 @@ public:
if (tb1->ty == TY::Tstruct)
{
tree t1 = build_expr (e->e1);
- tree t2 = convert_for_assignment (e->e2, e->e1->type, true);
StructDeclaration *sd = tb1->isTypeStruct ()->sym;
/* Look for struct = 0. */
@@ -1049,25 +1050,8 @@ public:
else
{
/* Simple struct literal assignment. */
- tree init = NULL_TREE;
-
- /* Fill any alignment holes in the struct using memset. */
- if ((e->op == EXP::construct
- || (e->e2->op == EXP::structLiteral && e->op == EXP::blit))
- && (sd->isUnionDeclaration () || !identity_compare_p (sd)))
- {
- t1 = stabilize_reference (t1);
- init = build_memset_call (t1);
- }
-
- /* Elide generating assignment if init is all zeroes. */
- if (init != NULL_TREE && initializer_zerop (t2))
- this->result_ = compound_expr (init, t1);
- else
- {
- tree result = build_assign (modifycode, t1, t2);
- this->result_ = compound_expr (init, result);
- }
+ tree t2 = convert_for_assignment (e->e2, e->e1->type, true);
+ this->result_ = build_assign (modifycode, t1, t2);
}
return;
@@ -1100,7 +1084,7 @@ public:
|| (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral)
|| (e->op == EXP::construct && e->e2->op == EXP::call)
|| (e->op == EXP::construct && !lvalue && postblit)
- || (e->op == EXP::blit || e->e1->type->size () == 0))
+ || (e->op == EXP::blit || dmd::size (e->e1->type) == 0))
{
tree t1 = build_expr (e->e1);
tree t2 = convert_for_assignment (e->e2, e->e1->type);
@@ -1190,7 +1174,7 @@ public:
/* Index the associative array. */
tree result = build_libcall (libcall, dmd::pointerTo (e->type), 4,
ptr, tinfo,
- size_int (tb1->nextOf ()->size ()),
+ size_int (dmd::size (tb1->nextOf ())),
build_address (key));
if (!e->indexIsInBounds && array_bounds_check ())
@@ -1497,14 +1481,14 @@ public:
void visit (PtrExp *e) final override
{
Type *tnext = NULL;
- size_t offset;
+ dinteger_t offset;
tree result;
if (e->e1->op == EXP::add)
{
AddExp *ae = e->e1->isAddExp ();
if (ae->e1->op == EXP::address
- && ae->e2->isConst () && ae->e2->type->isintegral ())
+ && ae->e2->isConst () && ae->e2->type->isIntegral ())
{
Expression *ex = ae->e1->isAddrExp ()->e1;
tnext = ex->type->toBasetype ();
@@ -1620,7 +1604,7 @@ public:
if (dve->e1->op == EXP::structLiteral)
{
StructLiteralExp *sle = dve->e1->isStructLiteralExp ();
- sle->useStaticInit = false;
+ sle->useStaticInit (false);
}
FuncDeclaration *fd = dve->var->isFuncDeclaration ();
@@ -1752,7 +1736,7 @@ public:
if (returnvalue != NULL_TREE)
exp = compound_expr (exp, returnvalue);
- if (tf->isref ())
+ if (tf->isRef ())
exp = build_deref (exp);
/* Some library calls are defined to return a generic type.
@@ -1781,7 +1765,7 @@ public:
void visit (DelegateExp *e) final override
{
- if (e->func->semanticRun == PASS::semantic3done)
+ if (e->func->semanticRun () == PASS::semantic3done)
{
/* Add the function as nested function if it belongs to this module.
ie: it is a member of this module, or it is a template instance. */
@@ -2072,7 +2056,7 @@ public:
void visit (SymOffExp *e) final override
{
/* Build the address and offset of the symbol. */
- size_t soffset = e->isSymOffExp ()->offset;
+ dinteger_t soffset = e->isSymOffExp ()->offset;
tree result = get_decl_tree (e->var);
TREE_USED (result) = 1;
@@ -2178,7 +2162,7 @@ public:
tree type = build_ctype (e->type);
tree length = size_int (sd->dsym->structsize);
tree ptr = (sd->dsym->isStructDeclaration ()
- && sd->dsym->type->isZeroInit (e->loc))
+ && dmd::isZeroInit (sd->dsym->type, e->loc))
? null_pointer_node : build_address (result);
this->result_ = d_array_value (type, length, ptr);
@@ -2241,18 +2225,24 @@ public:
storage class, then the instance is allocated on the stack
rather than the heap or using the class specific allocator. */
tree var = build_local_temp (TREE_TYPE (type));
+ SET_DECL_ALIGN (var, cd->alignsize * BITS_PER_UNIT);
+ DECL_USER_ALIGN (var) = 1;
new_call = build_nop (type, build_address (var));
setup_exp = modify_expr (var, aggregate_initializer_decl (cd));
}
- else if (global.params.ehnogc && e->thrownew)
+ else if (e->placement != NULL)
{
- /* Allocating a `@nogc' Exception with `_d_newThrowable' has already
- been handled by the front-end. */
- gcc_unreachable ();
+ /* Generate: placement_expr = typeid(class).init */
+ tree placement_expr = build_expr (e->placement);
+ new_call = build_nop (type, build_address (placement_expr));
+ tree class_init = build_vconvert (TREE_TYPE (placement_expr),
+ aggregate_initializer_decl (cd));
+ setup_exp = modify_expr (placement_expr, class_init);
}
else
{
- /* Generate: _d_newclass() */
+ /* Generate: _d_newclass()
+ or: _d_newThrowable() */
new_call = build_expr (e->lowering);
}
@@ -2321,12 +2311,22 @@ public:
return;
}
- /* This case should have been rewritten to `_d_newitemT' during the
- semantic phase. */
- gcc_assert (e->lowering);
+ if (e->placement != NULL)
+ {
+ /* Generate: &placement_expr */
+ tree placement_expr = build_expr (e->placement);
+ new_call = build_nop (build_ctype (tb),
+ build_address (placement_expr));
+ }
+ else
+ {
+ /* This case should have been rewritten to `_d_newitemT' during the
+ semantic phase. */
+ gcc_assert (e->lowering);
- /* Generate: _d_newitemT() */
- new_call = build_expr (e->lowering);
+ /* Generate: _d_newitemT() */
+ new_call = build_expr (e->lowering);
+ }
if (e->member || !e->arguments)
{
@@ -2391,7 +2391,7 @@ public:
/* Allocating memory for a new pointer. */
TypePointer *tpointer = tb->isTypePointer ();
- if (tpointer->next->size () == 0)
+ if (dmd::size (tpointer->next) == 0)
{
/* Pointer element size is unknown. */
this->result_ = d_convert (build_ctype (e->type),
@@ -2399,12 +2399,22 @@ public:
return;
}
- /* This case should have been rewritten to `_d_newitemT' during the
- semantic phase. */
- gcc_assert (e->lowering);
+ if (e->placement != NULL)
+ {
+ /* Generate: &placement_expr */
+ tree placement_expr = build_expr (e->placement);
+ result = build_nop (build_ctype (tb),
+ build_address (placement_expr));
+ }
+ else
+ {
+ /* This case should have been rewritten to `_d_newitemT' during the
+ semantic phase. */
+ gcc_assert (e->lowering);
- /* Generate: _d_newitemT() */
- result = build_expr (e->lowering);
+ /* Generate: _d_newitemT() */
+ result = build_expr (e->lowering);
+ }
if (e->arguments && e->arguments->length == 1)
{
@@ -2429,7 +2439,7 @@ public:
CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (aatype), mem);
result = build_nop (build_ctype (e->type),
- build_constructor (aatype, ce));
+ build_padded_constructor (aatype, ce));
}
else
gcc_unreachable ();
@@ -2502,7 +2512,7 @@ public:
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
}
- tree ctor = build_constructor (type, elms);
+ tree ctor = build_padded_constructor (type, elms);
TREE_CONSTANT (ctor) = 1;
this->result_ = ctor;
return;
@@ -2584,8 +2594,10 @@ public:
this->result_ = d_array_value (build_ctype (e->type),
size_int (0), null_pointer_node);
else
- this->result_ = build_constructor (make_array_type (tb->nextOf (), 0),
- NULL);
+ {
+ tree arrtype = make_array_type (tb->nextOf (), 0);
+ this->result_ = build_padded_constructor (arrtype, NULL);
+ }
return;
}
@@ -2626,7 +2638,7 @@ public:
/* Now return the constructor as the correct type. For static arrays there
is nothing else to do. For dynamic arrays, return a two field struct.
For pointers, return the address. */
- tree ctor = build_constructor (satype, elms);
+ tree ctor = build_padded_constructor (satype, elms);
tree type = build_ctype (e->type);
/* Nothing else to do for static arrays. */
@@ -2655,22 +2667,6 @@ public:
if (constant_p && initializer_constant_valid_p (ctor, TREE_TYPE (ctor)))
TREE_STATIC (ctor) = 1;
- /* Use memset to fill any alignment holes in the array. */
- if (!this->constp_ && !this->literalp_)
- {
- TypeStruct *ts = etype->baseElemOf ()->isTypeStruct ();
-
- if (ts != NULL && (!identity_compare_p (ts->sym)
- || ts->sym->isUnionDeclaration ()))
- {
- tree var = build_local_temp (TREE_TYPE (ctor));
- tree init = build_memset_call (var);
- /* Evaluate memset() first, then any saved elements. */
- saved_elems = compound_expr (init, saved_elems);
- ctor = compound_expr (modify_expr (var, ctor), var);
- }
- }
-
this->result_ = compound_expr (saved_elems, d_convert (type, ctor));
}
else if (e->onstack)
@@ -2692,10 +2688,13 @@ public:
/* Now copy the constructor into memory. */
tree size = size_mult_expr (size_int (e->elements->length),
- size_int (tb->nextOf ()->size ()));
+ size_int (dmd::size (tb->nextOf ())));
tree result = build_memcpy_call (mem, build_address (ctor), size);
+ /* Fill any alignment holes in the array. */
+ result = compound_expr (result, build_clear_padding_call (mem));
+
/* Return the array pointed to by MEM. */
result = compound_expr (result, mem);
@@ -2727,7 +2726,7 @@ public:
TypeAArray *ta = tb->isTypeAArray ();
if (e->keys->length == 0)
{
- this->result_ = build_constructor (build_ctype (ta), NULL);
+ this->result_ = build_padded_constructor (build_ctype (ta), NULL);
return;
}
@@ -2759,7 +2758,7 @@ public:
CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (aatype), mem);
tree result = build_nop (build_ctype (e->type),
- build_constructor (aatype, ce));
+ build_padded_constructor (aatype, ce));
this->result_ = compound_expr (init, result);
}
@@ -2770,13 +2769,13 @@ public:
/* Handle empty struct literals. */
if (e->elements == NULL || e->sd->fields.length == 0)
{
- this->result_ = build_constructor (build_ctype (e->type), NULL);
+ this->result_ = build_padded_constructor (build_ctype (e->type), NULL);
return;
}
/* Building sinit trees are delayed until after frontend semantic
processing has complete. Build the static initializer now. */
- if (e->useStaticInit && !this->constp_ && !e->sd->isCsymbol ())
+ if (e->useStaticInit () && !this->constp_ && !e->sd->isCsymbol ())
{
tree init = aggregate_initializer_decl (e->sd);
@@ -2821,7 +2820,7 @@ public:
elem = d_save_expr (elem);
if (initializer_zerop (elem))
- value = build_constructor (build_ctype (ftype), NULL);
+ value = build_padded_constructor (build_ctype (ftype), NULL);
else
value = build_array_from_val (ftype, elem);
}
@@ -2844,7 +2843,7 @@ public:
tree field = get_symbol_decl (e->sd->vthis);
tree value = build_vthis (e->sd);
CONSTRUCTOR_APPEND_ELT (ve, field, value);
- gcc_assert (e->useStaticInit == false);
+ gcc_assert (e->useStaticInit () == false);
}
/* Build a constructor in the correct shape of the aggregate type. */
@@ -2869,18 +2868,6 @@ public:
tree var = build_deref (e->sym);
ctor = compound_expr (modify_expr (var, ctor), var);
}
- else if (!this->literalp_)
- {
- /* Use memset to fill any alignment holes in the object. */
- if (!identity_compare_p (e->sd) || e->sd->isUnionDeclaration ())
- {
- tree var = build_local_temp (TREE_TYPE (ctor));
- tree init = build_memset_call (var);
- /* Evaluate memset() first, then any saved element constructors. */
- saved_elems = compound_expr (init, saved_elems);
- ctor = compound_expr (modify_expr (var, ctor), var);
- }
- }
this->result_ = compound_expr (saved_elems, ctor);
}
@@ -2920,7 +2907,7 @@ public:
if (constant_p)
this->result_ = build_vector_from_ctor (type, elms);
else
- this->result_ = build_constructor (type, elms);
+ this->result_ = build_padded_constructor (type, elms);
}
else if (e->e1->type->toBasetype ()->ty == TY::Tsarray)
{
@@ -3060,7 +3047,7 @@ build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
tree result = build_expr (e);
/* Convert for initializing the DECL_RESULT. */
- if (tf->isref ())
+ if (tf->isRef ())
{
/* If we are returning a reference, take the address. */
result = convert_expr (result, e->type, type);
diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi
index fe1c625..3a8bea0 100644
--- a/gcc/d/gdc.texi
+++ b/gcc/d/gdc.texi
@@ -14,7 +14,7 @@
@include gcc-common.texi
@c Copyright years for this manual.
-@set copyrights-d 2006-2024
+@set copyrights-d 2006-2025
@copying
@c man begin COPYRIGHT
@@ -273,8 +273,16 @@ Sets @code{__traits(getTargetInfo, "cppStd")} to @code{201703}.
This is the default.
@item c++20
Sets @code{__traits(getTargetInfo, "cppStd")} to @code{202002}.
+@item c++23
+Sets @code{__traits(getTargetInfo, "cppStd")} to @code{202302}.
@end table
+@opindex finclude-imports
+@item -finclude-imports
+Include imported modules in the compilation, as if they were given on the
+command line. When this option is enabled, all imported modules are compiled
+except those that are part of libphobos.
+
@opindex finvariants
@opindex fno-invariants
@item -fno-invariants
diff --git a/gcc/d/implement-d.texi b/gcc/d/implement-d.texi
index 770189c..a39fd58 100644
--- a/gcc/d/implement-d.texi
+++ b/gcc/d/implement-d.texi
@@ -1,5 +1,5 @@
@ignore
-Copyright (C) 2022-2024 Free Software Foundation, Inc.
+Copyright (C) 2022-2025 Free Software Foundation, Inc.
This is part of the GNU D manual.
For copying conditions, see the file gdc.texi.
@end ignore
@@ -1892,6 +1892,10 @@ This version is defined by the GNU D compiler. If all you need to know is
whether or not your D program is being compiled by GDC, or a non-GDC compiler,
you can simply test @code{version(GNU)}.
+@item GNU_CET
+This version is defined when @option{-fcf-protection} is used. The protection
+level is also set in @code{__traits(getTargetInfo, "CET")} (@pxref{Traits}).
+
@item GNU_DWARF2_Exceptions
@itemx GNU_SEH_Exceptions
@itemx GNU_SjLj_Exceptions
@@ -2121,6 +2125,10 @@ recognize. These are documented by the D language specification hosted at
The following keys are recognized by GNU D.
@table @code
+@item CET
+When @option{-fcf-protection} is used, the first bit is set to 1 for the value
+@code{branch} and the second bit is set to 1 for the value @code{return}.
+
@item cppRuntimeLibrary
The C++ runtime library affinity for this toolchain.
diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc
index 074d9e6..16e4df6 100644
--- a/gcc/d/imports.cc
+++ b/gcc/d/imports.cc
@@ -1,5 +1,5 @@
/* imports.cc -- Build imported modules/declarations.
- Copyright (C) 2014-2024 Free Software Foundation, Inc.
+ Copyright (C) 2014-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -77,7 +77,7 @@ public:
void visit (Module *m) final override
{
Loc loc = (m->md != NULL) ? m->md->loc
- : Loc (m->srcfile.toChars (), 1, 0);
+ : Loc::singleFilename (m->srcfile.toChars ());
this->result_ = build_decl (make_location_t (loc), NAMESPACE_DECL,
get_identifier (m->toPrettyChars ()),
@@ -130,7 +130,7 @@ public:
void visit (VarDeclaration *d) final override
{
/* Not all kinds of manifest constants create a CONST_DECL. */
- if (!d->canTakeAddressOf () && !d->type->isscalar ())
+ if (!d->canTakeAddressOf () && !d->type->isScalar ())
return;
visit ((Declaration *) d);
@@ -182,7 +182,11 @@ public:
vec_alloc (tset, d->a.length);
for (size_t i = 0; i < d->a.length; i++)
- vec_safe_push (tset, build_import_decl (d->a[i]));
+ {
+ tree overload = build_import_decl (d->a[i]);
+ if (overload != NULL_TREE)
+ vec_safe_push (tset, overload);
+ }
this->result_ = build_tree_list_vec (tset);
tset->truncate (0);
diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc
index c895c1a..e2b6fe1 100644
--- a/gcc/d/intrinsics.cc
+++ b/gcc/d/intrinsics.cc
@@ -1,5 +1,5 @@
/* intrinsics.cc -- D language compiler intrinsics.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/intrinsics.def b/gcc/d/intrinsics.def
index 24c9830..083613b 100644
--- a/gcc/d/intrinsics.def
+++ b/gcc/d/intrinsics.def
@@ -1,5 +1,5 @@
/* intrinsics.def -- Definitions for D compiler intrinsics.
- Copyright (C) 2014-2024 Free Software Foundation, Inc.
+ Copyright (C) 2014-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/lang-specs.h b/gcc/d/lang-specs.h
index 6f3ff2f..64e7a5f 100644
--- a/gcc/d/lang-specs.h
+++ b/gcc/d/lang-specs.h
@@ -1,5 +1,5 @@
/* lang-specs.h -- GCC driver specs for D frontend.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
@@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see
{".dd", "@d", 0, 1, 0 },
{".di", "@d", 0, 1, 0 },
{"@d",
- "%{!E:d21 %i %(cc1_options) %I %{nostdinc*} %{i*} %{I*} %{J*} \
+ "%{!E:d21 %i %(cc1_options) %I %{nostdinc} %{i*} %{I*} %{J*} \
%{H} %{Hd*} %{Hf*} %{MD:-MD %b.deps} %{MMD:-MMD %b.deps} \
%{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} \
%{X:-Xf %b.json} %{Xf*} \
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index 2a92489..298ff58 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -1,5 +1,5 @@
; lang.opt -- Options for the D front end.
-; Copyright (C) 2006-2024 Free Software Foundation, Inc.
+; Copyright (C) 2006-2025 Free Software Foundation, Inc.
;
; GCC is free software; you can redistribute it and/or modify it under
; the terms of the GNU General Public License as published by the Free
@@ -320,10 +320,17 @@ Enum(extern_stdcpp) String(c++17) Value(201703)
EnumValue
Enum(extern_stdcpp) String(c++20) Value(202002)
+EnumValue
+Enum(extern_stdcpp) String(c++23) Value(202302)
+
fignore-unknown-pragmas
D
Ignore unsupported pragmas.
+finclude-imports
+D RejectNegative
+Include imported modules in the compilation.
+
finvariants
D Var(flag_invariants)
Generate code for class invariant contracts.
@@ -400,6 +407,10 @@ fpreview=nosharedaccess
D RejectNegative
Disable access to shared memory objects.
+fpreview=safer
+D RejectNegative
+Enable safety checks on all functions by default.
+
fpreview=rvaluerefparam
D RejectNegative
Enable rvalue arguments to ref parameters.
diff --git a/gcc/d/lang.opt.urls b/gcc/d/lang.opt.urls
index 09b2a26..b4886bf 100644
--- a/gcc/d/lang.opt.urls
+++ b/gcc/d/lang.opt.urls
@@ -1,7 +1,7 @@
; Autogenerated by regenerate-opt-urls.py from gcc/d/lang.opt and generated HTML
H
-UrlSuffix(gcc/Preprocessor-Options.html#index-H) LangUrlSuffix_D(gdc/Code-Generation.html#index-H)
+UrlSuffix(gcc/Preprocessor-Options.html#index-H) LangUrlSuffix_D(gdc/Code-Generation.html#index-H) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-H)
Hd
LangUrlSuffix_D(gdc/Code-Generation.html#index-Hd)
@@ -49,7 +49,7 @@ UrlSuffix(gcc/Warning-Options.html#index-Waddress)
; duplicate: 'gcc/Standard-Libraries.html#index-Wall-1'
; duplicate: 'gcc/Warning-Options.html#index-Wall'
Wall
-LangUrlSuffix_D(gdc/Warnings.html#index-Wall)
+LangUrlSuffix_D(gdc/Warnings.html#index-Wall) LangUrlSuffix_Fortran(gfortran/Error-and-Warning-Options.html#index-Wall)
Walloca
UrlSuffix(gcc/Warning-Options.html#index-Walloca) LangUrlSuffix_D(gdc/Warnings.html#index-Walloca)
@@ -67,14 +67,17 @@ Wdeprecated
UrlSuffix(gcc/Warning-Options.html#index-Wdeprecated) LangUrlSuffix_D(gdc/Warnings.html#index-Wdeprecated)
Werror
-UrlSuffix(gcc/Warning-Options.html#index-Werror) LangUrlSuffix_D(gdc/Warnings.html#index-Werror)
+UrlSuffix(gcc/Warning-Options.html#index-Werror) LangUrlSuffix_D(gdc/Warnings.html#index-Werror) LangUrlSuffix_Fortran(gfortran/Error-and-Warning-Options.html#index-Werror)
Wextra
-UrlSuffix(gcc/Warning-Options.html#index-Wextra) LangUrlSuffix_D(gdc/Warnings.html#index-Wextra)
+UrlSuffix(gcc/Warning-Options.html#index-Wextra) LangUrlSuffix_D(gdc/Warnings.html#index-Wextra) LangUrlSuffix_Fortran(gfortran/Error-and-Warning-Options.html#index-Wextra)
Wmismatched-special-enum
LangUrlSuffix_D(gdc/Warnings.html#index-Wmismatched-special-enum)
+Wpsabi
+UrlSuffix(gcc/Warning-Options.html#index-Wno-psabi)
+
Wspeculative
LangUrlSuffix_D(gdc/Warnings.html#index-Wno-speculative)
@@ -103,14 +106,14 @@ fassert
LangUrlSuffix_D(gdc/Runtime-Options.html#index-fassert)
fbounds-check
-LangUrlSuffix_D(gdc/Runtime-Options.html#index-fbounds-check)
+LangUrlSuffix_D(gdc/Runtime-Options.html#index-fbounds-check) LangUrlSuffix_Fortran(gfortran/Code-Gen-Options.html#index-fbounds-check)
fbounds-check=
-LangUrlSuffix_D(gdc/Runtime-Options.html#index-fbounds-check)
+LangUrlSuffix_D(gdc/Runtime-Options.html#index-fbounds-check) LangUrlSuffix_Fortran(gfortran/Code-Gen-Options.html#index-fbounds-check)
; skipping UrlSuffix for 'fbuiltin' due to multiple URLs:
; duplicate: 'gcc/C-Dialect-Options.html#index-fbuiltin'
-; duplicate: 'gcc/Other-Builtins.html#index-fno-builtin-3'
+; duplicate: 'gcc/Library-Builtins.html#index-fno-builtin-3'
; duplicate: 'gcc/Warning-Options.html#index-fno-builtin-1'
; skipping LangUrlSuffix_D for 'fbuiltin' due to multiple URLs:
; duplicate: 'gdc/Other-Builtins.html#index-fno-builtin-1'
@@ -152,6 +155,9 @@ LangUrlSuffix_D(gdc/Runtime-Options.html#index-fextern-std)
fignore-unknown-pragmas
LangUrlSuffix_D(gdc/Warnings.html#index-fignore-unknown-pragmas)
+finclude-imports
+LangUrlSuffix_D(gdc/Runtime-Options.html#index-finclude-imports)
+
finvariants
LangUrlSuffix_D(gdc/Runtime-Options.html#index-finvariants)
@@ -195,22 +201,22 @@ fweak-templates
LangUrlSuffix_D(gdc/Runtime-Options.html#index-fno-weak-templates)
imultilib
-UrlSuffix(gcc/Directory-Options.html#index-imultilib) LangUrlSuffix_D(gdc/Directory-Options.html#index-imultilib)
+UrlSuffix(gcc/Directory-Options.html#index-imultilib) LangUrlSuffix_D(gdc/Directory-Options.html#index-imultilib) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-imultilib)
iprefix
-UrlSuffix(gcc/Directory-Options.html#index-iprefix) LangUrlSuffix_D(gdc/Directory-Options.html#index-iprefix)
+UrlSuffix(gcc/Directory-Options.html#index-iprefix) LangUrlSuffix_D(gdc/Directory-Options.html#index-iprefix) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-iprefix)
isysroot
-UrlSuffix(gcc/Directory-Options.html#index-isysroot)
+UrlSuffix(gcc/Directory-Options.html#index-isysroot) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-isysroot)
isystem
-UrlSuffix(gcc/Directory-Options.html#index-isystem)
+UrlSuffix(gcc/Directory-Options.html#index-isystem) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-isystem)
nophoboslib
LangUrlSuffix_D(gdc/Linking.html#index-nophoboslib)
nostdinc
-UrlSuffix(gcc/Directory-Options.html#index-nostdinc) LangUrlSuffix_D(gdc/Directory-Options.html#index-nostdinc)
+UrlSuffix(gcc/Directory-Options.html#index-nostdinc) LangUrlSuffix_D(gdc/Directory-Options.html#index-nostdinc) LangUrlSuffix_Fortran(gfortran/Preprocessing-Options.html#index-nostdinc)
static-libphobos
LangUrlSuffix_D(gdc/Linking.html#index-static-libphobos)
diff --git a/gcc/d/longdouble.h b/gcc/d/longdouble.h
index 52e8e1d..37f4474 100644
--- a/gcc/d/longdouble.h
+++ b/gcc/d/longdouble.h
@@ -1,5 +1,5 @@
/* longdouble.h -- Definitions of floating-point access for the frontend.
- Copyright (C) 2015-2024 Free Software Foundation, Inc.
+ Copyright (C) 2015-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc
index b111ee9..14e4a48 100644
--- a/gcc/d/modules.cc
+++ b/gcc/d/modules.cc
@@ -1,5 +1,5 @@
/* modules.cc -- D module initialization and termination.
- Copyright (C) 2013-2024 Free Software Foundation, Inc.
+ Copyright (C) 2013-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "function.h"
#include "cgraph.h"
#include "stor-layout.h"
+#include "debug.h"
#include "toplev.h"
#include "target.h"
#include "common/common-target.h"
@@ -143,13 +144,13 @@ get_internal_fn (tree ident, const Visibility &visibility)
name = IDENTIFIER_POINTER (s);
}
- FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid,
- Identifier::idPool (name));
+ FuncDeclaration *fd = dmd::genCfunc (NULL, Type::tvoid,
+ Identifier::idPool (name));
fd->isGenerated (true);
- fd->loc = Loc (mod->srcfile.toChars (), 1, 0);
+ fd->loc = Loc::singleFilename (mod->srcfile.toChars ());
fd->parent = mod;
fd->visibility = visibility;
- fd->semanticRun = PASS::semantic3done;
+ fd->semanticRun (PASS::semantic3done);
return fd;
}
@@ -667,7 +668,7 @@ layout_moduleinfo (Module *decl)
CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aimports_dim));
CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
- build_constructor (satype, elms));
+ build_padded_constructor (satype, elms));
}
if (flags & MIlocalClasses)
@@ -684,7 +685,7 @@ layout_moduleinfo (Module *decl)
CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aclasses.length));
CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
- build_constructor (satype, elms));
+ build_padded_constructor (satype, elms));
}
if (flags & MIname)
@@ -927,6 +928,14 @@ d_finish_compilation (tree *vec, int len)
/* Complete all generated thunks. */
symtab->process_same_body_aliases ();
+ /* Output debug information for all type declarations in this unit. */
+ for (int i = 0; i < len; i++)
+ {
+ tree decl = vec[i];
+ if (TREE_CODE (decl) == TYPE_DECL)
+ debug_hooks->type_decl (decl, false);
+ }
+
/* Process all file scopes in this compilation, and the external_scope,
through wrapup_global_declarations. */
for (int i = 0; i < len; i++)
diff --git a/gcc/d/runtime.cc b/gcc/d/runtime.cc
index 8a64c52..d337669 100644
--- a/gcc/d/runtime.cc
+++ b/gcc/d/runtime.cc
@@ -1,5 +1,5 @@
/* runtime.cc -- D runtime functions called by generated code.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
index 6c1d44f..4aff0a6 100644
--- a/gcc/d/runtime.def
+++ b/gcc/d/runtime.def
@@ -1,5 +1,5 @@
/* runtime.def -- Definitions for D runtime functions.
- Copyright (C) 2014-2024 Free Software Foundation, Inc.
+ Copyright (C) 2014-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -142,8 +142,8 @@ DEF_D_RUNTIME (CXA_END_CATCH, "__cxa_end_catch", RT(VOID), P0(), 0)
/* When invariant() contracts are turned on, used after testing whether a
class != null for validating the state of a class. */
-DEF_D_RUNTIME (INVARIANT, "_D9invariant12_d_invariantFC6ObjectZv", RT(VOID),
- P1(OBJECT), 0)
+DEF_D_RUNTIME (INVARIANT, "_D2rt10invariant_12_d_invariantFC6ObjectZv",
+ RT(VOID), P1(OBJECT), 0)
#undef P0
#undef P1
diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc
index 9f5531c..b70db7a 100644
--- a/gcc/d/toir.cc
+++ b/gcc/d/toir.cc
@@ -1,5 +1,5 @@
/* toir.cc -- Lower D frontend statements to GCC trees.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -831,7 +831,7 @@ public:
/* A switch statement on a string gets turned into a library call.
It is not lowered during codegen. */
- if (!condtype->isscalar ())
+ if (!condtype->isScalar ())
{
error ("cannot handle switch condition of type %s",
condtype->toChars ());
@@ -920,7 +920,7 @@ public:
else
{
tree casevalue;
- if (s->exp->type->isscalar ())
+ if (s->exp->type->isScalar ())
casevalue = build_expr (s->exp);
else
casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
@@ -1008,7 +1008,7 @@ public:
/* Returning by hidden reference, store the result into the retval decl.
The result returned then becomes the retval reference itself. */
tree decl = DECL_RESULT (get_symbol_decl (this->func_));
- gcc_assert (!tf->isref ());
+ gcc_assert (!tf->isRef ());
/* If returning via NRVO, just refer to the DECL_RESULT; this differs
from using NULL_TREE in that it indicates that we care about the
@@ -1058,13 +1058,8 @@ public:
if (sle != NULL)
{
- StructDeclaration *sd = type->baseElemOf ()->isTypeStruct ()->sym;
sle->sym = build_address (this->func_->shidden);
using_rvo_p = true;
-
- /* Fill any alignment holes in the return slot using memset. */
- if (!identity_compare_p (sd) || sd->isUnionDeclaration ())
- add_stmt (build_memset_call (this->func_->shidden));
}
if (using_rvo_p == true)
@@ -1491,10 +1486,9 @@ public:
outputs, inputs, clobbers, labels);
SET_EXPR_LOCATION (exp, make_location_t (s->loc));
- /* If the extended syntax was not used, mark the ASM_EXPR as being an
- ASM_INPUT expression instead of an ASM_OPERAND with no operands. */
+ /* Record whether the basic rather than extended syntax was used. */
if (s->args == NULL && s->clobbers == NULL)
- ASM_INPUT_P (exp) = 1;
+ ASM_BASIC_P (exp) = 1;
/* All asm statements are assumed to have a side effect. As a future
optimization, this could be unset when building in release mode. */
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index cadcbe8..4c3e9e4 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -1,5 +1,5 @@
/* typeinfo.cc -- D runtime type identification.
- Copyright (C) 2013-2024 Free Software Foundation, Inc.
+ Copyright (C) 2013-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/scope.h"
#include "dmd/template.h"
#include "dmd/target.h"
+#include "dmd/typinf.h"
#include "tree.h"
#include "fold-const.h"
@@ -258,10 +259,10 @@ create_tinfo_types (Module *mod)
Identifier::idPool ("TypeInfo_Class"),
array_type_node, array_type_node, array_type_node,
array_type_node, ptr_type_node, ptr_type_node,
- ptr_type_node, d_uint_type, ptr_type_node,
- array_type_node, ptr_type_node, ptr_type_node,
- d_uint_type, d_uint_type, d_uint_type, d_uint_type,
- NULL);
+ ptr_type_node, d_ushort_type, d_ushort_type,
+ ptr_type_node, array_type_node, ptr_type_node,
+ ptr_type_node, d_uint_type, d_uint_type, d_uint_type,
+ d_uint_type, NULL);
object_module = mod;
}
@@ -488,14 +489,14 @@ class TypeInfoVisitor : public Visitor
CONSTRUCTOR_APPEND_ELT (v, size_int (3), size_int (b->offset));
/* Add to the array of interfaces. */
- value = build_constructor (vtbl_interface_type_node, v);
+ value = build_padded_constructor (vtbl_interface_type_node, v);
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
}
tree domain = size_int (cd->vtblInterfaces->length - 1);
tree arrtype = build_array_type (vtbl_interface_type_node,
build_index_type (domain));
- return build_constructor (arrtype, elms);
+ return build_padded_constructor (arrtype, elms);
}
/* Write out the interfacing vtable[] of base class BCD that will be accessed
@@ -541,7 +542,7 @@ class TypeInfoVisitor : public Visitor
tree vtbldomain = build_index_type (size_int (id->vtbl.length - 1));
tree vtbltype = build_array_type (vtable_entry_type, vtbldomain);
- tree value = build_constructor (vtbltype, elms);
+ tree value = build_padded_constructor (vtbltype, elms);
this->layout_field (value);
}
@@ -662,9 +663,9 @@ public:
this->layout_string (ed->toPrettyChars ());
/* Default initializer for enum. */
- if (ed->members && !d->tinfo->isZeroInit ())
+ if (ed->members && !dmd::isZeroInit (d->tinfo))
{
- tree length = size_int (ed->type->size ());
+ tree length = size_int (dmd::size (ed->type));
tree ptr = build_address (enum_initializer_decl (ed));
this->layout_field (d_array_value (array_type_node, length, ptr));
}
@@ -728,7 +729,8 @@ public:
void **__vptr;
void *__monitor;
TypeInfo value;
- TypeInfo key; */
+ TypeInfo key;
+ TypeInfo entry; */
void visit (TypeInfoAssociativeArrayDeclaration *d) final override
{
@@ -742,6 +744,12 @@ public:
/* TypeInfo for index of type. */
this->layout_field (build_typeinfo (d->loc, ti->index));
+
+ /* TypeInfo for the key/value pair. */
+ if (d->entry != NULL)
+ this->layout_field (build_typeinfo (d->loc, d->entry));
+ else
+ this->layout_field (null_pointer_node);
}
/* Layout of TypeInfo_Vector is:
@@ -813,6 +821,7 @@ public:
void *destructor;
void function(Object) classInvariant;
ClassFlags m_flags;
+ ushort depth;
void *deallocator;
OffsetTypeInfo[] m_offTi;
void function(Object) defaultConstructor;
@@ -918,7 +927,10 @@ public:
flags |= ClassFlags::noPointers;
Lhaspointers:
- this->layout_field (build_integer_cst (flags, d_uint_type));
+ this->layout_field (build_integer_cst (flags, d_ushort_type));
+
+ /* ushort depth; (not implemented) */
+ this->layout_field (build_zero_cst (d_ushort_type));
/* void *deallocator; */
this->layout_field (null_pointer_node);
@@ -979,7 +991,10 @@ public:
if (cd->isCOMinterface ())
flags |= ClassFlags::isCOMclass;
- this->layout_field (build_integer_cst (flags, d_uint_type));
+ this->layout_field (build_integer_cst (flags, d_ushort_type));
+
+ /* ushort depth; (not implemented) */
+ this->layout_field (build_zero_cst (d_ushort_type));
/* void *deallocator;
OffsetTypeInfo[] m_offTi; (not implemented)
@@ -1145,7 +1160,7 @@ public:
CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
build_typeinfo (d->loc, arg->type));
}
- tree ctor = build_constructor (build_ctype (satype), elms);
+ tree ctor = build_padded_constructor (build_ctype (satype), elms);
tree decl = this->internal_reference (ctor);
tree length = size_int (ti->arguments->length);
@@ -1415,7 +1430,7 @@ check_typeinfo_type (const Loc &loc, Scope *sc, Expression *expr)
{
/* Even when compiling without RTTI we should still be able to evaluate
TypeInfo at compile-time, just not at run-time. */
- if (!sc || !(sc->flags & unsigned(SCOPE::ctfe)))
+ if (!sc || !sc->ctfe ())
{
static int warned = 0;
@@ -1540,12 +1555,10 @@ get_cpp_typeinfo_decl (ClassDeclaration *decl)
return decl->cpp_type_info_ptr_sym;
}
-/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it.
- When GENERATE is true, push the TypeInfo as a member of MOD so that it will
- get code generation. */
+/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it. */
void
-create_typeinfo (Type *type, Module *mod, bool generate)
+create_typeinfo (Type *type, Scope *sc)
{
if (!Type::dtypeinfo)
create_frontend_tinfo_types ();
@@ -1554,6 +1567,9 @@ create_typeinfo (Type *type, Module *mod, bool generate)
Type *t = dmd::merge2 (type);
Identifier *ident;
+ if (TypeAArray *ta = t->isTypeAArray ())
+ t = dmd::makeNakedAssociativeArray (ta);
+
if (!t->vtinfo)
{
tinfo_kind tk = get_typeinfo_kind (t);
@@ -1631,9 +1647,11 @@ create_typeinfo (Type *type, Module *mod, bool generate)
{
ident = Identifier::idPool ("TypeInfo_AssociativeArray");
make_internal_typeinfo (tk, ident, ptr_type_node, ptr_type_node,
- NULL);
+ ptr_type_node, NULL);
}
- t->vtinfo = TypeInfoAssociativeArrayDeclaration::create (t);
+ t->vtinfo = sc && have_typeinfo_p (Type::typeinfoassociativearray)
+ ? dmd::getTypeInfoAssocArrayDeclaration (t->isTypeAArray (), sc)
+ : TypeInfoAssociativeArrayDeclaration::create (t);
break;
case TK_STRUCT_TYPE:
@@ -1703,9 +1721,10 @@ create_typeinfo (Type *type, Module *mod, bool generate)
/* If this has a custom implementation in rt/typeinfo, then
do not generate a COMDAT for it. */
- if (generate && !builtin_typeinfo_p (t))
+ if (!builtin_typeinfo_p (t))
{
/* Find module that will go all the way to an object file. */
+ Module *mod = sc ? sc->_module->importedFrom : NULL;
if (mod)
mod->members->push (t->vtinfo);
else
@@ -1719,113 +1738,4 @@ create_typeinfo (Type *type, Module *mod, bool generate)
gcc_assert (type->vtinfo != NULL);
}
-/* Implements a visitor interface to check whether a type is speculative.
- TypeInfo_Struct would reference the members of the struct it is representing
- (e.g: opEquals via xopEquals field), so if it's instantiated in speculative
- context, TypeInfo creation should also be stopped to avoid possible
- `unresolved symbol' linker errors. */
-
-class SpeculativeTypeVisitor : public Visitor
-{
- using Visitor::visit;
-
- bool result_;
-
-public:
- SpeculativeTypeVisitor (void)
- {
- this->result_ = false;
- }
-
- bool result (void)
- {
- return this->result_;
- }
-
- void visit (Type *t) final override
- {
- Type *tb = t->toBasetype ();
- if (tb != t)
- tb->accept (this);
- }
-
- void visit (TypeNext *t) final override
- {
- if (t->next)
- t->next->accept (this);
- }
-
- void visit (TypeBasic *) final override
- {
- }
-
- void visit (TypeVector *t) final override
- {
- t->basetype->accept (this);
- }
-
- void visit (TypeAArray *t) final override
- {
- t->index->accept (this);
- visit ((TypeNext *) t);
- }
-
- void visit (TypeFunction *t) final override
- {
- visit ((TypeNext *) t);
- }
-
- void visit (TypeStruct *t) final override
- {
- StructDeclaration *sd = t->sym;
- if (TemplateInstance *ti = sd->isInstantiated ())
- {
- if (!ti->needsCodegen ())
- {
- if (ti->minst || sd->requestTypeInfo ())
- return;
-
- this->result_ |= true;
- }
- }
- }
-
- void visit (TypeClass *t) final override
- {
- ClassDeclaration *cd = t->sym;
- if (TemplateInstance *ti = cd->isInstantiated ())
- {
- if (!ti->needsCodegen () && !ti->minst)
- {
- this->result_ |= true;
- }
- }
- }
-
- void visit (TypeTuple *t) final override
- {
- if (!t->arguments)
- return;
-
- for (size_t i = 0; i < t->arguments->length; i++)
- {
- Type *tprm = (*t->arguments)[i]->type;
- if (tprm)
- tprm->accept (this);
- if (this->result_)
- return;
- }
- }
-};
-
-/* Return true if type was instantiated in a speculative context. */
-
-bool
-speculative_type_p (Type *t)
-{
- SpeculativeTypeVisitor v = SpeculativeTypeVisitor ();
- t->accept (&v);
- return v.result ();
-}
-
#include "gt-d-typeinfo.h"
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 9fa2f88..1c74840 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -1,5 +1,5 @@
/* types.cc -- Lower D frontend types to GCC trees.
- Copyright (C) 2006-2024 Free Software Foundation, Inc.
+ Copyright (C) 2006-2025 Free Software Foundation, Inc.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -33,7 +33,6 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "tm.h"
#include "function.h"
-#include "toplev.h"
#include "target.h"
#include "stringpool.h"
#include "stor-layout.h"
@@ -481,7 +480,7 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
AttribDeclaration *attrib = sym->isAttribDeclaration ();
if (attrib != NULL)
{
- Dsymbols *decls = attrib->include (NULL);
+ Dsymbols *decls = dmd::include (attrib, NULL);
if (decls != NULL)
{
fields += layout_aggregate_members (decls, context, inherited_p);
@@ -704,18 +703,13 @@ finish_aggregate_type (unsigned structsize, unsigned alignsize, tree type)
TYPE_LANG_SPECIFIC (t) = TYPE_LANG_SPECIFIC (type);
TYPE_SIZE (t) = TYPE_SIZE (type);
TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (type);
- TYPE_PACKED (type) = TYPE_PACKED (type);
+ TYPE_PACKED (t) = TYPE_PACKED (type);
SET_TYPE_ALIGN (t, TYPE_ALIGN (type));
TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type);
}
- /* Finish debugging output for this type. */
- rest_of_type_compilation (type, TYPE_FILE_SCOPE_P (type));
+ /* Complete any other forward-referenced fields of this aggregate type. */
finish_incomplete_fields (type);
-
- /* Finish processing of TYPE_DECL. */
- rest_of_decl_compilation (TYPE_NAME (type),
- DECL_FILE_SCOPE_P (TYPE_NAME (type)), 0);
}
/* Returns true if the class or struct type TYPE has already been layed out by
@@ -892,7 +886,7 @@ public:
void visit (TypeSArray *t) final override
{
- if (t->dim->isConst () && t->dim->type->isintegral ())
+ if (t->dim->isConst () && t->dim->type->isIntegral ())
{
uinteger_t size = t->dim->toUInteger ();
t->ctype = make_array_type (t->next, size);
@@ -975,7 +969,7 @@ public:
if (t->next != NULL)
{
fntype = build_ctype (t->next);
- if (t->isref ())
+ if (t->isRef ())
fntype = build_reference_type (fntype);
}
else
@@ -1181,17 +1175,32 @@ public:
TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype);
SET_TYPE_ALIGN (t->ctype, TYPE_ALIGN (basetype));
TYPE_SIZE (t->ctype) = NULL_TREE;
- TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8;
+ TYPE_PRECISION (t->ctype) = dmd::size (t, t->sym->loc) * 8;
layout_type (t->ctype);
- /* Finish debugging output for this type. */
- rest_of_type_compilation (t->ctype, TYPE_FILE_SCOPE_P (t->ctype));
- finish_incomplete_fields (t->ctype);
+ /* Fix up all forward-referenced variants of this enum type. */
+ for (tree v = TYPE_MAIN_VARIANT (t->ctype); v;
+ v = TYPE_NEXT_VARIANT (v))
+ {
+ if (v == t->ctype)
+ continue;
- /* Finish processing of TYPE_DECL. */
- rest_of_decl_compilation (TYPE_NAME (t->ctype),
- DECL_FILE_SCOPE_P (TYPE_NAME (t->ctype)), 0);
+ TYPE_VALUES (v) = TYPE_VALUES (t->ctype);
+ TYPE_LANG_SPECIFIC (v) = TYPE_LANG_SPECIFIC (t->ctype);
+ TYPE_MIN_VALUE (v) = TYPE_MIN_VALUE (t->ctype);
+ TYPE_MAX_VALUE (v) = TYPE_MAX_VALUE (t->ctype);
+ TYPE_UNSIGNED (v) = TYPE_UNSIGNED (t->ctype);
+ TYPE_SIZE (v) = TYPE_SIZE (t->ctype);
+ TYPE_SIZE_UNIT (v) = TYPE_SIZE_UNIT (t->ctype);
+ SET_TYPE_MODE (v, TYPE_MODE (t->ctype));
+ TYPE_PRECISION (v) = TYPE_PRECISION (t->ctype);
+ SET_TYPE_ALIGN (v, TYPE_ALIGN (t->ctype));
+ TYPE_USER_ALIGN (v) = TYPE_USER_ALIGN (t->ctype);
+ }
+
+ /* Complete forward-referenced fields of this enum type. */
+ finish_incomplete_fields (t->ctype);
}
}
@@ -1278,7 +1287,8 @@ public:
build_type_decl (basetype, t->sym);
set_visibility_for_decl (basetype, t->sym);
apply_user_attributes (t->sym, basetype);
- finish_aggregate_type (t->sym->structsize, t->sym->alignsize, basetype);
+ /* The underlying record type of classes are packed. */
+ finish_aggregate_type (t->sym->structsize, 1, basetype);
/* Classes only live in memory, so always set the TREE_ADDRESSABLE bit. */
for (tree tv = basetype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv))