d: Add support for compiling without libphobos library.

Merges upstream dmd 3b3dca8be

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

gcc/d/ChangeLog:

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

	* d-builtins.cc (d_init_versions): Add D_BetterC, D_ModuleInfo,
	D_Exceptions, D_TypeInfo as predefined version conditions.
	* d-codegen.cc (build_bounds_condition): Generate trap if D asserts
	are turned off.
	* d-frontend.cc (getTypeInfoType): Add error when -fno-rtti is set.
	* d-lang.cc (d_init_options): Initialize new front-end options.
	(d_handle_option): Handle -fdruntime, -fexceptions, and -frtti.
	(d_post_options): Turn off D runtime features if -fno-druntime is set.
	* d-spec.cc (lang_specific_driver): Handle -fdruntime.
	* d-tree.h (have_typeinfo_p): Add prototype.
	(build_typeinfo): Update prototype.
	* decl.cc (DeclVisitor::visit(StructDeclaration)): Create typeinfo
	only if TypeInfo exists.
	(DeclVisitor::visit(ClassDeclaration)): Likewise.
	(DeclVisitor::visit(InterfaceDeclaration)): Likewise.
	(DeclVisitor::visit(EnumDeclaration)): Likewise.
	* expr.cc: Update all calls to build_typeinfo.
	* gdc.texi (Runtime Options): Document -fdruntime and -frtti.
	* lang.opt: Add -fdruntime and -frtti.
	* modules.cc (build_module_tree): Create module info only if
	ModuleInfo exists.
	* toir.cc (IRVisitor::visit(ThrowStatement)): Update test for
	-fno-exceptions.
	* typeinfo.cc (create_tinfo_types): Build internal typeinfo classes
	only if Object exists.
	(have_typeinfo_p): New function.
	(class TypeInfoVisitor): Update all calls to build_typeinfo.
	(build_typeinfo): Add error when -fno-rtti is set.

gcc/testsuite/ChangeLog:

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

	* gdc.test/fail_compilation/fail2456.d: New test.
	* gdc.test/fail_compilation/test18312.d: New test.
	* gdc.test/gdc-test.exp (gdc-convert-args): Handle -betterC.

From-SVN: r270518
This commit is contained in:
Iain Buclaw 2019-04-23 20:08:46 +00:00 committed by Iain Buclaw
parent 32efff9f94
commit c0aebc60b2
32 changed files with 509 additions and 160 deletions

View File

@ -1,3 +1,34 @@
2019-04-23 Iain Buclaw <ibuclaw@gdcproject.org>
* d-builtins.cc (d_init_versions): Add D_BetterC, D_ModuleInfo,
D_Exceptions, D_TypeInfo as predefined version conditions.
* d-codegen.cc (build_bounds_condition): Generate trap if D asserts
are turned off.
* d-frontend.cc (getTypeInfoType): Add error when -fno-rtti is set.
* d-lang.cc (d_init_options): Initialize new front-end options.
(d_handle_option): Handle -fdruntime, -fexceptions, and -frtti.
(d_post_options): Turn off D runtime features if -fno-druntime is set.
* d-spec.cc (lang_specific_driver): Handle -fdruntime.
* d-tree.h (have_typeinfo_p): Add prototype.
(build_typeinfo): Update prototype.
* decl.cc (DeclVisitor::visit(StructDeclaration)): Create typeinfo
only if TypeInfo exists.
(DeclVisitor::visit(ClassDeclaration)): Likewise.
(DeclVisitor::visit(InterfaceDeclaration)): Likewise.
(DeclVisitor::visit(EnumDeclaration)): Likewise.
* expr.cc: Update all calls to build_typeinfo.
* gdc.texi (Runtime Options): Document -fdruntime and -frtti.
* lang.opt: Add -fdruntime and -frtti.
* modules.cc (build_module_tree): Create module info only if
ModuleInfo exists.
* toir.cc (IRVisitor::visit(ThrowStatement)): Update test for
-fno-exceptions.
* typeinfo.cc (create_tinfo_types): Build internal typeinfo classes
only if Object exists.
(have_typeinfo_p): New function.
(class TypeInfoVisitor): Update all calls to build_typeinfo.
(build_typeinfo): Add error when -fno-rtti is set.
2019-04-21 Iain Buclaw <ibuclaw@gdcproject.org> 2019-04-21 Iain Buclaw <ibuclaw@gdcproject.org>
* decl.cc (DeclVisitor::visit(Import)): Set semanticRun after * decl.cc (DeclVisitor::visit(Import)): Set semanticRun after

View File

@ -447,6 +447,15 @@ d_init_versions (void)
if (global.params.useArrayBounds == BOUNDSCHECKoff) if (global.params.useArrayBounds == BOUNDSCHECKoff)
VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks"); 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"); VersionCondition::addPredefinedGlobalIdent ("all");
/* Emit all target-specific version identifiers. */ /* Emit all target-specific version identifiers. */

View File

@ -1762,7 +1762,10 @@ build_bounds_condition (const Loc& loc, tree index, tree len, bool inclusive)
have already taken care of implicit casts to unsigned. */ have already taken care of implicit casts to unsigned. */
tree condition = fold_build2 (inclusive ? GT_EXPR : GE_EXPR, tree condition = fold_build2 (inclusive ? GT_EXPR : GE_EXPR,
d_bool_type, index, len); 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); return build_condition (TREE_TYPE (index), condition, boundserr, index);
} }

View File

@ -612,8 +612,40 @@ eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
/* Build and return typeinfo type for TYPE. */ /* Build and return typeinfo type for TYPE. */
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); gcc_assert (type->ty != Terror);
create_typeinfo (type, sc ? sc->_module->importedFrom : NULL); create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
return type->vtinfo->type; return type->vtinfo->type;

View File

@ -276,6 +276,9 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options)
global.params.useOut = true; global.params.useOut = true;
global.params.useArrayBounds = BOUNDSCHECKdefault; global.params.useArrayBounds = BOUNDSCHECKdefault;
global.params.useSwitchError = true; global.params.useSwitchError = true;
global.params.useModuleInfo = true;
global.params.useTypeInfo = true;
global.params.useExceptions = true;
global.params.useInline = false; global.params.useInline = false;
global.params.obj = true; global.params.obj = true;
global.params.hdrStripPlainFunctions = 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); global.params.ddocfiles->push (arg);
break; break;
case OPT_fdruntime:
global.params.betterC = !value;
break;
case OPT_fdump_d_original: case OPT_fdump_d_original:
global.params.vcg_ast = value; global.params.vcg_ast = value;
break; break;
case OPT_fexceptions:
global.params.useExceptions = value;
break;
case OPT_fignore_unknown_pragmas: case OPT_fignore_unknown_pragmas:
global.params.ignoreUnsupportedPragmas = value; global.params.ignoreUnsupportedPragmas = value;
break; break;
@ -490,7 +501,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break; break;
case OPT_fmoduleinfo: case OPT_fmoduleinfo:
global.params.betterC = !value; global.params.useModuleInfo = value;
break; break;
case OPT_fonly_: case OPT_fonly_:
@ -509,6 +520,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.release = value; global.params.release = value;
break; break;
case OPT_frtti:
global.params.useTypeInfo = value;
break;
case OPT_fswitch_errors: case OPT_fswitch_errors:
global.params.useSwitchError = value; global.params.useSwitchError = value;
break; break;
@ -728,6 +743,20 @@ d_post_options (const char ** fn)
global.params.useSwitchError = false; 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 /* Turn off partitioning unless it was explicitly requested, as it doesn't
work with D exception chaining, where EH handler uses LSDA to determine work with D exception chaining, where EH handler uses LSDA to determine
whether two thrown exception are in the same context. */ whether two thrown exception are in the same context. */

View File

@ -144,6 +144,7 @@ lang_specific_driver (cl_decoded_option **in_decoded_options,
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
{ {
const char *arg = decoded_options[i].arg; const char *arg = decoded_options[i].arg;
const int value = decoded_options[i].value;
switch (decoded_options[i].opt_index) switch (decoded_options[i].opt_index)
{ {
@ -161,6 +162,11 @@ lang_specific_driver (cl_decoded_option **in_decoded_options,
args[i] |= SKIPOPT; args[i] |= SKIPOPT;
break; break;
case OPT_fdruntime:
if (!value)
need_phobos = false;
break;
case OPT_defaultlib_: case OPT_defaultlib_:
if (defaultlib != NULL) if (defaultlib != NULL)
free (CONST_CAST (char *, defaultlib)); free (CONST_CAST (char *, defaultlib));

View File

@ -647,11 +647,12 @@ extern void d_finish_compilation (tree *, int);
extern tree build_libcall (libcall_fn, Type *, int ...); extern tree build_libcall (libcall_fn, Type *, int ...);
/* In typeinfo.cc. */ /* In typeinfo.cc. */
extern bool have_typeinfo_p (ClassDeclaration *);
extern tree layout_typeinfo (TypeInfoDeclaration *); extern tree layout_typeinfo (TypeInfoDeclaration *);
extern tree layout_classinfo (ClassDeclaration *); extern tree layout_classinfo (ClassDeclaration *);
extern tree get_typeinfo_decl (TypeInfoDeclaration *); extern tree get_typeinfo_decl (TypeInfoDeclaration *);
extern tree get_classinfo_decl (ClassDeclaration *); 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_typeinfo (Type *, Module *);
extern void create_tinfo_types (Module *); extern void create_tinfo_types (Module *);
extern void layout_cpp_typeinfo (ClassDeclaration *); extern void layout_cpp_typeinfo (ClassDeclaration *);

View File

@ -379,7 +379,8 @@ public:
return; return;
/* Generate TypeInfo. */ /* Generate TypeInfo. */
create_typeinfo (d->type, NULL); if (have_typeinfo_p (Type::dtypeinfo))
create_typeinfo (d->type, NULL);
/* Generate static initializer. */ /* Generate static initializer. */
d->sinit = aggregate_initializer_decl (d); d->sinit = aggregate_initializer_decl (d);
@ -523,7 +524,9 @@ public:
d_finish_decl (d->sinit); d_finish_decl (d->sinit);
/* Put out the TypeInfo. */ /* 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); DECL_INITIAL (d->csym) = layout_classinfo (d);
d_linkonce_linkage (d->csym); d_linkonce_linkage (d->csym);
d_finish_decl (d->csym); d_finish_decl (d->csym);
@ -588,8 +591,11 @@ public:
d->csym = get_classinfo_decl (d); d->csym = get_classinfo_decl (d);
/* Put out the TypeInfo. */ /* Put out the TypeInfo. */
create_typeinfo (d->type, NULL); if (have_typeinfo_p (Type::dtypeinfo))
d->type->vtinfo->accept (this); {
create_typeinfo (d->type, NULL);
d->type->vtinfo->accept (this);
}
DECL_INITIAL (d->csym) = layout_classinfo (d); DECL_INITIAL (d->csym) = layout_classinfo (d);
d_linkonce_linkage (d->csym); d_linkonce_linkage (d->csym);
@ -622,7 +628,8 @@ public:
return; return;
/* Generate TypeInfo. */ /* Generate TypeInfo. */
create_typeinfo (d->type, NULL); if (have_typeinfo_p (Type::dtypeinfo))
create_typeinfo (d->type, NULL);
TypeEnum *tc = (TypeEnum *) d->type; TypeEnum *tc = (TypeEnum *) d->type;
if (tc->sym->members && !d->type->isZeroInit ()) if (tc->sym->members && !d->type->isZeroInit ())

View File

@ -1,4 +1,4 @@
065fbd452f2aa498fc3a554be48a5495bd98aa14 3b3dca8be201b443f17621cd29cf614007b5c75e
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository. merge done from the dlang/dmd repository.

View File

@ -839,7 +839,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
} }
else else
{ {
// _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n]) // __ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
uinteger_t n = 1; uinteger_t n = 1;
while (tv->ty == Tsarray) while (tv->ty == Tsarray)
@ -865,7 +865,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->upperIsInBounds = true;
((SliceExp *)ex)->lowerIsLessThanUpper = 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 a->push(new ExpStatement(loc, ex)); // combine in forward order
@ -896,7 +896,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
} }
else else
{ {
// _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
uinteger_t n = 1; uinteger_t n = 1;
while (tv->ty == Tsarray) while (tv->ty == Tsarray)
@ -922,7 +922,7 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->upperIsInBounds = true;
((SliceExp *)ex)->lowerIsLessThanUpper = 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))); a->push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex)));
} }
@ -1047,7 +1047,7 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
} }
else else
{ {
// _ArrayDtor((cast(S*)this.v.ptr)[0 .. n]) // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
uinteger_t n = 1; uinteger_t n = 1;
while (tv->ty == Tsarray) while (tv->ty == Tsarray)
@ -1073,7 +1073,7 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
((SliceExp *)ex)->upperIsInBounds = true; ((SliceExp *)ex)->upperIsInBounds = true;
((SliceExp *)ex)->lowerIsLessThanUpper = 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 e = Expression::combine(ex, e); // combine in reverse order
} }

View File

@ -131,7 +131,7 @@ Expression *implicitCastTo(Expression *e, Scope *sc, Type *t)
visit((Expression *)e); visit((Expression *)e);
Type *tb = result->type->toBasetype(); Type *tb = result->type->toBasetype();
if (tb->ty == Tarray) if (tb->ty == Tarray && global.params.useTypeInfo && Type::dtypeinfo)
semanticTypeInfo(sc, ((TypeDArray *)tb)->next); semanticTypeInfo(sc, ((TypeDArray *)tb)->next);
} }

View File

@ -2118,7 +2118,7 @@ Expression *VarDeclaration::callScopeDtor(Scope *)
} }
else else
{ {
// _ArrayDtor(v[0 .. n]) // __ArrayDtor(v[0 .. n])
e = new VarExp(loc, this); e = new VarExp(loc, this);
const d_uns64 sdsz = sd->type->size(); 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. // This is a hack so we can call destructors on const/immutable objects.
e->type = sd->type->arrayOf(); 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; return e;
} }

View File

@ -4633,8 +4633,8 @@ public:
fd = ((VarExp *)ecall)->var->isFuncDeclaration(); fd = ((VarExp *)ecall)->var->isFuncDeclaration();
assert(fd); assert(fd);
if (fd->ident == Id::_ArrayPostblit || if (fd->ident == Id::__ArrayPostblit ||
fd->ident == Id::_ArrayDtor) fd->ident == Id::__ArrayDtor)
{ {
assert(e->arguments->dim == 1); assert(e->arguments->dim == 1);
Expression *ea = (*e->arguments)[0]; Expression *ea = (*e->arguments)[0];
@ -4654,7 +4654,7 @@ public:
if (CTFEExp::isCantExp(result)) if (CTFEExp::isCantExp(result))
return; return;
if (fd->ident == Id::_ArrayPostblit) if (fd->ident == Id::__ArrayPostblit)
result = evaluatePostblit(istate, result); result = evaluatePostblit(istate, result);
else else
result = evaluateDtor(istate, result); result = evaluateDtor(istate, result);

View File

@ -575,69 +575,6 @@ Module *Module::parse()
error("has non-identifier characters in filename, use module declaration instead"); 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 // Insert module into the symbol table
Dsymbol *s = this; Dsymbol *s = this;
if (isPackageFile) if (isPackageFile)

View File

@ -23,7 +23,7 @@
#include "template.h" #include "template.h"
#include "tokens.h" #include "tokens.h"
Type *getTypeInfoType(Type *t, Scope *sc); Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
TypeTuple *toArgTypes(Type *t); TypeTuple *toArgTypes(Type *t);
void unSpeculative(Scope *sc, RootObject *o); void unSpeculative(Scope *sc, RootObject *o);
bool MODimplicitConv(MOD modfrom, MOD modto); bool MODimplicitConv(MOD modfrom, MOD modto);
@ -101,7 +101,7 @@ void semanticTypeInfo(Scope *sc, Type *t)
{ {
Scope scx; Scope scx;
scx._module = sd->getModule(); scx._module = sd->getModule();
getTypeInfoType(t, &scx); getTypeInfoType(sd->loc, t, &scx);
sd->requestTypeInfo = true; sd->requestTypeInfo = true;
} }
else if (!sc->minst) else if (!sc->minst)
@ -111,7 +111,7 @@ void semanticTypeInfo(Scope *sc, Type *t)
} }
else else
{ {
getTypeInfoType(t, sc); getTypeInfoType(sd->loc, t, sc);
sd->requestTypeInfo = true; sd->requestTypeInfo = true;
// Bugzilla 15149, if the typeid operand type comes from a // Bugzilla 15149, if the typeid operand type comes from a
@ -1165,9 +1165,12 @@ void StructDeclaration::semantic(Scope *sc)
buildOpAssign(this, sc2); buildOpAssign(this, sc2);
buildOpEquals(this, sc2); buildOpEquals(this, sc2);
xeq = buildXopEquals(this, sc2); if (global.params.useTypeInfo && Type::dtypeinfo) // these functions are used for TypeInfo
xcmp = buildXopCmp(this, sc2); {
xhash = buildXtoHash(this, sc2); xeq = buildXopEquals(this, sc2);
xcmp = buildXopCmp(this, sc2);
xhash = buildXtoHash(this, sc2);
}
inv = buildInv(this, sc2); inv = buildInv(this, sc2);

View File

@ -46,7 +46,7 @@ bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istar
bool symbolIsVisible(Module *mod, Dsymbol *s); bool symbolIsVisible(Module *mod, Dsymbol *s);
VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e); VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false); 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); bool MODimplicitConv(MOD modfrom, MOD modto);
MATCH MODmethodConv(MOD modfrom, MOD modto); MATCH MODmethodConv(MOD modfrom, MOD modto);
void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod); void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
@ -713,7 +713,8 @@ public:
return setError(); return setError();
} }
semanticTypeInfo(sc, e->type); if (global.params.useTypeInfo && Type::dtypeinfo)
semanticTypeInfo(sc, e->type);
result = e; result = e;
} }
@ -1819,7 +1820,7 @@ public:
{ {
// Handle this in the glue layer // Handle this in the glue layer
e = new TypeidExp(exp->loc, ta); e = new TypeidExp(exp->loc, ta);
e->type = getTypeInfoType(ta, sc); e->type = getTypeInfoType(exp->loc, ta, sc);
semanticTypeInfo(sc, ta); semanticTypeInfo(sc, ta);

View File

@ -246,6 +246,15 @@ public:
s->finalbody && (des = s->finalbody->isDtorExpStatement()) != NULL && s->finalbody && (des = s->finalbody->isDtorExpStatement()) != NULL &&
fd->nrvo_var == des->var) 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. /* Normally local variable dtors are called regardless exceptions.
* But for nrvo_var, its dtor should be called only when exception is thrown. * 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. // Do the semantic analysis on the internals of the function.
void FuncDeclaration::semantic3(Scope *sc) void FuncDeclaration::semantic3(Scope *sc)
@ -1708,7 +1727,10 @@ void FuncDeclaration::semantic3(Scope *sc)
Expression *exp = (*returns)[i]->exp; Expression *exp = (*returns)[i]->exp;
if (exp->op == TOKvar && ((VarExp *)exp)->var == vresult) 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 // Remove `return vresult;` from returns
returns->remove(i); returns->remove(i);
continue; continue;
@ -1901,7 +1923,7 @@ void FuncDeclaration::semantic3(Scope *sc)
if (returns) if (returns)
{ {
bool implicit0 = (f->next->ty == Tvoid && isMain()); bool implicit0 = addReturn0(this);
Type *tret = implicit0 ? Type::tint32 : f->next; Type *tret = implicit0 ? Type::tint32 : f->next;
assert(tret->ty != Tvoid); assert(tret->ty != Tvoid);
if (vresult || returnLabel) if (vresult || returnLabel)
@ -2123,7 +2145,7 @@ void FuncDeclaration::semantic3(Scope *sc)
a->push(s); a->push(s);
} }
} }
if (isMain() && f->next->ty == Tvoid) if (addReturn0(this))
{ {
// Add a return 0; statement // Add a return 0; statement
Statement *s = new ReturnStatement(Loc(), new IntegerExp(0)); Statement *s = new ReturnStatement(Loc(), new IntegerExp(0));

View File

@ -36,6 +36,14 @@ enum BOUNDSCHECK
BOUNDSCHECKsafeonly // do bounds checking only in @safe functions 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 enum CPU
{ {
x87, x87,
@ -116,6 +124,9 @@ struct Param
bool nofloat; // code should not pull in floating point support bool nofloat; // code should not pull in floating point support
bool ignoreUnsupportedPragmas; // rather than error on them bool ignoreUnsupportedPragmas; // rather than error on them
bool enforcePropertySyntax; 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 betterC; // be a "better C" compiler; no dependency on D runtime
bool addMain; // add a default main() function bool addMain; // add a default main() function
bool allInst; // generate code for all template instantiations bool allInst; // generate code for all template instantiations
@ -126,7 +137,9 @@ struct Param
bool showGaggedErrors; // print gagged errors anyway bool showGaggedErrors; // print gagged errors anyway
CPU cpu; // CPU instruction set to target 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 const char *argv0; // program name
Array<const char *> *modFileAliasStrings; // array of char*'s of -I module filename alias strings Array<const char *> *modFileAliasStrings; // array of char*'s of -I module filename alias strings

View File

@ -264,9 +264,9 @@ Msgtable msgtable[] =
{ "monitorexit", "_d_monitorexit" }, { "monitorexit", "_d_monitorexit" },
{ "criticalenter", "_d_criticalenter" }, { "criticalenter", "_d_criticalenter" },
{ "criticalexit", "_d_criticalexit" }, { "criticalexit", "_d_criticalexit" },
{ "_ArrayEq", NULL }, { "__ArrayEq", NULL },
{ "_ArrayPostblit", NULL }, { "__ArrayPostblit", NULL },
{ "_ArrayDtor", NULL }, { "__ArrayDtor", NULL },
{ "dup", NULL }, { "dup", NULL },
{ "_aaApply", NULL }, { "_aaApply", NULL },
{ "_aaApply2", NULL }, { "_aaApply2", NULL },

View File

@ -900,7 +900,9 @@ Expression *op_overload(Expression *e, Scope *sc)
if (t->ty != Tstruct) if (t->ty != Tstruct)
return false; return false;
semanticTypeInfo(sc, t); if (global.params.useTypeInfo && Type::dtypeinfo)
semanticTypeInfo(sc, t);
return ((TypeStruct *)t)->sym->hasIdentityEquals; return ((TypeStruct *)t)->sym->hasIdentityEquals;
} }
@ -919,9 +921,9 @@ Expression *op_overload(Expression *e, Scope *sc)
if (needsDirectEq(t1, t2, sc)) if (needsDirectEq(t1, t2, sc))
{ {
/* Rewrite as: /* 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); result = new CallExp(e->loc, eeq, e->e1, e->e2);
if (e->op == TOKnotequal) if (e->op == TOKnotequal)
result = new NotExp(e->loc, result); result = new NotExp(e->loc, result);

View File

@ -70,7 +70,6 @@ Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool
//printf("Parser::Parser()\n"); //printf("Parser::Parser()\n");
scanloc = loc; scanloc = loc;
#ifndef IN_GCC
if (loc.filename) if (loc.filename)
{ {
/* Create a pseudo-filename for the mixin string, as it may not even exist /* 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); sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum);
scanloc.filename = filename; scanloc.filename = filename;
} }
#endif
mod = module; mod = module;
md = NULL; md = NULL;

View File

@ -2073,8 +2073,19 @@ public:
CompoundStatement *cs; CompoundStatement *cs;
Statement *s; Statement *s;
if (global.params.useSwitchError) if (global.params.useSwitchError &&
s = new SwitchErrorStatement(ss->loc); 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 else
s = new ExpStatement(ss->loc, new HaltExp(ss->loc)); s = new ExpStatement(ss->loc, new HaltExp(ss->loc));
@ -3118,6 +3129,18 @@ public:
void visit(TryCatchStatement *tcs) 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; unsigned flags = 0;
const unsigned FLAGcpp = 1; const unsigned FLAGcpp = 1;
const unsigned FLAGd = 2; const unsigned FLAGd = 2;
@ -3227,7 +3250,14 @@ public:
return; 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); result = new CompoundStatement(tfs->loc, tfs->_body, tfs->finalbody);
return; return;
@ -3237,7 +3267,6 @@ public:
void visit(OnScopeStatement *oss) void visit(OnScopeStatement *oss)
{ {
#ifndef IN_GCC
if (oss->tok != TOKon_scope_exit) if (oss->tok != TOKon_scope_exit)
{ {
// scope(success) and scope(failure) are rewritten to try-catch(-finally) statement, // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
@ -3255,7 +3284,6 @@ public:
return setError(); return setError();
} }
} }
#endif
sc = sc->push(); sc = sc->push();
sc->tf = NULL; sc->tf = NULL;
@ -3281,6 +3309,18 @@ public:
{ {
//printf("ThrowStatement::semantic()\n"); //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(); FuncDeclaration *fd = sc->parent->isFuncDeclaration();
fd->hasReturnExp |= 2; fd->hasReturnExp |= 2;
@ -3463,7 +3503,6 @@ void semantic(Catch *c, Scope *sc)
{ {
//printf("Catch::semantic(%s)\n", ident->toChars()); //printf("Catch::semantic(%s)\n", ident->toChars());
#ifndef IN_GCC
if (sc->os && sc->os->tok != TOKon_scope_failure) if (sc->os && sc->os->tok != TOKon_scope_failure)
{ {
// If enclosing is scope(success) or scope(exit), this will be placed in finally block. // 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"); error(c->loc, "cannot put catch statement inside finally block");
c->errors = true; c->errors = true;
} }
#endif
ScopeDsymbol *sym = new ScopeDsymbol(); ScopeDsymbol *sym = new ScopeDsymbol();
sym->parent = sc->scopesym; sym->parent = sc->scopesym;

View File

@ -424,7 +424,7 @@ public:
tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3, tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3,
d_array_convert (e->e1), d_array_convert (e->e1),
d_array_convert (e->e2), d_array_convert (e->e2),
build_typeinfo (t1array)); build_typeinfo (e->loc, t1array));
if (e->op == TOKnotequal) if (e->op == TOKnotequal)
result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result); result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
@ -449,7 +449,7 @@ public:
/* Use _aaEqual() for associative arrays. */ /* Use _aaEqual() for associative arrays. */
TypeAArray *taa1 = (TypeAArray *) tb1; TypeAArray *taa1 = (TypeAArray *) tb1;
tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3, tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3,
build_typeinfo (taa1), build_typeinfo (e->loc, taa1),
build_expr (e->e1), build_expr (e->e1),
build_expr (e->e2)); build_expr (e->e2));
@ -485,7 +485,7 @@ public:
/* Build a call to _aaInX(). */ /* Build a call to _aaInX(). */
this->result_ = build_libcall (LIBCALL_AAINX, e->type, 3, this->result_ = build_libcall (LIBCALL_AAINX, e->type, 3,
build_expr (e->e2), build_expr (e->e2),
build_typeinfo (tkey), build_typeinfo (e->loc, tkey),
build_address (key)); build_address (key));
} }
@ -533,7 +533,7 @@ public:
tree call = build_libcall (LIBCALL_ADCMP2, Type::tint32, 3, tree call = build_libcall (LIBCALL_ADCMP2, Type::tint32, 3,
d_array_convert (e->e1), d_array_convert (e->e1),
d_array_convert (e->e2), d_array_convert (e->e2),
build_typeinfo (telem->arrayOf ())); build_typeinfo (e->loc, telem->arrayOf ()));
result = build_boolop (code, call, integer_zero_node); result = build_boolop (code, call, integer_zero_node);
this->result_ = d_convert (build_ctype (e->type), result); this->result_ = d_convert (build_ctype (e->type), result);
@ -745,13 +745,13 @@ public:
size_int (ndims), build_address (var)); size_int (ndims), build_address (var));
result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2, result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2,
build_typeinfo (e->type), arrs); build_typeinfo (e->loc, e->type), arrs);
} }
else else
{ {
/* Handle single concatenation (a ~ b). */ /* Handle single concatenation (a ~ b). */
result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3, 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->e1, &elemvars),
d_array_convert (etype, e->e2, &elemvars)); d_array_convert (etype, e->e2, &elemvars));
} }
@ -859,7 +859,7 @@ public:
{ {
gcc_assert (tb1->ty == Tarray || tb2->ty == Tsarray); 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)); tree ptr = build_address (build_expr (e->e1));
if ((tb2->ty == Tarray || tb2->ty == Tsarray) if ((tb2->ty == Tarray || tb2->ty == Tsarray)
@ -924,7 +924,7 @@ public:
? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT; ? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT;
tree result = build_libcall (libcall, ale->e1->type, 3, tree result = build_libcall (libcall, ale->e1->type, 3,
build_typeinfo (ale->e1->type), build_typeinfo (ale->loc, ale->e1->type),
newlength, ptr); newlength, ptr);
this->result_ = d_array_length (result); this->result_ = d_array_length (result);
@ -954,7 +954,8 @@ public:
libcall_fn libcall = (e->op == TOKconstruct) libcall_fn libcall = (e->op == TOKconstruct)
? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN; ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN;
/* So we can call postblits on const/immutable objects. */ /* 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, tree result = build_libcall (libcall, Type::tvoid, 4,
d_array_ptr (t1), d_array_ptr (t1),
@ -1004,7 +1005,7 @@ public:
? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN; ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN;
this->result_ = build_libcall (libcall, e->type, 3, 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->e2),
d_array_convert (e->e1)); d_array_convert (e->e1));
} }
@ -1133,7 +1134,7 @@ public:
{ {
/* Generate: _d_arrayctor(ti, from, to) */ /* Generate: _d_arrayctor(ti, from, to) */
result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3, result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3,
build_typeinfo (etype), build_typeinfo (e->loc, etype),
d_array_convert (e->e2), d_array_convert (e->e2),
d_array_convert (e->e1)); d_array_convert (e->e1));
} }
@ -1146,7 +1147,7 @@ public:
tree elembuf = build_local_temp (build_ctype (etype)); tree elembuf = build_local_temp (build_ctype (etype));
result = build_libcall (libcall, arrtype, 4, result = build_libcall (libcall, arrtype, 4,
build_typeinfo (etype), build_typeinfo (e->loc, etype),
d_array_convert (e->e2), d_array_convert (e->e2),
d_array_convert (e->e1), d_array_convert (e->e1),
build_address (elembuf)); build_address (elembuf));
@ -1210,13 +1211,13 @@ public:
{ {
libcall = LIBCALL_AAGETY; libcall = LIBCALL_AAGETY;
ptr = build_address (build_expr (e->e1)); ptr = build_address (build_expr (e->e1));
tinfo = build_typeinfo (tb1->unSharedOf ()->mutableOf ()); tinfo = build_typeinfo (e->loc, tb1->unSharedOf ()->mutableOf ());
} }
else else
{ {
libcall = LIBCALL_AAGETRVALUEX; libcall = LIBCALL_AAGETRVALUEX;
ptr = build_expr (e->e1); ptr = build_expr (e->e1);
tinfo = build_typeinfo (tkey); tinfo = build_typeinfo (e->loc, tkey);
} }
/* Index the associative array. */ /* Index the associative array. */
@ -1227,7 +1228,10 @@ public:
if (!e->indexIsInBounds && array_bounds_check ()) 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 = d_save_expr (result);
result = build_condition (TREE_TYPE (result), result = build_condition (TREE_TYPE (result),
d_truthvalue_conversion (result), d_truthvalue_conversion (result),
@ -1486,7 +1490,7 @@ public:
/* Might need to run destructor on array contents. */ /* Might need to run destructor on array contents. */
TypeStruct *ts = (TypeStruct *) telem; TypeStruct *ts = (TypeStruct *) telem;
if (ts->sym->dtor) if (ts->sym->dtor)
ti = build_typeinfo (tb1->nextOf ()); ti = build_typeinfo (e->loc, tb1->nextOf ());
} }
/* Generate: _delarray_t (&t1, ti); */ /* Generate: _delarray_t (&t1, ti); */
@ -1505,8 +1509,9 @@ public:
TypeStruct *ts = (TypeStruct *)tnext; TypeStruct *ts = (TypeStruct *)tnext;
if (ts->sym->dtor) if (ts->sym->dtor)
{ {
tree ti = build_typeinfo (e->loc, tnext);
this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid, this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid,
2, t1, build_typeinfo (tnext)); 2, t1, ti);
return; return;
} }
} }
@ -1536,7 +1541,7 @@ public:
this->result_ = build_libcall (LIBCALL_AADELX, Type::tbool, 3, this->result_ = build_libcall (LIBCALL_AADELX, Type::tbool, 3,
build_expr (e->e1), build_expr (e->e1),
build_typeinfo (tkey), build_typeinfo (e->loc, tkey),
build_address (index)); build_address (index));
} }
else else
@ -1967,7 +1972,8 @@ public:
tree assert_pass = void_node; tree assert_pass = void_node;
tree assert_fail; tree assert_fail;
if (global.params.useAssert) if (global.params.useAssert
&& global.params.checkAction == CHECKACTION_D)
{ {
/* Generate: ((bool) e1 ? (void)0 : _d_assert (...)) /* Generate: ((bool) e1 ? (void)0 : _d_assert (...))
or: (e1 != null ? e1._invariant() : _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 else
{ {
/* Assert contracts are turned off, if the contract condition has no /* Assert contracts are turned off, if the contract condition has no
@ -2066,7 +2079,7 @@ public:
{ {
if (Type *tid = isType (e->obj)) 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 the typeinfo is at an offset. */
if (tid->vtinfo->offset) if (tid->vtinfo->offset)
@ -2390,7 +2403,7 @@ public:
/* Generate: _d_newitemT() */ /* Generate: _d_newitemT() */
libcall_fn libcall = htype->isZeroInit () libcall_fn libcall = htype->isZeroInit ()
? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT; ? 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); new_call = build_libcall (libcall, tb, 1, arg);
} }
@ -2461,7 +2474,7 @@ public:
libcall_fn libcall = tarray->next->isZeroInit () libcall_fn libcall = tarray->next->isZeroInit ()
? LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT; ? LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT;
result = build_libcall (libcall, tb, 2, result = build_libcall (libcall, tb, 2,
build_typeinfo (e->type), build_typeinfo (e->loc, e->type),
build_expr (arg)); build_expr (arg));
} }
else else
@ -2491,7 +2504,7 @@ public:
libcall_fn libcall = telem->isZeroInit () libcall_fn libcall = telem->isZeroInit ()
? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX; ? 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 ()), tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()),
size_int (e->arguments->dim), size_int (e->arguments->dim),
build_address (var)); build_address (var));
@ -2519,7 +2532,7 @@ public:
libcall_fn libcall = tpointer->next->isZeroInit (e->loc) libcall_fn libcall = tpointer->next->isZeroInit (e->loc)
? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT; ? 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); result = build_libcall (libcall, tb, 1, arg);
if (e->arguments && e->arguments->dim == 1) if (e->arguments && e->arguments->dim == 1)
@ -2746,7 +2759,7 @@ public:
/* Allocate space on the memory managed heap. */ /* Allocate space on the memory managed heap. */
tree mem = build_libcall (LIBCALL_ARRAYLITERALTX, tree mem = build_libcall (LIBCALL_ARRAYLITERALTX,
etype->pointerTo (), 2, etype->pointerTo (), 2,
build_typeinfo (etype->arrayOf ()), build_typeinfo (e->loc, etype->arrayOf ()),
size_int (e->elements->dim)); size_int (e->elements->dim));
mem = d_save_expr (mem); mem = d_save_expr (mem);
@ -2821,7 +2834,7 @@ public:
build_address (avals)); build_address (avals));
tree mem = build_libcall (LIBCALL_ASSOCARRAYLITERALTX, Type::tvoidptr, 3, 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. */ /* Return an associative array pointed to by MEM. */
tree aatype = build_ctype (ta); tree aatype = build_ctype (ta);

View File

@ -233,6 +233,18 @@ is compiled into the program.
Turns on compilation of any @code{debug} code identified by @var{ident}. Turns on compilation of any @code{debug} code identified by @var{ident}.
@end table @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 @item -fno-invariants
@cindex @option{-finvariants} @cindex @option{-finvariants}
@cindex @option{-fno-invariants} @cindex @option{-fno-invariants}
@ -279,6 +291,13 @@ gdc -fno-assert -fbounds-check=safe -fno-invariants \
-fno-postconditions -fno-preconditions -fno-switch-errors -fno-postconditions -fno-preconditions -fno-switch-errors
@end example @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 @item -fno-switch-errors
@cindex @option{-fswitch-errors} @cindex @option{-fswitch-errors}
@cindex @option{-fno-switch-errors} @cindex @option{-fno-switch-errors}

View File

@ -229,6 +229,10 @@ fdoc-inc=
D Joined RejectNegative D Joined RejectNegative
-fdoc-inc=<file> Include a Ddoc macro <file>. -fdoc-inc=<file> Include a Ddoc macro <file>.
fdruntime
D
Assume that standard D runtime libraries and \"D main\" exist.
fdump-d-original fdump-d-original
D D
Display the frontend AST after parsing and semantic passes. 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>. -fmodule-file=<package.module>=<filespec> use <filespec> as source file for <package.module>.
fmoduleinfo fmoduleinfo
D D Var(flag_moduleinfo)
Generate ModuleInfo struct for output module. Generate ModuleInfo struct for output module.
fonly= fonly=
@ -269,6 +273,10 @@ frelease
D D
Compile release version. Compile release version.
frtti
D
; Documented in C
fswitch-errors fswitch-errors
D Var(flag_switch_errors) D Var(flag_switch_errors)
Generate code for switches without a default case. Generate code for switches without a default case.

View File

@ -776,7 +776,8 @@ build_module_tree (Module *decl)
/* Default behavior is to always generate module info because of templates. /* Default behavior is to always generate module info because of templates.
Can be switched off for not compiling against runtime library. */ 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")) && decl->ident != Identifier::idPool ("__entrypoint"))
{ {
if (mi.ctors || mi.ctorgates) if (mi.ctors || mi.ctorgates)

View File

@ -1120,7 +1120,7 @@ public:
InterfaceDeclaration *id = cd->isInterfaceDeclaration (); InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
tree arg = build_expr_dtor (s->exp); tree arg = build_expr_dtor (s->exp);
if (!flag_exceptions) if (!global.params.useExceptions)
{ {
static int warned = 0; static int warned = 0;
if (!warned) if (!warned)

View File

@ -227,6 +227,10 @@ create_tinfo_types (Module *mod)
ptr_type_node, d_uint_type, ptr_type_node, ptr_type_node, d_uint_type, ptr_type_node,
array_type_node, ptr_type_node, ptr_type_node, NULL); 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 /* Create all frontend TypeInfo classes declarations. We rely on all
existing, even if only just as stubs. */ existing, even if only just as stubs. */
if (!Type::dtypeinfo) if (!Type::dtypeinfo)
@ -289,6 +293,27 @@ create_tinfo_types (Module *mod)
ClassDeclaration::object); 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 /* Implements the visitor interface to build the TypeInfo layout of all
TypeInfoDeclaration AST classes emitted from the D Front-end. TypeInfoDeclaration AST classes emitted from the D Front-end.
All visit methods accept one parameter D, which holds the frontend AST 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) void layout_base (ClassDeclaration *cd)
{ {
gcc_assert (cd != NULL); 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_field (null_pointer_node);
} }
@ -490,7 +520,7 @@ public:
this->layout_base (Type::typeinfoconst); this->layout_base (Type::typeinfoconst);
/* TypeInfo for the mutable type. */ /* TypeInfo for the mutable type. */
this->layout_field (build_typeinfo (tm)); this->layout_field (build_typeinfo (d->loc, tm));
} }
/* Layout of TypeInfo_Immutable is: /* Layout of TypeInfo_Immutable is:
@ -507,7 +537,7 @@ public:
this->layout_base (Type::typeinfoinvariant); this->layout_base (Type::typeinfoinvariant);
/* TypeInfo for the mutable type. */ /* TypeInfo for the mutable type. */
this->layout_field (build_typeinfo (tm)); this->layout_field (build_typeinfo (d->loc, tm));
} }
/* Layout of TypeInfo_Shared is: /* Layout of TypeInfo_Shared is:
@ -524,7 +554,7 @@ public:
this->layout_base (Type::typeinfoshared); this->layout_base (Type::typeinfoshared);
/* TypeInfo for the unshared type. */ /* TypeInfo for the unshared type. */
this->layout_field (build_typeinfo (tm)); this->layout_field (build_typeinfo (d->loc, tm));
} }
/* Layout of TypeInfo_Inout is: /* Layout of TypeInfo_Inout is:
@ -541,7 +571,7 @@ public:
this->layout_base (Type::typeinfowild); this->layout_base (Type::typeinfowild);
/* TypeInfo for the mutable type. */ /* TypeInfo for the mutable type. */
this->layout_field (build_typeinfo (tm)); this->layout_field (build_typeinfo (d->loc, tm));
} }
/* Layout of TypeInfo_Enum is: /* Layout of TypeInfo_Enum is:
@ -561,7 +591,7 @@ public:
this->layout_base (Type::typeinfoenum); this->layout_base (Type::typeinfoenum);
/* TypeInfo for enum members. */ /* 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; : null_pointer_node;
this->layout_field (memtype); this->layout_field (memtype);
@ -593,7 +623,7 @@ public:
this->layout_base (Type::typeinfopointer); this->layout_base (Type::typeinfopointer);
/* TypeInfo for pointer-to type. */ /* 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: /* Layout of TypeInfo_Array is:
@ -610,7 +640,7 @@ public:
this->layout_base (Type::typeinfoarray); this->layout_base (Type::typeinfoarray);
/* TypeInfo for array of type. */ /* 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: /* Layout of TypeInfo_StaticArray is:
@ -628,7 +658,7 @@ public:
this->layout_base (Type::typeinfostaticarray); this->layout_base (Type::typeinfostaticarray);
/* TypeInfo for array of type. */ /* TypeInfo for array of type. */
this->layout_field (build_typeinfo (ti->next)); this->layout_field (build_typeinfo (d->loc, ti->next));
/* Static array length. */ /* Static array length. */
this->layout_field (size_int (ti->dim->toInteger ())); this->layout_field (size_int (ti->dim->toInteger ()));
@ -649,10 +679,10 @@ public:
this->layout_base (Type::typeinfoassociativearray); this->layout_base (Type::typeinfoassociativearray);
/* TypeInfo for value of type. */ /* 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. */ /* 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: /* Layout of TypeInfo_Vector is:
@ -669,7 +699,7 @@ public:
this->layout_base (Type::typeinfovector); this->layout_base (Type::typeinfovector);
/* TypeInfo for equivalent static array. */ /* 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: /* Layout of TypeInfo_Function is:
@ -687,7 +717,7 @@ public:
this->layout_base (Type::typeinfofunction); this->layout_base (Type::typeinfofunction);
/* TypeInfo for function return value. */ /* 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. */ /* Mangled name of function declaration. */
this->layout_string (d->tinfo->deco); this->layout_string (d->tinfo->deco);
@ -708,7 +738,7 @@ public:
this->layout_base (Type::typeinfodelegate); this->layout_base (Type::typeinfodelegate);
/* TypeInfo for delegate return value. */ /* 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. */ /* Mangled name of delegate declaration. */
this->layout_string (d->tinfo->deco); this->layout_string (d->tinfo->deco);
@ -1038,12 +1068,12 @@ public:
if (global.params.is64bit) if (global.params.is64bit)
{ {
/* TypeInfo m_arg1; */ /* TypeInfo m_arg1; */
tree arg1type = (sd->arg1type) ? build_typeinfo (sd->arg1type) tree arg1type = (sd->arg1type) ? build_typeinfo (d->loc, sd->arg1type)
: null_pointer_node; : null_pointer_node;
this->layout_field (arg1type); this->layout_field (arg1type);
/* TypeInfo m_arg2; */ /* TypeInfo m_arg2; */
tree arg2type = (sd->arg2type) ? build_typeinfo (sd->arg2type) tree arg2type = (sd->arg2type) ? build_typeinfo (d->loc, sd->arg2type)
: null_pointer_node; : null_pointer_node;
this->layout_field (arg2type); this->layout_field (arg2type);
} }
@ -1075,7 +1105,7 @@ public:
{ {
Parameter *arg = (*ti->arguments)[i]; Parameter *arg = (*ti->arguments)[i];
CONSTRUCTOR_APPEND_ELT (elms, size_int (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 ctor = build_constructor (build_ctype (satype), elms);
tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor); tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
@ -1311,8 +1341,20 @@ get_classinfo_decl (ClassDeclaration *decl)
/* Returns typeinfo reference for TYPE. */ /* Returns typeinfo reference for TYPE. */
tree 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); gcc_assert (type->ty != Terror);
create_typeinfo (type, NULL); create_typeinfo (type, NULL);
return build_address (get_typeinfo_decl (type->vtinfo)); return build_address (get_typeinfo_decl (type->vtinfo));

View File

@ -1,3 +1,9 @@
2019-04-23 Iain Buclaw <ibuclaw@gdcproject.org>
* gdc.test/fail_compilation/fail2456.d: New test.
* gdc.test/fail_compilation/test18312.d: New test.
* gdc.test/gdc-test.exp (gdc-convert-args): Handle -betterC.
2018-04-23 Sudakshina Das <sudi.das@arm.com> 2018-04-23 Sudakshina Das <sudi.das@arm.com>
* gcc.target/aarch64/bti-1.c: Add scan directive for gnu note section * gcc.target/aarch64/bti-1.c: Add scan directive for gnu note section

View File

@ -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
}
}

View File

@ -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 ~ "]";
}

View File

@ -39,6 +39,9 @@ proc gdc-convert-args { args } {
} elseif [string match "-allinst" $arg] { } elseif [string match "-allinst" $arg] {
lappend out "-fall-instantiations" lappend out "-fall-instantiations"
} elseif [string match "-betterC" $arg] {
lappend out "-fno-druntime"
} elseif { [string match "-boundscheck" $arg] } elseif { [string match "-boundscheck" $arg]
|| [string match "-boundscheck=on" $arg] } { || [string match "-boundscheck=on" $arg] } {
lappend out "-fbounds-check" lappend out "-fbounds-check"