d: Add support for compiling without libphobos library.
authorIain Buclaw <ibuclaw@gdcproject.org>
Tue, 23 Apr 2019 20:08:46 +0000 (20:08 +0000)
committerIain Buclaw <ibuclaw@gcc.gnu.org>
Tue, 23 Apr 2019 20:08:46 +0000 (20:08 +0000)
Merges upstream dmd 3b3dca8be

Reviewed-on: https://github.com/dlang/dmd/pull/9678

gcc/d/ChangeLog:

2019-04-23  Iain Buclaw  <ibuclaw@gdcproject.org>

* 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  <ibuclaw@gdcproject.org>

* 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

32 files changed:
gcc/d/ChangeLog
gcc/d/d-builtins.cc
gcc/d/d-codegen.cc
gcc/d/d-frontend.cc
gcc/d/d-lang.cc
gcc/d/d-spec.cc
gcc/d/d-tree.h
gcc/d/decl.cc
gcc/d/dmd/MERGE
gcc/d/dmd/clone.c
gcc/d/dmd/dcast.c
gcc/d/dmd/declaration.c
gcc/d/dmd/dinterpret.c
gcc/d/dmd/dmodule.c
gcc/d/dmd/dstruct.c
gcc/d/dmd/expressionsem.c
gcc/d/dmd/func.c
gcc/d/dmd/globals.h
gcc/d/dmd/idgen.c
gcc/d/dmd/opover.c
gcc/d/dmd/parse.c
gcc/d/dmd/statementsem.c
gcc/d/expr.cc
gcc/d/gdc.texi
gcc/d/lang.opt
gcc/d/modules.cc
gcc/d/toir.cc
gcc/d/typeinfo.cc
gcc/testsuite/ChangeLog
gcc/testsuite/gdc.test/fail_compilation/fail2456.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test18312.d [new file with mode: 0644]
gcc/testsuite/gdc.test/gdc-test.exp

index 7629c9608f815bb7fdb8c692eb0ec9a7bde49820..de191cb7a0215fc9dd489b25f2b3f0d388dbb7b8 100644 (file)
@@ -1,3 +1,34 @@
+2019-04-23  Iain Buclaw  <ibuclaw@gdcproject.org>
+
+       * 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  <ibuclaw@gdcproject.org>
 
        * decl.cc (DeclVisitor::visit(Import)): Set semanticRun after
index f263aafbd599ab3204d905745e933b06bd374aa1..3dbdafb492a89c5e119e72ea2db475afb096da1f 100644 (file)
@@ -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.  */
index 26929109b486c4376306a5f66c52c978c3561e35..2abff92fc8864b38cebc5defdb5fefc59b59d44a 100644 (file)
@@ -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);
 }
index d1d3c78ec8653072124b1b19de2fcffda2b3f4a7..ccd5f50130f6fc824f6ebc05bdeb53bbafca5a30 100644 (file)
@@ -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),
+                       "%<object.TypeInfo%> 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),
+                   "%<object.TypeInfo%> 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;
index d97525a590e645ae097710b6595381b9816e72d6..62a8ddd69b290e10a42243d5fa58ced8ae03a8b7 100644 (file)
@@ -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.  */
index 3d491f56fa7c8e7fb832d53fddf789d7dc2dc2e2..9eba6902bb9fc3a236e985e12dfc031bce17ec54 100644 (file)
@@ -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));
index cff832cc645499fb613e5ff435c696c680eabf2e..a514bc3902fe54cfdc3df1f1fd078939ad11a0a0 100644 (file)
@@ -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 *);
index 26de272455b4f2d545a5c5f71954be5f55ef1ab2..49723649230367ee7c9d9515ae2f3ea9d90f7fc9 100644 (file)
@@ -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 ())
index c360fe5c2ed427a44b63eeb25b4e8d2c477007fd..7424576512b79cb218d4ac1f8f4d62304dd15539 100644 (file)
@@ -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.
index 888cba5db7fbb97adca0f7de8e769a4633abd517..d9a9055cb99b69c6c2e4eb0e3d3351930be35a37 100644 (file)
@@ -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
     }
index 2fa762cb529bb46b5855379224060ee36d9813f4..a3df701c34146b40000ea105dbe3f9947813d2da 100644 (file)
@@ -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);
         }
 
index 835c6aef8311b72663015930f52ac948ed25f6d4..d0911e21858207a848cd456d657486e0db41d7ae 100644 (file)
@@ -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;
     }
index 40f3e77cbc56f804ef9f12b9b0d9fa70383798c4..acca4e8097db7414038fa9873630ec9d9592f299 100644 (file)
@@ -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);
index 07e47127130ed53ed74510631d5ce8b7c4687d04..1f6fd9f10a6d46ce874142ac3865ef14cd4161ee 100644 (file)
@@ -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)
index d35b005a47d27067103bb9c2f62fc9677d1a85cb..1338e1f69b04ed99d450d434c975e23da606a692 100644 (file)
@@ -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);
 
index a88ff8822acd25ed08dc8d2ee40ab2a52283bcd6..19b7ccb72367d225718e28352d74533a9ae9d562 100644 (file)
@@ -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);
 
index afba82aac7d0ed74f07c49c03ca4e24fcf773500..568decc8cee79307d4433f366ef6e8855d3db27e 100644 (file)
@@ -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));
index e2d42c7b67b8e093a166b09ac8c29ba68843825b..1094679b83761071c345564399c66b87ef38a5b0 100644 (file)
@@ -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<const char *> *modFileAliasStrings; // array of char*'s of -I module filename alias strings
index e75004893aa25d13cd2cf404904a8062293cd594..dc0ecd138615a4c0a61dd278ff445ac419d84dae 100644 (file)
@@ -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 },
index 453ba65852cdd62541c34153ee6dfcc85275f077..b3ea6cf467184729e8860a16efca96f3aab9fbc2 100644 (file)
@@ -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);
index 3afdbc257f80b4a8f720931cf679315be60d6147..9da58af046d2983bbf03b86a59ddb81f3c2e2352 100644 (file)
@@ -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;
index f694fb1b278ffe85c3b2980e8b5a7b0c6a7a4917..64cc42d9ce9b48a6643c5d3834a6a4669a6df3a6 100644 (file)
@@ -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;
index acf81a6cca0ae10fe1bf794630755e25dfe3abba..6497619e5fdeb130dffe17d48694d9f0dbe67aa1 100644 (file)
@@ -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);
index faadffa2502e707494c4d306435166b9998a25b4..bf2621039887e3d9dbbcb71beb8642fdc3a48466 100644 (file)
@@ -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}
index f65be444d4532f52c61f7fbcc0e980dc0cdd0c4f..26cf52c6ca75b107fc55bebc2b3b4c054fa4c61b 100644 (file)
@@ -229,6 +229,10 @@ fdoc-inc=
 D Joined RejectNegative
 -fdoc-inc=<file>       Include a Ddoc macro <file>.
 
+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=<package.module>=<filespec>      use <filespec> as source file for <package.module>.
 
 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.
index 35050c8e17a1a91cc347d2d473c4bc8304fc6026..88cc5e89e9a7e90b5850bccba3f6b7b02817a072 100644 (file)
@@ -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)
index ebe763865009f127e29fe0364d92f4546cc1ee3e..f1b2e09a94d2158b1bbcd3ffa4ac45cb9c0393c8 100644 (file)
@@ -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)
index dac66acdcd4d5e41d1fee915c2ca7b5de4eb07ba..ffa7e23786512754f73b4115a333d3334bb10cb0 100644 (file)
@@ -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),
+                   "%<object.TypeInfo%> 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));
index 76e1a8ee8f700630647c334ff92cbfb0fd1772af..22145fb0cb3fe9ea9b9644404df005717347f078 100644 (file)
@@ -1,3 +1,9 @@
+2019-04-23  Iain Buclaw  <ibuclaw@gdcproject.org>
+
+       * 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  <sudi.das@arm.com>
 
        * 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 (file)
index 0000000..e8cf5ab
--- /dev/null
@@ -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 (file)
index 0000000..e354a11
--- /dev/null
@@ -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 ~ "]";
+}
index ab8a4a3cfbdc217ebd16b45a583098f60989e14f..ce5575c071ab1f701e6184891cc7af94637fc005 100644 (file)
@@ -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"