d: Merge upstream dmd 817610b16d, phobos b578dfad9
D front-end changes: - Import latest bug fixes to mainline. Phobos changes: - Import latest bug fixes to mainline. - std.logger module has been moved out of experimental. - Removed std.experimental.typecons module. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 817610b16d. * d-ctfloat.cc (CTFloat::parse): Update for new front-end interface. * d-lang.cc (d_parse_file): Likewise. * expr.cc (ExprVisitor::visit (AssignExp *)): Remove handling of array assignments to non-trivial static and dynamic arrays. * runtime.def (ARRAYASSIGN): Remove. (ARRAYASSIGN_L): Remove. (ARRAYASSIGN_R): Remove. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 817610b16d. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/internal/array/arrayassign.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos b578dfad9. * src/Makefile.am (PHOBOS_DSOURCES): Remove std/experimental/typecons.d. Add std/logger package. * src/Makefile.in: Regenerate.
This commit is contained in:
parent
cace77f4fb
commit
b7a586beae
101 changed files with 5810 additions and 5672 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1191,7 +1191,6 @@ d_parse_file (void)
|
|||
}
|
||||
|
||||
/* Do deferred semantic analysis. */
|
||||
Module::dprogress = 1;
|
||||
Module::runDeferredSemantic ();
|
||||
|
||||
if (Module::deferred.length)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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;
|
||||
|
@ -6812,6 +6825,135 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
|
|||
ds.semanticRun = PASS.semanticdone;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* 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`.
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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())
|
||||
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())
|
||||
{
|
||||
if (tn.isMutable() && mayHavePointers(tn))
|
||||
return stc; // escape through pointers
|
||||
}
|
||||
else if (t.ty == Tarray || t.ty == Tpointer)
|
||||
{
|
||||
Type tn = t.nextOf().toBasetype();
|
||||
if (!(tn.isMutable() && tn.hasPointers()))
|
||||
continue;
|
||||
}
|
||||
return stc;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -3,18 +3,18 @@ template AliasSeq(T...) { alias AliasSeq = T; }
|
|||
template Unqual(T)
|
||||
{
|
||||
static if (is(T U == const U))
|
||||
alias Unqual = U;
|
||||
alias Unqual = U;
|
||||
else static if (is(T U == immutable U))
|
||||
alias Unqual = U;
|
||||
alias Unqual = U;
|
||||
else
|
||||
alias Unqual = T;
|
||||
alias Unqual = T;
|
||||
}
|
||||
|
||||
template staticMap(alias F, T...)
|
||||
{
|
||||
alias A = AliasSeq!();
|
||||
static foreach (t; T)
|
||||
A = AliasSeq!(A, F!t); // what's tested
|
||||
A = AliasSeq!(A, F!t); // what's tested
|
||||
alias staticMap = A;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ template reverse(T...)
|
|||
{
|
||||
alias A = AliasSeq!();
|
||||
static foreach (t; T)
|
||||
A = AliasSeq!(t, A); // what's tested
|
||||
A = AliasSeq!(t, A); // what's tested
|
||||
alias reverse = A;
|
||||
}
|
||||
|
||||
|
@ -38,3 +38,98 @@ alias TK2 = reverse!(int, const uint, X2);
|
|||
static assert(TK2[0] == 3);
|
||||
static assert(is(TK2[1] == const(uint)));
|
||||
static assert(is(TK2[2] == int));
|
||||
|
||||
/**************************************************/
|
||||
|
||||
template Tp(Args...)
|
||||
{
|
||||
alias Tp = AliasSeq!(int, 1, "asd", Args);
|
||||
static foreach (arg; Args)
|
||||
{
|
||||
Tp = AliasSeq!(4, Tp, "zxc", arg, Tp, 5, 4, int, Tp[0..2]);
|
||||
}
|
||||
}
|
||||
|
||||
void fun(){}
|
||||
|
||||
alias a1 = Tp!(char[], fun, x => x);
|
||||
static assert(
|
||||
__traits(isSame, a1, AliasSeq!(4, 4, 4, int, 1, "asd", char[], fun,
|
||||
x => x, "zxc", char[], int, 1, "asd", char[], fun, x => x,
|
||||
5, 4, int, int, 1, "zxc", fun, 4, int, 1, "asd", char[],
|
||||
fun, x => x, "zxc", char[], int, 1, "asd", char[], fun,
|
||||
x => x, 5, 4, int, int, 1, 5, 4, int, 4, int, "zxc", x => x,
|
||||
4, 4, int, 1, "asd", char[], fun, x => x, "zxc", char[],
|
||||
int, 1, "asd", char[], fun, x => x, 5, 4, int, int, 1,
|
||||
"zxc", fun, 4, int, 1, "asd", char[], fun, x => x, "zxc",
|
||||
char[], int, 1, "asd", char[], fun, x => x, 5, 4, int, int,
|
||||
1, 5, 4, int, 4, int, 5, 4, int, 4, 4)));
|
||||
|
||||
template Tp2(Args...)
|
||||
{
|
||||
alias Tp2 = () => 1;
|
||||
static foreach (i; 0..Args.length)
|
||||
Tp2 = AliasSeq!(Tp2, Args[i]);
|
||||
}
|
||||
|
||||
const x = 8;
|
||||
static assert(
|
||||
__traits(isSame, Tp2!(2, float, x), AliasSeq!(() => 1, 2, float, x)));
|
||||
|
||||
|
||||
enum F(int i) = i * i;
|
||||
|
||||
template staticMap2(alias fun, args...)
|
||||
{
|
||||
alias staticMap2 = AliasSeq!();
|
||||
static foreach (i; 0 .. args.length)
|
||||
staticMap2 = AliasSeq!(fun!(args[i]), staticMap2, fun!(args[i]));
|
||||
}
|
||||
|
||||
enum a2 = staticMap2!(F, 0, 1, 2, 3, 4);
|
||||
|
||||
struct Cmp(T...){}
|
||||
// isSame sucks
|
||||
static assert(is(Cmp!a2 == Cmp!(16, 9, 4, 1, 0, 0, 1, 4, 9, 16)));
|
||||
|
||||
template Tp3()
|
||||
{
|
||||
alias aa1 = int;
|
||||
static foreach (t; AliasSeq!(float, char[]))
|
||||
aa1 = AliasSeq!(aa1, t);
|
||||
static assert(is(aa1 == AliasSeq!(int, float, char[])));
|
||||
|
||||
alias aa2 = AliasSeq!int;
|
||||
static foreach (t; AliasSeq!(float, char[]))
|
||||
aa2 = AliasSeq!(aa2, t);
|
||||
static assert(is(aa2 == AliasSeq!(int, float, char[])));
|
||||
|
||||
alias aa3 = AliasSeq!int;
|
||||
aa3 = AliasSeq!(float, char);
|
||||
static assert(is(aa3 == AliasSeq!(float, char)));
|
||||
}
|
||||
alias a3 = Tp3!();
|
||||
|
||||
template Tp4() // Uses slow path because overload
|
||||
{
|
||||
alias AliasSeq(T...) = T;
|
||||
alias AliasSeq(alias f, T...) = T;
|
||||
|
||||
alias aa4 = int;
|
||||
aa4 = AliasSeq!(aa4, float);
|
||||
static assert(is(aa4 == AliasSeq!(int, float)));
|
||||
|
||||
}
|
||||
alias a4 = Tp4!();
|
||||
|
||||
template Tp5() // same tp overloaded, still uses fast path
|
||||
{
|
||||
alias AliasSeq2(T...) = T;
|
||||
alias AliasSeq = AliasSeq2;
|
||||
alias AliasSeq = AliasSeq2;
|
||||
|
||||
alias aa5 = int;
|
||||
aa5 = AliasSeq!(aa5, float);
|
||||
static assert(is(aa5 == AliasSeq!(int, float)));
|
||||
}
|
||||
alias a5 = Tp5!();
|
||||
|
|
28
gcc/testsuite/gdc.test/compilable/scope_infer_array_assign.d
Normal file
28
gcc/testsuite/gdc.test/compilable/scope_infer_array_assign.d
Normal file
|
@ -0,0 +1,28 @@
|
|||
// REQUIRED_ARGS: -preview=dip1000
|
||||
|
||||
// Test that scope inference works even with non POD array assignment
|
||||
// This is tricky because it gets lowered to something like:
|
||||
// (S[] __assigntmp0 = e[]) , _d_arrayassign_l(this.e[], __assigntmp0) , this.e[];
|
||||
|
||||
@safe:
|
||||
|
||||
struct File
|
||||
{
|
||||
void* f;
|
||||
~this() scope { }
|
||||
}
|
||||
|
||||
struct Vector
|
||||
{
|
||||
File[] e;
|
||||
|
||||
auto assign(File[] e)
|
||||
{
|
||||
this.e[] = e[]; // slice copy
|
||||
}
|
||||
}
|
||||
|
||||
void test(scope File[] arr, Vector v)
|
||||
{
|
||||
v.assign(arr);
|
||||
}
|
25
gcc/testsuite/gdc.test/compilable/test21197.d
Normal file
25
gcc/testsuite/gdc.test/compilable/test21197.d
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* REQUIRED_ARGS: -preview=dip1000
|
||||
*/
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21197
|
||||
|
||||
@safe void check2()
|
||||
{
|
||||
int random;
|
||||
|
||||
S create1() return scope {
|
||||
return S();
|
||||
}
|
||||
|
||||
scope S gen1 = create1;
|
||||
|
||||
S create2() {
|
||||
return S(&random);
|
||||
}
|
||||
|
||||
scope S gen2 = create2;
|
||||
}
|
||||
|
||||
struct S
|
||||
{
|
||||
int* r;
|
||||
}
|
|
@ -6,3 +6,9 @@ struct foo { }
|
|||
@foo bar () { }
|
||||
|
||||
/************************************************/
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23241
|
||||
|
||||
alias feynman = int;
|
||||
enum get = __traits(getAttributes, feynman);
|
||||
static assert(get.length == 0);
|
||||
|
|
33
gcc/testsuite/gdc.test/fail_compilation/aliasassign2.d
Normal file
33
gcc/testsuite/gdc.test/fail_compilation/aliasassign2.d
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/aliasassign2.d(16): Error: `alias aa1 = aa1;` cannot alias itself, use a qualified name to create an overload set
|
||||
fail_compilation/aliasassign2.d(19): Error: template instance `aliasassign2.Tp1!()` error instantiating
|
||||
fail_compilation/aliasassign2.d(24): Error: undefined identifier `unknown`
|
||||
fail_compilation/aliasassign2.d(26): Error: template instance `aliasassign2.Tp2!()` error instantiating
|
||||
fail_compilation/aliasassign2.d(31): Error: template instance `AliasSeqX!(aa3, 1)` template `AliasSeqX` is not defined, did you mean AliasSeq(T...)?
|
||||
fail_compilation/aliasassign2.d(33): Error: template instance `aliasassign2.Tp3!()` error instantiating
|
||||
---
|
||||
*/
|
||||
|
||||
alias AliasSeq(T...) = T;
|
||||
|
||||
template Tp1()
|
||||
{
|
||||
alias aa1 = aa1;
|
||||
aa1 = AliasSeq!(aa1, float);
|
||||
}
|
||||
alias a1 = Tp1!();
|
||||
|
||||
template Tp2()
|
||||
{
|
||||
alias aa2 = AliasSeq!();
|
||||
aa2 = AliasSeq!(aa2, unknown);
|
||||
}
|
||||
alias a2 = Tp2!();
|
||||
|
||||
template Tp3()
|
||||
{
|
||||
alias aa3 = AliasSeq!();
|
||||
aa3 = AliasSeqX!(aa3, 1);
|
||||
}
|
||||
alias a3 = Tp3!();
|
40
gcc/testsuite/gdc.test/fail_compilation/diag23295.d
Normal file
40
gcc/testsuite/gdc.test/fail_compilation/diag23295.d
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
REQUIRED_ARGS: -preview=dip1000
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/diag23295.d(21): Error: scope variable `x` assigned to non-scope parameter `y` calling `foo`
|
||||
fail_compilation/diag23295.d(32): which is assigned to non-scope parameter `z`
|
||||
fail_compilation/diag23295.d(34): which is not `scope` because of `f = & z`
|
||||
fail_compilation/diag23295.d(24): Error: scope variable `ex` assigned to non-scope parameter `e` calling `thro`
|
||||
fail_compilation/diag23295.d(39): which is not `scope` because of `throw e`
|
||||
---
|
||||
*/
|
||||
|
||||
// explain why scope inference failed
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23295
|
||||
|
||||
@safe:
|
||||
|
||||
void main()
|
||||
{
|
||||
scope int* x;
|
||||
foo(x, null);
|
||||
|
||||
scope Exception ex;
|
||||
thro(ex);
|
||||
}
|
||||
|
||||
auto foo(int* y, int** w)
|
||||
{
|
||||
fooImpl(y, null);
|
||||
}
|
||||
|
||||
auto fooImpl(int* z, int** w)
|
||||
{
|
||||
auto f = &z;
|
||||
}
|
||||
|
||||
auto thro(Exception e)
|
||||
{
|
||||
throw e;
|
||||
}
|
|
@ -1,26 +1,27 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail10968.d(41): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(41): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(42): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(42): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(43): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(43): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(46): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(46): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(44): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.arrayassign._d_arrayassign_l!(SA[], SA)._d_arrayassign_l`
|
||||
fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(47): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor`
|
||||
fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(48): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor`
|
||||
fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor`
|
||||
fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(49): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
|
||||
fail_compilation/fail10968.d(30): `fail10968.SA.__postblit` is declared here
|
||||
fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor`
|
||||
---
|
||||
*/
|
||||
|
||||
|
@ -51,12 +52,12 @@ void bar() pure @safe
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail10968.d(74): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
|
||||
fail_compilation/fail10968.d(75): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
|
||||
fail_compilation/fail10968.d(76): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
|
||||
fail_compilation/fail10968.d(79): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
|
||||
fail_compilation/fail10968.d(77): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
|
||||
fail_compilation/fail10968.d(80): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
|
||||
fail_compilation/fail10968.d(81): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
|
||||
fail_compilation/fail10968.d(82): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ void test1()
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail14669.d(29): Error: `auto` can only be used as part of `auto ref` for template function parameters
|
||||
fail_compilation/fail14669.d(29): Error: cannot explicitly instantiate template function with `auto ref` parameter
|
||||
fail_compilation/fail14669.d(38): Error: template instance `fail14669.bar1!int` error instantiating
|
||||
fail_compilation/fail14669.d(30): Error: `auto` can only be used as part of `auto ref` for template function parameters
|
||||
fail_compilation/fail14669.d(30): Error: cannot explicitly instantiate template function with `auto ref` parameter
|
||||
fail_compilation/fail14669.d(40): Error: template instance `fail14669.bar2!int` error instantiating
|
||||
---
|
||||
*/
|
||||
|
|
|
@ -3,7 +3,7 @@ TEST_OUTPUT:
|
|||
---
|
||||
fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` when expecting `(`
|
||||
fail_compilation/ice8795.d-mixin-14(14): Error: expression expected, not `End of File`
|
||||
fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` when expecting `)`
|
||||
fail_compilation/ice8795.d-mixin-14(14): Error: missing closing `)` after `switch (0`
|
||||
fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` instead of statement
|
||||
fail_compilation/ice8795.d-mixin-15(15): Error: { } expected following `interface` declaration
|
||||
fail_compilation/ice8795.d-mixin-15(15): Error: anonymous interfaces not allowed
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
module imports.import15525;
|
||||
|
||||
template Tuple{ static if }
|
24
gcc/testsuite/gdc.test/fail_compilation/issue12652.d
Normal file
24
gcc/testsuite/gdc.test/fail_compilation/issue12652.d
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
----
|
||||
fail_compilation/issue12652.d(18): Error: static initializations of associative arrays is not allowed.
|
||||
fail_compilation/issue12652.d(18): associative arrays must be initialized at runtime: https://dlang.org/spec/hash-map.html#runtime_initialization
|
||||
---
|
||||
*/
|
||||
|
||||
enum A
|
||||
{
|
||||
x,
|
||||
y,
|
||||
z
|
||||
}
|
||||
|
||||
struct S
|
||||
{
|
||||
string[A] t = [A.x : "aaa", A.y : "bbb"];
|
||||
}
|
||||
|
||||
void main ()
|
||||
{
|
||||
S s;
|
||||
}
|
|
@ -78,6 +78,7 @@ void foo() @safe
|
|||
fail_compilation/retscope6.d(8016): Error: address of variable `i` assigned to `p` with longer lifetime
|
||||
fail_compilation/retscope6.d(8031): Error: reference to local variable `i` assigned to non-scope parameter `p` calling `betty`
|
||||
fail_compilation/retscope6.d(8031): Error: reference to local variable `j` assigned to non-scope parameter `q` calling `betty`
|
||||
fail_compilation/retscope6.d(8021): which is assigned to non-scope parameter `p`
|
||||
fail_compilation/retscope6.d(8048): Error: reference to local variable `j` assigned to non-scope parameter `q` calling `archie`
|
||||
---
|
||||
*/
|
||||
|
@ -255,6 +256,7 @@ void escape_throw_20150() @safe
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/retscope6.d(14019): Error: scope variable `scopePtr` assigned to non-scope parameter `x` calling `noInfer23021`
|
||||
fail_compilation/retscope6.d(14009): which is not `scope` because of `*escapeHole = cast(const(int)*)x`
|
||||
fail_compilation/retscope6.d(14022): Error: scope variable `scopePtr` may not be returned
|
||||
---
|
||||
*/
|
||||
|
|
|
@ -225,3 +225,14 @@ auto ref Object test_inference_4(const return shared ref Object a)
|
|||
{
|
||||
return a;
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23226
|
||||
// Allow accessing non-shared `this`
|
||||
struct BitRange
|
||||
{
|
||||
int bits;
|
||||
void f()
|
||||
{
|
||||
this.bits++;
|
||||
}
|
||||
}
|
||||
|
|
17
gcc/testsuite/gdc.test/fail_compilation/test15525.d
Normal file
17
gcc/testsuite/gdc.test/fail_compilation/test15525.d
Normal file
|
@ -0,0 +1,17 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=15525
|
||||
|
||||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/imports/import15525.d(3): Error: parenthesized template parameter list expected following template identifier
|
||||
fail_compilation/imports/import15525.d(3): Error: (expression) expected following `static if`
|
||||
fail_compilation/imports/import15525.d(3): Error: declaration expected, not `}`
|
||||
fail_compilation/test15525.d(16): Error: template instance `Tuple!()` template `Tuple` is not defined
|
||||
---
|
||||
*/
|
||||
|
||||
struct CrashMe
|
||||
{
|
||||
import imports.import15525;
|
||||
Tuple!() crash;
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
/* REQUIRED_ARGS: -preview=dip1000
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test17423.d(26): Error: reference to local `this` assigned to non-scope parameter `dlg` calling `opApply`
|
||||
fail_compilation/test17423.d(27): Error: reference to local `this` assigned to non-scope parameter `dlg` calling `opApply`
|
||||
fail_compilation/test17423.d(16): which is not `scope` because of `this.myDlg = dlg`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
21
gcc/testsuite/gdc.test/fail_compilation/test17764.d
Normal file
21
gcc/testsuite/gdc.test/fail_compilation/test17764.d
Normal file
|
@ -0,0 +1,21 @@
|
|||
/* REQUIRED_ARGS: -preview=dip1000
|
||||
* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test17764.d(109): Error: scope variable `c` assigned to non-scope `global`
|
||||
---
|
||||
*/
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=17764
|
||||
|
||||
#line 100
|
||||
|
||||
int** global;
|
||||
|
||||
struct S { int** str; }
|
||||
|
||||
void f() @safe
|
||||
{
|
||||
int* buf;
|
||||
S[1] c = S(&buf);
|
||||
global = c[0].str; /* This should be rejected. */
|
||||
}
|
|
@ -2,15 +2,16 @@
|
|||
REQUIRED_ARGS: -preview=dip1000
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test20245.d(20): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling `escape`
|
||||
fail_compilation/test20245.d(21): Error: copying `&x` into allocated memory escapes a reference to parameter `x`
|
||||
fail_compilation/test20245.d(22): Error: scope variable `a` may not be returned
|
||||
fail_compilation/test20245.d(26): Error: cannot take address of `scope` variable `x` since `scope` applies to first indirection only
|
||||
fail_compilation/test20245.d(32): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling `escape`
|
||||
fail_compilation/test20245.d(33): Error: copying `&x` into allocated memory escapes a reference to parameter `x`
|
||||
fail_compilation/test20245.d(49): Error: reference to local variable `price` assigned to non-scope `this.minPrice`
|
||||
fail_compilation/test20245.d(68): Error: reference to local variable `this` assigned to non-scope parameter `msg` calling `this`
|
||||
fail_compilation/test20245.d(88): Error: reference to local variable `this` assigned to non-scope parameter `content` calling `listUp`
|
||||
fail_compilation/test20245.d(21): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling `escape`
|
||||
fail_compilation/test20245.d(22): Error: copying `&x` into allocated memory escapes a reference to parameter `x`
|
||||
fail_compilation/test20245.d(23): Error: scope variable `a` may not be returned
|
||||
fail_compilation/test20245.d(27): Error: cannot take address of `scope` variable `x` since `scope` applies to first indirection only
|
||||
fail_compilation/test20245.d(33): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling `escape`
|
||||
fail_compilation/test20245.d(34): Error: copying `&x` into allocated memory escapes a reference to parameter `x`
|
||||
fail_compilation/test20245.d(50): Error: reference to local variable `price` assigned to non-scope `this.minPrice`
|
||||
fail_compilation/test20245.d(69): Error: reference to local variable `this` assigned to non-scope parameter `msg` calling `this`
|
||||
fail_compilation/test20245.d(89): Error: reference to local variable `this` assigned to non-scope parameter `content` calling `listUp`
|
||||
fail_compilation/test20245.d(82): which is not `scope` because of `charPtr = content`
|
||||
---
|
||||
*/
|
||||
|
||||
|
|
44
gcc/testsuite/gdc.test/fail_compilation/test20809.d
Normal file
44
gcc/testsuite/gdc.test/fail_compilation/test20809.d
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
REQUIRED_ARGS: -de
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test20809.d(114): Deprecation: returning `this.a` escapes a reference to parameter `this`
|
||||
fail_compilation/test20809.d(112): perhaps annotate the function with `return`
|
||||
---
|
||||
*/
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20809
|
||||
|
||||
#line 100
|
||||
|
||||
@safe:
|
||||
|
||||
struct S
|
||||
{
|
||||
@safe:
|
||||
int a;
|
||||
~this()
|
||||
{
|
||||
a = 0;
|
||||
}
|
||||
|
||||
ref int val()
|
||||
{
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
S bar()
|
||||
{
|
||||
return S(2);
|
||||
}
|
||||
|
||||
int foo()
|
||||
{
|
||||
return bar.val;
|
||||
}
|
||||
|
||||
void test()
|
||||
{
|
||||
assert(foo() == 2);
|
||||
}
|
35
gcc/testsuite/gdc.test/fail_compilation/test23073.d
Normal file
35
gcc/testsuite/gdc.test/fail_compilation/test23073.d
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
REQUIRED_ARGS: -preview=dip1000
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test23073.d(28): Error: scope variable `c` assigned to non-scope parameter `c` calling `assignNext`
|
||||
fail_compilation/test23073.d(22): which is not `scope` because of `c.next = c`
|
||||
---
|
||||
*/
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23073
|
||||
// scope inference from pure doesn't consider self-assignment
|
||||
|
||||
@safe:
|
||||
|
||||
class C
|
||||
{
|
||||
C next;
|
||||
}
|
||||
|
||||
void assignNext(C c) pure nothrow @nogc
|
||||
{
|
||||
c.next = c;
|
||||
}
|
||||
|
||||
C escape() @nogc
|
||||
{
|
||||
scope C c = new C();
|
||||
assignNext(c);
|
||||
return c.next;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
C dangling = escape();
|
||||
}
|
46
gcc/testsuite/gdc.test/fail_compilation/testsemi.d
Normal file
46
gcc/testsuite/gdc.test/fail_compilation/testsemi.d
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/testsemi.d(102): Error: found `int` when expecting `;` following static assert
|
||||
fail_compilation/testsemi.d(102): Error: no identifier for declarator `x`
|
||||
fail_compilation/testsemi.d(109): Error: found `alias` when expecting `;` following alias reassignment
|
||||
fail_compilation/testsemi.d(112): Error: found `}` when expecting `;` following invariant
|
||||
fail_compilation/testsemi.d(117): Error: found `int` when expecting `;` following `alias Identifier this`
|
||||
fail_compilation/testsemi.d(117): Error: no identifier for declarator `x`
|
||||
fail_compilation/testsemi.d(123): Error: found `int` when expecting `;` following mixin
|
||||
fail_compilation/testsemi.d(129): Error: found `int` when expecting `;` following `import` Expression
|
||||
fail_compilation/testsemi.d(131): Error: `}` expected following members in `class` declaration at fail_compilation/testsemi.d(112)
|
||||
---
|
||||
*/
|
||||
|
||||
#line 100
|
||||
|
||||
static assert(1)
|
||||
int x;
|
||||
|
||||
template map(alias F, Args...)
|
||||
{
|
||||
alias A = AliasSeq!();
|
||||
static foreach (Arg; Args)
|
||||
A = AliasSeq!(A, F!Arg)
|
||||
alias staticMap = A;
|
||||
}
|
||||
|
||||
class C { invariant(3) }
|
||||
|
||||
class D
|
||||
{
|
||||
alias x this
|
||||
int x;
|
||||
}
|
||||
|
||||
void test1()
|
||||
{
|
||||
mixin("int x;")
|
||||
int y;
|
||||
}
|
||||
|
||||
void test2()
|
||||
{
|
||||
import(1)
|
||||
int z;
|
||||
}
|
21
gcc/testsuite/gdc.test/runnable/test20365.d
Normal file
21
gcc/testsuite/gdc.test/runnable/test20365.d
Normal file
|
@ -0,0 +1,21 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=20365
|
||||
|
||||
string result = "";
|
||||
|
||||
struct S
|
||||
{
|
||||
long[3] a;
|
||||
this(ref typeof(this)) { result ~= "C"; }
|
||||
}
|
||||
|
||||
void fun()
|
||||
{
|
||||
S[4] a;
|
||||
auto b = a;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
fun();
|
||||
assert(result == "CCCC");
|
||||
}
|
14
gcc/testsuite/gdc.test/runnable/test20809.d
Normal file
14
gcc/testsuite/gdc.test/runnable/test20809.d
Normal file
|
@ -0,0 +1,14 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=20809
|
||||
|
||||
|
||||
@safe:
|
||||
struct S{
|
||||
@safe:
|
||||
int[8] a;
|
||||
~this(){ a[] = 0; }
|
||||
ref val(){ return a; }
|
||||
}
|
||||
S bar(){ return S([2,2,2,2,2,2,2,2]); }
|
||||
int[8] foo(){ return bar.val; }
|
||||
|
||||
void main(){ assert(foo() == [2,2,2,2,2,2,2,2]); } // error
|
|
@ -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.
|
||||
|
|
|
@ -171,17 +171,18 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
|
|||
core/builtins.d core/checkedint.d core/cpuid.d core/demangle.d \
|
||||
core/exception.d core/gc/config.d core/gc/gcinterface.d \
|
||||
core/gc/registry.d core/int128.d core/internal/abort.d \
|
||||
core/internal/array/appending.d core/internal/array/capacity.d \
|
||||
core/internal/array/casting.d core/internal/array/comparison.d \
|
||||
core/internal/array/concatenation.d core/internal/array/construction.d \
|
||||
core/internal/array/duplication.d core/internal/array/equality.d \
|
||||
core/internal/array/operations.d core/internal/array/utils.d \
|
||||
core/internal/atomic.d core/internal/attributes.d \
|
||||
core/internal/container/array.d core/internal/container/common.d \
|
||||
core/internal/container/hashtab.d core/internal/container/treap.d \
|
||||
core/internal/convert.d core/internal/dassert.d \
|
||||
core/internal/destruction.d core/internal/entrypoint.d \
|
||||
core/internal/gc/bits.d core/internal/gc/impl/conservative/gc.d \
|
||||
core/internal/array/appending.d core/internal/array/arrayassign.d \
|
||||
core/internal/array/capacity.d core/internal/array/casting.d \
|
||||
core/internal/array/comparison.d core/internal/array/concatenation.d \
|
||||
core/internal/array/construction.d core/internal/array/duplication.d \
|
||||
core/internal/array/equality.d core/internal/array/operations.d \
|
||||
core/internal/array/utils.d core/internal/atomic.d \
|
||||
core/internal/attributes.d core/internal/container/array.d \
|
||||
core/internal/container/common.d core/internal/container/hashtab.d \
|
||||
core/internal/container/treap.d core/internal/convert.d \
|
||||
core/internal/dassert.d core/internal/destruction.d \
|
||||
core/internal/entrypoint.d core/internal/gc/bits.d \
|
||||
core/internal/gc/impl/conservative/gc.d \
|
||||
core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \
|
||||
core/internal/gc/os.d core/internal/gc/pooltable.d \
|
||||
core/internal/gc/proxy.d core/internal/hash.d core/internal/lifetime.d \
|
||||
|
|
|
@ -192,6 +192,7 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
|
|||
core/demangle.lo core/exception.lo core/gc/config.lo \
|
||||
core/gc/gcinterface.lo core/gc/registry.lo core/int128.lo \
|
||||
core/internal/abort.lo core/internal/array/appending.lo \
|
||||
core/internal/array/arrayassign.lo \
|
||||
core/internal/array/capacity.lo core/internal/array/casting.lo \
|
||||
core/internal/array/comparison.lo \
|
||||
core/internal/array/concatenation.lo \
|
||||
|
@ -839,17 +840,18 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
|
|||
core/builtins.d core/checkedint.d core/cpuid.d core/demangle.d \
|
||||
core/exception.d core/gc/config.d core/gc/gcinterface.d \
|
||||
core/gc/registry.d core/int128.d core/internal/abort.d \
|
||||
core/internal/array/appending.d core/internal/array/capacity.d \
|
||||
core/internal/array/casting.d core/internal/array/comparison.d \
|
||||
core/internal/array/concatenation.d core/internal/array/construction.d \
|
||||
core/internal/array/duplication.d core/internal/array/equality.d \
|
||||
core/internal/array/operations.d core/internal/array/utils.d \
|
||||
core/internal/atomic.d core/internal/attributes.d \
|
||||
core/internal/container/array.d core/internal/container/common.d \
|
||||
core/internal/container/hashtab.d core/internal/container/treap.d \
|
||||
core/internal/convert.d core/internal/dassert.d \
|
||||
core/internal/destruction.d core/internal/entrypoint.d \
|
||||
core/internal/gc/bits.d core/internal/gc/impl/conservative/gc.d \
|
||||
core/internal/array/appending.d core/internal/array/arrayassign.d \
|
||||
core/internal/array/capacity.d core/internal/array/casting.d \
|
||||
core/internal/array/comparison.d core/internal/array/concatenation.d \
|
||||
core/internal/array/construction.d core/internal/array/duplication.d \
|
||||
core/internal/array/equality.d core/internal/array/operations.d \
|
||||
core/internal/array/utils.d core/internal/atomic.d \
|
||||
core/internal/attributes.d core/internal/container/array.d \
|
||||
core/internal/container/common.d core/internal/container/hashtab.d \
|
||||
core/internal/container/treap.d core/internal/convert.d \
|
||||
core/internal/dassert.d core/internal/destruction.d \
|
||||
core/internal/entrypoint.d core/internal/gc/bits.d \
|
||||
core/internal/gc/impl/conservative/gc.d \
|
||||
core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \
|
||||
core/internal/gc/os.d core/internal/gc/pooltable.d \
|
||||
core/internal/gc/proxy.d core/internal/hash.d core/internal/lifetime.d \
|
||||
|
@ -1201,6 +1203,8 @@ core/internal/array/$(am__dirstamp):
|
|||
@$(MKDIR_P) core/internal/array
|
||||
@: > core/internal/array/$(am__dirstamp)
|
||||
core/internal/array/appending.lo: core/internal/array/$(am__dirstamp)
|
||||
core/internal/array/arrayassign.lo: \
|
||||
core/internal/array/$(am__dirstamp)
|
||||
core/internal/array/capacity.lo: core/internal/array/$(am__dirstamp)
|
||||
core/internal/array/casting.lo: core/internal/array/$(am__dirstamp)
|
||||
core/internal/array/comparison.lo: \
|
||||
|
|
|
@ -2328,7 +2328,7 @@ char[] mangle(T)(return scope const(char)[] fqn, return scope char[] dst = null)
|
|||
|
||||
@property bool empty() const { return !s.length; }
|
||||
|
||||
@property const(char)[] front() const return
|
||||
@property const(char)[] front() const return scope
|
||||
{
|
||||
immutable i = indexOfDot();
|
||||
return i == -1 ? s[0 .. $] : s[0 .. i];
|
||||
|
|
|
@ -14,7 +14,7 @@ void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted
|
|||
{
|
||||
// Consider making this a compile time check.
|
||||
version (D_Exceptions)
|
||||
throw staticError!SwitchError(file, line, null);
|
||||
throw staticError!SwitchError("No appropriate switch clause found", file, line, null);
|
||||
else
|
||||
assert(0, "No appropriate switch clause found");
|
||||
}
|
||||
|
@ -446,16 +446,16 @@ class ForkError : Error
|
|||
*/
|
||||
class SwitchError : Error
|
||||
{
|
||||
@safe pure nothrow @nogc this( string file = __FILE__, size_t line = __LINE__, Throwable next = null )
|
||||
@safe pure nothrow @nogc this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
|
||||
{
|
||||
super( "No appropriate switch clause found", file, line, next );
|
||||
super( msg, file, line, next );
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
{
|
||||
auto se = new SwitchError();
|
||||
auto se = new SwitchError("No appropriate switch clause found");
|
||||
assert(se.file == __FILE__);
|
||||
assert(se.line == __LINE__ - 2);
|
||||
assert(se.next is null);
|
||||
|
@ -463,7 +463,7 @@ unittest
|
|||
}
|
||||
|
||||
{
|
||||
auto se = new SwitchError("hello", 42, new Exception("It's an Exception!"));
|
||||
auto se = new SwitchError("No appropriate switch clause found", "hello", 42, new Exception("It's an Exception!"));
|
||||
assert(se.file == "hello");
|
||||
assert(se.line == 42);
|
||||
assert(se.next !is null);
|
||||
|
|
304
libphobos/libdruntime/core/internal/array/arrayassign.d
Normal file
304
libphobos/libdruntime/core/internal/array/arrayassign.d
Normal file
|
@ -0,0 +1,304 @@
|
|||
module core.internal.array.arrayassign;
|
||||
|
||||
// Force `enforceRawArraysConformable` to remain `pure` `@nogc`
|
||||
private void enforceRawArraysConformable(const char[] action, const size_t elementSize,
|
||||
const void[] a1, const void[] a2, const bool allowOverlap) @trusted @nogc pure nothrow
|
||||
{
|
||||
import core.internal.util.array : enforceRawArraysConformable;
|
||||
|
||||
alias Type = void function(const char[] action, const size_t elementSize,
|
||||
const void[] a1, const void[] a2, in bool allowOverlap = false) @nogc pure nothrow;
|
||||
(cast(Type)&enforceRawArraysConformable)(action, elementSize, a1, a2, allowOverlap);
|
||||
}
|
||||
|
||||
private template CopyElem(string CopyAction)
|
||||
{
|
||||
const char[] CopyElem = "{\n" ~ q{
|
||||
memcpy(&tmp, cast(void*) &dst, elemSize);
|
||||
} ~ CopyAction ~ q{
|
||||
auto elem = cast(Unqual!T*) &tmp;
|
||||
destroy(*elem);
|
||||
} ~ "}\n";
|
||||
}
|
||||
|
||||
private template CopyArray(bool CanOverlap, string CopyAction)
|
||||
{
|
||||
const char[] CopyArray = CanOverlap ? q{
|
||||
if (vFrom.ptr < vTo.ptr && vTo.ptr < vFrom.ptr + elemSize * vFrom.length)
|
||||
foreach_reverse (i, ref dst; to)
|
||||
} ~ CopyElem!(CopyAction) ~ q{
|
||||
else
|
||||
foreach (i, ref dst; to)
|
||||
} ~ CopyElem!(CopyAction)
|
||||
: q{
|
||||
foreach (i, ref dst; to)
|
||||
} ~ CopyElem!(CopyAction);
|
||||
}
|
||||
|
||||
private template ArrayAssign(string CopyLogic, string AllowOverLap)
|
||||
{
|
||||
const char[] ArrayAssign = q{
|
||||
import core.internal.traits : hasElaborateCopyConstructor, Unqual;
|
||||
import core.lifetime : copyEmplace;
|
||||
import core.stdc.string : memcpy;
|
||||
|
||||
void[] vFrom = (cast(void*) from.ptr)[0 .. from.length];
|
||||
void[] vTo = (cast(void*) to.ptr)[0 .. to.length];
|
||||
enum elemSize = T.sizeof;
|
||||
|
||||
enforceRawArraysConformable("copy", elemSize, vFrom, vTo, } ~ AllowOverLap ~ q{);
|
||||
|
||||
void[elemSize] tmp = void;
|
||||
|
||||
} ~ CopyLogic ~ q{
|
||||
|
||||
return to;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Does array assignment (not construction) from another array of the same
|
||||
* element type. Handles overlapping copies. Assumes the right hand side is an
|
||||
* lvalue,
|
||||
*
|
||||
* Used for static array assignment with non-POD element types:
|
||||
* ---
|
||||
* struct S
|
||||
* {
|
||||
* ~this() {} // destructor, so not Plain Old Data
|
||||
* }
|
||||
*
|
||||
* void main()
|
||||
* {
|
||||
* S[3] arr;
|
||||
* S[3] lvalue;
|
||||
*
|
||||
* arr = lvalue;
|
||||
* // Generates:
|
||||
* // _d_arrayassign_l(arr[], lvalue[]), arr;
|
||||
* }
|
||||
* ---
|
||||
*
|
||||
* Params:
|
||||
* to = destination array
|
||||
* from = source array
|
||||
* Returns:
|
||||
* `to`
|
||||
*/
|
||||
Tarr _d_arrayassign_l(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted
|
||||
{
|
||||
mixin(ArrayAssign!(q{
|
||||
static if (hasElaborateCopyConstructor!T)
|
||||
} ~ CopyArray!(true, "copyEmplace(from[i], dst);") ~ q{
|
||||
else
|
||||
} ~ CopyArray!(true, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"),
|
||||
"true"));
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
int counter;
|
||||
struct S
|
||||
{
|
||||
int val;
|
||||
this(int val) { this.val = val; }
|
||||
this(const scope ref S rhs)
|
||||
{
|
||||
val = rhs.val;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
S[4] arr1;
|
||||
S[4] arr2 = [S(0), S(1), S(2), S(3)];
|
||||
_d_arrayassign_l(arr1[], arr2[]);
|
||||
|
||||
assert(counter == 4);
|
||||
assert(arr1 == arr2);
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
@safe unittest
|
||||
{
|
||||
int counter;
|
||||
struct S
|
||||
{
|
||||
int val;
|
||||
this(int val) { this.val = val; }
|
||||
this(const scope ref S rhs)
|
||||
{
|
||||
val = rhs.val;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
S[4] arr1;
|
||||
S[4] arr2 = [S(0), S(1), S(2), S(3)];
|
||||
_d_arrayassign_l(arr1[], arr2[]);
|
||||
|
||||
assert(counter == 4);
|
||||
assert(arr1 == arr2);
|
||||
}
|
||||
|
||||
@safe nothrow unittest
|
||||
{
|
||||
// Test that throwing works
|
||||
int counter;
|
||||
bool didThrow;
|
||||
|
||||
struct Throw
|
||||
{
|
||||
int val;
|
||||
this(this)
|
||||
{
|
||||
counter++;
|
||||
if (counter == 2)
|
||||
throw new Exception("");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
Throw[4] a;
|
||||
Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)];
|
||||
_d_arrayassign_l(a[], b[]);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
didThrow = true;
|
||||
}
|
||||
assert(didThrow);
|
||||
assert(counter == 2);
|
||||
|
||||
|
||||
// Test that `nothrow` works
|
||||
didThrow = false;
|
||||
counter = 0;
|
||||
struct NoThrow
|
||||
{
|
||||
int val;
|
||||
this(this)
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
NoThrow[4] a;
|
||||
NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
|
||||
_d_arrayassign_l(a[], b[]);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
didThrow = false;
|
||||
}
|
||||
assert(!didThrow);
|
||||
assert(counter == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does array assignment (not construction) from another array of the same
|
||||
* element type. Does not support overlapping copies. Assumes the right hand
|
||||
* side is an rvalue,
|
||||
*
|
||||
* Used for static array assignment with non-POD element types:
|
||||
* ---
|
||||
* struct S
|
||||
* {
|
||||
* ~this() {} // destructor, so not Plain Old Data
|
||||
* }
|
||||
*
|
||||
* void main()
|
||||
* {
|
||||
* S[3] arr;
|
||||
* S[3] getRvalue() {return lvalue;}
|
||||
*
|
||||
* arr = getRvalue();
|
||||
* // Generates:
|
||||
* // (__appendtmp = getRvalue), _d_arrayassign_l(arr[], __appendtmp), arr;
|
||||
* }
|
||||
* ---
|
||||
*
|
||||
* Params:
|
||||
* to = destination array
|
||||
* from = source array
|
||||
* Returns:
|
||||
* `to`
|
||||
*/
|
||||
Tarr _d_arrayassign_r(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted
|
||||
{
|
||||
mixin(ArrayAssign!(
|
||||
CopyArray!(false, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"),
|
||||
"false"));
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
int counter;
|
||||
struct S
|
||||
{
|
||||
int val;
|
||||
this(int val) { this.val = val; }
|
||||
this(const scope ref S rhs)
|
||||
{
|
||||
val = rhs.val;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
S[4] arr1;
|
||||
S[4] arr2 = [S(0), S(1), S(2), S(3)];
|
||||
_d_arrayassign_r(arr1[], arr2[]);
|
||||
|
||||
assert(counter == 0);
|
||||
assert(arr1 == arr2);
|
||||
}
|
||||
|
||||
// copy constructor
|
||||
@safe unittest
|
||||
{
|
||||
int counter;
|
||||
struct S
|
||||
{
|
||||
int val;
|
||||
this(int val) { this.val = val; }
|
||||
this(const scope ref S rhs)
|
||||
{
|
||||
val = rhs.val;
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
S[4] arr1;
|
||||
S[4] arr2 = [S(0), S(1), S(2), S(3)];
|
||||
_d_arrayassign_r(arr1[], arr2[]);
|
||||
|
||||
assert(counter == 0);
|
||||
assert(arr1 == arr2);
|
||||
}
|
||||
|
||||
@safe nothrow unittest
|
||||
{
|
||||
// Test that `nothrow` works
|
||||
bool didThrow = false;
|
||||
int counter = 0;
|
||||
struct NoThrow
|
||||
{
|
||||
int val;
|
||||
this(this)
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
NoThrow[4] a;
|
||||
NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
|
||||
_d_arrayassign_r(a[], b[]);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
didThrow = false;
|
||||
}
|
||||
assert(!didThrow);
|
||||
assert(counter == 0);
|
||||
}
|
|
@ -236,6 +236,33 @@ unittest
|
|||
static assert(!useMemcmp!(int[], int[]));
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21094
|
||||
unittest
|
||||
{
|
||||
static class C
|
||||
{
|
||||
int a;
|
||||
}
|
||||
static struct S
|
||||
{
|
||||
bool isValid;
|
||||
C fib;
|
||||
|
||||
inout(C) get() pure @safe @nogc nothrow inout
|
||||
{
|
||||
return isValid ? fib : C.init;
|
||||
}
|
||||
T opCast(T : C)() const { return null; }
|
||||
|
||||
alias get this;
|
||||
}
|
||||
|
||||
auto foo(S[] lhs, S[] rhs)
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a reference to an array element, eliding bounds check and
|
||||
// casting void to ubyte.
|
||||
pragma(inline, true)
|
||||
|
|
|
@ -188,10 +188,40 @@ version (linux)
|
|||
|
||||
extern (D) inout(ubyte)* CMSG_DATA( return scope inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); }
|
||||
|
||||
private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc;
|
||||
extern (D) inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc
|
||||
version (CRuntime_Musl)
|
||||
{
|
||||
return __cmsg_nxthdr(msg, cmsg);
|
||||
extern (D)
|
||||
{
|
||||
private size_t __CMSG_LEN(inout(cmsghdr)* cmsg) pure nothrow @nogc
|
||||
{
|
||||
return (cmsg.cmsg_len + size_t.sizeof -1) & cast(size_t)(~(size_t.sizeof - 1));
|
||||
}
|
||||
|
||||
private inout(cmsghdr)* __CMSG_NEXT(inout(cmsghdr)* cmsg) pure nothrow @nogc
|
||||
{
|
||||
return cmsg + __CMSG_LEN(cmsg);
|
||||
}
|
||||
|
||||
private inout(msghdr)* __MHDR_END(inout(msghdr)* mhdr) pure nothrow @nogc
|
||||
{
|
||||
return cast(inout(msghdr)*)(mhdr.msg_control + mhdr.msg_controllen);
|
||||
}
|
||||
|
||||
inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc
|
||||
{
|
||||
return cmsg.cmsg_len < cmsghdr.sizeof ||
|
||||
__CMSG_LEN(cmsg) + cmsghdr.sizeof >= __MHDR_END(msg) - cast(inout(msghdr)*)(cmsg)
|
||||
? cast(inout(cmsghdr)*) null : cast(inout(cmsghdr)*) __CMSG_NEXT(cmsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc;
|
||||
extern (D) inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc
|
||||
{
|
||||
return __cmsg_nxthdr(msg, cmsg);
|
||||
}
|
||||
}
|
||||
|
||||
extern (D) inout(cmsghdr)* CMSG_FIRSTHDR( inout(msghdr)* mhdr ) pure nothrow @nogc
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* $(TR $(TD Arrays) $(TD
|
||||
* $(MYREF assumeSafeAppend)
|
||||
* $(MYREF capacity)
|
||||
* $(A #.dup.2, $(TT dup))
|
||||
* $(MYREF idup)
|
||||
* $(MYREF reserve)
|
||||
* ))
|
||||
|
@ -14,6 +15,7 @@
|
|||
* $(MYREF byKeyValue)
|
||||
* $(MYREF byValue)
|
||||
* $(MYREF clear)
|
||||
* $(MYREF dup)
|
||||
* $(MYREF get)
|
||||
* $(MYREF keys)
|
||||
* $(MYREF rehash)
|
||||
|
@ -23,15 +25,15 @@
|
|||
* ))
|
||||
* $(TR $(TD General) $(TD
|
||||
* $(MYREF destroy)
|
||||
* $(MYREF dup)
|
||||
* $(MYREF hashOf)
|
||||
* $(MYREF opEquals)
|
||||
* $(MYREF imported)
|
||||
* $(MYREF noreturn)
|
||||
* ))
|
||||
* $(TR $(TD Types) $(TD
|
||||
* $(TR $(TD Classes) $(TD
|
||||
* $(MYREF Error)
|
||||
* $(MYREF Exception)
|
||||
* $(MYREF noreturn)
|
||||
* $(MYREF Object)
|
||||
* $(MYREF opEquals)
|
||||
* $(MYREF Throwable)
|
||||
* ))
|
||||
* $(TR $(TD Type info) $(TD
|
||||
|
@ -61,7 +63,11 @@ alias size_t = typeof(int.sizeof);
|
|||
alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0);
|
||||
|
||||
alias sizediff_t = ptrdiff_t; // For backwards compatibility only.
|
||||
alias noreturn = typeof(*null); /// bottom type
|
||||
/**
|
||||
* Bottom type.
|
||||
* See $(DDSUBLINK spec/type, noreturn).
|
||||
*/
|
||||
alias noreturn = typeof(*null);
|
||||
|
||||
alias hash_t = size_t; // For backwards compatibility only.
|
||||
alias equals_t = bool; // For backwards compatibility only.
|
||||
|
@ -266,7 +272,9 @@ class Object
|
|||
the typeinfo name string compare. This is because of dmd's dll implementation. However,
|
||||
it can infer to @safe if your class' opEquals is.
|
||||
+/
|
||||
bool opEquals(LHS, RHS)(LHS lhs, RHS rhs) if (is(LHS : const Object) && is(RHS : const Object))
|
||||
bool opEquals(LHS, RHS)(LHS lhs, RHS rhs)
|
||||
if ((is(LHS : const Object) || is(LHS : const shared Object)) &&
|
||||
(is(RHS : const Object) || is(RHS : const shared Object)))
|
||||
{
|
||||
static if (__traits(compiles, lhs.opEquals(rhs)) && __traits(compiles, rhs.opEquals(lhs)))
|
||||
{
|
||||
|
@ -505,6 +513,16 @@ unittest
|
|||
assert(obj1 != obj2);
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23291
|
||||
@system unittest
|
||||
{
|
||||
static shared class C { bool opEquals(const(shared(C)) rhs) const shared { return true;}}
|
||||
const(C) c = new C();
|
||||
const(C)[] a = [c];
|
||||
const(C)[] b = [c];
|
||||
assert(a[0] == b[0]);
|
||||
}
|
||||
|
||||
private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow;
|
||||
|
||||
void setSameMutex(shared Object ownee, shared Object owner)
|
||||
|
@ -3473,13 +3491,18 @@ ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init)
|
|||
private enum bool isSafeCopyable(T) = is(typeof(() @safe { union U { T x; } T *x; auto u = U(*x); }));
|
||||
|
||||
/***********************************
|
||||
* Looks up key; if it exists applies the update callable else evaluates the
|
||||
* create callable and adds it to the associative array
|
||||
* Calls `create` if `key` doesn't exist in the associative array,
|
||||
* otherwise calls `update`.
|
||||
* `create` returns a corresponding value for `key`.
|
||||
* `update` accepts a key parameter. If it returns a value, the value is
|
||||
* set for `key`.
|
||||
* Params:
|
||||
* aa = The associative array.
|
||||
* key = The key.
|
||||
* create = The callable to apply on create.
|
||||
* update = The callable to apply on update.
|
||||
* create = The callable to create a value for `key`.
|
||||
* Must return V.
|
||||
* update = The callable to call if `key` exists.
|
||||
* Takes a K argument, returns a V or void.
|
||||
*/
|
||||
void update(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update)
|
||||
if (is(typeof(create()) : V) && (is(typeof(update(aa[K.init])) : V) || is(typeof(update(aa[K.init])) == void)))
|
||||
|
@ -3509,23 +3532,39 @@ if (is(typeof(create()) : V) && (is(typeof(update(aa[K.init])) : V) || is(typeof
|
|||
}
|
||||
|
||||
///
|
||||
@system unittest
|
||||
@safe unittest
|
||||
{
|
||||
auto aa = ["k1": 1];
|
||||
int[string] aa;
|
||||
|
||||
aa.update("k1", {
|
||||
return -1; // create (won't be executed)
|
||||
}, (ref int v) {
|
||||
v += 1; // update
|
||||
});
|
||||
assert(aa["k1"] == 2);
|
||||
// create
|
||||
aa.update("key",
|
||||
() => 1,
|
||||
(int) {} // not executed
|
||||
);
|
||||
assert(aa["key"] == 1);
|
||||
|
||||
aa.update("k2", {
|
||||
return 0; // create
|
||||
}, (ref int v) {
|
||||
v = -1; // update (won't be executed)
|
||||
});
|
||||
assert(aa["k2"] == 0);
|
||||
// update value by ref
|
||||
aa.update("key",
|
||||
() => 0, // not executed
|
||||
(ref int v) {
|
||||
v += 1;
|
||||
});
|
||||
assert(aa["key"] == 2);
|
||||
|
||||
// update from return value
|
||||
aa.update("key",
|
||||
() => 0, // not executed
|
||||
(int v) => v * 2
|
||||
);
|
||||
assert(aa["key"] == 4);
|
||||
|
||||
// 'update' without changing value
|
||||
aa.update("key",
|
||||
() => 0, // not executed
|
||||
(int) {
|
||||
// do something else
|
||||
});
|
||||
assert(aa["key"] == 4);
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
|
@ -4576,6 +4615,8 @@ public import core.internal.array.casting: __ArrayCast;
|
|||
public import core.internal.array.concatenation : _d_arraycatnTXImpl;
|
||||
public import core.internal.array.construction : _d_arrayctor;
|
||||
public import core.internal.array.construction : _d_arraysetctor;
|
||||
public import core.internal.array.arrayassign : _d_arrayassign_l;
|
||||
public import core.internal.array.arrayassign : _d_arrayassign_r;
|
||||
public import core.internal.array.capacity: _d_arraysetlengthTImpl;
|
||||
|
||||
public import core.internal.dassert: _d_assert_fail;
|
||||
|
|
|
@ -19,171 +19,6 @@ private
|
|||
debug(PRINTF) import core.stdc.stdio;
|
||||
}
|
||||
|
||||
/*
|
||||
* Superseded array assignment hook. Does not take into account destructors:
|
||||
* https://issues.dlang.org/show_bug.cgi?id=13661
|
||||
* Kept for backward binary compatibility. This function can be removed in the future.
|
||||
*/
|
||||
extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to)
|
||||
{
|
||||
debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize);
|
||||
|
||||
immutable elementSize = ti.tsize;
|
||||
|
||||
// Need a temporary buffer tmp[] big enough to hold one element
|
||||
void[16] buf = void;
|
||||
void* ptmp = (elementSize > buf.sizeof) ? malloc(elementSize) : buf.ptr;
|
||||
scope (exit)
|
||||
{
|
||||
if (ptmp != buf.ptr)
|
||||
free(ptmp);
|
||||
}
|
||||
return _d_arrayassign_l(ti, from, to, ptmp);
|
||||
}
|
||||
|
||||
/**
|
||||
Does array assignment (not construction) from another array of the same
|
||||
element type.
|
||||
|
||||
Handles overlapping copies.
|
||||
|
||||
The `_d_arrayassign_l` variant assumes the right hand side is an lvalue,
|
||||
while `_d_arrayassign_r` assumes it's an rvalue, which means it doesn't have to call copy constructors.
|
||||
|
||||
Used for static array assignment with non-POD element types:
|
||||
---
|
||||
struct S
|
||||
{
|
||||
~this() {} // destructor, so not Plain Old Data
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S[3] arr;
|
||||
S[3] lvalue;
|
||||
|
||||
arr = lvalue;
|
||||
// Generates:
|
||||
// S _tmp;
|
||||
// _d_arrayassign_l(typeid(S), (cast(void*) lvalue.ptr)[0..lvalue.length], (cast(void*) arr.ptr)[0..arr.length], &_tmp);
|
||||
|
||||
S[3] getRvalue() {return lvalue;}
|
||||
arr = getRvalue();
|
||||
// Similar, but `_d_arrayassign_r`
|
||||
}
|
||||
---
|
||||
|
||||
Params:
|
||||
ti = `TypeInfo` of the array element type.
|
||||
dst = target memory. Its `.length` is equal to the element count, not byte length.
|
||||
src = source memory. Its `.length` is equal to the element count, not byte length.
|
||||
ptmp = Temporary memory for element swapping, must have capacity of `ti.tsize` bytes.
|
||||
Returns: `dst`
|
||||
*/
|
||||
extern (C) void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp)
|
||||
{
|
||||
debug(PRINTF) printf("_d_arrayassign_l(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize);
|
||||
|
||||
immutable elementSize = ti.tsize;
|
||||
|
||||
enforceRawArraysConformable("copy", elementSize, src, dst, true);
|
||||
|
||||
if (src.ptr < dst.ptr && dst.ptr < src.ptr + elementSize * src.length)
|
||||
{
|
||||
// If dst is in the middle of src memory, use reverse order.
|
||||
for (auto i = dst.length; i--; )
|
||||
{
|
||||
void* pdst = dst.ptr + i * elementSize;
|
||||
void* psrc = src.ptr + i * elementSize;
|
||||
memcpy(ptmp, pdst, elementSize);
|
||||
memcpy(pdst, psrc, elementSize);
|
||||
ti.postblit(pdst);
|
||||
ti.destroy(ptmp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, use normal order.
|
||||
foreach (i; 0 .. dst.length)
|
||||
{
|
||||
void* pdst = dst.ptr + i * elementSize;
|
||||
void* psrc = src.ptr + i * elementSize;
|
||||
memcpy(ptmp, pdst, elementSize);
|
||||
memcpy(pdst, psrc, elementSize);
|
||||
ti.postblit(pdst);
|
||||
ti.destroy(ptmp);
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
unittest // Bugzilla 14024
|
||||
{
|
||||
string op;
|
||||
|
||||
struct S
|
||||
{
|
||||
char x = 'x';
|
||||
this(this) { op ~= x-0x20; } // upper case
|
||||
~this() { op ~= x; } // lower case
|
||||
}
|
||||
|
||||
S[4] mem;
|
||||
ref S[2] slice(int a, int b) { return mem[a .. b][0 .. 2]; }
|
||||
|
||||
op = null;
|
||||
mem[0].x = 'a';
|
||||
mem[1].x = 'b';
|
||||
mem[2].x = 'x';
|
||||
mem[3].x = 'y';
|
||||
slice(0, 2) = slice(2, 4); // [ab] = [xy]
|
||||
assert(op == "XaYb", op);
|
||||
|
||||
op = null;
|
||||
mem[0].x = 'x';
|
||||
mem[1].x = 'y';
|
||||
mem[2].x = 'a';
|
||||
mem[3].x = 'b';
|
||||
slice(2, 4) = slice(0, 2); // [ab] = [xy]
|
||||
assert(op == "XaYb", op);
|
||||
|
||||
op = null;
|
||||
mem[0].x = 'a';
|
||||
mem[1].x = 'b';
|
||||
mem[2].x = 'c';
|
||||
slice(0, 2) = slice(1, 3); // [ab] = [bc]
|
||||
assert(op == "BaCb", op);
|
||||
|
||||
op = null;
|
||||
mem[0].x = 'x';
|
||||
mem[1].x = 'y';
|
||||
mem[2].x = 'z';
|
||||
slice(1, 3) = slice(0, 2); // [yz] = [xy]
|
||||
assert(op == "YzXy", op);
|
||||
}
|
||||
|
||||
/// ditto
|
||||
extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp)
|
||||
{
|
||||
debug(PRINTF) printf("_d_arrayassign_r(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize);
|
||||
|
||||
immutable elementSize = ti.tsize;
|
||||
|
||||
enforceRawArraysConformable("copy", elementSize, src, dst, false);
|
||||
|
||||
// Always use normal order, because we can assume that
|
||||
// the rvalue src has no overlapping with dst.
|
||||
foreach (i; 0 .. dst.length)
|
||||
{
|
||||
void* pdst = dst.ptr + i * elementSize;
|
||||
void* psrc = src.ptr + i * elementSize;
|
||||
memcpy(ptmp, pdst, elementSize);
|
||||
memcpy(pdst, psrc, elementSize);
|
||||
ti.destroy(ptmp);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
Set all elements of an array to a single value.
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
5748ca43fd5c3e31ce7a8511f542b67e5d5a3dc6
|
||||
b578dfad94770574d7e522557a77276c35943daa
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/phobos repository.
|
||||
|
|
|
@ -127,11 +127,10 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \
|
|||
std/experimental/logger/core.d std/experimental/logger/filelogger.d \
|
||||
std/experimental/logger/multilogger.d \
|
||||
std/experimental/logger/nulllogger.d std/experimental/logger/package.d \
|
||||
std/experimental/typecons.d std/file.d std/format/internal/floats.d \
|
||||
std/format/internal/read.d std/format/internal/write.d \
|
||||
std/format/package.d std/format/read.d std/format/spec.d \
|
||||
std/format/write.d std/functional.d std/getopt.d std/int128.d \
|
||||
std/internal/attributes.d std/internal/cstring.d \
|
||||
std/file.d std/format/internal/floats.d std/format/internal/read.d \
|
||||
std/format/internal/write.d std/format/package.d std/format/read.d \
|
||||
std/format/spec.d std/format/write.d std/functional.d std/getopt.d \
|
||||
std/int128.d std/internal/attributes.d std/internal/cstring.d \
|
||||
std/internal/math/biguintcore.d std/internal/math/biguintnoasm.d \
|
||||
std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
|
||||
std/internal/memory.d std/internal/scopebuffer.d \
|
||||
|
@ -139,7 +138,9 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \
|
|||
std/internal/test/uda.d std/internal/unicode_comp.d \
|
||||
std/internal/unicode_decomp.d std/internal/unicode_grapheme.d \
|
||||
std/internal/unicode_norm.d std/internal/unicode_tables.d \
|
||||
std/internal/windows/advapi32.d std/json.d std/math/algebraic.d \
|
||||
std/internal/windows/advapi32.d std/json.d std/logger/core.d \
|
||||
std/logger/filelogger.d std/logger/multilogger.d \
|
||||
std/logger/nulllogger.d std/logger/package.d std/math/algebraic.d \
|
||||
std/math/constants.d std/math/exponential.d std/math/hardware.d \
|
||||
std/math/operations.d std/math/package.d std/math/remainder.d \
|
||||
std/math/rounding.d std/math/traits.d std/math/trigonometry.d \
|
||||
|
|
|
@ -218,7 +218,6 @@ am__dirstamp = $(am__leading_dot)dirstamp
|
|||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/logger/multilogger.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/logger/nulllogger.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/logger/package.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/typecons.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/file.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/internal/floats.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/internal/read.lo \
|
||||
|
@ -246,7 +245,11 @@ am__dirstamp = $(am__leading_dot)dirstamp
|
|||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_norm.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_tables.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/windows/advapi32.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/json.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/json.lo std/logger/core.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/filelogger.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/multilogger.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/nulllogger.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/package.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/algebraic.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/constants.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/exponential.lo \
|
||||
|
@ -589,11 +592,10 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \
|
|||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/logger/core.d std/experimental/logger/filelogger.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/logger/multilogger.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/logger/nulllogger.d std/experimental/logger/package.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/typecons.d std/file.d std/format/internal/floats.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/internal/read.d std/format/internal/write.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/package.d std/format/read.d std/format/spec.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/write.d std/functional.d std/getopt.d std/int128.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/attributes.d std/internal/cstring.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/file.d std/format/internal/floats.d std/format/internal/read.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/internal/write.d std/format/package.d std/format/read.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/spec.d std/format/write.d std/functional.d std/getopt.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/int128.d std/internal/attributes.d std/internal/cstring.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/biguintcore.d std/internal/math/biguintnoasm.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/memory.d std/internal/scopebuffer.d \
|
||||
|
@ -601,7 +603,9 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \
|
|||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/uda.d std/internal/unicode_comp.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_decomp.d std/internal/unicode_grapheme.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_norm.d std/internal/unicode_tables.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/windows/advapi32.d std/json.d std/math/algebraic.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/windows/advapi32.d std/json.d std/logger/core.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/filelogger.d std/logger/multilogger.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/nulllogger.d std/logger/package.d std/math/algebraic.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/constants.d std/math/exponential.d std/math/hardware.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/operations.d std/math/package.d std/math/remainder.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/rounding.d std/math/traits.d std/math/trigonometry.d \
|
||||
|
@ -830,7 +834,6 @@ std/experimental/logger/nulllogger.lo: \
|
|||
std/experimental/logger/$(am__dirstamp)
|
||||
std/experimental/logger/package.lo: \
|
||||
std/experimental/logger/$(am__dirstamp)
|
||||
std/experimental/typecons.lo: std/experimental/$(am__dirstamp)
|
||||
std/file.lo: std/$(am__dirstamp)
|
||||
std/format/internal/$(am__dirstamp):
|
||||
@$(MKDIR_P) std/format/internal
|
||||
|
@ -879,6 +882,14 @@ std/internal/windows/$(am__dirstamp):
|
|||
std/internal/windows/advapi32.lo: \
|
||||
std/internal/windows/$(am__dirstamp)
|
||||
std/json.lo: std/$(am__dirstamp)
|
||||
std/logger/$(am__dirstamp):
|
||||
@$(MKDIR_P) std/logger
|
||||
@: > std/logger/$(am__dirstamp)
|
||||
std/logger/core.lo: std/logger/$(am__dirstamp)
|
||||
std/logger/filelogger.lo: std/logger/$(am__dirstamp)
|
||||
std/logger/multilogger.lo: std/logger/$(am__dirstamp)
|
||||
std/logger/nulllogger.lo: std/logger/$(am__dirstamp)
|
||||
std/logger/package.lo: std/logger/$(am__dirstamp)
|
||||
std/math/$(am__dirstamp):
|
||||
@$(MKDIR_P) std/math
|
||||
@: > std/math/$(am__dirstamp)
|
||||
|
@ -994,6 +1005,8 @@ mostlyclean-compile:
|
|||
-rm -f std/internal/test/*.lo
|
||||
-rm -f std/internal/windows/*.$(OBJEXT)
|
||||
-rm -f std/internal/windows/*.lo
|
||||
-rm -f std/logger/*.$(OBJEXT)
|
||||
-rm -f std/logger/*.lo
|
||||
-rm -f std/math/*.$(OBJEXT)
|
||||
-rm -f std/math/*.lo
|
||||
-rm -f std/net/*.$(OBJEXT)
|
||||
|
@ -1033,6 +1046,7 @@ clean-libtool:
|
|||
-rm -rf std/internal/math/.libs std/internal/math/_libs
|
||||
-rm -rf std/internal/test/.libs std/internal/test/_libs
|
||||
-rm -rf std/internal/windows/.libs std/internal/windows/_libs
|
||||
-rm -rf std/logger/.libs std/logger/_libs
|
||||
-rm -rf std/math/.libs std/math/_libs
|
||||
-rm -rf std/net/.libs std/net/_libs
|
||||
-rm -rf std/range/.libs std/range/_libs
|
||||
|
@ -1162,6 +1176,7 @@ distclean-generic:
|
|||
-rm -f std/internal/math/$(am__dirstamp)
|
||||
-rm -f std/internal/test/$(am__dirstamp)
|
||||
-rm -f std/internal/windows/$(am__dirstamp)
|
||||
-rm -f std/logger/$(am__dirstamp)
|
||||
-rm -f std/math/$(am__dirstamp)
|
||||
-rm -f std/net/$(am__dirstamp)
|
||||
-rm -f std/range/$(am__dirstamp)
|
||||
|
|
|
@ -459,6 +459,19 @@ $(BOOKTABLE ,
|
|||
$(TDNW $(MREF core,simd))
|
||||
$(TD SIMD intrinsics)
|
||||
)
|
||||
$(LEADINGROW Logging)
|
||||
$(TR
|
||||
$(TDNW
|
||||
$(MREF std,logger)$(BR)
|
||||
$(MREF std,logger,core)$(BR)
|
||||
$(MREF std,logger,filelogger)$(BR)
|
||||
$(MREF std,logger,multilogger)$(BR)
|
||||
$(MREF std,logger,nulllogger)$(BR)
|
||||
)
|
||||
$(TD
|
||||
Logging.
|
||||
)
|
||||
)
|
||||
|
||||
$(COMMENT
|
||||
$(LEADINGROW Undocumented modules (intentionally omitted).)
|
||||
|
@ -509,18 +522,6 @@ $(COMMENT
|
|||
Deprecated modules.
|
||||
)
|
||||
)
|
||||
$(TR
|
||||
$(TDNW
|
||||
$(MREF std,experimental,logger)$(BR)
|
||||
$(MREF std,experimental,logger,core)$(BR)
|
||||
$(MREF std,experimental,logger,filelogger)$(BR)
|
||||
$(MREF std,experimental,logger,multilogger)$(BR)
|
||||
$(MREF std,experimental,logger,nulllogger)$(BR)
|
||||
)
|
||||
$(TD
|
||||
Experimental modules.
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -1798,7 +1798,7 @@ if (isInputRange!R)
|
|||
assert(equal(g3, [ tuple(1, 2u), tuple(2, 2u) ]));
|
||||
|
||||
interface I {}
|
||||
class C : I { override size_t toHash() const nothrow @safe { return 0; } }
|
||||
static class C : I { override size_t toHash() const nothrow @safe { return 0; } }
|
||||
const C[] a4 = [new const C()];
|
||||
auto g4 = a4.group!"a is b";
|
||||
assert(g4.front[1] == 1);
|
||||
|
@ -2255,25 +2255,26 @@ if (isForwardRange!Range)
|
|||
import std.algorithm.comparison : equal;
|
||||
|
||||
size_t popCount = 0;
|
||||
class RefFwdRange
|
||||
static class RefFwdRange
|
||||
{
|
||||
int[] impl;
|
||||
size_t* pcount;
|
||||
|
||||
@safe nothrow:
|
||||
|
||||
this(int[] data) { impl = data; }
|
||||
this(int[] data, size_t* pcount) { impl = data; this.pcount = pcount; }
|
||||
@property bool empty() { return impl.empty; }
|
||||
@property auto ref front() { return impl.front; }
|
||||
void popFront()
|
||||
{
|
||||
impl.popFront();
|
||||
popCount++;
|
||||
(*pcount)++;
|
||||
}
|
||||
@property auto save() { return new RefFwdRange(impl); }
|
||||
@property auto save() { return new RefFwdRange(impl, pcount); }
|
||||
}
|
||||
static assert(isForwardRange!RefFwdRange);
|
||||
|
||||
auto testdata = new RefFwdRange([1, 3, 5, 2, 4, 7, 6, 8, 9]);
|
||||
auto testdata = new RefFwdRange([1, 3, 5, 2, 4, 7, 6, 8, 9], &popCount);
|
||||
auto groups = testdata.chunkBy!((a,b) => (a % 2) == (b % 2));
|
||||
auto outerSave1 = groups.save;
|
||||
|
||||
|
@ -6058,7 +6059,7 @@ if (is(typeof(binaryFun!pred(r.front, s.front)) : bool)
|
|||
import std.algorithm.comparison : equal;
|
||||
|
||||
// Test by-reference separator
|
||||
class RefSep {
|
||||
static class RefSep {
|
||||
@safe:
|
||||
string _impl;
|
||||
this(string s) { _impl = s; }
|
||||
|
|
|
@ -13,7 +13,7 @@ $(T2 any,
|
|||
`any!"a > 0"([1, 2, -3, -4])` returns `true` because at least one
|
||||
element is positive)
|
||||
$(T2 balancedParens,
|
||||
`balancedParens("((1 + 1) / 2)")` returns `true` because the
|
||||
`balancedParens("((1 + 1) / 2)", '(', ')')` returns `true` because the
|
||||
string has balanced parentheses.)
|
||||
$(T2 boyerMooreFinder,
|
||||
`find("hello world", boyerMooreFinder("or"))` returns `"orld"`
|
||||
|
|
|
@ -2297,7 +2297,7 @@ if (isInputRange!RoR &&
|
|||
// https://issues.dlang.org/show_bug.cgi?id=10895
|
||||
@safe unittest
|
||||
{
|
||||
class A
|
||||
static class A
|
||||
{
|
||||
string name;
|
||||
alias name this;
|
||||
|
@ -4376,8 +4376,8 @@ unittest
|
|||
return app[];
|
||||
}
|
||||
|
||||
class C {}
|
||||
struct S { const(C) c; }
|
||||
static class C {}
|
||||
static struct S { const(C) c; }
|
||||
S[] s = [ S(new C) ];
|
||||
|
||||
auto t = fastCopy(s); // Does not compile
|
||||
|
|
|
@ -1541,7 +1541,7 @@ Returns:
|
|||
number in upper case.
|
||||
|
||||
*/
|
||||
string toHex(const(BigInt) x) @safe
|
||||
string toHex(const(BigInt) x) pure @safe
|
||||
{
|
||||
import std.array : appender;
|
||||
auto outbuff = appender!string();
|
||||
|
|
|
@ -478,6 +478,20 @@ if (isFloatingPoint!T)
|
|||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns a complex number instance that correponds in size and in ABI
|
||||
to the associated C compiler's `_Complex` type.
|
||||
*/
|
||||
auto toNative()
|
||||
{
|
||||
import core.stdc.config : c_complex_float, c_complex_double, c_complex_real;
|
||||
static if (is(T == float))
|
||||
return c_complex_float(re, im);
|
||||
else static if (is(T == double))
|
||||
return c_complex_double(re, im);
|
||||
else
|
||||
return c_complex_real(re, im);
|
||||
}
|
||||
}
|
||||
|
||||
@safe pure nothrow unittest
|
||||
|
@ -1910,3 +1924,14 @@ Complex!T pow(T)(const T x, Complex!T n) @trusted pure nothrow @nogc
|
|||
}
|
||||
}}
|
||||
}
|
||||
|
||||
@safe pure nothrow @nogc unittest
|
||||
{
|
||||
import std.meta : AliasSeq;
|
||||
static foreach (T; AliasSeq!(float, double, real))
|
||||
{{
|
||||
auto c = Complex!T(123, 456);
|
||||
auto n = c.toNative();
|
||||
assert(c.re == n.re && c.im == n.im);
|
||||
}}
|
||||
}
|
||||
|
|
|
@ -2055,7 +2055,7 @@ if ( is(typeof(binaryFun!less((ElementType!Stuff).init, (ElementType!Stuff).init
|
|||
}
|
||||
|
||||
//Combinations not in examples.
|
||||
@safe pure unittest
|
||||
@system pure unittest
|
||||
{
|
||||
auto rbt1 = redBlackTree!(true, string)("hello", "hello");
|
||||
auto rbt2 = redBlackTree!((a, b){return a < b;}, double)(5.1, 2.3);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,272 +1,13 @@
|
|||
// Written in the D programming language.
|
||||
/**
|
||||
Source: $(PHOBOSSRC std/experimental/logger/filelogger.d)
|
||||
*/
|
||||
* This module is now deprecated, use $(MREF std, logger, filelogger)
|
||||
* instead.
|
||||
*
|
||||
* Copyright: Copyright The D Language Foundation 2005 - 2015.
|
||||
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||
* Authors:
|
||||
* Source: $(PHOBOSSRC std/experimental/logger/filelogger.d)
|
||||
*
|
||||
* $(SCRIPT inhibitQuickIndex = 1;)
|
||||
*/
|
||||
module std.experimental.logger.filelogger;
|
||||
|
||||
import std.experimental.logger.core;
|
||||
import std.stdio;
|
||||
|
||||
import std.typecons : Flag;
|
||||
|
||||
/** An option to create $(LREF FileLogger) directory if it is non-existent.
|
||||
*/
|
||||
alias CreateFolder = Flag!"CreateFolder";
|
||||
|
||||
/** This `Logger` implementation writes log messages to the associated
|
||||
file. The name of the file has to be passed on construction time. If the file
|
||||
is already present new log messages will be append at its end.
|
||||
*/
|
||||
class FileLogger : Logger
|
||||
{
|
||||
import std.concurrency : Tid;
|
||||
import std.datetime.systime : SysTime;
|
||||
import std.format.write : formattedWrite;
|
||||
|
||||
/** A constructor for the `FileLogger` Logger.
|
||||
|
||||
Params:
|
||||
fn = The filename of the output file of the `FileLogger`. If that
|
||||
file can not be opened for writting an exception will be thrown.
|
||||
lv = The `LogLevel` for the `FileLogger`. By default the
|
||||
|
||||
Example:
|
||||
-------------
|
||||
auto l1 = new FileLogger("logFile");
|
||||
auto l2 = new FileLogger("logFile", LogLevel.fatal);
|
||||
auto l3 = new FileLogger("logFile", LogLevel.fatal, CreateFolder.yes);
|
||||
-------------
|
||||
*/
|
||||
this(const string fn, const LogLevel lv = LogLevel.all) @safe
|
||||
{
|
||||
this(fn, lv, CreateFolder.yes);
|
||||
}
|
||||
|
||||
/** A constructor for the `FileLogger` Logger that takes a reference to
|
||||
a `File`.
|
||||
|
||||
The `File` passed must be open for all the log call to the
|
||||
`FileLogger`. If the `File` gets closed, using the `FileLogger`
|
||||
for logging will result in undefined behaviour.
|
||||
|
||||
Params:
|
||||
fn = The file used for logging.
|
||||
lv = The `LogLevel` for the `FileLogger`. By default the
|
||||
`LogLevel` for `FileLogger` is `LogLevel.all`.
|
||||
createFileNameFolder = if yes and fn contains a folder name, this
|
||||
folder will be created.
|
||||
|
||||
Example:
|
||||
-------------
|
||||
auto file = File("logFile.log", "w");
|
||||
auto l1 = new FileLogger(file);
|
||||
auto l2 = new FileLogger(file, LogLevel.fatal);
|
||||
-------------
|
||||
*/
|
||||
this(const string fn, const LogLevel lv, CreateFolder createFileNameFolder) @safe
|
||||
{
|
||||
import std.file : exists, mkdirRecurse;
|
||||
import std.path : dirName;
|
||||
import std.conv : text;
|
||||
|
||||
super(lv);
|
||||
this.filename = fn;
|
||||
|
||||
if (createFileNameFolder)
|
||||
{
|
||||
auto d = dirName(this.filename);
|
||||
mkdirRecurse(d);
|
||||
assert(exists(d), text("The folder the FileLogger should have",
|
||||
" created in '", d,"' could not be created."));
|
||||
}
|
||||
|
||||
this.file_.open(this.filename, "a");
|
||||
}
|
||||
|
||||
/** A constructor for the `FileLogger` Logger that takes a reference to
|
||||
a `File`.
|
||||
|
||||
The `File` passed must be open for all the log call to the
|
||||
`FileLogger`. If the `File` gets closed, using the `FileLogger`
|
||||
for logging will result in undefined behaviour.
|
||||
|
||||
Params:
|
||||
file = The file used for logging.
|
||||
lv = The `LogLevel` for the `FileLogger`. By default the
|
||||
`LogLevel` for `FileLogger` is `LogLevel.all`.
|
||||
|
||||
Example:
|
||||
-------------
|
||||
auto file = File("logFile.log", "w");
|
||||
auto l1 = new FileLogger(file);
|
||||
auto l2 = new FileLogger(file, LogLevel.fatal);
|
||||
-------------
|
||||
*/
|
||||
this(File file, const LogLevel lv = LogLevel.all) @safe
|
||||
{
|
||||
super(lv);
|
||||
this.file_ = file;
|
||||
}
|
||||
|
||||
/** If the `FileLogger` is managing the `File` it logs to, this
|
||||
method will return a reference to this File.
|
||||
*/
|
||||
@property File file() @safe
|
||||
{
|
||||
return this.file_;
|
||||
}
|
||||
|
||||
/* This method overrides the base class method in order to log to a file
|
||||
without requiring heap allocated memory. Additionally, the `FileLogger`
|
||||
local mutex is logged to serialize the log calls.
|
||||
*/
|
||||
override protected void beginLogMsg(string file, int line, string funcName,
|
||||
string prettyFuncName, string moduleName, LogLevel logLevel,
|
||||
Tid threadId, SysTime timestamp, Logger logger)
|
||||
@safe
|
||||
{
|
||||
import std.string : lastIndexOf;
|
||||
ptrdiff_t fnIdx = file.lastIndexOf('/') + 1;
|
||||
ptrdiff_t funIdx = funcName.lastIndexOf('.') + 1;
|
||||
|
||||
auto lt = this.file_.lockingTextWriter();
|
||||
systimeToISOString(lt, timestamp);
|
||||
import std.conv : to;
|
||||
formattedWrite(lt, " [%s] %s:%u:%s ", logLevel.to!string,
|
||||
file[fnIdx .. $], line, funcName[funIdx .. $]);
|
||||
}
|
||||
|
||||
/* This methods overrides the base class method and writes the parts of
|
||||
the log call directly to the file.
|
||||
*/
|
||||
override protected void logMsgPart(scope const(char)[] msg)
|
||||
{
|
||||
formattedWrite(this.file_.lockingTextWriter(), "%s", msg);
|
||||
}
|
||||
|
||||
/* This methods overrides the base class method and finalizes the active
|
||||
log call. This requires flushing the `File` and releasing the
|
||||
`FileLogger` local mutex.
|
||||
*/
|
||||
override protected void finishLogMsg()
|
||||
{
|
||||
this.file_.lockingTextWriter().put("\n");
|
||||
this.file_.flush();
|
||||
}
|
||||
|
||||
/* This methods overrides the base class method and delegates the
|
||||
`LogEntry` data to the actual implementation.
|
||||
*/
|
||||
override protected void writeLogMsg(ref LogEntry payload)
|
||||
{
|
||||
this.beginLogMsg(payload.file, payload.line, payload.funcName,
|
||||
payload.prettyFuncName, payload.moduleName, payload.logLevel,
|
||||
payload.threadId, payload.timestamp, payload.logger);
|
||||
this.logMsgPart(payload.msg);
|
||||
this.finishLogMsg();
|
||||
}
|
||||
|
||||
/** If the `FileLogger` was constructed with a filename, this method
|
||||
returns this filename. Otherwise an empty `string` is returned.
|
||||
*/
|
||||
string getFilename()
|
||||
{
|
||||
return this.filename;
|
||||
}
|
||||
|
||||
/** The `File` log messages are written to. */
|
||||
protected File file_;
|
||||
|
||||
/** The filename of the `File` log messages are written to. */
|
||||
protected string filename;
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
import std.array : empty;
|
||||
import std.file : deleteme, remove;
|
||||
import std.string : indexOf;
|
||||
|
||||
string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile";
|
||||
auto l = new FileLogger(filename);
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
remove(filename);
|
||||
}
|
||||
|
||||
string notWritten = "this should not be written to file";
|
||||
string written = "this should be written to file";
|
||||
|
||||
l.logLevel = LogLevel.critical;
|
||||
l.log(LogLevel.warning, notWritten);
|
||||
l.log(LogLevel.critical, written);
|
||||
destroy(l);
|
||||
|
||||
auto file = File(filename, "r");
|
||||
string readLine = file.readln();
|
||||
assert(readLine.indexOf(written) != -1, readLine);
|
||||
readLine = file.readln();
|
||||
assert(readLine.indexOf(notWritten) == -1, readLine);
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
import std.file : rmdirRecurse, exists, deleteme;
|
||||
import std.path : dirName;
|
||||
|
||||
const string tmpFolder = dirName(deleteme);
|
||||
const string filepath = tmpFolder ~ "/bug15771/minas/oops/";
|
||||
const string filename = filepath ~ "output.txt";
|
||||
assert(!exists(filepath));
|
||||
|
||||
auto f = new FileLogger(filename, LogLevel.all, CreateFolder.yes);
|
||||
scope(exit) () @trusted { rmdirRecurse(tmpFolder ~ "/bug15771"); }();
|
||||
|
||||
f.log("Hello World!");
|
||||
assert(exists(filepath));
|
||||
f.file.close();
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
import std.array : empty;
|
||||
import std.file : deleteme, remove;
|
||||
import std.string : indexOf;
|
||||
|
||||
string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile";
|
||||
auto file = File(filename, "w");
|
||||
auto l = new FileLogger(file);
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
remove(filename);
|
||||
}
|
||||
|
||||
string notWritten = "this should not be written to file";
|
||||
string written = "this should be written to file";
|
||||
|
||||
l.logLevel = LogLevel.critical;
|
||||
l.log(LogLevel.warning, notWritten);
|
||||
l.log(LogLevel.critical, written);
|
||||
file.close();
|
||||
|
||||
file = File(filename, "r");
|
||||
string readLine = file.readln();
|
||||
assert(readLine.indexOf(written) != -1, readLine);
|
||||
readLine = file.readln();
|
||||
assert(readLine.indexOf(notWritten) == -1, readLine);
|
||||
file.close();
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
auto dl = cast(FileLogger) sharedLog;
|
||||
assert(dl !is null);
|
||||
assert(dl.logLevel == LogLevel.info);
|
||||
assert(globalLogLevel == LogLevel.all);
|
||||
|
||||
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
|
||||
assert(tl !is null);
|
||||
stdThreadLocalLog.logLevel = LogLevel.all;
|
||||
}
|
||||
public import std.logger.filelogger;
|
||||
|
|
|
@ -1,200 +1,13 @@
|
|||
// Written in the D programming language.
|
||||
/**
|
||||
Source: $(PHOBOSSRC std/experimental/logger/multilogger.d)
|
||||
*/
|
||||
* This module is now deprecated, use $(MREF std, logger, multilogger)
|
||||
* instead.
|
||||
*
|
||||
* Copyright: Copyright The D Language Foundation 2005 - 2015.
|
||||
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||
* Authors:
|
||||
* Source: $(PHOBOSSRC std/experimental/logger/multilogger.d)
|
||||
*
|
||||
* $(SCRIPT inhibitQuickIndex = 1;)
|
||||
*/
|
||||
module std.experimental.logger.multilogger;
|
||||
|
||||
import std.experimental.logger.core;
|
||||
import std.experimental.logger.filelogger;
|
||||
|
||||
/** This Element is stored inside the `MultiLogger` and associates a
|
||||
`Logger` to a `string`.
|
||||
*/
|
||||
struct MultiLoggerEntry
|
||||
{
|
||||
string name; /// The name if the `Logger`
|
||||
Logger logger; /// The stored `Logger`
|
||||
}
|
||||
|
||||
/** MultiLogger logs to multiple `Logger`. The `Logger`s are stored in an
|
||||
`Logger[]` in their order of insertion.
|
||||
|
||||
Every data logged to this `MultiLogger` will be distributed to all the $(D
|
||||
Logger)s inserted into it. This `MultiLogger` implementation can
|
||||
hold multiple `Logger`s with the same name. If the method `removeLogger`
|
||||
is used to remove a `Logger` only the first occurrence with that name will
|
||||
be removed.
|
||||
*/
|
||||
class MultiLogger : Logger
|
||||
{
|
||||
/** A constructor for the `MultiLogger` Logger.
|
||||
|
||||
Params:
|
||||
lv = The `LogLevel` for the `MultiLogger`. By default the
|
||||
`LogLevel` for `MultiLogger` is `LogLevel.all`.
|
||||
|
||||
Example:
|
||||
-------------
|
||||
auto l1 = new MultiLogger(LogLevel.trace);
|
||||
-------------
|
||||
*/
|
||||
this(const LogLevel lv = LogLevel.all) @safe
|
||||
{
|
||||
super(lv);
|
||||
}
|
||||
|
||||
/** This member holds all `Logger`s stored in the `MultiLogger`.
|
||||
|
||||
When inheriting from `MultiLogger` this member can be used to gain
|
||||
access to the stored `Logger`.
|
||||
*/
|
||||
protected MultiLoggerEntry[] logger;
|
||||
|
||||
/** This method inserts a new Logger into the `MultiLogger`.
|
||||
|
||||
Params:
|
||||
name = The name of the `Logger` to insert.
|
||||
newLogger = The `Logger` to insert.
|
||||
*/
|
||||
void insertLogger(string name, Logger newLogger) @safe
|
||||
{
|
||||
this.logger ~= MultiLoggerEntry(name, newLogger);
|
||||
}
|
||||
|
||||
/** This method removes a Logger from the `MultiLogger`.
|
||||
|
||||
Params:
|
||||
toRemove = The name of the `Logger` to remove. If the `Logger`
|
||||
is not found `null` will be returned. Only the first occurrence of
|
||||
a `Logger` with the given name will be removed.
|
||||
|
||||
Returns: The removed `Logger`.
|
||||
*/
|
||||
Logger removeLogger(in char[] toRemove) @safe
|
||||
{
|
||||
import std.algorithm.mutation : copy;
|
||||
import std.range.primitives : back, popBack;
|
||||
for (size_t i = 0; i < this.logger.length; ++i)
|
||||
{
|
||||
if (this.logger[i].name == toRemove)
|
||||
{
|
||||
Logger ret = this.logger[i].logger;
|
||||
this.logger[i] = this.logger.back;
|
||||
this.logger.popBack();
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* The override to pass the payload to all children of the
|
||||
`MultiLoggerBase`.
|
||||
*/
|
||||
override protected void writeLogMsg(ref LogEntry payload) @safe
|
||||
{
|
||||
foreach (it; this.logger)
|
||||
{
|
||||
/* We don't perform any checks here to avoid race conditions.
|
||||
Instead the child will check on its own if its log level matches
|
||||
and assume LogLevel.all for the globalLogLevel (since we already
|
||||
know the message passes this test).
|
||||
*/
|
||||
it.logger.forwardMsg(payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
import std.exception : assertThrown;
|
||||
import std.experimental.logger.nulllogger;
|
||||
auto a = new MultiLogger;
|
||||
auto n0 = new NullLogger();
|
||||
auto n1 = new NullLogger();
|
||||
a.insertLogger("zero", n0);
|
||||
a.insertLogger("one", n1);
|
||||
|
||||
auto n0_1 = a.removeLogger("zero");
|
||||
assert(n0_1 is n0);
|
||||
auto n = a.removeLogger("zero");
|
||||
assert(n is null);
|
||||
|
||||
auto n1_1 = a.removeLogger("one");
|
||||
assert(n1_1 is n1);
|
||||
n = a.removeLogger("one");
|
||||
assert(n is null);
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
auto a = new MultiLogger;
|
||||
auto n0 = new TestLogger;
|
||||
auto n1 = new TestLogger;
|
||||
a.insertLogger("zero", n0);
|
||||
a.insertLogger("one", n1);
|
||||
|
||||
a.log("Hello TestLogger"); int line = __LINE__;
|
||||
assert(n0.msg == "Hello TestLogger");
|
||||
assert(n0.line == line);
|
||||
assert(n1.msg == "Hello TestLogger");
|
||||
assert(n1.line == line);
|
||||
}
|
||||
|
||||
// Issue #16
|
||||
@system unittest
|
||||
{
|
||||
import std.file : deleteme;
|
||||
import std.stdio : File;
|
||||
import std.string : indexOf;
|
||||
string logName = deleteme ~ __FUNCTION__ ~ ".log";
|
||||
auto logFileOutput = File(logName, "w");
|
||||
scope(exit)
|
||||
{
|
||||
import std.file : remove;
|
||||
logFileOutput.close();
|
||||
remove(logName);
|
||||
}
|
||||
auto traceLog = new FileLogger(logFileOutput, LogLevel.all);
|
||||
auto infoLog = new TestLogger(LogLevel.info);
|
||||
|
||||
auto root = new MultiLogger(LogLevel.all);
|
||||
root.insertLogger("fileLogger", traceLog);
|
||||
root.insertLogger("stdoutLogger", infoLog);
|
||||
|
||||
string tMsg = "A trace message";
|
||||
root.trace(tMsg); int line1 = __LINE__;
|
||||
|
||||
assert(infoLog.line != line1);
|
||||
assert(infoLog.msg != tMsg);
|
||||
|
||||
string iMsg = "A info message";
|
||||
root.info(iMsg); int line2 = __LINE__;
|
||||
|
||||
assert(infoLog.line == line2);
|
||||
assert(infoLog.msg == iMsg, infoLog.msg ~ ":" ~ iMsg);
|
||||
|
||||
logFileOutput.close();
|
||||
logFileOutput = File(logName, "r");
|
||||
assert(logFileOutput.isOpen);
|
||||
assert(!logFileOutput.eof);
|
||||
|
||||
auto line = logFileOutput.readln();
|
||||
assert(line.indexOf(tMsg) != -1, line ~ ":" ~ tMsg);
|
||||
assert(!logFileOutput.eof);
|
||||
line = logFileOutput.readln();
|
||||
assert(line.indexOf(iMsg) != -1, line ~ ":" ~ tMsg);
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
auto dl = cast(FileLogger) sharedLog;
|
||||
assert(dl !is null);
|
||||
assert(dl.logLevel == LogLevel.info);
|
||||
assert(globalLogLevel == LogLevel.all);
|
||||
|
||||
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
|
||||
assert(tl !is null);
|
||||
stdThreadLocalLog.logLevel = LogLevel.all;
|
||||
}
|
||||
public import std.logger.multilogger;
|
||||
|
|
|
@ -1,41 +1,13 @@
|
|||
// Written in the D programming language.
|
||||
/**
|
||||
Source: $(PHOBOSSRC std/experimental/logger/nulllogger.d)
|
||||
*/
|
||||
* This module is now deprecated, use $(MREF std, logger, nulllogger)
|
||||
* instead.
|
||||
*
|
||||
* Copyright: Copyright The D Language Foundation 2005 - 2015.
|
||||
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||
* Authors:
|
||||
* Source: $(PHOBOSSRC std/experimental/logger/nulllogger.d)
|
||||
*
|
||||
* $(SCRIPT inhibitQuickIndex = 1;)
|
||||
*/
|
||||
module std.experimental.logger.nulllogger;
|
||||
|
||||
import std.experimental.logger.core;
|
||||
|
||||
/** The `NullLogger` will not process any log messages.
|
||||
|
||||
In case of a log message with `LogLevel.fatal` nothing will happen.
|
||||
*/
|
||||
class NullLogger : Logger
|
||||
{
|
||||
/** The default constructor for the `NullLogger`.
|
||||
|
||||
Independent of the parameter this Logger will never log a message.
|
||||
|
||||
Params:
|
||||
lv = The `LogLevel` for the `NullLogger`. By default the `LogLevel`
|
||||
for `NullLogger` is `LogLevel.all`.
|
||||
*/
|
||||
this(const LogLevel lv = LogLevel.all) @safe
|
||||
{
|
||||
super(lv);
|
||||
this.fatalHandler = delegate() {};
|
||||
}
|
||||
|
||||
override protected void writeLogMsg(ref LogEntry payload) @safe @nogc
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
import std.experimental.logger.core : LogLevel;
|
||||
auto nl1 = new NullLogger(LogLevel.all);
|
||||
nl1.info("You will never read this.");
|
||||
nl1.fatal("You will never read this, either and it will not throw");
|
||||
}
|
||||
public import std.logger.nulllogger;
|
||||
|
|
|
@ -1,168 +1,17 @@
|
|||
// Written in the D programming language.
|
||||
/**
|
||||
Implements logging facilities.
|
||||
|
||||
Copyright: Copyright Robert "burner" Schadek 2013 --
|
||||
License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
|
||||
Authors: $(HTTP www.svs.informatik.uni-oldenburg.de/60865.html, Robert burner Schadek)
|
||||
|
||||
$(H3 Basic Logging)
|
||||
|
||||
Message logging is a common approach to expose runtime information of a
|
||||
program. Logging should be easy, but also flexible and powerful, therefore
|
||||
`D` provides a standard interface for logging.
|
||||
|
||||
The easiest way to create a log message is to write:
|
||||
-------------
|
||||
import std.experimental.logger;
|
||||
|
||||
void main() {
|
||||
log("Hello World");
|
||||
}
|
||||
-------------
|
||||
This will print a message to the `stderr` device. The message will contain
|
||||
the filename, the line number, the name of the surrounding function, the time
|
||||
and the message.
|
||||
|
||||
More complex log call can go along the lines like:
|
||||
-------------
|
||||
log("Logging to the sharedLog with its default LogLevel");
|
||||
logf(LogLevel.info, 5 < 6, "%s to the sharedLog with its LogLevel.info", "Logging");
|
||||
info("Logging to the sharedLog with its info LogLevel");
|
||||
warning(5 < 6, "Logging to the sharedLog with its LogLevel.warning if 5 is less than 6");
|
||||
error("Logging to the sharedLog with its error LogLevel");
|
||||
errorf("Logging %s the sharedLog %s its error LogLevel", "to", "with");
|
||||
critical("Logging to the"," sharedLog with its error LogLevel");
|
||||
fatal("Logging to the sharedLog with its fatal LogLevel");
|
||||
|
||||
auto fLogger = new FileLogger("NameOfTheLogFile");
|
||||
fLogger.log("Logging to the fileLogger with its default LogLevel");
|
||||
fLogger.info("Logging to the fileLogger with its default LogLevel");
|
||||
fLogger.warning(5 < 6, "Logging to the fileLogger with its LogLevel.warning if 5 is less than 6");
|
||||
fLogger.warningf(5 < 6, "Logging to the fileLogger with its LogLevel.warning if %s is %s than 6", 5, "less");
|
||||
fLogger.critical("Logging to the fileLogger with its info LogLevel");
|
||||
fLogger.log(LogLevel.trace, 5 < 6, "Logging to the fileLogger"," with its default LogLevel if 5 is less than 6");
|
||||
fLogger.fatal("Logging to the fileLogger with its warning LogLevel");
|
||||
-------------
|
||||
Additionally, this example shows how a new `FileLogger` is created.
|
||||
Individual `Logger` and the global log functions share commonly named
|
||||
functions to log data.
|
||||
|
||||
The names of the functions are as follows:
|
||||
$(UL
|
||||
$(LI `log`)
|
||||
$(LI `trace`)
|
||||
$(LI `info`)
|
||||
$(LI `warning`)
|
||||
$(LI `critical`)
|
||||
$(LI `fatal`)
|
||||
)
|
||||
The default `Logger` will by default log to `stderr` and has a default
|
||||
`LogLevel` of `LogLevel.all`. The default Logger can be accessed by
|
||||
using the property called `sharedLog`. This property is a reference to the
|
||||
current default `Logger`. This reference can be used to assign a new
|
||||
default `Logger`.
|
||||
-------------
|
||||
sharedLog = new FileLogger("New_Default_Log_File.log");
|
||||
-------------
|
||||
|
||||
Additional `Logger` can be created by creating a new instance of the
|
||||
required `Logger`.
|
||||
|
||||
$(H3 Logging Fundamentals)
|
||||
$(H4 LogLevel)
|
||||
The `LogLevel` of a log call can be defined in two ways. The first is by
|
||||
calling `log` and passing the `LogLevel` explicitly as the first argument.
|
||||
The second way of setting the `LogLevel` of a
|
||||
log call, is by calling either `trace`, `info`, `warning`,
|
||||
`critical`, or `fatal`. The log call will then have the respective
|
||||
`LogLevel`. If no `LogLevel` is defined the log call will use the
|
||||
current `LogLevel` of the used `Logger`. If data is logged with
|
||||
`LogLevel` `fatal` by default an `Error` will be thrown.
|
||||
This behaviour can be modified by using the member `fatalHandler` to
|
||||
assign a custom delegate to handle log call with `LogLevel` `fatal`.
|
||||
|
||||
$(H4 Conditional Logging)
|
||||
Conditional logging can be achieved be passing a `bool` as first
|
||||
argument to a log function. If conditional logging is used the condition must
|
||||
be `true` in order to have the log message logged.
|
||||
|
||||
In order to combine an explicit `LogLevel` passing with conditional
|
||||
logging, the `LogLevel` has to be passed as first argument followed by the
|
||||
`bool`.
|
||||
|
||||
$(H4 Filtering Log Messages)
|
||||
Messages are logged if the `LogLevel` of the log message is greater than or
|
||||
equal to the `LogLevel` of the used `Logger` and additionally if the
|
||||
`LogLevel` of the log message is greater than or equal to the global `LogLevel`.
|
||||
If a condition is passed into the log call, this condition must be true.
|
||||
|
||||
The global `LogLevel` is accessible by using `globalLogLevel`.
|
||||
To assign a `LogLevel` of a `Logger` use the `logLevel` property of
|
||||
the logger.
|
||||
|
||||
$(H4 Printf Style Logging)
|
||||
If `printf`-style logging is needed add a $(B f) to the logging call, such as
|
||||
$(D myLogger.infof("Hello %s", "world");) or $(D fatalf("errno %d", 1337)).
|
||||
The additional $(B f) appended to the function name enables `printf`-style
|
||||
logging for all combinations of explicit `LogLevel` and conditional
|
||||
logging functions and methods.
|
||||
|
||||
$(H4 Thread Local Redirection)
|
||||
Calls to the free standing log functions are not directly forwarded to the
|
||||
global `Logger` `sharedLog`. Actually, a thread local `Logger` of
|
||||
type `StdForwardLogger` processes the log call and then, by default, forwards
|
||||
the created `Logger.LogEntry` to the `sharedLog` `Logger`.
|
||||
The thread local `Logger` is accessible by the `stdThreadLocalLog`
|
||||
property. This property allows to assign user defined `Logger`. The default
|
||||
`LogLevel` of the `stdThreadLocalLog` `Logger` is `LogLevel.all`
|
||||
and it will therefore forward all messages to the `sharedLog` `Logger`.
|
||||
The `LogLevel` of the `stdThreadLocalLog` can be used to filter log
|
||||
calls before they reach the `sharedLog` `Logger`.
|
||||
|
||||
$(H3 User Defined Logger)
|
||||
To customize the `Logger` behavior, create a new `class` that inherits from
|
||||
the abstract `Logger` `class`, and implements the `writeLogMsg`
|
||||
method.
|
||||
-------------
|
||||
class MyCustomLogger : Logger
|
||||
{
|
||||
this(LogLevel lv) @safe
|
||||
{
|
||||
super(lv);
|
||||
}
|
||||
|
||||
override void writeLogMsg(ref LogEntry payload)
|
||||
{
|
||||
// log message in my custom way
|
||||
}
|
||||
}
|
||||
|
||||
auto logger = new MyCustomLogger(LogLevel.info);
|
||||
logger.log("Awesome log message with LogLevel.info");
|
||||
-------------
|
||||
|
||||
To gain more precise control over the logging process, additionally to
|
||||
overriding the `writeLogMsg` method the methods `beginLogMsg`,
|
||||
`logMsgPart` and `finishLogMsg` can be overridden.
|
||||
|
||||
$(H3 Provided Logger)
|
||||
By default four `Logger` implementations are given. The `FileLogger`
|
||||
logs data to files. It can also be used to log to `stdout` and `stderr`
|
||||
as these devices are files as well. A `Logger` that logs to `stdout` can
|
||||
therefore be created by $(D new FileLogger(stdout)).
|
||||
The `MultiLogger` is basically an associative array of `string`s to
|
||||
`Logger`. It propagates log calls to its stored `Logger`. The
|
||||
`ArrayLogger` contains an array of `Logger` and also propagates log
|
||||
calls to its stored `Logger`. The `NullLogger` does not do anything. It
|
||||
will never log a message and will never throw on a log call with `LogLevel`
|
||||
`error`.
|
||||
|
||||
Source: $(PHOBOSSRC std/experimental/logger/package.d)
|
||||
*/
|
||||
* This module is now deprecated, use $(MREF std, logger)
|
||||
* instead.
|
||||
*
|
||||
* Copyright: Copyright The D Language Foundation 2005 - 2015.
|
||||
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||
* Authors:
|
||||
* Source: $(PHOBOSSRC std/experimental/logger/package.d)
|
||||
*
|
||||
* $(SCRIPT inhibitQuickIndex = 1;)
|
||||
*/
|
||||
module std.experimental.logger;
|
||||
|
||||
public import std.experimental.logger.core;
|
||||
public import std.experimental.logger.filelogger;
|
||||
public import std.experimental.logger.multilogger;
|
||||
public import std.experimental.logger.nulllogger;
|
||||
public import std.logger.core;
|
||||
public import std.logger.filelogger;
|
||||
public import std.logger.multilogger;
|
||||
public import std.logger.nulllogger;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1835,7 +1835,7 @@ void defaultGetoptFormatter(Output)(Output output, string text, Option[] opt, st
|
|||
assert(flag);
|
||||
}
|
||||
|
||||
@safe unittest // Delegates as callbacks
|
||||
@system unittest // Delegates as callbacks
|
||||
{
|
||||
alias TwoArgOptionHandler = void delegate(string option, string value) @safe;
|
||||
|
||||
|
|
|
@ -1537,19 +1537,15 @@ if (isOutputRange!(Out,char))
|
|||
toStringImpl!char(str);
|
||||
}
|
||||
|
||||
// recursive @safe inference is broken here
|
||||
// workaround: if json.put is @safe, we should be too,
|
||||
// so annotate the recursion as @safe manually
|
||||
static if (isSafe!({ json.put(""); }))
|
||||
{
|
||||
void delegate(ref const JSONValue, ulong) @safe toValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
void delegate(ref const JSONValue, ulong) @system toValue;
|
||||
}
|
||||
/* make the function infer @system when json.put() is @system
|
||||
*/
|
||||
if (0)
|
||||
json.put(' ');
|
||||
|
||||
void toValueImpl(ref const JSONValue value, ulong indentLevel)
|
||||
/* Mark as @trusted because json.put() may be @system. This has difficulty
|
||||
* inferring @safe because it is recursive.
|
||||
*/
|
||||
void toValueImpl(ref const JSONValue value, ulong indentLevel) @trusted
|
||||
{
|
||||
void putTabs(ulong additionalIndent = 0)
|
||||
{
|
||||
|
@ -1594,7 +1590,7 @@ if (isOutputRange!(Out,char))
|
|||
json.put(':');
|
||||
if (pretty)
|
||||
json.put(' ');
|
||||
toValue(member, indentLevel + 1);
|
||||
toValueImpl(member, indentLevel + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1631,7 +1627,7 @@ if (isOutputRange!(Out,char))
|
|||
if (i)
|
||||
putCharAndEOL(',');
|
||||
putTabs(1);
|
||||
toValue(el, indentLevel + 1);
|
||||
toValueImpl(el, indentLevel + 1);
|
||||
}
|
||||
putEOL();
|
||||
putTabs();
|
||||
|
@ -1710,9 +1706,7 @@ if (isOutputRange!(Out,char))
|
|||
}
|
||||
}
|
||||
|
||||
toValue = &toValueImpl;
|
||||
|
||||
toValue(root, 0);
|
||||
toValueImpl(root, 0);
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=12897
|
||||
|
|
3049
libphobos/src/std/logger/core.d
Normal file
3049
libphobos/src/std/logger/core.d
Normal file
File diff suppressed because it is too large
Load diff
272
libphobos/src/std/logger/filelogger.d
Normal file
272
libphobos/src/std/logger/filelogger.d
Normal file
|
@ -0,0 +1,272 @@
|
|||
// Written in the D programming language.
|
||||
/**
|
||||
Source: $(PHOBOSSRC std/logger/filelogger.d)
|
||||
*/
|
||||
module std.logger.filelogger;
|
||||
|
||||
import std.logger.core;
|
||||
import std.stdio;
|
||||
|
||||
import std.typecons : Flag;
|
||||
|
||||
/** An option to create $(LREF FileLogger) directory if it is non-existent.
|
||||
*/
|
||||
alias CreateFolder = Flag!"CreateFolder";
|
||||
|
||||
/** This `Logger` implementation writes log messages to the associated
|
||||
file. The name of the file has to be passed on construction time. If the file
|
||||
is already present new log messages will be append at its end.
|
||||
*/
|
||||
class FileLogger : Logger
|
||||
{
|
||||
import std.concurrency : Tid;
|
||||
import std.datetime.systime : SysTime;
|
||||
import std.format.write : formattedWrite;
|
||||
|
||||
/** A constructor for the `FileLogger` Logger.
|
||||
|
||||
Params:
|
||||
fn = The filename of the output file of the `FileLogger`. If that
|
||||
file can not be opened for writting an exception will be thrown.
|
||||
lv = The `LogLevel` for the `FileLogger`. By default the
|
||||
|
||||
Example:
|
||||
-------------
|
||||
auto l1 = new FileLogger("logFile");
|
||||
auto l2 = new FileLogger("logFile", LogLevel.fatal);
|
||||
auto l3 = new FileLogger("logFile", LogLevel.fatal, CreateFolder.yes);
|
||||
-------------
|
||||
*/
|
||||
this(const string fn, const LogLevel lv = LogLevel.all) @safe
|
||||
{
|
||||
this(fn, lv, CreateFolder.yes);
|
||||
}
|
||||
|
||||
/** A constructor for the `FileLogger` Logger that takes a reference to
|
||||
a `File`.
|
||||
|
||||
The `File` passed must be open for all the log call to the
|
||||
`FileLogger`. If the `File` gets closed, using the `FileLogger`
|
||||
for logging will result in undefined behaviour.
|
||||
|
||||
Params:
|
||||
fn = The file used for logging.
|
||||
lv = The `LogLevel` for the `FileLogger`. By default the
|
||||
`LogLevel` for `FileLogger` is `LogLevel.all`.
|
||||
createFileNameFolder = if yes and fn contains a folder name, this
|
||||
folder will be created.
|
||||
|
||||
Example:
|
||||
-------------
|
||||
auto file = File("logFile.log", "w");
|
||||
auto l1 = new FileLogger(file);
|
||||
auto l2 = new FileLogger(file, LogLevel.fatal);
|
||||
-------------
|
||||
*/
|
||||
this(const string fn, const LogLevel lv, CreateFolder createFileNameFolder) @safe
|
||||
{
|
||||
import std.file : exists, mkdirRecurse;
|
||||
import std.path : dirName;
|
||||
import std.conv : text;
|
||||
|
||||
super(lv);
|
||||
this.filename = fn;
|
||||
|
||||
if (createFileNameFolder)
|
||||
{
|
||||
auto d = dirName(this.filename);
|
||||
mkdirRecurse(d);
|
||||
assert(exists(d), text("The folder the FileLogger should have",
|
||||
" created in '", d,"' could not be created."));
|
||||
}
|
||||
|
||||
this.file_.open(this.filename, "a");
|
||||
}
|
||||
|
||||
/** A constructor for the `FileLogger` Logger that takes a reference to
|
||||
a `File`.
|
||||
|
||||
The `File` passed must be open for all the log call to the
|
||||
`FileLogger`. If the `File` gets closed, using the `FileLogger`
|
||||
for logging will result in undefined behaviour.
|
||||
|
||||
Params:
|
||||
file = The file used for logging.
|
||||
lv = The `LogLevel` for the `FileLogger`. By default the
|
||||
`LogLevel` for `FileLogger` is `LogLevel.all`.
|
||||
|
||||
Example:
|
||||
-------------
|
||||
auto file = File("logFile.log", "w");
|
||||
auto l1 = new FileLogger(file);
|
||||
auto l2 = new FileLogger(file, LogLevel.fatal);
|
||||
-------------
|
||||
*/
|
||||
this(File file, const LogLevel lv = LogLevel.all) @safe
|
||||
{
|
||||
super(lv);
|
||||
this.file_ = file;
|
||||
}
|
||||
|
||||
/** If the `FileLogger` is managing the `File` it logs to, this
|
||||
method will return a reference to this File.
|
||||
*/
|
||||
@property File file() @safe
|
||||
{
|
||||
return this.file_;
|
||||
}
|
||||
|
||||
/* This method overrides the base class method in order to log to a file
|
||||
without requiring heap allocated memory. Additionally, the `FileLogger`
|
||||
local mutex is logged to serialize the log calls.
|
||||
*/
|
||||
override protected void beginLogMsg(string file, int line, string funcName,
|
||||
string prettyFuncName, string moduleName, LogLevel logLevel,
|
||||
Tid threadId, SysTime timestamp, Logger logger)
|
||||
@safe
|
||||
{
|
||||
import std.string : lastIndexOf;
|
||||
ptrdiff_t fnIdx = file.lastIndexOf('/') + 1;
|
||||
ptrdiff_t funIdx = funcName.lastIndexOf('.') + 1;
|
||||
|
||||
auto lt = this.file_.lockingTextWriter();
|
||||
systimeToISOString(lt, timestamp);
|
||||
import std.conv : to;
|
||||
formattedWrite(lt, " [%s] %s:%u:%s ", logLevel.to!string,
|
||||
file[fnIdx .. $], line, funcName[funIdx .. $]);
|
||||
}
|
||||
|
||||
/* This methods overrides the base class method and writes the parts of
|
||||
the log call directly to the file.
|
||||
*/
|
||||
override protected void logMsgPart(scope const(char)[] msg)
|
||||
{
|
||||
formattedWrite(this.file_.lockingTextWriter(), "%s", msg);
|
||||
}
|
||||
|
||||
/* This methods overrides the base class method and finalizes the active
|
||||
log call. This requires flushing the `File` and releasing the
|
||||
`FileLogger` local mutex.
|
||||
*/
|
||||
override protected void finishLogMsg()
|
||||
{
|
||||
this.file_.lockingTextWriter().put("\n");
|
||||
this.file_.flush();
|
||||
}
|
||||
|
||||
/* This methods overrides the base class method and delegates the
|
||||
`LogEntry` data to the actual implementation.
|
||||
*/
|
||||
override protected void writeLogMsg(ref LogEntry payload)
|
||||
{
|
||||
this.beginLogMsg(payload.file, payload.line, payload.funcName,
|
||||
payload.prettyFuncName, payload.moduleName, payload.logLevel,
|
||||
payload.threadId, payload.timestamp, payload.logger);
|
||||
this.logMsgPart(payload.msg);
|
||||
this.finishLogMsg();
|
||||
}
|
||||
|
||||
/** If the `FileLogger` was constructed with a filename, this method
|
||||
returns this filename. Otherwise an empty `string` is returned.
|
||||
*/
|
||||
string getFilename()
|
||||
{
|
||||
return this.filename;
|
||||
}
|
||||
|
||||
/** The `File` log messages are written to. */
|
||||
protected File file_;
|
||||
|
||||
/** The filename of the `File` log messages are written to. */
|
||||
protected string filename;
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
import std.array : empty;
|
||||
import std.file : deleteme, remove;
|
||||
import std.string : indexOf;
|
||||
|
||||
string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile";
|
||||
auto l = new FileLogger(filename);
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
remove(filename);
|
||||
}
|
||||
|
||||
string notWritten = "this should not be written to file";
|
||||
string written = "this should be written to file";
|
||||
|
||||
l.logLevel = LogLevel.critical;
|
||||
l.log(LogLevel.warning, notWritten);
|
||||
l.log(LogLevel.critical, written);
|
||||
destroy(l);
|
||||
|
||||
auto file = File(filename, "r");
|
||||
string readLine = file.readln();
|
||||
assert(readLine.indexOf(written) != -1, readLine);
|
||||
readLine = file.readln();
|
||||
assert(readLine.indexOf(notWritten) == -1, readLine);
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
import std.file : rmdirRecurse, exists, deleteme;
|
||||
import std.path : dirName;
|
||||
|
||||
const string tmpFolder = dirName(deleteme);
|
||||
const string filepath = tmpFolder ~ "/bug15771/minas/oops/";
|
||||
const string filename = filepath ~ "output.txt";
|
||||
assert(!exists(filepath));
|
||||
|
||||
auto f = new FileLogger(filename, LogLevel.all, CreateFolder.yes);
|
||||
scope(exit) () @trusted { rmdirRecurse(tmpFolder ~ "/bug15771"); }();
|
||||
|
||||
f.log("Hello World!");
|
||||
assert(exists(filepath));
|
||||
f.file.close();
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
import std.array : empty;
|
||||
import std.file : deleteme, remove;
|
||||
import std.string : indexOf;
|
||||
|
||||
string filename = deleteme ~ __FUNCTION__ ~ ".tempLogFile";
|
||||
auto file = File(filename, "w");
|
||||
auto l = new FileLogger(file);
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
remove(filename);
|
||||
}
|
||||
|
||||
string notWritten = "this should not be written to file";
|
||||
string written = "this should be written to file";
|
||||
|
||||
l.logLevel = LogLevel.critical;
|
||||
l.log(LogLevel.warning, notWritten);
|
||||
l.log(LogLevel.critical, written);
|
||||
file.close();
|
||||
|
||||
file = File(filename, "r");
|
||||
string readLine = file.readln();
|
||||
assert(readLine.indexOf(written) != -1, readLine);
|
||||
readLine = file.readln();
|
||||
assert(readLine.indexOf(notWritten) == -1, readLine);
|
||||
file.close();
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
auto dl = cast(FileLogger) sharedLog;
|
||||
assert(dl !is null);
|
||||
assert(dl.logLevel == LogLevel.info);
|
||||
assert(globalLogLevel == LogLevel.all);
|
||||
|
||||
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
|
||||
assert(tl !is null);
|
||||
stdThreadLocalLog.logLevel = LogLevel.all;
|
||||
}
|
200
libphobos/src/std/logger/multilogger.d
Normal file
200
libphobos/src/std/logger/multilogger.d
Normal file
|
@ -0,0 +1,200 @@
|
|||
// Written in the D programming language.
|
||||
/**
|
||||
Source: $(PHOBOSSRC std/logger/multilogger.d)
|
||||
*/
|
||||
module std.logger.multilogger;
|
||||
|
||||
import std.logger.core;
|
||||
import std.logger.filelogger;
|
||||
|
||||
/** This Element is stored inside the `MultiLogger` and associates a
|
||||
`Logger` to a `string`.
|
||||
*/
|
||||
struct MultiLoggerEntry
|
||||
{
|
||||
string name; /// The name if the `Logger`
|
||||
Logger logger; /// The stored `Logger`
|
||||
}
|
||||
|
||||
/** MultiLogger logs to multiple `Logger`. The `Logger`s are stored in an
|
||||
`Logger[]` in their order of insertion.
|
||||
|
||||
Every data logged to this `MultiLogger` will be distributed to all the $(D
|
||||
Logger)s inserted into it. This `MultiLogger` implementation can
|
||||
hold multiple `Logger`s with the same name. If the method `removeLogger`
|
||||
is used to remove a `Logger` only the first occurrence with that name will
|
||||
be removed.
|
||||
*/
|
||||
class MultiLogger : Logger
|
||||
{
|
||||
/** A constructor for the `MultiLogger` Logger.
|
||||
|
||||
Params:
|
||||
lv = The `LogLevel` for the `MultiLogger`. By default the
|
||||
`LogLevel` for `MultiLogger` is `LogLevel.all`.
|
||||
|
||||
Example:
|
||||
-------------
|
||||
auto l1 = new MultiLogger(LogLevel.trace);
|
||||
-------------
|
||||
*/
|
||||
this(const LogLevel lv = LogLevel.all) @safe
|
||||
{
|
||||
super(lv);
|
||||
}
|
||||
|
||||
/** This member holds all `Logger`s stored in the `MultiLogger`.
|
||||
|
||||
When inheriting from `MultiLogger` this member can be used to gain
|
||||
access to the stored `Logger`.
|
||||
*/
|
||||
protected MultiLoggerEntry[] logger;
|
||||
|
||||
/** This method inserts a new Logger into the `MultiLogger`.
|
||||
|
||||
Params:
|
||||
name = The name of the `Logger` to insert.
|
||||
newLogger = The `Logger` to insert.
|
||||
*/
|
||||
void insertLogger(string name, Logger newLogger) @safe
|
||||
{
|
||||
this.logger ~= MultiLoggerEntry(name, newLogger);
|
||||
}
|
||||
|
||||
/** This method removes a Logger from the `MultiLogger`.
|
||||
|
||||
Params:
|
||||
toRemove = The name of the `Logger` to remove. If the `Logger`
|
||||
is not found `null` will be returned. Only the first occurrence of
|
||||
a `Logger` with the given name will be removed.
|
||||
|
||||
Returns: The removed `Logger`.
|
||||
*/
|
||||
Logger removeLogger(in char[] toRemove) @safe
|
||||
{
|
||||
import std.algorithm.mutation : copy;
|
||||
import std.range.primitives : back, popBack;
|
||||
for (size_t i = 0; i < this.logger.length; ++i)
|
||||
{
|
||||
if (this.logger[i].name == toRemove)
|
||||
{
|
||||
Logger ret = this.logger[i].logger;
|
||||
this.logger[i] = this.logger.back;
|
||||
this.logger.popBack();
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* The override to pass the payload to all children of the
|
||||
`MultiLoggerBase`.
|
||||
*/
|
||||
override protected void writeLogMsg(ref LogEntry payload) @safe
|
||||
{
|
||||
foreach (it; this.logger)
|
||||
{
|
||||
/* We don't perform any checks here to avoid race conditions.
|
||||
Instead the child will check on its own if its log level matches
|
||||
and assume LogLevel.all for the globalLogLevel (since we already
|
||||
know the message passes this test).
|
||||
*/
|
||||
it.logger.forwardMsg(payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
import std.exception : assertThrown;
|
||||
import std.logger.nulllogger;
|
||||
auto a = new MultiLogger;
|
||||
auto n0 = new NullLogger();
|
||||
auto n1 = new NullLogger();
|
||||
a.insertLogger("zero", n0);
|
||||
a.insertLogger("one", n1);
|
||||
|
||||
auto n0_1 = a.removeLogger("zero");
|
||||
assert(n0_1 is n0);
|
||||
auto n = a.removeLogger("zero");
|
||||
assert(n is null);
|
||||
|
||||
auto n1_1 = a.removeLogger("one");
|
||||
assert(n1_1 is n1);
|
||||
n = a.removeLogger("one");
|
||||
assert(n is null);
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
auto a = new MultiLogger;
|
||||
auto n0 = new TestLogger;
|
||||
auto n1 = new TestLogger;
|
||||
a.insertLogger("zero", n0);
|
||||
a.insertLogger("one", n1);
|
||||
|
||||
a.log("Hello TestLogger"); int line = __LINE__;
|
||||
assert(n0.msg == "Hello TestLogger");
|
||||
assert(n0.line == line);
|
||||
assert(n1.msg == "Hello TestLogger");
|
||||
assert(n1.line == line);
|
||||
}
|
||||
|
||||
// Issue #16
|
||||
@system unittest
|
||||
{
|
||||
import std.file : deleteme;
|
||||
import std.stdio : File;
|
||||
import std.string : indexOf;
|
||||
string logName = deleteme ~ __FUNCTION__ ~ ".log";
|
||||
auto logFileOutput = File(logName, "w");
|
||||
scope(exit)
|
||||
{
|
||||
import std.file : remove;
|
||||
logFileOutput.close();
|
||||
remove(logName);
|
||||
}
|
||||
auto traceLog = new FileLogger(logFileOutput, LogLevel.all);
|
||||
auto infoLog = new TestLogger(LogLevel.info);
|
||||
|
||||
auto root = new MultiLogger(LogLevel.all);
|
||||
root.insertLogger("fileLogger", traceLog);
|
||||
root.insertLogger("stdoutLogger", infoLog);
|
||||
|
||||
string tMsg = "A trace message";
|
||||
root.trace(tMsg); int line1 = __LINE__;
|
||||
|
||||
assert(infoLog.line != line1);
|
||||
assert(infoLog.msg != tMsg);
|
||||
|
||||
string iMsg = "A info message";
|
||||
root.info(iMsg); int line2 = __LINE__;
|
||||
|
||||
assert(infoLog.line == line2);
|
||||
assert(infoLog.msg == iMsg, infoLog.msg ~ ":" ~ iMsg);
|
||||
|
||||
logFileOutput.close();
|
||||
logFileOutput = File(logName, "r");
|
||||
assert(logFileOutput.isOpen);
|
||||
assert(!logFileOutput.eof);
|
||||
|
||||
auto line = logFileOutput.readln();
|
||||
assert(line.indexOf(tMsg) != -1, line ~ ":" ~ tMsg);
|
||||
assert(!logFileOutput.eof);
|
||||
line = logFileOutput.readln();
|
||||
assert(line.indexOf(iMsg) != -1, line ~ ":" ~ tMsg);
|
||||
}
|
||||
|
||||
@system unittest
|
||||
{
|
||||
auto dl = cast(FileLogger) sharedLog;
|
||||
assert(dl !is null);
|
||||
assert(dl.logLevel == LogLevel.info);
|
||||
assert(globalLogLevel == LogLevel.all);
|
||||
|
||||
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
|
||||
assert(tl !is null);
|
||||
stdThreadLocalLog.logLevel = LogLevel.all;
|
||||
}
|
41
libphobos/src/std/logger/nulllogger.d
Normal file
41
libphobos/src/std/logger/nulllogger.d
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Written in the D programming language.
|
||||
/**
|
||||
Source: $(PHOBOSSRC std/logger/nulllogger.d)
|
||||
*/
|
||||
module std.logger.nulllogger;
|
||||
|
||||
import std.logger.core;
|
||||
|
||||
/** The `NullLogger` will not process any log messages.
|
||||
|
||||
In case of a log message with `LogLevel.fatal` nothing will happen.
|
||||
*/
|
||||
class NullLogger : Logger
|
||||
{
|
||||
/** The default constructor for the `NullLogger`.
|
||||
|
||||
Independent of the parameter this Logger will never log a message.
|
||||
|
||||
Params:
|
||||
lv = The `LogLevel` for the `NullLogger`. By default the `LogLevel`
|
||||
for `NullLogger` is `LogLevel.all`.
|
||||
*/
|
||||
this(const LogLevel lv = LogLevel.all) @safe
|
||||
{
|
||||
super(lv);
|
||||
this.fatalHandler = delegate() {};
|
||||
}
|
||||
|
||||
override protected void writeLogMsg(ref LogEntry payload) @safe @nogc
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
import std.logger.core : LogLevel;
|
||||
auto nl1 = new NullLogger(LogLevel.all);
|
||||
nl1.info("You will never read this.");
|
||||
nl1.fatal("You will never read this, either and it will not throw");
|
||||
}
|
168
libphobos/src/std/logger/package.d
Normal file
168
libphobos/src/std/logger/package.d
Normal file
|
@ -0,0 +1,168 @@
|
|||
// Written in the D programming language.
|
||||
/**
|
||||
Implements logging facilities.
|
||||
|
||||
Copyright: Copyright Robert "burner" Schadek 2013 --
|
||||
License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
|
||||
Authors: $(HTTP www.svs.informatik.uni-oldenburg.de/60865.html, Robert burner Schadek)
|
||||
|
||||
$(H3 Basic Logging)
|
||||
|
||||
Message logging is a common approach to expose runtime information of a
|
||||
program. Logging should be easy, but also flexible and powerful, therefore
|
||||
`D` provides a standard interface for logging.
|
||||
|
||||
The easiest way to create a log message is to write:
|
||||
-------------
|
||||
import std.logger;
|
||||
|
||||
void main() {
|
||||
log("Hello World");
|
||||
}
|
||||
-------------
|
||||
This will print a message to the `stderr` device. The message will contain
|
||||
the filename, the line number, the name of the surrounding function, the time
|
||||
and the message.
|
||||
|
||||
More complex log call can go along the lines like:
|
||||
-------------
|
||||
log("Logging to the sharedLog with its default LogLevel");
|
||||
logf(LogLevel.info, 5 < 6, "%s to the sharedLog with its LogLevel.info", "Logging");
|
||||
info("Logging to the sharedLog with its info LogLevel");
|
||||
warning(5 < 6, "Logging to the sharedLog with its LogLevel.warning if 5 is less than 6");
|
||||
error("Logging to the sharedLog with its error LogLevel");
|
||||
errorf("Logging %s the sharedLog %s its error LogLevel", "to", "with");
|
||||
critical("Logging to the"," sharedLog with its error LogLevel");
|
||||
fatal("Logging to the sharedLog with its fatal LogLevel");
|
||||
|
||||
auto fLogger = new FileLogger("NameOfTheLogFile");
|
||||
fLogger.log("Logging to the fileLogger with its default LogLevel");
|
||||
fLogger.info("Logging to the fileLogger with its default LogLevel");
|
||||
fLogger.warning(5 < 6, "Logging to the fileLogger with its LogLevel.warning if 5 is less than 6");
|
||||
fLogger.warningf(5 < 6, "Logging to the fileLogger with its LogLevel.warning if %s is %s than 6", 5, "less");
|
||||
fLogger.critical("Logging to the fileLogger with its info LogLevel");
|
||||
fLogger.log(LogLevel.trace, 5 < 6, "Logging to the fileLogger"," with its default LogLevel if 5 is less than 6");
|
||||
fLogger.fatal("Logging to the fileLogger with its warning LogLevel");
|
||||
-------------
|
||||
Additionally, this example shows how a new `FileLogger` is created.
|
||||
Individual `Logger` and the global log functions share commonly named
|
||||
functions to log data.
|
||||
|
||||
The names of the functions are as follows:
|
||||
$(UL
|
||||
$(LI `log`)
|
||||
$(LI `trace`)
|
||||
$(LI `info`)
|
||||
$(LI `warning`)
|
||||
$(LI `critical`)
|
||||
$(LI `fatal`)
|
||||
)
|
||||
The default `Logger` will by default log to `stderr` and has a default
|
||||
`LogLevel` of `LogLevel.all`. The default Logger can be accessed by
|
||||
using the property called `sharedLog`. This property is a reference to the
|
||||
current default `Logger`. This reference can be used to assign a new
|
||||
default `Logger`.
|
||||
-------------
|
||||
sharedLog = new FileLogger("New_Default_Log_File.log");
|
||||
-------------
|
||||
|
||||
Additional `Logger` can be created by creating a new instance of the
|
||||
required `Logger`.
|
||||
|
||||
$(H3 Logging Fundamentals)
|
||||
$(H4 LogLevel)
|
||||
The `LogLevel` of a log call can be defined in two ways. The first is by
|
||||
calling `log` and passing the `LogLevel` explicitly as the first argument.
|
||||
The second way of setting the `LogLevel` of a
|
||||
log call, is by calling either `trace`, `info`, `warning`,
|
||||
`critical`, or `fatal`. The log call will then have the respective
|
||||
`LogLevel`. If no `LogLevel` is defined the log call will use the
|
||||
current `LogLevel` of the used `Logger`. If data is logged with
|
||||
`LogLevel` `fatal` by default an `Error` will be thrown.
|
||||
This behaviour can be modified by using the member `fatalHandler` to
|
||||
assign a custom delegate to handle log call with `LogLevel` `fatal`.
|
||||
|
||||
$(H4 Conditional Logging)
|
||||
Conditional logging can be achieved be passing a `bool` as first
|
||||
argument to a log function. If conditional logging is used the condition must
|
||||
be `true` in order to have the log message logged.
|
||||
|
||||
In order to combine an explicit `LogLevel` passing with conditional
|
||||
logging, the `LogLevel` has to be passed as first argument followed by the
|
||||
`bool`.
|
||||
|
||||
$(H4 Filtering Log Messages)
|
||||
Messages are logged if the `LogLevel` of the log message is greater than or
|
||||
equal to the `LogLevel` of the used `Logger` and additionally if the
|
||||
`LogLevel` of the log message is greater than or equal to the global `LogLevel`.
|
||||
If a condition is passed into the log call, this condition must be true.
|
||||
|
||||
The global `LogLevel` is accessible by using `globalLogLevel`.
|
||||
To assign a `LogLevel` of a `Logger` use the `logLevel` property of
|
||||
the logger.
|
||||
|
||||
$(H4 Printf Style Logging)
|
||||
If `printf`-style logging is needed add a $(B f) to the logging call, such as
|
||||
$(D myLogger.infof("Hello %s", "world");) or $(D fatalf("errno %d", 1337)).
|
||||
The additional $(B f) appended to the function name enables `printf`-style
|
||||
logging for all combinations of explicit `LogLevel` and conditional
|
||||
logging functions and methods.
|
||||
|
||||
$(H4 Thread Local Redirection)
|
||||
Calls to the free standing log functions are not directly forwarded to the
|
||||
global `Logger` `sharedLog`. Actually, a thread local `Logger` of
|
||||
type `StdForwardLogger` processes the log call and then, by default, forwards
|
||||
the created `Logger.LogEntry` to the `sharedLog` `Logger`.
|
||||
The thread local `Logger` is accessible by the `stdThreadLocalLog`
|
||||
property. This property allows to assign user defined `Logger`. The default
|
||||
`LogLevel` of the `stdThreadLocalLog` `Logger` is `LogLevel.all`
|
||||
and it will therefore forward all messages to the `sharedLog` `Logger`.
|
||||
The `LogLevel` of the `stdThreadLocalLog` can be used to filter log
|
||||
calls before they reach the `sharedLog` `Logger`.
|
||||
|
||||
$(H3 User Defined Logger)
|
||||
To customize the `Logger` behavior, create a new `class` that inherits from
|
||||
the abstract `Logger` `class`, and implements the `writeLogMsg`
|
||||
method.
|
||||
-------------
|
||||
class MyCustomLogger : Logger
|
||||
{
|
||||
this(LogLevel lv) @safe
|
||||
{
|
||||
super(lv);
|
||||
}
|
||||
|
||||
override void writeLogMsg(ref LogEntry payload)
|
||||
{
|
||||
// log message in my custom way
|
||||
}
|
||||
}
|
||||
|
||||
auto logger = new MyCustomLogger(LogLevel.info);
|
||||
logger.log("Awesome log message with LogLevel.info");
|
||||
-------------
|
||||
|
||||
To gain more precise control over the logging process, additionally to
|
||||
overriding the `writeLogMsg` method the methods `beginLogMsg`,
|
||||
`logMsgPart` and `finishLogMsg` can be overridden.
|
||||
|
||||
$(H3 Provided Logger)
|
||||
By default four `Logger` implementations are given. The `FileLogger`
|
||||
logs data to files. It can also be used to log to `stdout` and `stderr`
|
||||
as these devices are files as well. A `Logger` that logs to `stdout` can
|
||||
therefore be created by $(D new FileLogger(stdout)).
|
||||
The `MultiLogger` is basically an associative array of `string`s to
|
||||
`Logger`. It propagates log calls to its stored `Logger`. The
|
||||
`ArrayLogger` contains an array of `Logger` and also propagates log
|
||||
calls to its stored `Logger`. The `NullLogger` does not do anything. It
|
||||
will never log a message and will never throw on a log call with `LogLevel`
|
||||
`error`.
|
||||
|
||||
Source: $(PHOBOSSRC std/logger/package.d)
|
||||
*/
|
||||
module std.logger;
|
||||
|
||||
public import std.logger.core;
|
||||
public import std.logger.filelogger;
|
||||
public import std.logger.multilogger;
|
||||
public import std.logger.nulllogger;
|
|
@ -627,35 +627,9 @@ Evaluates to `AliasSeq!(fun!(args[0]), fun!(args[1]), ..., fun!(args[$ - 1]))`.
|
|||
*/
|
||||
template staticMap(alias fun, args...)
|
||||
{
|
||||
version (__staticMap_simplest_but_buggy)
|
||||
{
|
||||
// @@@ BUG @@@
|
||||
// The following straightforward implementation exposes a bug.
|
||||
// See issue https://issues.dlang.org/show_bug.cgi?id=22421 and unittest below.
|
||||
alias staticMap = AliasSeq!();
|
||||
static foreach (arg; args)
|
||||
staticMap = AliasSeq!(staticMap, fun!arg);
|
||||
}
|
||||
else version (__staticMap_simple_but_slow)
|
||||
{
|
||||
// This has a performance bug. Appending to the staticMap seems to be quadratic.
|
||||
alias staticMap = AliasSeq!();
|
||||
static foreach (i; 0 .. args.length)
|
||||
staticMap = AliasSeq!(staticMap, fun!(args[i]));
|
||||
}
|
||||
else // Current best-of-breed implementation imitates quicksort
|
||||
{
|
||||
static if (args.length <= 8)
|
||||
{
|
||||
alias staticMap = AliasSeq!();
|
||||
static foreach (i; 0 .. args.length)
|
||||
staticMap = AliasSeq!(staticMap, fun!(args[i]));
|
||||
}
|
||||
else
|
||||
{
|
||||
alias staticMap = AliasSeq!(staticMap!(fun, args[0 .. $ / 2]), staticMap!(fun, args[$ / 2 .. $]));
|
||||
}
|
||||
}
|
||||
alias staticMap = AliasSeq!();
|
||||
static foreach (arg; args)
|
||||
staticMap = AliasSeq!(staticMap, fun!arg);
|
||||
}
|
||||
|
||||
///
|
||||
|
|
|
@ -53,6 +53,7 @@ public import
|
|||
std.getopt,
|
||||
std.int128,
|
||||
std.json,
|
||||
std.logger,
|
||||
std.math,
|
||||
std.mathspecial,
|
||||
std.meta,
|
||||
|
|
|
@ -2806,7 +2806,7 @@ auto ref choice(Range)(ref Range range)
|
|||
{
|
||||
import std.algorithm.searching : canFind;
|
||||
|
||||
class MyTestClass
|
||||
static class MyTestClass
|
||||
{
|
||||
int x;
|
||||
|
||||
|
|
|
@ -43,11 +43,16 @@ $(TR $(TD Objects) $(TD
|
|||
))
|
||||
|
||||
$(SECTION Synopsis)
|
||||
---
|
||||
import std.regex;
|
||||
import std.stdio;
|
||||
void main()
|
||||
{
|
||||
|
||||
Create a regex at runtime:
|
||||
$(RUNNABLE_EXAMPLE
|
||||
$(RUNNABLE_EXAMPLE_STDIN
|
||||
They met on 24/01/1970.
|
||||
7/8/99 wasn't as hot as 7/8/2022.
|
||||
)
|
||||
---
|
||||
import std.regex;
|
||||
import std.stdio;
|
||||
// Print out all possible dd/mm/yy(yy) dates found in user input.
|
||||
auto r = regex(r"\b[0-9][0-9]?/[0-9][0-9]?/[0-9][0-9](?:[0-9][0-9])?\b");
|
||||
foreach (line; stdin.byLine)
|
||||
|
@ -57,19 +62,24 @@ $(TR $(TD Objects) $(TD
|
|||
foreach (c; matchAll(line, r))
|
||||
writeln(c.hit);
|
||||
}
|
||||
}
|
||||
...
|
||||
|
||||
// Create a static regex at compile-time, which contains fast native code.
|
||||
---
|
||||
)
|
||||
Create a static regex at compile-time, which contains fast native code:
|
||||
$(RUNNABLE_EXAMPLE
|
||||
---
|
||||
import std.regex;
|
||||
auto ctr = ctRegex!(`^.*/([^/]+)/?$`);
|
||||
|
||||
// It works just like a normal regex:
|
||||
auto c2 = matchFirst("foo/bar", ctr); // First match found here, if any
|
||||
assert(!c2.empty); // Be sure to check if there is a match before examining contents!
|
||||
assert(c2[1] == "bar"); // Captures is a range of submatches: 0 = full match.
|
||||
|
||||
...
|
||||
// multi-pattern regex
|
||||
---
|
||||
)
|
||||
Multi-pattern regex:
|
||||
$(RUNNABLE_EXAMPLE
|
||||
---
|
||||
import std.regex;
|
||||
auto multi = regex([`\d+,\d+`, `([a-z]+):(\d+)`]);
|
||||
auto m = "abc:43 12,34".matchAll(multi);
|
||||
assert(m.front.whichPattern == 2);
|
||||
|
@ -77,21 +87,27 @@ $(TR $(TD Objects) $(TD
|
|||
assert(m.front[2] == "43");
|
||||
m.popFront();
|
||||
assert(m.front.whichPattern == 1);
|
||||
assert(m.front[1] == "12");
|
||||
...
|
||||
|
||||
assert(m.front[0] == "12,34");
|
||||
---
|
||||
)
|
||||
$(LREF Captures) and `opCast!bool`:
|
||||
$(RUNNABLE_EXAMPLE
|
||||
---
|
||||
import std.regex;
|
||||
// The result of `matchAll/matchFirst` is directly testable with `if/assert/while`,
|
||||
// e.g. test if a string consists of letters only:
|
||||
assert(matchFirst("LettersOnly", `^\p{L}+$`));
|
||||
|
||||
// And we can take advantage of the ability to define a variable in the $(LINK2 https://dlang.org/spec/statement.html#IfCondition `IfCondition`):
|
||||
if (const auto captures = matchFirst("At l34st one digit, but maybe more...", `((\d)(\d*))`))
|
||||
// And we can take advantage of the ability to define a variable in the IfCondition:
|
||||
if (const captures = matchFirst("At l34st one digit, but maybe more...", `((\d)(\d*))`))
|
||||
{
|
||||
assert(captures[2] == "3");
|
||||
assert(captures[3] == "4");
|
||||
assert(captures[1] == "34");
|
||||
}
|
||||
---
|
||||
)
|
||||
See_Also: $(LINK2 https://dlang.org/spec/statement.html#IfCondition, `IfCondition`).
|
||||
|
||||
$(SECTION Syntax and general information)
|
||||
The general usage guideline is to keep regex complexity on the side of simplicity,
|
||||
|
@ -470,7 +486,7 @@ private struct CTRegexWrapper(Char)
|
|||
alias getRe this;
|
||||
}
|
||||
|
||||
template ctRegexImpl(alias pattern, string flags=[])
|
||||
template ctRegexImpl(alias pattern, string flags="")
|
||||
{
|
||||
import std.regex.internal.backtracking, std.regex.internal.parser;
|
||||
static immutable r = cast(immutable) regex(pattern, flags);
|
||||
|
@ -518,7 +534,7 @@ template ctRegexImpl(alias pattern, string flags=[])
|
|||
pattern = Regular expression
|
||||
flags = The _attributes (g, i, m, s and x accepted)
|
||||
+/
|
||||
public enum ctRegex(alias pattern, alias flags=[]) = ctRegexImpl!(pattern, flags).wrapper;
|
||||
public enum ctRegex(alias pattern, string flags="") = ctRegexImpl!(pattern, flags).wrapper;
|
||||
|
||||
enum isRegexFor(RegEx, R) = is(immutable RegEx == immutable Regex!(BasicElementOf!R))
|
||||
|| is(RegEx : const(Regex!(BasicElementOf!R)))
|
||||
|
|
|
@ -6884,7 +6884,7 @@ if (isSomeString!S)
|
|||
|
||||
if (inword)
|
||||
{
|
||||
if (col + 1 + (s.length - wordstart) >= columns)
|
||||
if (col + 1 + (s.length - wordstart) > columns)
|
||||
{
|
||||
result ~= '\n';
|
||||
result ~= indent;
|
||||
|
@ -6929,6 +6929,13 @@ if (isSomeString!S)
|
|||
});
|
||||
}
|
||||
|
||||
@safe pure unittest // https://issues.dlang.org/show_bug.cgi?id=23298
|
||||
{
|
||||
assert("1 2 3 4 5 6 7 8 9".wrap(17) == "1 2 3 4 5 6 7 8 9\n");
|
||||
assert("1 2 3 4 5 6 7 8 9 ".wrap(17) == "1 2 3 4 5 6 7 8 9\n");
|
||||
assert("1 2 3 4 5 6 7 8 99".wrap(17) == "1 2 3 4 5 6 7 8\n99\n");
|
||||
}
|
||||
|
||||
/******************************************
|
||||
* Removes one level of indentation from a multi-line string.
|
||||
*
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue