From 6cd007bd9c3665e0f3db0f7667e7f9fc13bb5e93 Mon Sep 17 00:00:00 2001 From: Martin Kinkelin Date: Fri, 21 Feb 2020 17:44:29 +0100 Subject: [PATCH] Upgrade frontend & libs to early v2.091.0 (dlang/dmd@44112eb84b) --- CMakeLists.txt | 6 +- dmd/access.d | 5 +- dmd/aggregate.d | 14 +- dmd/aggregate.h | 6 +- dmd/aliasthis.d | 2 +- dmd/aliasthis.h | 2 +- dmd/apply.d | 2 +- dmd/argtypes.d | 2 +- dmd/argtypes_sysv_x64.d | 2 +- dmd/arrayop.d | 2 +- dmd/arraytypes.d | 2 +- dmd/arraytypes.h | 2 +- dmd/ast_node.d | 2 +- dmd/ast_node.h | 2 +- dmd/attrib.d | 7 +- dmd/attrib.h | 8 +- dmd/blockexit.d | 2 +- dmd/builtin.d | 9 +- dmd/canthrow.d | 5 +- dmd/cli.d | 61 +- dmd/clone.d | 17 +- dmd/compiler.d | 5 +- dmd/compiler.h | 2 +- dmd/complex.d | 2 +- dmd/complex_t.h | 2 +- dmd/cond.d | 5 +- dmd/cond.h | 3 +- dmd/console.d | 2 +- dmd/constfold.d | 2 +- dmd/cppmangle.d | 8 +- dmd/cppmanglewin.d | 2 +- dmd/ctfe.h | 2 +- dmd/ctfeexpr.d | 2 +- dmd/ctorflow.d | 2 +- dmd/dcast.d | 2 +- dmd/dclass.d | 2 +- dmd/declaration.d | 15 +- dmd/declaration.h | 22 +- dmd/delegatize.d | 2 +- dmd/denum.d | 2 +- dmd/dimport.d | 13 +- dmd/dinterpret.d | 20 +- dmd/dmacro.d | 8 +- dmd/dmangle.d | 4 +- dmd/dmodule.d | 47 +- dmd/doc.d | 7 +- dmd/doc.h | 2 +- dmd/dscope.d | 2 +- dmd/dstruct.d | 2 +- dmd/dsymbol.d | 52 +- dmd/dsymbol.h | 6 +- dmd/dsymbolsem.d | 75 +- dmd/dtemplate.d | 8 +- dmd/dtoh.d | 1697 +++++++++++++++++++++ dmd/dversion.d | 2 +- dmd/entity.d | 2 +- dmd/enum.h | 2 +- dmd/errors.d | 238 +-- dmd/errors.h | 2 +- dmd/escape.d | 66 +- dmd/expression.d | 12 +- dmd/expression.h | 3 +- dmd/expressionsem.d | 174 +-- dmd/filecache.d | 2 +- dmd/foreachvar.d | 323 ++++ dmd/func.d | 111 +- dmd/globals.d | 52 +- dmd/globals.h | 23 +- dmd/gluelayer.d | 2 +- dmd/hdrgen.d | 17 +- dmd/hdrgen.h | 2 +- dmd/id.d | 4 +- dmd/id.h | 2 +- dmd/identifier.d | 4 +- dmd/identifier.h | 2 +- dmd/impcnvtab.d | 2 +- dmd/imphint.d | 4 +- dmd/import.h | 2 +- dmd/init.d | 2 +- dmd/init.h | 2 +- dmd/initsem.d | 2 +- dmd/inline.d | 113 +- dmd/inlinecost.d | 26 +- dmd/intrange.d | 2 +- dmd/json.d | 4 +- dmd/json.h | 2 +- dmd/lambdacomp.d | 2 +- dmd/lexer.d | 170 +-- dmd/mangle.h | 2 +- dmd/mars.d | 81 +- dmd/module.h | 3 +- dmd/mtype.d | 9 +- dmd/mtype.h | 5 +- dmd/nogc.d | 4 +- dmd/nspace.d | 2 +- dmd/nspace.h | 2 +- dmd/ob.d | 2564 ++++++++++++++++++++++++++++++++ dmd/objc.d | 12 +- dmd/objc.h | 2 +- dmd/opover.d | 2 +- dmd/optimize.d | 4 +- dmd/parse.d | 120 +- dmd/parsetimevisitor.d | 1 - dmd/printast.d | 2 +- dmd/root/aav.d | 2 +- dmd/root/array.d | 48 +- dmd/root/array.h | 2 +- dmd/root/bitarray.d | 2 +- dmd/root/bitarray.h | 2 +- dmd/root/ctfloat.d | 2 +- dmd/root/ctfloat.h | 2 +- dmd/root/dcompat.h | 2 +- dmd/root/dsystem.h | 2 +- dmd/root/file.d | 4 +- dmd/root/file.h | 2 +- dmd/root/filename.d | 4 +- dmd/root/filename.h | 2 +- dmd/root/hash.d | 2 +- dmd/root/longdouble.d | 2 +- dmd/root/longdouble.h | 2 +- dmd/root/man.d | 8 +- dmd/root/object.h | 2 +- dmd/root/outbuffer.d | 4 +- dmd/root/outbuffer.h | 2 +- dmd/root/port.d | 2 +- dmd/root/port.h | 2 +- dmd/root/region.d | 2 +- dmd/root/rmem.d | 9 +- dmd/root/rmem.h | 2 +- dmd/root/root.h | 2 +- dmd/root/rootobject.d | 2 +- dmd/root/speller.d | 2 +- dmd/root/string.d | 173 +++ dmd/root/stringtable.d | 2 +- dmd/safe.d | 2 +- dmd/sapply.d | 2 +- dmd/scope.h | 5 +- dmd/semantic2.d | 3 +- dmd/semantic3.d | 22 +- dmd/sideeffect.d | 13 +- dmd/statement.d | 22 +- dmd/statement.h | 3 +- dmd/statement_rewrite_walker.d | 2 +- dmd/statementsem.d | 42 +- dmd/staticassert.d | 2 +- dmd/staticassert.h | 2 +- dmd/staticcond.d | 14 +- dmd/target.d | 4 +- dmd/target.h | 2 +- dmd/template.h | 2 +- dmd/templateparamsem.d | 2 +- dmd/tokens.d | 2 +- dmd/tokens.h | 2 +- dmd/traits.d | 27 +- dmd/transitivevisitor.d | 7 - dmd/typesem.d | 19 +- dmd/typinf.d | 2 +- dmd/utf.d | 2 +- dmd/utils.d | 83 +- dmd/version.h | 2 +- dmd/visitor.d | 3 +- dmd/visitor.h | 6 +- driver/config.d | 1 + driver/main.cpp | 7 +- gen/classes.cpp | 2 +- ir/irclass.cpp | 2 +- runtime/CMakeLists.txt | 2 +- runtime/druntime | 2 +- runtime/phobos | 2 +- tests/d2/dmd-testsuite | 2 +- 170 files changed, 5759 insertions(+), 1236 deletions(-) create mode 100644 dmd/dtoh.d create mode 100644 dmd/foreachvar.d create mode 100644 dmd/ob.d create mode 100644 dmd/root/string.d diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ea5b42a7c2..b62a479da0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,11 +97,11 @@ include(GetLinuxDistribution) # # Version information -set(LDC_VERSION "1.20.0") # May be overridden by git hash tag +set(LDC_VERSION "1.21.0") # May be overridden by git hash tag set(DMDFE_MAJOR_VERSION 2) set(DMDFE_MINOR_VERSION 0) -set(DMDFE_PATCH_VERSION 90) -set(DMDFE_FIX_LEVEL 1) +set(DMDFE_PATCH_VERSION 91) +set(DMDFE_FIX_LEVEL 0) set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}${DMDFE_PATCH_VERSION}) if(DEFINED DMDFE_FIX_LEVEL) diff --git a/dmd/access.d b/dmd/access.d index a50edbf1ed8..543afe43cc6 100644 --- a/dmd/access.d +++ b/dmd/access.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/access.d, _access.d) @@ -211,7 +211,6 @@ bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d) * Check access to package/module `p` from scope `sc`. * * Params: - * loc = source location for issued error message * sc = scope from which to access to a fully qualified package name * p = the package/module to check access for * Returns: true if the package is not accessible. @@ -221,7 +220,7 @@ bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d) * (see https://issues.dlang.org/show_bug.cgi?id=313). * */ -bool checkAccess(Loc loc, Scope* sc, Package p) +bool checkAccess(Scope* sc, Package p) { if (sc._module == p) return false; diff --git a/dmd/aggregate.d b/dmd/aggregate.d index a998cc1e990..6a820cb38e7 100644 --- a/dmd/aggregate.d +++ b/dmd/aggregate.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d) @@ -79,7 +79,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol VarDeclarations fields; // VarDeclaration fields Sizeok sizeok = Sizeok.none; // set when structsize contains valid data Dsymbol deferred; // any deferred semantic2() or semantic3() symbol - bool isdeprecated; // true if deprecated /// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface ClassKind classKind; @@ -100,7 +99,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol FuncDeclarations invs; // Array of invariants FuncDeclaration inv; // invariant NewDeclaration aggNew; // allocator - DeleteDeclaration aggDelete; // deallocator // CtorDeclaration or TemplateDeclaration Dsymbol ctor; @@ -133,7 +131,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol Scope* newScope(Scope* sc) { auto sc2 = sc.push(this); - sc2.stc &= STC.safeGroup; + sc2.stc &= STCFlowThruAggregate; sc2.parent = this; sc2.inunion = isUnionDeclaration(); sc2.protection = Prot(Prot.Kind.public_); @@ -636,7 +634,13 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol // is aggregate deprecated? override final bool isDeprecated() const { - return isdeprecated; + return !!(this.storage_class & STC.deprecated_); + } + + /// Flag this aggregate as deprecated + final void setDeprecated() + { + this.storage_class |= STC.deprecated_; } /**************************************** diff --git a/dmd/aggregate.h b/dmd/aggregate.h index 42adaa5bf3d..c402e8ccd07 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -22,7 +22,6 @@ class FuncDeclaration; class CtorDeclaration; class DtorDeclaration; class NewDeclaration; -class DeleteDeclaration; class InterfaceDeclaration; class TypeInfoClassDeclaration; class VarDeclaration; @@ -83,7 +82,6 @@ class AggregateDeclaration : public ScopeDsymbol VarDeclarations fields; // VarDeclaration fields Sizeok sizeok; // set when structsize contains valid data Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol - bool isdeprecated; // true if deprecated ClassKind::Type classKind; // specifies the linkage type @@ -101,7 +99,6 @@ class AggregateDeclaration : public ScopeDsymbol FuncDeclarations invs; // Array of invariants FuncDeclaration *inv; // invariant NewDeclaration *aggNew; // allocator - DeleteDeclaration *aggDelete; // deallocator Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration @@ -130,6 +127,7 @@ class AggregateDeclaration : public ScopeDsymbol bool fill(Loc loc, Expressions *elements, bool ctorinit); Type *getType(); bool isDeprecated() const; // is aggregate deprecated? + void setDeprecated(); bool isNested() const; bool isExport() const; Dsymbol *searchCtor(); diff --git a/dmd/aliasthis.d b/dmd/aliasthis.d index fec7b119769..c4da0b11054 100644 --- a/dmd/aliasthis.d +++ b/dmd/aliasthis.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d) diff --git a/dmd/aliasthis.h b/dmd/aliasthis.h index 0fa89c1b699..4777f7e1ad2 100644 --- a/dmd/aliasthis.h +++ b/dmd/aliasthis.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2009-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2009-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/apply.d b/dmd/apply.d index dcaa6725d33..315b48c9914 100644 --- a/dmd/apply.d +++ b/dmd/apply.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/apply.d, _apply.d) diff --git a/dmd/argtypes.d b/dmd/argtypes.d index 09278a327eb..a92bebc9343 100644 --- a/dmd/argtypes.d +++ b/dmd/argtypes.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/argtypes.d, _argtypes.d) diff --git a/dmd/argtypes_sysv_x64.d b/dmd/argtypes_sysv_x64.d index 8959763e447..e9d81cb14dc 100644 --- a/dmd/argtypes_sysv_x64.d +++ b/dmd/argtypes_sysv_x64.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Martin Kinkelin * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_sysv_x64.d, _argtypes_sysv_x64.d) diff --git a/dmd/arrayop.d b/dmd/arrayop.d index 996548eaab8..480d7dbd989 100644 --- a/dmd/arrayop.d +++ b/dmd/arrayop.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d, _arrayop.d) diff --git a/dmd/arraytypes.d b/dmd/arraytypes.d index 22937456632..bc12206f8a1 100644 --- a/dmd/arraytypes.d +++ b/dmd/arraytypes.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d) diff --git a/dmd/arraytypes.h b/dmd/arraytypes.h index 3d5a48ffddb..02a5cc8fabb 100644 --- a/dmd/arraytypes.h +++ b/dmd/arraytypes.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2006-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2006-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/ast_node.d b/dmd/ast_node.d index 7562755fa55..67465524d5e 100644 --- a/dmd/ast_node.d +++ b/dmd/ast_node.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d, _ast_node.d) diff --git a/dmd/ast_node.h b/dmd/ast_node.h index dee9d04062a..09519af0e99 100644 --- a/dmd/ast_node.h +++ b/dmd/ast_node.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/attrib.d b/dmd/attrib.d index 2cc50e91fd9..f0aa43850e1 100644 --- a/dmd/attrib.d +++ b/dmd/attrib.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d) @@ -1225,6 +1225,11 @@ extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration { return this; } + + override void accept(Visitor v) + { + v.visit(this); + } } diff --git a/dmd/attrib.h b/dmd/attrib.h index 4b2dfa9e02d..40fa3940d5a 100644 --- a/dmd/attrib.h +++ b/dmd/attrib.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -188,11 +188,12 @@ class StaticIfDeclaration : public ConditionalDeclaration void accept(Visitor *v) { v->visit(this); } }; -class StaticForeachDeclaration : public ConditionalDeclaration +class StaticForeachDeclaration : public AttribDeclaration { public: StaticForeach *sfe; ScopeDsymbol *scopesym; + bool onStack; bool cached; Dsymbols *cache; @@ -207,7 +208,7 @@ class StaticForeachDeclaration : public ConditionalDeclaration void accept(Visitor *v) { v->visit(this); } }; -class ForwardingAttribDeclaration : AttribDeclaration +class ForwardingAttribDeclaration : public AttribDeclaration { public: ForwardingScopeDsymbol *sym; @@ -215,6 +216,7 @@ class ForwardingAttribDeclaration : AttribDeclaration Scope *newScope(Scope *sc); void addMember(Scope *sc, ScopeDsymbol *sds); ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; } + void accept(Visitor *v) { v->visit(this); } }; // Mixin declarations diff --git a/dmd/blockexit.d b/dmd/blockexit.d index 6a6b0f0fcb1..f15782d9c47 100644 --- a/dmd/blockexit.d +++ b/dmd/blockexit.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d, _blockexit.d) diff --git a/dmd/builtin.d b/dmd/builtin.d index e5d8d6bc7de..8e91187be90 100644 --- a/dmd/builtin.d +++ b/dmd/builtin.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d) @@ -665,11 +665,11 @@ public extern (C++) void builtin_init() { version (IN_LLVM) { - builtins._init(201); + builtins._init(204); } else { - builtins._init(65); + builtins._init(113); } // @safe @nogc pure nothrow real function(real) add_builtin("_D4core4math3sinFNaNbNiNfeZe", &eval_sin); @@ -724,14 +724,17 @@ else add_builtin("_D4core4math6rndtolFNaNbNiNfeZl", &eval_unimp); // @safe @nogc pure nothrow real function(real) add_builtin("_D3std4math3tanFNaNbNiNfeZe", &eval_tan); + add_builtin("_D3std4math4trig3tanFNaNbNiNfeZe", &eval_tan); add_builtin("_D3std4math5expm1FNaNbNiNfeZe", &eval_unimp); // @trusted @nogc pure nothrow real function(real) add_builtin("_D3std4math3tanFNaNbNiNeeZe", &eval_tan); + add_builtin("_D3std4math4trig3tanFNaNbNiNeeZe", &eval_tan); add_builtin("_D3std4math3expFNaNbNiNeeZe", &eval_exp); add_builtin("_D3std4math5expm1FNaNbNiNeeZe", &eval_expm1); add_builtin("_D3std4math4exp2FNaNbNiNeeZe", &eval_exp2); // @safe @nogc pure nothrow real function(real, real) add_builtin("_D3std4math5atan2FNaNbNiNfeeZe", &eval_unimp); + add_builtin("_D3std4math4trig5atan2FNaNbNiNfeeZe", &eval_unimp); version (IN_LLVM) { // LDC's core.math.ldexp is defined as alias to core.stdc.math.ldexpl diff --git a/dmd/canthrow.d b/dmd/canthrow.d index 7e453f3fefc..25d59b51575 100644 --- a/dmd/canthrow.d +++ b/dmd/canthrow.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d, _canthrow.d) @@ -144,9 +144,6 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow if (ad.dtor) checkFuncThrows(de, ad.dtor); - - if (ad.aggDelete && tb.ty != Tarray) - checkFuncThrows(de, ad.aggDelete); } override void visit(AssignExp ae) diff --git a/dmd/cli.d b/dmd/cli.d index 26b28dd613d..f049a2c4588 100644 --- a/dmd/cli.d +++ b/dmd/cli.d @@ -7,7 +7,7 @@ * However, this file will be used to generate the * $(LINK2 https://dlang.org/dmd-linux.html, online documentation) and MAN pages. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cli.d, _cli.d) @@ -199,8 +199,8 @@ version (IN_LLVM) {} else Option("c", "compile only, do not link" ), - Option("check=[assert|bounds|in|invariant|out|switch|h|help|?][=[on|off]]", - "Enable or disable specific checks", + Option("check=[assert|bounds|in|invariant|out|switch][=[on|off]]", + "enable or disable specific checks", `Overrides default, -boundscheck, -release and -unittest options to enable or disable specific checks. $(UL $(LI $(B assert): assertion checking) @@ -215,7 +215,10 @@ version (IN_LLVM) {} else $(LI $(B off): specified check is disabled.) )` ), - Option("checkaction=[D|C|halt|context|h|help|?]", + Option("check=[h|help|?]", + "list information on all available checks" + ), + Option("checkaction=[D|C|halt|context]", "behavior on assert/boundscheck/finalswitch failure", `Sets behavior when an assert fails, and array boundscheck fails, or a final switch errors. @@ -226,6 +229,9 @@ version (IN_LLVM) {} else $(LI $(B context): Prints the error context as part of the unrecoverable $(D AssertError).) )` ), + Option("checkaction=[h|help|?]", + "list information on all available check actions" + ), Option("color", "turn colored console output on" ), @@ -273,12 +279,12 @@ dmd -cov -unittest myprog.d `Silently allow $(DDLINK deprecate,deprecate,deprecated features) and use of symbols with $(DDSUBLINK $(ROOT_DIR)spec/attribute, deprecated, deprecated attributes).`, ), - Option("dw", - "issue a message when deprecated features or symbols are used (default)" - ), Option("de", "issue an error when deprecated features or symbols are used (halt compilation)" ), + Option("dw", + "issue a message when deprecated features or symbols are used (default)" + ), Option("debug", "compile in debug code", `Compile in $(LINK2 spec/version.html#debug, debug) code`, @@ -313,7 +319,7 @@ dmd -cov -unittest myprog.d With $(I filename), write module dependencies as text to $(I filename) (only imports).`, ), - Option("extern-std=[|h|help|?]", + Option("extern-std=", "set C++ name mangling compatibility with ", "Standards supported are: $(UL @@ -327,6 +333,9 @@ dmd -cov -unittest myprog.d Sets `__traits(getTargetInfo, \"cppStd\")` to `201703`) )", ), + Option("extern-std=[h|help|?]", + "list all supported standards" + ), Option("fPIC", "generate position independent code", TargetOS.all & ~(TargetOS.windows | TargetOS.macOS) @@ -334,10 +343,8 @@ dmd -cov -unittest myprog.d Option("g", "add symbolic debug info", `$(WINDOWS - Add CodeView symbolic debug info with - $(LINK2 $(ROOT_DIR)spec/abi.html#codeview, D extensions) - for debuggers such as - $(LINK2 http://ddbg.mainia.de/releases.html, Ddbg) + Add CodeView symbolic debug info. See + $(LINK2 http://dlang.org/windbg.html, Debugging on Windows). ) $(UNIX Add symbolic debug info in Dwarf format @@ -370,6 +377,15 @@ dmd -cov -unittest myprog.d Option("Hf=", "write 'header' file to filename" ), + Option("HC", + "generate C++ 'header' file" + ), + Option("HCd=", + "write C++ 'header' file to directory" + ), + Option("HCf=", + "write C++ 'header' file to filename" + ), Option("-help", "print help and exit" ), @@ -526,7 +542,7 @@ dmd -cov -unittest myprog.d If no Visual C installation is detected, a wrapper for the redistributable VC2010 dynamic runtime library and mingw based platform import libraries will be linked instead using the LLD linker provided by the LLVM project. - The detection can be skipped explicitly if $(TT msvcrt100) is specified as + The detection can be skipped explicitly if $(TT msvcrt120) is specified as $(I libname). If $(I libname) is empty, no C runtime library is automatically linked in.", TargetOS.windows, @@ -579,7 +595,7 @@ dmd -cov -unittest myprog.d "enable an upcoming language change identified by 'id'", `Preview an upcoming language change identified by $(I id)`, ), - Option("preview=?", + Option("preview=[h|help|?]", "list all upcoming language changes" ), Option("profile", @@ -605,7 +621,7 @@ dmd -cov -unittest myprog.d "revert language change identified by 'id'", `Revert language change identified by $(I id)`, ), - Option("revert=?", + Option("revert=[h|help|?]", "list all revertable language changes" ), Option("run ", @@ -639,15 +655,24 @@ dmd -cov -unittest myprog.d Option("vcolumns", "print character (column) numbers in diagnostics" ), + Option("verror-style=[digitalmars|gnu]", + "set the style for file/line number annotations on compiler messages", + `Set the style for file/line number annotations on compiler messages, + where: + $(DL + $(DT digitalmars)$(DD 'file(line[,column]): message'. This is the default.) + $(DT gnu)$(DD 'file:line[:column]: message', conforming to the GNU standard used by gcc and clang.) + )`, + ), Option("verrors=", "limit the number of error messages (0 means unlimited)" ), - Option("verrors=spec", - "show errors from speculative compiles such as __traits(compiles,...)" - ), Option("verrors=context", "show error messages with the context of the erroring source line" ), + Option("verrors=spec", + "show errors from speculative compiles such as __traits(compiles,...)" + ), Option("-version", "print compiler version and exit" ), diff --git a/dmd/clone.d b/dmd/clone.d index e0376956189..686cad28e3d 100644 --- a/dmd/clone.d +++ b/dmd/clone.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/clone.d, _clone.d) @@ -849,6 +849,7 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc; Loc declLoc = ad.dtors.dim ? ad.dtors[0].loc : ad.loc; Loc loc; // internal code should have no loc to prevent coverage + FuncDeclaration xdtor_fwd = null; // if the dtor is an extern(C++) prototype, then we expect it performs a full-destruction; we don't need to build a full-dtor const bool dtorIsCppPrototype = ad.dtors.dim == 1 && ad.dtors[0].linkage == LINK.cpp && !ad.dtors[0].fbody; @@ -868,6 +869,15 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) auto sdv = (cast(TypeStruct)tv).sym; if (!sdv.dtor) continue; + + // fix: https://issues.dlang.org/show_bug.cgi?id=17257 + // braces for shrink wrapping scope of a + { + xdtor_fwd = sdv.dtor; // this dtor is temporary it could be anything + auto a = new AliasDeclaration(Loc.initial, Id.__xdtor, xdtor_fwd); + a.addMember(sc, ad); // temporarily add to symbol table + } + sdv.dtor.functionSemantic(); stc = mergeFuncAttrs(stc, sdv.dtor); @@ -1017,7 +1027,10 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) auto _alias = new AliasDeclaration(Loc.initial, Id.__xdtor, xdtor); _alias.dsymbolSemantic(sc); ad.members.push(_alias); - _alias.addMember(sc, ad); // add to symbol table + if (xdtor_fwd) + ad.symtab.update(_alias); // update forward dtor to correct one + else + _alias.addMember(sc, ad); // add to symbol table } return xdtor; diff --git a/dmd/compiler.d b/dmd/compiler.d index 130d0065238..cd8b934519e 100644 --- a/dmd/compiler.d +++ b/dmd/compiler.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d, _compiler.d) @@ -186,7 +186,8 @@ private struct ModuleComponentRange * True if the given module should be included in the compilation. */ private bool includeImportedModuleCheck(ModuleComponentRange components) - in { assert(includeImports); } body + in { assert(includeImports); } +do { createMatchNodes(); size_t nodeIndex = 0; diff --git a/dmd/compiler.h b/dmd/compiler.h index a50a2b73e5e..20388e3c09c 100644 --- a/dmd/compiler.h +++ b/dmd/compiler.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/complex.d b/dmd/complex.d index 0bde77f5886..b99aa3aa743 100644 --- a/dmd/complex.d +++ b/dmd/complex.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/complex.d, _complex.d) diff --git a/dmd/complex_t.h b/dmd/complex_t.h index 3c96076fcb6..9d92ed6cef9 100644 --- a/dmd/complex_t.h +++ b/dmd/complex_t.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/cond.d b/dmd/cond.d index 309797fa426..7557a5522e2 100644 --- a/dmd/cond.d +++ b/dmd/cond.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cond.d, _cond.d) @@ -26,6 +26,7 @@ import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; import dmd.root.rootobject; +import dmd.root.string; import dmd.tokens; import dmd.utils; import dmd.visitor; @@ -652,6 +653,7 @@ extern (C++) final class VersionCondition : DVCondition case "HPPA64": case "SH": case "WebAssembly": + case "WASI": case "Alpha": case "Alpha_SoftFloat": case "Alpha_HardFloat": @@ -665,6 +667,7 @@ extern (C++) final class VersionCondition : DVCondition case "CRuntime_Microsoft": case "CRuntime_Musl": case "CRuntime_UClibc": + case "CRuntime_WASI": case "CppRuntime_Clang": case "CppRuntime_DigitalMars": case "CppRuntime_Gcc": diff --git a/dmd/cond.h b/dmd/cond.h index 009d6e7f650..8411e7db124 100644 --- a/dmd/cond.h +++ b/dmd/cond.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -91,7 +91,6 @@ class StaticIfCondition : public Condition { public: Expression *exp; - int nest; // limit circular dependencies Condition *syntaxCopy(); int include(Scope *sc); diff --git a/dmd/console.d b/dmd/console.d index b193a8a854f..cfb45b24ed9 100644 --- a/dmd/console.d +++ b/dmd/console.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/console.d, _console.d) diff --git a/dmd/constfold.d b/dmd/constfold.d index 8829fa8a7d4..81828a0f44e 100644 --- a/dmd/constfold.d +++ b/dmd/constfold.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d) diff --git a/dmd/cppmangle.d b/dmd/cppmangle.d index 51198960416..0fb6af581e4 100644 --- a/dmd/cppmangle.d +++ b/dmd/cppmangle.d @@ -5,7 +5,7 @@ * This is the POSIX side of the implementation. * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d) @@ -505,11 +505,13 @@ private final class CppMangleVisitor : Visitor * ::= # type or template * ::= X E # expression * ::= # simple expressions - * ::= I * E # argument pack + * ::= J * E # argument pack + * + * Reference: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.template-arg */ if (TemplateTupleParameter tt = tp.isTemplateTupleParameter()) { - buf.writeByte('I'); // argument pack + buf.writeByte('J'); // argument pack // mangle the rest of the arguments as types foreach (j; i .. (*ti.tiargs).dim) diff --git a/dmd/cppmanglewin.d b/dmd/cppmanglewin.d index 231704d2052..2731597a67e 100644 --- a/dmd/cppmanglewin.d +++ b/dmd/cppmanglewin.d @@ -1,7 +1,7 @@ /** * Compiler implementation of the $(LINK2 http://www.dlang.org, D programming language) * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmanglewin.d, _cppmanglewin.d) diff --git a/dmd/ctfe.h b/dmd/ctfe.h index 51da94c9a64..7af330bf748 100644 --- a/dmd/ctfe.h +++ b/dmd/ctfe.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/ctfeexpr.d b/dmd/ctfeexpr.d index fd66defe5a6..e3ae3450f6a 100644 --- a/dmd/ctfeexpr.d +++ b/dmd/ctfeexpr.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d) diff --git a/dmd/ctorflow.d b/dmd/ctorflow.d index cbabab7e3e1..0d593bdccf5 100644 --- a/dmd/ctorflow.d +++ b/dmd/ctorflow.d @@ -4,7 +4,7 @@ * * Manage flow analysis for constructors. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d, _ctorflow.d) diff --git a/dmd/dcast.d b/dmd/dcast.d index c0c8c3562a1..21740d36ac0 100644 --- a/dmd/dcast.d +++ b/dmd/dcast.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d) diff --git a/dmd/dclass.d b/dmd/dclass.d index 21b195baa75..d65836ecbcb 100644 --- a/dmd/dclass.d +++ b/dmd/dclass.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d) diff --git a/dmd/declaration.d b/dmd/declaration.d index 465ffb0299e..da08a2c7d63 100644 --- a/dmd/declaration.d +++ b/dmd/declaration.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d, _declaration.d) @@ -249,12 +249,13 @@ enum STC : long future = (1L << 50), // introducing new base class function local = (1L << 51), // do not forward (see dmd.dsymbol.ForwardingScopeDsymbol). returninferred = (1L << 52), // 'return' has been inferred and should not be part of mangling + live = (1L << 53), // function @live attribute // Group members are mutually exclusive (there can be only one) safeGroup = STC.safe | STC.trusted | STC.system, TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild), - FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | + FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live | STC.safeGroup), } @@ -262,7 +263,14 @@ enum STCStorageClass = (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ | STC.abstract_ | STC.synchronized_ | STC.deprecated_ | STC.future | STC.override_ | STC.lazy_ | STC.alias_ | STC.out_ | STC.in_ | STC.manifest | STC.immutable_ | STC.shared_ | STC.wild | STC.nothrow_ | STC.nogc | STC.pure_ | STC.ref_ | STC.return_ | STC.tls | STC.gshared | - STC.property | STC.safeGroup | STC.disable | STC.local); + STC.property | STC.safeGroup | STC.disable | STC.local | STC.live); + +/* These storage classes "flow through" to the inner scope of a Dsymbol + */ +enum STCFlowThruAggregate = STC.safeGroup; /// for an AggregateDeclaration +enum STCFlowThruFunction = ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.abstract_ | STC.deprecated_ | STC.override_ | + STC.TYPECTOR | STC.final_ | STC.tls | STC.gshared | STC.ref_ | STC.return_ | STC.property | + STC.nothrow_ | STC.pure_ | STC.safe | STC.trusted | STC.system); /// for a FuncDeclaration /* Accumulator for successive matches. */ @@ -1080,6 +1088,7 @@ extern (C++) class VarDeclaration : Declaration bool isargptr; // if parameter that _argptr points to bool ctorinit; // it has been initialized in a ctor bool iscatchvar; // this is the exception object variable in catch() clause + bool isowner; // this is an Owner, despite it being `scope` // Both these mean the var is not rebindable once assigned, // and the destructor gets run when it goes out of scope diff --git a/dmd/declaration.h b/dmd/declaration.h index affc01183bf..583ce528553 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -217,6 +217,7 @@ class VarDeclaration : public Declaration bool isargptr; // if parameter that _argptr points to bool ctorinit; // it has been initialized in a ctor bool iscatchvar; // this is the exception object variable in catch() clause + bool isowner; // this is an Owner, despite it being `scope` bool onstack; // it is a class that was allocated on the stack #if IN_LLVM bool onstackWithDtor; // it is a class that was allocated on the stack and needs destruction @@ -629,6 +630,8 @@ class FuncDeclaration : public Declaration static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0); static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0); + bool checkNrvo(); + FuncDeclaration *isFuncDeclaration() { return this; } virtual FuncDeclaration *toAliasFunc() { return this; } @@ -808,20 +811,3 @@ class NewDeclaration : public FuncDeclaration NewDeclaration *isNewDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } }; - - -class DeleteDeclaration : public FuncDeclaration -{ -public: - Parameters *parameters; - - Dsymbol *syntaxCopy(Dsymbol *); - const char *kind() const; - bool isDelete(); - bool isVirtual() const; - bool addPreInvariant(); - bool addPostInvariant(); - - DeleteDeclaration *isDeleteDeclaration() { return this; } - void accept(Visitor *v) { v->visit(this); } -}; diff --git a/dmd/delegatize.d b/dmd/delegatize.d index 292a3dbb481..13de6f9836c 100644 --- a/dmd/delegatize.d +++ b/dmd/delegatize.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d, _delegatize.d) diff --git a/dmd/denum.d b/dmd/denum.d index fa7d76e646f..2927ee9adef 100644 --- a/dmd/denum.d +++ b/dmd/denum.d @@ -4,7 +4,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d) diff --git a/dmd/dimport.d b/dmd/dimport.d index 4989b1963b5..affb0e2e105 100644 --- a/dmd/dimport.d +++ b/dmd/dimport.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d) @@ -210,16 +210,7 @@ extern (C++) final class Import : Dsymbol if (mod && !mod.importedFrom) mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule; if (!pkg) - { - if (mod && mod.isPackageFile) - { - // one level depth package.d file (import pkg; ./pkg/package.d) - // it's necessary to use the wrapping Package already created - pkg = mod.pkg; - } - else - pkg = mod; - } + pkg = mod; //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); return global.errors != errors; } diff --git a/dmd/dinterpret.d b/dmd/dinterpret.d index c96b1653416..848186054d3 100644 --- a/dmd/dinterpret.d +++ b/dmd/dinterpret.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d) @@ -5618,12 +5618,6 @@ public: auto cre = cast(ClassReferenceExp)result; auto cd = cre.originalClass(); - if (cd.aggDelete) - { - e.error("member deallocators not supported by CTFE"); - result = CTFEExp.cantexp; - return; - } if (cd.dtor) { @@ -5647,12 +5641,6 @@ public: auto sd = (cast(TypeStruct)tb).sym; auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1; - if (sd.aggDelete) - { - e.error("member deallocators not supported by CTFE"); - result = CTFEExp.cantexp; - return; - } if (sd.dtor) { @@ -5675,12 +5663,6 @@ public: } auto sd = (cast(TypeStruct)tv).sym; - if (sd.aggDelete) - { - e.error("member deallocators not supported by CTFE"); - result = CTFEExp.cantexp; - return; - } if (sd.dtor) { diff --git a/dmd/dmacro.d b/dmd/dmacro.d index 95c5014807b..b2e84402175 100644 --- a/dmd/dmacro.d +++ b/dmd/dmacro.d @@ -4,7 +4,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d, _dmacro.d) @@ -61,10 +61,10 @@ extern (C++) struct MacroTable } // limit recursive expansion __gshared int nest; - __gshared const(int) nestLimit = 1000; - if (nest > nestLimit) + if (nest > global.recursionLimit) { - error(Loc.initial, "DDoc macro expansion limit exceeded; more than %d expansions.", nestLimit); + error(Loc.initial, "DDoc macro expansion limit exceeded; more than %d expansions.", + global.recursionLimit); return; } nest++; diff --git a/dmd/dmangle.d b/dmd/dmangle.d index 4bb3c1e8926..7660afcac5d 100644 --- a/dmd/dmangle.d +++ b/dmd/dmangle.d @@ -1,7 +1,7 @@ /** * Compiler implementation of the $(LINK2 http://www.dlang.org, D programming language) * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d) @@ -32,10 +32,10 @@ import dmd.mtype; import dmd.root.ctfloat; import dmd.root.outbuffer; import dmd.root.aav; +import dmd.root.string; import dmd.target; import dmd.tokens; import dmd.utf; -import dmd.utils; import dmd.visitor; private immutable char[TMAX] mangleChar = diff --git a/dmd/dmodule.d b/dmd/dmodule.d index 1d0a937ecd3..c9cab5a9a43 100644 --- a/dmd/dmodule.d +++ b/dmd/dmodule.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d, _dmodule.d) @@ -39,9 +39,9 @@ import dmd.root.outbuffer; import dmd.root.port; import dmd.root.rmem; import dmd.root.rootobject; +import dmd.root.string; import dmd.semantic2; import dmd.semantic3; -import dmd.utils; import dmd.visitor; version (IN_LLVM) { @@ -429,7 +429,6 @@ extern (C++) final class Module : Package bool isHdrFile; // if it is a header (.di) file bool isDocFile; // if it is a documentation input file, not D source bool isPackageFile; // if it is a package.d - Package pkg; // if isPackageFile is true, the Package that contains this package.d Strings contentImportedFiles; // array of files whose content was imported int needmoduleinfo; int selfimports; // 0: don't know, 1: does not, 2: does @@ -696,7 +695,7 @@ else extern (D) void setDocfile() { - docfile = setOutfilename(global.params.docname.toDString, global.params.docdir.toDString, arg, global.doc_ext); + docfile = setOutfilename(global.params.docname, global.params.docdir, arg, global.doc_ext); } /** @@ -782,12 +781,11 @@ else /// syntactic parse Module parse() { - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - return parse!ASTCodegen(diagnosticReporter); + return parseModule!ASTCodegen(); } /// ditto - extern (D) Module parse(AST)(DiagnosticReporter diagnosticReporter) + extern (D) Module parseModule(AST)() { @@ -1048,13 +1046,11 @@ else isHdrFile = true; } { - scope p = new Parser!AST(this, buf, cast(bool) docfile, diagnosticReporter); + scope p = new Parser!AST(this, buf, cast(bool) docfile); p.nextToken(); members = p.parseModule(); md = p.md; numlines = p.scanloc.linnum; - if (p.errors) - ++global.errors; } srcBuffer.destroy(); srcBuffer = null; @@ -1107,27 +1103,15 @@ else * * To avoid the conflict: * 1. If preceding package name insertion had occurred by Package::resolve, - * reuse the previous wrapping 'Package' if it exists + * later package.d loading will change Package::isPkgMod to PKG.module_ and set Package::mod. * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here. - * - * Then change Package::isPkgMod to PKG.module_ and set Package::mod. - * - * Note that the 'wrapping Package' is the Package that contains package.d and other submodules, - * the one inserted to the symbol table. */ - auto ps = dst.lookup(ident); - Package p = ps ? ps.isPackage() : null; - if (p is null) - { - p = new Package(Loc.initial, ident); - p.tag = this.tag; // reuse the same package tag - p.symtab = new DsymbolTable(); - } - this.tag = p.tag; // reuse the 'older' package tag - this.pkg = p; + auto p = new Package(Loc.initial, ident); p.parent = this.parent; p.isPkgMod = PKG.module_; p.mod = this; + p.tag = this.tag; // reuse the same package tag + p.symtab = new DsymbolTable(); s = p; } if (!dst.insert(s)) @@ -1151,9 +1135,16 @@ else } else if (Package pkg = prev.isPackage()) { - // 'package.d' loaded after a previous 'Package' insertion - if (isPackageFile) + if (pkg.isPkgMod == PKG.unknown && isPackageFile) + { + /* If the previous inserted Package is not yet determined as package.d, + * link it to the actual module. + */ + pkg.isPkgMod = PKG.module_; + pkg.mod = this; + pkg.tag = this.tag; // reuse the same package tag amodules.push(this); // Add to global array of all modules + } else error(md ? md.loc : loc, "from file %s conflicts with package name %s", srcname, pkg.toChars()); } diff --git a/dmd/doc.d b/dmd/doc.d index e4e20fd5822..1ab990657f8 100644 --- a/dmd/doc.d +++ b/dmd/doc.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/doc.d, _doc.d) @@ -46,6 +46,7 @@ import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.port; import dmd.root.rmem; +import dmd.root.string; import dmd.tokens; import dmd.utf; import dmd.utils; @@ -5257,8 +5258,8 @@ private void highlightCode3(Scope* sc, ref OutBuffer buf, const(char)* p, const( private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset) { uint errorsave = global.startGagging(); - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, diagnosticReporter); + + scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1); OutBuffer res; const(char)* lastp = cast(char*)buf[].ptr; //printf("highlightCode2('%.*s')\n", cast(int)(buf.length - 1), buf[].ptr); diff --git a/dmd/doc.h b/dmd/doc.h index 8719d2eda18..888d2e8f09f 100644 --- a/dmd/doc.h +++ b/dmd/doc.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/dscope.d b/dmd/dscope.d index 3e4827b50ea..6f7d1c2f4a4 100644 --- a/dmd/dscope.d +++ b/dmd/dscope.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d) diff --git a/dmd/dstruct.d b/dmd/dstruct.d index b1ec1342b63..41ab8ccbdc8 100644 --- a/dmd/dstruct.d +++ b/dmd/dstruct.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d, _dstruct.d) diff --git a/dmd/dsymbol.d b/dmd/dsymbol.d index 2e64168ab30..2586703dbb0 100644 --- a/dmd/dsymbol.d +++ b/dmd/dsymbol.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d) @@ -48,9 +48,9 @@ import dmd.root.aav; import dmd.root.rmem; import dmd.root.rootobject; import dmd.root.speller; +import dmd.root.string; import dmd.statement; import dmd.tokens; -import dmd.utils; import dmd.visitor; version (IN_LLVM) @@ -1253,7 +1253,6 @@ version (IN_LLVM) inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; } inout(Import) isImport() inout { return null; } inout(EnumDeclaration) isEnumDeclaration() inout { return null; } - inout(DeleteDeclaration) isDeleteDeclaration() inout { return null; } inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; } inout(AttribDeclaration) isAttribDeclaration() inout { return null; } inout(AnonDeclaration) isAnonDeclaration() inout { return null; } @@ -1401,7 +1400,8 @@ public: * need to check s once) */ - if ((s2.isOverloadSet() || s2.isOverloadable()) && (a || s.isOverloadable())) + auto so2 = s2.isOverloadSet(); + if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable())) { if (symbolIsVisible(this, s2)) { @@ -1411,6 +1411,26 @@ public: s = s2; continue; } + + /* Two different overflow sets can have the same members + * https://issues.dlang.org/show_bug.cgi?id=16709 + */ + auto so = s.isOverloadSet(); + if (so && so2) + { + if (so.a.length == so2.a.length) + { + foreach (j; 0 .. so.a.length) + { + if (so.a[j] !is so2.a[j]) + goto L1; + } + continue; // the same + L1: + { } // different + } + } + if (flags & IgnoreAmbiguous) // if return NULL on ambiguity return null; if (!(flags & IgnoreErrors)) @@ -1548,7 +1568,29 @@ public: } if (loc.isValid()) { - .error(loc, "`%s` at %s conflicts with `%s` at %s", s1.toPrettyChars(), s1.locToChars(), s2.toPrettyChars(), s2.locToChars()); + .error(loc, "%s `%s` at %s conflicts with %s `%s` at %s", + s1.kind(), s1.toPrettyChars(), s1.locToChars(), + s2.kind(), s2.toPrettyChars(), s2.locToChars()); + + static if (0) + { + if (auto so = s1.isOverloadSet()) + { + printf("first %p:\n", so); + foreach (s; so.a[]) + { + printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars()); + } + } + if (auto so = s2.isOverloadSet()) + { + printf("second %p:\n", so); + foreach (s; so.a[]) + { + printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars()); + } + } + } } else { diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h index 52432201417..703f709b696 100644 --- a/dmd/dsymbol.h +++ b/dmd/dsymbol.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -78,7 +78,6 @@ class ArrayScopeSymbol; class SymbolDeclaration; class Expression; class ExpressionDsymbol; -class DeleteDeclaration; class OverloadSet; struct AA; #ifdef IN_GCC @@ -289,7 +288,6 @@ class Dsymbol : public ASTNode virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } virtual Import *isImport() { return NULL; } virtual EnumDeclaration *isEnumDeclaration() { return NULL; } - virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; } virtual AttribDeclaration *isAttribDeclaration() { return NULL; } virtual AnonDeclaration *isAnonDeclaration() { return NULL; } @@ -378,6 +376,7 @@ class OverloadSet : public Dsymbol class ForwardingScopeDsymbol : public ScopeDsymbol { +public: ScopeDsymbol *forward; Dsymbol *symtabInsert(Dsymbol *s); @@ -390,6 +389,7 @@ class ForwardingScopeDsymbol : public ScopeDsymbol class ExpressionDsymbol : public Dsymbol { +public: Expression *exp; ExpressionDsymbol *isExpressionDsymbol() { return this; } diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index af5e87b2d2f..4dbc627b369 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d, _dsymbolsem.d) @@ -2142,16 +2142,13 @@ version (IN_LLVM) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false, diagnosticReporter); + scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false); p.nextToken(); auto d = p.parseDeclDefs(0); - if (p.errors) - { - assert(global.errors != errors); // should have caught all these cases + if (global.errors != errors) return null; - } + if (p.token.value != TOK.endOfFile) { cd.error("incomplete mixin declaration `%s`", str.ptr); @@ -4582,53 +4579,6 @@ version (IN_LLVM) funcDeclarationSemantic(nd); } - override void visit(DeleteDeclaration deld) - { - //printf("DeleteDeclaration::semantic()\n"); - - // @@@DEPRECATED_2.091@@@ - // Made an error in 2.087. - // Should be removed in 2.091 - error(deld.loc, "class deallocators are obsolete, consider moving the deallocation strategy outside of the class"); - - if (deld.semanticRun >= PASS.semanticdone) - return; - if (deld._scope) - { - sc = deld._scope; - deld._scope = null; - } - - deld.parent = sc.parent; - Dsymbol p = deld.parent.pastMixin(); - if (!p.isAggregateDeclaration()) - { - error(deld.loc, "deallocator can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); - deld.type = Type.terror; - deld.errors = true; - return; - } - if (!deld.type) - deld.type = new TypeFunction(ParameterList(deld.parameters), Type.tvoid, LINK.d, deld.storage_class); - - deld.type = deld.type.typeSemantic(deld.loc, sc); - - // Check that there is only one argument of type void* - TypeFunction tf = deld.type.toTypeFunction(); - if (tf.parameterList.length != 1) - { - deld.error("one argument of type `void*` expected"); - } - else - { - Parameter fparam = tf.parameterList[0]; - if (!fparam.type.equals(Type.tvoid.pointerTo())) - deld.error("one argument of type `void*` expected, not `%s`", fparam.type.toChars()); - } - - funcDeclarationSemantic(deld); - } - /* https://issues.dlang.org/show_bug.cgi?id=19731 * * Some aggregate member functions might have had @@ -4713,8 +4663,6 @@ version (IN_LLVM) sd.alignment = sc.alignment(); sd.storage_class |= sc.stc; - if (sd.storage_class & STC.deprecated_) - sd.isdeprecated = true; if (sd.storage_class & STC.abstract_) sd.error("structs, unions cannot be `abstract`"); @@ -4792,7 +4740,6 @@ version (IN_LLVM) /* Look for special member functions. */ sd.aggNew = cast(NewDeclaration)sd.search(Loc.initial, Id.classNew); - sd.aggDelete = cast(DeleteDeclaration)sd.search(Loc.initial, Id.classDelete); // Look for the constructor sd.ctor = sd.searchCtor(); @@ -4929,8 +4876,6 @@ version (IN_LLVM) cldec.protection = sc.protection; cldec.storage_class |= sc.stc; - if (cldec.storage_class & STC.deprecated_) - cldec.isdeprecated = true; if (cldec.storage_class & STC.auto_) cldec.error("storage class `auto` is invalid when declaring a class, did you mean to use `scope`?"); if (cldec.storage_class & STC.scope_) @@ -5035,7 +4980,7 @@ version (IN_LLVM) if (!cldec.isDeprecated()) { // Deriving from deprecated class makes this one deprecated too - cldec.isdeprecated = true; + cldec.setDeprecated(); tc.checkDeprecated(cldec.loc, sc); } } @@ -5127,7 +5072,7 @@ version (IN_LLVM) if (!cldec.isDeprecated()) { // Deriving from deprecated class makes this one deprecated too - cldec.isdeprecated = true; + cldec.setDeprecated(); tc.checkDeprecated(cldec.loc, sc); } } @@ -5389,7 +5334,6 @@ version (IN_LLVM) */ // Can be in base class cldec.aggNew = cast(NewDeclaration)cldec.search(Loc.initial, Id.classNew); - cldec.aggDelete = cast(DeleteDeclaration)cldec.search(Loc.initial, Id.classDelete); // Look for the constructor cldec.ctor = cldec.searchCtor(); @@ -5589,9 +5533,6 @@ version (IN_LLVM) idec.protection = sc.protection; idec.storage_class |= sc.stc; - if (idec.storage_class & STC.deprecated_) - idec.isdeprecated = true; - idec.userAttribDecl = sc.userAttribDecl; } else if (idec.symtab) @@ -5705,8 +5646,8 @@ version (IN_LLVM) { if (!idec.isDeprecated()) { - // Deriving from deprecated class makes this one deprecated too - idec.isdeprecated = true; + // Deriving from deprecated interface makes this one deprecated too + idec.setDeprecated(); tc.checkDeprecated(idec.loc, sc); } } diff --git a/dmd/dtemplate.d b/dmd/dtemplate.d index 0a930d24428..91a1151a055 100644 --- a/dmd/dtemplate.d +++ b/dmd/dtemplate.d @@ -28,7 +28,7 @@ * arguments, and uses it if found. * - Otherwise, the rest of semantic is run on the `TemplateInstance`. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d) @@ -1356,6 +1356,11 @@ else // Set up scope for parameters Scope* paramscope = scopeForTemplateParameters(ti,sc); + // Mark the parameter scope as deprecated if the templated + // function is deprecated (since paramscope.enclosing is the + // calling scope already) + paramscope.stc |= fd.storage_class & STC.deprecated_; + TemplateTupleParameter tp = isVariadic(); Tuple declaredTuple = null; @@ -2205,6 +2210,7 @@ else sc2.parent = ti; sc2.tinst = ti; sc2.minst = sc.minst; + sc2.stc |= fd.storage_class & STC.deprecated_; fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs); diff --git a/dmd/dtoh.d b/dmd/dtoh.d new file mode 100644 index 00000000000..86914221143 --- /dev/null +++ b/dmd/dtoh.d @@ -0,0 +1,1697 @@ +/** + * Compiler implementation of the + * $(LINK2 http://www.dlang.org, D programming language). + * + * This module contains the implementation of the C++ header generation available through + * the command line switch -Hc. + * + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d) + * Documentation: https://dlang.org/phobos/dmd_dtoh.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtoh.d + */ +module dmd.dtoh; + +import core.stdc.stdio; +import core.stdc.string; +import core.stdc.ctype; + +import dmd.astcodegen; +import dmd.arraytypes; +import dmd.globals; +import dmd.identifier; +import dmd.json; +import dmd.mars; +import dmd.root.array; +import dmd.root.file; +import dmd.root.filename; +import dmd.root.rmem; +import dmd.visitor; +import dmd.tokens; + +import dmd.root.outbuffer; +import dmd.utils; + +//debug = Debug_DtoH; +enum isBuildingCompiler = false; + +private struct DMDType +{ + __gshared Identifier c_long; + __gshared Identifier c_ulong; + __gshared Identifier c_longlong; + __gshared Identifier c_ulonglong; + __gshared Identifier c_long_double; + __gshared Identifier AssocArray; + __gshared Identifier Array; + + static void _init() + { + c_long = Identifier.idPool("__c_long"); + c_ulong = Identifier.idPool("__c_ulong"); + c_longlong = Identifier.idPool("__c_longlong"); + c_ulonglong = Identifier.idPool("__c_ulonglong"); + c_long_double = Identifier.idPool("__c_long_double"); + + if (isBuildingCompiler) + { + AssocArray = Identifier.idPool("AssocArray"); + Array = Identifier.idPool("Array"); + } + + } +} + +private struct DMDModule +{ + __gshared Identifier identifier; + __gshared Identifier root; + __gshared Identifier visitor; + __gshared Identifier parsetimevisitor; + __gshared Identifier permissivevisitor; + __gshared Identifier strictvisitor; + __gshared Identifier transitivevisitor; + __gshared Identifier dmd; + static void _init() + { + identifier = Identifier.idPool("identifier"); + root = Identifier.idPool("root"); + visitor = Identifier.idPool("visitor"); + parsetimevisitor = Identifier.idPool("parsetimevisitor"); + permissivevisitor = Identifier.idPool("permissivevisitor"); + strictvisitor = Identifier.idPool("strictvisitor"); + transitivevisitor = Identifier.idPool("transitivevisitor"); + dmd = Identifier.idPool("dmd"); + } +} + +private struct DMDClass +{ + __gshared Identifier ID; ////Identifier + __gshared Identifier Visitor; + __gshared Identifier ParseTimeVisitor; + static void _init() + { + ID = Identifier.idPool("Identifier"); + Visitor = Identifier.idPool("Visitor"); + ParseTimeVisitor = Identifier.idPool("ParseTimeVisitor"); + } + +} + +private bool isIdentifierClass(ASTCodegen.ClassDeclaration cd) +{ + return (cd.ident == DMDClass.ID && + cd.parent !is null && + cd.parent.ident == DMDModule.identifier && + cd.parent.parent && cd.parent.parent.ident == DMDModule.dmd && + !cd.parent.parent.parent); +} + +private bool isVisitorClass(ASTCodegen.ClassDeclaration cd) +{ + for (auto cdb = cd; cdb; cdb = cdb.baseClass) + { + if (cdb.ident == DMDClass.Visitor || + cdb.ident == DMDClass.ParseTimeVisitor) + return true; + } + return false; +} + +private bool isIgnoredModule(ASTCodegen.Module m) +{ + if (!m) + return true; + + // Ignore dmd.root + if (m.parent && m.parent.ident == DMDModule.root && + m.parent.parent && m.parent.parent.ident == DMDModule.dmd && + !m.parent.parent.parent) + { + return true; + } + + // Ignore dmd.visitor and derivatives + if ((m.ident == DMDModule.visitor || + m.ident == DMDModule.parsetimevisitor || + m.ident == DMDModule.permissivevisitor || + m.ident == DMDModule.strictvisitor || + m.ident == DMDModule.transitivevisitor) && + m.parent && m.parent.ident == DMDModule.dmd && + !m.parent.parent) + { + return true; + } + return false; +} + +private bool isFrontendModule(ASTCodegen.Module m) +{ + if (!m || !m.parent) + return false; + + // Ignore dmd.root + if (m.parent.ident == DMDModule.root && + m.parent.parent && m.parent.parent.ident == DMDModule.dmd && + !m.parent.parent.parent) + { + return false; + } + + // Ignore dmd.visitor and derivatives + if ((m.ident == DMDModule.visitor || + m.ident == DMDModule.parsetimevisitor || + m.ident == DMDModule.permissivevisitor || + m.ident == DMDModule.strictvisitor || + m.ident == DMDModule.transitivevisitor) && + m.parent && m.parent.ident == DMDModule.dmd && + !m.parent.parent) + { + return false; + } + return ((m.parent.ident == DMDModule.dmd && !m.parent.parent) || + (m.parent.parent.ident == DMDModule.dmd && !m.parent.parent.parent)); +} + +private void initialize() +{ + __gshared bool initialized; + + if (!initialized) + { + initialized = true; + + DMDType._init(); + if (isBuildingCompiler) + { + DMDModule._init(); + DMDClass._init(); + } + } +} + +void genCppHdrFiles(ref Modules ms) +{ + initialize(); + + OutBuffer buf; + buf.writestring("#pragma once\n"); + buf.writeByte('\n'); + buf.printf("// Automatically generated by dmd -HC\n"); + buf.writeByte('\n'); + buf.writestring("#include \n"); + buf.writestring("#include \n"); + buf.writestring("#include \n"); + buf.writestring("#include \n"); + buf.writeByte('\n'); + buf.writestring("#define _d_void void\n"); + buf.writestring("#define _d_bool bool\n"); + buf.writestring("#define _d_byte signed char\n"); + buf.writestring("#define _d_ubyte unsigned char\n"); + buf.writestring("#define _d_short short\n"); + buf.writestring("#define _d_ushort unsigned short\n"); + buf.writestring("#define _d_int int\n"); + buf.writestring("#define _d_uint unsigned\n"); + if (global.params.isLP64) + { + buf.writestring("#define _d_long long\n"); + buf.writestring("#define _d_ulong unsigned long\n"); + } + else + { + buf.writestring("#define _d_long long long\n"); + buf.writestring("#define _d_ulong unsigned long long\n"); + } + buf.writestring("#define _d_float float\n"); + buf.writestring("#define _d_double double\n"); + buf.writestring("#define _d_real long double\n"); + buf.writestring("#define _d_char char\n"); + buf.writestring("#define _d_wchar wchar_t\n"); + buf.writestring("#define _d_dchar unsigned\n"); + buf.writestring("typedef _d_long d_int64;\n"); + buf.writestring("\n"); + buf.writestring("#define _d_null NULL\n"); + buf.writestring("\n\n"); + + OutBuffer check; + OutBuffer done; + OutBuffer decl; + scope v = new ToCppBuffer!ASTCodegen(&check, &buf, &done, &decl); + foreach (m; ms) + { + //printf("// Parsing module %s\n", m.toPrettyChars()); + buf.printf("// Parsing module %s\n", m.toPrettyChars()); + m.accept(v); + } + buf.write(&done); + buf.write(&decl); + //printf("%s\n", decl.peekSlice().ptr); + + + debug (Debug_DtoH) + { + buf.writestring(` +#if OFFSETS + template + size_t getSlotNumber(int dummy, ...) + { + T c; + va_list ap; + va_start(ap, dummy); + void *f = va_arg(ap, void*); + for (size_t i = 0; ; i++) + { + if ( (*(void***)&c)[i] == f) + return i; + } + va_end(ap); + } + + void testOffsets() + { +`); + buf.write(&check); + buf.writestring(` + } +#endif +`); + } + + if (global.params.cxxhdrname is null) + { + // Write to stdout; assume it succeeds + size_t n = fwrite(buf[].ptr, 1, buf.length, stdout); + assert(n == buf.length); // keep gcc happy about return values + } + else + { + const(char)[] name = FileName.combine(global.params.cxxhdrdir, global.params.cxxhdrname); + writeFile(Loc.initial, name, buf[]); + } +} + +/**************************************************** + */ +extern(C++) final class ToCppBuffer(AST) : Visitor +{ + alias visit = Visitor.visit; +public: + bool[void*] visited; + bool[void*] forwarded; + OutBuffer* fwdbuf; + OutBuffer* checkbuf; + OutBuffer* donebuf; + OutBuffer* buf; + AST.AggregateDeclaration adparent; + AST.ClassDeclaration cdparent; + AST.TemplateDeclaration tdparent; + Identifier ident; + LINK linkage = LINK.d; + bool forwardedAA; + + this(OutBuffer* checkbuf, OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) + { + this.checkbuf = checkbuf; + this.fwdbuf = fwdbuf; + this.donebuf = donebuf; + this.buf = buf; + } + + private void indent() + { + if (adparent) + buf.writestring(" "); + } + + override void visit(AST.Dsymbol s) + { + debug (Debug_DtoH) + { + printf("[AST.Dsymbol enter] %s\n", s.toChars()); + scope(exit) printf("[AST.Dsymbol exit] %s\n", s.toChars()); + } + + if (isBuildingCompiler && s.getModule() && s.getModule().isFrontendModule()) + { + indent(); + buf.printf("// ignored %s %s\n", s.kind(), s.toPrettyChars()); + } + } + + override void visit(AST.Import i) + { + debug (Debug_DtoH) + { + printf("[AST.Import enter] %s\n", i.toChars()); + scope(exit) printf("[AST.Import exit] %s\n", i.toChars()); + } + } + + override void visit(AST.AttribDeclaration pd) + { + debug (Debug_DtoH) + { + printf("[AST.AttribDeclaration enter] %s\n", pd.toChars()); + scope(exit) printf("[AST.AttribDeclaration exit] %s\n", pd.toChars()); + } + Dsymbols* decl = pd.include(null); + if (!decl) + return; + + foreach (s; *decl) + { + if (adparent || s.prot().kind >= AST.Prot.Kind.public_) + s.accept(this); + } + } + + override void visit(AST.LinkDeclaration ld) + { + debug (Debug_DtoH) + { + printf("[AST.LinkDeclaration enter] %s\n", ld.toChars()); + scope(exit) printf("[AST.LinkDeclaration exit] %s\n", ld.toChars()); + } + auto save = linkage; + linkage = ld.linkage; + if (ld.linkage != LINK.c && ld.linkage != LINK.cpp) + { + indent(); + buf.printf("// ignoring %s block because of linkage\n", ld.toPrettyChars()); + } + else + { + visit(cast(AST.AttribDeclaration)ld); + } + linkage = save; + } + + override void visit(AST.Module m) + { + debug (Debug_DtoH) + { + printf("[AST.Module enter] %s\n", m.toChars()); + scope(exit) printf("[AST.Module exit] %s\n", m.toChars()); + } + foreach (s; *m.members) + { + if (s.prot().kind < AST.Prot.Kind.public_) + continue; + s.accept(this); + } + } + + override void visit(AST.FuncDeclaration fd) + { + debug (Debug_DtoH) + { + printf("[AST.FuncDeclaration enter] %s\n", fd.toChars()); + scope(exit) printf("[AST.FuncDeclaration exit] %s\n", fd.toChars()); + } + if (cast(void*)fd in visited) + return; + if (isBuildingCompiler && fd.getModule() && fd.getModule().isIgnoredModule()) + return; + + // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars()); + visited[cast(void*)fd] = true; + + auto tf = cast(AST.TypeFunction)fd.type; + indent(); + if (!tf || !tf.deco) + { + buf.printf("// ignoring function %s because semantic hasn't been run\n", fd.toPrettyChars()); + return; + } + if (tf.linkage != LINK.c && tf.linkage != LINK.cpp) + { + buf.printf("// ignoring function %s because of linkage\n", fd.toPrettyChars()); + return; + } + if (!adparent && !fd.fbody) + { + buf.printf("// ignoring function %s because it's extern\n", fd.toPrettyChars()); + return; + } + + if (tf.linkage == LINK.c) + buf.writestring("extern \"C\" "); + else if (!adparent) + buf.writestring("extern "); + if (adparent && fd.isStatic()) + buf.writestring("static "); + if (adparent && fd.vtblIndex != -1) + { + if (!fd.isOverride()) + buf.writestring("virtual "); + + auto s = adparent.search(Loc.initial, fd.ident); + if (!(adparent.storage_class & AST.STC.abstract_) && + !(cast(AST.ClassDeclaration)adparent).isAbstract() && + s is fd && !fd.overnext) + { + auto save = buf; + buf = checkbuf; + buf.writestring(" assert(getSlotNumber<"); + buf.writestring(adparent.ident.toChars()); + buf.writestring(">(0, &"); + buf.writestring(adparent.ident.toChars()); + buf.writestring("::"); + buf.writestring(fd.ident.toChars()); + buf.printf(") == %d);\n", fd.vtblIndex); + buf = save; + } + } + + if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11) + buf.printf("private: "); + funcToBuffer(tf, fd); + if (adparent && tf.isConst()) + { + bool fdOverridesAreConst = true; + foreach (fdv; fd.foverrides) + { + auto tfv = cast(AST.TypeFunction)fdv.type; + if (!tfv.isConst()) + { + fdOverridesAreConst = false; + break; + } + } + + buf.writestring(fdOverridesAreConst ? " const" : " /* const */"); + } + if (adparent && fd.isAbstract()) + buf.writestring(" = 0"); + if (adparent && fd.isDisabled && global.params.cplusplus >= CppStdRevision.cpp11) + buf.printf(" = delete"); + buf.printf(";\n"); + if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11) + buf.printf("public:\n"); + if (!adparent) + buf.printf("\n"); + } + + override void visit(AST.UnitTestDeclaration utd) + { + debug (Debug_DtoH) + { + printf("[AST.UnitTestDeclaration enter] %s\n", utd.toChars()); + scope(exit) printf("[AST.UnitTestDeclaration exit] %s\n", utd.toChars()); + } + } + + override void visit(AST.VarDeclaration vd) + { + debug (Debug_DtoH) + { + printf("[AST.VarDeclaration enter] %s\n", vd.toChars()); + scope(exit) printf("[AST.VarDeclaration exit] %s\n", vd.toChars()); + } + if (cast(void*)vd in visited) + return; + if (isBuildingCompiler && vd.getModule() && vd.getModule().isIgnoredModule()) + return; + + visited[cast(void*)vd] = true; + + if (vd.alignment != uint.max) + { + indent(); + buf.printf("// Ignoring var %s alignment %u\n", vd.toChars(), vd.alignment); + } + + if (vd.storage_class & AST.STC.manifest && + vd.type.isintegral() && + vd._init && vd._init.isExpInitializer()) + { + indent(); + buf.writestring("#define "); + buf.writestring(vd.ident.toChars()); + buf.writestring(" "); + auto e = AST.initializerToExpression(vd._init); + if (e.type.ty == AST.Tbool) + buf.printf("%d", e.toInteger()); + else + AST.initializerToExpression(vd._init).accept(this); + buf.writestring("\n"); + if (!adparent) + buf.printf("\n"); + return; + } + + if (tdparent && vd.type && !vd.type.deco) + { + indent(); + if (linkage != LINK.c && linkage != LINK.cpp) + { + buf.printf("// ignoring variable %s because of linkage\n", vd.toPrettyChars()); + return; + } + typeToBuffer(vd.type, vd.ident); + buf.writestring(";\n"); + return; + } + + if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.tls | AST.STC.gshared) || + vd.parent && vd.parent.isModule()) + { + indent(); + if (vd.linkage != LINK.c && vd.linkage != LINK.cpp) + { + buf.printf("// ignoring variable %s because of linkage\n", vd.toPrettyChars()); + return; + } + if (vd.storage_class & AST.STC.tls) + { + buf.printf("// ignoring variable %s because of thread-local storage\n", vd.toPrettyChars()); + return; + } + if (vd.linkage == LINK.c) + buf.writestring("extern \"C\" "); + else if (!adparent) + buf.writestring("extern "); + if (adparent) + buf.writestring("static "); + typeToBuffer(vd.type, vd.ident); + buf.writestring(";\n"); + if (!adparent) + buf.printf("\n"); + return; + } + + if (adparent && vd.type && vd.type.deco) + { + indent(); + auto save = cdparent; + cdparent = vd.isField() ? adparent.isClassDeclaration() : null; + typeToBuffer(vd.type, vd.ident); + cdparent = save; + buf.writestring(";\n"); + + if (auto t = vd.type.isTypeStruct()) + includeSymbol(t.sym); + + auto savex = buf; + buf = checkbuf; + buf.writestring(" assert(offsetof("); + buf.writestring(adparent.ident.toChars()); + buf.writestring(", "); + buf.writestring(vd.ident.toChars()); + buf.printf(") == %d);\n", vd.offset); + buf = savex; + return; + } + visit(cast(AST.Dsymbol)vd); + } + + override void visit(AST.TypeInfoDeclaration tid) + { + debug (Debug_DtoH) + { + printf("[AST.TypeInfoDeclaration enter] %s\n", tid.toChars()); + scope(exit) printf("[AST.TypeInfoDeclaration exit] %s\n", tid.toChars()); + } + } + + override void visit(AST.AliasDeclaration ad) + { + debug (Debug_DtoH) + { + printf("[AST.AliasDeclaration enter] %s\n", ad.toChars()); + scope(exit) printf("[AST.AliasDeclaration exit] %s\n", ad.toChars()); + } + if (isBuildingCompiler && ad.getModule() && ad.getModule().isIgnoredModule()) + return; + + if (auto t = ad.type) + { + if (t.ty == AST.Tdelegate) + { + visit(cast(AST.Dsymbol)ad); + return; + } + buf.writestring("typedef "); + typeToBuffer(t, ad.ident); + buf.writestring(";\n"); + if (!adparent) + buf.printf("\n"); + return; + } + if (!ad.aliassym) + { + assert(0); + } + if (auto ti = ad.aliassym.isTemplateInstance()) + { + visitTi(ti); + return; + } + if (auto sd = ad.aliassym.isStructDeclaration()) + { + buf.writestring("typedef "); + sd.type.accept(this); + buf.writestring(" "); + buf.writestring(ad.ident.toChars()); + buf.writestring(";\n"); + if (!adparent) + buf.printf("\n"); + return; + } + if (ad.aliassym.isDtorDeclaration()) + { + // Ignore. It's taken care of while visiting FuncDeclaration + return; + } + indent(); + buf.printf("// ignored %s %s\n", ad.aliassym.kind(), ad.aliassym.toPrettyChars()); + } + + override void visit(AST.AnonDeclaration ad) + { + debug (Debug_DtoH) + { + printf("[AST.AnonDeclaration enter] %s\n", ad.toChars()); + scope(exit) printf("[AST.AnonDeclaration exit] %s\n", ad.toChars()); + } + indent(); + buf.writestring(ad.isunion ? "union\n" : "struct\n"); + indent(); + buf.writestring("{\n"); + foreach (s; *ad.decl) + { + indent(); + s.accept(this); + } + indent(); + buf.writestring("};\n"); + } + + private bool memberField(AST.VarDeclaration vd) + { + if (!vd.type || !vd.type.deco || !vd.ident) + return false; + if (!vd.isField()) + return false; + if (vd.type.ty == AST.Tfunction) + return false; + if (vd.type.ty == AST.Tsarray) + return false; + return true; + } + + override void visit(AST.StructDeclaration sd) + { + debug (Debug_DtoH) + { + printf("[AST.StructDeclaration enter] %s\n", sd.toChars()); + scope(exit) printf("[AST.StructDeclaration exit] %s\n", sd.toChars()); + } + if (sd.isInstantiated()) + return; + if (cast(void*)sd in visited) + return; + if (!sd.type || !sd.type.deco) + return; + if (isBuildingCompiler && sd.getModule() && sd.getModule().isIgnoredModule()) + return; + + visited[cast(void*)sd] = true; + if (linkage != LINK.c && linkage != LINK.cpp) + { + buf.printf("// ignoring non-cpp struct %s because of linkage\n", sd.toChars()); + return; + } + + buf.writestring(sd.isUnionDeclaration() ? "union" : "struct"); + pushAlignToBuffer(sd.alignment); + buf.writestring(sd.ident.toChars()); + if (!sd.members) + { + buf.writestring(";\n\n"); + return; + } + + buf.writestring("\n{\n"); + auto save = adparent; + adparent = sd; + foreach (m; *sd.members) + { + m.accept(this); + } + adparent = save; + // Generate default ctor + if (!sd.noDefaultCtor) + { + buf.printf(" %s()", sd.ident.toChars()); + size_t varCount; + bool first = true; + foreach (m; *sd.members) + { + if (auto vd = m.isVarDeclaration()) + { + if (!memberField(vd)) + continue; + varCount++; + + if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct && + !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray) + { + continue; + } + if (vd._init && vd._init.isVoidInitializer()) + continue; + + if (first) + { + buf.printf(" : "); + first = false; + } + else + { + buf.printf(", "); + } + buf.printf("%s(", vd.ident.toChars()); + + if (vd._init) + { + AST.initializerToExpression(vd._init).accept(this); + } + buf.printf(")"); + } + } + buf.printf(" {}\n"); + } + + version (none) + { + if (varCount) + { + buf.printf(" %s(", sd.ident.toChars()); + bool first = true; + foreach (m; *sd.members) + { + if (auto vd = m.isVarDeclaration()) + { + if (!memberField(vd)) + continue; + if (first) + first = false; + else + buf.writestring(", "); + assert(vd.type); + assert(vd.ident); + typeToBuffer(vd.type, vd.ident); + } + } + buf.printf(") {"); + foreach (m; *sd.members) + { + if (auto vd = m.isVarDeclaration()) + { + if (!memberField(vd)) + continue; + buf.printf(" this->%s = %s;", vd.ident.toChars(), vd.ident.toChars()); + } + } + buf.printf(" }\n"); + } + } + buf.writestring("};\n"); + + popAlignToBuffer(sd.alignment); + buf.writestring("\n"); + + auto savex = buf; + buf = checkbuf; + buf.writestring(" assert(sizeof("); + buf.writestring(sd.ident.toChars()); + buf.printf(") == %d);\n", sd.size(Loc.initial)); + buf = savex; + } + + private void pushAlignToBuffer(uint alignment) + { + // DMD ensures alignment is a power of two + //assert(alignment > 0 && ((alignment & (alignment - 1)) == 0), + // "Invalid alignment size"); + + // When no alignment is specified, `uint.max` is the default + if (alignment == uint.max) + { + buf.writeByte(' '); + return; + } + + buf.writestring("\n#if defined(__GNUC__) || defined(__clang__)\n"); + // The equivalent of `#pragma pack(push, n)` is `__attribute__((packed, aligned(n)))` + // NOTE: removing the packed attribute will might change the resulting size + buf.printf(" __attribute__((packed, aligned(%d)))\n", alignment); + buf.writestring("#elif defined(_MSC_VER)\n"); + buf.printf(" __declspec(align(%d))\n", alignment); + buf.writestring("#elif defined(__DMC__)\n"); + buf.printf(" #pragma pack(push, %d)\n", alignment); + //buf.printf("#pragma pack(%d)\n", alignment); + buf.writestring("#endif\n"); + } + + private void popAlignToBuffer(uint alignment) + { + if (alignment == uint.max) + return; + + buf.writestring("#if defined(__DMC__)\n"); + buf.writestring(" #pragma pack(pop)\n"); + //buf.writestring("#pragma pack()\n"); + buf.writestring("#endif\n"); + } + + private void includeSymbol(AST.Dsymbol ds) + { + debug (Debug_DtoH) + { + printf("[includeSymbol(AST.Dsymbol) enter] %s\n", ds.toChars()); + scope(exit) printf("[includeSymbol(AST.Dsymbol) exit] %s\n", ds.toChars()); + } + if (cast(void*) ds in visited) + return; + + OutBuffer decl; + auto save = buf; + buf = &decl; + ds.accept(this); + buf = save; + donebuf.writestring(decl.peekChars()); + } + + override void visit(AST.ClassDeclaration cd) + { + debug (Debug_DtoH) + { + printf("[AST.ClassDeclaration enter] %s\n", cd.toChars()); + scope(exit) printf("[AST.ClassDeclaration exit] %s\n", cd.toChars()); + } + if (cast(void*)cd in visited) + return; + if (isBuildingCompiler) + { + if (cd.getModule() && cd.getModule().isIgnoredModule()) + return; + if (cd.isVisitorClass()) + return; + } + + visited[cast(void*)cd] = true; + if (!cd.isCPPclass()) + { + buf.printf("// ignoring non-cpp class %s\n", cd.toChars()); + return; + } + + buf.writestring("class "); + buf.writestring(cd.ident.toChars()); + if (cd.baseClass) + { + buf.writestring(" : public "); + buf.writestring(cd.baseClass.ident.toChars()); + + includeSymbol(cd.baseClass); + } + if (!cd.members) + { + buf.writestring(";\n\n"); + return; + } + + buf.writestring("\n{\npublic:\n"); + auto save = adparent; + adparent = cd; + foreach (m; *cd.members) + { + m.accept(this); + } + adparent = save; + + // Generate special static inline function. + if (isBuildingCompiler && cd.isIdentifierClass()) + { + buf.writestring(" static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); }\n"); + } + + buf.writestring("};\n\n"); + } + + override void visit(AST.EnumDeclaration ed) + { + debug (Debug_DtoH) + { + printf("[AST.EnumDeclaration enter] %s\n", ed.toChars()); + scope(exit) printf("[AST.EnumDeclaration exit] %s\n", ed.toChars()); + } + if (cast(void*)ed in visited) + return; + + if (isBuildingCompiler && ed.getModule() && ed.getModule().isIgnoredModule()) + return; + + visited[cast(void*)ed] = true; + + //if (linkage != LINK.c && linkage != LINK.cpp) + //{ + //buf.printf("// ignoring non-cpp enum %s because of linkage\n", ed.toChars()); + //return; + //} + + bool hasBaseType = false; + + switch (ed.memtype.ty) + { + case AST.Tbool, AST.Tvoid: + case AST.Tchar, AST.Twchar, AST.Tdchar: + case AST.Tint8, AST.Tuns8: + case AST.Tint16, AST.Tuns16: + case AST.Tint64, AST.Tuns64: + case AST.Tfloat32, AST.Tfloat64, AST.Tfloat80: + hasBaseType = true; + break; + case AST.Tint32, AST.Tuns32, AST.Tenum: // by default, the base is an int + break; + default: + import dmd.root.string : toDString; + printf ("%s\n", ed.ident.toChars()); + assert(0, ed.memtype.kind.toDString); + } + + if (ed.isSpecial()) + return; + const(char)* ident = null; + if (ed.ident) + ident = ed.ident.toChars(); + if (!ident) + { + buf.writestring("enum"); + } + else if (hasBaseType) + { + //printf("typedef _d_%s %s;\n", ed.memtype.kind, ident); + if (global.params.cplusplus >= CppStdRevision.cpp11) + { + //printf("Using cpp 11 and beyond\n"); + buf.printf("enum %s : %s", ident, ed.memtype.kind); + } + else + { + //printf("Using cpp 98\n"); + buf.writestring("typedef _d_"); + buf.writestring(ed.memtype.kind); + buf.writeByte(' '); + buf.writestring(ident); + buf.writestring(";\n"); + buf.writestring("enum"); + } + } + else + { + buf.writestring("enum "); + buf.writestring(ident); + } + + if (!ed.members) + { + buf.writestring(";\n\n"); + return; + } + + buf.writestring("\n{\n"); + foreach (i, m; *ed.members) + { + if (i) + buf.writestring(",\n"); + buf.writestring(" "); + if (ident && global.params.cplusplus == CppStdRevision.cpp98) + { + foreach (c; ident[0 .. strlen(ident)]) + buf.writeByte(toupper(c)); + } + m.accept(this); + } + buf.writestring("\n};\n\n"); + + //printf("Enum %s min %d max %d\n", ident, ed.minval.toInteger(), ed.maxval.toInteger()); + } + + override void visit(AST.EnumMember em) + { + debug (Debug_DtoH) + { + printf("[AST.EnumMember enter] %s\n", em.toChars()); + scope(exit) printf("[AST.EnumMember exit] %s\n", em.toChars()); + } + buf.writestring(em.ident.toChars()); + buf.writestring(" = "); + //if (cast(AST.StringExp)em.value) + //{ + //em.value.error("cannot convert string enum"); + //return ; + //} + auto ie = cast(AST.IntegerExp)em.value; + visitInteger(ie.toInteger(), em.ed.memtype); + } + + private void typeToBuffer(AST.Type t, Identifier ident) + { + debug (Debug_DtoH) + { + printf("[typeToBuffer(AST.Type) enter] %s ident %s\n", t.toChars(), ident.toChars()); + scope(exit) printf("[typeToBuffer(AST.Type) exit] %s ident %s\n", t.toChars(), ident.toChars()); + } + this.ident = ident; + t.accept(this); + if (this.ident) + { + buf.writeByte(' '); + buf.writestring(ident.toChars()); + } + this.ident = null; + if (auto tsa = t.isTypeSArray()) + { + buf.writeByte('['); + tsa.dim.accept(this); + buf.writeByte(']'); + } + } + + override void visit(AST.Type t) + { + debug (Debug_DtoH) + { + printf("[AST.Type enter] %s\n", t.toChars()); + scope(exit) printf("[AST.Type exit] %s\n", t.toChars()); + } + printf("Invalid type: %s\n", t.toPrettyChars()); + assert(0); + } + + override void visit(AST.TypeIdentifier t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeIdentifier enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeIdentifier exit] %s\n", t.toChars()); + } + buf.writestring(t.ident.toChars()); + } + + override void visit(AST.TypeBasic t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeBasic enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeBasic exit] %s\n", t.toChars()); + } + if (!cdparent && t.isConst()) + buf.writestring("const "); + switch (t.ty) + { + case AST.Tbool, AST.Tvoid: + case AST.Tchar, AST.Twchar, AST.Tdchar: + case AST.Tint8, AST.Tuns8: + case AST.Tint16, AST.Tuns16: + case AST.Tint32, AST.Tuns32: + case AST.Tint64, AST.Tuns64: + case AST.Tfloat32, AST.Tfloat64, AST.Tfloat80: + buf.writestring("_d_"); + buf.writestring(t.dstring); + break; + default: + //t.print(); + assert(0); + } + } + + override void visit(AST.TypePointer t) + { + debug (Debug_DtoH) + { + printf("[AST.TypePointer enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypePointer exit] %s\n", t.toChars()); + } + auto ts = t.next.isTypeStruct(); + if (ts && !strcmp(ts.sym.ident.toChars(), "__va_list_tag")) + { + buf.writestring("va_list"); + return; + } + t.next.accept(this); + if (t.next.ty != AST.Tfunction) + buf.writeByte('*'); + if (!cdparent && t.isConst()) + buf.writestring(" const"); + } + + override void visit(AST.TypeSArray t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeSArray enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeSArray exit] %s\n", t.toChars()); + } + t.next.accept(this); + } + + override void visit(AST.TypeAArray t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeAArray enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeAArray exit] %s\n", t.toChars()); + } + AST.Type.tvoidptr.accept(this); + } + + override void visit(AST.TypeFunction tf) + { + debug (Debug_DtoH) + { + printf("[AST.TypeFunction enter] %s\n", tf.toChars()); + scope(exit) printf("[AST.TypeFunction exit] %s\n", tf.toChars()); + } + tf.next.accept(this); + buf.writeByte('('); + buf.writeByte('*'); + if (ident) + buf.writestring(ident.toChars()); + ident = null; + buf.writeByte(')'); + buf.writeByte('('); + foreach (i; 0 .. AST.Parameter.dim(tf.parameterList.parameters)) + { + if (i) + buf.writestring(", "); + auto fparam = AST.Parameter.getNth(tf.parameterList.parameters, i); + fparam.accept(this); + } + if (tf.parameterList.varargs) + { + if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1) + buf.writestring(", "); + buf.writestring("..."); + } + buf.writeByte(')'); + } + + private void enumToBuffer(AST.EnumDeclaration ed) + { + debug (Debug_DtoH) + { + printf("[enumToBuffer(AST.EnumDeclaration) enter] %s\n", ed.toChars()); + scope(exit) printf("[enumToBuffer(AST.EnumDeclaration) exit] %s\n", ed.toChars()); + } + if (ed.isSpecial()) + { + buf.writestring(ed.toChars()); + return; + } + + if (ed.ident == DMDType.c_long) + buf.writestring("long"); + else if (ed.ident == DMDType.c_ulong) + buf.writestring("unsigned long"); + else if (ed.ident == DMDType.c_longlong) + buf.writestring("long long"); + else if (ed.ident == DMDType.c_ulonglong) + buf.writestring("unsigned long long"); + else if (ed.ident == DMDType.c_long_double) + buf.writestring("long double"); + else + { + //ed.print(); + assert(0); + } + } + + override void visit(AST.TypeEnum t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeEnum enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeEnum exit] %s\n", t.toChars()); + } + if (cast(void*)t.sym !in forwarded) + { + forwarded[cast(void*)t.sym] = true; + auto save = buf; + buf = fwdbuf; + //printf("Visiting enum %s from module %s %s\n", t.sym.toPrettyChars(), t.toChars(), t.sym.loc.toChars()); + t.sym.accept(this); + buf = save; + } + if (!cdparent && t.isConst()) + buf.writestring("const "); + enumToBuffer(t.sym); + } + + override void visit(AST.TypeStruct t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeStruct enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeStruct exit] %s\n", t.toChars()); + } + if (cast(void*)t.sym !in forwarded && !t.sym.parent.isTemplateInstance()) + { + forwarded[cast(void*)t.sym] = true; + fwdbuf.writestring(t.sym.isUnionDeclaration() ? "union " : "struct "); + fwdbuf.writestring(t.sym.toChars()); + fwdbuf.writestring(";\n"); + } + + if (!cdparent && t.isConst()) + buf.writestring("const "); + if (auto ti = t.sym.parent.isTemplateInstance()) + { + visitTi(ti); + return; + } + buf.writestring(t.sym.toChars()); + } + + override void visit(AST.TypeDArray t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeDArray enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeDArray exit] %s\n", t.toChars()); + } + if (!cdparent && t.isConst()) + buf.writestring("const "); + buf.writestring("DArray< "); + t.next.accept(this); + buf.writestring(" >"); + } + + private void visitTi(AST.TemplateInstance ti) + { + debug (Debug_DtoH) + { + printf("[visitTi(AST.TemplateInstance) enter] %s\n", ti.toChars()); + scope(exit) printf("[visitTi(AST.TemplateInstance) exit] %s\n", ti.toChars()); + } + + // FIXME: Restricting this to DMD seems wrong ... + if (isBuildingCompiler) + { + if (ti.tempdecl.ident == DMDType.AssocArray) + { + if (!forwardedAA) + { + forwardedAA = true; + fwdbuf.writestring("struct AA;\n"); + } + buf.writestring("AA*"); + return; + } + if (ti.tempdecl.ident == DMDType.Array) + { + buf.writestring("Array"); + } + else + goto LprintTypes; + } + else + { + LprintTypes: + foreach (o; *ti.tiargs) + { + if (!AST.isType(o)) + return; + } + buf.writestring(ti.tempdecl.ident.toChars()); + } + buf.writeByte('<'); + foreach (i, o; *ti.tiargs) + { + if (i) + buf.writestring(", "); + if (auto tt = AST.isType(o)) + { + tt.accept(this); + } + else + { + //ti.print(); + //o.print(); + assert(0); + } + } + buf.writeByte('>'); + } + + override void visit(AST.TemplateDeclaration td) + { + debug (Debug_DtoH) + { + printf("[AST.TemplateDeclaration enter] %s\n", td.toChars()); + scope(exit) printf("[AST.TemplateDeclaration exit] %s\n", td.toChars()); + } + if (cast(void*)td in visited) + return; + visited[cast(void*)td] = true; + + if (isBuildingCompiler && td.getModule() && td.getModule().isIgnoredModule()) + return; + + if (!td.parameters || !td.onemember || !td.onemember.isStructDeclaration()) + { + visit(cast(AST.Dsymbol)td); + return; + } + + // Explicitly disallow templates with non-type parameters or specialization. + foreach (p; *td.parameters) + { + if (!p.isTemplateTypeParameter() || p.specialization()) + { + visit(cast(AST.Dsymbol)td); + return; + } + } + + if (linkage != LINK.c && linkage != LINK.cpp) + { + buf.printf("// ignoring template %s because of linkage\n", td.toPrettyChars()); + return; + } + + auto sd = td.onemember.isStructDeclaration(); + auto save = tdparent; + tdparent = td; + indent(); + buf.writestring("template <"); + bool first = true; + foreach (p; *td.parameters) + { + if (first) + first = false; + else + buf.writestring(", "); + buf.writestring("typename "); + buf.writestring(p.ident.toChars()); + } + buf.writestring(">\n"); + buf.writestring(sd.isUnionDeclaration() ? "union " : "struct "); + buf.writestring(sd.ident.toChars()); + if (sd.members) + { + buf.writestring("\n{\n"); + auto savex = adparent; + adparent = sd; + foreach (m; *sd.members) + { + m.accept(this); + } + adparent = savex; + buf.writestring("};\n\n"); + } + else + { + buf.writestring(";\n\n"); + } + tdparent = save; + } + + override void visit(AST.TypeClass t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeClass enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeClass exit] %s\n", t.toChars()); + } + if (cast(void*)t.sym !in forwarded) + { + forwarded[cast(void*)t.sym] = true; + fwdbuf.writestring("class "); + fwdbuf.writestring(t.sym.toChars()); + fwdbuf.writestring(";\n"); + } + + if (!cdparent && t.isConst()) + buf.writestring("const "); + buf.writestring(t.sym.toChars()); + buf.writeByte('*'); + if (!cdparent && t.isConst()) + buf.writestring(" const"); + } + + private void funcToBuffer(AST.TypeFunction tf, AST.FuncDeclaration fd) + { + debug (Debug_DtoH) + { + printf("[funcToBuffer(AST.TypeFunction) enter] %s\n", tf.toChars()); + scope(exit) printf("[funcToBuffer(AST.TypeFunction) exit] %s\n", tf.toChars()); + } + + Identifier ident = fd.ident; + + assert(tf.next); + if (fd.isCtorDeclaration() || fd.isDtorDeclaration()) + { + if (fd.isDtorDeclaration()) + { + buf.writeByte('~'); + } + buf.writestring(adparent.toChars()); + } + else + { + tf.next.accept(this); + if (tf.isref) + buf.writeByte('&'); + buf.writeByte(' '); + buf.writestring(ident.toChars()); + } + + buf.writeByte('('); + foreach (i; 0 .. AST.Parameter.dim(tf.parameterList.parameters)) + { + if (i) + buf.writestring(", "); + auto fparam = AST.Parameter.getNth(tf.parameterList.parameters, i); + fparam.accept(this); + } + if (tf.parameterList.varargs) + { + if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1) + buf.writestring(", "); + buf.writestring("..."); + } + buf.writeByte(')'); + } + + override void visit(AST.Parameter p) + { + debug (Debug_DtoH) + { + printf("[AST.Parameter enter] %s\n", p.toChars()); + scope(exit) printf("[AST.Parameter exit] %s\n", p.toChars()); + } + ident = p.ident; + p.type.accept(this); + assert(!(p.storageClass & ~(AST.STC.ref_))); + if (p.storageClass & AST.STC.ref_) + buf.writeByte('&'); + buf.writeByte(' '); + if (ident) + buf.writestring(ident.toChars()); + ident = null; + version (all) + { + if (p.defaultArg && p.defaultArg.op >= TOK.int32Literal && p.defaultArg.op < TOK.struct_) + { + //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op); + buf.writestring(" = "); + buf.writestring(p.defaultArg.toChars()); + } + } + else + { + if (p.defaultArg) + { + //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op); + //return; + buf.writestring("/*"); + buf.writestring(" = "); + buf.writestring(p.defaultArg.toChars()); + //p.defaultArg.accept(this); + buf.writestring("*/"); + } + } + } + + override void visit(AST.Expression e) + { + debug (Debug_DtoH) + { + printf("[AST.Expression enter] %s\n", e.toChars()); + scope(exit) printf("[AST.Expression exit] %s\n", e.toChars()); + } + assert(0); + } + + override void visit(AST.NullExp e) + { + debug (Debug_DtoH) + { + printf("[AST.NullExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.NullExp exit] %s\n", e.toChars()); + } + buf.writestring("_d_null"); + } + + override void visit(AST.ArrayLiteralExp e) + { + debug (Debug_DtoH) + { + printf("[AST.ArrayLiteralExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.ArrayLiteralExp exit] %s\n", e.toChars()); + } + buf.writestring("arrayliteral"); + } + + override void visit(AST.StringExp e) + { + debug (Debug_DtoH) + { + printf("[AST.StringExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.StringExp exit] %s\n", e.toChars()); + } + assert(e.sz == 1 || e.sz == 2); + if (e.sz == 2) + buf.writeByte('L'); + buf.writeByte('"'); + + for (size_t i = 0; i < e.len; i++) + { + uint c = e.charAt(i); + switch (c) + { + case '"': + case '\\': + buf.writeByte('\\'); + goto default; + default: + if (c <= 0xFF) + { + if (c <= 0x7F && isprint(c)) + buf.writeByte(c); + else + buf.printf("\\x%02x", c); + } + else if (c <= 0xFFFF) + { + buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); + } + else + { + buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", + c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); + } + break; + } + } + buf.writeByte('"'); + } + + override void visit(AST.RealExp e) + { + debug (Debug_DtoH) + { + printf("[AST.RealExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.RealExp exit] %s\n", e.toChars()); + } + + // TODO: Needs to implemented, used e.g. for struct member initializers + buf.writestring("0"); + } + + override void visit(AST.IntegerExp e) + { + debug (Debug_DtoH) + { + printf("[AST.IntegerExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.IntegerExp exit] %s\n", e.toChars()); + } + visitInteger(e.toInteger, e.type); + } + + private void visitInteger(dinteger_t v, AST.Type t) + { + debug (Debug_DtoH) + { + printf("[visitInteger(AST.Type) enter] %s\n", t.toChars()); + scope(exit) printf("[visitInteger(AST.Type) exit] %s\n", t.toChars()); + } + switch (t.ty) + { + case AST.Tenum: + auto te = cast(AST.TypeEnum)t; + buf.writestring("("); + enumToBuffer(te.sym); + buf.writestring(")"); + visitInteger(v, te.sym.memtype); + break; + case AST.Tbool: + buf.writestring(v ? "true" : "false"); + break; + case AST.Tint8: + buf.printf("%d", cast(byte)v); + break; + case AST.Tuns8: + case AST.Tchar: + buf.printf("%uu", cast(ubyte)v); + break; + case AST.Tint16: + buf.printf("%d", cast(short)v); + break; + case AST.Tuns16: + buf.printf("%uu", cast(ushort)v); + break; + case AST.Tint32: + buf.printf("%d", cast(int)v); + break; + case AST.Tuns32: + buf.printf("%uu", cast(uint)v); + break; + case AST.Tint64: + buf.printf("%lldLL", v); + break; + case AST.Tuns64: + buf.printf("%lluLLU", v); + break; + default: + //t.print(); + assert(0); + } + } + + override void visit(AST.StructLiteralExp sle) + { + debug (Debug_DtoH) + { + printf("[AST.StructLiteralExp enter] %s\n", sle.toChars()); + scope(exit) printf("[AST.StructLiteralExp exit] %s\n", sle.toChars()); + } + buf.writestring(sle.sd.ident.toChars()); + buf.writeByte('('); + foreach(i, e; *sle.elements) + { + if (i) + buf.writestring(", "); + e.accept(this); + } + buf.writeByte(')'); + } +} diff --git a/dmd/dversion.d b/dmd/dversion.d index f8d367d209d..fd87386cf95 100644 --- a/dmd/dversion.d +++ b/dmd/dversion.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d, _dversion.d) diff --git a/dmd/entity.d b/dmd/entity.d index f8fdc149c3a..15ba6aef1f9 100644 --- a/dmd/entity.d +++ b/dmd/entity.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/entity.d, _entity.d) diff --git a/dmd/enum.h b/dmd/enum.h index d0ae0981399..5d49a5e98fd 100644 --- a/dmd/enum.h +++ b/dmd/enum.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/errors.d b/dmd/errors.d index 3cc08fb9955..15a1cffb17d 100644 --- a/dmd/errors.d +++ b/dmd/errors.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d) @@ -19,220 +19,11 @@ import core.stdc.string; import dmd.globals; import dmd.root.outbuffer; import dmd.root.rmem; +import dmd.root.string; import dmd.console; -import dmd.utils; nothrow: -/// Interface for diagnostic reporting. -abstract class DiagnosticReporter -{ - nothrow: - - /// Returns: the number of errors that occurred during lexing or parsing. - abstract int errorCount(); - - /// Returns: the number of warnings that occurred during lexing or parsing. - abstract int warningCount(); - - /// Returns: the number of deprecations that occurred during lexing or parsing. - abstract int deprecationCount(); - - /** - Reports an error message. - - Params: - loc = Location of error - format = format string for error - ... = format string arguments - */ - final void error(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - error(loc, format, args); - va_end(args); - } - - /// ditto - abstract void error(const ref Loc loc, const(char)* format, va_list args); - - /** - Reports additional details about an error message. - - Params: - loc = Location of error - format = format string for supplemental message - ... = format string arguments - */ - final void errorSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - errorSupplemental(loc, format, args); - va_end(args); - } - - /// ditto - abstract void errorSupplemental(const ref Loc loc, const(char)* format, va_list); - - /** - Reports a warning message. - - Params: - loc = Location of warning - format = format string for warning - ... = format string arguments - */ - final void warning(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - warning(loc, format, args); - va_end(args); - } - - /// ditto - abstract void warning(const ref Loc loc, const(char)* format, va_list args); - - /** - Reports additional details about a warning message. - - Params: - loc = Location of warning - format = format string for supplemental message - ... = format string arguments - */ - final void warningSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - warningSupplemental(loc, format, args); - va_end(args); - } - - /// ditto - abstract void warningSupplemental(const ref Loc loc, const(char)* format, va_list); - - /** - Reports a deprecation message. - - Params: - loc = Location of the deprecation - format = format string for the deprecation - ... = format string arguments - */ - final void deprecation(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - deprecation(loc, format, args); - va_end(args); - } - - /// ditto - abstract void deprecation(const ref Loc loc, const(char)* format, va_list args); - - /** - Reports additional details about a deprecation message. - - Params: - loc = Location of deprecation - format = format string for supplemental message - ... = format string arguments - */ - final void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - deprecationSupplemental(loc, format, args); - va_end(args); - } - - /// ditto - abstract void deprecationSupplemental(const ref Loc loc, const(char)* format, va_list); -} - -/** -Diagnostic reporter which prints the diagnostic messages to stderr. - -This is usually the default diagnostic reporter. -*/ -final class StderrDiagnosticReporter : DiagnosticReporter -{ - private const DiagnosticReporting useDeprecated; - - private int errorCount_; - private int warningCount_; - private int deprecationCount_; - - nothrow: - - /** - Initializes this object. - - Params: - useDeprecated = indicates how deprecation diagnostics should be - handled - */ - this(DiagnosticReporting useDeprecated) - { - this.useDeprecated = useDeprecated; - } - - override int errorCount() - { - return errorCount_; - } - - override int warningCount() - { - return warningCount_; - } - - override int deprecationCount() - { - return deprecationCount_; - } - - override void error(const ref Loc loc, const(char)* format, va_list args) - { - verror(loc, format, args); - errorCount_++; - } - - override void errorSupplemental(const ref Loc loc, const(char)* format, va_list args) - { - verrorSupplemental(loc, format, args); - } - - override void warning(const ref Loc loc, const(char)* format, va_list args) - { - vwarning(loc, format, args); - warningCount_++; - } - - override void warningSupplemental(const ref Loc loc, const(char)* format, va_list args) - { - vwarningSupplemental(loc, format, args); - } - - override void deprecation(const ref Loc loc, const(char)* format, va_list args) - { - vdeprecation(loc, format, args); - - if (useDeprecated == DiagnosticReporting.error) - errorCount_++; - else - deprecationCount_++; - } - - override void deprecationSupplemental(const ref Loc loc, const(char)* format, va_list args) - { - vdeprecationSupplemental(loc, format, args); - } -} - /** * Color highlighting to classify messages */ @@ -402,6 +193,20 @@ extern (C++) void message(const(char)* format, ...) va_end(ap); } +/** + * The type of the diagnostic handler + * see verrorPrint for arguments + * Returns: true if error handling is done, false to continue printing to stderr + */ +alias DiagnosticHandler = bool delegate(const ref Loc location, Color headerColor, const(char)* header, const(char)* messageFormat, va_list args, const(char)* prefix1, const(char)* prefix2); + +/** + * The diagnostic handler. + * If non-null it will be called for every diagnostic message issued by the compiler. + * If it returns false, the message will be printed to stderr as usual. + */ +__gshared DiagnosticHandler diagnosticHandler; + /** * Print a tip message with the prefix and highlighting. * Params: @@ -431,6 +236,11 @@ extern (C++) void tip(const(char)* format, ...) private void verrorPrint(const ref Loc loc, Color headerColor, const(char)* header, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null) { + if (diagnosticHandler && diagnosticHandler(loc, headerColor, header, format, ap, p1, p2)) + return; + + if (global.params.showGaggedErrors && global.gag) + fprintf(stderr, "(spec:%d) ", global.gag); Console* con = cast(Console*)global.console; const p = loc.toChars(); if (con) @@ -516,10 +326,7 @@ extern (C++) void verror(const ref Loc loc, const(char)* format, va_list ap, con else { if (global.params.showGaggedErrors) - { - fprintf(stderr, "(spec:%d) ", global.gag); verrorPrint(loc, Classification.gagged, header, format, ap, p1, p2); - } global.gaggedErrors++; } } @@ -765,8 +572,7 @@ private void colorHighlightCode(ref OutBuffer buf) ++nested; auto gaggedErrorsSave = global.startGagging(); - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, diagnosticReporter); + scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1); OutBuffer res; const(char)* lastp = cast(char*)buf[].ptr; //printf("colorHighlightCode('%.*s')\n", cast(int)(buf.length - 1), buf.data); diff --git a/dmd/errors.h b/dmd/errors.h index 8071aa0139c..a6c09365fec 100644 --- a/dmd/errors.h +++ b/dmd/errors.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/escape.d b/dmd/escape.d index ae8427375a7..b4767b0ecea 100644 --- a/dmd/escape.d +++ b/dmd/escape.d @@ -4,7 +4,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/escape.d, _escape.d) @@ -1420,8 +1420,9 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v) * Params: * e = expression to be returned by value * er = where to place collected data + * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`. */ -private void escapeByValue(Expression e, EscapeByResults* er) +void escapeByValue(Expression e, EscapeByResults* er, bool live = false) { //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars()); extern (C++) final class EscapeVisitor : Visitor @@ -1429,10 +1430,12 @@ private void escapeByValue(Expression e, EscapeByResults* er) alias visit = Visitor.visit; public: EscapeByResults* er; + bool live; - extern (D) this(EscapeByResults* er) + extern (D) this(EscapeByResults* er, bool live) { this.er = er; + this.live = live; } override void visit(Expression e) @@ -1446,7 +1449,7 @@ private void escapeByValue(Expression e, EscapeByResults* er) * but it'll be placed in static data so no need to check it. */ if (e.e1.op != TOK.structLiteral) - escapeByRef(e.e1, er); + escapeByRef(e.e1, er, live); } override void visit(SymOffExp e) @@ -1469,20 +1472,29 @@ private void escapeByValue(Expression e, EscapeByResults* er) er.byvalue.push(e.var); } + override void visit(PtrExp e) + { + if (live && e.type.hasPointers()) + e.e1.accept(this); + } + override void visit(DotVarExp e) { auto t = e.e1.type.toBasetype(); - if (t.ty == Tstruct) + if (!live && t.ty == Tstruct || + live && e.type.hasPointers()) + { e.e1.accept(this); + } } override void visit(DelegateExp e) { Type t = e.e1.type.toBasetype(); if (t.ty == Tclass || t.ty == Tpointer) - escapeByValue(e.e1, er); + escapeByValue(e.e1, er, live); else - escapeByRef(e.e1, er); + escapeByRef(e.e1, er, live); er.byfunc.push(e.func); } @@ -1542,7 +1554,7 @@ private void escapeByValue(Expression e, EscapeByResults* er) Type tb = e.type.toBasetype(); if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray) { - escapeByRef(e.e1, er); + escapeByRef(e.e1, er, live); } else e.e1.accept(this); @@ -1570,7 +1582,7 @@ private void escapeByValue(Expression e, EscapeByResults* er) { Type tb = e.type.toBasetype(); if (tb.ty != Tsarray) - escapeByRef(e.e1, er); + escapeByRef(e.e1, er, live); } else e.e1.accept(this); @@ -1578,7 +1590,8 @@ private void escapeByValue(Expression e, EscapeByResults* er) override void visit(IndexExp e) { - if (e.e1.type.toBasetype().ty == Tsarray) + if (e.e1.type.toBasetype().ty == Tsarray || + live && e.type.hasPointers()) { e.e1.accept(this); } @@ -1662,7 +1675,7 @@ private void escapeByValue(Expression e, EscapeByResults* er) arg.accept(this); } else - escapeByRef(arg, er); + escapeByRef(arg, er, live); } } } @@ -1689,7 +1702,7 @@ private void escapeByValue(Expression e, EscapeByResults* er) dve.e1.accept(this); } else - escapeByRef(dve.e1, er); + escapeByRef(dve.e1, er, live); } } else if (dve.var.storage_class & STC.return_ || tf.isreturn) @@ -1697,7 +1710,7 @@ private void escapeByValue(Expression e, EscapeByResults* er) if (dve.var.storage_class & STC.scope_) dve.e1.accept(this); else if (dve.var.storage_class & STC.ref_) - escapeByRef(dve.e1, er); + escapeByRef(dve.e1, er, live); } // If it's also a nested function that is 'return scope' if (fd && fd.isNested()) @@ -1731,7 +1744,7 @@ private void escapeByValue(Expression e, EscapeByResults* er) } } - scope EscapeVisitor v = new EscapeVisitor(er); + scope EscapeVisitor v = new EscapeVisitor(er, live); e.accept(v); } @@ -1752,8 +1765,9 @@ private void escapeByValue(Expression e, EscapeByResults* er) * Params: * e = expression to be returned by 'ref' * er = where to place collected data + * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`. */ -private void escapeByRef(Expression e, EscapeByResults* er) +void escapeByRef(Expression e, EscapeByResults* er, bool live = false) { //printf("[%s] escapeByRef, e: %s\n", e.loc.toChars(), e.toChars()); extern (C++) final class EscapeRefVisitor : Visitor @@ -1761,10 +1775,12 @@ private void escapeByRef(Expression e, EscapeByResults* er) alias visit = Visitor.visit; public: EscapeByResults* er; + bool live; - extern (D) this(EscapeByResults* er) + extern (D) this(EscapeByResults* er, bool live) { this.er = er; + this.live = live; } override void visit(Expression e) @@ -1797,14 +1813,14 @@ private void escapeByRef(Expression e, EscapeByResults* er) override void visit(ThisExp e) { if (e.var && e.var.toParent2().isFuncDeclaration().isThis2) - escapeByValue(e, er); + escapeByValue(e, er, live); else if (e.var) er.byref.push(e.var); } override void visit(PtrExp e) { - escapeByValue(e.e1, er); + escapeByValue(e.e1, er, live); } override void visit(IndexExp e) @@ -1828,7 +1844,7 @@ private void escapeByRef(Expression e, EscapeByResults* er) } else if (tb.ty == Tarray) { - escapeByValue(e.e1, er); + escapeByValue(e.e1, er, live); } } @@ -1849,7 +1865,7 @@ private void escapeByRef(Expression e, EscapeByResults* er) { Type t1b = e.e1.type.toBasetype(); if (t1b.ty == Tclass) - escapeByValue(e.e1, er); + escapeByValue(e.e1, er, live); else e.e1.accept(this); } @@ -1915,7 +1931,7 @@ private void escapeByRef(Expression e, EscapeByResults* er) er.byexp.push(de); } else - escapeByValue(arg, er); + escapeByValue(arg, er, live); } } } @@ -1935,7 +1951,7 @@ private void escapeByRef(Expression e, EscapeByResults* er) if (dve.var.storage_class & STC.return_ || tf.isreturn) { if (dve.var.storage_class & STC.scope_ || tf.isscope) - escapeByValue(dve.e1, er); + escapeByValue(dve.e1, er, live); else if (dve.var.storage_class & STC.ref_ || tf.isref) dve.e1.accept(this); } @@ -1950,7 +1966,7 @@ private void escapeByRef(Expression e, EscapeByResults* er) // If it's a delegate, check it too if (e.e1.op == TOK.variable && t1.ty == Tdelegate) { - escapeByValue(e.e1, er); + escapeByValue(e.e1, er, live); } /* If it's a nested function that is 'return ref' @@ -1971,7 +1987,7 @@ private void escapeByRef(Expression e, EscapeByResults* er) } } - scope EscapeRefVisitor v = new EscapeRefVisitor(er); + scope EscapeRefVisitor v = new EscapeRefVisitor(er, live); e.accept(v); } @@ -1979,7 +1995,7 @@ private void escapeByRef(Expression e, EscapeByResults* er) /************************************ * Aggregate the data collected by the escapeBy??() functions. */ -private struct EscapeByResults +struct EscapeByResults { VarDeclarations byref; // array into which variables being returned by ref are inserted VarDeclarations byvalue; // array into which variables with values containing pointers are inserted diff --git a/dmd/expression.d b/dmd/expression.d index 15f45376511..9d7958d9b1c 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d) @@ -59,13 +59,13 @@ import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.rootobject; +import dmd.root.string; import dmd.safe; import dmd.sideeffect; import dmd.target; import dmd.tokens; import dmd.typesem; import dmd.utf; -import dmd.utils; import dmd.visitor; version (IN_LLVM) import gen.dpragma; @@ -1243,12 +1243,12 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode return false; if (sc.intypeof == 1) return false; - if (sc.flags & SCOPE.ctfe) + if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) return false; if (!f.isSafe() && !f.isTrusted()) { - if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe()) { if (!loc.isValid()) // e.g. implicitly generated dtor loc = sc.func.loc; @@ -1278,12 +1278,12 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode return false; if (sc.intypeof == 1) return false; - if (sc.flags & SCOPE.ctfe) + if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) return false; if (!f.isNogc()) { - if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC() && !(sc.flags & SCOPE.debug_)) + if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC()) { if (loc.linnum == 0) // e.g. implicitly generated dtor loc = sc.func.loc; diff --git a/dmd/expression.h b/dmd/expression.h index af00fcf95d7..05a680175b8 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -1399,6 +1399,7 @@ struct UnionExp class ObjcClassReferenceExp : public Expression { +public: ClassDeclaration* classDeclaration; void accept(Visitor *v) { v->visit(this); } diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 2b17e597624..8843ad8d55e 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d) @@ -60,6 +60,7 @@ import dmd.root.file; import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rootobject; +import dmd.root.string; import dmd.semantic2; import dmd.semantic3; import dmd.sideeffect; @@ -176,7 +177,7 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) // https://issues.dlang.org/show_bug.cgi?id=12585 // Extract the side effect part if ue.e1 is comma. - if (!isTrivialExp(e1)) + if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect() { /* Even if opDollar is needed, 'e1' should be evaluate only once. So * Rewrite: @@ -1573,12 +1574,15 @@ private Expression rewriteOpAssign(BinExp exp) /**************************************** * Preprocess arguments to function. + * Input: + * reportErrors whether or not to report errors here. Some callers are not + * checking actual function params, so they'll do their own error reporting * Output: * exps[] tuples expanded, properties resolved, rewritten in place * Returns: * true a semantic error occurred */ -private bool preFunctionParameters(Scope* sc, Expressions* exps) +private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool reportErrors = true) { bool err = false; if (exps) @@ -1596,15 +1600,21 @@ private bool preFunctionParameters(Scope* sc, Expressions* exps) if (arg.op == TOK.type) { - arg.error("cannot pass type `%s` as a function argument", arg.toChars()); - arg = new ErrorExp(); + if (reportErrors) + { + arg.error("cannot pass type `%s` as a function argument", arg.toChars()); + arg = new ErrorExp(); + } err = true; } } else if (arg.type.toBasetype().ty == Tfunction) { - arg.error("cannot pass function `%s` as a function argument", arg.toChars()); - arg = new ErrorExp(); + if (reportErrors) + { + arg.error("cannot pass function `%s` as a function argument", arg.toChars()); + arg = new ErrorExp(); + } err = true; } else if (checkNonAssignmentArrayOp(arg)) @@ -2381,8 +2391,6 @@ Package resolveIsPackage(Dsymbol sym) } pkg = imp.pkg; } - else if (auto mod = sym.isModule()) - pkg = mod.isPackageFile ? mod.pkg : sym.isPackage(); else pkg = sym.isPackage(); if (pkg) @@ -3320,6 +3328,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + //for error messages if the argument in [] is not convertible to size_t + const originalNewtype = exp.newtype; + // https://issues.dlang.org/show_bug.cgi?id=11581 // With the syntax `new T[edim]` or `thisexp.new T[edim]`, // T should be analyzed first and edim should go into arguments iff it's @@ -3378,14 +3389,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.newtype = exp.type; // in case type gets cast to something else Type tb = exp.type.toBasetype(); //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); - if (arrayExpressionSemantic(exp.newargs, sc) || preFunctionParameters(sc, exp.newargs)) { return setError(); } - if (arrayExpressionSemantic(exp.arguments, sc) || - preFunctionParameters(sc, exp.arguments)) + if (arrayExpressionSemantic(exp.arguments, sc)) + { + return setError(); + } + //https://issues.dlang.org/show_bug.cgi?id=20547 + //exp.arguments are the "parameters" to [], not to a real function + //so the errors that come from preFunctionParameters are misleading + if (originalNewtype.ty == Tsarray) + { + if (preFunctionParameters(sc, exp.arguments, false)) + { + exp.error("cannot create a `%s` with `new`", originalNewtype.toChars()); + return setError(); + } + } + else if (preFunctionParameters(sc, exp.arguments)) { return setError(); } @@ -3396,7 +3420,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - size_t nargs = exp.arguments ? exp.arguments.dim : 0; + const size_t nargs = exp.arguments ? exp.arguments.dim : 0; Expression newprefix = null; if (tb.ty == Tclass) @@ -3749,7 +3773,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - exp.error("new can only create structs, dynamic arrays or class objects, not `%s`'s", exp.type.toChars()); + exp.error("cannot create a `%s` with `new`", exp.type.toChars()); return setError(); } @@ -4800,22 +4824,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.f.checkNestedReference(sc, exp.loc)) return setError(); } - else if (sc.func && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe)) + else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_))) { bool err = false; - if (!tf.purity && !(sc.flags & SCOPE.debug_) && sc.func.setImpure()) + if (!tf.purity && sc.func.setImpure()) { exp.error("`pure` %s `%s` cannot call impure %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } - if (!tf.isnogc && sc.func.setGC() && !(sc.flags & SCOPE.debug_) ) + if (!tf.isnogc && sc.func.setGC()) { exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } - if (tf.trust <= TRUST.system && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (tf.trust <= TRUST.system && sc.func.setUnsafe()) { exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); @@ -5672,17 +5696,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor uint errors = global.errors; const len = buf.length; const str = buf.extractChars()[0 .. len]; - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false, diagnosticReporter); + scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); Expression e = p.parseExpression(); - if (p.errors) - { - assert(global.errors != errors); // should have caught all these cases + if (global.errors != errors) return null; - } + if (p.token.value != TOK.endOfFile) { exp.error("incomplete mixin expression `%s`", str.ptr); @@ -5790,9 +5811,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // save expression as a string before any semantic expansion - // if -checkaction=context is enabled an no message exists - const generateMsg = !exp.msg && global.params.checkAction == CHECKACTION.context; - auto assertExpMsg = generateMsg ? exp.toChars() : null; + auto assertExpMsg = exp.msg ? null : exp.toChars(); if (Expression ex = unaSemantic(exp, sc)) { @@ -5804,7 +5823,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = exp.e1.optimize(WANTvalue); exp.e1 = exp.e1.toBoolean(sc); - if (generateMsg) + if (!exp.msg && global.params.checkAction == CHECKACTION.context) // no message - use assert expression as msg { /* @@ -5829,7 +5848,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (op.hasSideEffect) { - auto tmp = copyToTemp(0, "__assertOp", op); + const stc = STC.exptemp | (op.isLvalue() ? STC.ref_ : STC.rvalue); + auto tmp = copyToTemp(stc, "__assertOp", op); tmp.dsymbolSemantic(sc); auto decl = new DeclarationExp(op.loc, tmp); @@ -6362,10 +6382,25 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (callExp.e1.type.toBasetype().ty == Tdelegate) { - VarExp ve2 = callExp.e1.isVarExp(); - ve2.delegateWasExtracted = true; - ve2.var.storage_class |= STC.scope_; - result = ve2; + /* https://issues.dlang.org/show_bug.cgi?id=20551 + * + * Cannot take address of lazy parameter in @safe code + * because it might end up being a pointer to undefined + * memory. + */ + if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) + { + exp.error("cannot take address of lazy parameter `%s` in `@safe` function `%s`", + ve.toChars(), sc.func.toChars()); + setError(); + } + else + { + VarExp ve2 = callExp.e1.isVarExp(); + ve2.delegateWasExtracted = true; + ve2.var.storage_class |= STC.scope_; + result = ve2; + } return; } } @@ -6503,7 +6538,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (sc.func && !sc.intypeof) { - if (sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (!(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { exp.error("`this` reference necessary to take address of member `%s` in `@safe` function `%s`", f.toChars(), sc.func.toChars()); } @@ -6525,7 +6560,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (ce.e1.type.ty == Tfunction) { TypeFunction tf = cast(TypeFunction)ce.e1.type; - if (tf.isref && sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`", ce.e1.toChars(), sc.func.toChars()); @@ -6826,48 +6861,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (tb.ty == Tstruct) { ad = (cast(TypeStruct)tb).sym; - auto f = ad.aggDelete; - auto fd = ad.dtor; - if (!f) - { - semanticTypeInfo(sc, tb); - break; - } - - /* Construct: - * ea = copy e1 to a tmp to do side effects only once - * eb = call destructor - * ec = call deallocator - */ - Expression ea = null; - Expression eb = null; - Expression ec = null; - VarDeclaration v = null; - if (fd && f) - { - v = copyToTemp(0, "__tmpea", exp.e1); - v.dsymbolSemantic(sc); - ea = new DeclarationExp(exp.loc, v); - ea.type = v.type; - } - if (fd) - { - Expression e = ea ? new VarExp(exp.loc, v) : exp.e1; - e = new DotVarExp(Loc.initial, e, fd, false); - eb = new CallExp(exp.loc, e); - eb = eb.expressionSemantic(sc); - } - if (f) - { - Type tpv = Type.tvoid.pointerTo(); - Expression e = ea ? new VarExp(exp.loc, v) : exp.e1.castTo(sc, tpv); - e = new CallExp(exp.loc, new VarExp(exp.loc, f, false), e); - ec = e.expressionSemantic(sc); - } - ea = Expression.combine(ea, eb, ec); - assert(ea); - result = ea; - return; + semanticTypeInfo(sc, tb); } break; @@ -6896,19 +6890,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor err |= exp.checkSafety(sc, ad.dtor); err |= exp.checkNogc(sc, ad.dtor); } - if (ad.aggDelete && tb.ty != Tarray) - { - err |= exp.checkPurity(sc, ad.aggDelete); - err |= exp.checkSafety(sc, ad.aggDelete); - err |= exp.checkNogc(sc, ad.aggDelete); - } if (err) return setError(); } if (!sc.intypeof && sc.func && !exp.isRAII && - sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + !(sc.flags & SCOPE.debug_) && + sc.func.setUnsafe()) { exp.error("`%s` is not `@safe` but is used in `@safe` function `%s`", exp.toChars(), sc.func.toChars()); err = true; @@ -7061,9 +7050,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Check for unsafe casts if (!sc.intypeof && + !(sc.flags & SCOPE.debug_) && !isSafeCast(ex, t1b, tob) && - (!sc.func && sc.stc & STC.safe || sc.func && sc.func.setUnsafe()) && - !(sc.flags & SCOPE.debug_)) + (!sc.func && sc.stc & STC.safe || sc.func && sc.func.setUnsafe())) { exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars()); return setError(); @@ -7290,7 +7279,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.error("need upper and lower bound to slice pointer"); return setError(); } - if (sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { exp.error("pointer slicing not allowed in safe functions"); return setError(); @@ -7786,7 +7775,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.e2.op == TOK.int64 && exp.e2.toInteger() == 0) { } - else if (sc.func && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + else if (sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { exp.error("safe function `%s` cannot index pointer `%s`", sc.func.toPrettyChars(), exp.e1.toChars()); return setError(); @@ -9123,7 +9112,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) { - if (!sc.intypeof && sc.func && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { exp.error("cannot copy `void[]` to `void[]` in `@safe` code"); return setError(); @@ -11488,7 +11477,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag) if (s) { auto p = s.isPackage(); - if (p && checkAccess(exp.loc, sc, p)) + if (p && checkAccess(sc, p)) { s = null; } @@ -11977,13 +11966,14 @@ private bool checkAddressVar(Scope* sc, UnaExp exp, VarDeclaration v) // Taking the address of v means it cannot be set to 'scope' later v.storage_class &= ~STC.maybescope; v.doNotInferScope = true; - if (v.storage_class & STC.scope_ && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (exp.e1.type.hasPointers() && v.storage_class & STC.scope_ && + !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { exp.error("cannot take address of `scope` %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); return false; } } - else if (sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + else if (!(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); return false; diff --git a/dmd/filecache.d b/dmd/filecache.d index 86a7bea9433..3129cb6a885 100644 --- a/dmd/filecache.d +++ b/dmd/filecache.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/filecache.d, filecache.d) diff --git a/dmd/foreachvar.d b/dmd/foreachvar.d new file mode 100644 index 00000000000..f320ce04af2 --- /dev/null +++ b/dmd/foreachvar.d @@ -0,0 +1,323 @@ +/** + * Compiler implementation of the + * $(LINK2 http://www.dlang.org, D programming language). + * + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d, _foreachvar.d) + * Documentation: https://dlang.org/phobos/dmd_foreachvar.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/foreachvar.d + */ + +module dmd.foreachvar; + +import core.stdc.stdio; +import core.stdc.stdlib; +import core.stdc.string; + +import dmd.apply; +import dmd.arraytypes; +import dmd.attrib; +import dmd.dclass; +import dmd.declaration; +import dmd.dstruct; +import dmd.dsymbol; +import dmd.dsymbolsem; +import dmd.dtemplate; +import dmd.errors; +import dmd.expression; +import dmd.func; +import dmd.id; +import dmd.identifier; +import dmd.init; +import dmd.initsem; +import dmd.mtype; +import dmd.printast; +import dmd.root.array; +import dmd.root.rootobject; +import dmd.statement; +import dmd.tokens; +import dmd.visitor; + +/********************************************* + * Visit each Expression in e, and call dgVar() on each variable declared in it. + * Params: + * e = expression tree to visit + * dgVar = call when a variable is declared + */ +void foreachVar(Expression e, void delegate(VarDeclaration) dgVar) +{ + if (!e) + return; + + extern (C++) final class VarWalker : StoppableVisitor + { + alias visit = typeof(super).visit; + extern (D) void delegate(VarDeclaration) dgVar; + + extern (D) this(void delegate(VarDeclaration) dgVar) + { + this.dgVar = dgVar; + } + + override void visit(Expression e) + { + } + + override void visit(ErrorExp e) + { + } + + override void visit(DeclarationExp e) + { + VarDeclaration v = e.declaration.isVarDeclaration(); + if (!v) + return; + if (TupleDeclaration td = v.toAlias().isTupleDeclaration()) + { + if (!td.objects) + return; + foreach (o; *td.objects) + { + Expression ex = isExpression(o); + DsymbolExp s = ex ? ex.isDsymbolExp() : null; + assert(s); + VarDeclaration v2 = s.s.isVarDeclaration(); + assert(v2); + dgVar(v2); + } + } + else + dgVar(v); + Dsymbol s = v.toAlias(); + if (s == v && !v.isStatic() && v._init) + { + if (auto ie = v._init.isExpInitializer()) + ie.exp.foreachVar(dgVar); + } + } + + override void visit(IndexExp e) + { + if (e.lengthVar) + dgVar(e.lengthVar); + } + + override void visit(SliceExp e) + { + if (e.lengthVar) + dgVar(e.lengthVar); + } + } + + scope VarWalker v = new VarWalker(dgVar); + walkPostorder(e, v); +} + +/*************** + * Transitively walk Statement s, pass Expressions to dgExp(), VarDeclarations to dgVar(). + * Params: + * s = Statement to traverse + * dgExp = delegate to pass found Expressions to + * dgVar = delegate to pass found VarDeclarations to + */ +void foreachExpAndVar(Statement s, + void delegate(Expression) dgExp, + void delegate(VarDeclaration) dgVar) +{ + void visit(Statement s) + { + void visitExp(ExpStatement s) + { + if (s.exp) + dgExp(s.exp); + } + + void visitDtorExp(DtorExpStatement s) + { + if (s.exp) + dgExp(s.exp); + } + + void visitIf(IfStatement s) + { + dgExp(s.condition); + visit(s.ifbody); + visit(s.elsebody); + } + + void visitDo(DoStatement s) + { + dgExp(s.condition); + visit(s._body); + } + + void visitFor(ForStatement s) + { + visit(s._init); + if (s.condition) + dgExp(s.condition); + if (s.increment) + dgExp(s.increment); + visit(s._body); + } + + void visitSwitch(SwitchStatement s) + { + dgExp(s.condition); + // Note that the body contains the Case and Default + // statements, so we only need to compile the expressions + foreach (cs; *s.cases) + { + dgExp(cs.exp); + } + visit(s._body); + } + + void visitCase(CaseStatement s) + { + visit(s.statement); + } + + void visitReturn(ReturnStatement s) + { + if (s.exp) + dgExp(s.exp); + } + + void visitCompound(CompoundStatement s) + { + if (s.statements) + { + foreach (s2; *s.statements) + { + visit(s2); + } + } + } + + void visitCompoundDeclaration(CompoundDeclarationStatement s) + { + visitCompound(s); + } + + void visitUnrolledLoop(UnrolledLoopStatement s) + { + foreach (s2; *s.statements) + { + visit(s2); + } + } + + void visitScope(ScopeStatement s) + { + visit(s.statement); + } + + void visitDefault(DefaultStatement s) + { + visit(s.statement); + } + + void visitWith(WithStatement s) + { + // If it is with(Enum) {...}, just execute the body. + if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type) + { + } + else + { + dgVar(s.wthis); + dgExp(s.exp); + } + visit(s._body); + } + + void visitTryCatch(TryCatchStatement s) + { + visit(s._body); + foreach (ca; *s.catches) + { + if (ca.var) + dgVar(ca.var); + visit(ca.handler); + } + } + + void visitTryFinally(TryFinallyStatement s) + { + visit(s._body); + visit(s.finalbody); + } + + void visitThrow(ThrowStatement s) + { + dgExp(s.exp); + } + + void visitLabel(LabelStatement s) + { + visit(s.statement); + } + + if (!s) + return; + + final switch (s.stmt) + { + case STMT.Exp: visitExp(s.isExpStatement()); break; + case STMT.DtorExp: visitDtorExp(s.isDtorExpStatement()); break; + case STMT.Compound: visitCompound(s.isCompoundStatement()); break; + case STMT.CompoundDeclaration: visitCompoundDeclaration(s.isCompoundDeclarationStatement()); break; + case STMT.UnrolledLoop: visitUnrolledLoop(s.isUnrolledLoopStatement()); break; + case STMT.Scope: visitScope(s.isScopeStatement()); break; + case STMT.Do: visitDo(s.isDoStatement()); break; + case STMT.For: visitFor(s.isForStatement()); break; + case STMT.If: visitIf(s.isIfStatement()); break; + case STMT.Switch: visitSwitch(s.isSwitchStatement()); break; + case STMT.Case: visitCase(s.isCaseStatement()); break; + case STMT.Default: visitDefault(s.isDefaultStatement()); break; + case STMT.Return: visitReturn(s.isReturnStatement()); break; + case STMT.With: visitWith(s.isWithStatement()); break; + case STMT.TryCatch: visitTryCatch(s.isTryCatchStatement()); break; + case STMT.TryFinally: visitTryFinally(s.isTryFinallyStatement()); break; + case STMT.Throw: visitThrow(s.isThrowStatement()); break; + case STMT.Label: visitLabel(s.isLabelStatement()); break; + + case STMT.CompoundAsm: + case STMT.Asm: + case STMT.InlineAsm: + case STMT.GccAsm: + + case STMT.Break: + case STMT.Continue: + case STMT.GotoDefault: + case STMT.GotoCase: + case STMT.SwitchError: + case STMT.Goto: + case STMT.Pragma: + case STMT.Import: + case STMT.Error: + break; // ignore these + + case STMT.ScopeGuard: + case STMT.Foreach: + case STMT.ForeachRange: + case STMT.Debug: + case STMT.CaseRange: + case STMT.StaticForeach: + case STMT.StaticAssert: + case STMT.Conditional: + case STMT.While: + case STMT.Forwarding: + case STMT.Compile: + case STMT.Peel: + case STMT.Synchronized: + assert(0); // should have been rewritten + } + } + + visit(s); +} + diff --git a/dmd/func.d b/dmd/func.d index 8f7b2feb7ba..a3096fa1250 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d) @@ -40,13 +40,13 @@ import dmd.mtype; import dmd.objc; import dmd.root.outbuffer; import dmd.root.rootobject; +import dmd.root.string; import dmd.semantic2; import dmd.semantic3; import dmd.statement_rewrite_walker; import dmd.statement; import dmd.statementsem; import dmd.tokens; -import dmd.utils; import dmd.visitor; /// Inline Status @@ -2516,6 +2516,55 @@ version (IN_LLVM) error("parameters must be `main()` or `main(string[] args)`"); } + /*********************************************** + * Check all return statements for a function to verify that returning + * using NRVO is possible. + * + * Returns: + * true if the result cannot be returned by hidden reference. + */ + final bool checkNrvo() + { + if (!nrvo_can) + return true; + + if (returns is null) + return true; + + auto tf = type.toTypeFunction(); + + foreach (rs; *returns) + { + if (rs.exp.op == TOK.variable) + { + auto ve = cast(VarExp)rs.exp; + auto v = ve.var.isVarDeclaration(); + if (tf.isref) + { + // Function returns a reference + return true; + } + else if (!v || v.isOut() || v.isRef()) + return true; + else if (nrvo_var is null) + { + if (!v.isDataseg() && !v.isParameter() && v.toParent2() == this) + { + //printf("Setting nrvo to %s\n", v.toChars()); + nrvo_var = v; + } + else + return true; + } + else if (nrvo_var != v) + return true; + } + else //if (!exp.isLvalue()) // keep NRVO-ability + return true; + } + return false; + } + override final inout(FuncDeclaration) isFuncDeclaration() inout { return this; @@ -3325,6 +3374,9 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration this.ident = id ? id : Id.empty; this.tok = tok; this.fes = fes; + // Always infer scope for function literals + // See https://issues.dlang.org/show_bug.cgi?id=20362 + this.flags |= FUNCFLAG.inferScope; //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars()); } @@ -3927,58 +3979,3 @@ extern (C++) final class NewDeclaration : FuncDeclaration v.visit(this); } } - -/*********************************************************** - */ -extern (C++) final class DeleteDeclaration : FuncDeclaration -{ - Parameters* parameters; - - extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Parameters* fparams) - { - super(loc, endloc, Id.classDelete, STC.static_ | stc, null); - this.parameters = fparams; - } - - override Dsymbol syntaxCopy(Dsymbol s) - { - assert(!s); - auto f = new DeleteDeclaration(loc, endloc, storage_class, Parameter.arraySyntaxCopy(parameters)); - return FuncDeclaration.syntaxCopy(f); - } - - override const(char)* kind() const - { - return "deallocator"; - } - - override bool isDelete() - { - return true; - } - - override bool isVirtual() const - { - return false; - } - - override bool addPreInvariant() - { - return false; - } - - override bool addPostInvariant() - { - return false; - } - - override inout(DeleteDeclaration) isDeleteDeclaration() inout - { - return this; - } - - override void accept(Visitor v) - { - v.visit(this); - } -} diff --git a/dmd/globals.d b/dmd/globals.d index e16ea7ae840..c113cc1f9e9 100644 --- a/dmd/globals.d +++ b/dmd/globals.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/globals.d, _globals.d) @@ -56,6 +56,12 @@ enum DiagnosticReporting : ubyte off, // disable diagnostic } +enum MessageStyle : ubyte +{ + digitalmars, // filename.d(line): message + gnu, // filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html +} + enum CHECKENABLE : ubyte { _default, // initial value @@ -239,8 +245,8 @@ extern (C++) struct Param const(char)[] libname; // .lib file output name bool doDocComments; // process embedded documentation comments - const(char)* docdir; // write documentation file to docdir directory - const(char)* docname; // write documentation file to docname + const(char)[] docdir; // write documentation file to docdir directory + const(char)[] docname; // write documentation file to docname Array!(const(char)*) ddocfiles; // macro include files for Ddoc bool doHdrGeneration; // process embedded documentation comments @@ -248,6 +254,10 @@ extern (C++) struct Param const(char)[] hdrname; // write 'header' file to docname bool hdrStripPlainFunctions = true; // strip the bodies of plain (non-template) functions + bool doCxxHdrGeneration; // write 'Cxx header' file + const(char)[] cxxhdrdir; // write 'header' file to docdir directory + const(char)[] cxxhdrname; // write 'header' file to docname + bool doJsonGeneration; // write JSON file const(char)[] jsonfilename; // write JSON file to jsonfilename JsonFieldFlags jsonFieldFlags; // JSON field flags to include @@ -268,6 +278,7 @@ extern (C++) struct Param const(char)[] moduleDepsFile; // filename for deps output OutBuffer* moduleDeps; // contents to be written to deps file + MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages // Hidden debug switches bool debugb; @@ -348,11 +359,12 @@ version (IN_LLVM) string doc_ext = "html"; // for Ddoc generated files string ddoc_ext = "ddoc"; // for Ddoc macro include files string hdr_ext = "di"; // for D 'header' import files + string cxxhdr_ext = "h"; // for C/C++ 'header' files string json_ext = "json"; // for JSON files string map_ext = "map"; // for .map files bool run_noext; // allow -run sources without extensions. - string copyright = "Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved"; + string copyright = "Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved"; string written = "written by Walter Bright"; Array!(const(char)*)* path; // Array of char*'s which form the import lookup path @@ -605,7 +617,9 @@ nothrow: this.filename = filename; } - extern (C++) const(char)* toChars(bool showColumns = global.params.showColumns) const pure nothrow + extern (C++) const(char)* toChars( + bool showColumns = global.params.showColumns, + ubyte messageStyle = global.params.messageStyle) const pure nothrow { OutBuffer buf; if (filename) @@ -614,14 +628,28 @@ nothrow: } if (linnum) { - buf.writeByte('('); - buf.print(linnum); - if (showColumns && charnum) + final switch (messageStyle) { - buf.writeByte(','); - buf.print(charnum); + case MessageStyle.digitalmars: + buf.writeByte('('); + buf.print(linnum); + if (showColumns && charnum) + { + buf.writeByte(','); + buf.print(charnum); + } + buf.writeByte(')'); + break; + case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html + buf.writeByte(':'); + buf.print(linnum); + if (showColumns && charnum) + { + buf.writeByte(':'); + buf.print(charnum); + } + break; } - buf.writeByte(')'); } return buf.extractChars(); } @@ -657,7 +685,7 @@ nothrow: extern (D) size_t toHash() const @trusted pure nothrow { - import dmd.utils : toDString; + import dmd.root.string : toDString; auto hash = hashOf(linnum); hash = hashOf(charnum, hash); diff --git a/dmd/globals.h b/dmd/globals.h index 0d5ca7754ab..510dd81eb70 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -38,6 +38,13 @@ enum DIAGNOSTICoff // disable diagnostic }; +typedef unsigned char MessageStyle; +enum +{ + MESSAGESTYLEdigitalmars, // file(line,column): message + MESSAGESTYLEgnu // file:line:column: message +}; + // The state of array bounds checking typedef unsigned char CHECKENABLE; enum @@ -200,8 +207,8 @@ struct Param DString libname; // .lib file output name bool doDocComments; // process embedded documentation comments - const char *docdir; // write documentation file to docdir directory - const char *docname; // write documentation file to docname + DString docdir; // write documentation file to docdir directory + DString docname; // write documentation file to docname Array ddocfiles; // macro include files for Ddoc bool doHdrGeneration; // process embedded documentation comments @@ -209,6 +216,10 @@ struct Param DString hdrname; // write 'header' file to docname bool hdrStripPlainFunctions; // strip the bodies of plain (non-template) functions + bool doCxxHdrGeneration; // write 'Cxx header' file + DString cxxhdrdir; // write 'header' file to docdir directory + DString cxxhdrname; // write 'header' file to docname + bool doJsonGeneration; // write JSON file DString jsonfilename; // write JSON file to jsonfilename unsigned jsonFieldFlags; // JSON field flags to include @@ -229,6 +240,7 @@ struct Param DString moduleDepsFile; // filename for deps output OutBuffer *moduleDeps; // contents to be written to deps file + MessageStyle messageStyle; // style of file/line annotations on messages // Hidden debug switches bool debugb; @@ -305,6 +317,7 @@ struct Global const DString doc_ext; // for Ddoc generated files const DString ddoc_ext; // for Ddoc macro include files const DString hdr_ext; // for D 'header' import files + const DString cxxhdr_ext; // for C/C++ 'header' files const DString json_ext; // for JSON files const DString map_ext; // for .map files bool run_noext; // allow -run sources without extensions. @@ -408,7 +421,9 @@ struct Loc this->filename = filename; } - const char *toChars(bool showColumns = global.params.showColumns) const; + const char *toChars( + bool showColumns = global.params.showColumns, + MessageStyle messageStyle = global.params.messageStyle) const; bool equals(const Loc& loc) const; }; diff --git a/dmd/gluelayer.d b/dmd/gluelayer.d index fee2c75b029..dfd50c48d47 100644 --- a/dmd/gluelayer.d +++ b/dmd/gluelayer.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d, _gluelayer.d) diff --git a/dmd/hdrgen.d b/dmd/hdrgen.d index 7a6b13f2516..03bbb0805e2 100644 --- a/dmd/hdrgen.d +++ b/dmd/hdrgen.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d, _hdrgen.d) @@ -44,6 +44,7 @@ import dmd.parse; import dmd.root.ctfloat; import dmd.root.outbuffer; import dmd.root.rootobject; +import dmd.root.string; import dmd.statement; import dmd.staticassert; import dmd.target; @@ -383,6 +384,11 @@ public: } } + override void visit(ForwardingStatement s) + { + s.statement.accept(this); + } + override void visit(IfStatement s) { buf.writestring("if ("); @@ -1738,15 +1744,6 @@ public: bodyToBuffer(d); } - override void visit(DeleteDeclaration d) - { - if (stcToBuffer(buf, d.storage_class & ~STC.static_)) - buf.writeByte(' '); - buf.writestring("delete"); - parametersToBuffer(ParameterList(d.parameters, VarArg.none), buf, hgs); - bodyToBuffer(d); - } - override void visit(Module m) { moduleToBuffer2(m, buf, hgs); diff --git a/dmd/hdrgen.h b/dmd/hdrgen.h index a51c30c6c8a..2478a656368 100644 --- a/dmd/hdrgen.h +++ b/dmd/hdrgen.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Dave Fladebo * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/id.d b/dmd/id.d index f62cc694f64..57fd1ec1f82 100644 --- a/dmd/id.d +++ b/dmd/id.d @@ -5,7 +5,7 @@ * This module contains the `Id` struct with a list of predefined symbols the * compiler knows about. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/id.d, _id.d) @@ -203,6 +203,7 @@ immutable Msgtable[] msgtable = { "future", "__future" }, { "property" }, { "nogc" }, + { "live" }, { "safe" }, { "trusted" }, { "system" }, @@ -359,6 +360,7 @@ immutable Msgtable[] msgtable = { "etc" }, { "attribute" }, { "math" }, + { "trig" }, { "sin" }, { "cos" }, { "tan" }, diff --git a/dmd/id.h b/dmd/id.h index b2a50898a3b..186d303881c 100644 --- a/dmd/id.h +++ b/dmd/id.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2017-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2017-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/identifier.d b/dmd/identifier.d index a4e81b0f760..e8557b6ee41 100644 --- a/dmd/identifier.d +++ b/dmd/identifier.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d, _identifier.d) @@ -19,10 +19,10 @@ import dmd.globals; import dmd.id; import dmd.root.outbuffer; import dmd.root.rootobject; +import dmd.root.string; import dmd.root.stringtable; import dmd.tokens; import dmd.utf; -import dmd.utils; /*********************************************************** diff --git a/dmd/identifier.h b/dmd/identifier.h index 30787d5fee7..f1f5683c326 100644 --- a/dmd/identifier.h +++ b/dmd/identifier.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/impcnvtab.d b/dmd/impcnvtab.d index 67b166b4e65..e6c44c985db 100644 --- a/dmd/impcnvtab.d +++ b/dmd/impcnvtab.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d, _impcnvtab.d) diff --git a/dmd/imphint.d b/dmd/imphint.d index feb04c028a0..9636476f0f3 100644 --- a/dmd/imphint.d +++ b/dmd/imphint.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d, _imphint.d) @@ -12,8 +12,6 @@ module dmd.imphint; -import dmd.utils; - /****************************************** * Looks for undefined identifier s to see * if it might be undefined because an import diff --git a/dmd/import.h b/dmd/import.h index cc5472fcbe9..27923d4d695 100644 --- a/dmd/import.h +++ b/dmd/import.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/init.d b/dmd/init.d index e2e69089917..6912063847b 100644 --- a/dmd/init.d +++ b/dmd/init.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d) diff --git a/dmd/init.h b/dmd/init.h index a6f1d620c8c..f139a1c682a 100644 --- a/dmd/init.h +++ b/dmd/init.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/initsem.d b/dmd/initsem.d index 728932377c7..2548e5d6133 100644 --- a/dmd/initsem.d +++ b/dmd/initsem.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d, _initsem.d) diff --git a/dmd/inline.d b/dmd/inline.d index 6b42bfa0a0f..f8c88b83185 100644 --- a/dmd/inline.d +++ b/dmd/inline.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inline.d, _inline.d) @@ -83,9 +83,8 @@ public Expression inlineCopy(Expression e, Scope* sc) * for explanation of why just a copy() is broken */ //return e.copy(); - if (e.op == TOK.delegate_) + if (auto de = e.isDelegateExp()) { - DelegateExp de = cast(DelegateExp)e; if (de.func.isNested()) { /* https://issues.dlang.org/show_bug.cgi?id=4820 @@ -439,8 +438,8 @@ public: { if (e.var != ids.from[i]) continue; - auto se = cast(SymOffExp)e.copy(); - se.var = cast(Declaration)ids.to[i]; + auto se = e.copy().isSymOffExp(); + se.var = ids.to[i].isDeclaration(); result = se; return; } @@ -454,8 +453,8 @@ public: { if (e.var != ids.from[i]) continue; - auto ve = cast(VarExp)e.copy(); - ve.var = cast(Declaration)ids.to[i]; + auto ve = e.copy().isVarExp(); + ve.var = ids.to[i].isDeclaration(); result = ve; return; } @@ -516,7 +515,7 @@ public: uint i = f.followInstantiationContext(fdv); if (i == 1 && f == ids.fd) { - auto ve = cast(VarExp)e.copy(); + auto ve = e.copy().isVarExp(); ve.originalScope = ids.fd; result = ve; return; @@ -568,7 +567,7 @@ public: } else if (v && v.nestedrefs.dim) { - auto ve = cast(VarExp)e.copy(); + auto ve = e.copy().isVarExp(); ve.originalScope = ids.fd; result = ve; return; @@ -685,7 +684,7 @@ public: { vto.edtor = doInlineAs!Expression(vd.edtor, ids); } - auto de = cast(DeclarationExp)e.copy(); + auto de = e.copy().isDeclarationExp(); de.declaration = vto; result = de; return; @@ -704,7 +703,7 @@ public: override void visit(TypeidExp e) { //printf("TypeidExp.doInlineAs!%s(): %s\n", Result.stringof.ptr, e.toChars()); - auto te = cast(TypeidExp)e.copy(); + auto te = e.copy().isTypeidExp(); if (auto ex = isExpression(te.obj)) { te.obj = doInlineAs!Expression(ex, ids); @@ -717,7 +716,7 @@ public: override void visit(NewExp e) { //printf("NewExp.doInlineAs!%s(): %s\n", Result.stringof.ptr, e.toChars()); - auto ne = cast(NewExp)e.copy(); + auto ne = e.copy().isNewExp(); ne.thisexp = doInlineAs!Expression(e.thisexp, ids); ne.argprefix = doInlineAs!Expression(e.argprefix, ids); ne.newargs = arrayExpressionDoInline(e.newargs); @@ -735,9 +734,8 @@ public: if (tb.ty == Tarray) { Type tv = tb.nextOf().baseElemOf(); - if (tv.ty == Tstruct) + if (auto ts = tv.isTypeStruct()) { - auto ts = cast(TypeStruct)tv; auto sd = ts.sym; if (sd.dtor) semanticTypeInfo(null, ts); @@ -754,7 +752,7 @@ public: override void visit(AssertExp e) { - auto ae = cast(AssertExp)e.copy(); + auto ae = e.copy().isAssertExp(); ae.e1 = doInlineAs!Expression(e.e1, ids); ae.msg = doInlineAs!Expression(e.msg, ids); result = ae; @@ -770,7 +768,7 @@ public: override void visit(CallExp e) { - auto ce = cast(CallExp)e.copy(); + auto ce = e.copy().isCallExp(); ce.e1 = doInlineAs!Expression(e.e1, ids); ce.arguments = arrayExpressionDoInline(e.arguments); result = ce; @@ -780,9 +778,8 @@ public: { visit(cast(BinExp)e); - if (e.e1.op == TOK.arrayLength) + if (auto ale = e.e1.isArrayLengthExp()) { - auto ale = cast(ArrayLengthExp)e.e1; Type tn = ale.e1.type.toBasetype().nextOf(); semanticTypeInfo(null, tn); } @@ -809,7 +806,7 @@ public: override void visit(IndexExp e) { - auto are = cast(IndexExp)e.copy(); + auto are = e.copy().isIndexExp(); are.e1 = doInlineAs!Expression(e.e1, ids); if (e.lengthVar) { @@ -838,7 +835,7 @@ public: override void visit(SliceExp e) { - auto are = cast(SliceExp)e.copy(); + auto are = e.copy().isSliceExp(); are.e1 = doInlineAs!Expression(e.e1, ids); if (e.lengthVar) { @@ -869,7 +866,7 @@ public: override void visit(TupleExp e) { - auto ce = cast(TupleExp)e.copy(); + auto ce = e.copy().isTupleExp(); ce.e0 = doInlineAs!Expression(e.e0, ids); ce.exps = arrayExpressionDoInline(e.exps); result = ce; @@ -877,7 +874,7 @@ public: override void visit(ArrayLiteralExp e) { - auto ce = cast(ArrayLiteralExp)e.copy(); + auto ce = e.copy().isArrayLiteralExp(); ce.basis = doInlineAs!Expression(e.basis, ids); ce.elements = arrayExpressionDoInline(e.elements); result = ce; @@ -887,7 +884,7 @@ public: override void visit(AssocArrayLiteralExp e) { - auto ce = cast(AssocArrayLiteralExp)e.copy(); + auto ce = e.copy().isAssocArrayLiteralExp(); ce.keys = arrayExpressionDoInline(e.keys); ce.values = arrayExpressionDoInline(e.values); result = ce; @@ -902,7 +899,7 @@ public: result = e.inlinecopy; return; } - auto ce = cast(StructLiteralExp)e.copy(); + auto ce = e.copy().isStructLiteralExp(); e.inlinecopy = ce; ce.elements = arrayExpressionDoInline(e.elements); e.inlinecopy = null; @@ -911,7 +908,7 @@ public: override void visit(ArrayExp e) { - auto ce = cast(ArrayExp)e.copy(); + auto ce = e.copy().isArrayExp(); ce.e1 = doInlineAs!Expression(e.e1, ids); ce.arguments = arrayExpressionDoInline(e.arguments); result = ce; @@ -919,7 +916,7 @@ public: override void visit(CondExp e) { - auto ce = cast(CondExp)e.copy(); + auto ce = e.copy().isCondExp(); ce.econd = doInlineAs!Expression(e.econd, ids); ce.e1 = doInlineAs!Expression(e.e1, ids); ce.e2 = doInlineAs!Expression(e.e2, ids); @@ -987,9 +984,9 @@ public: /* If there's a TOK.call at the top, then it may fail to inline * as an Expression. Try to inline as a Statement instead. */ - if (exp.op == TOK.call) + if (auto ce = exp.isCallExp()) { - visitCallExp(cast(CallExp)exp, null, true); + visitCallExp(ce, null, true); if (eresult) exp = eresult; auto s = sresult; @@ -1001,9 +998,8 @@ public: /* If there's a CondExp or CommaExp at the top, then its * sub-expressions may be inlined as statements. */ - if (exp.op == TOK.question) + if (auto e = exp.isCondExp()) { - auto e = cast(CondExp)exp; inlineScan(e.econd); auto s1 = inlineScanExpAsStatement(e.e1); auto s2 = inlineScanExpAsStatement(e.e2); @@ -1013,9 +1009,8 @@ public: auto elsebody = !s2 ? new ExpStatement(e.e2.loc, e.e2) : s2; return new IfStatement(exp.loc, null, e.econd, ifbody, elsebody, exp.loc); } - if (exp.op == TOK.comma) + if (auto e = exp.isCommaExp()) { - auto e = cast(CommaExp)exp; auto s1 = inlineScanExpAsStatement(e.e1); auto s2 = inlineScanExpAsStatement(e.e2); if (!s1 && !s2) @@ -1265,16 +1260,16 @@ public: // Look for NRVO, as inlining NRVO function returns require special handling if (e.op == TOK.construct && e.e2.op == TOK.call) { - CallExp ce = cast(CallExp)e.e2; + auto ce = e.e2.isCallExp(); if (ce.f && ce.f.nrvo_can && ce.f.nrvo_var) // NRVO { - if (e.e1.op == TOK.variable) + if (auto ve = e.e1.isVarExp()) { /* Inlining: * S s = foo(); // initializing by rvalue * S s = S(1); // constructor call */ - Declaration d = (cast(VarExp)e.e1).var; + Declaration d = ve.var; if (d.storage_class & (STC.out_ | STC.ref_)) // refinit goto L1; } @@ -1359,9 +1354,8 @@ public: * If so, and that is only assigned its _init. * If so, do 'copy propagation' of the _init value and try to inline it. */ - if (e.e1.op == TOK.variable) + if (auto ve = e.e1.isVarExp()) { - VarExp ve = cast(VarExp)e.e1; fd = ve.var.isFuncDeclaration(); if (fd) // delegate call @@ -1377,19 +1371,17 @@ public: if (ei && ei.exp.op == TOK.blit) { Expression e2 = (cast(AssignExp)ei.exp).e2; - if (e2.op == TOK.function_) + if (auto fe = e2.isFuncExp()) { - auto fld = (cast(FuncExp)e2).fd; + auto fld = fe.fd; assert(fld.tok == TOK.delegate_); fd = fld; inlineFd(); } - else if (e2.op == TOK.delegate_) + else if (auto de = e2.isDelegateExp()) { - auto de = cast(DelegateExp)e2; - if (de.e1.op == TOK.variable) + if (auto ve2 = de.e1.isVarExp()) { - auto ve2 = cast(VarExp)de.e1; fd = ve2.var.isFuncDeclaration(); inlineFd(); } @@ -1398,9 +1390,8 @@ public: } } } - else if (e.e1.op == TOK.dotVariable) + else if (auto dve = e.e1.isDotVarExp()) { - DotVarExp dve = cast(DotVarExp)e.e1; fd = dve.var.isFuncDeclaration(); if (fd && fd != parent && canInline(fd, true, false, asStatements)) { @@ -1420,7 +1411,7 @@ public: else if (e.e1.op == TOK.star && (cast(PtrExp)e.e1).e1.op == TOK.variable) { - VarExp ve = cast(VarExp)(cast(PtrExp)e.e1).e1; + auto ve = e.e1.isPtrExp().e1.isVarExp(); VarDeclaration v = ve.var.isVarDeclaration(); if (v && v._init && onlyOneAssign(v, parent)) { @@ -1430,16 +1421,15 @@ public: { Expression e2 = (cast(AssignExp)ei.exp).e2; // function pointer call - if (e2.op == TOK.symbolOffset) + if (auto se = e2.isSymOffExp()) { - auto se = cast(SymOffExp)e2; fd = se.var.isFuncDeclaration(); inlineFd(); } // function literal call - else if (e2.op == TOK.function_) + else if (auto fe = e2.isFuncExp()) { - auto fld = (cast(FuncExp)e2).fd; + auto fld = fe.fd; assert(fld.tok == TOK.function_); fd = fld; inlineFd(); @@ -1459,7 +1449,7 @@ public: while (ex.op == TOK.comma) { ex.type = e.type; - ex = (cast(CommaExp)ex).e2; + ex = ex.isCommaExp().e2; } ex.type = e.type; } @@ -1700,8 +1690,7 @@ private bool canInline(FuncDeclaration fd, bool hasthis, bool hdrscan, bool stat if (fd.type) { - assert(fd.type.ty == Tfunction); - TypeFunction tf = cast(TypeFunction)fd.type; + TypeFunction tf = fd.type.isTypeFunction(); // no variadic parameter lists if (tf.parameterList.varargs == VarArg.variadic) @@ -1879,9 +1868,9 @@ private void expandInline(Loc callLoc, FuncDeclaration fd, FuncDeclaration paren Expression ethis, Expressions* arguments, bool asStatements, VarDeclaration vthis2, out Expression eresult, out Statement sresult, out bool again) { - TypeFunction tf = cast(TypeFunction)fd.type; + auto tf = fd.type.isTypeFunction(); static if (LOG || CANINLINE_LOG || EXPANDINLINE_LOG) - printf("FuncDeclaration.expandInline('%s')\n", fd.toChars()); + printf("FuncDeclaration.expandInline('%s', %d)\n", fd.toChars(), asStatements); static if (EXPANDINLINE_LOG) { if (eret) printf("\teret = %s\n", eret.toChars()); @@ -1899,9 +1888,9 @@ private void expandInline(Loc callLoc, FuncDeclaration fd, FuncDeclaration paren VarDeclaration vret; // will be set the function call result if (eret) { - if (eret.op == TOK.variable) + if (auto ve = eret.isVarExp()) { - vret = (cast(VarExp)eret).var.isVarDeclaration(); + vret = ve.var.isVarDeclaration(); assert(!(vret.storage_class & (STC.out_ | STC.ref_))); eret = null; } @@ -1977,9 +1966,9 @@ private void expandInline(Loc callLoc, FuncDeclaration fd, FuncDeclaration paren vthis2._init = new ExpInitializer(vthis2.loc, ce); vthis = vthis2; } - else if (ethis.op == TOK.variable) + else if (auto ve = ethis.isVarExp()) { - vthis = (cast(VarExp)ethis).var.isVarDeclaration(); + vthis = ve.var.isVarDeclaration(); } else { @@ -2048,15 +2037,13 @@ private void expandInline(Loc callLoc, FuncDeclaration fd, FuncDeclaration paren if (vfrom.type.ty == Tdelegate || vfrom.type.ty == Tpointer && vfrom.type.nextOf().ty == Tfunction) { - if (arg.op == TOK.variable) + if (auto ve = arg.isVarExp()) { - VarExp ve = cast(VarExp)arg; if (ve.var.isFuncDeclaration()) again = true; } - else if (arg.op == TOK.symbolOffset) + else if (auto se = arg.isSymOffExp()) { - SymOffExp se = cast(SymOffExp)arg; if (se.var.isFuncDeclaration()) again = true; } diff --git a/dmd/inlinecost.d b/dmd/inlinecost.d index e38633244b8..a97fb51763d 100644 --- a/dmd/inlinecost.d +++ b/dmd/inlinecost.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inlinecost.d, _inlinecost.d) @@ -195,8 +195,7 @@ public: scope InlineCostVisitor icv = new InlineCostVisitor(this); foreach (i; 0 .. s.statements.dim) { - Statement s2 = (*s.statements)[i]; - if (s2) + if (Statement s2 = (*s.statements)[i]) { /* Specifically allow: * if (condition) @@ -368,9 +367,9 @@ public: { //printf("VarExp.inlineCost3() %s\n", toChars()); Type tb = e.type.toBasetype(); - if (tb.ty == Tstruct) + if (auto ts = tb.isTypeStruct()) { - StructDeclaration sd = (cast(TypeStruct)tb).sym; + StructDeclaration sd = ts.sym; if (sd.isNested()) { /* An inner struct will be nested inside another function hierarchy than where @@ -446,11 +445,9 @@ public: override void visit(DeclarationExp e) { //printf("DeclarationExp.inlineCost3()\n"); - VarDeclaration vd = e.declaration.isVarDeclaration(); - if (vd) + if (auto vd = e.declaration.isVarDeclaration()) { - TupleDeclaration td = vd.toAlias().isTupleDeclaration(); - if (td) + if (auto td = vd.toAlias().isTupleDeclaration()) { cost = COST_MAX; // finish DeclarationExp.doInlineAs return; @@ -470,13 +467,12 @@ public: // Scan initializer (vd.init) if (vd._init) { - ExpInitializer ie = vd._init.isExpInitializer(); - if (ie) + if (auto ie = vd._init.isExpInitializer()) { expressionInlineCost(ie.exp); } } - cost += 1; + ++cost; } // aggregates are accepted under certain circumstances @@ -487,7 +483,11 @@ public: } // These can contain functions, which when copied, get output twice. - if (e.declaration.isStructDeclaration() || e.declaration.isClassDeclaration() || e.declaration.isFuncDeclaration() || e.declaration.isAttribDeclaration() || e.declaration.isTemplateMixin()) + if (e.declaration.isStructDeclaration() || + e.declaration.isClassDeclaration() || + e.declaration.isFuncDeclaration() || + e.declaration.isAttribDeclaration() || + e.declaration.isTemplateMixin()) { cost = COST_MAX; return; diff --git a/dmd/intrange.d b/dmd/intrange.d index 4fed17b8817..7d07aff7525 100644 --- a/dmd/intrange.d +++ b/dmd/intrange.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d, _intrange.d) diff --git a/dmd/json.d b/dmd/json.d index e677cbaedfd..119169f38fb 100644 --- a/dmd/json.d +++ b/dmd/json.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/json.d, _json.d) @@ -35,7 +35,7 @@ import dmd.identifier; import dmd.mtype; import dmd.root.outbuffer; import dmd.root.rootobject; -import dmd.utils; +import dmd.root.string; import dmd.visitor; version(Windows) { diff --git a/dmd/json.h b/dmd/json.h index a831e461cb5..db299185b99 100644 --- a/dmd/json.h +++ b/dmd/json.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/lambdacomp.d b/dmd/lambdacomp.d index a39ce47919f..6efa6b15983 100644 --- a/dmd/lambdacomp.d +++ b/dmd/lambdacomp.d @@ -7,7 +7,7 @@ * The serialization is a string which contains the type of the parameters and the * string represantation of the lambda expression. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lamdbacomp.d, _lambdacomp.d) diff --git a/dmd/lexer.d b/dmd/lexer.d index 64d3c768795..8391d91d818 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d, _lexer.d) @@ -28,9 +28,9 @@ import dmd.root.ctfloat; import dmd.root.outbuffer; import dmd.root.port; import dmd.root.rmem; +import dmd.root.string; import dmd.tokens; import dmd.utf; -import dmd.utils; nothrow: @@ -152,8 +152,7 @@ unittest /* Not much here, just trying things out. */ string text = "int"; // We rely on the implicit null-terminator - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0, diagnosticReporter); + scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0); TOK tok; tok = lex1.nextToken(); //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32); @@ -188,8 +187,7 @@ unittest foreach (testcase; testcases) { - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0, diagnosticReporter); + scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0); TOK tok = lex2.nextToken(); size_t iterations = 1; while ((tok != TOK.endOfFile) && (iterations++ < testcase.length)) @@ -227,7 +225,6 @@ class Lexer int inTokenStringConstant; // can be larger than 1 when in nested q{} strings int lastDocLine; // last line of previous doc comment - DiagnosticReporter diagnosticReporter; Token* tokenFreelist; } @@ -244,18 +241,10 @@ class Lexer * endoffset = the last offset to read into base[] * doDocComment = handle documentation comments * commentToken = comments become TOK.comment's - * diagnosticReporter = the diagnostic reporter to use */ this(const(char)* filename, const(char)* base, size_t begoffset, - size_t endoffset, bool doDocComment, bool commentToken, - DiagnosticReporter diagnosticReporter) pure - in + size_t endoffset, bool doDocComment, bool commentToken) pure { - assert(diagnosticReporter !is null); - } - body - { - this.diagnosticReporter = diagnosticReporter; scanloc = Loc(filename, 1, 1); //printf("Lexer::Lexer(%p,%d)\n",base,length); //printf("lexer.filename = %s\n", filename); @@ -294,12 +283,6 @@ class Lexer } } - /// Returns: `true` if any errors occurred during lexing or parsing. - final bool errors() - { - return diagnosticReporter.errorCount > 0; - } - /// Returns: a newly allocated `Token`. Token* allocateToken() pure nothrow @safe { @@ -1167,25 +1150,19 @@ class Lexer */ private uint escapeSequence() { - return Lexer.escapeSequence(token.loc, diagnosticReporter, p); + return Lexer.escapeSequence(token.loc, p); } /** Parse the given string literal escape sequence into a single character. Params: loc = the location of the current token - handler = the diagnostic reporter object sequence = pointer to string with escape sequence to parse. this is a reference variable that is also used to return the position after the sequence Returns: the escaped sequence as a single character */ - private static dchar escapeSequence(const ref Loc loc, DiagnosticReporter handler, ref const(char)* sequence) - in - { - assert(handler !is null); - } - body + private static dchar escapeSequence(const ref Loc loc, ref const(char)* sequence) { const(char)* p = sequence; // cache sequence reference on stack scope(exit) sequence = p; @@ -1251,20 +1228,20 @@ class Lexer break; if (!ishex(cast(char)c)) { - handler.error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); + .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits); break; } } if (ndigits != 2 && !utf_isValidDchar(v)) { - handler.error(loc, "invalid UTF character \\U%08x", v); + .error(loc, "invalid UTF character \\U%08x", v); v = '?'; // recover with valid UTF character } c = v; } else { - handler.error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c); + .error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c); p++; } break; @@ -1278,7 +1255,7 @@ class Lexer c = HtmlNamedEntity(idstart, p - idstart); if (c == ~0) { - handler.error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); + .error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); c = '?'; } p++; @@ -1286,7 +1263,7 @@ class Lexer default: if (isalpha(*p) || (p != idstart && isdigit(*p))) continue; - handler.error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart); + .error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart); c = '?'; break; } @@ -1311,11 +1288,11 @@ class Lexer while (++n < 3 && isoctal(cast(char)c)); c = v; if (c > 0xFF) - handler.error(loc, "escape octal sequence \\%03o is larger than \\377", c); + .error(loc, "escape octal sequence \\%03o is larger than \\377", c); } else { - handler.error(loc, "undefined escape sequence \\%c", c); + .error(loc, "undefined escape sequence \\%c", c); p++; } break; @@ -2315,7 +2292,7 @@ class Lexer { va_list args; va_start(args, format); - diagnosticReporter.error(token.loc, format, args); + .verror(token.loc, format, args); va_end(args); } @@ -2323,31 +2300,7 @@ class Lexer { va_list args; va_start(args, format); - diagnosticReporter.error(loc, format, args); - va_end(args); - } - - final void errorSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - diagnosticReporter.errorSupplemental(loc, format, args); - va_end(args); - } - - final void warning(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - diagnosticReporter.warning(loc, format, args); - va_end(args); - } - - final void warningSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - diagnosticReporter.warningSupplemental(loc, format, args); + .verror(loc, format, args); va_end(args); } @@ -2355,23 +2308,7 @@ class Lexer { va_list args; va_start(args, format); - diagnosticReporter.deprecation(token.loc, format, args); - va_end(args); - } - - final void deprecation(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - diagnosticReporter.deprecation(loc, format, args); - va_end(args); - } - - final void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) - { - va_list args; - va_start(args, format); - diagnosticReporter.deprecationSupplemental(loc, format, args); + .vdeprecation(token.loc, format, args); va_end(args); } @@ -2578,7 +2515,7 @@ class Lexer */ OutBuffer buf; - void trimTrailingWhitespace() nothrow + void trimTrailingWhitespace() { const s = buf[]; auto len = s.length; @@ -2691,23 +2628,18 @@ private: unittest { - static final class AssertDiagnosticReporter : DiagnosticReporter + import dmd.console; + nothrow bool assertDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, + const(char)* format, va_list ap, const(char)* p1, const(char)* p2) { - override int errorCount() { assert(0); } - override int warningCount() { assert(0); } - override int deprecationCount() { assert(0); } - override void error(const ref Loc, const(char)*, va_list) { assert(0); } - override void errorSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - override void warning(const ref Loc, const(char)*, va_list) { assert(0); } - override void warningSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - override void deprecation(const ref Loc, const(char)*, va_list) { assert(0); } - override void deprecationSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } + assert(0); } + diagnosticHandler = &assertDiagnosticHandler; + static void test(T)(string sequence, T expected) { - scope assertOnError = new AssertDiagnosticReporter(); auto p = cast(const(char)*)sequence.ptr; - assert(expected == Lexer.escapeSequence(Loc.initial, assertOnError, p)); + assert(expected == Lexer.escapeSequence(Loc.initial, p)); assert(p == sequence.ptr + sequence.length); } @@ -2743,46 +2675,42 @@ unittest test(`"`, '"'); test(`<`, '<'); test(`>`, '>'); + + diagnosticHandler = null; } unittest { - static final class ExpectDiagnosticReporter : DiagnosticReporter - { - string expected; - bool gotError; - - nothrow: + import dmd.console; + string expected; + bool gotError; - this(string expected) { this.expected = expected; } + nothrow bool expectDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, + const(char)* format, va_list ap, const(char)* p1, const(char)* p2) + { + assert(cast(Classification)headerColor == Classification.error); - override int errorCount() { assert(0); } - override int warningCount() { assert(0); } - override int deprecationCount() { assert(0); } + gotError = true; + char[100] buffer = void; + auto actual = buffer[0 .. vsprintf(buffer.ptr, format, ap)]; + assert(expected == actual); + return true; + } - override void error(const ref Loc loc, const(char)* format, va_list args) - { - gotError = true; - char[100] buffer = void; - auto actual = buffer[0 .. vsprintf(buffer.ptr, format, args)]; - assert(expected == actual); - } + diagnosticHandler = &expectDiagnosticHandler; - override void errorSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - override void warning(const ref Loc, const(char)*, va_list) { assert(0); } - override void warningSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - override void deprecation(const ref Loc, const(char)*, va_list) { assert(0); } - override void deprecationSupplemental(const ref Loc, const(char)*, va_list) { assert(0); } - } - static void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength) nothrow + void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength) { - scope handler = new ExpectDiagnosticReporter(expectedError); + uint errors = global.errors; + gotError = false; + expected = expectedError; auto p = cast(const(char)*)sequence.ptr; - auto actualReturnValue = Lexer.escapeSequence(Loc.initial, handler, p); - assert(handler.gotError); + auto actualReturnValue = Lexer.escapeSequence(Loc.initial, p); + assert(gotError); assert(expectedReturnValue == actualReturnValue); auto actualScanLength = p - sequence.ptr; assert(expectedScanLength == actualScanLength); + global.errors = errors; } test("c", `undefined escape sequence \c`, 'c', 1); @@ -2814,4 +2742,6 @@ unittest test(""", `unterminated named entity "`, '?', 5); test("400", `escape octal sequence \400 is larger than \377`, 0x100, 3); + + diagnosticHandler = null; } diff --git a/dmd/mangle.h b/dmd/mangle.h index d52741c2541..3d2230d60d0 100644 --- a/dmd/mangle.h +++ b/dmd/mangle.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/mars.d b/dmd/mars.d index 093350abad8..9eb8ff83438 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -7,7 +7,7 @@ * utilities needed for arguments parsing, path manipulation, etc... * This file is not shared with other compilers which use the DMD front-end. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mars.d, _mars.d) @@ -36,6 +36,7 @@ import dmd.dmodule; import dmd.doc; import dmd.dsymbol; import dmd.dsymbolsem; +import dmd.dtoh; import dmd.errors; import dmd.expression; import dmd.globals; @@ -59,6 +60,7 @@ import dmd.root.man; import dmd.root.outbuffer; // IN_LLVM import dmd.root.response; import dmd.root.rmem; +import dmd.root.string; import dmd.root.stringtable; import dmd.semantic2; import dmd.semantic3; @@ -588,7 +590,7 @@ version (IN_LLVM) if (m.isHdrFile) { // Remove m's object file from list of object files - for (size_t j = 0; j < params.objfiles.dim; j++) + for (size_t j = 0; j < params.objfiles.length; j++) { if (m.objfile.toChars() == params.objfiles[j]) { @@ -596,7 +598,7 @@ version (IN_LLVM) break; } } - if (params.objfiles.dim == 0) + if (params.objfiles.length == 0) params.link = false; } if (m.isDocFile) @@ -607,7 +609,7 @@ version (IN_LLVM) modules.remove(modi); modi--; // Remove m's object file from list of object files - for (size_t j = 0; j < params.objfiles.dim; j++) + for (size_t j = 0; j < params.objfiles.length; j++) { if (m.objfile.toChars() == params.objfiles[j]) { @@ -615,7 +617,7 @@ version (IN_LLVM) break; } } - if (params.objfiles.dim == 0) + if (params.objfiles.length == 0) params.link = false; } } @@ -769,7 +771,7 @@ version (IN_LLVM) {} else Library library = null; if (params.lib) { - if (params.objfiles.dim == 0) + if (params.objfiles.length == 0) { error(Loc.initial, "no input files"); return EXIT_FAILURE; @@ -807,6 +809,13 @@ version (IN_LLVM) {} else File.write(cgFilename.ptr, buf[]); } } + + if (global.params.doCxxHdrGeneration) + genCppHdrFiles(modules); + + if (global.errors) + fatal(); + version (IN_LLVM) { import core.memory : GC; @@ -876,7 +885,7 @@ else if (global.errors) fatal(); int status = EXIT_SUCCESS; - if (!params.objfiles.dim) + if (!params.objfiles.length) { if (params.link) error(Loc.initial, "no object files to link"); @@ -998,7 +1007,7 @@ extern (C++) void generateJson(Modules* modules) } else { - if (global.params.objfiles.dim == 0) + if (global.params.objfiles.length == 0) { error(Loc.initial, "cannot determine JSON filename, use `-Xf=` or provide a source file"); fatal(); @@ -1044,6 +1053,8 @@ version (NoMain) {} else } } + extern extern(C) __gshared string[] rt_options; + /** * DMD's entry point, C main. * @@ -1068,7 +1079,11 @@ version (NoMain) {} else } } if (!lowmem) + { + __gshared string[] disable_options = [ "gcopt=disable:1" ]; + rt_options = disable_options; mem.disableGC(); + } } // initialize druntime and call _Dmain() below @@ -1083,20 +1098,10 @@ version (NoMain) {} else */ extern (C) int _Dmain(char[][]) { - import core.memory; import core.runtime; - - // Older host druntime versions need druntime to be initialized before - // disabling the GC, so we cannot disable it in C main above. - static if (isGCAvailable) - { - if (!mem.isGCEnabled) - GC.disable(); - } - else - { + import core.memory; + static if (!isGCAvailable) GC.disable(); - } version(D_Coverage) { @@ -2174,6 +2179,17 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param return true; } } + else if (startsWith(p + 1, "verror-style=")) + { + const style = p + 1 + "verror-style=".length; + + if (strcmp(style, "digitalmars") == 0) + params.messageStyle = MessageStyle.digitalmars; + else if (strcmp(style, "gnu") == 0) + params.messageStyle = MessageStyle.gnu; + else + error("unknown error style '%s', must be 'digitalmars' or 'gnu'", style); + } else if (startsWith(p + 1, "mcpu")) // https://dlang.org/dmd.html#switch-mcpu { enum len = "-mcpu=".length; @@ -2398,12 +2414,33 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param case 'd': // https://dlang.org/dmd.html#switch-Dd if (!p[3]) goto Lnoarg; - params.docdir = p + 3 + (p[3] == '='); + params.docdir = (p + 3 + (p[3] == '=')).toDString(); break; case 'f': // https://dlang.org/dmd.html#switch-Df if (!p[3]) goto Lnoarg; - params.docname = p + 3 + (p[3] == '='); + params.docname = (p + 3 + (p[3] == '=')).toDString(); + break; + case 0: + break; + default: + goto Lerror; + } + } + else if (p[1] == 'H' && p[2] == 'C') // https://dlang.org/dmd.html#switch-HC + { + params.doCxxHdrGeneration = true; + switch (p[3]) + { + case 'd': // https://dlang.org/dmd.html#switch-HCd + if (!p[4]) + goto Lnoarg; + params.cxxhdrdir = (p + 4 + (p[4] == '=')).toDString; + break; + case 'f': // https://dlang.org/dmd.html#switch-HCf + if (!p[4]) + goto Lnoarg; + params.cxxhdrname = (p + 4 + (p[4] == '=')).toDString; break; case 0: break; diff --git a/dmd/module.h b/dmd/module.h index 2154e11872f..5706d815a9b 100644 --- a/dmd/module.h +++ b/dmd/module.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -85,7 +85,6 @@ class Module : public Package bool isHdrFile; // if it is a header (.di) file bool isDocFile; // if it is a documentation input file, not D source bool isPackageFile; // if it is a package.d - Package *pkg; // if isPackageFile is true, the Package that contains this package.d Strings contentImportedFiles; // array of files whose content was imported int needmoduleinfo; int selfimports; // 0: don't know, 1: does not, 2: does diff --git a/dmd/mtype.d b/dmd/mtype.d index a38b3c14139..f2f770616e5 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d) @@ -287,7 +287,7 @@ enum ENUMTY : int Tvector, Tint128, Tuns128, - TTraits, + Ttraits, Tmixin, TMAX, } @@ -336,7 +336,7 @@ alias Tnull = ENUMTY.Tnull; alias Tvector = ENUMTY.Tvector; alias Tint128 = ENUMTY.Tint128; alias Tuns128 = ENUMTY.Tuns128; -alias Ttraits = ENUMTY.TTraits; +alias Ttraits = ENUMTY.Ttraits; alias Tmixin = ENUMTY.Tmixin; alias TMAX = ENUMTY.TMAX; @@ -4169,6 +4169,7 @@ extern (C++) final class TypeFunction : TypeNext bool isscope; // true: 'this' is scope bool isreturninferred; // true: 'this' is return from inference bool isscopeinferred; // true: 'this' is scope from inference + bool islive; // is @live LINK linkage; // calling convention TRUST trust; // level of trust PURE purity = PURE.impure; @@ -4194,6 +4195,8 @@ extern (C++) final class TypeFunction : TypeNext this.isnogc = true; if (stc & STC.property) this.isproperty = true; + if (stc & STC.live) + this.islive = true; if (stc & STC.ref_) this.isref = true; diff --git a/dmd/mtype.h b/dmd/mtype.h index 51907503cdc..8e25e59c040 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -103,7 +103,7 @@ enum ENUMTY Tvector, Tint128, Tuns128, - TTraits, + Ttraits, TMAX }; typedef unsigned char TY; // ENUMTY @@ -604,6 +604,7 @@ class TypeFunction : public TypeNext bool isscope; // true: 'this' is scope bool isreturninferred; // true: 'this' is return from inference bool isscopeinferred; // true: 'this' is scope from inference + bool islive; // is @live LINK linkage; // calling convention TRUST trust; // level of trust PURE purity; // PURExxxx diff --git a/dmd/nogc.d b/dmd/nogc.d index f5e0e354d7b..197cf649858 100644 --- a/dmd/nogc.d +++ b/dmd/nogc.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d, _nogc.d) @@ -160,8 +160,6 @@ public: default: break; } - if (ad && ad.aggDelete) - return; if (f.setGC()) { diff --git a/dmd/nspace.d b/dmd/nspace.d index 75b8e694026..f3a9a32dbfd 100644 --- a/dmd/nspace.d +++ b/dmd/nspace.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d) diff --git a/dmd/nspace.h b/dmd/nspace.h index c79a0df44ba..95c38c12234 100644 --- a/dmd/nspace.h +++ b/dmd/nspace.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/ob.d b/dmd/ob.d new file mode 100644 index 00000000000..3781b587203 --- /dev/null +++ b/dmd/ob.d @@ -0,0 +1,2564 @@ +/** + * Flow analysis for Ownership/Borrowing + * + * Compiler implementation of the + * $(LINK2 http://www.dlang.org, D programming language). + * + * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ob.d, _ob.d) + * Documentation: https://dlang.org/phobos/dmd_escape.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ob.d + */ + +module dmd.ob; + +import core.stdc.stdio : printf; +import core.stdc.stdlib; +import core.stdc.string; + +import dmd.root.array; +import dmd.root.rootobject; +import dmd.root.rmem; + +import dmd.aggregate; +import dmd.apply; +import dmd.arraytypes; +import dmd.declaration; +import dmd.dscope; +import dmd.dsymbol; +import dmd.dtemplate; +import dmd.errors; +import dmd.escape; +import dmd.expression; +import dmd.foreachvar; +import dmd.func; +import dmd.globals; +import dmd.identifier; +import dmd.init; +import dmd.mtype; +import dmd.printast; +import dmd.statement; +import dmd.tokens; +import dmd.visitor; + +import dmd.root.bitarray; +import dmd.root.outbuffer; + +/********************************** + * Perform ownership/borrowing checks for funcdecl. + * Does not modify the AST, just checks for errors. + */ + +void oblive(FuncDeclaration funcdecl) +{ + //printf("oblive() %s\n", funcdecl.toChars()); + //printf("fbody: %s\n", funcdecl.fbody.toChars()); + ObState obstate; + + /* Build the flow graph + */ + setLabelStatementExtraFields(funcdecl.labtab); + toObNodes(obstate.nodes, funcdecl.fbody); + insertFinallyBlockCalls(obstate.nodes); + insertFinallyBlockGotos(obstate.nodes); + removeUnreachable(obstate.nodes); + computePreds(obstate.nodes); + + numberNodes(obstate.nodes); + //foreach (ob; obstate.nodes) ob.print(); + + collectVars(funcdecl, obstate.vars); + allocStates(obstate); + doDataFlowAnalysis(obstate); + + checkObErrors(obstate); +} + +alias ObNodes = Array!(ObNode*); + +/******************************************* + * Collect the state information. + */ +struct ObState +{ + ObNodes nodes; + VarDeclarations vars; + + Array!size_t varStack; /// temporary storage + Array!bool mutableStack; /// parallel to varStack[], is type mutable? + + PtrVarState[] varPool; /// memory pool + + ~this() + { + mem.xfree(varPool.ptr); + } +} + +/*********************************************** + * A node in the function's expression graph, and its edges to predecessors and successors. + */ +struct ObNode +{ + Expression exp; /// expression for the node + ObNodes preds; /// predecessors + ObNodes succs; /// successors + ObNode* tryBlock; /// try-finally block we're inside + ObType obtype; + uint index; /// index of this in obnodes + + PtrVarState[] gen; /// new states generated for this node + PtrVarState[] input; /// variable states on entry to exp + PtrVarState[] output; /// variable states on exit to exp + + this(ObNode* tryBlock) + { + this.tryBlock = tryBlock; + } + + void print() + { + printf("%d: %s %s\n", index, obtype.toString.ptr, exp ? exp.toChars() : "-"); + printf(" preds: "); + foreach (ob; preds) + printf(" %d", ob.index); + printf("\n succs: "); + foreach (ob; succs) + printf(" %d", ob.index); + printf("\n\n"); + } +} + + +enum ObType : ubyte +{ + goto_, /// goto one of the succs[] + return_, /// returns from function + retexp, /// returns expression from function + throw_, /// exits with throw + exit, /// exits program + try_, + finally_, + fend, +} + +string toString(ObType obtype) +{ + return obtype == ObType.goto_ ? "goto " : + obtype == ObType.return_ ? "ret " : + obtype == ObType.retexp ? "retexp" : + obtype == ObType.throw_ ? "throw" : + obtype == ObType.exit ? "exit" : + obtype == ObType.try_ ? "try" : + obtype == ObType.finally_ ? "finally" : + obtype == ObType.fend ? "fend" : + "---"; +} + +/*********** + Pointer variable states: + + Undefined not in a usable state + + T* p = void; + + Owner mutable pointer + + T* p = initializer; + + Borrowed scope mutable pointer, borrowed from [p] + + T* p = initializer; + scope T* b = p; + + Readonly scope const pointer, copied from [p] + + T* p = initializer; + scope const(T)* cp = p; + + Examples: + + T* p = initializer; // p is owner + T** pp = &p; // pp borrows from p + + T* p = initialize; // p is owner + T* q = p; // transfer: q is owner, p is undefined + */ + +enum PtrState : ubyte +{ + Undefined, Owner, Borrowed, Readonly +} + +/************ + */ +const(char)* toChars(PtrState state) +{ + return ["Undefined", "Owner", "Borrowed", "Readonly"][state].ptr; +} + +/****** + * Carries the state of a pointer variable. + */ +struct PtrVarState +{ + BitArray deps; /// dependencies + PtrState state; /// state the pointer variable is in + + void opAssign(const ref PtrVarState pvs) + { + state = pvs.state; + deps = pvs.deps; + } + + /* Combine `this` and `pvs` into `this`, + * on the idea that the `this` and the `pvs` paths + * are being merged + * Params: + * pvs = path to be merged with `this` + */ + void combine(ref PtrVarState pvs, size_t vi, PtrVarState[] gen) + { + static uint X(PtrState x1, PtrState x2) { return x1 * (PtrState.max + 1) + x2; } + + with (PtrState) + { + switch (X(state, pvs.state)) + { + case X(Undefined, Undefined): + case X(Undefined, Owner ): + case X(Undefined, Borrowed ): + case X(Undefined, Readonly ): + break; + + case X(Owner , Owner ): + break; + + case X(Borrowed , Borrowed): + case X(Readonly , Readonly): + deps.or(pvs.deps); + break; + + default: + makeUndefined(vi, gen); + break; + } + } + } + + bool opEquals(const ref PtrVarState pvs) const + { + return state == pvs.state && + deps == pvs.deps; + } + + /*********************** + */ + void print(VarDeclaration[] vars) + { + string s = ["Undefined", "Owner", "Borrowed", "Lent", "Readonly", "View"][state]; + printf("%.*s [", cast(int)s.length, s.ptr); + assert(vars.length == deps.length); + OutBuffer buf; + depsToBuf(buf, vars); + string t = buf[]; + printf("%.*s]\n", cast(int)t.length, t.ptr); + } + + /***************************** + * Produce a user-readable comma separated string of the + * dependencies. + * Params: + * buf = write resulting string here + * vars = array from which to get the variable names + */ + void depsToBuf(ref OutBuffer buf, const VarDeclaration[] vars) + { + bool any = false; + foreach (i; 0 .. deps.length) + { + if (deps[i]) + { + if (any) + buf.writestring(", "); + buf.writestring(vars[i].toString()); + any = true; + } + } + } +} + + +/***************************************** + * Set the `.extra` field for LabelStatements in labtab[]. + */ +void setLabelStatementExtraFields(DsymbolTable labtab) +{ + if (labtab) + foreach (keyValue; labtab.tab.asRange) + { + //printf(" KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars()); + auto label = cast(LabelDsymbol)keyValue.value; + if (label.statement) + label.statement.extra = cast(void*) new ObNode(null); + } +} + +/***************************************** + * Convert statement into ObNodes. + */ + +void toObNodes(ref ObNodes obnodes, Statement s) +{ + ObNode* breakBlock; + ObNode* contBlock; + ObNode* switchBlock; + ObNode* defaultBlock; + ObNode* tryBlock; + + ObNode* curblock = new ObNode(tryBlock); + obnodes.push(curblock); + + void visit(Statement s) + { + if (!s) + return; + + ObNode* newNode() + { + return new ObNode(tryBlock); + } + + ObNode* nextNodeIs(ObNode* ob) + { + obnodes.push(ob); + curblock = ob; + return ob; + } + + ObNode* nextNode() + { + return nextNodeIs(newNode()); + } + + ObNode* gotoNextNodeIs(ObNode* ob) + { + obnodes.push(ob); + curblock.succs.push(ob); + curblock = ob; + return ob; + } + + // block_goto(blx, BCgoto, null) + ObNode* gotoNextNode() + { + return gotoNextNodeIs(newNode()); + } + + /*** + * Doing a goto to dest + */ + ObNode* gotoDest(ObNode* dest) + { + curblock.succs.push(dest); + return nextNode(); + } + + void visitExp(ExpStatement s) + { + curblock.obtype = ObType.goto_; + curblock.exp = s.exp; + gotoNextNode(); + } + + void visitDtorExp(DtorExpStatement s) + { + visitExp(s); + } + + void visitCompound(CompoundStatement s) + { + if (s.statements) + { + foreach (s2; *s.statements) + { + visit(s2); + } + } + } + + void visitCompoundDeclaration(CompoundDeclarationStatement s) + { + visitCompound(s); + } + + void visitUnrolledLoop(UnrolledLoopStatement s) + { + auto breakBlockSave = breakBlock; + breakBlock = newNode(); + auto contBlockSave = contBlock; + + gotoNextNode(); + + foreach (s2; *s.statements) + { + if (s2) + { + contBlock = newNode(); + + visit(s2); + + gotoNextNodeIs(contBlock); + } + } + + gotoNextNodeIs(breakBlock); + + contBlock = contBlockSave; + breakBlock = breakBlockSave; + } + + void visitScope(ScopeStatement s) + { + if (s.statement) + { + visit(s.statement); + + if (breakBlock) + { + gotoNextNodeIs(breakBlock); + } + } + } + + void visitDo(DoStatement s) + { + auto breakBlockSave = breakBlock; + auto contBlockSave = contBlock; + + breakBlock = newNode(); + contBlock = newNode(); + + auto bpre = curblock; + + auto ob = newNode(); + obnodes.push(ob); + curblock.succs.push(ob); + curblock = ob; + bpre.succs.push(curblock); + + contBlock.succs.push(curblock); + contBlock.succs.push(breakBlock); + + visit(s._body); + + gotoNextNodeIs(contBlock); + contBlock.exp = s.condition; + nextNodeIs(breakBlock); + + contBlock = contBlockSave; + breakBlock = breakBlockSave; + } + + void visitFor(ForStatement s) + { + //printf("visit(ForStatement)) %u..%u\n", s.loc.linnum, s.endloc.linnum); + auto breakBlockSave = breakBlock; + auto contBlockSave = contBlock; + + breakBlock = newNode(); + contBlock = newNode(); + + visit(s._init); + + auto bcond = gotoNextNode(); + contBlock.succs.push(bcond); + + if (s.condition) + { + bcond.exp = s.condition; + auto ob = newNode(); + obnodes.push(ob); + bcond.succs.push(ob); + bcond.succs.push(breakBlock); + curblock = ob; + } + else + { /* No conditional, it's a straight goto + */ + bcond.exp = s.condition; + bcond.succs.push(nextNode()); + } + + visit(s._body); + /* End of the body goes to the continue block + */ + curblock.succs.push(contBlock); + nextNodeIs(contBlock); + + if (s.increment) + curblock.exp = s.increment; + + /* The 'break' block follows the for statement. + */ + nextNodeIs(breakBlock); + + contBlock = contBlockSave; + breakBlock = breakBlockSave; + } + + void visitIf(IfStatement s) + { + // bexit is the block that gets control after this IfStatement is done + auto bexit = breakBlock ? breakBlock : newNode(); + + curblock.exp = s.condition; + + auto bcond = curblock; + gotoNextNode(); + + visit(s.ifbody); + curblock.succs.push(bexit); + + if (s.elsebody) + { + bcond.succs.push(nextNode()); + + visit(s.elsebody); + + gotoNextNodeIs(bexit); + } + else + { + bcond.succs.push(bexit); + nextNodeIs(bexit); + } + } + + void visitSwitch(SwitchStatement s) + { + auto breakBlockSave = breakBlock; + auto switchBlockSave = switchBlock; + auto defaultBlockSave = defaultBlock; + + switchBlock = curblock; + + /* Block for where "break" goes to + */ + breakBlock = newNode(); + + /* Block for where "default" goes to. + * If there is a default statement, then that is where default goes. + * If not, then do: + * default: break; + * by making the default block the same as the break block. + */ + defaultBlock = s.sdefault ? newNode() : breakBlock; + + const numcases = s.cases ? s.cases.dim : 0; + + /* allocate a block for each case + */ + if (numcases) + foreach (cs; *s.cases) + { + cs.extra = cast(void*)newNode(); + } + + curblock.exp = s.condition; + + if (s.hasVars) + { /* Generate a sequence of if-then-else blocks for the cases. + */ + if (numcases) + foreach (cs; *s.cases) + { + auto ecase = newNode(); + obnodes.push(ecase); + ecase.exp = cs.exp; + curblock.succs.push(ecase); + + auto cn = cast(ObNode*)cs.extra; + ecase.succs.push(cn); + ecase.succs.push(nextNode()); + } + + /* The final 'else' clause goes to the default + */ + curblock.succs.push(defaultBlock); + nextNode(); + + visit(s._body); + + /* Have the end of the switch body fall through to the block + * following the switch statement. + */ + gotoNextNodeIs(breakBlock); + + breakBlock = breakBlockSave; + switchBlock = switchBlockSave; + defaultBlock = defaultBlockSave; + return; + } + + auto ob = newNode(); + obnodes.push(ob); + curblock = ob; + + switchBlock.succs.push(defaultBlock); + + visit(s._body); + + /* Have the end of the switch body fall through to the block + * following the switch statement. + */ + gotoNextNodeIs(breakBlock); + + breakBlock = breakBlockSave; + switchBlock = switchBlockSave; + defaultBlock = defaultBlockSave; + } + + void visitCase(CaseStatement s) + { + auto cb = cast(ObNode*)s.extra; + cb.tryBlock = tryBlock; + switchBlock.succs.push(cb); + cb.tryBlock = tryBlock; + gotoNextNodeIs(cb); + + visit(s.statement); + } + + void visitDefault(DefaultStatement s) + { + defaultBlock.tryBlock = tryBlock; + gotoNextNodeIs(defaultBlock); + visit(s.statement); + } + + void visitGotoDefault(GotoDefaultStatement s) + { + gotoDest(defaultBlock); + } + + void visitGotoCase(GotoCaseStatement s) + { + gotoDest(cast(ObNode*)s.cs.extra); + } + + void visitSwitchError(SwitchErrorStatement s) + { + curblock.obtype = ObType.throw_; + curblock.exp = s.exp; + + nextNode(); + } + + void visitReturn(ReturnStatement s) + { + //printf("visitReturn() %s\n", s.toChars()); + curblock.obtype = s.exp && s.exp.type.toBasetype().ty != Tvoid + ? ObType.retexp + : ObType.return_; + curblock.exp = s.exp; + + nextNode(); + } + + void visitBreak(BreakStatement s) + { + gotoDest(breakBlock); + } + + void visitContinue(ContinueStatement s) + { + gotoDest(contBlock); + } + + void visitWith(WithStatement s) + { + visit(s._body); + } + + void visitTryCatch(TryCatchStatement s) + { + /* tryblock + * body + * breakBlock + * catches + * breakBlock2 + */ + + auto breakBlockSave = breakBlock; + breakBlock = newNode(); + + auto tryblock = gotoNextNode(); + + visit(s._body); + + gotoNextNodeIs(breakBlock); + + // create new break block that follows all the catches + auto breakBlock2 = newNode(); + + gotoDest(breakBlock2); + + foreach (cs; *s.catches) + { + /* Each catch block is a successor to tryblock + * and the last block of try body + */ + auto bcatch = curblock; + tryblock.succs.push(bcatch); + breakBlock.succs.push(bcatch); + + nextNode(); + + visit(cs.handler); + + gotoDest(breakBlock2); + } + + curblock.succs.push(breakBlock2); + obnodes.push(breakBlock2); + curblock = breakBlock2; + + breakBlock = breakBlockSave; + } + + void visitTryFinally(TryFinallyStatement s) + { + /* Build this: + * 1 goto [2] + * 2 try_ [3] [5] [7] + * 3 body + * 4 goto [8] + * 5 finally_ [6] + * 6 finalbody + * 7 fend [8] + * 8 lastblock + */ + + auto b2 = gotoNextNode(); + b2.obtype = ObType.try_; + tryBlock = b2; + + gotoNextNode(); + + visit(s._body); + + auto b4 = gotoNextNode(); + + tryBlock = b2.tryBlock; + + auto b5 = newNode(); + b5.obtype = ObType.finally_; + nextNodeIs(b5); + gotoNextNode(); + + visit(s.finalbody); + + auto b7 = gotoNextNode(); + b7.obtype = ObType.fend; + + auto b8 = gotoNextNode(); + + b2.succs.push(b5); + b2.succs.push(b7); + + b4.succs.push(b8); + } + + void visitThrow(ThrowStatement s) + { + curblock.obtype = ObType.throw_; + curblock.exp = s.exp; + nextNode(); + } + + void visitGoto(GotoStatement s) + { + gotoDest(cast(ObNode*)s.label.statement.extra); + } + + void visitLabel(LabelStatement s) + { + auto ob = cast(ObNode*)s.extra; + ob.tryBlock = tryBlock; + visit(s.statement); + } + + final switch (s.stmt) + { + case STMT.Exp: visitExp(s.isExpStatement()); break; + case STMT.DtorExp: visitDtorExp(s.isDtorExpStatement()); break; + case STMT.Compound: visitCompound(s.isCompoundStatement()); break; + case STMT.CompoundDeclaration: visitCompoundDeclaration(s.isCompoundDeclarationStatement()); break; + case STMT.UnrolledLoop: visitUnrolledLoop(s.isUnrolledLoopStatement()); break; + case STMT.Scope: visitScope(s.isScopeStatement()); break; + case STMT.Do: visitDo(s.isDoStatement()); break; + case STMT.For: visitFor(s.isForStatement()); break; + case STMT.If: visitIf(s.isIfStatement()); break; + case STMT.Switch: visitSwitch(s.isSwitchStatement()); break; + case STMT.Case: visitCase(s.isCaseStatement()); break; + case STMT.Default: visitDefault(s.isDefaultStatement()); break; + case STMT.GotoDefault: visitGotoDefault(s.isGotoDefaultStatement()); break; + case STMT.GotoCase: visitGotoCase(s.isGotoCaseStatement()); break; + case STMT.SwitchError: visitSwitchError(s.isSwitchErrorStatement()); break; + case STMT.Return: visitReturn(s.isReturnStatement()); break; + case STMT.Break: visitBreak(s.isBreakStatement()); break; + case STMT.Continue: visitContinue(s.isContinueStatement()); break; + case STMT.With: visitWith(s.isWithStatement()); break; + case STMT.TryCatch: visitTryCatch(s.isTryCatchStatement()); break; + case STMT.TryFinally: visitTryFinally(s.isTryFinallyStatement()); break; + case STMT.Throw: visitThrow(s.isThrowStatement()); break; + case STMT.Goto: visitGoto(s.isGotoStatement()); break; + case STMT.Label: visitLabel(s.isLabelStatement()); break; + + case STMT.CompoundAsm: + case STMT.Asm: + case STMT.InlineAsm: + case STMT.GccAsm: + + case STMT.Pragma: + case STMT.Import: + case STMT.ScopeGuard: + case STMT.Error: + break; // ignore these + + case STMT.Foreach: + case STMT.ForeachRange: + case STMT.Debug: + case STMT.CaseRange: + case STMT.StaticForeach: + case STMT.StaticAssert: + case STMT.Conditional: + case STMT.While: + case STMT.Forwarding: + case STMT.Compile: + case STMT.Peel: + case STMT.Synchronized: + debug printf("s: %s\n", s.toChars()); + assert(0); // should have been rewritten + } + } + + visit(s); + curblock.obtype = ObType.return_; + + assert(breakBlock is null); + assert(contBlock is null); + assert(switchBlock is null); + assert(defaultBlock is null); + assert(tryBlock is null); +} + +/*************************************************** + * Insert finally block calls when doing a goto from + * inside a try block to outside. + * Done after blocks are generated because then we know all + * the edges of the graph, but before the pred's are computed. + * Params: + * obnodes = graph of the function + */ + +void insertFinallyBlockCalls(ref ObNodes obnodes) +{ + ObNode* bcret = null; + ObNode* bcretexp = null; + + enum log = false; + + static if (log) + { + printf("------- before ----------\n"); + numberNodes(obnodes); + foreach (ob; obnodes) ob.print(); + printf("-------------------------\n"); + } + + foreach (ob; obnodes) + { + if (!ob.tryBlock) + continue; + + switch (ob.obtype) + { + case ObType.return_: + // Rewrite into a ObType.goto_ => ObType.return_ + if (!bcret) + { + bcret = new ObNode(); + bcret.obtype = ob.obtype; + } + ob.obtype = ObType.goto_; + ob.succs.push(bcret); + goto case_goto; + + case ObType.retexp: + // Rewrite into a ObType.goto_ => ObType.retexp + if (!bcretexp) + { + bcretexp = new ObNode(); + bcretexp.obtype = ob.obtype; + } + ob.obtype = ObType.goto_; + ob.succs.push(bcretexp); + goto case_goto; + + case ObType.goto_: + if (ob.succs.length != 1) + break; + + case_goto: + { + auto target = ob.succs[0]; // destination of goto + ob.succs.setDim(0); + auto lasttry = target.tryBlock; + auto blast = ob; + for (auto bt = ob.tryBlock; bt != lasttry; bt = bt.tryBlock) + { + assert(bt.obtype == ObType.try_); + auto bf = bt.succs[1]; + assert(bf.obtype == ObType.finally_); + auto bfend = bt.succs[2]; + assert(bfend.obtype == ObType.fend); + + if (!blast.succs.contains(bf.succs[0])) + blast.succs.push(bf.succs[0]); + + blast = bfend; + } + if (!blast.succs.contains(target)) + blast.succs.push(target); + + break; + } + + default: + break; + } + } + if (bcret) + obnodes.push(bcret); + if (bcretexp) + obnodes.push(bcretexp); + + static if (log) + { + printf("------- after ----------\n"); + numberNodes(obnodes); + foreach (ob; obnodes) ob.print(); + printf("-------------------------\n"); + } +} + +/*************************************************** + * Remove try-finally scaffolding. + * Params: + * obnodes = nodes for the function + */ + +void insertFinallyBlockGotos(ref ObNodes obnodes) +{ + /* Remove all the try_, finally_, lpad and ret nodes. + * Actually, just make them into no-ops. + */ + foreach (ob; obnodes) + { + ob.tryBlock = null; + switch (ob.obtype) + { + case ObType.try_: + ob.obtype = ObType.goto_; + ob.succs.remove(2); // remove fend + ob.succs.remove(1); // remove finally_ + break; + + case ObType.finally_: + ob.obtype = ObType.goto_; + break; + + case ObType.fend: + ob.obtype = ObType.goto_; + break; + + default: + break; + } + } +} + +/********************************* + * Set the `index` field of each ObNode + * to its index in the array. + */ +void numberNodes(ref ObNodes obnodes) +{ + foreach (i, ob; obnodes) + { + ob.index = cast(uint)i; + } +} + + +/********************************* + * Remove unreachable nodes and compress + * them out of obnodes[]. + * Params: + * obnodes = array of nodes + */ +void removeUnreachable(ref ObNodes obnodes) +{ + if (!obnodes.length) + return; + + /* Mark all nodes as unreachable, + * temporarilly reusing ObNode.index + */ + foreach (ob; obnodes) + ob.index = 0; + + /* Recurseively mark ob and all its successors as reachable + */ + static void mark(ObNode* ob) + { + ob.index = 1; + foreach (succ; ob.succs) + { + if (!succ.index) + mark(succ); + } + } + + mark(obnodes[0]); // first node is entry point + + /* Remove unreachable nodes by shifting the remainder left + */ + size_t j = 1; + foreach (i; 1 .. obnodes.length) + { + if (obnodes[i].index) + { + if (i != j) + obnodes[j] = obnodes[i]; + ++j; + } + else + { + obnodes[i].destroy(); + } + } + obnodes.setDim(j); +} + + + +/************************************* + * Compute predecessors. + */ +void computePreds(ref ObNodes obnodes) +{ + foreach (ob; obnodes) + { + foreach (succ; ob.succs) + { + succ.preds.push(ob); + } + } +} + +/******************************* + * Are we interested in tracking this variable? + */ +bool isTrackableVar(VarDeclaration v) +{ + /* Currently only dealing with pointers + */ + if (v.type.toBasetype().ty != Tpointer) + return false; + if (v.needsScopeDtor()) + return false; + if (v.storage_class & STC.parameter && !v.type.isMutable()) + return false; + return !v.isDataseg(); +} + +/******************************* + * Are we interested in tracking this expression? + * Returns: + * variable if so, null if not + */ +VarDeclaration isTrackableVarExp(Expression e) +{ + if (auto ve = e.isVarExp()) + { + if (auto v = ve.var.isVarDeclaration()) + if (isTrackableVar(v)) + return v; + } + return null; +} + + +/************** + * Find the pointer variable declarations in this function, + * and fill `vars` with them. + * Params: + * funcdecl = function we are in + * vars = array to fill in + */ +void collectVars(FuncDeclaration funcdecl, out VarDeclarations vars) +{ + enum log = false; + if (log) + printf("----------------collectVars()---------------\n"); + + if (funcdecl.parameters) + foreach (v; (*funcdecl.parameters)[]) + { + if (isTrackableVar(v)) + vars.push(v); + } + + void dgVar(VarDeclaration v) + { + if (isTrackableVar(v)) + vars.push(v); + } + + void dgExp(Expression e) + { + foreachVar(e, &dgVar); + } + + foreachExpAndVar(funcdecl.fbody, &dgExp, &dgVar); + + static if (log) + { + foreach (i, v; vars[]) + { + printf("vars[%d] = %s\n", cast(int)i, v.toChars()); + } + } +} + +/*********************************** + * Allocate BitArrays in PtrVarState. + * Can be allocated much more efficiently by subdividing a single + * large array of bits + */ +void allocDeps(PtrVarState[] pvss) +{ + //printf("allocDeps()\n"); + foreach (ref pvs; pvss) + { + pvs.deps.length = pvss.length; + } +} + + +/************************************** + * Allocate state variables foreach node. + */ +void allocStates(ref ObState obstate) +{ + //printf("---------------allocStates()------------------\n"); + const vlen = obstate.vars.length; + PtrVarState* p = cast(PtrVarState*) mem.xcalloc(obstate.nodes.length * 3 * vlen, PtrVarState.sizeof); + obstate.varPool = p[0 .. obstate.nodes.length * 3 * vlen]; + foreach (i, ob; obstate.nodes) + { + //printf(" [%d]\n", cast(int)i); +// ob.kill.length = obstate.vars.length; +// ob.comb.length = obstate.vars.length; + ob.gen = p[0 .. vlen]; p += vlen; + ob.input = p[0 .. vlen]; p += vlen; + ob.output = p[0 .. vlen]; p += vlen; + + allocDeps(ob.gen); + allocDeps(ob.input); + allocDeps(ob.output); + } +} + +/****************************** + * Does v meet the definiton of a `Borrowed` pointer? + * Returns: + * true if it does + */ +bool isBorrowedPtr(VarDeclaration v) +{ + return v.isScope() && !v.isowner && v.type.nextOf().isMutable(); +} + +/****************************** + * Does v meet the definiton of a `Readonly` pointer? + * Returns: + * true if it does + */ +bool isReadonlyPtr(VarDeclaration v) +{ + return v.isScope() && !v.type.nextOf().isMutable(); +} + +/*************************************** + * Compute the gen/comb/kill vectors for each node. + */ +void genKill(ref ObState obstate, ObNode* ob) +{ + enum log = false; + if (log) + printf("-----------computeGenKill()-----------\n"); + + /*************** + * Assigning result of expression `e` to variable `v`. + */ + void dgWriteVar(ObNode* ob, VarDeclaration v, Expression e, bool initializer) + { + const vi = obstate.vars.find(v); + assert(vi != size_t.max); + PtrVarState* pvs = &ob.gen[vi]; + if (e) + { + if (isBorrowedPtr(v)) + pvs.state = PtrState.Borrowed; + else if (isReadonlyPtr(v)) + pvs.state = PtrState.Readonly; + else + pvs.state = PtrState.Owner; + pvs.deps.zero(); + + EscapeByResults er; + escapeByValue(e, &er, true); + bool any = false; // if any variables are assigned to v + + void by(VarDeclaration r) + { + const ri = obstate.vars.find(r); + if (ri != size_t.max && ri != vi) + { + pvs.deps[ri] = true; // v took from r + auto pvsr = &ob.gen[ri]; + any = true; + + if (isBorrowedPtr(v)) + { + // v is borrowing from r + pvs.state = PtrState.Borrowed; + } + else if (isReadonlyPtr(v)) + { + pvs.state = PtrState.Readonly; + } + else + { + // move r to v, which "consumes" r + pvsr.state = PtrState.Undefined; + pvsr.deps.zero(); + } + } + } + + foreach (VarDeclaration v2; er.byvalue) + by(v2); + foreach (VarDeclaration v2; er.byref) + by(v2); + + /* Make v an Owner for initializations like: + * scope v = malloc(); + */ + if (initializer && !any && isBorrowedPtr(v)) + { + v.isowner = true; + pvs.state = PtrState.Owner; + } + } + else + { + if (isBorrowedPtr(v)) + pvs.state = PtrState.Borrowed; + else if (isReadonlyPtr(v)) + pvs.state = PtrState.Readonly; + else + pvs.state = PtrState.Owner; + pvs.deps.zero(); + } + } + + void dgReadVar(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) + { + if (log) + printf("dgReadVar() %s %d\n", v.toChars(), mutable); + const vi = obstate.vars.find(v); + assert(vi != size_t.max); + readVar(ob, vi, mutable, ob.gen); + } + + void foreachExp(ObNode* ob, Expression e) + { + extern (C++) final class ExpWalker : Visitor + { + alias visit = typeof(super).visit; + extern (D) void delegate(ObNode*, VarDeclaration, Expression, bool) dgWriteVar; + extern (D) void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar; + ObNode* ob; + ObState* obstate; + + extern (D) this(void delegate(ObNode*, VarDeclaration, Expression, bool) dgWriteVar, + void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar, + ObNode* ob, ref ObState obstate) + { + this.dgWriteVar = dgWriteVar; + this.dgReadVar = dgReadVar; + this.ob = ob; + this.obstate = &obstate; + } + + override void visit(Expression e) + { + //printf("[%s] %s: %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars()); + //assert(0); + } + + void visitAssign(AssignExp ae, bool initializer) + { + ae.e2.accept(this); + if (auto ve = ae.e1.isVarExp()) + { + if (auto v = ve.var.isVarDeclaration()) + if (isTrackableVar(v)) + dgWriteVar(ob, v, ae.e2, initializer); + } + else + ae.e1.accept(this); + } + + override void visit(AssignExp ae) + { + visitAssign(ae, false); + } + + override void visit(DeclarationExp e) + { + void Dsymbol_visit(Dsymbol s) + { + if (auto vd = s.isVarDeclaration()) + { + s = s.toAlias(); + if (s != vd) + return Dsymbol_visit(s); + if (!isTrackableVar(vd)) + return; + + if (!(vd._init && vd._init.isVoidInitializer())) + { + auto ei = vd._init ? vd._init.isExpInitializer() : null; + if (ei) + visitAssign(cast(AssignExp)ei.exp, true); + else + dgWriteVar(ob, vd, null, false); + } + } + else if (auto td = s.isTupleDeclaration()) + { + foreach (o; *td.objects) + { + if (auto eo = o.isExpression()) + { + if (auto se = eo.isDsymbolExp()) + { + Dsymbol_visit(se.s); + } + } + } + } + } + + Dsymbol_visit(e.declaration); + } + + override void visit(VarExp ve) + { + //printf("VarExp: %s\n", ve.toChars()); + if (auto v = ve.var.isVarDeclaration()) + if (isTrackableVar(v)) + { + dgReadVar(ve.loc, ob, v, isMutableRef(ve.type)); + } + } + + override void visit(CallExp ce) + { + //printf("CallExp() %s\n", ce.toChars()); + ce.e1.accept(this); + auto t = ce.e1.type.toBasetype(); + auto tf = t.isTypeFunction(); + if (!tf) + { + assert(t.ty == Tdelegate); + tf = t.nextOf().isTypeFunction(); + assert(tf); + } + + // j=1 if _arguments[] is first argument + const int j = tf.isDstyleVariadic(); + bool hasOut; + const varStackSave = obstate.varStack.length; + + foreach (const i, arg; (*ce.arguments)[]) + { + if (i - j < tf.parameterList.length && + i >= j) + { + Parameter p = tf.parameterList[i - j]; + auto pt = p.type.toBasetype(); + + EscapeByResults er; + escapeByValue(arg, &er, true); + + if (!(p.storageClass & STC.out_ && arg.isVarExp())) + arg.accept(this); + + void by(VarDeclaration v) + { + if (!isTrackableVar(v)) + return; + + const vi = obstate.vars.find(v); + if (vi == size_t.max) + return; + + auto pvs = &ob.gen[vi]; + + if (p.storageClass & STC.out_) + { + /// initialize + hasOut = true; + makeUndefined(vi, ob.gen); + } + else if (p.storageClass & STC.scope_) + { + // borrow + obstate.varStack.push(vi); + obstate.mutableStack.push(isMutableRef(pt)); + } + else + { + // move (i.e. consume arg) + makeUndefined(vi, ob.gen); + } + } + + foreach (VarDeclaration v2; er.byvalue) + by(v2); + foreach (VarDeclaration v2; er.byref) + by(v2); + } + else // variadic args + { + arg.accept(this); + + EscapeByResults er; + escapeByValue(arg, &er, true); + + void byv(VarDeclaration v) + { + if (!isTrackableVar(v)) + return; + + const vi = obstate.vars.find(v); + if (vi == size_t.max) + return; + + auto pvs = &ob.gen[vi]; + obstate.varStack.push(vi); + obstate.mutableStack.push(isMutableRef(arg.type)); + + // move (i.e. consume arg) + makeUndefined(vi, ob.gen); + } + + foreach (VarDeclaration v2; er.byvalue) + byv(v2); + foreach (VarDeclaration v2; er.byref) + byv(v2); + } + } + + /* Do a dummy 'read' of each variable passed to the function, + * to detect O/B errors + */ + assert(obstate.varStack.length == obstate.mutableStack.length); + foreach (i; varStackSave .. obstate.varStack.length) + { + const vi = obstate.varStack[i]; + auto pvs = &ob.gen[vi]; + auto v = obstate.vars[vi]; + //if (pvs.state == PtrState.Undefined) + //v.error(ce.loc, "is Undefined, cannot pass to function"); + + dgReadVar(ce.loc, ob, v, obstate.mutableStack[i]); + } + + /* Pop off stack all variables for this function call + */ + obstate.varStack.setDim(varStackSave); + obstate.mutableStack.setDim(varStackSave); + + if (hasOut) + // Initialization of out's only happens after the function call + foreach (const i, arg; (*ce.arguments)[]) + { + if (i - j < tf.parameterList.length && + i >= j) + { + Parameter p = tf.parameterList[i - j]; + if (p.storageClass & STC.out_) + { + if (auto v = isTrackableVarExp(arg)) + dgWriteVar(ob, v, null, true); + } + } + } + } + + override void visit(SymOffExp e) + { + if (auto v = e.var.isVarDeclaration()) + if (isTrackableVar(v)) + { + dgReadVar(e.loc, ob, v, isMutableRef(e.type)); + } + } + + override void visit(LogicalExp e) + { + e.e1.accept(this); + + const vlen = obstate.vars.length; + auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof); + PtrVarState[] gen1 = p[0 .. vlen]; + foreach (i, ref pvs; gen1) + { + pvs = ob.gen[i]; + } + + e.e2.accept(this); + + // Merge gen1 into ob.gen + foreach (i; 0 .. vlen) + { + ob.gen[i].combine(gen1[i], i, ob.gen); + } + + mem.xfree(p); // should free .deps too + } + + override void visit(CondExp e) + { + e.econd.accept(this); + + const vlen = obstate.vars.length; + auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof); + PtrVarState[] gen1 = p[0 .. vlen]; + foreach (i, ref pvs; gen1) + { + pvs = ob.gen[i]; + } + + e.e1.accept(this); + + // Swap gen1 with ob.gen + foreach (i; 0 .. vlen) + { + gen1[i].deps.swap(ob.gen[i].deps); + const state = gen1[i].state; + gen1[i].state = ob.gen[i].state; + ob.gen[i].state = state; + } + + e.e2.accept(this); + + /* xxx1 is the state from expression e1, ob.xxx is the state from e2. + * Merge xxx1 into ob.xxx to get the state from `e`. + */ + foreach (i; 0 .. vlen) + { + ob.gen[i].combine(gen1[i], i, ob.gen); + } + + mem.xfree(p); // should free .deps too + } + + override void visit(AddrExp e) + { + /* Taking the address of struct literal is normally not + * allowed, but CTFE can generate one out of a new expression, + * but it'll be placed in static data so no need to check it. + */ + if (e.e1.op != TOK.structLiteral) + e.e1.accept(this); + } + + override void visit(UnaExp e) + { + e.e1.accept(this); + } + + override void visit(BinExp e) + { + e.e1.accept(this); + e.e2.accept(this); + } + + override void visit(ArrayLiteralExp e) + { + Type tb = e.type.toBasetype(); + if (tb.ty == Tsarray || tb.ty == Tarray) + { + if (e.basis) + e.basis.accept(this); + foreach (el; *e.elements) + { + if (el) + el.accept(this); + } + } + } + + override void visit(StructLiteralExp e) + { + if (e.elements) + { + foreach (ex; *e.elements) + { + if (ex) + ex.accept(this); + } + } + } + + override void visit(AssocArrayLiteralExp e) + { + if (e.keys) + { + foreach (i, key; *e.keys) + { + if (key) + key.accept(this); + if (auto value = (*e.values)[i]) + value.accept(this); + } + } + } + + override void visit(NewExp e) + { + Type tb = e.newtype.toBasetype(); + if (e.arguments) + { + foreach (ex; *e.arguments) + { + if (ex) + ex.accept(this); + } + } + } + + override void visit(SliceExp e) + { + e.e1.accept(this); + if (e.lwr) + e.lwr.accept(this); + if (e.upr) + e.upr.accept(this); + } + } + + if (e) + { + scope ExpWalker ew = new ExpWalker(&dgWriteVar, &dgReadVar, ob, obstate); + e.accept(ew); + } + } + + foreachExp(ob, ob.exp); +} + +/*************************************** + * Determine the state of a variable based on + * its type and storage class. + */ +PtrState toPtrState(VarDeclaration v) +{ + /* pointer to mutable: Owner + * pointer to mutable, scope: Borrowed + * pointer to const: Owner + * pointer to const, scope: Readonly + * ref: Borrowed + * const ref: Readonly + */ + auto tb = v.type.toBasetype(); + if (v.isRef()) + { + return tb.isMutable() ? PtrState.Borrowed : PtrState.Readonly; + } + auto tp = tb.isTypePointer(); + assert(tp); + if (v.isScope()) + { + return tp.nextOf().isMutable() ? PtrState.Borrowed : PtrState.Readonly; + } + else + return PtrState.Owner; +} + + +/*************************************** + * Do the data flow analysis (i.e. compute the input[] + * and output[] vectors for each ObNode). + */ +void doDataFlowAnalysis(ref ObState obstate) +{ + enum log = false; + if (log) + printf("-----------------doDataFlowAnalysis()-------------------------\n"); + + if (!obstate.nodes.length) + return; + + auto startnode = obstate.nodes[0]; + assert(startnode.preds.length == 0); + + /* Set opening state `input[]` for first node + */ + foreach (i, ref ps; startnode.input) + { + auto v = obstate.vars[i]; + auto state = toPtrState(v); + if (v.isParameter()) + { + if (v.isOut()) + state = PtrState.Undefined; + else + state = PtrState.Owner; + } + else + state = PtrState.Undefined; + ps.state = state; + ps.deps.zero(); + startnode.gen[i] = ps; + } + + /* Set all output[]s to Undefined + */ + foreach (ob; obstate.nodes[]) + { + foreach (ref ps; ob.output) + { + ps.state = PtrState.Undefined; + ps.deps.zero(); + } + } + + const vlen = obstate.vars.length; + PtrVarState pvs; + pvs.deps.length = vlen; + int counter = 0; + bool changes; + do + { + changes = false; + assert(++counter <= 1000); // should converge, but don't hang if it doesn't + foreach (ob; obstate.nodes[]) + { + /* Construct ob.gen[] by combining the .output[]s of each ob.preds[] + * and set ob.input[] to the same state + */ + if (ob != startnode) + { + assert(ob.preds.length); + + foreach (i; 0 .. vlen) + { + ob.gen[i] = ob.preds[0].output[i]; + } + + foreach (j; 1 .. ob.preds.length) + { + foreach (i; 0 .. vlen) + { + ob.gen[i].combine(ob.preds[j].output[i], i, ob.gen); + } + } + + /* Set ob.input[] to ob.gen[], + * if any changes were made we'll have to do another iteration + */ + foreach (i; 0 .. vlen) + { + if (ob.gen[i] != ob.input[i]) + { + ob.input[i] = ob.gen[i]; + changes = true; + } + } + } + + /* Compute gen[] for node ob + */ + genKill(obstate, ob); + + foreach (i; 0 .. vlen) + { + if (ob.gen[i] != ob.output[i]) + { + ob.output[i] = ob.gen[i]; + changes = true; + } + } + } + } while (changes); + + static if (log) + { + foreach (obi, ob; obstate.nodes) + { + printf("%d: %s\n", obi, ob.exp ? ob.exp.toChars() : "".ptr); + printf(" input:\n"); + foreach (i, ref pvs2; ob.input[]) + { + printf(" %s: ", obstate.vars[i].toChars()); pvs2.print(obstate.vars[]); + } + + printf(" output:\n"); + foreach (i, ref pvs2; ob.output[]) + { + printf(" %s: ", obstate.vars[i].toChars()); pvs2.print(obstate.vars[]); + } + } + printf("\n"); + } +} + + +/*************************************** + * Check for Ownership/Borrowing errors. + */ +void checkObErrors(ref ObState obstate) +{ + enum log = false; + if (log) + printf("------------checkObErrors()----------\n"); + + void dgWriteVar(ObNode* ob, PtrVarState[] cpvs, VarDeclaration v, Expression e) + { + if (log) printf("dgWriteVar(v:%s, e:%s)\n", v.toChars(), e ? e.toChars() : "null"); + const vi = obstate.vars.find(v); + assert(vi != size_t.max); + PtrVarState* pvs = &cpvs[vi]; + if (e) + { + if (isBorrowedPtr(v)) + pvs.state = PtrState.Borrowed; + else if (isReadonlyPtr(v)) + pvs.state = PtrState.Readonly; + else + pvs.state = PtrState.Owner; + pvs.deps.zero(); + + EscapeByResults er; + escapeByValue(e, &er, true); + + void by(VarDeclaration r) // `v` = `r` + { + //printf(" by(%s)\n", r.toChars()); + const ri = obstate.vars.find(r); + if (ri == size_t.max) + return; + + with (PtrState) + { + pvs.deps[ri] = true; // v took from r + auto pvsr = &cpvs[ri]; + + if (pvsr.state == Undefined) + { + v.error(e.loc, "is reading from `%s` which is Undefined", r.toChars()); + } + else if (isBorrowedPtr(v)) // v is going to borrow from r + { + if (pvsr.state == Readonly) + v.error(e.loc, "is borrowing from `%s` which is Readonly", r.toChars()); + + pvs.state = Borrowed; + } + else if (isReadonlyPtr(v)) + { + pvs.state = Readonly; + } + else + { + // move from r to v + pvsr.state = Undefined; + pvsr.deps.zero(); + } + } + } + + foreach (VarDeclaration v2; er.byvalue) + by(v2); + foreach (VarDeclaration v2; er.byref) + by(v2); + } + else + { + if (isBorrowedPtr(v)) + pvs.state = PtrState.Borrowed; + else if (isReadonlyPtr(v)) + pvs.state = PtrState.Readonly; + else + pvs.state = PtrState.Owner; + pvs.deps.zero(); + } + } + + void dgReadVar(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[] gen) + { + if (log) printf("dgReadVar() %s\n", v.toChars()); + const vi = obstate.vars.find(v); + assert(vi != size_t.max); + auto pvs = &gen[vi]; + if (pvs.state == PtrState.Undefined) + v.error(loc, "has undefined state and cannot be read"); + + readVar(ob, vi, mutable, gen); + } + + void foreachExp(ObNode* ob, Expression e, PtrVarState[] cpvs) + { + extern (C++) final class ExpWalker : Visitor + { + alias visit = typeof(super).visit; + extern (D) void delegate(ObNode*, PtrVarState[], VarDeclaration, Expression) dgWriteVar; + extern (D) void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar; + PtrVarState[] cpvs; + ObNode* ob; + ObState* obstate; + + extern (D) this(void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar, + void delegate(ObNode*, PtrVarState[], VarDeclaration, Expression) dgWriteVar, + PtrVarState[] cpvs, ObNode* ob, ref ObState obstate) + { + this.dgReadVar = dgReadVar; + this.dgWriteVar = dgWriteVar; + this.cpvs = cpvs; + this.ob = ob; + this.obstate = &obstate; + } + + override void visit(Expression) + { + } + + override void visit(DeclarationExp e) + { + void Dsymbol_visit(Dsymbol s) + { + if (auto vd = s.isVarDeclaration()) + { + s = s.toAlias(); + if (s != vd) + return Dsymbol_visit(s); + if (!isTrackableVar(vd)) + return; + + if (vd._init && vd._init.isVoidInitializer()) + return; + + auto ei = vd._init ? vd._init.isExpInitializer() : null; + if (ei) + { + auto e = ei.exp; + if (auto ae = e.isConstructExp()) + e = ae.e2; + dgWriteVar(ob, cpvs, vd, e); + } + else + dgWriteVar(ob, cpvs, vd, null); + } + else if (auto td = s.isTupleDeclaration()) + { + foreach (o; *td.objects) + { + if (auto eo = o.isExpression()) + { + if (auto se = eo.isDsymbolExp()) + { + Dsymbol_visit(se.s); + } + } + } + } + } + + Dsymbol_visit(e.declaration); + } + + override void visit(AssignExp ae) + { + ae.e2.accept(this); + if (auto ve = ae.e1.isVarExp()) + { + if (auto v = ve.var.isVarDeclaration()) + if (isTrackableVar(v)) + dgWriteVar(ob, cpvs, v, ae.e2); + } + else + ae.e1.accept(this); + } + + override void visit(VarExp ve) + { + //printf("VarExp: %s\n", ve.toChars()); + if (auto v = ve.var.isVarDeclaration()) + if (isTrackableVar(v)) + { + dgReadVar(ve.loc, ob, v, isMutableRef(ve.type), cpvs); + } + } + + override void visit(CallExp ce) + { + //printf("CallExp(%s)\n", ce.toChars()); + ce.e1.accept(this); + auto t = ce.e1.type.toBasetype(); + auto tf = t.isTypeFunction(); + if (!tf) + { + assert(t.ty == Tdelegate); + tf = t.nextOf().isTypeFunction(); + assert(tf); + } + + // j=1 if _arguments[] is first argument + const int j = tf.isDstyleVariadic(); + bool hasOut; + const varStackSave = obstate.varStack.length; + + foreach (const i, arg; (*ce.arguments)[]) + { + if (i - j < tf.parameterList.length && + i >= j) + { + Parameter p = tf.parameterList[i - j]; + auto pt = p.type.toBasetype(); + + if (!(p.storageClass & STC.out_ && arg.isVarExp())) + arg.accept(this); + + EscapeByResults er; + escapeByValue(arg, &er, true); + + void by(VarDeclaration v) + { + if (!isTrackableVar(v)) + return; + + const vi = obstate.vars.find(v); + if (vi == size_t.max) + return; + + auto pvs = &cpvs[vi]; + + if (p.storageClass & STC.out_) + { + /// initialize + hasOut = true; + makeUndefined(vi, cpvs); + } + else if (p.storageClass & STC.scope_) + { + // borrow + obstate.varStack.push(vi); + obstate.mutableStack.push(isMutableRef(pt)); + } + else + { + // move (i.e. consume arg) + if (pvs.state != PtrState.Owner) + v.error(arg.loc, "is not Owner, cannot consume its value"); + makeUndefined(vi, cpvs); + } + } + + foreach (VarDeclaration v2; er.byvalue) + by(v2); + foreach (VarDeclaration v2; er.byref) + by(v2); + } + else // variadic args + { + arg.accept(this); + + EscapeByResults er; + escapeByValue(arg, &er, true); + + void byv(VarDeclaration v) + { + if (!isTrackableVar(v)) + return; + + const vi = obstate.vars.find(v); + if (vi == size_t.max) + return; + + auto pvs = &cpvs[vi]; + obstate.varStack.push(vi); + obstate.mutableStack.push(isMutableRef(arg.type)); + + // move (i.e. consume arg) + if (pvs.state != PtrState.Owner) + v.error(arg.loc, "is not Owner, cannot consume its value"); + makeUndefined(vi, cpvs); + } + + foreach (VarDeclaration v2; er.byvalue) + byv(v2); + foreach (VarDeclaration v2; er.byref) + byv(v2); + } + } + + /* Do a dummy 'read' of each variable passed to the function, + * to detect O/B errors + */ + assert(obstate.varStack.length == obstate.mutableStack.length); + foreach (i; varStackSave .. obstate.varStack.length) + { + const vi = obstate.varStack[i]; + auto pvs = &cpvs[vi]; + auto v = obstate.vars[vi]; + //if (pvs.state == PtrState.Undefined) + //v.error(ce.loc, "is Undefined, cannot pass to function"); + + dgReadVar(ce.loc, ob, v, obstate.mutableStack[i], cpvs); + + if (pvs.state == PtrState.Owner) + { + for (size_t k = i + 1; k < obstate.varStack.length;++k) + { + const vk = obstate.varStack[k]; + if (vk == vi) + { + if (obstate.mutableStack[vi] || obstate.mutableStack[vk]) + { + v.error(ce.loc, "is passed as Owner more than once"); + break; // no need to continue + } + } + } + } + } + + /* Pop off stack all variables for this function call + */ + obstate.varStack.setDim(varStackSave); + obstate.mutableStack.setDim(varStackSave); + + if (hasOut) + // Initialization of out's only happens after the function call + foreach (const i, arg; (*ce.arguments)[]) + { + if (i - j < tf.parameterList.length && + i >= j) + { + Parameter p = tf.parameterList[i - j]; + if (p.storageClass & STC.out_) + { + if (auto v = isTrackableVarExp(arg)) + { + dgWriteVar(ob, cpvs, v, null); + } + } + } + } + } + + override void visit(SymOffExp e) + { + if (auto v = e.var.isVarDeclaration()) + if (isTrackableVar(v)) + { + dgReadVar(e.loc, ob, v, isMutableRef(e.type), cpvs); + } + } + + override void visit(LogicalExp e) + { + e.e1.accept(this); + + const vlen = obstate.vars.length; + auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof); + PtrVarState[] out1 = p[0 .. vlen]; + foreach (i, ref pvs; out1) + { + pvs = cpvs[i]; + } + + e.e2.accept(this); + + // Merge out1 into cpvs + foreach (i; 0 .. vlen) + { + cpvs[i].combine(out1[i], i, cpvs); + } + + mem.xfree(p); // should free .deps too + } + + override void visit(CondExp e) + { + e.econd.accept(this); + + const vlen = obstate.vars.length; + auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof); + PtrVarState[] out1 = p[0 .. vlen]; + foreach (i, ref pvs; out1) + { + pvs = cpvs[i]; + } + + e.e1.accept(this); + + // Swap out1 with cpvs + foreach (i; 0 .. vlen) + { + out1[i].deps.swap(cpvs[i].deps); + const state = out1[i].state; + out1[i].state = cpvs[i].state; + cpvs[i].state = state; + } + + e.e2.accept(this); + + // Merge out1 into cpvs + foreach (i; 0 .. vlen) + { + cpvs[i].combine(out1[i], i, cpvs); + } + + mem.xfree(p); // should free .deps too + } + + override void visit(AddrExp e) + { + /* Taking the address of struct literal is normally not + * allowed, but CTFE can generate one out of a new expression, + * but it'll be placed in static data so no need to check it. + */ + if (e.e1.op != TOK.structLiteral) + e.e1.accept(this); + } + + override void visit(UnaExp e) + { + e.e1.accept(this); + } + + override void visit(BinExp e) + { + e.e1.accept(this); + e.e2.accept(this); + } + + override void visit(ArrayLiteralExp e) + { + Type tb = e.type.toBasetype(); + if (tb.ty == Tsarray || tb.ty == Tarray) + { + if (e.basis) + e.basis.accept(this); + foreach (el; *e.elements) + { + if (el) + el.accept(this); + } + } + } + + override void visit(StructLiteralExp e) + { + if (e.elements) + { + foreach (ex; *e.elements) + { + if (ex) + ex.accept(this); + } + } + } + + override void visit(AssocArrayLiteralExp e) + { + if (e.keys) + { + foreach (i, key; *e.keys) + { + if (key) + key.accept(this); + if (auto value = (*e.values)[i]) + value.accept(this); + } + } + } + + override void visit(NewExp e) + { + Type tb = e.newtype.toBasetype(); + if (e.arguments) + { + foreach (ex; *e.arguments) + { + if (ex) + ex.accept(this); + } + } + } + + override void visit(SliceExp e) + { + e.e1.accept(this); + if (e.lwr) + e.lwr.accept(this); + if (e.upr) + e.upr.accept(this); + } + } + + if (e) + { + scope ExpWalker ew = new ExpWalker(&dgReadVar, &dgWriteVar, cpvs, ob, obstate); + e.accept(ew); + } + } + + const vlen = obstate.vars.length; + auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof); + PtrVarState[] cpvs = p[0 .. vlen]; + foreach (ref pvs; cpvs) + pvs.deps.length = vlen; + + foreach (obi, ob; obstate.nodes) + { + static if (log) + { + printf("%d: %s\n", obi, ob.exp ? ob.exp.toChars() : "".ptr); + printf(" input:\n"); + foreach (i, ref pvs; ob.input[]) + { + printf(" %s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]); + } + } + + /* Combine the .output[]s of each ob.preds[] looking for errors + */ + if (obi) // skip startnode + { + assert(ob.preds.length); + + foreach (i; 0 .. vlen) + { + ob.gen[i] = ob.preds[0].output[i]; + } + + foreach (j; 1 .. ob.preds.length) + { + foreach (i; 0 .. vlen) + { + auto pvs1 = &ob.gen[i]; + auto pvs2 = &ob.preds[j].output[i]; + const s1 = pvs1.state; + const s2 = pvs2.state; + if (s1 != s2 && (s1 == PtrState.Owner || s2 == PtrState.Owner)) + { + auto v = obstate.vars[i]; + v.error(ob.exp ? ob.exp.loc : v.loc, "is both %s and %s", s1.toChars(), s2.toChars()); + } + pvs1.combine(*pvs2, i, ob.gen); + } + } + } + + /* Prolly should use gen[] instead of cpvs[], or vice versa + */ + foreach (i, ref pvs; ob.input) + { + cpvs[i] = pvs; + } + + foreachExp(ob, ob.exp, cpvs); + + static if (log) + { + printf(" cpvs:\n"); + foreach (i, ref pvs; cpvs[]) + { + printf(" %s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]); + } + printf(" output:\n"); + foreach (i, ref pvs; ob.output[]) + { + printf(" %s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]); + } + } + + if (ob.obtype == ObType.retexp) + { + EscapeByResults er; + escapeByValue(ob.exp, &er, true); + + void by(VarDeclaration r) // `r` is the rvalue + { + const ri = obstate.vars.find(r); + if (ri == size_t.max) + return; + with (PtrState) + { + auto pvsr = &ob.output[ri]; + switch (pvsr.state) + { + case Undefined: + r.error(ob.exp.loc, "is returned but is Undefined"); + break; + + case Owner: + pvsr.state = Undefined; // returning a pointer "consumes" it + break; + + case Borrowed: + case Readonly: + break; + + default: + assert(0); + } + } + } + + foreach (VarDeclaration v2; er.byvalue) + by(v2); + foreach (VarDeclaration v2; er.byref) + by(v2); + } + + if (ob.obtype == ObType.return_ || ob.obtype == ObType.retexp) + { + foreach (i, ref pvs; ob.output[]) + { + //printf("%s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]); + if (pvs.state == PtrState.Owner) + { + auto v = obstate.vars[i]; + v.error(v.loc, "is left dangling at return"); + } + } + } + } +} + + +/*************************************************** + * Read from variable vi. + * The beginning of the 'scope' of a variable is when it is first read. + * Hence, when a read is done, instead of when assignment to the variable is done, the O/B rules are enforced. + * (Also called "non-lexical scoping".) + */ +void readVar(ObNode* ob, const size_t vi, bool mutable, PtrVarState[] gen) +{ + //printf("readVar(v%d)\n", cast(int)vi); + auto pvso = &gen[vi]; + switch (pvso.state) + { + case PtrState.Owner: + //printf("t: %s\n", t.toChars()); + if (mutable) // if mutable read + { + makeChildrenUndefined(vi, gen); + } + else // const read + { + // If there's a Borrow child, set that to Undefined + foreach (di; 0 .. gen.length) + { + auto pvsd = &gen[di]; + if (pvsd.deps[vi] && pvsd.state == PtrState.Borrowed) // if di borrowed vi + { + makeUndefined(di, gen); + } + } + } + break; + + case PtrState.Borrowed: + /* All children become Undefined + */ + makeChildrenUndefined(vi, gen); + break; + + case PtrState.Readonly: + break; + + case PtrState.Undefined: + break; + + default: + break; + } +} + +/******************** + * Recursively make Undefined all who list vi as a dependency + */ +void makeChildrenUndefined(size_t vi, PtrVarState[] gen) +{ + //printf("makeChildrenUndefined(%d)\n", vi); + auto pvs = &gen[vi]; + foreach (di; 0 .. gen.length) + { + if (gen[di].deps[vi]) // if di depends on vi + { + if (gen[di].state != PtrState.Undefined) + { + gen[di].state = PtrState.Undefined; // set this first to avoid infinite recursion + makeChildrenUndefined(di, gen); + gen[di].deps.zero(); + } + } + } +} + + +/******************** + * Recursively make Undefined vi undefined and all who list vi as a dependency + */ +void makeUndefined(size_t vi, PtrVarState[] gen) +{ + auto pvs = &gen[vi]; + pvs.state = PtrState.Undefined; // set this first to avoid infinite recursion + makeChildrenUndefined(vi, gen); + pvs.deps.zero(); +} + +/************************* + * Is type `t` a reference to a const or a reference to a mutable? + */ +bool isMutableRef(Type t) +{ + auto tb = t.toBasetype(); + return (tb.nextOf() ? tb.nextOf() : tb).isMutable(); +} diff --git a/dmd/objc.d b/dmd/objc.d index 8b2e685679f..4fb2b866e32 100644 --- a/dmd/objc.d +++ b/dmd/objc.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/objc.d, _objc.d) @@ -502,7 +502,7 @@ else { assert(id.classKind == ClassKind.objc); } - body + do { // don't report deprecations for the metaclass to avoid duplicated // messages. @@ -576,7 +576,7 @@ else assert(fd.selector); assert(fd.isMember); } - body + do { // * final member functions are kept virtual with Objective-C linkage // because the Objective-C runtime always use dynamic dispatch. @@ -591,7 +591,7 @@ else { assert(metaclass); } - body + do { if (cd.classKind == ClassKind.objc && fd.isStatic && !cd.objc.isMeta) return cd.objc.metaclass; @@ -604,7 +604,7 @@ else { assert(fd.parent.isClassDeclaration); } - body + do { if (cd.classKind != ClassKind.objc) return; @@ -642,7 +642,7 @@ else { assert(fd.selectorParameter is null); } - body + do { if (!fd.selector) return null; diff --git a/dmd/objc.h b/dmd/objc.h index e328ebd24a6..257b463faeb 100644 --- a/dmd/objc.h +++ b/dmd/objc.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2015-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2015-2020 by The D Language Foundation, All Rights Reserved * written by Michel Fortin * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/opover.d b/dmd/opover.d index 57645de6c79..9acf4af09ba 100644 --- a/dmd/opover.d +++ b/dmd/opover.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/opover.d, _opover.d) diff --git a/dmd/optimize.d b/dmd/optimize.d index ee383af477e..a3656362fa3 100644 --- a/dmd/optimize.d +++ b/dmd/optimize.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d, _optimize.d) @@ -1153,7 +1153,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) size_t b; while (1) { - if (b++ == 500) + if (b++ == global.recursionLimit) { e.error("infinite loop while optimizing expression"); fatal(); diff --git a/dmd/parse.d b/dmd/parse.d index 3fe228eba2d..34e9e65f828 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d) @@ -23,8 +23,8 @@ import dmd.root.filename; import dmd.root.outbuffer; import dmd.root.rmem; import dmd.root.rootobject; +import dmd.root.string; import dmd.tokens; -import dmd.utils; // How multiple declarations are parsed. // If 1, treat as C. @@ -294,10 +294,9 @@ final class Parser(AST) : Lexer * Input: * loc location in source file of mixin */ - extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, - bool doDocComment, DiagnosticReporter diagnosticReporter) + extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment) { - super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, diagnosticReporter); + super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false); //printf("Parser::Parser()\n"); scanloc = loc; @@ -317,9 +316,9 @@ final class Parser(AST) : Lexer //nextToken(); // start up the scanner } - extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, DiagnosticReporter diagnosticReporter) + extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment) { - super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, diagnosticReporter); + super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false); //printf("Parser::Parser()\n"); mod = _module; @@ -656,10 +655,6 @@ final class Parser(AST) : Lexer s = parseNew(pAttrs); break; - case TOK.delete_: - s = parseDelete(pAttrs); - break; - case TOK.colon: case TOK.leftCurly: error("declaration expected, not `%s`", token.toChars()); @@ -710,7 +705,7 @@ final class Parser(AST) : Lexer } else if (next == TOK.foreach_ || next == TOK.foreach_reverse_) { - s = parseForeach!(true,true)(loc, pLastDecl); + s = parseForeach!(true,true)(token.loc, pLastDecl); } else { @@ -840,6 +835,15 @@ final class Parser(AST) : Lexer tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body)) { + version (none) + { + // This deprecation has been disabled for the time being, see PR10763 + // @@@DEPRECATED@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.091 - Can be removed from 2.101 + if (tk.value == TOK.identifier && tk.ident == Id._body) + deprecation("Usage of the `body` keyword is deprecated. Use `do` instead."); + } a = parseDeclarations(true, pAttrs, pAttrs.comment); if (a && a.dim) *pLastDecl = (*a)[a.dim - 1]; @@ -2787,27 +2791,6 @@ final class Parser(AST) : Lexer return s; } - /***************************************** - * Parse a delete definition: - * delete(parameters) { body } - * Current token is 'delete'. - */ - private AST.Dsymbol parseDelete(PrefixAttributes!AST* pAttrs) - { - const loc = token.loc; - StorageClass stc = getStorageClass!AST(pAttrs); - - nextToken(); - - AST.VarArg varargs; - AST.Parameters* parameters = parseParameters(&varargs); - if (varargs != AST.VarArg.none) - error("`...` not allowed in delete function parameter list"); - auto f = new AST.DeleteDeclaration(loc, Loc.initial, stc, parameters); - AST.Dsymbol s = parseContracts(f); - return s; - } - /********************************************** * Parse parameter list. */ @@ -3088,6 +3071,7 @@ final class Parser(AST) : Lexer else if (token.value == TOK.leftCurly) { bool isAnonymousEnum = !id; + TOK prevTOK; //printf("enum definition\n"); e.members = new AST.Dsymbols(); @@ -3127,6 +3111,7 @@ final class Parser(AST) : Lexer AST.stcToBuffer(&buf, _stc); error(attributeErrorMessage, buf.peekChars()); } + prevTOK = token.value; nextToken(); } break; @@ -3134,6 +3119,7 @@ final class Parser(AST) : Lexer if (StorageClass _stc = parseDeprecatedAttribute(deprecationMessage)) { stc |= _stc; + prevTOK = token.value; nextToken(); } break; @@ -3143,6 +3129,7 @@ final class Parser(AST) : Lexer { ident = token.ident; type = null; + prevTOK = token.value; nextToken(); } else @@ -3157,16 +3144,26 @@ final class Parser(AST) : Lexer if (type == AST.Type.terror) { type = null; + prevTOK = token.value; nextToken(); } + else + { + prevTOK = TOK.identifier; + } } else { error(attributeErrorMessage, token.toChars()); + prevTOK = token.value; nextToken(); } break; } + if (token.value == TOK.comma) + { + prevTOK = token.value; + } } if (type && type != AST.Type.terror) @@ -3176,12 +3173,19 @@ final class Parser(AST) : Lexer if (!isAnonymousEnum) error("type only allowed if anonymous enum and no enum type"); } - AST.Expression value; if (token.value == TOK.assign) { - nextToken(); - value = parseAssignExp(); + if (prevTOK == TOK.identifier) + { + nextToken(); + value = parseAssignExp(); + } + else + { + error("assignment must be preceded by an identifier"); + nextToken(); + } } else { @@ -4627,6 +4631,15 @@ final class Parser(AST) : Lexer (tk.value == TOK.leftParentheses || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body)) { + version (none) + { + // This deprecation has been disabled for the time being, see PR10763 + // @@@DEPRECATED@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.091 - Can be removed from 2.101 + if (tk.value == TOK.identifier && tk.ident == Id._body) + deprecation("Usage of the `body` keyword is deprecated. Use `do` instead."); + } ts = null; } else @@ -4991,7 +5004,17 @@ final class Parser(AST) : Lexer case TOK.identifier: if (token.ident == Id._body) + { + version (none) + { + // This deprecation has been disabled for the time being, see PR10763 + // @@@DEPRECATED@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.091 - Can be removed from 2.101 + deprecation("Usage of the `body` keyword is deprecated. Use `do` instead."); + } goto case TOK.do_; + } goto default; case TOK.do_: @@ -6610,10 +6633,13 @@ final class Parser(AST) : Lexer if (token.value == TOK.colon) { nextToken(); - AST.ExpInitializer expInit = value.isExpInitializer(); - assert(expInit); - e = expInit.exp; - value = parseInitializer(); + if (auto ei = value.isExpInitializer()) + { + e = ei.exp; + value = parseInitializer(); + } + else + error("initializer expression expected following colon, not `%s`", token.toChars()); } else e = null; @@ -7182,7 +7208,17 @@ final class Parser(AST) : Lexer case TOK.identifier: if (t.ident == Id._body) + { + version (none) + { + // This deprecation has been disabled for the time being, see PR10763 + // @@@DEPRECATED@@@ + // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md + // Deprecated in 2.091 - Can be removed from 2.101 + deprecation("Usage of the `body` keyword is deprecated. Use `do` instead."); + } goto case TOK.do_; + } goto default; case TOK.if_: @@ -8992,7 +9028,7 @@ final class Parser(AST) : Lexer auto edim = AST.typeToExpression(index); if (!edim) { - error("need size of rightmost array, not type `%s`", index.toChars()); + error("cannot create a `%s` with `new`", t.toChars); return new AST.NullExp(loc); } t = new AST.TypeSArray(taa.next, edim); @@ -9037,6 +9073,7 @@ final class Parser(AST) : Lexer (ident == Id.safe) ? AST.STC.safe : (ident == Id.trusted) ? AST.STC.trusted : (ident == Id.system) ? AST.STC.system : + (ident == Id.live) ? AST.STC.live : (ident == Id.future) ? AST.STC.future : (ident == Id.disable) ? AST.STC.disable : 0; @@ -9048,6 +9085,7 @@ final class Parser(AST) : Lexer AST.STC.safe | AST.STC.trusted | AST.STC.system | + AST.STC.live | /*AST.STC.future |*/ // probably should be included AST.STC.disable; } diff --git a/dmd/parsetimevisitor.d b/dmd/parsetimevisitor.d index ce3735eb09b..d951faa8418 100644 --- a/dmd/parsetimevisitor.d +++ b/dmd/parsetimevisitor.d @@ -55,7 +55,6 @@ public: void visit(AST.InvariantDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.UnitTestDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.NewDeclaration s) { visit(cast(AST.FuncDeclaration)s); } - void visit(AST.DeleteDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.StaticCtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.StaticDtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); } void visit(AST.SharedStaticCtorDeclaration s) { visit(cast(AST.StaticCtorDeclaration)s); } diff --git a/dmd/printast.d b/dmd/printast.d index bd5cb23576a..e513bb422e5 100644 --- a/dmd/printast.d +++ b/dmd/printast.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/printast.d, _printast.d) diff --git a/dmd/root/aav.d b/dmd/root/aav.d index c4dbc43c3f2..82e0878d267 100644 --- a/dmd/root/aav.d +++ b/dmd/root/aav.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d, root/_aav.d) diff --git a/dmd/root/array.d b/dmd/root/array.d index e8ceff55a89..dca7c3b78bf 100644 --- a/dmd/root/array.d +++ b/dmd/root/array.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/array.d, root/_array.d) @@ -15,6 +15,7 @@ module dmd.root.array; import core.stdc.string; import dmd.root.rmem; +import dmd.root.string; debug { @@ -52,32 +53,51 @@ public: ///returns elements comma separated in [] extern(D) const(char)[] toString() const { - static if (is(typeof(T.init.toString()))) + static const(char)[] toStringImpl(alias toStringFunc, Array)(Array* a, bool quoted = false) { - const(char)[][] buf = (cast(const(char)[]*)mem.xcalloc((char[]).sizeof, length))[0 .. length]; + const(char)[][] buf = (cast(const(char)[]*)mem.xcalloc((char[]).sizeof, a.length))[0 .. a.length]; size_t len = 2; // [ and ] - foreach (u; 0 .. length) + const seplen = quoted ? 3 : 1; // ',' or null terminator and optionally '"' + if (a.length == 0) + len += 1; // null terminator + else { - buf[u] = data[u].toString(); - len += buf[u].length + 1; //length + ',' or null terminator + foreach (u; 0 .. a.length) + { + buf[u] = toStringFunc(a.data[u]); + len += buf[u].length + seplen; + } } char[] str = (cast(char*)mem.xmalloc_noscan(len))[0..len]; str[0] = '['; char* p = str.ptr + 1; - foreach (u; 0 .. length) + foreach (u; 0 .. a.length) { if (u) *p++ = ','; + if (quoted) + *p++ = '"'; memcpy(p, buf[u].ptr, buf[u].length); p += buf[u].length; + if (quoted) + *p++ = '"'; } *p++ = ']'; *p = 0; - assert(p - str.ptr == str.length - 1); //null terminator + assert(p - str.ptr == str.length - 1); // null terminator mem.xfree(buf.ptr); return str[0 .. $-1]; } + + static if (is(typeof(T.init.toString()))) + { + return toStringImpl!(a => a.toString)(&this); + } + else static if (is(typeof(T.init.toDString()))) + { + return toStringImpl!(a => a.toDString)(&this, true); + } else { assert(0); @@ -282,6 +302,7 @@ public: unittest { + // Test for objects implementing toString() static struct S { int s = -1; @@ -292,6 +313,17 @@ unittest } auto array = Array!S(4); assert(array.toString() == "[S,S,S,S]"); + array.setDim(0); + assert(array.toString() == "[]"); + + // Test for toDString() + auto strarray = Array!(const(char)*)(2); + strarray[0] = "hello"; + strarray[1] = "world"; + auto str = strarray.toString(); + assert(str == `["hello","world"]`); + // Test presence of null terminator. + assert(str.ptr[str.length] == '\0'); } unittest diff --git a/dmd/root/array.h b/dmd/root/array.h index add63fe00d3..b1a8b675505 100644 --- a/dmd/root/array.h +++ b/dmd/root/array.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 2011-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/bitarray.d b/dmd/root/bitarray.d index 71ccf3dcc9b..b1509843b51 100644 --- a/dmd/root/bitarray.d +++ b/dmd/root/bitarray.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d, root/_bitarray.d) diff --git a/dmd/root/bitarray.h b/dmd/root/bitarray.h index de0a3a39dd3..7fc17856f0f 100644 --- a/dmd/root/bitarray.h +++ b/dmd/root/bitarray.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 2011-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/ctfloat.d b/dmd/root/ctfloat.d index 4f8c50efa90..3a90f78b4d4 100644 --- a/dmd/root/ctfloat.d +++ b/dmd/root/ctfloat.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d, root/_ctfloat.d) diff --git a/dmd/root/ctfloat.h b/dmd/root/ctfloat.h index 0c51bac5868..304b178fcb7 100644 --- a/dmd/root/ctfloat.h +++ b/dmd/root/ctfloat.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/dcompat.h b/dmd/root/dcompat.h index 7209ec758fc..19f942031a2 100644 --- a/dmd/root/dcompat.h +++ b/dmd/root/dcompat.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/dsystem.h b/dmd/root/dsystem.h index 43447e51a20..5c66f0e5419 100644 --- a/dmd/root/dsystem.h +++ b/dmd/root/dsystem.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/file.d b/dmd/root/file.d index f012f35a51a..00958026ba4 100644 --- a/dmd/root/file.d +++ b/dmd/root/file.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/file.d, root/_file.d) @@ -24,7 +24,7 @@ version (Windows) } import dmd.root.filename; import dmd.root.rmem; -import dmd.utils; +import dmd.root.string; /// Owns a (rmem-managed) file buffer. struct FileBuffer diff --git a/dmd/root/file.h b/dmd/root/file.h index 74725a8bca2..8be6cd4dad3 100644 --- a/dmd/root/file.h +++ b/dmd/root/file.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/filename.d b/dmd/root/filename.d index cd1ae168b02..80f93cf878e 100644 --- a/dmd/root/filename.d +++ b/dmd/root/filename.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.d, root/_filename.d) @@ -21,7 +21,7 @@ import dmd.root.outbuffer; import dmd.root.port; import dmd.root.rmem; import dmd.root.rootobject; -import dmd.utils; +import dmd.root.string; version (Posix) { diff --git a/dmd/root/filename.h b/dmd/root/filename.h index 0a4cc1d02f7..635d87811c9 100644 --- a/dmd/root/filename.h +++ b/dmd/root/filename.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/hash.d b/dmd/root/hash.d index e978b1e7de9..9a66686f35f 100644 --- a/dmd/root/hash.d +++ b/dmd/root/hash.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Martin Nowak, Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d, root/_hash.d) diff --git a/dmd/root/longdouble.d b/dmd/root/longdouble.d index 5a60c529fde..5b6ae9c85a9 100644 --- a/dmd/root/longdouble.d +++ b/dmd/root/longdouble.d @@ -1,4 +1,4 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Rainer Schuetze * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/longdouble.h b/dmd/root/longdouble.h index f7a8ee09b88..86da02315f4 100644 --- a/dmd/root/longdouble.h +++ b/dmd/root/longdouble.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Rainer Schuetze * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/man.d b/dmd/root/man.d index 4877e56ae26..ce80b743865 100644 --- a/dmd/root/man.d +++ b/dmd/root/man.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/man.d, root/_man.d) @@ -27,7 +27,7 @@ version (Windows) { assert(strncmp(url, "http://", 7) == 0 || strncmp(url, "https://", 8) == 0); } - body + do { ShellExecuteA(null, "open", url, null, null, SW_SHOWNORMAL); } @@ -39,7 +39,7 @@ else version (OSX) { assert(strncmp(url, "http://", 7) == 0 || strncmp(url, "https://", 8) == 0); } - body + do { pid_t childpid; const(char)*[5] args; @@ -73,7 +73,7 @@ else version (Posix) { assert(strncmp(url, "http://", 7) == 0 || strncmp(url, "https://", 8) == 0); } - body + do { pid_t childpid; const(char)*[3] args; diff --git a/dmd/root/object.h b/dmd/root/object.h index 0b3da705de3..54d3efd2bc5 100644 --- a/dmd/root/object.h +++ b/dmd/root/object.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/outbuffer.d b/dmd/root/outbuffer.d index 727499e40d6..b647116826e 100644 --- a/dmd/root/outbuffer.d +++ b/dmd/root/outbuffer.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d, root/_outbuffer.d) @@ -17,7 +17,7 @@ import core.stdc.stdio; import core.stdc.string; import dmd.root.rmem; import dmd.root.rootobject; -import dmd.utils; +import dmd.root.string; debug { diff --git a/dmd/root/outbuffer.h b/dmd/root/outbuffer.h index 401339c75ca..1ad19b027b7 100644 --- a/dmd/root/outbuffer.h +++ b/dmd/root/outbuffer.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/port.d b/dmd/root/port.d index d1441982667..eed2e43bc8c 100644 --- a/dmd/root/port.d +++ b/dmd/root/port.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d, root/_port.d) diff --git a/dmd/root/port.h b/dmd/root/port.h index 2e3a7032e98..d915d4e847f 100644 --- a/dmd/root/port.h +++ b/dmd/root/port.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/region.d b/dmd/root/region.d index 47d9eb96db5..ce58cd2c8d1 100644 --- a/dmd/root/region.d +++ b/dmd/root/region.d @@ -4,7 +4,7 @@ * * Region storage allocator implementation. * - * Copyright: Copyright (C) 2019-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 2019-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d, root/_region.d) diff --git a/dmd/root/rmem.d b/dmd/root/rmem.d index 672e0bbe8ef..618379507f0 100644 --- a/dmd/root/rmem.d +++ b/dmd/root/rmem.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d, root/_rmem.d) @@ -213,6 +213,13 @@ else version (GNU) { enum OVERRIDE_MEMALLOC = true; } +else version (GNU) +{ + version (IN_GCC) + enum OVERRIDE_MEMALLOC = false; + else + enum OVERRIDE_MEMALLOC = true; +} else { enum OVERRIDE_MEMALLOC = false; diff --git a/dmd/root/rmem.h b/dmd/root/rmem.h index cfbc8a21171..1bfbd39e3be 100644 --- a/dmd/root/rmem.h +++ b/dmd/root/rmem.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/root.h b/dmd/root/root.h index 2225f2c107b..3c1655cb9df 100644 --- a/dmd/root/root.h +++ b/dmd/root/root.h @@ -1,5 +1,5 @@ -/* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved +/* Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * All Rights Reserved, written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/root/rootobject.d b/dmd/root/rootobject.d index bb84a04b32d..3a8dcfffe57 100644 --- a/dmd/root/rootobject.d +++ b/dmd/root/rootobject.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rootobject.d, root/_rootobject.d) diff --git a/dmd/root/speller.d b/dmd/root/speller.d index 4e4ec86e4c1..ef7ac4cf866 100644 --- a/dmd/root/speller.d +++ b/dmd/root/speller.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/speller.d, root/_speller.d) diff --git a/dmd/root/string.d b/dmd/root/string.d new file mode 100644 index 00000000000..383bf9a5cce --- /dev/null +++ b/dmd/root/string.d @@ -0,0 +1,173 @@ +/** + * This module contains various string related functions. + * + * Compiler implementation of the D programming language + * http://dlang.org + * + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved + * Authors: Walter Bright, http://www.digitalmars.com + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/string.d, root/_string.d) + * Documentation: https://dlang.org/phobos/dmd_root_string.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/string.d + */ +module dmd.root.string; + +/// Slices a `\0`-terminated C-string, excluding the terminator +inout(char)[] toDString (inout(char)* s) pure nothrow @nogc +{ + import core.stdc.string : strlen; + return s ? s[0 .. strlen(s)] : null; +} + +/** +Compare two slices for equality, in a case-insensitive way + +Comparison is based on `char` and does not do decoding. +As a result, it's only really accurate for plain ASCII strings. + +Params: +s1 = string to compare +s2 = string to compare + +Returns: +`true` if `s1 == s2` regardless of case +*/ +extern(D) static bool iequals(const(char)[] s1, const(char)[] s2) +{ + import core.stdc.ctype : toupper; + + if (s1.length != s2.length) + return false; + + foreach (idx, c1; s1) + { + // Since we did a length check, it is safe to bypass bounds checking + const c2 = s2.ptr[idx]; + if (c1 != c2) + if (toupper(c1) != toupper(c2)) + return false; + } + return true; +} + +/** +Copy the content of `src` into a C-string ('\0' terminated) then call `dg` + +The intent of this function is to provide an allocation-less +way to call a C function using a D slice. +The function internally allocates a buffer if needed, but frees it on exit. + +Note: +The argument to `dg` is `scope`. To keep the data around after `dg` exits, +one has to copy it. + +Params: +src = Slice to use to call the C function +dg = Delegate to call afterwards + +Returns: +The return value of `T` +*/ +auto toCStringThen(alias dg)(const(char)[] src) nothrow +{ + import dmd.root.rmem : mem; + + const len = src.length + 1; + char[512] small = void; + scope ptr = (src.length < (small.length - 1)) + ? small[0 .. len] + : (cast(char*)mem.xmalloc(len))[0 .. len]; + scope (exit) + { + if (&ptr[0] != &small[0]) + mem.xfree(&ptr[0]); + } + ptr[0 .. src.length] = src[]; + ptr[src.length] = '\0'; + return dg(ptr); +} + +unittest +{ + assert("Hello world".toCStringThen!((v) => v == "Hello world\0")); + assert("Hello world\0".toCStringThen!((v) => v == "Hello world\0\0")); + assert(null.toCStringThen!((v) => v == "\0")); +} + +/** + * Strips one leading line terminator of the given string. + * + * The following are what the Unicode standard considers as line terminators: + * + * | Name | D Escape Sequence | Unicode Code Point | + * |---------------------|-------------------|--------------------| + * | Line feed | `\n` | `U+000A` | + * | Line tabulation | `\v` | `U+000B` | + * | Form feed | `\f` | `U+000C` | + * | Carriage return | `\r` | `U+000D` | + * | Next line | | `U+0085` | + * | Line separator | | `U+2028` | + * | Paragraph separator | | `U+2029` | + * + * This function will also strip `\n\r`. + */ +string stripLeadingLineTerminator(string str) pure nothrow @nogc @safe +{ + enum nextLine = "\xC2\x85"; + enum lineSeparator = "\xE2\x80\xA8"; + enum paragraphSeparator = "\xE2\x80\xA9"; + + if (str.length == 0) + return str; + + switch (str[0]) + { + case '\n': + { + if (str.length >= 2 && str[1] == '\r') + return str[2 .. $]; + goto case; + } + case '\v', '\f', '\r': return str[1 .. $]; + + case nextLine[0]: + { + if (str.length >= 2 && str[0 .. 2] == nextLine) + return str[2 .. $]; + + return str; + } + + case lineSeparator[0]: + { + if (str.length >= 3) + { + const prefix = str[0 .. 3]; + + if (prefix == lineSeparator || prefix == paragraphSeparator) + return str[3 .. $]; + } + + return str; + } + + default: return str; + } +} + +unittest +{ + assert("".stripLeadingLineTerminator == ""); + assert("foo".stripLeadingLineTerminator == "foo"); + assert("\xC2foo".stripLeadingLineTerminator == "\xC2foo"); + assert("\xE2foo".stripLeadingLineTerminator == "\xE2foo"); + assert("\nfoo".stripLeadingLineTerminator == "foo"); + assert("\vfoo".stripLeadingLineTerminator == "foo"); + assert("\ffoo".stripLeadingLineTerminator == "foo"); + assert("\rfoo".stripLeadingLineTerminator == "foo"); + assert("\u0085foo".stripLeadingLineTerminator == "foo"); + assert("\u2028foo".stripLeadingLineTerminator == "foo"); + assert("\u2029foo".stripLeadingLineTerminator == "foo"); + assert("\n\rfoo".stripLeadingLineTerminator == "foo"); +} diff --git a/dmd/root/stringtable.d b/dmd/root/stringtable.d index f2d0ce020f0..3c073339e8a 100644 --- a/dmd/root/stringtable.d +++ b/dmd/root/stringtable.d @@ -2,7 +2,7 @@ * Compiler implementation of the D programming language * http://dlang.org * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: Walter Bright, http://www.digitalmars.com * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d, root/_stringtable.d) diff --git a/dmd/safe.d b/dmd/safe.d index 10b44a3c2a2..ead32c77fcf 100644 --- a/dmd/safe.d +++ b/dmd/safe.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/safe.d, _safe.d) diff --git a/dmd/sapply.d b/dmd/sapply.d index 8f523c35e2f..7f36ac7c315 100644 --- a/dmd/sapply.d +++ b/dmd/sapply.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sparse.d, _sparse.d) diff --git a/dmd/scope.h b/dmd/scope.h index 438fdcb7666..944a8b54d30 100644 --- a/dmd/scope.h +++ b/dmd/scope.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -52,9 +52,10 @@ class CPPNamespaceDeclaration; #define SCOPEctfe 0x0080 // inside a ctfe-only expression #define SCOPEcompile 0x0100 // inside __traits(compile) #define SCOPEignoresymbolvisibility 0x0200 // ignore symbol visibility (Bugzilla 15907) -#define SCOPEfullinst 0x1000 // fully instantiate templates #define SCOPEfree 0x8000 // is on free list +#define SCOPEfullinst 0x10000 // fully instantiate templates +#define SCOPEalias 0x20000 // inside alias declaration struct Scope { diff --git a/dmd/semantic2.d b/dmd/semantic2.d index 9b8b02c5ac1..94d04279a67 100644 --- a/dmd/semantic2.d +++ b/dmd/semantic2.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d, _semantic2.d) @@ -61,7 +61,6 @@ import dmd.statementsem; import dmd.staticassert; import dmd.tokens; import dmd.utf; -import dmd.utils; import dmd.statement; import dmd.target; import dmd.templateparamsem; diff --git a/dmd/semantic3.d b/dmd/semantic3.d index 84bbc7c9696..c2879161cea 100644 --- a/dmd/semantic3.d +++ b/dmd/semantic3.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d, _semantic3.d) @@ -50,6 +50,7 @@ import dmd.hdrgen; import dmd.mtype; import dmd.nogc; import dmd.nspace; +import dmd.ob; import dmd.objc; import dmd.opover; import dmd.parse; @@ -62,7 +63,6 @@ import dmd.statementsem; import dmd.staticassert; import dmd.tokens; import dmd.utf; -import dmd.utils; import dmd.semantic2; import dmd.statement; import dmd.target; @@ -314,9 +314,7 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.sw = null; sc2.fes = funcdecl.fes; sc2.linkage = LINK.d; - sc2.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.abstract_ | STC.deprecated_ | STC.override_ | - STC.TYPECTOR | STC.final_ | STC.tls | STC.gshared | STC.ref_ | STC.return_ | STC.property | - STC.nothrow_ | STC.pure_ | STC.safe | STC.trusted | STC.system); + sc2.stc &= STCFlowThruFunction; sc2.protection = Prot(Prot.Kind.public_); sc2.explicitProtection = 0; sc2.aligndecl = null; @@ -488,8 +486,10 @@ version (IN_LLVM) stc |= STC.scope_; } } - if (funcdecl.flags & FUNCFLAG.inferScope && !(fparam.storageClass & STC.scope_)) + + if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_)) stc |= STC.maybescope; + stc |= fparam.storageClass & (STC.in_ | STC.out_ | STC.ref_ | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor); v.storage_class = stc; v.dsymbolSemantic(sc2); @@ -661,7 +661,9 @@ version (IN_LLVM) if (funcdecl.storage_class & STC.auto_) funcdecl.storage_class &= ~STC.auto_; } - if (!target.isReturnOnStack(f, funcdecl.needThis())) + + // handle NRVO + if (!target.isReturnOnStack(f, funcdecl.needThis()) || funcdecl.checkNrvo()) funcdecl.nrvo_can = 0; if (funcdecl.fbody.isErrorStatement()) @@ -1385,6 +1387,12 @@ else sc = sc.pop(); } + // Do live analysis + if (funcdecl.fbody && funcdecl.type.ty != Terror && funcdecl.type.isTypeFunction().islive) + { + oblive(funcdecl); + } + /* If this function had instantiated with gagging, error reproduction will be * done by TemplateInstance::semantic. * Otherwise, error gagging should be temporarily ungagged by functionSemantic3. diff --git a/dmd/sideeffect.d b/dmd/sideeffect.d index f729e62b79f..0211d0499f1 100644 --- a/dmd/sideeffect.d +++ b/dmd/sideeffect.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d, _sideeffect.d) @@ -390,7 +390,16 @@ VarDeclaration copyToTemp(StorageClass stc, const char[] name, Expression e) Expression extractSideEffect(Scope* sc, const char[] name, ref Expression e0, Expression e, bool alwaysCopy = false) { - if (!alwaysCopy && isTrivialExp(e)) + //printf("extractSideEffect(e: %s)\n", e.toChars()); + + /* The trouble here is that if CTFE is running, extracting the side effect + * results in an assignment, and then the interpreter says it cannot evaluate the + * side effect assignment variable. But we don't have to worry about side + * effects in function calls anyway, because then they won't CTFE. + * https://issues.dlang.org/show_bug.cgi?id=17145 + */ + if (!alwaysCopy && + ((sc.flags & SCOPE.ctfe) ? !hasSideEffect(e) : isTrivialExp(e))) return e; auto vd = copyToTemp(0, name, e); diff --git a/dmd/statement.d b/dmd/statement.d index c557dba8a23..907ce3d4d5d 100644 --- a/dmd/statement.d +++ b/dmd/statement.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d) @@ -615,6 +615,11 @@ private Statement toStatement(Dsymbol s) result = visitMembers(d.loc, d.decl); } + override void visit(ForwardingAttribDeclaration d) + { + result = visitMembers(d.loc, d.decl); + } + override void visit(StaticAssert s) { } @@ -635,8 +640,7 @@ private Statement toStatement(Dsymbol s) override void visit(StaticForeachDeclaration d) { assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe); - (d.sfe.aggrfe ? d.sfe.aggrfe._body : d.sfe.rangefe._body) = visitMembers(d.loc, d.decl); - result = new StaticForeachStatement(d.loc, d.sfe); + result = visitMembers(d.loc, d.include(null)); } override void visit(CompileDeclaration d) @@ -825,19 +829,15 @@ extern (C++) final class CompileStatement : Statement const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope p = new Parser!ASTCodegen(loc, sc._module, str, false, diagnosticReporter); + scope p = new Parser!ASTCodegen(loc, sc._module, str, false); p.nextToken(); auto a = new Statements(); while (p.token.value != TOK.endOfFile) { Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); - if (!s || p.errors) - { - assert(!p.errors || global.errors != errors); // make sure we caught all the cases + if (!s || global.errors != errors) return errorStatements(); - } a.push(s); } return a; @@ -1501,7 +1501,7 @@ extern (C++) final class StaticForeachStatement : Statement override Statement syntaxCopy() { - return new StaticForeachStatement(loc,sfe.syntaxCopy()); + return new StaticForeachStatement(loc, sfe.syntaxCopy()); } override Statements* flatten(Scope* sc) @@ -1510,7 +1510,7 @@ extern (C++) final class StaticForeachStatement : Statement if (sfe.ready()) { import dmd.statementsem; - auto s = makeTupleForeach!(true,false)(sc, sfe.aggrfe,sfe.needExpansion); + auto s = makeTupleForeach!(true, false)(sc, sfe.aggrfe, sfe.needExpansion); auto result = s.flatten(sc); if (result) { diff --git a/dmd/statement.h b/dmd/statement.h index aa96c7219c5..756e0340c1b 100644 --- a/dmd/statement.h +++ b/dmd/statement.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. @@ -284,6 +284,7 @@ class ScopeStatement : public Statement class ForwardingStatement : public Statement { +public: ForwardingScopeDsymbol *sym; Statement *statement; diff --git a/dmd/statement_rewrite_walker.d b/dmd/statement_rewrite_walker.d index f9fec58d97e..cf576b78b3e 100644 --- a/dmd/statement_rewrite_walker.d +++ b/dmd/statement_rewrite_walker.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d, _statement_rewrite_walker.d) diff --git a/dmd/statementsem.d b/dmd/statementsem.d index f410d21bd90..7dd2138d671 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d, _statementsem.d) @@ -48,13 +48,13 @@ import dmd.mtype; import dmd.nogc; import dmd.opover; import dmd.root.outbuffer; +import dmd.root.string; import dmd.semantic2; import dmd.sideeffect; import dmd.statement; import dmd.target; import dmd.tokens; import dmd.typesem; -import dmd.utils; import dmd.visitor; version (IN_LLVM) import gen.dpragma; @@ -673,9 +673,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor { auto needExpansion = args[$-1]; assert(sc); - auto previous = sc.scopesym; } - alias s = fs; auto loc = fs.loc; size_t dim = fs.parameters.dim; @@ -915,7 +913,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor var = new AliasDeclaration(loc, ident, t); if (paramtype) { - fs.error("cannot specify element type for symbol `%s`", s.toChars()); + fs.error("cannot specify element type for symbol `%s`", fs.toChars()); setError(); return false; } @@ -991,14 +989,12 @@ private extern (C++) final class StatementSemanticVisitor : Visitor else static if (!isDecl) { auto fwd = new ForwardingStatement(loc, res); - previous = fwd.sym; res = fwd; } else { import dmd.attrib: ForwardingAttribDeclaration; auto res = new ForwardingAttribDeclaration(st); - previous = res.sym; } static if (!isDecl) { @@ -3375,41 +3371,9 @@ version (IN_LLVM) * return x; return 3; // ok, x can be a value */ } - - // handle NRVO - if (fd.nrvo_can && rs.exp.op == TOK.variable) - { - VarExp ve = cast(VarExp)rs.exp; - VarDeclaration v = ve.var.isVarDeclaration(); - if (tf.isref) - { - // Function returns a reference - if (!inferRef) - fd.nrvo_can = 0; - } - else if (!v || v.isOut() || v.isRef()) - fd.nrvo_can = 0; - else if (fd.nrvo_var is null) - { - if (!v.isDataseg() && !v.isParameter() && v.toParent2() == fd) - { - //printf("Setting nrvo to %s\n", v.toChars()); - fd.nrvo_var = v; - } - else - fd.nrvo_can = 0; - } - else if (fd.nrvo_var != v) - fd.nrvo_can = 0; - } - else //if (!exp.isLvalue()) // keep NRVO-ability - fd.nrvo_can = 0; } else { - // handle NRVO - fd.nrvo_can = 0; - // infer return type if (fd.inferRetType) { diff --git a/dmd/staticassert.d b/dmd/staticassert.d index 8abdf26984a..c4e6ee6ab6a 100644 --- a/dmd/staticassert.d +++ b/dmd/staticassert.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d, _staticassert.d) diff --git a/dmd/staticassert.h b/dmd/staticassert.h index e5e55aeb974..a3d3afed94c 100644 --- a/dmd/staticassert.h +++ b/dmd/staticassert.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/staticcond.d b/dmd/staticcond.d index f1cd7ea7664..2c689cf1c13 100644 --- a/dmd/staticcond.d +++ b/dmd/staticcond.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d, _staticcond.d) @@ -12,7 +12,6 @@ module dmd.staticcond; -import dmd.aliasthis; import dmd.arraytypes; import dmd.dmodule; import dmd.dscope; @@ -26,7 +25,6 @@ import dmd.mtype; import dmd.root.array; import dmd.root.outbuffer; import dmd.tokens; -import dmd.utils; @@ -109,16 +107,6 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool return false; } - e = resolveAliasThis(sc, e); - - if (!e.type.isBoolean()) - { - original.error("expression `%s` of type `%s` does not have a boolean value", - original.toChars(), e.type.toChars()); - errors = true; - return false; - } - e = e.ctfeInterpret(); if (e.isBool(true)) diff --git a/dmd/target.d b/dmd/target.d index 7fc057eab3f..39c50adf9d5 100644 --- a/dmd/target.d +++ b/dmd/target.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d) @@ -28,9 +28,9 @@ import dmd.identifier; import dmd.mtype; import dmd.typesem; import dmd.tokens : TOK; -import dmd.utils : toDString; import dmd.root.ctfloat; import dmd.root.outbuffer; +import dmd.root.string : toDString; version (IN_LLVM) import gen.llvmhelpers; diff --git a/dmd/target.h b/dmd/target.h index 0009573982e..6b773ea9491 100644 --- a/dmd/target.h +++ b/dmd/target.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2013-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2013-2020 by The D Language Foundation, All Rights Reserved * written by Iain Buclaw * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/template.h b/dmd/template.h index 36341cd535a..02ebd94cb0b 100644 --- a/dmd/template.h +++ b/dmd/template.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/templateparamsem.d b/dmd/templateparamsem.d index 5fc19120b2e..64a34c6be40 100644 --- a/dmd/templateparamsem.d +++ b/dmd/templateparamsem.d @@ -4,7 +4,7 @@ * * Template implementation. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d, _templateparamsem.d) diff --git a/dmd/tokens.d b/dmd/tokens.d index 9fa9df9f625..3698105a158 100644 --- a/dmd/tokens.d +++ b/dmd/tokens.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d, _tokens.d) diff --git a/dmd/tokens.h b/dmd/tokens.h index b90aca2068f..e7caa641af6 100644 --- a/dmd/tokens.h +++ b/dmd/tokens.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/traits.d b/dmd/traits.d index bad146da9be..0103e052f52 100644 --- a/dmd/traits.d +++ b/dmd/traits.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/traits.d, _traits.d) @@ -49,7 +49,7 @@ import dmd.typesem; import dmd.visitor; import dmd.root.rootobject; import dmd.root.outbuffer; -import dmd.utils; +import dmd.root.string; enum LOGSEMANTIC = false; @@ -1455,14 +1455,15 @@ Expression semanticTraits(TraitsExp e, Scope* sc) //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars()); if (sm.ident) { - const idx = sm.ident.toChars(); - if (idx[0] == '_' && - idx[1] == '_' && - sm.ident != Id.ctor && - sm.ident != Id.dtor && - sm.ident != Id.__xdtor && - sm.ident != Id.postblit && - sm.ident != Id.__xpostblit) + // https://issues.dlang.org/show_bug.cgi?id=10096 + // https://issues.dlang.org/show_bug.cgi?id=10100 + // Skip over internal members in __traits(allMembers) + if ((sm.isCtorDeclaration() && sm.ident != Id.ctor) || + (sm.isDtorDeclaration() && sm.ident != Id.dtor) || + (sm.isPostBlitDeclaration() && sm.ident != Id.postblit) || + sm.isInvariantDeclaration() || + sm.isUnitTestDeclaration()) + { return 0; } @@ -1575,14 +1576,12 @@ Expression semanticTraits(TraitsExp e, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope p = new Parser!ASTCodegen(e.loc, sc._module, str, false, diagnosticReporter); + scope p = new Parser!ASTCodegen(e.loc, sc._module, str, false); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); o = p.parseTypeOrAssignExp(TOK.endOfFile); - if (p.errors || - p.token.value != TOK.endOfFile) + if (errors != global.errors || p.token.value != TOK.endOfFile) { err = true; break; diff --git a/dmd/transitivevisitor.d b/dmd/transitivevisitor.d index 21fd4128886..2167abe2433 100644 --- a/dmd/transitivevisitor.d +++ b/dmd/transitivevisitor.d @@ -851,13 +851,6 @@ package mixin template ParseVisitMethods(AST) visitFuncBody(d); } - override void visit(AST.DeleteDeclaration d) - { - //printf("Visiting DeleteDeclaration\n"); - visitParameters(d.parameters); - visitFuncBody(d); - } - // Initializers //============================================================ diff --git a/dmd/typesem.d b/dmd/typesem.d index 14ec8db7be3..dcef6bb5718 100644 --- a/dmd/typesem.d +++ b/dmd/typesem.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d) @@ -55,13 +55,13 @@ import dmd.root.ctfloat; import dmd.root.rmem; import dmd.root.outbuffer; import dmd.root.rootobject; +import dmd.root.string; import dmd.root.stringtable; import dmd.semantic3; import dmd.sideeffect; import dmd.target; import dmd.tokens; import dmd.typesem; -import dmd.utils; /************************** * This evaluates exp while setting length to be the number @@ -1002,7 +1002,7 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc) { if (search_function(sd, Id.eq)) { - .error(loc, "%sAA key type `%s` should have `size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars()); + .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars()); } else { @@ -1148,7 +1148,7 @@ extern(C++) Type typeSemantic(Type t, Loc loc, Scope* sc) bool errors = false; - if (mtype.inuse > 500) + if (mtype.inuse > global.recursionLimit) { mtype.inuse = 0; .error(loc, "recursive type"); @@ -1997,13 +1997,12 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope diagnosticReporter = new StderrDiagnosticReporter(global.params.useDeprecated); - scope p = new Parser!ASTCodegen(loc, sc._module, str, false, diagnosticReporter); + scope p = new Parser!ASTCodegen(loc, sc._module, str, false); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); auto o = p.parseTypeOrAssignExp(TOK.endOfFile); - if (p.errors) + if (errors != global.errors) { assert(global.errors != errors); // should have caught all these cases return null; @@ -3373,7 +3372,7 @@ else e.error("`%s` is not an expression", e.toChars()); return new ErrorExp(); } - else if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + else if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { e.error("`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e.toChars(), e.toChars()); return new ErrorExp(); @@ -3421,7 +3420,7 @@ else } else if (ident == Id.ptr) { - if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { e.error("`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e.toChars(), e.toChars()); return new ErrorExp(); @@ -3487,7 +3486,7 @@ else } else if (ident == Id.funcptr) { - if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && sc.func.setUnsafe() && !(sc.flags & SCOPE.debug_)) + if (!(flag & DotExpFlag.noDeref) && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) { e.error("`%s.funcptr` cannot be used in `@safe` code", e.toChars()); return new ErrorExp(); diff --git a/dmd/typinf.d b/dmd/typinf.d index 80e5053e4e5..d2c5ef770fe 100644 --- a/dmd/typinf.d +++ b/dmd/typinf.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typeinf.d, _typeinf.d) diff --git a/dmd/utf.d b/dmd/utf.d index 89e952cbc12..26c27489a3c 100644 --- a/dmd/utf.d +++ b/dmd/utf.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utf.d, _utf.d) diff --git a/dmd/utils.d b/dmd/utils.d index bf07bbc90f0..a4e1412259d 100644 --- a/dmd/utils.d +++ b/dmd/utils.d @@ -5,7 +5,7 @@ * * This modules defines some utility functions for DMD. * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utils.d, _utils.d) @@ -21,7 +21,7 @@ import dmd.globals; import dmd.root.file; import dmd.root.filename; import dmd.root.outbuffer; -import dmd.root.rmem; +import dmd.root.string; /** @@ -137,82 +137,3 @@ void escapePath(OutBuffer* buf, const(char)* fname) fname++; } } - -/// Slices a `\0`-terminated C-string, excluding the terminator -inout(char)[] toDString (inout(char)* s) pure nothrow @nogc -{ - return s ? s[0 .. strlen(s)] : null; -} - -/** -Compare two slices for equality, in a case-insensitive way - -Comparison is based on `char` and does not do decoding. -As a result, it's only really accurate for plain ASCII strings. - -Params: -s1 = string to compare -s2 = string to compare - -Returns: -`true` if `s1 == s2` regardless of case -*/ -extern(D) static bool iequals(const(char)[] s1, const(char)[] s2) -{ - import core.stdc.ctype : toupper; - - if (s1.length != s2.length) - return false; - - foreach (idx, c1; s1) - { - // Since we did a length check, it is safe to bypass bounds checking - const c2 = s2.ptr[idx]; - if (c1 != c2) - if (toupper(c1) != toupper(c2)) - return false; - } - return true; -} - -/** -Copy the content of `src` into a C-string ('\0' terminated) then call `dg` - -The intent of this function is to provide an allocation-less -way to call a C function using a D slice. -The function internally allocates a buffer if needed, but frees it on exit. - -Note: -The argument to `dg` is `scope`. To keep the data around after `dg` exits, -one has to copy it. - -Params: -src = Slice to use to call the C function -dg = Delegate to call afterwards - -Returns: -The return value of `T` -*/ -auto toCStringThen(alias dg)(const(char)[] src) nothrow -{ - const len = src.length + 1; - char[512] small = void; - scope ptr = (src.length < (small.length - 1)) - ? small[0 .. len] - : (cast(char*)mem.xmalloc(len))[0 .. len]; - scope (exit) - { - if (&ptr[0] != &small[0]) - mem.xfree(&ptr[0]); - } - ptr[0 .. src.length] = src[]; - ptr[src.length] = '\0'; - return dg(ptr); -} - -unittest -{ - assert("Hello world".toCStringThen!((v) => v == "Hello world\0")); - assert("Hello world\0".toCStringThen!((v) => v == "Hello world\0\0")); - assert(null.toCStringThen!((v) => v == "\0")); -} diff --git a/dmd/version.h b/dmd/version.h index 6e246685429..9c11c0fcf2b 100644 --- a/dmd/version.h +++ b/dmd/version.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. diff --git a/dmd/visitor.d b/dmd/visitor.d index 727f165acae..3b01fdea040 100644 --- a/dmd/visitor.d +++ b/dmd/visitor.d @@ -2,7 +2,7 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/visitor.d, _visitor.d) @@ -42,6 +42,7 @@ public: void visit(ASTCodegen.ArrayScopeSymbol s) { visit(cast(ASTCodegen.ScopeDsymbol)s); } void visit(ASTCodegen.OverDeclaration s) { visit(cast(ASTCodegen.Declaration)s); } void visit(ASTCodegen.SymbolDeclaration s) { visit(cast(ASTCodegen.Declaration)s); } + void visit(ASTCodegen.ForwardingAttribDeclaration s) { visit(cast(ASTCodegen.AttribDeclaration)s); } void visit(ASTCodegen.ThisDeclaration s) { visit(cast(ASTCodegen.VarDeclaration)s); } void visit(ASTCodegen.TypeInfoDeclaration s) { visit(cast(ASTCodegen.VarDeclaration)s); } void visit(ASTCodegen.TypeInfoStructDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); } diff --git a/dmd/visitor.h b/dmd/visitor.h index f83c101b77d..4715d9b7084 100644 --- a/dmd/visitor.h +++ b/dmd/visitor.h @@ -1,6 +1,6 @@ /* Compiler implementation of the D programming language - * Copyright (C) 2013-2019 by The D Language Foundation, All Rights Reserved + * Copyright (C) 2013-2020 by The D Language Foundation, All Rights Reserved * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt @@ -109,6 +109,7 @@ class StaticIfDeclaration; class CompileDeclaration; class StaticForeachDeclaration; class UserAttributeDeclaration; +class ForwardingAttribDeclaration; class ScopeDsymbol; class TemplateDeclaration; @@ -166,7 +167,6 @@ class SharedStaticDtorDeclaration; class InvariantDeclaration; class UnitTestDeclaration; class NewDeclaration; -class DeleteDeclaration; class Initializer; class VoidInitializer; @@ -346,7 +346,6 @@ class ParseTimeVisitor virtual void visit(InvariantDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(UnitTestDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(NewDeclaration *s) { visit((FuncDeclaration *)s); } - virtual void visit(DeleteDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(StaticCtorDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(StaticDtorDeclaration *s) { visit((FuncDeclaration *)s); } virtual void visit(SharedStaticCtorDeclaration *s) { visit((StaticCtorDeclaration *)s); } @@ -589,6 +588,7 @@ class Visitor : public ParseTimeVisitor virtual void visit(ArrayScopeSymbol *s) { visit((ScopeDsymbol *)s); } virtual void visit(OverDeclaration *s) { visit((Declaration *)s); } virtual void visit(SymbolDeclaration *s) { visit((Declaration *)s); } + virtual void visit(ForwardingAttribDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(ThisDeclaration *s) { visit((VarDeclaration *)s); } virtual void visit(TypeInfoDeclaration *s) { visit((VarDeclaration *)s); } virtual void visit(TypeInfoStructDeclaration *s) { visit((TypeInfoDeclaration *)s); } diff --git a/driver/config.d b/driver/config.d index b5859b8583d..b819580b7dd 100644 --- a/driver/config.d +++ b/driver/config.d @@ -100,6 +100,7 @@ class GroupSetting : Setting Setting[] parseConfigFile(const(char)* filename) { import dmd.globals : Loc; + import dmd.root.string : toDString; import dmd.utils; auto content = readFile(Loc.initial, filename).extractSlice(); diff --git a/driver/main.cpp b/driver/main.cpp index 5f44a065c99..dd8d8e115ac 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -351,9 +351,10 @@ void parseCommandLine(Strings &sourceFiles) { global.params.objname = opts::fromPathString(objectFile); global.params.objdir = opts::fromPathString(objectDir); - global.params.docdir = opts::fromPathString(ddocDir).ptr; - global.params.docname = opts::fromPathString(ddocFile).ptr; - global.params.doDocComments |= global.params.docdir || global.params.docname; + global.params.docdir = opts::fromPathString(ddocDir); + global.params.docname = opts::fromPathString(ddocFile); + global.params.doDocComments |= + global.params.docdir.length || global.params.docname.length; global.params.jsonfilename = opts::fromPathString(jsonFile); if (global.params.jsonfilename.length) { diff --git a/gen/classes.cpp b/gen/classes.cpp index 450d8d3aa5a..5db8afeb21a 100644 --- a/gen/classes.cpp +++ b/gen/classes.cpp @@ -677,7 +677,7 @@ LLConstant *DtoDefineClassInfo(ClassDeclaration *cd) { b.push_uint(flags); // deallocator - b.push_funcptr(cd->aggDelete, Type::tvoid->pointerTo()); + b.push_null_vp(); // offset typeinfo VarDeclaration *offTiVar = cinfo->fields[9]; diff --git a/ir/irclass.cpp b/ir/irclass.cpp index ac3ca1aa87d..cc3b179b82a 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -96,7 +96,7 @@ LLGlobalVariable *IrAggr::getClassInfoSymbol() { LLType *type = DtoType(aggrdecl->type); LLType *bodyType = llvm::cast(type)->getElementType(); bool hasDestructor = (classdecl->dtor != nullptr); - bool hasCustomDelete = (classdecl->aggDelete != nullptr); + bool hasCustomDelete = false; // Construct the fields llvm::Metadata *mdVals[CD_NumFields]; mdVals[CD_BodyType] = diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 7a7d0f0f198..05a4ce0e06d 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -55,7 +55,7 @@ set(CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}) set(DRUNTIME_EXTRA_FLAGS -preview=fieldwise) set(DRUNTIME_EXTRA_UNITTEST_FLAGS -d-version=CoreUnittest -unittest) # no `-checkaction=context` yet set(PHOBOS2_EXTRA_FLAGS -transition=complex) -set(PHOBOS2_EXTRA_UNITTEST_FLAGS -unittest) +set(PHOBOS2_EXTRA_UNITTEST_FLAGS -d-version=StdUnittest -unittest) # Shadow the D_FLAGS cache variable by a regular variable containing all base D flags set(D_FLAGS ${D_FLAGS} ${D_EXTRA_FLAGS}) diff --git a/runtime/druntime b/runtime/druntime index 7521d110b00..93ea097822f 160000 --- a/runtime/druntime +++ b/runtime/druntime @@ -1 +1 @@ -Subproject commit 7521d110b009f16f04bbf6e57b6c09b22f7262a3 +Subproject commit 93ea097822f8c8eaedefe430c91be25ab718eb5e diff --git a/runtime/phobos b/runtime/phobos index 1ede700a54c..19f691096c5 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 1ede700a54c73db33f2d1d2d4d45b0b4bec39e24 +Subproject commit 19f691096c5246cbc75e92875699a6aa4a52dc8d diff --git a/tests/d2/dmd-testsuite b/tests/d2/dmd-testsuite index 0c4e8d1fa3b..c49f04021b3 160000 --- a/tests/d2/dmd-testsuite +++ b/tests/d2/dmd-testsuite @@ -1 +1 @@ -Subproject commit 0c4e8d1fa3bb64eab31164a6629ad10f782dfc7d +Subproject commit c49f04021b37ccaac7b709fca88a62b7a9f3ee94