+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
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. */
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);
}
/* 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;
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;
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;
break;
case OPT_fmoduleinfo:
- global.params.betterC = !value;
+ global.params.useModuleInfo = value;
break;
case OPT_fonly_:
global.params.release = value;
break;
+ case OPT_frtti:
+ global.params.useTypeInfo = value;
+ break;
+
case OPT_fswitch_errors:
global.params.useSwitchError = value;
break;
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. */
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)
{
args[i] |= SKIPOPT;
break;
+ case OPT_fdruntime:
+ if (!value)
+ need_phobos = false;
+ break;
+
case OPT_defaultlib_:
if (defaultlib != NULL)
free (CONST_CAST (char *, defaultlib));
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 *);
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);
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);
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);
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 ())
-065fbd452f2aa498fc3a554be48a5495bd98aa14
+3b3dca8be201b443f17621cd29cf614007b5c75e
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
}
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)
((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
}
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)
((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)));
}
}
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)
((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
}
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);
}
}
else
{
- // _ArrayDtor(v[0 .. n])
+ // __ArrayDtor(v[0 .. n])
e = new VarExp(loc, this);
const d_uns64 sdsz = sd->type->size();
// 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;
}
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];
if (CTFEExp::isCantExp(result))
return;
- if (fd->ident == Id::_ArrayPostblit)
+ if (fd->ident == Id::__ArrayPostblit)
result = evaluatePostblit(istate, result);
else
result = evaluateDtor(istate, result);
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)
#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);
{
Scope scx;
scx._module = sd->getModule();
- getTypeInfoType(t, &scx);
+ getTypeInfoType(sd->loc, t, &scx);
sd->requestTypeInfo = true;
}
else if (!sc->minst)
}
else
{
- getTypeInfoType(t, sc);
+ getTypeInfoType(sd->loc, t, sc);
sd->requestTypeInfo = true;
// Bugzilla 15149, if the typeid operand type comes from a
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);
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);
return setError();
}
- semanticTypeInfo(sc, e->type);
+ if (global.params.useTypeInfo && Type::dtypeinfo)
+ semanticTypeInfo(sc, e->type);
result = e;
}
{
// 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);
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.
*
}
}
+/* 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)
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;
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)
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));
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,
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
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
{ "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 },
if (t->ty != Tstruct)
return false;
- semanticTypeInfo(sc, t);
+ if (global.params.useTypeInfo && Type::dtypeinfo)
+ semanticTypeInfo(sc, t);
+
return ((TypeStruct *)t)->sym->hasIdentityEquals;
}
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);
//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
sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum);
scanloc.filename = filename;
}
-#endif
mod = module;
md = NULL;
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));
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;
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;
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,
return setError();
}
}
-#endif
sc = sc->push();
sc->tf = NULL;
{
//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;
{
//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.
error(c->loc, "cannot put catch statement inside finally block");
c->errors = true;
}
-#endif
ScopeDsymbol *sym = new ScopeDsymbol();
sym->parent = sc->scopesym;
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);
/* 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));
/* 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));
}
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);
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));
}
{
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)
? 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);
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),
? 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));
}
{
/* 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));
}
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));
{
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. */
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),
/* 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); */
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;
}
}
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
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 (...)) */
}
}
}
+ 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
{
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)
/* 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);
}
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
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));
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)
/* 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);
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);
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}
-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}
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.
-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=
D
Compile release version.
+frtti
+D
+; Documented in C
+
fswitch-errors
D Var(flag_switch_errors)
Generate code for switches without a default case.
/* 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)
InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
tree arg = build_expr_dtor (s->exp);
- if (!flag_exceptions)
+ if (!global.params.useExceptions)
{
static int warned = 0;
if (!warned)
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)
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
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);
}
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:
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:
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:
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:
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);
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:
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:
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 ()));
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:
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:
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);
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);
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);
}
{
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);
/* 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));
+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
--- /dev/null
+/*
+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
+ }
+}
--- /dev/null
+/*
+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 ~ "]";
+}
} 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"