[d] Committed support for compiling without libphobos library.

Message ID CABOHX+czRgTSzmuwCm=YOt_o_Ka96ihnrVRzmU0GqqXOOGvqWw@mail.gmail.com
State New
Headers show
Series
  • [d] Committed support for compiling without libphobos library.
Related show

Commit Message

Iain Buclaw April 23, 2019, 8:10 p.m.
Hi,

This patch backports support from the dmd front-end the options to
omit generating code that depends on libdruntime existing, and enables
the controlling of them by adding the options -fdruntime, and -frtti.
The other two options -fexceptions and -fmoduleinfo have also been
adapted accordingly.

Bootstrapped and regression tested on x86_64-linux-gnu.

Committed to trunk as r270518.
--
Iain
---
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.

---

Patch

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),
+			"%<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;
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<const char *> *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=<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.
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),
+		    "%<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));
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"