From c0aebc60b2ac19816f0431241d8f7203e60afb01 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Tue, 23 Apr 2019 20:08:46 +0000 Subject: [PATCH] d: Add support for compiling without libphobos library. Merges upstream dmd 3b3dca8be Reviewed-on: https://github.com/dlang/dmd/pull/9678 gcc/d/ChangeLog: 2019-04-23 Iain Buclaw * d-builtins.cc (d_init_versions): Add D_BetterC, D_ModuleInfo, D_Exceptions, D_TypeInfo as predefined version conditions. * d-codegen.cc (build_bounds_condition): Generate trap if D asserts are turned off. * d-frontend.cc (getTypeInfoType): Add error when -fno-rtti is set. * d-lang.cc (d_init_options): Initialize new front-end options. (d_handle_option): Handle -fdruntime, -fexceptions, and -frtti. (d_post_options): Turn off D runtime features if -fno-druntime is set. * d-spec.cc (lang_specific_driver): Handle -fdruntime. * d-tree.h (have_typeinfo_p): Add prototype. (build_typeinfo): Update prototype. * decl.cc (DeclVisitor::visit(StructDeclaration)): Create typeinfo only if TypeInfo exists. (DeclVisitor::visit(ClassDeclaration)): Likewise. (DeclVisitor::visit(InterfaceDeclaration)): Likewise. (DeclVisitor::visit(EnumDeclaration)): Likewise. * expr.cc: Update all calls to build_typeinfo. * gdc.texi (Runtime Options): Document -fdruntime and -frtti. * lang.opt: Add -fdruntime and -frtti. * modules.cc (build_module_tree): Create module info only if ModuleInfo exists. * toir.cc (IRVisitor::visit(ThrowStatement)): Update test for -fno-exceptions. * typeinfo.cc (create_tinfo_types): Build internal typeinfo classes only if Object exists. (have_typeinfo_p): New function. (class TypeInfoVisitor): Update all calls to build_typeinfo. (build_typeinfo): Add error when -fno-rtti is set. gcc/testsuite/ChangeLog: 2019-04-23 Iain Buclaw * gdc.test/fail_compilation/fail2456.d: New test. * gdc.test/fail_compilation/test18312.d: New test. * gdc.test/gdc-test.exp (gdc-convert-args): Handle -betterC. From-SVN: r270518 --- gcc/d/ChangeLog | 31 +++++ gcc/d/d-builtins.cc | 9 ++ gcc/d/d-codegen.cc | 5 +- gcc/d/d-frontend.cc | 34 +++++- gcc/d/d-lang.cc | 31 ++++- gcc/d/d-spec.cc | 6 + gcc/d/d-tree.h | 3 +- gcc/d/decl.cc | 17 ++- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/clone.c | 12 +- gcc/d/dmd/dcast.c | 2 +- gcc/d/dmd/declaration.c | 4 +- gcc/d/dmd/dinterpret.c | 6 +- gcc/d/dmd/dmodule.c | 63 ---------- gcc/d/dmd/dstruct.c | 15 ++- gcc/d/dmd/expressionsem.c | 7 +- gcc/d/dmd/func.c | 28 ++++- gcc/d/dmd/globals.h | 15 ++- gcc/d/dmd/idgen.c | 6 +- gcc/d/dmd/opover.c | 8 +- gcc/d/dmd/parse.c | 2 - gcc/d/dmd/statementsem.c | 52 +++++++-- gcc/d/expr.cc | 65 ++++++----- gcc/d/gdc.texi | 19 +++ gcc/d/lang.opt | 10 +- gcc/d/modules.cc | 3 +- gcc/d/toir.cc | 2 +- gcc/d/typeinfo.cc | 78 ++++++++++--- gcc/testsuite/ChangeLog | 6 + .../gdc.test/fail_compilation/fail2456.d | 110 ++++++++++++++++++ .../gdc.test/fail_compilation/test18312.d | 15 +++ gcc/testsuite/gdc.test/gdc-test.exp | 3 + 32 files changed, 509 insertions(+), 160 deletions(-) create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail2456.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test18312.d diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 7629c9608f8..de191cb7a02 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,3 +1,34 @@ +2019-04-23 Iain Buclaw + + * d-builtins.cc (d_init_versions): Add D_BetterC, D_ModuleInfo, + D_Exceptions, D_TypeInfo as predefined version conditions. + * d-codegen.cc (build_bounds_condition): Generate trap if D asserts + are turned off. + * d-frontend.cc (getTypeInfoType): Add error when -fno-rtti is set. + * d-lang.cc (d_init_options): Initialize new front-end options. + (d_handle_option): Handle -fdruntime, -fexceptions, and -frtti. + (d_post_options): Turn off D runtime features if -fno-druntime is set. + * d-spec.cc (lang_specific_driver): Handle -fdruntime. + * d-tree.h (have_typeinfo_p): Add prototype. + (build_typeinfo): Update prototype. + * decl.cc (DeclVisitor::visit(StructDeclaration)): Create typeinfo + only if TypeInfo exists. + (DeclVisitor::visit(ClassDeclaration)): Likewise. + (DeclVisitor::visit(InterfaceDeclaration)): Likewise. + (DeclVisitor::visit(EnumDeclaration)): Likewise. + * expr.cc: Update all calls to build_typeinfo. + * gdc.texi (Runtime Options): Document -fdruntime and -frtti. + * lang.opt: Add -fdruntime and -frtti. + * modules.cc (build_module_tree): Create module info only if + ModuleInfo exists. + * toir.cc (IRVisitor::visit(ThrowStatement)): Update test for + -fno-exceptions. + * typeinfo.cc (create_tinfo_types): Build internal typeinfo classes + only if Object exists. + (have_typeinfo_p): New function. + (class TypeInfoVisitor): Update all calls to build_typeinfo. + (build_typeinfo): Add error when -fno-rtti is set. + 2019-04-21 Iain Buclaw * decl.cc (DeclVisitor::visit(Import)): Set semanticRun after diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index f263aafbd59..3dbdafb492a 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -447,6 +447,15 @@ d_init_versions (void) if (global.params.useArrayBounds == BOUNDSCHECKoff) VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks"); + if (global.params.betterC) + VersionCondition::addPredefinedGlobalIdent ("D_BetterC"); + else + { + VersionCondition::addPredefinedGlobalIdent ("D_ModuleInfo"); + VersionCondition::addPredefinedGlobalIdent ("D_Exceptions"); + VersionCondition::addPredefinedGlobalIdent ("D_TypeInfo"); + } + VersionCondition::addPredefinedGlobalIdent ("all"); /* Emit all target-specific version identifiers. */ diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 26929109b48..2abff92fc88 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -1762,7 +1762,10 @@ build_bounds_condition (const Loc& loc, tree index, tree len, bool inclusive) have already taken care of implicit casts to unsigned. */ tree condition = fold_build2 (inclusive ? GT_EXPR : GE_EXPR, d_bool_type, index, len); - tree boundserr = d_assert_call (loc, LIBCALL_ARRAY_BOUNDS); + /* Terminate the program with a trap if no D runtime present. */ + tree boundserr = (global.params.checkAction == CHECKACTION_D) + ? d_assert_call (loc, LIBCALL_ARRAY_BOUNDS) + : build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0); return build_condition (TREE_TYPE (index), condition, boundserr, index); } diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc index d1d3c78ec86..ccd5f50130f 100644 --- a/gcc/d/d-frontend.cc +++ b/gcc/d/d-frontend.cc @@ -612,8 +612,40 @@ eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments) /* Build and return typeinfo type for TYPE. */ Type * -getTypeInfoType (Type *type, Scope *sc) +getTypeInfoType (Loc loc, Type *type, Scope *sc) { + if (!global.params.useTypeInfo) + { + /* Even when compiling without RTTI we should still be able to evaluate + TypeInfo at compile-time, just not at run-time. */ + if (!sc || !(sc->flags & SCOPEctfe)) + { + static int warned = 0; + + if (!warned) + { + error_at (make_location_t (loc), + "% cannot be used with -fno-rtti"); + warned = 1; + } + } + } + + if (Type::dtypeinfo == NULL + || (Type::dtypeinfo->storage_class & STCtemp)) + { + /* If TypeInfo has not been declared, warn about each location once. */ + static Loc warnloc; + + if (!loc.equals (warnloc)) + { + error_at (make_location_t (loc), + "% could not be found, " + "but is implicitly used"); + warnloc = loc; + } + } + gcc_assert (type->ty != Terror); create_typeinfo (type, sc ? sc->_module->importedFrom : NULL); return type->vtinfo->type; diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index d97525a590e..62a8ddd69b2 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -276,6 +276,9 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options) global.params.useOut = true; global.params.useArrayBounds = BOUNDSCHECKdefault; global.params.useSwitchError = true; + global.params.useModuleInfo = true; + global.params.useTypeInfo = true; + global.params.useExceptions = true; global.params.useInline = false; global.params.obj = true; global.params.hdrStripPlainFunctions = true; @@ -467,10 +470,18 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.ddocfiles->push (arg); break; + case OPT_fdruntime: + global.params.betterC = !value; + break; + case OPT_fdump_d_original: global.params.vcg_ast = value; break; + case OPT_fexceptions: + global.params.useExceptions = value; + break; + case OPT_fignore_unknown_pragmas: global.params.ignoreUnsupportedPragmas = value; break; @@ -490,7 +501,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fmoduleinfo: - global.params.betterC = !value; + global.params.useModuleInfo = value; break; case OPT_fonly_: @@ -509,6 +520,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.release = value; break; + case OPT_frtti: + global.params.useTypeInfo = value; + break; + case OPT_fswitch_errors: global.params.useSwitchError = value; break; @@ -728,6 +743,20 @@ d_post_options (const char ** fn) global.params.useSwitchError = false; } + if (global.params.betterC) + { + if (!global_options_set.x_flag_moduleinfo) + global.params.useModuleInfo = false; + + if (!global_options_set.x_flag_rtti) + global.params.useTypeInfo = false; + + if (!global_options_set.x_flag_exceptions) + global.params.useExceptions = false; + + global.params.checkAction = CHECKACTION_halt; + } + /* Turn off partitioning unless it was explicitly requested, as it doesn't work with D exception chaining, where EH handler uses LSDA to determine whether two thrown exception are in the same context. */ diff --git a/gcc/d/d-spec.cc b/gcc/d/d-spec.cc index 3d491f56fa7..9eba6902bb9 100644 --- a/gcc/d/d-spec.cc +++ b/gcc/d/d-spec.cc @@ -144,6 +144,7 @@ lang_specific_driver (cl_decoded_option **in_decoded_options, for (i = 1; i < argc; i++) { const char *arg = decoded_options[i].arg; + const int value = decoded_options[i].value; switch (decoded_options[i].opt_index) { @@ -161,6 +162,11 @@ lang_specific_driver (cl_decoded_option **in_decoded_options, args[i] |= SKIPOPT; break; + case OPT_fdruntime: + if (!value) + need_phobos = false; + break; + case OPT_defaultlib_: if (defaultlib != NULL) free (CONST_CAST (char *, defaultlib)); diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index cff832cc645..a514bc3902f 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -647,11 +647,12 @@ extern void d_finish_compilation (tree *, int); extern tree build_libcall (libcall_fn, Type *, int ...); /* In typeinfo.cc. */ +extern bool have_typeinfo_p (ClassDeclaration *); extern tree layout_typeinfo (TypeInfoDeclaration *); extern tree layout_classinfo (ClassDeclaration *); extern tree get_typeinfo_decl (TypeInfoDeclaration *); extern tree get_classinfo_decl (ClassDeclaration *); -extern tree build_typeinfo (Type *); +extern tree build_typeinfo (const Loc &, Type *); extern void create_typeinfo (Type *, Module *); extern void create_tinfo_types (Module *); extern void layout_cpp_typeinfo (ClassDeclaration *); diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 26de272455b..49723649230 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -379,7 +379,8 @@ public: return; /* Generate TypeInfo. */ - create_typeinfo (d->type, NULL); + if (have_typeinfo_p (Type::dtypeinfo)) + create_typeinfo (d->type, NULL); /* Generate static initializer. */ d->sinit = aggregate_initializer_decl (d); @@ -523,7 +524,9 @@ public: d_finish_decl (d->sinit); /* Put out the TypeInfo. */ - create_typeinfo (d->type, NULL); + if (have_typeinfo_p (Type::dtypeinfo)) + create_typeinfo (d->type, NULL); + DECL_INITIAL (d->csym) = layout_classinfo (d); d_linkonce_linkage (d->csym); d_finish_decl (d->csym); @@ -588,8 +591,11 @@ public: d->csym = get_classinfo_decl (d); /* Put out the TypeInfo. */ - create_typeinfo (d->type, NULL); - d->type->vtinfo->accept (this); + if (have_typeinfo_p (Type::dtypeinfo)) + { + create_typeinfo (d->type, NULL); + d->type->vtinfo->accept (this); + } DECL_INITIAL (d->csym) = layout_classinfo (d); d_linkonce_linkage (d->csym); @@ -622,7 +628,8 @@ public: return; /* Generate TypeInfo. */ - create_typeinfo (d->type, NULL); + if (have_typeinfo_p (Type::dtypeinfo)) + create_typeinfo (d->type, NULL); TypeEnum *tc = (TypeEnum *) d->type; if (tc->sym->members && !d->type->isZeroInit ()) diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index c360fe5c2ed..7424576512b 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -065fbd452f2aa498fc3a554be48a5495bd98aa14 +3b3dca8be201b443f17621cd29cf614007b5c75e The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/clone.c b/gcc/d/dmd/clone.c index 888cba5db7f..d9a9055cb99 100644 --- a/gcc/d/dmd/clone.c +++ b/gcc/d/dmd/clone.c @@ -839,7 +839,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) } else { - // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n]) + // __ArrayPostblit((cast(S*)this.v.ptr)[0 .. n]) uinteger_t n = 1; while (tv->ty == Tsarray) @@ -865,7 +865,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) ((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->lowerIsLessThanUpper = true; - ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayPostblit), ex); + ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayPostblit), ex); } a->push(new ExpStatement(loc, ex)); // combine in forward order @@ -896,7 +896,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) } else { - // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) + // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) uinteger_t n = 1; while (tv->ty == Tsarray) @@ -922,7 +922,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) ((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->lowerIsLessThanUpper = true; - ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex); + ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayDtor), ex); } a->push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex))); } @@ -1047,7 +1047,7 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc) } else { - // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) + // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) uinteger_t n = 1; while (tv->ty == Tsarray) @@ -1073,7 +1073,7 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc) ((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->lowerIsLessThanUpper = true; - ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex); + ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayDtor), ex); } e = Expression::combine(ex, e); // combine in reverse order } diff --git a/gcc/d/dmd/dcast.c b/gcc/d/dmd/dcast.c index 2fa762cb529..a3df701c341 100644 --- a/gcc/d/dmd/dcast.c +++ b/gcc/d/dmd/dcast.c @@ -131,7 +131,7 @@ Expression *implicitCastTo(Expression *e, Scope *sc, Type *t) visit((Expression *)e); Type *tb = result->type->toBasetype(); - if (tb->ty == Tarray) + if (tb->ty == Tarray && global.params.useTypeInfo && Type::dtypeinfo) semanticTypeInfo(sc, ((TypeDArray *)tb)->next); } diff --git a/gcc/d/dmd/declaration.c b/gcc/d/dmd/declaration.c index 835c6aef831..d0911e21858 100644 --- a/gcc/d/dmd/declaration.c +++ b/gcc/d/dmd/declaration.c @@ -2118,7 +2118,7 @@ Expression *VarDeclaration::callScopeDtor(Scope *) } else { - // _ArrayDtor(v[0 .. n]) + // __ArrayDtor(v[0 .. n]) e = new VarExp(loc, this); const d_uns64 sdsz = sd->type->size(); @@ -2133,7 +2133,7 @@ Expression *VarDeclaration::callScopeDtor(Scope *) // This is a hack so we can call destructors on const/immutable objects. e->type = sd->type->arrayOf(); - e = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), e); + e = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayDtor), e); } return e; } diff --git a/gcc/d/dmd/dinterpret.c b/gcc/d/dmd/dinterpret.c index 40f3e77cbc5..acca4e8097d 100644 --- a/gcc/d/dmd/dinterpret.c +++ b/gcc/d/dmd/dinterpret.c @@ -4633,8 +4633,8 @@ public: fd = ((VarExp *)ecall)->var->isFuncDeclaration(); assert(fd); - if (fd->ident == Id::_ArrayPostblit || - fd->ident == Id::_ArrayDtor) + if (fd->ident == Id::__ArrayPostblit || + fd->ident == Id::__ArrayDtor) { assert(e->arguments->dim == 1); Expression *ea = (*e->arguments)[0]; @@ -4654,7 +4654,7 @@ public: if (CTFEExp::isCantExp(result)) return; - if (fd->ident == Id::_ArrayPostblit) + if (fd->ident == Id::__ArrayPostblit) result = evaluatePostblit(istate, result); else result = evaluateDtor(istate, result); diff --git a/gcc/d/dmd/dmodule.c b/gcc/d/dmd/dmodule.c index 07e47127130..1f6fd9f10a6 100644 --- a/gcc/d/dmd/dmodule.c +++ b/gcc/d/dmd/dmodule.c @@ -575,69 +575,6 @@ Module *Module::parse() error("has non-identifier characters in filename, use module declaration instead"); } - // Add internal used functions in 'object' module members. - if (!parent && ident == Id::object) - { - static const utf8_t code_ArrayEq[] = - "bool _ArrayEq(T1, T2)(T1[] a, T2[] b) {\n" - " if (a.length != b.length) return false;\n" - " foreach (size_t i; 0 .. a.length) { if (a[i] != b[i]) return false; }\n" - " return true; }\n"; - - static const utf8_t code_ArrayPostblit[] = - "void _ArrayPostblit(T)(T[] a) { foreach (ref T e; a) e.__xpostblit(); }\n"; - - static const utf8_t code_ArrayDtor[] = - "void _ArrayDtor(T)(T[] a) { foreach_reverse (ref T e; a) e.__xdtor(); }\n"; - - static const utf8_t code_xopEquals[] = - "bool _xopEquals(in void*, in void*) { throw new Error(\"TypeInfo.equals is not implemented\"); }\n"; - - static const utf8_t code_xopCmp[] = - "bool _xopCmp(in void*, in void*) { throw new Error(\"TypeInfo.compare is not implemented\"); }\n"; - - Identifier *arreq = Id::_ArrayEq; - Identifier *xopeq = Identifier::idPool("_xopEquals"); - Identifier *xopcmp = Identifier::idPool("_xopCmp"); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *sx = (*members)[i]; - if (!sx) continue; - if (arreq && sx->ident == arreq) arreq = NULL; - if (xopeq && sx->ident == xopeq) xopeq = NULL; - if (xopcmp && sx->ident == xopcmp) xopcmp = NULL; - } - - if (arreq) - { - Parser p(loc, this, code_ArrayEq, strlen((const char *)code_ArrayEq), 0); - p.nextToken(); - members->append(p.parseDeclDefs(0)); - } - { - Parser p(loc, this, code_ArrayPostblit, strlen((const char *)code_ArrayPostblit), 0); - p.nextToken(); - members->append(p.parseDeclDefs(0)); - } - { - Parser p(loc, this, code_ArrayDtor, strlen((const char *)code_ArrayDtor), 0); - p.nextToken(); - members->append(p.parseDeclDefs(0)); - } - if (xopeq) - { - Parser p(loc, this, code_xopEquals, strlen((const char *)code_xopEquals), 0); - p.nextToken(); - members->append(p.parseDeclDefs(0)); - } - if (xopcmp) - { - Parser p(loc, this, code_xopCmp, strlen((const char *)code_xopCmp), 0); - p.nextToken(); - members->append(p.parseDeclDefs(0)); - } - } - // Insert module into the symbol table Dsymbol *s = this; if (isPackageFile) diff --git a/gcc/d/dmd/dstruct.c b/gcc/d/dmd/dstruct.c index d35b005a47d..1338e1f69b0 100644 --- a/gcc/d/dmd/dstruct.c +++ b/gcc/d/dmd/dstruct.c @@ -23,7 +23,7 @@ #include "template.h" #include "tokens.h" -Type *getTypeInfoType(Type *t, Scope *sc); +Type *getTypeInfoType(Loc loc, Type *t, Scope *sc); TypeTuple *toArgTypes(Type *t); void unSpeculative(Scope *sc, RootObject *o); bool MODimplicitConv(MOD modfrom, MOD modto); @@ -101,7 +101,7 @@ void semanticTypeInfo(Scope *sc, Type *t) { Scope scx; scx._module = sd->getModule(); - getTypeInfoType(t, &scx); + getTypeInfoType(sd->loc, t, &scx); sd->requestTypeInfo = true; } else if (!sc->minst) @@ -111,7 +111,7 @@ void semanticTypeInfo(Scope *sc, Type *t) } else { - getTypeInfoType(t, sc); + getTypeInfoType(sd->loc, t, sc); sd->requestTypeInfo = true; // Bugzilla 15149, if the typeid operand type comes from a @@ -1165,9 +1165,12 @@ void StructDeclaration::semantic(Scope *sc) buildOpAssign(this, sc2); buildOpEquals(this, sc2); - xeq = buildXopEquals(this, sc2); - xcmp = buildXopCmp(this, sc2); - xhash = buildXtoHash(this, sc2); + if (global.params.useTypeInfo && Type::dtypeinfo) // these functions are used for TypeInfo + { + xeq = buildXopEquals(this, sc2); + xcmp = buildXopCmp(this, sc2); + xhash = buildXtoHash(this, sc2); + } inv = buildInv(this, sc2); diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c index a88ff8822ac..19b7ccb7236 100644 --- a/gcc/d/dmd/expressionsem.c +++ b/gcc/d/dmd/expressionsem.c @@ -46,7 +46,7 @@ bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istar bool symbolIsVisible(Module *mod, Dsymbol *s); VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e); Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false); -Type *getTypeInfoType(Type *t, Scope *sc); +Type *getTypeInfoType(Loc loc, Type *t, Scope *sc); bool MODimplicitConv(MOD modfrom, MOD modto); MATCH MODmethodConv(MOD modfrom, MOD modto); void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod); @@ -713,7 +713,8 @@ public: return setError(); } - semanticTypeInfo(sc, e->type); + if (global.params.useTypeInfo && Type::dtypeinfo) + semanticTypeInfo(sc, e->type); result = e; } @@ -1819,7 +1820,7 @@ public: { // Handle this in the glue layer e = new TypeidExp(exp->loc, ta); - e->type = getTypeInfoType(ta, sc); + e->type = getTypeInfoType(exp->loc, ta, sc); semanticTypeInfo(sc, ta); diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c index afba82aac7d..568decc8cee 100644 --- a/gcc/d/dmd/func.c +++ b/gcc/d/dmd/func.c @@ -246,6 +246,15 @@ public: s->finalbody && (des = s->finalbody->isDtorExpStatement()) != NULL && fd->nrvo_var == des->var) { + if (!(global.params.useExceptions && ClassDeclaration::throwable)) + { + /* Don't need to call destructor at all, since it is nrvo + */ + replaceCurrent(s->_body); + s->_body->accept(this); + return; + } + /* Normally local variable dtors are called regardless exceptions. * But for nrvo_var, its dtor should be called only when exception is thrown. * @@ -1325,6 +1334,16 @@ static void buildEnsureRequire(FuncDeclaration *fdx) } } +/* Determine if function should add `return 0;` + */ +static bool addReturn0(FuncDeclaration *funcdecl) +{ + TypeFunction *f = (TypeFunction *)funcdecl->type; + + return f->next->ty == Tvoid && + (funcdecl->isMain() || (global.params.betterC && funcdecl->isCMain())); +} + // Do the semantic analysis on the internals of the function. void FuncDeclaration::semantic3(Scope *sc) @@ -1708,7 +1727,10 @@ void FuncDeclaration::semantic3(Scope *sc) Expression *exp = (*returns)[i]->exp; if (exp->op == TOKvar && ((VarExp *)exp)->var == vresult) { - exp->type = f->next; + if (addReturn0(this)) + exp->type = Type::tint32; + else + exp->type = f->next; // Remove `return vresult;` from returns returns->remove(i); continue; @@ -1901,7 +1923,7 @@ void FuncDeclaration::semantic3(Scope *sc) if (returns) { - bool implicit0 = (f->next->ty == Tvoid && isMain()); + bool implicit0 = addReturn0(this); Type *tret = implicit0 ? Type::tint32 : f->next; assert(tret->ty != Tvoid); if (vresult || returnLabel) @@ -2123,7 +2145,7 @@ void FuncDeclaration::semantic3(Scope *sc) a->push(s); } } - if (isMain() && f->next->ty == Tvoid) + if (addReturn0(this)) { // Add a return 0; statement Statement *s = new ReturnStatement(Loc(), new IntegerExp(0)); diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index e2d42c7b67b..1094679b837 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -36,6 +36,14 @@ enum BOUNDSCHECK BOUNDSCHECKsafeonly // do bounds checking only in @safe functions }; +typedef unsigned char CHECKACTION; +enum +{ + CHECKACTION_D, // call D assert on failure + CHECKACTION_C, // call C assert on failure + CHECKACTION_halt // cause program halt on failure +}; + enum CPU { x87, @@ -116,6 +124,9 @@ struct Param bool nofloat; // code should not pull in floating point support bool ignoreUnsupportedPragmas; // rather than error on them bool enforcePropertySyntax; + bool useModuleInfo; // generate runtime module information + bool useTypeInfo; // generate runtime type information + bool useExceptions; // support exception handling bool betterC; // be a "better C" compiler; no dependency on D runtime bool addMain; // add a default main() function bool allInst; // generate code for all template instantiations @@ -126,7 +137,9 @@ struct Param bool showGaggedErrors; // print gagged errors anyway CPU cpu; // CPU instruction set to target - BOUNDSCHECK useArrayBounds; + + BOUNDSCHECK useArrayBounds; // when to generate code for array bounds checks + CHECKACTION checkAction; // action to take when bounds, asserts or switch defaults are violated const char *argv0; // program name Array *modFileAliasStrings; // array of char*'s of -I module filename alias strings diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c index e75004893aa..dc0ecd13861 100644 --- a/gcc/d/dmd/idgen.c +++ b/gcc/d/dmd/idgen.c @@ -264,9 +264,9 @@ Msgtable msgtable[] = { "monitorexit", "_d_monitorexit" }, { "criticalenter", "_d_criticalenter" }, { "criticalexit", "_d_criticalexit" }, - { "_ArrayEq", NULL }, - { "_ArrayPostblit", NULL }, - { "_ArrayDtor", NULL }, + { "__ArrayEq", NULL }, + { "__ArrayPostblit", NULL }, + { "__ArrayDtor", NULL }, { "dup", NULL }, { "_aaApply", NULL }, { "_aaApply2", NULL }, diff --git a/gcc/d/dmd/opover.c b/gcc/d/dmd/opover.c index 453ba65852c..b3ea6cf4671 100644 --- a/gcc/d/dmd/opover.c +++ b/gcc/d/dmd/opover.c @@ -900,7 +900,9 @@ Expression *op_overload(Expression *e, Scope *sc) if (t->ty != Tstruct) return false; - semanticTypeInfo(sc, t); + if (global.params.useTypeInfo && Type::dtypeinfo) + semanticTypeInfo(sc, t); + return ((TypeStruct *)t)->sym->hasIdentityEquals; } @@ -919,9 +921,9 @@ Expression *op_overload(Expression *e, Scope *sc) if (needsDirectEq(t1, t2, sc)) { /* Rewrite as: - * _ArrayEq(e1, e2) + * __ArrayEq(e1, e2) */ - Expression *eeq = new IdentifierExp(e->loc, Id::_ArrayEq); + Expression *eeq = new IdentifierExp(e->loc, Id::__ArrayEq); result = new CallExp(e->loc, eeq, e->e1, e->e2); if (e->op == TOKnotequal) result = new NotExp(e->loc, result); diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c index 3afdbc257f8..9da58af046d 100644 --- a/gcc/d/dmd/parse.c +++ b/gcc/d/dmd/parse.c @@ -70,7 +70,6 @@ Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool //printf("Parser::Parser()\n"); scanloc = loc; -#ifndef IN_GCC if (loc.filename) { /* Create a pseudo-filename for the mixin string, as it may not even exist @@ -80,7 +79,6 @@ Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum); scanloc.filename = filename; } -#endif mod = module; md = NULL; diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c index f694fb1b278..64cc42d9ce9 100644 --- a/gcc/d/dmd/statementsem.c +++ b/gcc/d/dmd/statementsem.c @@ -2073,8 +2073,19 @@ public: CompoundStatement *cs; Statement *s; - if (global.params.useSwitchError) - s = new SwitchErrorStatement(ss->loc); + if (global.params.useSwitchError && + global.params.checkAction != CHECKACTION_halt) + { + if (global.params.checkAction == CHECKACTION_C) + { + /* Rewrite as an assert(0) and let e2ir generate + * the call to the C assert failure function + */ + s = new ExpStatement(ss->loc, new AssertExp(ss->loc, new IntegerExp(ss->loc, 0, Type::tint32))); + } + else + s = new SwitchErrorStatement(ss->loc); + } else s = new ExpStatement(ss->loc, new HaltExp(ss->loc)); @@ -3118,6 +3129,18 @@ public: void visit(TryCatchStatement *tcs) { + if (!global.params.useExceptions) + { + tcs->error("Cannot use try-catch statements with -betterC"); + return setError(); + } + + if (!ClassDeclaration::throwable) + { + tcs->error("Cannot use try-catch statements because `object.Throwable` was not declared"); + return setError(); + } + unsigned flags = 0; const unsigned FLAGcpp = 1; const unsigned FLAGd = 2; @@ -3227,7 +3250,14 @@ public: return; } - if (blockExit(tfs->_body, sc->func, false) == BEfallthru) + int blockexit = blockExit(tfs->_body, sc->func, false); + + // if not worrying about exceptions + if (!(global.params.useExceptions && ClassDeclaration::throwable)) + blockexit &= ~BEthrow; // don't worry about paths that otherwise may throw + + // Don't care about paths that halt, either + if ((blockexit & ~BEhalt) == BEfallthru) { result = new CompoundStatement(tfs->loc, tfs->_body, tfs->finalbody); return; @@ -3237,7 +3267,6 @@ public: void visit(OnScopeStatement *oss) { -#ifndef IN_GCC if (oss->tok != TOKon_scope_exit) { // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement, @@ -3255,7 +3284,6 @@ public: return setError(); } } -#endif sc = sc->push(); sc->tf = NULL; @@ -3281,6 +3309,18 @@ public: { //printf("ThrowStatement::semantic()\n"); + if (!global.params.useExceptions) + { + ts->error("Cannot use `throw` statements with -betterC"); + return setError(); + } + + if (!ClassDeclaration::throwable) + { + ts->error("Cannot use `throw` statements because `object.Throwable` was not declared"); + return setError(); + } + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); fd->hasReturnExp |= 2; @@ -3463,7 +3503,6 @@ void semantic(Catch *c, Scope *sc) { //printf("Catch::semantic(%s)\n", ident->toChars()); -#ifndef IN_GCC if (sc->os && sc->os->tok != TOKon_scope_failure) { // If enclosing is scope(success) or scope(exit), this will be placed in finally block. @@ -3481,7 +3520,6 @@ void semantic(Catch *c, Scope *sc) error(c->loc, "cannot put catch statement inside finally block"); c->errors = true; } -#endif ScopeDsymbol *sym = new ScopeDsymbol(); sym->parent = sc->scopesym; diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index acf81a6cca0..6497619e5fd 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -424,7 +424,7 @@ public: tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3, d_array_convert (e->e1), d_array_convert (e->e2), - build_typeinfo (t1array)); + build_typeinfo (e->loc, t1array)); if (e->op == TOKnotequal) result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result); @@ -449,7 +449,7 @@ public: /* Use _aaEqual() for associative arrays. */ TypeAArray *taa1 = (TypeAArray *) tb1; tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3, - build_typeinfo (taa1), + build_typeinfo (e->loc, taa1), build_expr (e->e1), build_expr (e->e2)); @@ -485,7 +485,7 @@ public: /* Build a call to _aaInX(). */ this->result_ = build_libcall (LIBCALL_AAINX, e->type, 3, build_expr (e->e2), - build_typeinfo (tkey), + build_typeinfo (e->loc, tkey), build_address (key)); } @@ -533,7 +533,7 @@ public: tree call = build_libcall (LIBCALL_ADCMP2, Type::tint32, 3, d_array_convert (e->e1), d_array_convert (e->e2), - build_typeinfo (telem->arrayOf ())); + build_typeinfo (e->loc, telem->arrayOf ())); result = build_boolop (code, call, integer_zero_node); this->result_ = d_convert (build_ctype (e->type), result); @@ -745,13 +745,13 @@ public: size_int (ndims), build_address (var)); result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2, - build_typeinfo (e->type), arrs); + build_typeinfo (e->loc, e->type), arrs); } else { /* Handle single concatenation (a ~ b). */ result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3, - build_typeinfo (e->type), + build_typeinfo (e->loc, e->type), d_array_convert (etype, e->e1, &elemvars), d_array_convert (etype, e->e2, &elemvars)); } @@ -859,7 +859,7 @@ public: { gcc_assert (tb1->ty == Tarray || tb2->ty == Tsarray); - tree tinfo = build_typeinfo (e->type); + tree tinfo = build_typeinfo (e->loc, e->type); tree ptr = build_address (build_expr (e->e1)); if ((tb2->ty == Tarray || tb2->ty == Tsarray) @@ -924,7 +924,7 @@ public: ? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT; tree result = build_libcall (libcall, ale->e1->type, 3, - build_typeinfo (ale->e1->type), + build_typeinfo (ale->loc, ale->e1->type), newlength, ptr); this->result_ = d_array_length (result); @@ -954,7 +954,8 @@ public: libcall_fn libcall = (e->op == TOKconstruct) ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN; /* So we can call postblits on const/immutable objects. */ - tree ti = build_typeinfo (etype->unSharedOf ()->mutableOf ()); + Type *tm = etype->unSharedOf ()->mutableOf (); + tree ti = build_typeinfo (e->loc, tm); tree result = build_libcall (libcall, Type::tvoid, 4, d_array_ptr (t1), @@ -1004,7 +1005,7 @@ public: ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN; this->result_ = build_libcall (libcall, e->type, 3, - build_typeinfo (etype), + build_typeinfo (e->loc, etype), d_array_convert (e->e2), d_array_convert (e->e1)); } @@ -1133,7 +1134,7 @@ public: { /* Generate: _d_arrayctor(ti, from, to) */ result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3, - build_typeinfo (etype), + build_typeinfo (e->loc, etype), d_array_convert (e->e2), d_array_convert (e->e1)); } @@ -1146,7 +1147,7 @@ public: tree elembuf = build_local_temp (build_ctype (etype)); result = build_libcall (libcall, arrtype, 4, - build_typeinfo (etype), + build_typeinfo (e->loc, etype), d_array_convert (e->e2), d_array_convert (e->e1), build_address (elembuf)); @@ -1210,13 +1211,13 @@ public: { libcall = LIBCALL_AAGETY; ptr = build_address (build_expr (e->e1)); - tinfo = build_typeinfo (tb1->unSharedOf ()->mutableOf ()); + tinfo = build_typeinfo (e->loc, tb1->unSharedOf ()->mutableOf ()); } else { libcall = LIBCALL_AAGETRVALUEX; ptr = build_expr (e->e1); - tinfo = build_typeinfo (tkey); + tinfo = build_typeinfo (e->loc, tkey); } /* Index the associative array. */ @@ -1227,7 +1228,10 @@ public: if (!e->indexIsInBounds && array_bounds_check ()) { - tree tassert = d_assert_call (e->loc, LIBCALL_ARRAY_BOUNDS); + tree tassert = (global.params.checkAction == CHECKACTION_D) + ? d_assert_call (e->loc, LIBCALL_ARRAY_BOUNDS) + : build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0); + result = d_save_expr (result); result = build_condition (TREE_TYPE (result), d_truthvalue_conversion (result), @@ -1486,7 +1490,7 @@ public: /* Might need to run destructor on array contents. */ TypeStruct *ts = (TypeStruct *) telem; if (ts->sym->dtor) - ti = build_typeinfo (tb1->nextOf ()); + ti = build_typeinfo (e->loc, tb1->nextOf ()); } /* Generate: _delarray_t (&t1, ti); */ @@ -1505,8 +1509,9 @@ public: TypeStruct *ts = (TypeStruct *)tnext; if (ts->sym->dtor) { + tree ti = build_typeinfo (e->loc, tnext); this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid, - 2, t1, build_typeinfo (tnext)); + 2, t1, ti); return; } } @@ -1536,7 +1541,7 @@ public: this->result_ = build_libcall (LIBCALL_AADELX, Type::tbool, 3, build_expr (e->e1), - build_typeinfo (tkey), + build_typeinfo (e->loc, tkey), build_address (index)); } else @@ -1967,7 +1972,8 @@ public: tree assert_pass = void_node; tree assert_fail; - if (global.params.useAssert) + if (global.params.useAssert + && global.params.checkAction == CHECKACTION_D) { /* Generate: ((bool) e1 ? (void)0 : _d_assert (...)) or: (e1 != null ? e1._invariant() : _d_assert (...)) */ @@ -2011,6 +2017,13 @@ public: } } } + else if (global.params.useAssert + && global.params.checkAction == CHECKACTION_C) + { + /* Generate: __builtin_trap() */ + tree fn = builtin_decl_explicit (BUILT_IN_TRAP); + assert_fail = build_call_expr (fn, 0); + } else { /* Assert contracts are turned off, if the contract condition has no @@ -2066,7 +2079,7 @@ public: { if (Type *tid = isType (e->obj)) { - tree ti = build_typeinfo (tid); + tree ti = build_typeinfo (e->loc, tid); /* If the typeinfo is at an offset. */ if (tid->vtinfo->offset) @@ -2390,7 +2403,7 @@ public: /* Generate: _d_newitemT() */ libcall_fn libcall = htype->isZeroInit () ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT; - tree arg = build_typeinfo (e->newtype); + tree arg = build_typeinfo (e->loc, e->newtype); new_call = build_libcall (libcall, tb, 1, arg); } @@ -2461,7 +2474,7 @@ public: libcall_fn libcall = tarray->next->isZeroInit () ? LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT; result = build_libcall (libcall, tb, 2, - build_typeinfo (e->type), + build_typeinfo (e->loc, e->type), build_expr (arg)); } else @@ -2491,7 +2504,7 @@ public: libcall_fn libcall = telem->isZeroInit () ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX; - tree tinfo = build_typeinfo (e->type); + tree tinfo = build_typeinfo (e->loc, e->type); tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()), size_int (e->arguments->dim), build_address (var)); @@ -2519,7 +2532,7 @@ public: libcall_fn libcall = tpointer->next->isZeroInit (e->loc) ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT; - tree arg = build_typeinfo (e->newtype); + tree arg = build_typeinfo (e->loc, e->newtype); result = build_libcall (libcall, tb, 1, arg); if (e->arguments && e->arguments->dim == 1) @@ -2746,7 +2759,7 @@ public: /* Allocate space on the memory managed heap. */ tree mem = build_libcall (LIBCALL_ARRAYLITERALTX, etype->pointerTo (), 2, - build_typeinfo (etype->arrayOf ()), + build_typeinfo (e->loc, etype->arrayOf ()), size_int (e->elements->dim)); mem = d_save_expr (mem); @@ -2821,7 +2834,7 @@ public: build_address (avals)); tree mem = build_libcall (LIBCALL_ASSOCARRAYLITERALTX, Type::tvoidptr, 3, - build_typeinfo (ta), keys, vals); + build_typeinfo (e->loc, ta), keys, vals); /* Return an associative array pointed to by MEM. */ tree aatype = build_ctype (ta); diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi index faadffa2502..bf262103988 100644 --- a/gcc/d/gdc.texi +++ b/gcc/d/gdc.texi @@ -233,6 +233,18 @@ is compiled into the program. Turns on compilation of any @code{debug} code identified by @var{ident}. @end table +@item -fno-druntime +@cindex @option{-fdruntime} +@cindex @option{-fno-druntime} +Implements @uref{https://dlang.org/spec/betterc.html}. Assumes that +compilation targets an environment without a D runtime library. + +This is equivalent to compiling with the following options: + +@example +gdc -nophoboslib -fno-exceptions -fno-moduleinfo -fno-rtti +@end example + @item -fno-invariants @cindex @option{-finvariants} @cindex @option{-fno-invariants} @@ -279,6 +291,13 @@ gdc -fno-assert -fbounds-check=safe -fno-invariants \ -fno-postconditions -fno-preconditions -fno-switch-errors @end example +@item -fno-rtti +@cindex @option{-frtti} +@cindex @option{-fno-rtti} +Turns off generation of run-time type information for all user defined types. +Any code that uses features of the language that require access to this +information will result in an error. + @item -fno-switch-errors @cindex @option{-fswitch-errors} @cindex @option{-fno-switch-errors} diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index f65be444d45..26cf52c6ca7 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -229,6 +229,10 @@ fdoc-inc= D Joined RejectNegative -fdoc-inc= Include a Ddoc macro . +fdruntime +D +Assume that standard D runtime libraries and \"D main\" exist. + fdump-d-original D Display the frontend AST after parsing and semantic passes. @@ -250,7 +254,7 @@ D Joined RejectNegative -fmodule-file== use as source file for . fmoduleinfo -D +D Var(flag_moduleinfo) Generate ModuleInfo struct for output module. fonly= @@ -269,6 +273,10 @@ frelease D Compile release version. +frtti +D +; Documented in C + fswitch-errors D Var(flag_switch_errors) Generate code for switches without a default case. diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc index 35050c8e17a..88cc5e89e9a 100644 --- a/gcc/d/modules.cc +++ b/gcc/d/modules.cc @@ -776,7 +776,8 @@ build_module_tree (Module *decl) /* Default behavior is to always generate module info because of templates. Can be switched off for not compiling against runtime library. */ - if (!global.params.betterC + if (global.params.useModuleInfo + && Module::moduleinfo != NULL && decl->ident != Identifier::idPool ("__entrypoint")) { if (mi.ctors || mi.ctorgates) diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc index ebe76386500..f1b2e09a94d 100644 --- a/gcc/d/toir.cc +++ b/gcc/d/toir.cc @@ -1120,7 +1120,7 @@ public: InterfaceDeclaration *id = cd->isInterfaceDeclaration (); tree arg = build_expr_dtor (s->exp); - if (!flag_exceptions) + if (!global.params.useExceptions) { static int warned = 0; if (!warned) diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index dac66acdcd4..ffa7e237865 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -227,6 +227,10 @@ create_tinfo_types (Module *mod) ptr_type_node, d_uint_type, ptr_type_node, array_type_node, ptr_type_node, ptr_type_node, NULL); + /* If there's no Object class defined, then neither can TypeInfo be. */ + if (ClassDeclaration::object == NULL) + return; + /* Create all frontend TypeInfo classes declarations. We rely on all existing, even if only just as stubs. */ if (!Type::dtypeinfo) @@ -289,6 +293,27 @@ create_tinfo_types (Module *mod) ClassDeclaration::object); } +/* Return true if TypeInfo class TINFO is available in the runtime library. */ + +bool +have_typeinfo_p (ClassDeclaration *tinfo) +{ + /* Run-time typeinfo disabled on command line. */ + if (!global.params.useTypeInfo) + return false; + + /* Can't layout TypeInfo if type is not declared, or is an opaque + declaration in the object module. */ + if (!tinfo || !tinfo->members) + return false; + + /* Typeinfo is compiler-generated. */ + if (tinfo->storage_class & STCtemp) + return false; + + return true; +} + /* Implements the visitor interface to build the TypeInfo layout of all TypeInfoDeclaration AST classes emitted from the D Front-end. All visit methods accept one parameter D, which holds the frontend AST @@ -338,7 +363,12 @@ class TypeInfoVisitor : public Visitor void layout_base (ClassDeclaration *cd) { gcc_assert (cd != NULL); - this->layout_field (build_address (get_vtable_decl (cd))); + + if (have_typeinfo_p (cd)) + this->layout_field (build_address (get_vtable_decl (cd))); + else + this->layout_field (null_pointer_node); + this->layout_field (null_pointer_node); } @@ -490,7 +520,7 @@ public: this->layout_base (Type::typeinfoconst); /* TypeInfo for the mutable type. */ - this->layout_field (build_typeinfo (tm)); + this->layout_field (build_typeinfo (d->loc, tm)); } /* Layout of TypeInfo_Immutable is: @@ -507,7 +537,7 @@ public: this->layout_base (Type::typeinfoinvariant); /* TypeInfo for the mutable type. */ - this->layout_field (build_typeinfo (tm)); + this->layout_field (build_typeinfo (d->loc, tm)); } /* Layout of TypeInfo_Shared is: @@ -524,7 +554,7 @@ public: this->layout_base (Type::typeinfoshared); /* TypeInfo for the unshared type. */ - this->layout_field (build_typeinfo (tm)); + this->layout_field (build_typeinfo (d->loc, tm)); } /* Layout of TypeInfo_Inout is: @@ -541,7 +571,7 @@ public: this->layout_base (Type::typeinfowild); /* TypeInfo for the mutable type. */ - this->layout_field (build_typeinfo (tm)); + this->layout_field (build_typeinfo (d->loc, tm)); } /* Layout of TypeInfo_Enum is: @@ -561,7 +591,7 @@ public: this->layout_base (Type::typeinfoenum); /* TypeInfo for enum members. */ - tree memtype = (ed->memtype) ? build_typeinfo (ed->memtype) + tree memtype = (ed->memtype) ? build_typeinfo (d->loc, ed->memtype) : null_pointer_node; this->layout_field (memtype); @@ -593,7 +623,7 @@ public: this->layout_base (Type::typeinfopointer); /* TypeInfo for pointer-to type. */ - this->layout_field (build_typeinfo (ti->next)); + this->layout_field (build_typeinfo (d->loc, ti->next)); } /* Layout of TypeInfo_Array is: @@ -610,7 +640,7 @@ public: this->layout_base (Type::typeinfoarray); /* TypeInfo for array of type. */ - this->layout_field (build_typeinfo (ti->next)); + this->layout_field (build_typeinfo (d->loc, ti->next)); } /* Layout of TypeInfo_StaticArray is: @@ -628,7 +658,7 @@ public: this->layout_base (Type::typeinfostaticarray); /* TypeInfo for array of type. */ - this->layout_field (build_typeinfo (ti->next)); + this->layout_field (build_typeinfo (d->loc, ti->next)); /* Static array length. */ this->layout_field (size_int (ti->dim->toInteger ())); @@ -649,10 +679,10 @@ public: this->layout_base (Type::typeinfoassociativearray); /* TypeInfo for value of type. */ - this->layout_field (build_typeinfo (ti->next)); + this->layout_field (build_typeinfo (d->loc, ti->next)); /* TypeInfo for index of type. */ - this->layout_field (build_typeinfo (ti->index)); + this->layout_field (build_typeinfo (d->loc, ti->index)); } /* Layout of TypeInfo_Vector is: @@ -669,7 +699,7 @@ public: this->layout_base (Type::typeinfovector); /* TypeInfo for equivalent static array. */ - this->layout_field (build_typeinfo (ti->basetype)); + this->layout_field (build_typeinfo (d->loc, ti->basetype)); } /* Layout of TypeInfo_Function is: @@ -687,7 +717,7 @@ public: this->layout_base (Type::typeinfofunction); /* TypeInfo for function return value. */ - this->layout_field (build_typeinfo (ti->next)); + this->layout_field (build_typeinfo (d->loc, ti->next)); /* Mangled name of function declaration. */ this->layout_string (d->tinfo->deco); @@ -708,7 +738,7 @@ public: this->layout_base (Type::typeinfodelegate); /* TypeInfo for delegate return value. */ - this->layout_field (build_typeinfo (ti->next)); + this->layout_field (build_typeinfo (d->loc, ti->next)); /* Mangled name of delegate declaration. */ this->layout_string (d->tinfo->deco); @@ -1038,12 +1068,12 @@ public: if (global.params.is64bit) { /* TypeInfo m_arg1; */ - tree arg1type = (sd->arg1type) ? build_typeinfo (sd->arg1type) + tree arg1type = (sd->arg1type) ? build_typeinfo (d->loc, sd->arg1type) : null_pointer_node; this->layout_field (arg1type); /* TypeInfo m_arg2; */ - tree arg2type = (sd->arg2type) ? build_typeinfo (sd->arg2type) + tree arg2type = (sd->arg2type) ? build_typeinfo (d->loc, sd->arg2type) : null_pointer_node; this->layout_field (arg2type); } @@ -1075,7 +1105,7 @@ public: { Parameter *arg = (*ti->arguments)[i]; CONSTRUCTOR_APPEND_ELT (elms, size_int (i), - build_typeinfo (arg->type)); + build_typeinfo (d->loc, arg->type)); } tree ctor = build_constructor (build_ctype (satype), elms); tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor); @@ -1311,8 +1341,20 @@ get_classinfo_decl (ClassDeclaration *decl) /* Returns typeinfo reference for TYPE. */ tree -build_typeinfo (Type *type) +build_typeinfo (const Loc &loc, Type *type) { + if (!global.params.useTypeInfo) + { + static int warned = 0; + + if (!warned) + { + error_at (make_location_t (loc), + "% cannot be used with -fno-rtti"); + warned = 1; + } + } + gcc_assert (type->ty != Terror); create_typeinfo (type, NULL); return build_address (get_typeinfo_decl (type->vtinfo)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 76e1a8ee8f7..22145fb0cb3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-04-23 Iain Buclaw + + * gdc.test/fail_compilation/fail2456.d: New test. + * gdc.test/fail_compilation/test18312.d: New test. + * gdc.test/gdc-test.exp (gdc-convert-args): Handle -betterC. + 2018-04-23 Sudakshina Das * gcc.target/aarch64/bti-1.c: Add scan directive for gnu note section diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2456.d b/gcc/testsuite/gdc.test/fail_compilation/fail2456.d new file mode 100644 index 00000000000..e8cf5abbbf5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail2456.d @@ -0,0 +1,110 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail2456.d(14): Error: cannot put `scope(success)` statement inside finally block +--- +*/ +void test_success() +{ + try + { + } + finally + { + scope(success) {} // NG + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail2456.d(31): Error: cannot put `scope(failure)` statement inside finally block +--- +*/ +void test_failure() +{ + try + { + } + finally + { + scope(failure) {} // NG + } +} + +/* +TEST_OUTPUT: +--- +--- +*/ +void test_exit() +{ + try + { + } + finally + { + scope(exit) {} // OK + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail2456.d(64): Error: cannot put `scope(success)` statement inside `scope(success)` +fail_compilation/fail2456.d(65): Error: cannot put `scope(failure)` statement inside `scope(success)` +fail_compilation/fail2456.d(78): Error: cannot put `scope(success)` statement inside `scope(exit)` +fail_compilation/fail2456.d(79): Error: cannot put `scope(failure)` statement inside `scope(exit)` +--- +*/ +void test2456a() +{ + scope(success) + { + scope(success) {} // NG + scope(failure) {} // NG + scope(exit) {} // OK + } + + scope(failure) + { + scope(success) {} // OK + scope(failure) {} // OK + scope(exit) {} // OK + } + + scope(exit) + { + scope(success) {} // NG + scope(failure) {} // NG + scope(exit) {} // OK + } +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail2456.d(96): Error: cannot put catch statement inside `scope(success)` +fail_compilation/fail2456.d(108): Error: cannot put catch statement inside `scope(exit)` +--- +*/ +void test2456b() +{ + scope(success) + { + try {} + catch (Throwable) {} // NG + } + + scope(failure) + { + try {} + catch (Throwable) {} // OK + } + + scope(exit) + { + try {} + catch (Throwable) {} // NG + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18312.d b/gcc/testsuite/gdc.test/fail_compilation/test18312.d new file mode 100644 index 00000000000..e354a11eae8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test18312.d @@ -0,0 +1,15 @@ +/* +REQUIRED_ARGS: -betterC +TEST_OUTPUT: +--- +fail_compilation/test18312.d(14): Error: array concatenation of expression `"[" ~ s ~ "]"` requires the GC which is not available with -betterC +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=18312 + +extern (C) void main() +{ + scope string s; + s = "[" ~ s ~ "]"; +} diff --git a/gcc/testsuite/gdc.test/gdc-test.exp b/gcc/testsuite/gdc.test/gdc-test.exp index ab8a4a3cfbd..ce5575c071a 100644 --- a/gcc/testsuite/gdc.test/gdc-test.exp +++ b/gcc/testsuite/gdc.test/gdc-test.exp @@ -39,6 +39,9 @@ proc gdc-convert-args { args } { } elseif [string match "-allinst" $arg] { lappend out "-fall-instantiations" + } elseif [string match "-betterC" $arg] { + lappend out "-fno-druntime" + } elseif { [string match "-boundscheck" $arg] || [string match "-boundscheck=on" $arg] } { lappend out "-fbounds-check" -- 2.30.2