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:
parent
32efff9f94
commit
c0aebc60b2
|
@ -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
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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 *);
|
||||||
|
|
|
@ -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 ())
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 },
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 ~ "]";
|
||||||
|
}
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue