diff options
Diffstat (limited to 'gcc/d')
40 files changed, 914 insertions, 507 deletions
diff --git a/gcc/d/d-ctfloat.cc b/gcc/d/d-ctfloat.cc index c4d9a44..a434af9 100644 --- a/gcc/d/d-ctfloat.cc +++ b/gcc/d/d-ctfloat.cc @@ -85,14 +85,13 @@ CTFloat::isInfinity (real_t r) /* Return a real_t value from string BUFFER rounded to long double mode. */ real_t -CTFloat::parse (const char *buffer, bool *overflow) +CTFloat::parse (const char *buffer, bool &overflow) { 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. */ - if (overflow && r == target.RealProperties.infinity) - *overflow = true; + overflow = (r == target.RealProperties.infinity) ? true : false; return r; } diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 04147ed..dcc465f 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -1191,7 +1191,6 @@ d_parse_file (void) } /* Do deferred semantic analysis. */ - Module::dprogress = 1; Module::runDeferredSemantic (); if (Module::deferred.length) diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index c358b69..85fc49d 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -d7772a236983ec37b92d21b28bad3cd2de57b945 +817610b16d0f0f469b9fbb28c000956fb910c43f 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 50c5ac3..1c7e1dd 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -18,10 +18,10 @@ this license for that file. | Folder | Purpose | |--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [dmd/](https://github.com/dlang/dmd/tree/master/src/dmd) | The dmd driver and front-end | -| [dmd/backend/](https://github.com/dlang/dmd/tree/master/src/dmd/backend) | Code generation for x86 or x86-64. Shared by the [Digital Mars C compiler](https://github.com/DigitalMars/Compiler/), but not [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). | -| [dmd/common/](https://github.com/dlang/dmd/tree/master/src/dmd/common) | Code shared by the front-end and back-end | -| [dmd/root/](https://github.com/dlang/dmd/tree/master/src/dmd/root) | Meant as a portable utility library, but ["it wasn't very good and the only project left using it is dmd"](https://github.com/dlang/dmd/pull/9844#issuecomment-498479516). | +| [dmd/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd) | The dmd driver and front-end | +| [dmd/backend/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/backend) | Code generation for x86 or x86-64. Shared by the [Digital Mars C compiler](https://github.com/DigitalMars/Compiler/), but not [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). | +| [dmd/common/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/common) | Code shared by the front-end and back-end | +| [dmd/root/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/root) | Meant as a portable utility library, but ["it wasn't very good and the only project left using it is dmd"](https://github.com/dlang/dmd/pull/9844#issuecomment-498479516). | DMD has a mostly flat directory structure, so this section aims to divide all source files into logical groups for easier navigation. The groups are roughly ordered by how late they appear in the compilation process. @@ -31,26 +31,26 @@ Note that these groups have no strict meaning, the category assignments are a bi | File | Purpose | |-----------------------------------------------------------------------------|-----------------------------------------------------------------------| -| [mars.d](https://github.com/dlang/dmd/blob/master/src/dmd/mars.d) | The entry point. Contains `main`. | -| [cli.d](https://github.com/dlang/dmd/blob/master/src/dmd/cli.d) | Define the command line interface | -| [dmdparams.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmdparams.d) | DMD-specific parameters | -| [globals.d](https://github.com/dlang/dmd/blob/master/src/dmd/globals.d) | Define a structure storing command line options | -| [dinifile.d](https://github.com/dlang/dmd/blob/master/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) | -| [vsoptions.d](https://github.com/dlang/dmd/blob/master/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking | -| [frontend.d](https://github.com/dlang/dmd/blob/master/src/dmd/frontend.d) | An interface for using DMD as a library | -| [errors.d](https://github.com/dlang/dmd/blob/master/src/dmd/errors.d) | Error reporting functionality | -| [target.d](https://github.com/dlang/dmd/blob/master/src/dmd/target.d) | Manage target-specific parameters for cross-compiling (for LDC/GDC) | -| [compiler.d](https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d) | Describe a back-end compiler and implements compiler-specific actions | +| [mars.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mars.d) | The entry point. Contains `main`. | +| [cli.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cli.d) | Define the command line interface | +| [dmdparams.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmdparams.d) | DMD-specific parameters | +| [globals.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/globals.d) | Define a structure storing command line options | +| [dinifile.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) | +| [vsoptions.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking | +| [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 functionality | +| [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 | ### Lexing / parsing | File | Purpose | |-----------------------------------------------------------------------|----------------------------------------------------------------------| -| [lexer.d](https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d) | Convert source code into tokens for the D and ImportC parsers | -| [entity.d](https://github.com/dlang/dmd/blob/master/src/dmd/entity.d) | Define "\\&Entity;" escape sequence for strings / character literals | -| [tokens.d](https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d) | Define lexical tokens. | -| [parse.d](https://github.com/dlang/dmd/blob/master/src/dmd/parse.d) | D parser, converting tokens into an Abstract Syntax Tree (AST) | -| [cparse.d](https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d) | ImportC parser, converting tokens into an Abstract Syntax Tree (AST) | +| [lexer.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lexer.d) | Convert source code into tokens for the D and ImportC parsers | +| [entity.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/entity.d) | Define "\\&Entity;" escape sequence for strings / character literals | +| [tokens.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/tokens.d) | Define lexical tokens. | +| [parse.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/parse.d) | D parser, converting tokens into an Abstract Syntax Tree (AST) | +| [cparse.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cparse.d) | ImportC parser, converting tokens into an Abstract Syntax Tree (AST) | ### Semantic analysis @@ -58,88 +58,88 @@ Note that these groups have no strict meaning, the category assignments are a bi | File | Purpose | |---------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------| -| [dsymbol.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d) | Base class for a D symbol, e.g. a variable, function, module, enum etc. | -| [identifier.d](https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d) | Represents the name of a `Dsymbol` | -| [id.d](https://github.com/dlang/dmd/blob/master/src/dmd/id.d) | Define strings for pre-defined identifiers (e.g. `sizeof`, `string`) | -| [dscope.d](https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d) | Define a 'scope' on which symbol lookup can be performed | -| [dtemplate.d](https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d) | A template declaration or instance | -| [dmodule.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d) | Define a package and module | -| [mtype.d](https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d) | Define expression types such as `int`, `char[]`, `void function()` | -| [arraytypes.d](https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d) | For certain Declaration nodes of type `T`, provides aliases for `Array!T` | -| [declaration.d](https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d) | Misc. declarations of `alias`, variables, type tuples, `ClassInfo` etc. | -| [denum.d](https://github.com/dlang/dmd/blob/master/src/dmd/denum.d) | Defines `enum` declarations and enum members | -| [attrib.d](https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d) | Declarations of 'attributes' such as `private`, `pragma()`, `immutable`, `@UDA`, `align`, `extern(C++)` and more | -| [func.d](https://github.com/dlang/dmd/blob/master/src/dmd/func.d) | Define a function declaration (includes function literals, `invariant`, `unittest`) | -| [dversion.d](https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d) | Defines a version symbol, e.g. `version = ident`, `debug = ident` | +| [dsymbol.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbol.d) | Base class for a D symbol, e.g. a variable, function, module, enum etc. | +| [identifier.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/identifier.d) | Represents the name of a `Dsymbol` | +| [id.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/id.d) | Define strings for pre-defined identifiers (e.g. `sizeof`, `string`) | +| [dscope.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dscope.d) | Define a 'scope' on which symbol lookup can be performed | +| [dtemplate.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dtemplate.d) | A template declaration or instance | +| [dmodule.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmodule.d) | Define a package and module | +| [mtype.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mtype.d) | Define expression types such as `int`, `char[]`, `void function()` | +| [arraytypes.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/arraytypes.d) | For certain Declaration nodes of type `T`, provides aliases for `Array!T` | +| [declaration.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/declaration.d) | Misc. declarations of `alias`, variables, type tuples, `ClassInfo` etc. | +| [denum.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/denum.d) | Defines `enum` declarations and enum members | +| [attrib.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/nogc.d) | Declarations of 'attributes' such as `private`, `pragma()`, `immutable`, `@UDA`, `align`, `extern(C++)` and more | +| [func.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/func.d) | Define a function declaration (includes function literals, `invariant`, `unittest`) | +| [dversion.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dversion.d) | Defines a version symbol, e.g. `version = ident`, `debug = ident` | **AST nodes** | File | Purpose | |-----------------------------------------------------------------------------------|-------------------------------------------------------------| -| [ast_node.d](https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d) | Define an abstract AST node class | -| [astbase.d](https://github.com/dlang/dmd/blob/master/src/dmd/astbase.d) | Namespace of AST nodes that can be produced by the parser | -| [astcodegen.d](https://github.com/dlang/dmd/blob/master/src/dmd/astcodegen.d) | Namespace of AST nodes of a AST ready for code generation | -| [astenums.d](https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d) | Enums common to DMD and AST | -| [expression.d](https://github.com/dlang/dmd/blob/master/src/dmd/expression.d) | Define expression AST nodes | -| [statement.d](https://github.com/dlang/dmd/blob/master/src/dmd/statement.d) | Define statement AST nodes | -| [staticassert.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d) | Define a `static assert` AST node | -| [aggregate.d](https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d) | Define an aggregate (`struct`, `union` or `class`) AST node | -| [dclass.d](https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d) | Define a `class` AST node | -| [dstruct.d](https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d) | Define a `struct` or `union` AST node | -| [init.d](https://github.com/dlang/dmd/blob/master/src/dmd/init.d) | Define variable initializers | +| [ast_node.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ast_node.d) | Define an abstract AST node class | +| [astbase.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/astbase.d) | Namespace of AST nodes that can be produced by the parser | +| [astcodegen.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/astcodegen.d) | Namespace of AST nodes of a AST ready for code generation | +| [astenums.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/astenums.d) | Enums common to DMD and AST | +| [expression.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expression.d) | Define expression AST nodes | +| [statement.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statement.d) | Define statement AST nodes | +| [staticassert.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/staticassert.d) | Define a `static assert` AST node | +| [aggregate.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/aggregate.d) | Define an aggregate (`struct`, `union` or `class`) AST node | +| [dclass.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dclass.d) | Define a `class` AST node | +| [dstruct.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dstruct.d) | Define a `struct` or `union` AST node | +| [init.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/init.d) | Define variable initializers | **AST visitors** | File | Purpose | |-----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------| -| [parsetimevisitor.d](https://github.com/dlang/dmd/blob/master/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/src/dmd/permissivevisitor.d) | Subclass of ParseTimeVisitor that does not `assert(0)` on unimplemented nodes | -| [strictvisitor.d](https://github.com/dlang/dmd/blob/master/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/src/dmd/visitor.d) | A visitor implementing `visit` for all nodes present in the compiler | -| [transitivevisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/transitivevisitor.d) | Provide a mixin template with visit methods for the parse time AST | -| [apply.d](https://github.com/dlang/dmd/blob/master/src/dmd/apply.d) | Depth-first expression visitor | -| [sapply.d](https://github.com/dlang/dmd/blob/master/src/dmd/sapply.d) | Depth-first statement visitor | -| [statement_rewrite_walker.d](https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d) | Statement visitor that allows replacing the currently visited node | +| [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 | +| [apply.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/apply.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 | **Semantic passes** | File | Purpose | |-------------------------------------------------------------------------------------------|-------------------------------------------------------------------| -| [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) | -| [semantic2.d](https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d) | Do semantic 2 pass (symbol initializers) | -| [semantic3.d](https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d) | Do semantic 3 pass (function bodies) | -| [inline.d](https://github.com/dlang/dmd/blob/master/src/dmd/inline.d) | Do inline pass (optimization pass that dmd does in the front-end) | -| [inlinecost.d](https://github.com/dlang/dmd/blob/master/src/dmd/inlinecost.d) | Compute the cost of inlining a function call. | -| [expressionsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d) | Do semantic analysis for expressions | -| [statementsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d) | Do semantic analysis for statements | -| [initsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d) | Do semantic analysis for initializers | -| [templateparamsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters | -| [typesem.d](https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d) | Do semantic analysis for types | +| [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) | +| [semantic2.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic2.d) | Do semantic 2 pass (symbol initializers) | +| [semantic3.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/semantic3.d) | Do semantic 3 pass (function bodies) | +| [inline.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/inline.d) | Do inline pass (optimization pass that dmd does in the front-end) | +| [inlinecost.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/inlinecost.d) | Compute the cost of inlining a function call. | +| [expressionsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/expressionsem.d) | Do semantic analysis for expressions | +| [statementsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/statementsem.d) | Do semantic analysis for statements | +| [initsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/initsem.d) | Do semantic analysis for initializers | +| [templateparamsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters | +| [typesem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typesem.d) | Do semantic analysis for types | **Semantic helpers** | File | Purpose | |-------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| -| [opover.d](https://github.com/dlang/dmd/blob/master/src/dmd/opover.d) | Operator overloading | -| [clone.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d) | Generate automatic `opEquals`, `opAssign` and constructors for structs | -| [blockexit.d](https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d) | Find out in what ways control flow can exit a block | -| [ctorflow.d](https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d) | Control flow in constructors | -| [constfold.d](https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d) | Do constant folding of arithmetic expressions | -| [optimize.d](https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d) | Do constant folding more generally | -| [dcast.d](https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d) | Implicit or explicit cast(), finding common types e.g. in `x ? a : b`, integral promotions | -| [impcnvtab.d](https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d) | Define an implicit conversion table for basic types | -| [importc.d](https://github.com/dlang/dmd/blob/master/src/dmd/importc.d) | Helpers specific to ImportC | -| [sideeffect.d](https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings. | -| [mustuse.d](https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d) | Helpers related to the `@mustuse` attribute | +| [opover.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/opover.d) | Operator overloading | +| [clone.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d) | Generate automatic `opEquals`, `opAssign` and constructors for structs | +| [blockexit.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/blockexit.d) | Find out in what ways control flow can exit a block | +| [ctorflow.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ctorflow.d) | Control flow in constructors | +| [constfold.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/constfold.d) | Do constant folding of arithmetic expressions | +| [optimize.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/optimize.d) | Do constant folding more generally | +| [dcast.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dcast.d) | Implicit or explicit cast(), finding common types e.g. in `x ? a : b`, integral promotions | +| [impcnvtab.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/impcnvtab.d) | Define an implicit conversion table for basic types | +| [importc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/importc.d) | Helpers specific to ImportC | +| [sideeffect.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings. | +| [mustuse.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mustuse.d) | Helpers related to the `@mustuse` attribute | **Compile Time Function Execution (CTFE)** | File | Purpose | |-------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| -| [dinterpret.d](https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d) | CTFE entry point | -| [ctfeexpr.d](https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d) | CTFE for expressions involving pointers, slices, array concatenation etc. | -| [builtin.d](https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d) | Allow CTFE of certain external functions (`core.math`, `std.math` and `core.bitop`) | +| [dinterpret.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dinterpret.d) | CTFE entry point | +| [ctfeexpr.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ctfeexpr.d) | CTFE for expressions involving pointers, slices, array concatenation etc. | +| [builtin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/builtin.d) | Allow CTFE of certain external functions (`core.math`, `std.math` and `core.bitop`) | ### Specific language features @@ -147,116 +147,116 @@ Note that these groups have no strict meaning, the category assignments are a bi | File | Purpose | |---------------------------------------------------------------------------|----------------------------------------| -| [nogc.d](https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d) | `@nogc` checks | -| [safe.d](https://github.com/dlang/dmd/blob/master/src/dmd/safe.d) | `@safe` checks | -| [canthrow.d](https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d) | `nothrow` checks | -| [escape.d](https://github.com/dlang/dmd/blob/master/src/dmd/escape.d) | `scope` checks | -| [access.d](https://github.com/dlang/dmd/blob/master/src/dmd/access.d) | `public` / `private` checks | -| [ob.d](https://github.com/dlang/dmd/blob/master/src/dmd/ob.d) | Ownership / borrowing (`@live`) checks | +| [nogc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/nogc.d) | `@nogc` checks | +| [safe.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/safe.d) | `@safe` checks | +| [canthrow.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/canthrow.d) | `nothrow` checks | +| [escape.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/escape.d) | `scope` checks | +| [access.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/access.d) | `public` / `private` checks | +| [ob.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/ob.d) | Ownership / borrowing (`@live`) checks | **Inline Assembly** | File | Purpose | |-------------------------------------------------------------------------|-------------------------------------------| -| [iasm.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasm.d) | Inline assembly depending on the compiler | -| [iasmdmd.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasmdmd.d) | Inline assembly for DMD | -| [iasmgcc.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d) | Inline assembly for GDC | +| [iasm.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasm.d) | Inline assembly depending on the compiler | +| [iasmdmd.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasmdmd.d) | Inline assembly for DMD | +| [iasmgcc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/iasmgcc.d) | Inline assembly for GDC | **Other** | File | Purpose | |--------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| -| [aliasthis.d](https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d) | Resolve implicit conversions for `alias X this` | -| [traits.d](https://github.com/dlang/dmd/blob/master/src/dmd/traits.d) | `__traits()` | -| [lambdacomp.d](https://github.com/dlang/dmd/blob/master/src/dmd/lambdacomp.d) | `__traits(isSame, x => y, z => w)` | -| [cond.d](https://github.com/dlang/dmd/blob/master/src/dmd/cond.d) | Evaluate `static if`, `version` `debug ` | -| [staticcond.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d) | Lazily evaluate static conditions for `static if`, `static assert` and template constraints | -| [delegatize.d](https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d) | Converts expression to delegates for `lazy` parameters | -| [eh.d](https://github.com/dlang/dmd/blob/master/src/dmd/eh.d) | Generate tables for exception handling | -| [nspace.d](https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d) | Namespace for `extern (C++, Module)` | -| [intrange.d](https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d) | [Value range propagation](https://digitalmars.com/articles/b62.html) | -| [dimport.d](https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d) | Renamed imports (`import aliasSymbol = pkg1.pkg2.symbol`) | -| [arrayop.d](https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d) | Array operations (`a[] = b[] + c[]`) | -| [cpreprocess.d](https://github.com/dlang/dmd/blob/master/src/dmd/cpreprocess.d)| Run the C preprocessor on C source files | -| [typinf.d](https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d) | Generate typeinfo for `typeid()` (as well as internals) | +| [aliasthis.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/aliasthis.d) | Resolve implicit conversions for `alias X this` | +| [traits.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/traits.d) | `__traits()` | +| [lambdacomp.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lambdacomp.d) | `__traits(isSame, x => y, z => w)` | +| [cond.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cond.d) | Evaluate `static if`, `version` `debug ` | +| [staticcond.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/staticcond.d) | Lazily evaluate static conditions for `static if`, `static assert` and template constraints | +| [delegatize.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/delegatize.d) | Converts expression to delegates for `lazy` parameters | +| [eh.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/eh.d) | Generate tables for exception handling | +| [nspace.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/nspace.d) | Namespace for `extern (C++, Module)` | +| [intrange.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/intrange.d) | [Value range propagation](https://digitalmars.com/articles/b62.html) | +| [dimport.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dimport.d) | Renamed imports (`import aliasSymbol = pkg1.pkg2.symbol`) | +| [arrayop.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/arrayop.d) | Array operations (`a[] = b[] + c[]`) | +| [cpreprocess.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cpreprocess.d)| Run the C preprocessor on C source files | +| [typinf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/typinf.d) | Generate typeinfo for `typeid()` (as well as internals) | | File | Purpose | |-----------------------------------------------------------------------------|------------------------------------------------------------------------------------| -| [chkformat.d](https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d) | Validate arguments with format specifiers for `printf` / `scanf` etc. | -| [imphint.d](https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d) | Give a suggestion to e.g. `import std.stdio` when `writeln` could not be resolved. | +| [chkformat.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/chkformat.d) | Validate arguments with format specifiers for `printf` / `scanf` etc. | +| [imphint.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/imphint.d) | Give a suggestion to e.g. `import std.stdio` when `writeln` could not be resolved. | ### Library files | File | Purpose | |-------------------------------------------------------------------------------|------------------------------------------------------| -| [lib.d](https://github.com/dlang/dmd/blob/master/src/dmd/lib.d) | Abstract library class | -| [libelf.d](https://github.com/dlang/dmd/blob/master/src/dmd/libelf.d) | Library in ELF format (Unix) | -| [libmach.d](https://github.com/dlang/dmd/blob/master/src/dmd/libmach.d) | Library in Mach-O format (macOS) | -| [libmscoff.d](https://github.com/dlang/dmd/blob/master/src/dmd/libmscoff.d) | Library in COFF format (32/64-bit Windows) | -| [libomf.d](https://github.com/dlang/dmd/blob/master/src/dmd/libomf.d) | Library in OMF format (legacy 32-bit Windows) | -| [scanelf.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanelf.d) | Extract symbol names from a library in ELF format | -| [scanmach.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanmach.d) | Extract symbol names from a library in Mach-O format | -| [scanmscoff.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanmscoff.d) | Extract symbol names from a library in COFF format | -| [scanomf.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanomf.d) | Extract symbol names from a library in OMF format | +| [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 | ### Code generation / back-end interfacing | File | Purpose | |---------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| -| [dmsc.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmsc.d) | Configures and initializes the back-end | -| [toobj.d](https://github.com/dlang/dmd/blob/master/src/dmd/toobj.d) | Convert an AST that went through all semantic phases into an object file | -| [toir.d](https://github.com/dlang/dmd/blob/master/src/dmd/toir.d) | Convert Dsymbols intermediate representation | -| [e2ir.d](https://github.com/dlang/dmd/blob/master/src/dmd/e2ir.d) | Convert Expressions to intermediate representation | -| [s2ir.d](https://github.com/dlang/dmd/blob/master/src/dmd/s2ir.d) | Convert Statements to intermediate representation | -| [stmtstate.d](https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d) | Used to help transform statement AST into flow graph | -| [toctype.d](https://github.com/dlang/dmd/blob/master/src/dmd/toctype.d) | Convert a D type to a type the back-end understands | -| [tocsym.d](https://github.com/dlang/dmd/blob/master/src/dmd/tocsym.d) | Convert a D symbol to a symbol the linker understands (with mangled name) | -| [argtypes_x86.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_x86.d) | Convert a D type into simple (register) types for the 32-bit x86 ABI | -| [argtypes_sysv_x64.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_sysv_x64.d) | 'argtypes' for the x86_64 System V ABI | -| [argtypes_aarch64.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_aarch64.d) | 'argtypes' for the AArch64 ABI | -| [glue.d](https://github.com/dlang/dmd/blob/master/src/dmd/glue.d) | Generate the object file for function declarations | -| [gluelayer.d](https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d) | Declarations for back-end functions that the front-end invokes | -| [todt.d](https://github.com/dlang/dmd/blob/master/src/dmd/todt.d) | Convert initializers into structures that the back-end will add to the data segment | -| [tocvdebug.d](https://github.com/dlang/dmd/blob/master/src/dmd/tovcdebug.d) | Generate debug info in the CV4 debug format. | -| [objc.d](https://github.com/dlang/dmd/blob/master/src/dmd/objc.d) | Objective-C interfacing | -| [objc_glue.d](https://github.com/dlang/dmd/blob/master/src/dmd/objc_glue.d) | Glue code for Objective-C interop. | +| [dmsc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmsc.d) | Configures and initializes the back-end | +| [toobj.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/toobj.d) | Convert an AST that went through all semantic phases into an object file | +| [toir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/toir.d) | Convert Dsymbols intermediate representation | +| [e2ir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/e2ir.d) | Convert Expressions to intermediate representation | +| [s2ir.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/s2ir.d) | Convert Statements to intermediate representation | +| [stmtstate.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/stmtstate.d) | Used to help transform statement AST into flow graph | +| [toctype.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/toctype.d) | Convert a D type to a type the back-end understands | +| [tocsym.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/tocsym.d) | Convert a D symbol to a symbol the linker understands (with mangled name) | +| [argtypes_x86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_x86.d) | Convert a D type into simple (register) types for the 32-bit x86 ABI | +| [argtypes_sysv_x64.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_sysv_x64.d) | 'argtypes' for the x86_64 System V ABI | +| [argtypes_aarch64.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/argtypes_aarch64.d) | 'argtypes' for the AArch64 ABI | +| [glue.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/glue.d) | Generate the object file for function declarations | +| [gluelayer.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/gluelayer.d) | Declarations for back-end functions that the front-end invokes | +| [todt.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/todt.d) | Convert initializers into structures that the back-end will add to the data segment | +| [tocvdebug.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/tovcdebug.d) | Generate debug info in the CV4 debug format. | +| [objc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/objc.d) | Objective-C interfacing | +| [objc_glue.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/objc_glue.d) | Glue code for Objective-C interop. | **Name mangling** | File | Purpose | |-----------------------------------------------------------------------------------|------------------------------------------------------------------| -| [cppmangle.d](https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d) | C++ name mangling | -| [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/src/dmd/cppmanglewin.d) | C++ name mangling for Windows | -| [dmangle.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) | +| [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 | +| [dmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) | ### Linking | File | Purpose | |-------------------------------------------------------------------|-----------------------------------------| -| [link.d](https://github.com/dlang/dmd/blob/master/src/dmd/link.d) | Invoke the linker as a separate process | +| [link.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/link.d) | Invoke the linker as a separate process | ### Special output | File | Purpose | |-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------| -| [doc.d](https://github.com/dlang/dmd/blob/master/src/dmd/doc.d) | [Documentation generation](https://dlang.org/spec/ddoc.html) | -| [dmacro.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d) | DDoc macro processing | -| [hdrgen.d](https://github.com/dlang/dmd/blob/master/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/src/dmd/json.d) | Describe the module in a `.json` file for the `-X` flag | -| [dtoh.d](https://github.com/dlang/dmd/blob/master/src/dmd/dtoh.d) | C++ header generation from D source files | +| [doc.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/doc.d) | [Documentation generation](https://dlang.org/spec/ddoc.html) | +| [dmacro.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmacro.d) | DDoc macro processing | +| [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 | ### Utility -Note: many other utilities are in [dmd/root](https://github.com/dlang/dmd/tree/master/src/dmd/root). +Note: many other utilities are in [dmd/root](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/root). | File | Purpose | |-----------------------------------------------------------------------------------|---------------------------------------------------| -| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d) | Print error messages in color | -| [file_manager.d](https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d) | Keep file contents in memory | -| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d) | Utility functions related to files and file paths | +| [console.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/console.d) | Print error messages in color | +| [file_manager.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/file_manager.d) | Keep file contents in memory | +| [utils.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/utils.d) | Utility functions related to files and file paths | | File | Purpose | |---------------------------------------------------------------------------------|---------------------------------------------------------------| -| [asttypename.d](https://github.com/dlang/dmd/blob/master/src/dmd/asttypename.d) | Print the internal name of an AST node (for debugging only) | -| [printast.d](https://github.com/dlang/dmd/blob/master/src/dmd/printast.d) | Print the AST data structure | -| [foreachvar.d](https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d) | Used in `ob.d` to iterate over all variables in an expression | +| [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/astenums.d b/gcc/d/dmd/astenums.d index bf19693..091e96a 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -68,7 +68,6 @@ enum STC : ulong // transfer changes to declaration.h ref_ = 0x4_0000, /// `ref` scope_ = 0x8_0000, /// `scope` - maybescope = 0x10_0000, /// parameter might be `scope` scopeinferred = 0x20_0000, /// `scope` has been inferred and should not be part of mangling, `scope_` must also be set return_ = 0x40_0000, /// 'return ref' or 'return scope' for function parameters returnScope = 0x80_0000, /// if `ref return scope` then resolve to `ref` and `return scope` diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index fe6e1e3..088ca61 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -114,8 +114,10 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN import dmd.id : Id; auto sd = ts.sym; + const id = ce.f.ident; if (sd.postblit && - (ce.f.ident == Id._d_arrayctor || ce.f.ident == Id._d_arraysetctor)) + (id == Id._d_arrayctor || id == Id._d_arraysetctor || + id == Id._d_arrayassign_l || id == Id._d_arrayassign_r)) { checkFuncThrows(ce, sd.postblit); return; diff --git a/gcc/d/dmd/common/README.md b/gcc/d/dmd/common/README.md index fb282dc..853fd4f 100644 --- a/gcc/d/dmd/common/README.md +++ b/gcc/d/dmd/common/README.md @@ -2,7 +2,7 @@ | File | Purpose | |------------------------------------------------------------------------------------|-----------------------------------------------------------------| -| [bitfields.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d) | Pack multiple boolean fields into bit fields | -| [file.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d) | Functions and objects dedicated to file I/O and management | -| [outbuffer.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data | -| [string.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d) | Common string functions including filename manipulation | +| [bitfields.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/bitfields.d) | Pack multiple boolean fields into bit fields | +| [file.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/file.d) | Functions and objects dedicated to file I/O and management | +| [outbuffer.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data | +| [string.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/common/string.d) | Common string functions including filename manipulation | diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index 9a5bd82..9d544a4 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -109,12 +109,12 @@ struct OutBuffer } /// For porting with ease from dmd.backend.outbuf.Outbuffer - ubyte* buf() nothrow { + ubyte* buf() nothrow @system { return data.ptr; } /// For porting with ease from dmd.backend.outbuf.Outbuffer - ubyte** bufptr() nothrow { + ubyte** bufptr() nothrow @system { static struct Array { size_t length; ubyte* ptr; } auto a = cast(Array*) &data; assert(a.length == data.length && a.ptr == data.ptr); @@ -156,7 +156,7 @@ struct OutBuffer Params: nbytes = the number of additional bytes to reserve */ - extern (C++) void reserve(size_t nbytes) pure nothrow + extern (C++) void reserve(size_t nbytes) pure nothrow @trusted { //debug (stomp) printf("OutBuffer::reserve: size = %lld, offset = %lld, nbytes = %lld\n", data.length, offset, nbytes); const minSize = offset + nbytes; @@ -210,7 +210,7 @@ struct OutBuffer offset = 0; } - private void indent() pure nothrow + private void indent() pure nothrow @safe { if (level) { @@ -223,19 +223,19 @@ struct OutBuffer } // Write an array to the buffer, no reserve check - @trusted nothrow + @system nothrow void writen(const void *b, size_t len) { memcpy(data.ptr + offset, b, len); offset += len; } - extern (C++) void write(const(void)* data, size_t nbytes) pure nothrow + extern (C++) void write(const(void)* data, size_t nbytes) pure nothrow @system { write(data[0 .. nbytes]); } - void write(const(void)[] buf) pure nothrow + void write(scope const(void)[] buf) pure nothrow @trusted { if (doindent && !notlinehead) indent(); @@ -282,7 +282,7 @@ struct OutBuffer } /// NOT zero-terminated - extern (C++) void writestring(const(char)* s) pure nothrow + extern (C++) void writestring(const(char)* s) pure nothrow @system { if (!s) return; @@ -291,19 +291,19 @@ struct OutBuffer } /// ditto - void writestring(const(char)[] s) pure nothrow + void writestring(scope const(char)[] s) pure nothrow @safe { write(s); } /// ditto - void writestring(string s) pure nothrow + void writestring(scope string s) pure nothrow @safe { write(s); } /// NOT zero-terminated, followed by newline - void writestringln(const(char)[] s) pure nothrow + void writestringln(const(char)[] s) pure nothrow @safe { writestring(s); writenl(); @@ -311,25 +311,25 @@ struct OutBuffer /** Write string to buffer, ensure it is zero terminated */ - void writeStringz(const(char)* s) pure nothrow @trusted + void writeStringz(const(char)* s) pure nothrow @system { write(s[0 .. strlen(s)+1]); } /// ditto - void writeStringz(const(char)[] s) pure nothrow + void writeStringz(const(char)[] s) pure nothrow @safe { write(s); writeByte(0); } /// ditto - void writeStringz(string s) pure nothrow + void writeStringz(string s) pure nothrow @safe { writeStringz(cast(const(char)[])(s)); } - extern (C++) void prependstring(const(char)* string) pure nothrow + extern (C++) void prependstring(const(char)* string) pure nothrow @system { size_t len = strlen(string); reserve(len); @@ -339,7 +339,7 @@ struct OutBuffer } /// write newline - extern (C++) void writenl() pure nothrow + extern (C++) void writenl() pure nothrow @safe { version (Windows) { @@ -385,7 +385,7 @@ struct OutBuffer this.data[offset++] = cast(ubyte) b; } - extern (C++) void writeByte(uint b) pure nothrow + extern (C++) void writeByte(uint b) pure nothrow @safe { if (doindent && !notlinehead && b != '\n') indent(); @@ -394,7 +394,7 @@ struct OutBuffer offset++; } - extern (C++) void writeUTF8(uint b) pure nothrow + extern (C++) void writeUTF8(uint b) pure nothrow @safe { reserve(6); if (b <= 0x7F) @@ -427,7 +427,7 @@ struct OutBuffer assert(0); } - extern (C++) void prependbyte(uint b) pure nothrow + extern (C++) void prependbyte(uint b) pure nothrow @trusted { reserve(1); memmove(data.ptr + 1, data.ptr, offset); @@ -435,7 +435,7 @@ struct OutBuffer offset++; } - extern (C++) void writewchar(uint w) pure nothrow + extern (C++) void writewchar(uint w) pure nothrow @safe { version (Windows) { @@ -447,7 +447,7 @@ struct OutBuffer } } - extern (C++) void writeword(uint w) pure nothrow + extern (C++) void writeword(uint w) pure nothrow @trusted { version (Windows) { @@ -465,7 +465,7 @@ struct OutBuffer offset += 2; } - extern (C++) void writeUTF16(uint w) pure nothrow + extern (C++) void writeUTF16(uint w) pure nothrow @trusted { reserve(4); if (w <= 0xFFFF) @@ -483,7 +483,7 @@ struct OutBuffer assert(0); } - extern (C++) void write4(uint w) pure nothrow + extern (C++) void write4(uint w) pure nothrow @trusted { version (Windows) { @@ -500,7 +500,7 @@ struct OutBuffer offset += 4; } - extern (C++) void write(const OutBuffer* buf) pure nothrow + extern (C++) void write(const OutBuffer* buf) pure nothrow @trusted { if (buf) { @@ -510,7 +510,7 @@ struct OutBuffer } } - extern (C++) void fill0(size_t nbytes) pure nothrow + extern (C++) void fill0(size_t nbytes) pure nothrow @trusted { reserve(nbytes); memset(data.ptr + offset, 0, nbytes); @@ -531,7 +531,7 @@ struct OutBuffer return cast(char[])data[offset - nbytes .. offset]; } - extern (C++) void vprintf(const(char)* format, va_list args) nothrow + extern (C++) void vprintf(const(char)* format, va_list args) nothrow @system { int count; if (doindent && !notlinehead) @@ -567,7 +567,7 @@ struct OutBuffer static if (__VERSION__ < 2092) { - extern (C++) void printf(const(char)* format, ...) nothrow + extern (C++) void printf(const(char)* format, ...) nothrow @system { va_list ap; va_start(ap, format); @@ -577,7 +577,7 @@ struct OutBuffer } else { - pragma(printf) extern (C++) void printf(const(char)* format, ...) nothrow + pragma(printf) extern (C++) void printf(const(char)* format, ...) nothrow @system { va_list ap; va_start(ap, format); @@ -591,13 +591,13 @@ struct OutBuffer * Params: * u = integral value to append */ - extern (C++) void print(ulong u) pure nothrow + extern (C++) void print(ulong u) pure nothrow @safe { UnsignedStringBuf buf = void; writestring(unsignedToTempString(u, buf)); } - extern (C++) void bracket(char left, char right) pure nothrow + extern (C++) void bracket(char left, char right) pure nothrow @trusted { reserve(2); memmove(data.ptr + 1, data.ptr, offset); @@ -610,7 +610,7 @@ struct OutBuffer * Insert left at i, and right at j. * Return index just past right. */ - extern (C++) size_t bracket(size_t i, const(char)* left, size_t j, const(char)* right) pure nothrow + extern (C++) size_t bracket(size_t i, const(char)* left, size_t j, const(char)* right) pure nothrow @system { size_t leftlen = strlen(left); size_t rightlen = strlen(right); @@ -620,7 +620,7 @@ struct OutBuffer return j + leftlen + rightlen; } - extern (C++) void spread(size_t offset, size_t nbytes) pure nothrow + extern (C++) void spread(size_t offset, size_t nbytes) pure nothrow @system { reserve(nbytes); memmove(data.ptr + offset + nbytes, data.ptr + offset, this.offset - offset); @@ -630,19 +630,19 @@ struct OutBuffer /**************************************** * Returns: offset + nbytes */ - extern (C++) size_t insert(size_t offset, const(void)* p, size_t nbytes) pure nothrow + extern (C++) size_t insert(size_t offset, const(void)* p, size_t nbytes) pure nothrow @system { spread(offset, nbytes); memmove(data.ptr + offset, p, nbytes); return offset + nbytes; } - size_t insert(size_t offset, const(char)[] s) pure nothrow + size_t insert(size_t offset, const(char)[] s) pure nothrow @system { return insert(offset, s.ptr, s.length); } - extern (C++) void remove(size_t offset, size_t nbytes) pure nothrow @nogc + extern (C++) void remove(size_t offset, size_t nbytes) pure nothrow @nogc @system { memmove(data.ptr + offset, data.ptr + offset + nbytes, this.offset - (offset + nbytes)); this.offset -= nbytes; @@ -716,7 +716,7 @@ struct OutBuffer return extractData(); } - void writesLEB128(int value) pure nothrow + void writesLEB128(int value) pure nothrow @safe { while (1) { @@ -733,7 +733,7 @@ struct OutBuffer } } - void writeuLEB128(uint value) pure nothrow + void writeuLEB128(uint value) pure nothrow @safe { do { @@ -758,7 +758,7 @@ struct OutBuffer Returns: `true` iff the operation succeeded. */ - extern(D) bool moveToFile(const char* filename) + extern(D) bool moveToFile(const char* filename) @system { bool result = true; const bool identical = this[] == FileMapping!(const ubyte)(filename)[]; @@ -799,7 +799,7 @@ private: alias UnsignedStringBuf = char[20]; -char[] unsignedToTempString(ulong value, char[] buf, uint radix = 10) @safe pure nothrow @nogc +char[] unsignedToTempString(ulong value, return scope char[] buf, uint radix = 10) @safe pure nothrow @nogc { size_t i = buf.length; do diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 11229d4..6243e74 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -357,15 +357,31 @@ UnionExp copyLiteral(Expression e) r.origin = sle.origin; return ue; } - if (e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.symbolOffset || e.op == EXP.null_ || e.op == EXP.variable || e.op == EXP.dotVariable || e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.char_ || e.op == EXP.complex80 || e.op == EXP.void_ || e.op == EXP.vector || e.op == EXP.typeid_) - { + + switch(e.op) + { + case EXP.function_: + case EXP.delegate_: + case EXP.symbolOffset: + case EXP.null_: + case EXP.variable: + case EXP.dotVariable: + case EXP.int64: + case EXP.float64: + case EXP.char_: + case EXP.complex80: + case EXP.void_: + case EXP.vector: + case EXP.typeid_: // Simple value types // Keep e1 for DelegateExp and DotVarExp emplaceExp!(UnionExp)(&ue, e); Expression r = ue.exp(); r.type = e.type; return ue; + default: break; } + if (auto se = e.isSliceExp()) { if (se.type.toBasetype().ty == Tsarray) diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index ffb33d3..ff27e37 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -563,8 +563,9 @@ extern (C++) abstract class Declaration : Dsymbol extern (C++) final class TupleDeclaration : Declaration { Objects* objects; - bool isexp; // true: expression tuple TypeTuple tupletype; // !=null if this is a type tuple + bool isexp; // true: expression tuple + bool building; // it's growing in AliasAssign semantic extern (D) this(const ref Loc loc, Identifier ident, Objects* objects) { @@ -588,7 +589,7 @@ extern (C++) final class TupleDeclaration : Declaration */ //printf("TupleDeclaration::getType() %s\n", toChars()); - if (isexp) + if (isexp || building) return null; if (!tupletype) { @@ -931,6 +932,19 @@ extern (C++) final class AliasDeclaration : Declaration } else { + // stop AliasAssign tuple building + if (aliassym) + { + if (auto td = aliassym.isTupleDeclaration()) + { + if (td.building) + { + td.building = false; + semanticRun = PASS.semanticdone; + return td; + } + } + } if (_import && _import._scope) { /* If this is an internal alias for selective/renamed import, @@ -1076,7 +1090,7 @@ 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; // STC.maybescope variables that are assigned to this STC.maybescope variable + 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; @@ -1105,7 +1119,7 @@ extern (C++) class VarDeclaration : Declaration bool overlapped; /// if it is a field and has overlapping bool overlapUnsafe; /// if it is an overlapping field and the overlaps are unsafe - bool doNotInferScope; /// do not infer 'scope' for this variable + bool maybeScope; /// allow inferring 'scope' for this variable bool doNotInferReturn; /// do not infer 'return' for this variable bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index c8f6c2a..bc8db44 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -59,7 +59,6 @@ struct AttributeViolation; #define STCref 0x40000ULL /// `ref` #define STCscope 0x80000ULL /// `scope` - #define STCmaybescope 0x100000ULL /// parameter might be `scope` #define STCscopeinferred 0x200000ULL /// `scope` has been inferred and should not be part of mangling, `scope` must also be set #define STCreturn 0x400000ULL /// 'return ref' or 'return scope' for function parameters #define STCreturnScope 0x800000ULL /// if `ref return scope` then resolve to `ref` and `return scope` @@ -166,9 +165,9 @@ class TupleDeclaration final : public Declaration { public: Objects *objects; - bool isexp; // true: expression tuple - TypeTuple *tupletype; // !=NULL if this is a type tuple + bool isexp; // true: expression tuple + bool building; // it's growing in AliasAssign semantic TupleDeclaration *syntaxCopy(Dsymbol *) override; const char *kind() const override; @@ -264,8 +263,8 @@ public: bool overlapped(bool v); bool overlapUnsafe() const; // if it is an overlapping field and the overlaps are unsafe bool overlapUnsafe(bool v); - bool doNotInferScope() const; // do not infer 'scope' for this variable - bool doNotInferScope(bool v); + bool maybeScope() const; // allow inferring 'scope' for this variable + bool maybeScope(bool v); bool doNotInferReturn() const; // do not infer 'return' for this variable bool doNotInferReturn(bool v); bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index 156cce2..5cc3772 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -223,7 +223,16 @@ extern (C++) final class Import : Dsymbol override void importAll(Scope* sc) { if (mod) return; // Already done - load(sc); + + /* + * https://issues.dlang.org/show_bug.cgi?id=15525 + * + * Loading the import has failed, + * most likely because of parsing errors. + * Therefore we cannot trust the resulting AST. + */ + if (load(sc)) return; + if (!mod) return; // Failed if (sc.stc & STC.static_) diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 890c3b6..a9fd0f5 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -4778,6 +4778,12 @@ public: // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it. removeHookTraceImpl(e, fd); + bool isArrayConstructionOrAssign(FuncDeclaration fd) + { + return fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor || + fd.ident == Id._d_arrayassign_l || fd.ident == Id._d_arrayassign_r; + } + if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor) { assert(e.arguments.dim == 1); @@ -4831,27 +4837,36 @@ public: result = interpretRegion(ae, istate); return; } - else if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor) + else if (isArrayConstructionOrAssign(fd)) { - // In expressionsem.d `T[x] ea = eb;` was lowered to `_d_array{,set}ctor(ea[], eb[]);`. - // The following code will rewrite it back to `ea = eb` and then interpret that expression. - if (fd.ident == Id._d_arraysetctor) - assert(e.arguments.dim == 2); - else + // In expressionsem.d, the following lowerings were performed: + // * `T[x] ea = eb;` to `_d_array{,set}ctor(ea[], eb[]);`. + // * `ea = eb` (ea and eb are arrays) to `_d_arrayassign_{l,r}(ea[], eb[])`. + // The following code will rewrite them back to `ea = eb` and + // then interpret that expression. + + if (fd.ident == Id._d_arrayctor) assert(e.arguments.dim == 3); + else + assert(e.arguments.dim == 2); Expression ea = (*e.arguments)[0]; if (ea.isCastExp) ea = ea.isCastExp.e1; Expression eb = (*e.arguments)[1]; - if (eb.isCastExp && fd.ident == Id._d_arrayctor) + if (eb.isCastExp() && fd.ident != Id._d_arraysetctor) eb = eb.isCastExp.e1; - ConstructExp ce = new ConstructExp(e.loc, ea, eb); - ce.type = ea.type; + Expression rewrittenExp; + if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor) + rewrittenExp = new ConstructExp(e.loc, ea, eb); + else + rewrittenExp = new AssignExp(e.loc, ea, eb); + + rewrittenExp.type = ea.type; + result = interpret(rewrittenExp, istate); - result = interpret(ce, istate); return; } else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendTTrace) diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d index 9beac6b..358712b 100644 --- a/gcc/d/dmd/dmacro.d +++ b/gcc/d/dmd/dmacro.d @@ -14,8 +14,6 @@ module dmd.dmacro; import core.stdc.ctype; import core.stdc.string; import dmd.doc; -import dmd.errors; -import dmd.globals; import dmd.common.outbuffer; import dmd.root.rmem; @@ -28,7 +26,7 @@ extern (C++) struct MacroTable * name = name of macro * text = text of macro */ - extern (D) void define(const(char)[] name, const(char)[] text) + extern (D) void define(const(char)[] name, const(char)[] text) nothrow pure @safe { //printf("MacroTable::define('%.*s' = '%.*s')\n", cast(int)name.length, name.ptr, text.length, text.ptr); if (auto table = name in mactab) @@ -42,8 +40,10 @@ extern (C++) struct MacroTable /***************************************************** * Look for macros in buf and expand them in place. * Only look at the text in buf from start to pend. + * + * Returns: `true` on success, `false` when the recursion limit was reached */ - extern (D) void expand(ref OutBuffer buf, size_t start, ref size_t pend, const(char)[] arg) + extern (D) bool expand(ref OutBuffer buf, size_t start, ref size_t pend, const(char)[] arg, int recursionLimit) nothrow pure { version (none) { @@ -51,14 +51,10 @@ extern (C++) struct MacroTable printf("Buf is: '%.*s'\n", cast(int)(pend - start), buf.data + start); } // limit recursive expansion - __gshared int nest; - if (nest > global.recursionLimit) - { - error(Loc.initial, "DDoc macro expansion limit exceeded; more than %d expansions.", - global.recursionLimit); - return; - } - nest++; + recursionLimit--; + if (recursionLimit < 0) + return false; + size_t end = pend; assert(start <= end); assert(end <= buf.length); @@ -105,7 +101,9 @@ extern (C++) struct MacroTable end += marg.length - 2; // Scan replaced text for further expansion size_t mend = u + marg.length; - expand(buf, u, mend, null); + const success = expand(buf, u, mend, null, recursionLimit); + if (!success) + return false; end += mend - (u + marg.length); u = mend; } @@ -121,7 +119,9 @@ extern (C++) struct MacroTable end += -2 + 2 + marg.length + 2; // Scan replaced text for further expansion size_t mend = u + 2 + marg.length; - expand(buf, u + 2, mend, null); + const success = expand(buf, u + 2, mend, null, recursionLimit); + if (!success) + return false; end += mend - (u + 2 + marg.length); u = mend; } @@ -228,7 +228,9 @@ extern (C++) struct MacroTable // Scan replaced text for further expansion m.inuse++; size_t mend = v + 1 + 2 + m.text.length + 2; - expand(buf, v + 1, mend, marg); + const success = expand(buf, v + 1, mend, marg, recursionLimit); + if (!success) + return false; end += mend - (v + 1 + 2 + m.text.length + 2); m.inuse--; buf.remove(u, v + 1 - u); @@ -253,12 +255,12 @@ extern (C++) struct MacroTable } mem.xfree(cast(char*)arg); pend = end; - nest--; + return true; } private: - extern (D) Macro* search(const(char)[] name) + extern (D) Macro* search(const(char)[] name) @nogc nothrow pure @safe { //printf("Macro::search(%.*s)\n", cast(int)name.length, name.ptr); if (auto table = name in mactab) @@ -282,7 +284,7 @@ struct Macro const(char)[] text; // macro replacement text int inuse; // macro is in use (don't expand) - this(const(char)[] name, const(char)[] text) + this(const(char)[] name, const(char)[] text) @nogc nothrow pure @safe { this.name = name; this.text = text; @@ -297,7 +299,7 @@ struct Macro * copy allocated with mem.xmalloc() */ -char[] memdup(const(char)[] p) +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]; @@ -312,7 +314,7 @@ char[] memdup(const(char)[] p) * 1..9: get nth argument * -1: get 2nd through end */ -size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) +size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) @nogc nothrow pure { /* Scan forward for matching right parenthesis. * Nest parentheses. diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 5e802da..2cb1cc7 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -325,7 +325,6 @@ extern (C++) final class Module : Package extern (C++) __gshared Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them extern (C++) __gshared Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them extern (C++) __gshared Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them - extern (C++) __gshared uint dprogress; // progress resolving the deferred list static void _init() { @@ -1300,19 +1299,22 @@ extern (C++) final class Module : Package extern (D) static void addDeferredSemantic(Dsymbol s) { //printf("Module::addDeferredSemantic('%s')\n", s.toChars()); - deferred.push(s); + if (!deferred.contains(s)) + deferred.push(s); } extern (D) static void addDeferredSemantic2(Dsymbol s) { //printf("Module::addDeferredSemantic2('%s')\n", s.toChars()); - deferred2.push(s); + if (!deferred2.contains(s)) + deferred2.push(s); } extern (D) static void addDeferredSemantic3(Dsymbol s) { //printf("Module::addDeferredSemantic3('%s')\n", s.toChars()); - deferred3.push(s); + if (!deferred.contains(s)) + deferred3.push(s); } /****************************************** @@ -1320,19 +1322,15 @@ extern (C++) final class Module : Package */ static void runDeferredSemantic() { - if (dprogress == 0) - return; - __gshared int nested; if (nested) return; - //if (deferred.dim) printf("+Module::runDeferredSemantic(), len = %d\n", deferred.dim); + //if (deferred.dim) printf("+Module::runDeferredSemantic(), len = %ld\n", deferred.dim); nested++; size_t len; do { - dprogress = 0; len = deferred.dim; if (!len) break; @@ -1358,13 +1356,13 @@ extern (C++) final class Module : Package s.dsymbolSemantic(null); //printf("deferred: %s, parent = %s\n", s.toChars(), s.parent.toChars()); } - //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); + //printf("\tdeferred.dim = %ld, len = %ld\n", deferred.dim, len); if (todoalloc) free(todoalloc); } - while (deferred.dim < len || dprogress); // while making progress + while (deferred.dim != len); // while making progress nested--; - //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.dim); + //printf("-Module::runDeferredSemantic(), len = %ld\n", deferred.dim); } static void runDeferredSemantic2() diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 6eb433e..ba83649 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -226,12 +226,12 @@ private final class ParamSection : Section buf.writestring("$(DDOC_PARAM_ID "); { size_t o = buf.length; - Parameter fparam = isFunctionParameter(a, namestart, namelen); + Parameter fparam = isFunctionParameter(a, namestart[0 .. namelen]); if (!fparam) { // Comments on a template might refer to function parameters within. // Search the parameters of nested eponymous functions (with the same name.) - fparam = isEponymousFunctionParameter(a, namestart, namelen); + fparam = isEponymousFunctionParameter(a, namestart[0 .. namelen]); } bool isCVariadic = isCVariadicParameter(a, namestart[0 .. namelen]); if (isCVariadic) @@ -328,7 +328,7 @@ private final class MacroSection : Section private alias Sections = Array!(Section); // Workaround for missing Parameter instance for variadic params. (it's unnecessary to instantiate one). -private bool isCVariadicParameter(Dsymbols* a, const(char)[] p) +private bool isCVariadicParameter(Dsymbols* a, const(char)[] p) @safe { foreach (member; *a) { @@ -339,7 +339,7 @@ private bool isCVariadicParameter(Dsymbols* a, const(char)[] p) return false; } -private Dsymbol getEponymousMember(TemplateDeclaration td) +private Dsymbol getEponymousMember(TemplateDeclaration td) @safe { if (!td.onemember) return null; @@ -456,7 +456,11 @@ extern(C++) void gendocfile(Module m) OutBuffer buf2; buf2.writestring("$(DDOC)"); size_t end = buf2.length; - m.macrotable.expand(buf2, 0, end, null); + + const success = m.macrotable.expand(buf2, 0, end, null, global.recursionLimit); + if (!success) + error(Loc.initial, "DDoc macro expansion limit exceeded; more than %d expansions.", global.recursionLimit); + version (all) { /* Remove all the escape sequences from buf2, @@ -2561,17 +2565,17 @@ private size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref /**************************************************** */ -private bool isIdentifier(Dsymbols* a, const(char)* p, size_t len) +private bool isIdentifier(Dsymbols* a, const(char)[] s) { foreach (member; *a) { if (auto imp = member.isImport()) { // For example: `public import str = core.stdc.string;` - // This checks if `p` is equal to `str` + // This checks if `s` is equal to `str` if (imp.aliasId) { - if (p[0 .. len] == imp.aliasId.toString()) + if (s == imp.aliasId.toString()) return true; } else @@ -2586,14 +2590,14 @@ private bool isIdentifier(Dsymbols* a, const(char)* p, size_t len) } fullyQualifiedImport ~= imp.id.toString(); - // Check if `p` == `core.stdc.string` - if (p[0 .. len] == fullyQualifiedImport) + // Check if `s` == `core.stdc.string` + if (s == fullyQualifiedImport) return true; } } else if (member.ident) { - if (p[0 .. len] == member.ident.toString()) + if (s == member.ident.toString()) return true; } @@ -2603,12 +2607,12 @@ private bool isIdentifier(Dsymbols* a, const(char)* p, size_t len) /**************************************************** */ -private bool isKeyword(const(char)* p, size_t len) +private bool isKeyword(const(char)[] str) @safe { immutable string[3] table = ["true", "false", "null"]; foreach (s; table) { - if (p[0 .. len] == s) + if (str == s) return true; } return false; @@ -2616,7 +2620,7 @@ private bool isKeyword(const(char)* p, size_t len) /**************************************************** */ -private TypeFunction isTypeFunction(Dsymbol s) +private TypeFunction isTypeFunction(Dsymbol s) @safe { FuncDeclaration f = s.isFuncDeclaration(); /* f.type may be NULL for template members. @@ -2632,14 +2636,14 @@ private TypeFunction isTypeFunction(Dsymbol s) /**************************************************** */ -private Parameter isFunctionParameter(Dsymbol s, const(char)* p, size_t len) +private Parameter isFunctionParameter(Dsymbol s, const(char)[] str) @safe { TypeFunction tf = isTypeFunction(s); if (tf && tf.parameterList.parameters) { foreach (fparam; *tf.parameterList.parameters) { - if (fparam.ident && p[0 .. len] == fparam.ident.toString()) + if (fparam.ident && str == fparam.ident.toString()) { return fparam; } @@ -2650,11 +2654,11 @@ private Parameter isFunctionParameter(Dsymbol s, const(char)* p, size_t len) /**************************************************** */ -private Parameter isFunctionParameter(Dsymbols* a, const(char)* p, size_t len) +private Parameter isFunctionParameter(Dsymbols* a, const(char)[] p) @safe { - for (size_t i = 0; i < a.dim; i++) + foreach (Dsymbol sym; *a) { - Parameter fparam = isFunctionParameter((*a)[i], p, len); + Parameter fparam = isFunctionParameter(sym, p); if (fparam) { return fparam; @@ -2665,11 +2669,11 @@ private Parameter isFunctionParameter(Dsymbols* a, const(char)* p, size_t len) /**************************************************** */ -private Parameter isEponymousFunctionParameter(Dsymbols *a, const(char) *p, size_t len) +private Parameter isEponymousFunctionParameter(Dsymbols *a, const(char)[] p) @safe { - for (size_t i = 0; i < a.dim; i++) + foreach (Dsymbol dsym; *a) { - TemplateDeclaration td = (*a)[i].isTemplateDeclaration(); + TemplateDeclaration td = dsym.isTemplateDeclaration(); if (td && td.onemember) { /* Case 1: we refer to a template declaration inside the template @@ -2688,7 +2692,7 @@ private Parameter isEponymousFunctionParameter(Dsymbols *a, const(char) *p, size /// ...ddoc... alias case2 = case1!int; */ - AliasDeclaration ad = (*a)[i].isAliasDeclaration(); + AliasDeclaration ad = dsym.isAliasDeclaration(); if (ad && ad.aliassym) { td = ad.aliassym.isTemplateDeclaration(); @@ -2699,7 +2703,7 @@ private Parameter isEponymousFunctionParameter(Dsymbols *a, const(char) *p, size Dsymbol sym = getEponymousMember(td); if (sym) { - Parameter fparam = isFunctionParameter(sym, p, len); + Parameter fparam = isFunctionParameter(sym, p); if (fparam) { return fparam; @@ -4956,17 +4960,17 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s i = buf.bracket(i, "$(DDOC_AUTO_PSYMBOL_SUPPRESS ", j - 1, ")") - 1; break; } - if (isIdentifier(a, start, len)) + if (isIdentifier(a, start[0 .. len])) { i = buf.bracket(i, "$(DDOC_AUTO_PSYMBOL ", j, ")") - 1; break; } - if (isKeyword(start, len)) + if (isKeyword(start[0 .. len])) { i = buf.bracket(i, "$(DDOC_AUTO_KEYWORD ", j, ")") - 1; break; } - if (isFunctionParameter(a, start, len)) + if (isFunctionParameter(a, start[0 .. len])) { //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j); i = buf.bracket(i, "$(DDOC_AUTO_PARAM ", j, ")") - 1; @@ -5055,7 +5059,7 @@ private void highlightCode(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t off if (i < j) { size_t len = j - i; - if (isIdentifier(a, start, len)) + if (isIdentifier(a, start[0 .. len])) { i = buf.bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; continue; @@ -5066,12 +5070,12 @@ private void highlightCode(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t off if (i < j) { size_t len = j - i; - if (isIdentifier(a, start, len)) + if (isIdentifier(a, start[0 .. len])) { i = buf.bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; continue; } - if (isFunctionParameter(a, start, len)) + if (isFunctionParameter(a, start[0 .. len])) { //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j); i = buf.bracket(i, "$(DDOC_PARAM ", j, ")") - 1; @@ -5195,12 +5199,12 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of if (!sc) break; size_t len = lex.p - tok.ptr; - if (isIdentifier(a, tok.ptr, len)) + if (isIdentifier(a, tok.ptr[0 .. len])) { highlight = "$(D_PSYMBOL "; break; } - if (isFunctionParameter(a, tok.ptr, len)) + if (isFunctionParameter(a, tok.ptr[0 .. len])) { //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j); highlight = "$(D_PARAM "; @@ -5246,7 +5250,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of /**************************************** * Determine if p points to the start of a "..." parameter identifier. */ -private bool isCVariadicArg(const(char)[] p) +private bool isCVariadicArg(const(char)[] p) @nogc nothrow pure @safe { return p.length >= 3 && p[0 .. 3] == "..."; } @@ -5254,7 +5258,7 @@ private bool isCVariadicArg(const(char)[] p) /**************************************** * Determine if p points to the start of an identifier. */ -bool isIdStart(const(char)* p) +bool isIdStart(const(char)* p) @nogc nothrow pure { dchar c = *p; if (isalpha(c) || c == '_') @@ -5273,7 +5277,7 @@ bool isIdStart(const(char)* p) /**************************************** * Determine if p points to the rest of an identifier. */ -bool isIdTail(const(char)* p) +bool isIdTail(const(char)* p) @nogc nothrow pure { dchar c = *p; if (isalnum(c) || c == '_') @@ -5292,7 +5296,7 @@ bool isIdTail(const(char)* p) /**************************************** * Determine if p points to the indentation space. */ -private bool isIndentWS(const(char)* p) +private bool isIndentWS(const(char)* p) @nogc nothrow pure @safe { return (*p == ' ') || (*p == '\t'); } @@ -5300,7 +5304,7 @@ private bool isIndentWS(const(char)* p) /***************************************** * Return number of bytes in UTF character. */ -int utfStride(const(char)* p) +int utfStride(const(char)* p) @nogc nothrow pure { dchar c = *p; if (c < 0x80) @@ -5310,7 +5314,7 @@ int utfStride(const(char)* p) return cast(int)i; } -private inout(char)* stripLeadingNewlines(inout(char)* s) +private inout(char)* stripLeadingNewlines(inout(char)* s) @nogc nothrow pure { while (s && *s == '\n' || *s == '\r') s++; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 7f57cbe..c3424dc 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -359,6 +359,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym.overlapped = true; dsym.sequenceNumber = global.varSequenceNumber++; + if (!dsym.isScope()) + dsym.maybeScope = true; Scope* scx = null; if (dsym._scope) @@ -2034,8 +2036,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor ed.semanticRun = PASS.semanticdone; return; } - uint dprogress_save = Module.dprogress; - Scope* scx = null; if (ed._scope) { @@ -2093,7 +2093,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { // memtype is forward referenced, so try again later deferDsymbolSemantic(ed, scx); - Module.dprogress = dprogress_save; //printf("\tdeferring %s\n", toChars()); ed.semanticRun = PASS.initial; return; @@ -2134,8 +2133,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done ed.semanticRun = PASS.semanticdone; - Module.dprogress++; - // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint // Deprecated in 2.100 // Make an error in 2.110 @@ -3945,7 +3942,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (funcdecl.canInferAttributes(sc)) funcdecl.initInferAttributes(); - Module.dprogress++; funcdecl.semanticRun = PASS.semanticdone; /* Save scope for possible later use (if we need the @@ -4669,7 +4665,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sd.inv = buildInv(sd, sc2); - Module.dprogress++; sd.semanticRun = PASS.semanticdone; //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd.toChars()); @@ -5329,7 +5324,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor cldec.inv = buildInv(cldec, sc2); - Module.dprogress++; cldec.semanticRun = PASS.semanticdone; //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); @@ -5676,7 +5670,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor idec.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) ); - Module.dprogress++; idec.semanticRun = PASS.semanticdone; //printf("-InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type); @@ -6332,6 +6325,10 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* * resolve the alias of eponymous member. */ tempinst.aliasdecl = tempinst.aliasdecl.toAlias2(); + + // stop AliasAssign tuple building + if (auto td = tempinst.aliasdecl.isTupleDeclaration()) + td.building = false; } Laftersemantic: @@ -6726,13 +6723,28 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc) */ const errors = global.errors; + Dsymbol s; + + // Try AliasSeq optimization + if (auto ti = ds.type.isTypeInstance()) + { + if (!ti.tempinst.findTempDecl(sc, null)) + return errorRet(); + if (auto tempinst = isAliasSeq(sc, ti)) + { + s = aliasAssignInPlace(sc, tempinst, aliassym); + if (!s) + return errorRet(); + goto Lsymdone; + } + } /* This section is needed because Type.resolve() will: * const x = 3; * alias y = x; * try to convert identifier x to 3. */ - auto s = ds.type.toDsymbol(sc); + s = ds.type.toDsymbol(sc); if (errors != global.errors) return errorRet(); if (s == aliassym) @@ -6784,6 +6796,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc) if (s) // it's a symbolic alias { + Lsymdone: //printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars()); aliassym.type = null; aliassym.aliassym = s; @@ -6813,6 +6826,135 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc) } /*************************************** + * Expands template instance arguments inside 'alias assign' target declaration (aliassym), + * instead of inside 'tempinst.tiargs' every time. + * Params: + * tempinst = AliasSeq instance + * aliassym = the AliasDeclaration corresponding to AliasAssign + * Returns: + * null. + */ +private TupleDeclaration aliasAssignInPlace(Scope* sc, TemplateInstance tempinst, + AliasDeclaration aliassym) +{ + // Mark instance with semantic done, not needed but just in case. + tempinst.inst = tempinst; + tempinst.semanticRun = PASS.semanticdone; + TupleDeclaration td; + if (aliassym.type) + { + // Convert TypeTuple to TupleDeclaration to avoid back and forth allocations + // in the assignment process + if (auto tt = aliassym.type.isTypeTuple()) + { + auto objs = new Objects(tt.arguments.length); + foreach (i, p; *tt.arguments) + (*objs)[i] = p.type; + td = new TupleDeclaration(tempinst.loc, aliassym.ident, objs); + td.storage_class |= STC.templateparameter; + td.building = true; + aliassym.type = null; + } + else if (aliassym.type.isTypeError()) + return null; + + } + else if (auto otd = aliassym.aliassym.isTupleDeclaration()) + { + if (otd.building) + td = otd; + else + { + td = new TupleDeclaration(tempinst.loc, aliassym.ident, otd.objects.copy()); + td.storage_class |= STC.templateparameter; + td.building = true; + } + } + // If starting from single element in aliassym (td == null) we need to build the tuple + // after semanticTiargs to keep same semantics (for example a FuncLiteraldeclaration + // template argument is converted to FuncExp) + if (td) + aliassym.aliassym = td; + aliassym.semanticRun = PASS.semanticdone; + if (!TemplateInstance.semanticTiargs(tempinst.loc, sc, tempinst.tiargs, 0, td)) + { + tempinst.errors = true; + return null; + } + // The alias will stop tuple 'building' mode when used (in AliasDeclaration.toAlias(), + // then TupleDeclaration.getType() will work again) + aliassym.semanticRun = PASS.initial; + if (!td) + { + td = new TupleDeclaration(tempinst.loc, aliassym.ident, tempinst.tiargs); + td.storage_class |= STC.templateparameter; + td.building = true; + return td; + } + + auto tiargs = tempinst.tiargs; + size_t oldlen = td.objects.length; + size_t origstart; + size_t insertidx; + size_t insertlen; + foreach (i, o; *tiargs) + { + if (o !is td) + { + ++insertlen; + continue; + } + // tuple contains itself (tuple = AliasSeq!(..., tuple, ...)) + if (insertlen) // insert any left element before + { + td.objects.insert(insertidx, (*tiargs)[i - insertlen .. i]); + if (insertidx == 0) // reset original tuple start point + origstart = insertlen; + insertlen = 0; + } + if (insertidx) // insert tuple if found more than one time + { + td.objects.reserve(oldlen); // reserve first to assert a valid slice + td.objects.pushSlice((*td.objects)[origstart .. origstart + oldlen]); + } + insertidx = td.objects.length; + } + if (insertlen) + { + if (insertlen != tiargs.length) // insert any left element + td.objects.pushSlice((*tiargs)[$ - insertlen .. $]); + else + // just assign tiargs if tuple = AliasSeq!(nottuple, nottuple...) + td.objects = tempinst.tiargs; + } + return td; +} + +/*************************************** + * Check if a template instance is a trivial AliasSeq but without other overloads. + * We can only be 100% sure of being AliasSeq after running semanticTiargs() + * and findBestMatch() but this optimization must happen before that. + */ +private TemplateInstance isAliasSeq(Scope* sc, TypeInstance ti) +{ + auto tovers = ti.tempinst.tempdecl.isOverloadSet(); + foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1) + { + Dsymbol dstart = tovers ? tovers.a[oi] : ti.tempinst.tempdecl; + int r = overloadApply(dstart, (Dsymbol s) + { + auto td = s.isTemplateDeclaration(); + if (!td || !td.isTrivialAliasSeq) + return 1; + return 0; + }); + if (r) + return null; + } + return ti.tempinst; +} + +/*************************************** * Find all instance fields in `ad`, then push them into `fields`. * * Runs semantic() for all instance field variables, but also diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 02f12e4..34cae1d 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -6564,10 +6564,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol * tiargs array of template arguments * flags 1: replace const variables with their initializers * 2: don't devolve Parameter to Type + * atd tuple being optimized. If found, it's not expanded here + * but in AliasAssign semantic. * Returns: * false if one or more arguments have errors. */ - extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags) + extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags, TupleDeclaration atd = null) { // Run semantic on each argument, place results in tiargs[] //printf("+TemplateInstance.semanticTiargs()\n"); @@ -6767,6 +6769,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol TupleDeclaration d = sa.toAlias().isTupleDeclaration(); if (d) { + if (d is atd) + { + (*tiargs)[j] = d; + continue; + } // Expand tuple tiargs.remove(j); tiargs.insert(j, d.objects); diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index fb5e092..4f06bac 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -36,6 +36,21 @@ import dmd.tokens; import dmd.visitor; import dmd.arraytypes; +/// Groups global state for escape checking together +package(dmd) struct EscapeState +{ + // Maps `sequenceNumber` of a `VarDeclaration` to an object that contains the + // reason it failed to infer `scope` + // https://issues.dlang.org/show_bug.cgi?id=23295 + private __gshared RootObject[int] scopeInferFailure; + + /// Called by `initDMD` / `deinitializeDMD` to reset global state + static void reset() + { + scopeInferFailure = null; + } +} + /****************************************************** * Checks memory objects passed to a function. * Checks that if a memory object is passed by ref or by pointer, @@ -271,6 +286,40 @@ bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag) return errors; } +/** + * A `scope` variable was assigned to non-scope parameter `v`. + * If applicable, print why the parameter was not inferred `scope`. + * + * Params: + * printFunc = error/deprecation print function to use + * v = parameter that was not inferred + * recursionLimit = recursion limit for printing the reason + */ +void printScopeFailure(E)(E printFunc, VarDeclaration v, int recursionLimit) +{ + recursionLimit--; + if (recursionLimit < 0 || !v) + return; + + if (RootObject* o = v.sequenceNumber in EscapeState.scopeInferFailure) + { + switch ((*o).dyncast()) + { + case DYNCAST.expression: + Expression e = cast(Expression) *o; + printFunc(e.loc, "which is not `scope` because of `%s`", e.toChars()); + break; + case DYNCAST.dsymbol: + VarDeclaration v1 = cast(VarDeclaration) *o; + printFunc(v1.loc, "which is assigned to non-scope parameter `%s`", v1.toChars()); + printScopeFailure(printFunc, v1, recursionLimit); + break; + default: + assert(0); + } + } +} + /**************************************** * Function parameter `par` is being initialized to `arg`, * and `par` may escape. @@ -280,6 +329,7 @@ bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag) * sc = used to determine current function and module * fdc = function being called, `null` if called indirectly * par = function parameter (`this` if null) + * vPar = `VarDeclaration` corresponding to `par` * parStc = storage classes of function parameter (may have added `scope` from `pure`) * arg = initializer for param * assertmsg = true if the parameter is the msg argument to assert(bool, msg). @@ -287,7 +337,7 @@ bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag) * Returns: * `true` if pointers to the stack can escape via assignment */ -bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC parStc, Expression arg, bool assertmsg, bool gag) +bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, VarDeclaration vPar, STC parStc, Expression arg, bool assertmsg, bool gag) { enum log = false; if (log) printf("checkParamArgumentEscape(arg: %s par: %s)\n", @@ -327,13 +377,21 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC } else if (par) { - result |= sc.setUnsafeDIP1000(gag, arg.loc, - desc ~ " `%s` assigned to non-scope parameter `%s` calling `%s`", v, par, fdc); + if (sc.setUnsafeDIP1000(gag, arg.loc, + desc ~ " `%s` assigned to non-scope parameter `%s` calling `%s`", v, par, fdc)) + { + result = true; + printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), vPar, 10); + } } else { - result |= sc.setUnsafeDIP1000(gag, arg.loc, - desc ~ " `%s` assigned to non-scope parameter `this` calling `%s`", v, fdc); + if (sc.setUnsafeDIP1000(gag, arg.loc, + desc ~ " `%s` assigned to non-scope parameter `this` calling `%s`", v, fdc)) + { + result = true; + printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), fdc.vthis, 10); + } } } @@ -345,7 +403,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC Dsymbol p = v.toParent2(); - notMaybeScope(v); + notMaybeScope(v, vPar); if (v.isScope()) { @@ -366,7 +424,8 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC */ if (log) printf("no infer for %s in %s loc %s, fdc %s, %d\n", v.toChars(), sc.func.ident.toChars(), sc.func.loc.toChars(), fdc.ident.toChars(), __LINE__); - v.doNotInferScope = true; + + doNotInferScope(v, vPar); } } @@ -378,7 +437,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC Dsymbol p = v.toParent2(); - notMaybeScope(v); + notMaybeScope(v, arg); if (checkScopeVarAddr(v, arg, sc, gag)) { result = true; @@ -405,7 +464,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC Dsymbol p = v.toParent2(); - notMaybeScope(v); + notMaybeScope(v, arg); if ((v.isReference() || v.isScope()) && p == sc.func) { @@ -553,7 +612,16 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) return false; if (e1.isSliceExp()) - return false; + { + 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); @@ -650,7 +718,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (va && !vaIsRef && !va.isScope() && !v.isScope() && !v.isTypesafeVariadicParameter && !va.isTypesafeVariadicParameter && - (va.storage_class & v.storage_class & STC.maybescope) && + (va.isParameter() && va.maybeScope && v.isParameter() && v.maybeScope) && p == fd) { /* Add v to va's list of dependencies @@ -660,7 +728,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } if (vaIsFirstRef && - (v.isScope() || (v.storage_class & STC.maybescope)) && + (v.isScope() || v.maybeScope) && !(v.storage_class & STC.return_) && v.isParameter() && fd.flags & FUNCFLAG.returnInprocess && @@ -672,7 +740,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } if (!(va && va.isScope()) || vaIsRef) - notMaybeScope(v); + notMaybeScope(v, e); if (v.isScope()) { @@ -682,7 +750,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (va.isScope()) continue; - if (!va.doNotInferScope) + if (va.maybeScope) { if (log) printf("inferring scope for lvalue %s\n", va.toChars()); va.storage_class |= STC.scope_ | STC.scopeinferred; @@ -711,7 +779,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } } - if (va && !va.isDataseg() && !va.doNotInferScope) + if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) { if (!va.isScope()) { /* v is scope, and va is not scope, so va needs to @@ -742,7 +810,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) Type tb = v.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) { - if (va && !va.isDataseg() && !va.doNotInferScope) + if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) { if (!va.isScope()) { //printf("inferring scope for %s\n", va.toChars()); @@ -759,7 +827,7 @@ 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__); - v.doNotInferScope = true; + doNotInferScope(v, e); } } @@ -812,12 +880,12 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } if (!(va && va.isScope())) - notMaybeScope(v); + notMaybeScope(v, e); if (p != sc.func) continue; - if (va && !va.isDataseg() && !va.doNotInferScope) + if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) { if (!va.isScope()) { //printf("inferring scope for %s\n", va.toChars()); @@ -855,12 +923,12 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) Dsymbol p = v.toParent2(); if (!(va && va.isScope())) - notMaybeScope(v); + notMaybeScope(v, e); if (!(v.isReference() || v.isScope()) || p != fd) continue; - if (va && !va.isDataseg() && !va.doNotInferScope) + if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) { /* Don't infer STC.scope_ for va, because then a closure * won't be generated for fd. @@ -891,7 +959,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } if (ee.op == EXP.call && ee.type.toBasetype().isTypeStruct() && - (!va || !(va.storage_class & STC.temp))) + (!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)) { @@ -910,7 +978,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } } - if (va && !va.isDataseg() && !va.doNotInferScope) + if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) { if (!va.isScope()) { //printf("inferring scope for %s\n", va.toChars()); @@ -963,8 +1031,7 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag) } else { - //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__); - v.doNotInferScope = true; + notMaybeScope(v, new ThrowExp(e.loc, e)); } } return result; @@ -1036,7 +1103,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) else { //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__); - v.doNotInferScope = true; + notMaybeScope(v, e); } } @@ -1191,7 +1258,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) Dsymbol p = v.toParent2(); - if ((v.isScope() || (v.storage_class & STC.maybescope)) && + if ((v.isScope() || v.maybeScope) && !(v.storage_class & STC.return_) && v.isParameter() && !v.doNotInferReturn && @@ -1266,7 +1333,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) else { //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__); - v.doNotInferScope = true; + doNotInferScope(v, e); } } @@ -1330,7 +1397,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) if (!refs) { if (sc.func.vthis == v) - notMaybeScope(v); + notMaybeScope(v, e); if (checkScopeVarAddr(v, e, sc, gag)) { @@ -2226,26 +2293,41 @@ public void findAllOuterAccessedVariables(FuncDeclaration fd, VarDeclarations* v } /*********************************** - * Turn off `STC.maybescope` for variable `v`. + * Turn off `maybeScope` for variable `v`. * - * This exists in order to find where `STC.maybescope` is getting turned off. + * This exists in order to find where `maybeScope` is getting turned off. * Params: * v = variable + * o = reason for it being turned off: + * - `Expression` such as `throw e` or `&e` + * - `VarDeclaration` of a non-scope parameter it was assigned to + * - `null` for no reason */ -version (none) +private void notMaybeScope(VarDeclaration v, RootObject o) { - private void notMaybeScope(string file = __FILE__, int line = __LINE__)(VarDeclaration v) + if (v.maybeScope) { - printf("%.*s(%d): notMaybeScope('%s')\n", cast(int)file.length, file.ptr, line, v.toChars()); - v.storage_class &= ~STC.maybescope; + v.maybeScope = false; + if (o && v.isParameter()) + EscapeState.scopeInferFailure[v.sequenceNumber] = o; } } -else + +/*********************************** + * 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) { - private void notMaybeScope(VarDeclaration v) - { - v.storage_class &= ~STC.maybescope; - } + if (!v.isParameter) + notMaybeScope(v, o); } /*********************************** @@ -2259,6 +2341,7 @@ else */ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) { + if (funcdecl.flags & FUNCFLAG.returnInprocess) { funcdecl.flags &= ~FUNCFLAG.returnInprocess; @@ -2273,6 +2356,8 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) } } + if (!(funcdecl.flags & FUNCFLAG.inferScope)) + return; funcdecl.flags &= ~FUNCFLAG.inferScope; // Eliminate maybescope's @@ -2305,20 +2390,19 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) foreach (u, p; f.parameterList) { auto v = (*funcdecl.parameters)[u]; - if (v.storage_class & STC.maybescope) + if (v.maybeScope) { //printf("Inferring scope for %s\n", v.toChars()); - notMaybeScope(v); + notMaybeScope(v, null); v.storage_class |= STC.scope_ | STC.scopeinferred; p.storageClass |= STC.scope_ | STC.scopeinferred; - assert(!(p.storageClass & STC.maybescope)); } } } - if (funcdecl.vthis && funcdecl.vthis.storage_class & STC.maybescope) + if (funcdecl.vthis && funcdecl.vthis.maybeScope) { - notMaybeScope(funcdecl.vthis); + notMaybeScope(funcdecl.vthis, null); funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred; f.isScopeQual = true; f.isscopeinferred = true; @@ -2358,17 +2442,17 @@ private void eliminateMaybeScopes(VarDeclaration[] array) foreach (va; array) { if (log) printf(" va = %s\n", va.toChars()); - if (!(va.storage_class & (STC.maybescope | STC.scope_))) + if (!(va.maybeScope || va.isScope())) { if (va.maybes) { foreach (v; *va.maybes) { if (log) printf(" v = %s\n", v.toChars()); - if (v.storage_class & STC.maybescope) + if (v.maybeScope) { // v cannot be scope since it is assigned to a non-scope va - notMaybeScope(v); + notMaybeScope(v, va); if (!v.isReference()) v.storage_class &= ~(STC.return_ | STC.returninferred); changes = true; @@ -2485,7 +2569,7 @@ private bool enclosesLifetimeOf(const VarDeclaration va, const VarDeclaration v) * analysis for the function is completed. Thus, we save the data * until then. * Params: - * v = an `STC.maybescope` variable that was assigned to `this` + * v = a variable with `maybeScope == true` that was assigned to `this` */ private void addMaybe(VarDeclaration va, VarDeclaration v) { @@ -2570,8 +2654,7 @@ private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool g if (!v.isScope()) { - v.storage_class &= ~STC.maybescope; - v.doNotInferScope = true; + notMaybeScope(v, e); return false; } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 397a41b..f871fade 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -5153,7 +5153,7 @@ extern (C++) final class CallExp : UnaExp /* Type needs destruction, so declare a tmp * which the back end will recognize and call dtor on */ - auto tmp = copyToTemp(0, "__tmpfordtor", this); + auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), this); auto de = new DeclarationExp(loc, tmp); auto ve = new VarExp(loc, tmp); Expression e = new CommaExp(loc, de, ve); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 30baabd..3114100 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -2044,7 +2044,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc, /* Argument value can escape from the called function. * Check arg to see if it matters. */ - err |= checkParamArgumentEscape(sc, fd, p, cast(STC) pStc, arg, false, false); + VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null; + err |= checkParamArgumentEscape(sc, fd, p, vPar, cast(STC) pStc, arg, false, false); } // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference @@ -4726,7 +4727,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, null, STC.undefined_, ethis, false, false)) + if (checkParamArgumentEscape(sc, exp.f, null, null, STC.undefined_, ethis, false, false)) return setError(); } } @@ -6388,7 +6389,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, STC.undefined_, exp.msg, true, false); + checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false); } if (exp.msg && exp.msg.op == EXP.error) @@ -9934,7 +9935,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (isArrayCtor || isArraySetCtor) { const ts = t1b.nextOf().baseElemOf().isTypeStruct(); - if (!ts || (!ts.sym.postblit && !ts.sym.dtor)) + if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor)) return setResult(res); auto func = isArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor; @@ -9976,10 +9977,89 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor message("lowered %s =>\n %s", exp.toChars(), res.toChars()); } } + else if (auto ae = res.isAssignExp()) + res = lowerArrayAssign(ae); + else if (auto ce = res.isCommaExp()) + { + if (auto ae1 = ce.e1.isAssignExp()) + ce.e1 = lowerArrayAssign(ae1, true); + if (auto ae2 = ce.e2.isAssignExp()) + ce.e2 = lowerArrayAssign(ae2, true); + } return setResult(res); } + /*************************************** + * Lower AssignExp to `_d_arrayassign_{l,r}` if needed. + * + * Params: + * ae = the AssignExp to be lowered + * fromCommaExp = indicates whether `ae` is part of a CommaExp or not, + * so no unnecessary temporay variable is created. + * Returns: + * a CommaExp contiaining call a to `_d_arrayassign_{l,r}` if needed or + * `ae` otherwise + */ + private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false) + { + Type t1b = ae.e1.type.toBasetype(); + if (t1b.ty != Tsarray && t1b.ty != Tarray) + return ae; + + const isArrayAssign = + (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && + (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) && + (ae.e1.type.nextOf && ae.e2.type.nextOf && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf)); + + if (!isArrayAssign) + return ae; + + const ts = t1b.nextOf().baseElemOf().isTypeStruct(); + if (!ts || (!ts.sym.postblit && !ts.sym.dtor)) + return ae; + + Expression res; + auto func = ae.e2.isLvalue || ae.e2.isSliceExp ? Id._d_arrayassign_l : Id._d_arrayassign_r; + + // Lower to `.object._d_arrayassign_l{r}(e1, e2)`` + Expression id = new IdentifierExp(ae.loc, Id.empty); + id = new DotIdExp(ae.loc, id, Id.object); + id = new DotIdExp(ae.loc, id, func); + + auto arguments = new Expressions(); + arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf) + .expressionSemantic(sc)); + + Expression eValue2, value2 = ae.e2; + if (ae.e2.isLvalue) + value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf) + .expressionSemantic(sc); + else if (!fromCommaExp) + { + // Rvalues from CommaExps were introduced in `visit(AssignExp)` + // and are temporary variables themselves. Rvalues from trivial + // SliceExps are simply passed by reference without any copying. + + // `__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. + auto vd = copyToTemp(STC.rvalue | STC.nodtor | STC.scope_, "__assigntmp", ae.e2); + eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); + value2 = new VarExp(vd.loc, vd).expressionSemantic(sc); + } + arguments.push(value2); + + Expression ce = new CallExp(ae.loc, id, arguments); + res = Expression.combine(eValue2, ce).expressionSemantic(sc); + res = Expression.combine(res, ae.e1).expressionSemantic(sc); + + if (global.params.verbose) + message("lowered %s =>\n %s", ae.toChars(), res.toChars()); + + return res; + } + override void visit(PowAssignExp exp) { if (exp.type) @@ -13092,7 +13172,10 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) if (sc.func && sc.func.isSynchronized()) return false; - return sharedError(e); + if (!allowRef && e.type.isShared()) + return sharedError(e); + + return false; } bool visitDotVar(DotVarExp e) @@ -13182,8 +13265,6 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) } if (sc.func && !sc.intypeof && !v.isDataseg()) { - v.storage_class &= ~STC.maybescope; - v.doNotInferScope = true; if (global.params.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)) diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 7475cb4..4c09474 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -568,8 +568,6 @@ extern (C++) class FuncDeclaration : Declaration if (tf.isreturnscope) vthis.storage_class |= STC.returnScope; } - if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_)) - vthis.storage_class |= STC.maybescope; vthis.dsymbolSemantic(sc); if (!sc.insert(vthis)) diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 05886f9..745d5eb 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -116,10 +116,6 @@ extern (C++) struct Param DiagnosticReporting useDeprecated = DiagnosticReporting.inform; // how use of deprecated features are handled bool useUnitTests; // generate unittest code bool useInline = false; // inline expand functions - FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 - FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params - bool fixImmutableConv; // error on unsound immutable conversion - https://github.com/dlang/dmd/pull/14070 - bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md 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 @@ -131,31 +127,10 @@ extern (C++) struct Param bool useModuleInfo = true; // generate runtime module information bool useTypeInfo = true; // generate runtime type information bool useExceptions = true; // support exception handling - bool noSharedAccess; // read/write access to shared memory objects - bool previewIn; // `in` means `[ref] scope const`, accepts rvalues - bool shortenedMethods; // allow => in normal function declarations bool betterC; // be a "better C" compiler; no dependency on D runtime bool addMain; // add a default main() function bool allInst; // generate code for all template instantiations - bool fix16997 = true; // fix integral promotions for unary + - ~ operators - // https://issues.dlang.org/show_bug.cgi?id=16997 - bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes - bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract - /** The --transition=safe switch should only be used to show code with - * silent semantics changes related to @safe improvements. It should not be - * used to hide a feature that will have to go through deprecate-then-error - * before becoming default. - */ - bool ehnogc; // use @nogc exception handling - FeatureState dtorFields; // destruct fields of partially constructed objects - // https://issues.dlang.org/show_bug.cgi?id=14246 - bool fieldwise; // do struct equality testing field-wise rather than by memcmp() bool bitfields; // support C style bit fields - FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters - // https://dconf.org/2019/talks/alexandrescu.html - // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a - // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html - // Implementation: https://github.com/dlang/dmd/pull/9817 CppStdRevision cplusplus = CppStdRevision.cpp11; // version of C++ standard to support @@ -173,6 +148,28 @@ extern (C++) struct Param bool hcUsage; // print help on -HC switch bool logo; // print compiler logo + // Options for `-preview=/-revert=` + FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 + FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params + bool ehnogc; // use @nogc exception handling + bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md + bool fieldwise; // do struct equality testing field-wise rather than by memcmp() + bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes + FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters + // https://dconf.org/2019/talks/alexandrescu.html + // 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 + bool 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 + bool shortenedMethods; // allow => in normal function declarations + bool fixImmutableConv; // error on unsound immutable conversion - https://github.com/dlang/dmd/pull/14070 + bool fix16997 = true; // fix integral promotions for unary + - ~ operators + // https://issues.dlang.org/show_bug.cgi?id=16997 + FeatureState dtorFields; // destruct fields of partially constructed objects + // https://issues.dlang.org/show_bug.cgi?id=14246 + CHECKENABLE useInvariants = CHECKENABLE._default; // generate class invariant checks CHECKENABLE useIn = CHECKENABLE._default; // generate precondition checks CHECKENABLE useOut = CHECKENABLE._default; // generate postcondition checks diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 41472b2..a6b1c90 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -116,10 +116,6 @@ struct Param Diagnostic useDeprecated; bool useUnitTests; // generate unittest code bool useInline; // inline expand functions - FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 - FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params - bool fixImmutableConv; - bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md bool release; // build release version bool preservePaths; // true means don't strip path from source file Diagnostic warnings; @@ -131,22 +127,10 @@ struct Param bool useModuleInfo; // generate runtime module information bool useTypeInfo; // generate runtime type information bool useExceptions; // support exception handling - bool noSharedAccess; // read/write access to shared memory objects - bool previewIn; // `in` means `scope const`, perhaps `ref`, accepts rvalues - bool shortenedMethods; // allow => in normal function declarations bool betterC; // be a "better C" compiler; no dependency on D runtime bool addMain; // add a default main() function bool allInst; // generate code for all template instantiations - bool fix16997; // fix integral promotions for unary + - ~ operators - // https://issues.dlang.org/show_bug.cgi?id=16997 - bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes - bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract - bool ehnogc; // use @nogc exception handling - FeatureState dtorFields; // destruct fields of partially constructed objects - // https://issues.dlang.org/show_bug.cgi?id=14246 - bool fieldwise; // do struct equality testing field-wise rather than by memcmp() bool bitfields; // support C style bit fields - FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters CppStdRevision cplusplus; // version of C++ name mangling to support bool showGaggedErrors; // print gagged errors anyway bool printErrorContext; // print errors with the error context (the error line in the source file) @@ -162,6 +146,27 @@ struct Param bool hcUsage; // print help on -HC switch bool logo; // print logo; + // Options for `-preview=/-revert=` + FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 + FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params + bool ehnogc; // use @nogc exception handling + bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md + bool fieldwise; // do struct equality testing field-wise rather than by memcmp() + bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes + FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters + // https://dconf.org/2019/talks/alexandrescu.html + // 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 + bool 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 + bool shortenedMethods; // allow => in normal function declarations + bool fixImmutableConv; // error on unsound immutable conversion - https://github.com/dlang/dmd/pull/14070 + bool fix16997; // fix integral promotions for unary + - ~ operators + // https://issues.dlang.org/show_bug.cgi?id=16997 + FeatureState dtorFields; // destruct fields of partially constructed objects + // https://issues.dlang.org/show_bug.cgi?id=14246 CHECKENABLE useInvariants; // generate class invariant checks CHECKENABLE useIn; // generate precondition checks CHECKENABLE useOut; // generate postcondition checks diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 680d9c8..48995db 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -1890,7 +1890,17 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg buf.printf("%uu", cast(uint)v); break; case Tint64: - buf.printf("%lldL", v); + if (v == long.min) + { + // https://issues.dlang.org/show_bug.cgi?id=23173 + // This is a special case because - is not part of the + // integer literal and 9223372036854775808L overflows a long + buf.writestring("cast(long)-9223372036854775808"); + } + else + { + buf.printf("%lldL", v); + } break; case Tuns64: buf.printf("%lluLU", v); @@ -2651,7 +2661,9 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all assert(strlen(buffer.ptr) < BUFFER_LEN); if (allowHex) { - real_t r = CTFloat.parse(buffer.ptr); + bool isOutOfRange; + real_t r = CTFloat.parse(buffer.ptr, isOutOfRange); + //assert(!isOutOfRange); // test/compilable/test22725.c asserts here if (r != value) // if exact duplication CTFloat.sprint(buffer.ptr, 'a', value); } diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 5142daa..6695faa 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -160,6 +160,7 @@ immutable Msgtable[] msgtable = { "xopEquals", "__xopEquals" }, { "xopCmp", "__xopCmp" }, { "xtoHash", "__xtoHash" }, + { "__tmpfordtor" }, { "LINE", "__LINE__" }, { "FILE", "__FILE__" }, @@ -318,6 +319,8 @@ immutable Msgtable[] msgtable = { "_aaApply2" }, { "_d_arrayctor" }, { "_d_arraysetctor" }, + { "_d_arrayassign_l" }, + { "_d_arrayassign_r" }, // For pragma's { "Pinline", "inline" }, diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d index b42b4a1..7f92298 100644 --- a/gcc/d/dmd/identifier.d +++ b/gcc/d/dmd/identifier.d @@ -88,7 +88,7 @@ nothrow: return name.ptr; } - extern (D) override const(char)[] toString() const pure + extern (D) override const(char)[] toString() const pure @safe { return name; } diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 11afcdd..21bbde8 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -2531,7 +2531,7 @@ class Lexer auto sbufptr = cast(const(char)*)stringbuffer[].ptr; TOK result; bool isOutOfRange = false; - t.floatvalue = (isWellformedString ? CTFloat.parse(sbufptr, &isOutOfRange) : CTFloat.zero); + t.floatvalue = (isWellformedString ? CTFloat.parse(sbufptr, isOutOfRange) : CTFloat.zero); switch (*p) { case 'F': diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 5808c28..6bfb729 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -58,7 +58,6 @@ public: static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them static Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them static Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them - static unsigned dprogress; // progress resolving the deferred list static void _init(); diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 860cfa9..f2da41b 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -4407,30 +4407,46 @@ extern (C++) final class TypeFunction : TypeNext purityLevel(); + static bool mayHavePointers(Type t) + { + if (auto ts = t.isTypeStruct()) + { + auto sym = ts.sym; + if (sym.members && !sym.determineFields() && sym.type != Type.terror) + // struct is forward referenced, so "may have" pointers + return true; + } + return t.hasPointers(); + } + // See if p can escape via any of the other parameters if (purity == PURE.weak) { // Check escaping through parameters foreach (i, fparam; parameterList) { - if (fparam == p) - continue; Type t = fparam.type; if (!t) continue; - t = t.baseElemOf(); + t = t.baseElemOf(); // punch thru static arrays if (t.isMutable() && t.hasPointers()) { - if (fparam.isReference()) - { - } - else if (t.ty == Tarray || t.ty == Tpointer) + if (fparam.isReference() && fparam != p) + return stc; + + if (t.ty == Tdelegate) + return stc; // could escape thru delegate + + if (t.ty == Tclass) + return stc; + + /* if t is a pointer to mutable pointer + */ + if (auto tn = t.nextOf()) { - Type tn = t.nextOf().toBasetype(); - if (!(tn.isMutable() && tn.hasPointers())) - continue; + if (tn.isMutable() && mayHavePointers(tn)) + return stc; // escape through pointers } - return stc; } } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index a2c364e..ce2769d 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -1999,7 +1999,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } check(TOK.rightParenthesis); - check(TOK.semicolon); + check(TOK.semicolon, "static assert"); return new AST.StaticAssert(loc, exp, msg); } @@ -2648,7 +2648,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } check(TOK.rightParenthesis); - check(TOK.semicolon); + check(TOK.semicolon, "invariant"); e = new AST.AssertExp(loc, e, msg); auto fbody = new AST.ExpStatement(loc, e); auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody); @@ -4738,7 +4738,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); // advance past = auto t = parseType(); AST.Dsymbol s = new AST.AliasAssign(loc, ident, t, null); - check(TOK.semicolon); + check(TOK.semicolon, "alias reassignment"); addComment(s, comment); auto a = new AST.Dsymbols(); a.push(s); @@ -4774,7 +4774,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer auto s = new AST.AliasThis(loc, token.ident); nextToken(); check(TOK.this_); - check(TOK.semicolon); + check(TOK.semicolon, "`alias Identifier this`"); auto a = new AST.Dsymbols(); a.push(s); addComment(s, comment); @@ -4791,7 +4791,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer check(TOK.assign); auto s = new AliasThis(loc, token.ident); nextToken(); - check(TOK.semicolon); + check(TOK.semicolon, "`alias this = Identifier`"); auto a = new Dsymbols(); a.push(s); addComment(s, comment); @@ -5331,6 +5331,33 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer error(loc, "instead of C-style syntax, use D-style `%s%s%s`", t.toChars(), sp, s); } + /***************************** + * Ad-hoc error message for missing or extra parens that close a condition. + * Params: + * start = "if", "while", etc. Must be 0 terminated. + * param = if the condition is a declaration, this will be non-null + * condition = if param is null, then this is the conditional Expression. If condition is null, + * then an error in the condition was already reported. + */ + private void closeCondition(string start, AST.Parameter param, AST.Expression condition) + { + string format; + if (token.value != TOK.rightParenthesis && condition) + { + format = "missing closing `)` after `%s (%s`"; + } + else + check(TOK.rightParenthesis); + if (token.value == TOK.rightParenthesis) + { + if (condition) // if not an error in condition + format = "extra `)` after `%s (%s)`"; + nextToken(); + } + if (format) + error(format.ptr, start.ptr, param ? "declaration".ptr : condition.toChars()); + } + /***************************************** * Parses `foreach` statements, `static foreach` statements and * `static foreach` declarations. @@ -5905,7 +5932,7 @@ LagainStc: { // mixin(string) AST.Expression e = parseAssignExp(); - check(TOK.semicolon); + check(TOK.semicolon, "mixin"); if (e.op == EXP.mixin_) { AST.MixinExp cpe = cast(AST.MixinExp)e; @@ -5961,12 +5988,12 @@ LagainStc: } case TOK.while_: { - AST.Parameter param = null; nextToken(); check(TOK.leftParenthesis); - param = parseAssignCondition(); - AST.Expression condition = parseExpression(); - check(TOK.rightParenthesis); + auto param = parseAssignCondition(); + auto condition = parseExpression(); + closeCondition("while", param, condition); + Loc endloc; AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc); s = new AST.WhileStatement(loc, condition, _body, endloc, param); @@ -5987,7 +6014,6 @@ LagainStc: case TOK.do_: { AST.Statement _body; - AST.Expression condition; nextToken(); const lookingForElseSave = lookingForElse; @@ -5996,8 +6022,8 @@ LagainStc: lookingForElse = lookingForElseSave; check(TOK.while_); check(TOK.leftParenthesis); - condition = parseExpression(); - check(TOK.rightParenthesis); + auto condition = parseExpression(); + closeCondition("do .. while", null, condition); if (token.value == TOK.semicolon) nextToken(); else @@ -6058,25 +6084,11 @@ LagainStc: } case TOK.if_: { - AST.Parameter param = null; - AST.Expression condition; - nextToken(); check(TOK.leftParenthesis); - param = parseAssignCondition(); - condition = parseExpression(); - if (token.value != TOK.rightParenthesis && condition) - { - error("missing closing `)` after `if (%s`", param ? "declaration".ptr : condition.toChars()); - } - else - check(TOK.rightParenthesis); - if (token.value == TOK.rightParenthesis) - { - if (condition) // if not an error in condition - error("extra `)` after `if (%s)`", param ? "declaration".ptr : condition.toChars()); - nextToken(); - } + auto param = parseAssignCondition(); + auto condition = parseExpression(); + closeCondition("if", param, condition); { const lookingForElseSave = lookingForElse; @@ -6223,7 +6235,7 @@ LagainStc: nextToken(); check(TOK.leftParenthesis); AST.Expression condition = parseExpression(); - check(TOK.rightParenthesis); + closeCondition("switch", null, condition); AST.Statement _body = parseStatement(ParseStatementFlags.scope_); s = new AST.SwitchStatement(loc, condition, _body, isfinal); break; @@ -6402,7 +6414,7 @@ LagainStc: { nextToken(); exp = parseExpression(); - check(TOK.rightParenthesis); + closeCondition("synchronized", null, exp); } else exp = null; @@ -6419,7 +6431,7 @@ LagainStc: nextToken(); check(TOK.leftParenthesis); exp = parseExpression(); - check(TOK.rightParenthesis); + closeCondition("with", null, exp); _body = parseStatement(ParseStatementFlags.scope_, null, &endloc); s = new AST.WithStatement(loc, exp, _body, endloc); break; @@ -6511,7 +6523,7 @@ LagainStc: if (peekNext() == TOK.leftParenthesis) { AST.Expression e = parseExpression(); - check(TOK.semicolon); + check(TOK.semicolon, "`import` Expression"); s = new AST.ExpStatement(loc, e); } else diff --git a/gcc/d/dmd/root/README.md b/gcc/d/dmd/root/README.md index 464f338..121d37c 100644 --- a/gcc/d/dmd/root/README.md +++ b/gcc/d/dmd/root/README.md @@ -2,25 +2,25 @@ | File | Purpose | |--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| -| [aav.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d) | An associative array implementation | -| [array.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/array.d) | A dynamic array implementation | -| [bitarray.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d) | A compact array of bits | -| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/complex.d) | A complex number type | -| [ctfloat.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d) | A floating point type for compile-time calculations | -| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/env.d) | Modify environment variables | -| [file.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/file.d) | Read a file from disk and store it in memory | -| [filename.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.d) | Encapsulate path and file names | -| [hash.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d) | Calculate a hash for a byte array | -| [longdouble.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/longdouble.d) | 80-bit floating point number implementation in case they are not natively supported | -| [man.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/man.d) | Opens an online manual page | -| [optional.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.d) | Implementation of an 'Optional' type | -| [port.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d) | Portable routines for functions that have different implementations on different platforms | -| [region.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d) | A region allocator | -| [response.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/response.d) | Parse command line arguments from response files | -| [rmem.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d) | Allocate memory using `malloc` or the GC depending on the configuration | -| [rootobject.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/rootobject.d) | A root object that classes in dmd inherit from | -| [speller.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/speller.d) | Try to detect typos in identifiers | -| [string.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/string.d) | Various string related functions | -| [stringtable.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d) | Specialized associative array with string keys stored in a variable length structure | -| [strtold.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/strtold.d) | D implementation of the standard C function `strtold` (String to long double) | -| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/utf.d) | Encoding/decoding Unicode text | +| [aav.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/aav.d) | An associative array implementation | +| [array.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/array.d) | A dynamic array implementation | +| [bitarray.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/bitarray.d) | A compact array of bits | +| [complex.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/complex.d) | A complex number type | +| [ctfloat.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/ctfloat.d) | A floating point type for compile-time calculations | +| [env.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/env.d) | Modify environment variables | +| [file.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/file.d) | Read a file from disk and store it in memory | +| [filename.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/filename.d) | Encapsulate path and file names | +| [hash.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/hash.d) | Calculate a hash for a byte array | +| [longdouble.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/longdouble.d) | 80-bit floating point number implementation in case they are not natively supported | +| [man.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/man.d) | Opens an online manual page | +| [optional.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/optional.d) | Implementation of an 'Optional' type | +| [port.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/port.d) | Portable routines for functions that have different implementations on different platforms | +| [region.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/region.d) | A region allocator | +| [response.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/response.d) | Parse command line arguments from response files | +| [rmem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/rmem.d) | Allocate memory using `malloc` or the GC depending on the configuration | +| [rootobject.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/rootobject.d) | A root object that classes in dmd inherit from | +| [speller.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/speller.d) | Try to detect typos in identifiers | +| [string.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/string.d) | Various string related functions | +| [stringtable.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/stringtable.d) | Specialized associative array with string keys stored in a variable length structure | +| [strtold.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/strtold.d) | D implementation of the standard C function `strtold` (String to long double) | +| [utf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/root/utf.d) | Encoding/decoding Unicode text | diff --git a/gcc/d/dmd/root/array.d b/gcc/d/dmd/root/array.d index c2eb3e1..212fe96 100644 --- a/gcc/d/dmd/root/array.d +++ b/gcc/d/dmd/root/array.d @@ -222,6 +222,16 @@ public: } } + extern (D) void insert(size_t index, T[] a) pure nothrow + { + size_t d = a.length; + reserve(d); + if (length != index) + memmove(data.ptr + index + d, data.ptr + index, (length - index) * T.sizeof); + memcpy(data.ptr + index, a.ptr, d * T.sizeof); + length += d; + } + void insert(size_t index, T ptr) pure nothrow { reserve(1); @@ -414,6 +424,14 @@ unittest arrayA.zero(); foreach(e; arrayA) assert(e == 0); + + arrayA.setDim(0); + arrayA.pushSlice([5, 6]); + arrayA.insert(1, [1, 2]); + assert(arrayA[] == [5, 1, 2, 6]); + arrayA.insert(0, [7, 8]); + arrayA.insert(arrayA.length, [0, 9]); + assert(arrayA[] == [7, 8, 5, 1, 2, 6, 0, 9]); } /** diff --git a/gcc/d/dmd/root/ctfloat.d b/gcc/d/dmd/root/ctfloat.d index 5ccc7bf..8c2fe46 100644 --- a/gcc/d/dmd/root/ctfloat.d +++ b/gcc/d/dmd/root/ctfloat.d @@ -47,7 +47,7 @@ extern (C++) struct CTFloat static bool isInfinity(real_t r) pure; @system - static real_t parse(const(char)* literal, bool* isOutOfRange = null); + static real_t parse(const(char)* literal, out bool isOutOfRange); @system static int sprint(char* str, char fmt, real_t x); diff --git a/gcc/d/dmd/root/ctfloat.h b/gcc/d/dmd/root/ctfloat.h index 6b83dbf..5a6cf25 100644 --- a/gcc/d/dmd/root/ctfloat.h +++ b/gcc/d/dmd/root/ctfloat.h @@ -50,7 +50,7 @@ struct CTFloat static bool isSNaN(real_t r); static bool isInfinity(real_t r); - static real_t parse(const char *literal, bool *isOutOfRange = NULL); + static real_t parse(const char *literal, bool& isOutOfRange); static int sprint(char *str, char fmt, real_t x); static size_t hash(real_t a); diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 6f37770..ad4487f 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -472,9 +472,6 @@ private extern(C++) final class Semantic3Visitor : Visitor stc |= STC.variadic; } - if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_)) - stc |= STC.maybescope; - stc |= fparam.storageClass & (STC.IOR | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor | STC.returnScope | STC.register); v.storage_class = stc; v.dsymbolSemantic(sc2); diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index be95432..367c56b 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -1268,6 +1268,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) auto o = (*e.args)[0]; auto po = isParameter(o); auto s = getDsymbolWithoutExpCtx(o); + auto typeOfArg = isType(o); UserAttributeDeclaration udad = null; if (po) { @@ -1282,6 +1283,10 @@ Expression semanticTraits(TraitsExp e, Scope* sc) //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s._scope); udad = s.userAttribDecl; } + else if (typeOfArg) + { + // If there is a type but no symbol, do nothing rather than erroring. + } else { version (none) diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index b1f1b1f..b21ff79 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1447,6 +1447,11 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) eparam.storageClass &= ~STC.auto_; eparam.storageClass |= STC.autoref; } + else if (eparam.storageClass & STC.ref_) + { + .error(loc, "cannot explicitly instantiate template function with `auto ref` parameter"); + errors = true; + } else { .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters"); diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 140df7e..b0ce870 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -986,11 +986,9 @@ public: else if ((postblit || destructor) && e->op != EXP::blit && e->op != EXP::construct) { - /* Generate: _d_arrayassign(ti, from, to); */ - this->result_ = build_libcall (LIBCALL_ARRAYASSIGN, e->type, 3, - build_typeinfo (e, etype), - d_array_convert (e->e2), - d_array_convert (e->e1)); + /* Assigning to a non-trivially copyable array has already been + handled by the front-end. */ + gcc_unreachable (); } else { @@ -1124,27 +1122,7 @@ public: /* All other kinds of lvalue or rvalue static array assignment. Array construction has already been handled by the front-end. */ gcc_assert (e->op != EXP::construct); - - /* Generate: _d_arrayassign_l() - or: _d_arrayassign_r() */ - libcall_fn libcall = (lvalue) - ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R; - tree elembuf = build_local_temp (build_ctype (etype)); - Type *arrtype = (e->type->ty == TY::Tsarray) - ? etype->arrayOf () : e->type; - tree result = build_libcall (libcall, arrtype, 4, - build_typeinfo (e, etype), - d_array_convert (e->e2), - d_array_convert (e->e1), - build_address (elembuf)); - - /* Cast the libcall result back to a static array. */ - if (e->type->ty == TY::Tsarray) - result = indirect_ref (build_ctype (e->type), - d_array_ptr (result)); - - this->result_ = result; - return; + gcc_unreachable (); } /* Simple assignment. */ diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index 459a283..282f22c 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -115,14 +115,7 @@ DEF_D_RUNTIME (ALLOCMEMORY, "_d_allocmemory", RT(VOIDPTR), P1(SIZE_T), DEF_D_RUNTIME (ARRAYCOPY, "_d_arraycopy", RT(ARRAY_VOID), P3(SIZE_T, ARRAY_VOID, ARRAY_VOID), 0) -/* Used for array assignments from an existing array. The `set' variant is for - when the assignment value is a single element. */ -DEF_D_RUNTIME (ARRAYASSIGN, "_d_arrayassign", RT(ARRAY_VOID), - P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0) -DEF_D_RUNTIME (ARRAYASSIGN_L, "_d_arrayassign_l", RT(ARRAY_VOID), - P4(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID, VOIDPTR), 0) -DEF_D_RUNTIME (ARRAYASSIGN_R, "_d_arrayassign_r", RT(ARRAY_VOID), - P4(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID, VOIDPTR), 0) +/* Used for array assignments from a single element. */ DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR), P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0) |