63 changes: 0 additions & 63 deletions gcc/d/dmd/dmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
15 changes: 9 additions & 6 deletions gcc/d/dmd/dstruct.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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);

Expand Down
7 changes: 4 additions & 3 deletions gcc/d/dmd/expressionsem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -713,7 +713,8 @@ class ExpressionSemanticVisitor : public Visitor
return setError();
}

semanticTypeInfo(sc, e->type);
if (global.params.useTypeInfo && Type::dtypeinfo)
semanticTypeInfo(sc, e->type);

result = e;
}
Expand Down Expand Up @@ -1819,7 +1820,7 @@ class ExpressionSemanticVisitor : public Visitor
{
// 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);

Expand Down
28 changes: 25 additions & 3 deletions gcc/d/dmd/func.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,15 @@ class NrvoWalker : public StatementRewriteWalker
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.
*
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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));
Expand Down
15 changes: 14 additions & 1 deletion gcc/d/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions gcc/d/dmd/idgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
8 changes: 5 additions & 3 deletions gcc/d/dmd/opover.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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);
Expand Down
2 changes: 0 additions & 2 deletions gcc/d/dmd/parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down
52 changes: 45 additions & 7 deletions gcc/d/dmd/statementsem.c
Original file line number Diff line number Diff line change
Expand Up @@ -2073,8 +2073,19 @@ class StatementSemanticVisitor : public Visitor
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));

Expand Down Expand Up @@ -3118,6 +3129,18 @@ class StatementSemanticVisitor : public Visitor

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;
Expand Down Expand Up @@ -3227,7 +3250,14 @@ class StatementSemanticVisitor : public Visitor
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;
Expand All @@ -3237,7 +3267,6 @@ class StatementSemanticVisitor : public Visitor

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,
Expand All @@ -3255,7 +3284,6 @@ class StatementSemanticVisitor : public Visitor
return setError();
}
}
#endif

sc = sc->push();
sc->tf = NULL;
Expand All @@ -3281,6 +3309,18 @@ class StatementSemanticVisitor : public Visitor
{
//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;

Expand Down Expand Up @@ -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.
Expand All @@ -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;
Expand Down
65 changes: 39 additions & 26 deletions gcc/d/expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ class ExprVisitor : public Visitor
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);
Expand All @@ -449,7 +449,7 @@ class ExprVisitor : public Visitor
/* 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));

Expand Down Expand Up @@ -485,7 +485,7 @@ class ExprVisitor : public Visitor
/* 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));
}

Expand Down Expand Up @@ -533,7 +533,7 @@ class ExprVisitor : public Visitor
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);
Expand Down Expand Up @@ -745,13 +745,13 @@ class ExprVisitor : public Visitor
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));
}
Expand Down Expand Up @@ -859,7 +859,7 @@ class ExprVisitor : public Visitor
{
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)
Expand Down Expand Up @@ -924,7 +924,7 @@ class ExprVisitor : public Visitor
? 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);
Expand Down Expand Up @@ -954,7 +954,8 @@ class ExprVisitor : public Visitor
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),
Expand Down Expand Up @@ -1004,7 +1005,7 @@ class ExprVisitor : public Visitor
? 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));
}
Expand Down Expand Up @@ -1133,7 +1134,7 @@ class ExprVisitor : public Visitor
{
/* 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));
}
Expand All @@ -1146,7 +1147,7 @@ class ExprVisitor : public Visitor
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));
Expand Down Expand Up @@ -1210,13 +1211,13 @@ class ExprVisitor : public Visitor
{
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. */
Expand All @@ -1227,7 +1228,10 @@ class ExprVisitor : public Visitor

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),
Expand Down Expand Up @@ -1486,7 +1490,7 @@ class ExprVisitor : public Visitor
/* 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); */
Expand All @@ -1505,8 +1509,9 @@ class ExprVisitor : public Visitor
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;
}
}
Expand Down Expand Up @@ -1536,7 +1541,7 @@ class ExprVisitor : public Visitor

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
Expand Down Expand Up @@ -1967,7 +1972,8 @@ class ExprVisitor : public Visitor
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 (...)) */
Expand Down Expand Up @@ -2011,6 +2017,13 @@ class ExprVisitor : public Visitor
}
}
}
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
Expand Down Expand Up @@ -2066,7 +2079,7 @@ class ExprVisitor : public Visitor
{
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)
Expand Down Expand Up @@ -2390,7 +2403,7 @@ class ExprVisitor : public Visitor
/* 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);
}

Expand Down Expand Up @@ -2461,7 +2474,7 @@ class ExprVisitor : public Visitor
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
Expand Down Expand Up @@ -2491,7 +2504,7 @@ class ExprVisitor : public Visitor
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));
Expand Down Expand Up @@ -2519,7 +2532,7 @@ class ExprVisitor : public Visitor
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)
Expand Down Expand Up @@ -2746,7 +2759,7 @@ class ExprVisitor : public Visitor
/* 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);

Expand Down Expand Up @@ -2821,7 +2834,7 @@ class ExprVisitor : public Visitor
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);
Expand Down
19 changes: 19 additions & 0 deletions gcc/d/gdc.texi
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand Down Expand Up @@ -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}
Expand Down
10 changes: 9 additions & 1 deletion gcc/d/lang.opt
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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=
Expand All @@ -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.
Expand Down
3 changes: 2 additions & 1 deletion gcc/d/modules.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion gcc/d/toir.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1120,7 +1120,7 @@ class IRVisitor : public Visitor
InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
tree arg = build_expr_dtor (s->exp);

if (!flag_exceptions)
if (!global.params.useExceptions)
{
static int warned = 0;
if (!warned)
Expand Down
78 changes: 60 additions & 18 deletions gcc/d/typeinfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -490,7 +520,7 @@ class TypeInfoVisitor : public Visitor
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:
Expand All @@ -507,7 +537,7 @@ class TypeInfoVisitor : public Visitor
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:
Expand All @@ -524,7 +554,7 @@ class TypeInfoVisitor : public Visitor
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:
Expand All @@ -541,7 +571,7 @@ class TypeInfoVisitor : public Visitor
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:
Expand All @@ -561,7 +591,7 @@ class TypeInfoVisitor : public Visitor
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);

Expand Down Expand Up @@ -593,7 +623,7 @@ class TypeInfoVisitor : public Visitor
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:
Expand All @@ -610,7 +640,7 @@ class TypeInfoVisitor : public Visitor
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:
Expand All @@ -628,7 +658,7 @@ class TypeInfoVisitor : public Visitor
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 ()));
Expand All @@ -649,10 +679,10 @@ class TypeInfoVisitor : public Visitor
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:
Expand All @@ -669,7 +699,7 @@ class TypeInfoVisitor : public Visitor
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:
Expand All @@ -687,7 +717,7 @@ class TypeInfoVisitor : public Visitor
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);
Expand All @@ -708,7 +738,7 @@ class TypeInfoVisitor : public Visitor
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);
Expand Down Expand Up @@ -1038,12 +1068,12 @@ class TypeInfoVisitor : public Visitor
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);
}
Expand Down Expand Up @@ -1075,7 +1105,7 @@ class TypeInfoVisitor : public Visitor
{
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);
Expand Down Expand Up @@ -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));
Expand Down
6 changes: 6 additions & 0 deletions gcc/testsuite/ChangeLog
Original file line number Diff line number Diff line change
@@ -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
Expand Down
110 changes: 110 additions & 0 deletions gcc/testsuite/gdc.test/fail_compilation/fail2456.d
Original file line number Diff line number Diff line change
@@ -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
}
}
15 changes: 15 additions & 0 deletions gcc/testsuite/gdc.test/fail_compilation/test18312.d
Original file line number Diff line number Diff line change
@@ -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 ~ "]";
}
3 changes: 3 additions & 0 deletions gcc/testsuite/gdc.test/gdc-test.exp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down