d: Merge upstream dmd, druntime e4f8919591, phobos 3ad507b51.

D front-end changes:

    - Import dmd v2.101.0-beta.1.
    - Add predefined version `D_Optimized' when compiling with `-O'.
    - Shortened method syntax (DIP1043) is now enabled by default.
    - Array literals assigned to `scope' array variables are now
      allocated on the stack.
    - Implement `@system' variables (DIP1035), available behind the
      preview feature flag `-fpreview=systemvariables'.

D runtime changes:

    - Import druntime v2.101.0-beta.1.

Phobos changes:

    - Import phobos v2.101.0-beta.1.
    - Added `std.typecons.SafeRefCounted', that can be used in `@safe'
      code with `-fpreview=dip1000'.

gcc/d/ChangeLog:

	* d-attribs.cc (apply_user_attributes): Update for new front-end
	interface.
	* d-builtins.cc (d_init_versions): Predefine `D_Optimized' with
	compiling with optimizations enabled.
	* d-lang.cc (d_handle_option): Update for new front-end interface.
	Handle new option `-fpreview=systemvariables'.
	* dmd/MERGE: Merge upstream dmd e4f8919591.
	* dmd/VERSION: Bump version to v2.101.0-beta.1.
	* expr.cc (ExprVisitor::visit (AssignExp *)): Treat construction of
	static arrays from a call expression as a simple assignment.
	(ExprVisitor::visit (ArrayLiteralExp *)): Handle array literals with
	`scope' storage.
	* gdc.texi: Update documentation of `-fpreview=' options.
	* lang.opt (fpreview=shortenedmethods): Remove.
	(fpreview=systemvariables):  New option.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime e4f8919591.
	* src/MERGE: Merge upstream phobos 3ad507b51.

gcc/testsuite/ChangeLog:

	* gdc.dg/simd19630.d: Move tests with errors to ...
	* gdc.dg/simd19630b.d: ... here.  New test.
	* gdc.dg/simd19630c.d: New test.
	* gdc.dg/simd_ctfe.d: Removed.
	* gdc.dg/simd18867.d: New test.
	* gdc.dg/simd19788.d: New test.
	* gdc.dg/simd21469.d: New test.
	* gdc.dg/simd21672.d: New test.
	* gdc.dg/simd23077.d: New test.
	* gdc.dg/simd23084.d: New test.
	* gdc.dg/simd23085.d: New test.
	* gdc.dg/torture/simd19632.d: New test.
	* gdc.dg/torture/simd20041.d: New test.
	* gdc.dg/torture/simd21673.d: New test.
	* gdc.dg/torture/simd21676.d: New test.
	* gdc.dg/torture/simd22438.d: New test.
	* gdc.dg/torture/simd23009.d: New test.
	* gdc.dg/torture/simd23077.d: New test.
	* gdc.dg/torture/simd8.d: New test.
	* gdc.dg/torture/simd9.d: New test.
	* gdc.dg/torture/simd_prefetch.d: New test.
This commit is contained in:
Iain Buclaw 2022-10-29 09:05:54 +02:00
parent cfd8541805
commit 7e7ebe3e35
380 changed files with 3837 additions and 1994 deletions

View file

@ -426,7 +426,8 @@ build_attributes (Expressions *eattrs)
void
apply_user_attributes (Dsymbol *sym, tree node)
{
if (!sym->userAttribDecl)
UserAttributeDeclaration *uda = sym->userAttribDecl ();
if (uda == NULL)
return;
location_t saved_location = input_location;
@ -436,7 +437,7 @@ apply_user_attributes (Dsymbol *sym, tree node)
if (TYPE_P (node) && !COMPLETE_TYPE_P (node))
attr_flags |= ATTR_FLAG_TYPE_IN_PLACE;
Expressions *attrs = sym->userAttribDecl->getAttributes ();
Expressions *attrs = uda->getAttributes ();
decl_attributes (&node, build_attributes (attrs), attr_flags);
input_location = saved_location;

View file

@ -505,6 +505,9 @@ d_init_versions (void)
VersionCondition::addPredefinedGlobalIdent ("D_TypeInfo");
}
if (optimize)
VersionCondition::addPredefinedGlobalIdent ("D_Optimized");
VersionCondition::addPredefinedGlobalIdent ("all");
/* Emit all target-specific version identifiers. */

View file

@ -567,10 +567,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.fixAliasThis = value;
global.params.previewIn = value;
global.params.fix16997 = value;
global.params.noSharedAccess = value;
global.params.noSharedAccess = FeatureState::enabled;
global.params.rvalueRefParam = FeatureState::enabled;
global.params.inclusiveInContracts = value;
global.params.shortenedMethods = value;
global.params.systemVariables = FeatureState::enabled;
global.params.fixImmutableConv = value;
break;
@ -619,15 +619,15 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
case OPT_fpreview_nosharedaccess:
global.params.noSharedAccess = value;
global.params.noSharedAccess = FeatureState::enabled;
break;
case OPT_fpreview_rvaluerefparam:
global.params.rvalueRefParam = FeatureState::enabled;
break;
case OPT_fpreview_shortenedmethods:
global.params.shortenedMethods = value;
case OPT_fpreview_systemvariables:
global.params.systemVariables = FeatureState::enabled;
break;
case OPT_frelease:

View file

@ -1,4 +1,4 @@
4219ba670ce9ff92f3e874f0f048f2c28134c008
e4f89195913be1dc638707b1abb24c4f3ae7e0bf
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -1 +1 @@
v2.100.1
v2.101.0-beta.1

View file

@ -109,7 +109,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
CPPMANGLE cppmangle;
/// overridden symbol with pragma(mangle, "...") if not null
MangleOverride* mangleOverride;
MangleOverride* pMangleOverride;
/**
* !=null if is nested

View file

@ -82,7 +82,7 @@ public:
CPPMANGLE cppmangle;
// overridden symbol with pragma(mangle, "...")
MangleOverride *mangleOverride;
MangleOverride *pMangleOverride;
/* !=NULL if is nested
* pointing to the dsymbol that directly enclosing it.
* 1. The function that enclosing it (nested struct and class)
@ -174,7 +174,7 @@ public:
structalign_t alignment; // alignment applied outside of the struct
ThreeState ispod; // if struct is POD
private:
uint8_t bitFields;
uint16_t bitFields;
public:
static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject);
StructDeclaration *syntaxCopy(Dsymbol *s) override;

View file

@ -894,50 +894,9 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration
// then it's evaluated on demand in function semantic
return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this);
}
if (ident == Id.printf || ident == Id.scanf)
{
auto sc2 = sc.push();
if (ident == Id.printf)
// Override previous setting, never let both be set
sc2.flags = (sc2.flags & ~SCOPE.scanf) | SCOPE.printf;
else
sc2.flags = (sc2.flags & ~SCOPE.printf) | SCOPE.scanf;
return sc2;
}
return sc;
}
PINLINE evalPragmaInline(Scope* sc)
{
if (!args || args.dim == 0)
return PINLINE.default_;
Expression e = (*args)[0];
if (!e.type)
{
sc = sc.startCTFE();
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
e = e.ctfeInterpret();
e = e.toBoolean(sc);
if (e.isErrorExp())
error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars());
(*args)[0] = e;
}
const opt = e.toBool();
if (opt.isEmpty())
return PINLINE.default_;
else if (opt.get())
return PINLINE.always;
else
return PINLINE.never;
}
override const(char)* kind() const
{
return "pragma";

View file

@ -154,7 +154,6 @@ public:
PragmaDeclaration *syntaxCopy(Dsymbol *s) override;
Scope *newScope(Scope *sc) override;
PINLINE evalPragmaInline(Scope* sc);
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};

View file

@ -300,7 +300,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_);
auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf);
fop.storage_class |= STC.inference;
fop.flags |= FUNCFLAG.generated;
fop.isGenerated = true;
Expression e;
if (stc & STC.disable)
{
@ -581,7 +581,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopEquals;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
fop.flags |= FUNCFLAG.generated;
fop.isGenerated = true;
fop.parent = sd;
Expression e1 = new IdentifierExp(loc, Id.This);
Expression e2 = new IdentifierExp(loc, Id.p);
@ -705,7 +705,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopCmp;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
fop.flags |= FUNCFLAG.generated;
fop.isGenerated = true;
fop.parent = sd;
Expression e1 = new IdentifierExp(loc, Id.This);
Expression e2 = new IdentifierExp(loc, Id.p);
@ -823,7 +823,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
auto tf = new TypeFunction(ParameterList(parameters), Type.thash_t, LINK.d, STC.nothrow_ | STC.trusted);
Identifier id = Id.xtoHash;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
fop.flags |= FUNCFLAG.generated;
fop.isGenerated = true;
/* Do memberwise hashing.
*
@ -961,7 +961,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
{
//printf("Building __fieldDtor(), %s\n", e.toChars());
auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__fieldDtor);
dd.flags |= FUNCFLAG.generated;
dd.isGenerated = true;
dd.storage_class |= STC.inference;
dd.fbody = new ExpStatement(loc, e);
ad.members.push(dd);
@ -1017,7 +1017,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
e = Expression.combine(e, ce);
}
auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor);
dd.flags |= FUNCFLAG.generated;
dd.isGenerated = true;
dd.storage_class |= STC.inference;
dd.fbody = new ExpStatement(loc, e);
ad.members.push(dd);
@ -1088,7 +1088,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
stmts.push(new ExpStatement(loc, call));
stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
func.fbody = new CompoundStatement(loc, stmts);
func.flags |= FUNCFLAG.generated;
func.isGenerated = true;
auto sc2 = sc.push();
sc2.stc &= ~STC.static_; // not a static destructor
@ -1140,7 +1140,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
auto call = new CallExp(dtor.loc, dtor, null);
call.directcall = true; // non-virtual call Class.__dtor();
func.fbody = new ExpStatement(dtor.loc, call);
func.flags |= FUNCFLAG.generated;
func.isGenerated = true;
func.storage_class |= STC.inference;
auto sc2 = sc.push();
@ -1416,7 +1416,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
//printf("Building __fieldPostBlit()\n");
checkShared();
auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit);
dd.flags |= FUNCFLAG.generated;
dd.isGenerated = true;
dd.storage_class |= STC.inference | STC.scope_;
dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls);
sd.postblits.shift(dd);
@ -1454,7 +1454,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
checkShared();
auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit);
dd.flags |= FUNCFLAG.generated;
dd.isGenerated = true;
dd.storage_class |= STC.inference;
dd.fbody = new ExpStatement(loc, e);
sd.members.push(dd);
@ -1517,7 +1517,7 @@ private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const
auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true);
ccd.storage_class |= funcStc;
ccd.storage_class |= STC.inference;
ccd.flags |= FUNCFLAG.generated;
ccd.isGenerated = true;
return ccd;
}

View file

@ -23,6 +23,7 @@ if (__traits(isUnsigned, T))
string result = "extern (C++) pure nothrow @nogc @safe final {";
enum structName = __traits(identifier, S);
string initialValue = "";
foreach (size_t i, mem; __traits(allMembers, S))
{
static assert(is(typeof(__traits(getMember, S, mem)) == bool));
@ -37,8 +38,10 @@ if (__traits(isUnsigned, T))
v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~");
return v;
}";
initialValue = (__traits(getMember, S.init, mem) ? "1" : "0") ~ initialValue;
}
return result ~ "}\n private "~T.stringof~" bitFields;\n";
return result ~ "}\n private "~T.stringof~" bitFields = 0b" ~ initialValue ~ ";\n";
}
///
@ -48,7 +51,7 @@ unittest
{
bool x;
bool y;
bool z;
bool z = 1;
}
static struct S
@ -66,5 +69,5 @@ unittest
s.y = true;
assert(s.y);
assert(!s.x);
assert(!s.z);
assert(s.z);
}

View file

@ -144,9 +144,14 @@ struct FileMapping(Datum)
import core.stdc.string : strlen;
import core.stdc.stdlib : malloc;
import core.stdc.string : memcpy;
auto totalNameLength = filename.strlen() + 1;
name = cast(char*) memcpy(malloc(totalNameLength), filename, totalNameLength);
name || assert(0, "FileMapping: Out of memory.");
const totalNameLength = filename.strlen() + 1;
auto namex = cast(char*) malloc(totalNameLength);
if (!namex)
{
fprintf(stderr, "FileMapping: Out of memory.");
exit(1);
}
name = cast(char*) memcpy(namex, filename, totalNameLength);
}
/**

View file

@ -1906,6 +1906,8 @@ final class CParser(AST) : Parser!AST
{
auto str = asmName.peekString();
p.mangleOverride = str;
// p.adFlags |= AST.VarDeclaration.nounderscore;
p.adFlags |= 4; // cannot get above line to compile on Ubuntu
}
}
s = applySpecifier(s, specifier);
@ -5164,18 +5166,40 @@ final class CParser(AST) : Parser!AST
if (n.value == TOK.identifier && n.ident == Id.pop)
{
scan(&n);
while (n.value == TOK.comma)
size_t len = this.records.length;
if (n.value == TOK.rightParenthesis) // #pragma pack ( pop )
{
if (len == 0) // nothing to pop
return closingParen();
this.records.setDim(len - 1);
this.packs.setDim(len - 1);
if (len == 1) // stack is now empty
packalign.setDefault();
else
packalign = (*this.packs)[len - 1];
return closingParen();
}
while (n.value == TOK.comma) // #pragma pack ( pop ,
{
scan(&n);
if (n.value == TOK.identifier)
{
for (size_t len = this.records.length; len; --len)
/* pragma pack(pop, identifier
* Pop until identifier is found, pop that one too, and set
* alignment to the new top of the stack.
* If identifier is not found, do nothing.
*/
for ( ; len; --len)
{
if ((*this.records)[len - 1] == n.ident)
{
packalign = (*this.packs)[len - 1];
this.records.setDim(len - 1);
this.packs.setDim(len - 1);
if (len > 1)
packalign = (*this.packs)[len - 2];
else
packalign.setDefault(); // stack empty, use default
break;
}
}
@ -5184,14 +5208,18 @@ final class CParser(AST) : Parser!AST
else if (n.value == TOK.int32Literal)
{
setPackAlign(n);
this.records.push(null);
this.packs.push(packalign);
scan(&n);
}
else
{
error(loc, "identifier or alignment value expected following `#pragma pack(pop,` not `%s`", n.toChars());
scan(&n);
}
}
return closingParen();
}
/* # pragma pack ( integer )
* Sets alignment to integer
*/
if (n.value == TOK.int32Literal)
{
@ -5200,6 +5228,7 @@ final class CParser(AST) : Parser!AST
return closingParen();
}
/* # pragma pack ( )
* Sets alignment to default
*/
if (n.value == TOK.rightParenthesis)
{

View file

@ -615,7 +615,7 @@ private final class CppMangleVisitor : Visitor
if (!ti)
{
auto ag = s.isAggregateDeclaration();
const ident = (ag && ag.mangleOverride) ? ag.mangleOverride.id : s.ident;
const ident = (ag && ag.pMangleOverride) ? ag.pMangleOverride.id : s.ident;
this.writeNamespace(s.cppnamespace, () {
this.writeIdentifier(ident);
this.abiTags.writeSymbol(s, this);
@ -654,14 +654,14 @@ private final class CppMangleVisitor : Visitor
}
auto ag = ti.aliasdecl ? ti.aliasdecl.isAggregateDeclaration() : null;
if (ag && ag.mangleOverride)
if (ag && ag.pMangleOverride)
{
this.writeNamespace(
ti.toAlias().cppnamespace, () {
this.writeIdentifier(ag.mangleOverride.id);
if (ag.mangleOverride.agg && ag.mangleOverride.agg.isInstantiated())
this.writeIdentifier(ag.pMangleOverride.id);
if (ag.pMangleOverride.agg && ag.pMangleOverride.agg.isInstantiated())
{
auto to = ag.mangleOverride.agg.isInstantiated();
auto to = ag.pMangleOverride.agg.isInstantiated();
append(to);
this.abiTags.writeSymbol(to.tempdecl, this);
template_args(to);

View file

@ -327,6 +327,45 @@ MATCH implicitConvTo(Expression e, Type t)
return MATCH.nomatch;
}
// Apply mod bits to each function parameter,
// and see if we can convert the function argument to the modded type
static bool parametersModMatch(Expressions* args, TypeFunction tf, MOD mod)
{
const size_t nparams = tf.parameterList.length;
const size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended
foreach (const i; j .. args.dim)
{
Expression earg = (*args)[i];
Type targ = earg.type.toBasetype();
static if (LOG)
{
printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
}
if (i - j < nparams)
{
Parameter fparam = tf.parameterList[i - j];
if (fparam.isLazy())
return false; // not sure what to do with this
Type tparam = fparam.type;
if (!tparam)
continue;
if (fparam.isReference())
{
if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
return false;
continue;
}
}
static if (LOG)
{
printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
}
if (implicitMod(earg, targ, mod) == MATCH.nomatch)
return false;
}
return true;
}
MATCH visitAdd(AddExp e)
{
version (none)
@ -894,9 +933,6 @@ MATCH implicitConvTo(Expression e, Type t)
/* Apply mod bits to each function parameter,
* and see if we can convert the function argument to the modded type
*/
size_t nparams = tf.parameterList.length;
size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended
if (auto dve = e.e1.isDotVarExp())
{
/* Treat 'this' as just another function argument
@ -905,36 +941,9 @@ MATCH implicitConvTo(Expression e, Type t)
if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
return result;
}
foreach (const i; j .. e.arguments.dim)
{
Expression earg = (*e.arguments)[i];
Type targ = earg.type.toBasetype();
static if (LOG)
{
printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
}
if (i - j < nparams)
{
Parameter fparam = tf.parameterList[i - j];
if (fparam.isLazy())
return result; // not sure what to do with this
Type tparam = fparam.type;
if (!tparam)
continue;
if (fparam.isReference())
{
if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
return result;
continue;
}
}
static if (LOG)
{
printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
}
if (implicitMod(earg, targ, mod) == MATCH.nomatch)
return result;
}
if (!parametersModMatch(e.arguments, tf, mod))
return result;
/* Success
*/
@ -1206,47 +1215,16 @@ MATCH implicitConvTo(Expression e, Type t)
if (tf.purity == PURE.impure)
return MATCH.nomatch; // impure
// Allow a conversion to immutable type, or
// conversions of mutable types between thread-local and shared.
if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
{
return MATCH.nomatch;
}
// Allow a conversion to immutable type, or
// conversions of mutable types between thread-local and shared.
Expressions* args = e.arguments;
size_t nparams = tf.parameterList.length;
// if TypeInfoArray was prepended
size_t j = tf.isDstyleVariadic();
for (size_t i = j; i < e.arguments.dim; ++i)
if (!parametersModMatch(e.arguments, tf, mod))
{
Expression earg = (*args)[i];
Type targ = earg.type.toBasetype();
static if (LOG)
{
printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
}
if (i - j < nparams)
{
Parameter fparam = tf.parameterList[i - j];
if (fparam.isLazy())
return MATCH.nomatch; // not sure what to do with this
Type tparam = fparam.type;
if (!tparam)
continue;
if (fparam.isReference())
{
if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
return MATCH.nomatch;
continue;
}
}
static if (LOG)
{
printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
}
if (implicitMod(earg, targ, mod) == MATCH.nomatch)
return MATCH.nomatch;
return MATCH.nomatch;
}
}

View file

@ -227,6 +227,7 @@ extern (C++) abstract class Declaration : Dsymbol
ubyte adFlags; // control re-assignment of AliasDeclaration (put here for packing reasons)
enum wasRead = 1; // set if AliasDeclaration was read
enum ignoreRead = 2; // ignore any reads of AliasDeclaration
enum nounderscore = 4; // don't prepend _ to mangled name
Symbol* isym; // import version of csym
@ -481,6 +482,11 @@ extern (C++) abstract class Declaration : Dsymbol
return (storage_class & STC.scope_) != 0;
}
final bool isReturn() const pure nothrow @nogc @safe
{
return (storage_class & STC.return_) != 0;
}
final bool isSynchronized() const pure nothrow @nogc @safe
{
return (storage_class & STC.synchronized_) != 0;
@ -542,6 +548,11 @@ extern (C++) abstract class Declaration : Dsymbol
return (storage_class & STC.future) != 0;
}
final extern(D) bool isSystem() const pure nothrow @nogc @safe
{
return (storage_class & STC.system) != 0;
}
override final Visibility visible() pure nothrow @nogc @safe
{
return visibility;
@ -780,7 +791,17 @@ extern (C++) final class AliasDeclaration : Declaration
* is not overloadable.
*/
if (type)
return false;
{
/*
If type has been resolved already we could
still be inserting an alias from an import.
If we are handling an alias then pretend
it was inserting and return true, if not then
false since we didn't even pretend to insert something.
*/
return this._import && this.equals(s);
}
/* When s is added in member scope by static if, mixin("code") or others,
* aliassym is determined already. See the case in: test/compilable/test61.d
@ -1634,7 +1655,7 @@ extern (C++) class VarDeclaration : Declaration
// Add this VarDeclaration to fdv.closureVars[] if not already there
if (!sc.intypeof && !(sc.flags & SCOPE.compile) &&
// https://issues.dlang.org/show_bug.cgi?id=17605
(fdv.flags & FUNCFLAG.compileTimeOnly || !(fdthis.flags & FUNCFLAG.compileTimeOnly))
(fdv.isCompileTimeOnly || !fdthis.isCompileTimeOnly)
)
{
if (!fdv.closureVars.contains(this))
@ -1754,16 +1775,21 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
//printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
static void print(const ref FieldState fieldState)
enum log = false;
static if (log)
{
printf("FieldState.offset = %d bytes\n", fieldState.offset);
printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset);
printf(" .bitOffset = %d bits\n", fieldState.bitOffset);
printf(" .fieldSize = %d bytes\n", fieldState.fieldSize);
printf(" .inFlight = %d\n\n", fieldState.inFlight);
printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
void print(const ref FieldState fieldState)
{
printf("FieldState.offset = %d bytes\n", fieldState.offset);
printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset);
printf(" .bitOffset = %d bits\n", fieldState.bitOffset);
printf(" .fieldSize = %d bytes\n", fieldState.fieldSize);
printf(" .inFlight = %d\n", fieldState.inFlight);
printf(" fieldWidth = %d bits\n", fieldWidth);
}
print(fieldState);
}
//print(fieldState);
Type t = type.toBasetype();
const bool anon = isAnonymous();
@ -1780,6 +1806,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
assert(sz != SIZE_INVALID && sz < uint.max);
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize);
if (fieldWidth == 0 && !anon)
error(loc, "named bit fields cannot have 0 width");
@ -1790,6 +1817,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
void startNewField()
{
if (log) printf("startNewField()\n");
uint alignsize;
if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
@ -1881,15 +1909,15 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
if (!fieldState.inFlight)
{
//printf("not in flight\n");
startNewField();
}
else if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
if (fieldState.bitOffset + fieldWidth > memsize * 8)
{
//printf("start1 fieldState.bitOffset:%u fieldWidth:%u memsize:%u\n", fieldState.bitOffset, fieldWidth, memsize);
startNewField();
}
// If the bit-field spans more units of alignment than its type,
// start a new field at the next alignment boundary.
if (fieldState.bitOffset == fieldState.fieldSize * 8)
startNewField(); // the bit field is full
else
{
// if alignment boundary is crossed
@ -1909,6 +1937,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
if (memsize != fieldState.fieldSize ||
fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
{
//printf("new field\n");
startNewField();
}
}

View file

@ -139,6 +139,7 @@ public:
bool isWild() const { return (storage_class & STCwild) != 0; }
bool isAuto() const { return (storage_class & STCauto) != 0; }
bool isScope() const { return (storage_class & STCscope) != 0; }
bool isReturn() const { return (storage_class & STCreturn) != 0; }
bool isSynchronized() const { return (storage_class & STCsynchronized) != 0; }
bool isParameter() const { return (storage_class & STCparameter) != 0; }
bool isDeprecated() const override final { return (storage_class & STCdeprecated) != 0; }
@ -615,7 +616,54 @@ public:
AttributeViolation* safetyViolation;
unsigned flags; // FUNCFLAGxxxxx
// Formerly FUNCFLAGS
uint32_t flags;
bool purityInprocess() const;
bool purityInprocess(bool v);
bool safetyInprocess() const;
bool safetyInprocess(bool v);
bool nothrowInprocess() const;
bool nothrowInprocess(bool v);
bool nogcInprocess() const;
bool nogcInprocess(bool v);
bool returnInprocess() const;
bool returnInprocess(bool v);
bool inlineScanned() const;
bool inlineScanned(bool v);
bool inferScope() const;
bool inferScope(bool v);
bool hasCatches() const;
bool hasCatches(bool v);
bool isCompileTimeOnly() const;
bool isCompileTimeOnly(bool v);
bool printf() const;
bool printf(bool v);
bool scanf() const;
bool scanf(bool v);
bool noreturn() const;
bool noreturn(bool v);
bool isNRVO() const;
bool isNRVO(bool v);
bool isNaked() const;
bool isNaked(bool v);
bool isGenerated() const;
bool isGenerated(bool v);
bool isIntroducing() const;
bool isIntroducing(bool v);
bool hasSemantic3Errors() const;
bool hasSemantic3Errors(bool v);
bool hasNoEH() const;
bool hasNoEH(bool v);
bool inferRetType() const;
bool inferRetType(bool v);
bool hasDualContext() const;
bool hasDualContext(bool v);
bool hasAlwaysInlines() const;
bool hasAlwaysInlines(bool v);
bool isCrtCtor() const;
bool isCrtCtor(bool v);
bool isCrtDtor() const;
bool isCrtDtor(bool v);
// Data for a function declaration that is needed for the Objective-C
// integration.
@ -655,22 +703,6 @@ public:
bool isNogc();
bool isNogcBypassingInference();
bool isNRVO() const;
void isNRVO(bool v);
bool isNaked() const;
void isNaked(bool v);
bool isGenerated() const;
void isGenerated(bool v);
bool isIntroducing() const;
bool hasSemantic3Errors() const;
bool hasNoEH() const;
bool inferRetType() const;
bool hasDualContext() const;
bool hasAlwaysInlines() const;
bool isCrtCtor() const;
void isCrtCtor(bool v);
bool isCrtDtor() const;
void isCrtDtor(bool v);
virtual bool isNested() const;
AggregateDeclaration *isThis() override;

View file

@ -2872,6 +2872,12 @@ public:
else
m = v.getConstInitializer(true);
}
else if (v.type.isTypeNoreturn())
{
// Noreturn field with default initializer
(*elems)[fieldsSoFar + i] = null;
continue;
}
else
m = v.type.defaultInitLiteral(e.loc);
if (exceptionOrCant(m))

View file

@ -98,13 +98,13 @@ private const(char)[] getFilename(Identifier[] packages, Identifier ident) nothr
{
const(char)[] filename = ident.toString();
if (packages.length == 0)
return filename;
OutBuffer buf;
OutBuffer dotmods;
auto modAliases = &global.params.modFileAliasStrings;
if (packages.length == 0 && modAliases.length == 0)
return filename;
void checkModFileAlias(const(char)[] p)
{
/* Check and replace the contents of buf[] with
@ -308,7 +308,7 @@ extern (C++) class Package : ScopeDsymbol
packages ~= s.ident;
reverse(packages);
if (FileManager.lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null))
if (Module.find(getFilename(packages, ident)))
Module.load(Loc.initial, packages, this.ident);
else
isPkgMod = PKG.package_;
@ -492,6 +492,16 @@ extern (C++) final class Module : Package
return new Module(Loc.initial, filename, ident, doDocComment, doHdrGen);
}
static const(char)* find(const(char)* filename)
{
return find(filename.toDString).ptr;
}
extern (D) static const(char)[] find(const(char)[] filename)
{
return FileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null);
}
extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident)
{
return load(loc, packages ? (*packages)[] : null, ident);
@ -506,7 +516,7 @@ extern (C++) final class Module : Package
// foo\bar\baz
const(char)[] filename = getFilename(packages, ident);
// Look for the source file
if (const result = FileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null))
if (const result = find(filename))
filename = result; // leaks
auto m = new Module(loc, filename, ident, 0, 0);
@ -703,232 +713,12 @@ extern (C++) final class Module : Package
/// ditto
extern (D) Module parseModule(AST)()
{
enum Endian { little, big}
enum SourceEncoding { utf16, utf32}
/*
* Convert a buffer from UTF32 to UTF8
* Params:
* Endian = is the buffer big/little endian
* buf = buffer of UTF32 data
* Returns:
* input buffer reencoded as UTF8
*/
char[] UTF32ToUTF8(Endian endian)(const(char)[] buf)
{
static if (endian == Endian.little)
alias readNext = Port.readlongLE;
else
alias readNext = Port.readlongBE;
if (buf.length & 3)
{
error("odd length of UTF-32 char source %llu", cast(ulong) buf.length);
return null;
}
const (uint)[] eBuf = cast(const(uint)[])buf;
OutBuffer dbuf;
dbuf.reserve(eBuf.length);
foreach (i; 0 .. eBuf.length)
{
const u = readNext(&eBuf[i]);
if (u & ~0x7F)
{
if (u > 0x10FFFF)
{
error("UTF-32 value %08x greater than 0x10FFFF", u);
return null;
}
dbuf.writeUTF8(u);
}
else
dbuf.writeByte(u);
}
dbuf.writeByte(0); //add null terminator
return dbuf.extractSlice();
}
/*
* Convert a buffer from UTF16 to UTF8
* Params:
* Endian = is the buffer big/little endian
* buf = buffer of UTF16 data
* Returns:
* input buffer reencoded as UTF8
*/
char[] UTF16ToUTF8(Endian endian)(const(char)[] buf)
{
static if (endian == Endian.little)
alias readNext = Port.readwordLE;
else
alias readNext = Port.readwordBE;
if (buf.length & 1)
{
error("odd length of UTF-16 char source %llu", cast(ulong) buf.length);
return null;
}
const (ushort)[] eBuf = cast(const(ushort)[])buf;
OutBuffer dbuf;
dbuf.reserve(eBuf.length);
//i will be incremented in the loop for high codepoints
foreach (ref i; 0 .. eBuf.length)
{
uint u = readNext(&eBuf[i]);
if (u & ~0x7F)
{
if (0xD800 <= u && u < 0xDC00)
{
i++;
if (i >= eBuf.length)
{
error("surrogate UTF-16 high value %04x at end of file", u);
return null;
}
const u2 = readNext(&eBuf[i]);
if (u2 < 0xDC00 || 0xE000 <= u2)
{
error("surrogate UTF-16 low value %04x out of range", u2);
return null;
}
u = (u - 0xD7C0) << 10;
u |= (u2 - 0xDC00);
}
else if (u >= 0xDC00 && u <= 0xDFFF)
{
error("unpaired surrogate UTF-16 value %04x", u);
return null;
}
else if (u == 0xFFFE || u == 0xFFFF)
{
error("illegal UTF-16 value %04x", u);
return null;
}
dbuf.writeUTF8(u);
}
else
dbuf.writeByte(u);
}
dbuf.writeByte(0); //add a terminating null byte
return dbuf.extractSlice();
}
const(char)* srcname = srcfile.toChars();
//printf("Module::parse(srcname = '%s')\n", srcname);
isPackageFile = isPackageFileName(srcfile);
const(char)[] buf = cast(const(char)[]) this.src;
bool needsReencoding = true;
bool hasBOM = true; //assume there's a BOM
Endian endian;
SourceEncoding sourceEncoding;
if (buf.length >= 2)
{
/* Convert all non-UTF-8 formats to UTF-8.
* BOM : https://www.unicode.org/faq/utf_bom.html
* 00 00 FE FF UTF-32BE, big-endian
* FF FE 00 00 UTF-32LE, little-endian
* FE FF UTF-16BE, big-endian
* FF FE UTF-16LE, little-endian
* EF BB BF UTF-8
*/
if (buf[0] == 0xFF && buf[1] == 0xFE)
{
endian = Endian.little;
sourceEncoding = buf.length >= 4 && buf[2] == 0 && buf[3] == 0
? SourceEncoding.utf32
: SourceEncoding.utf16;
}
else if (buf[0] == 0xFE && buf[1] == 0xFF)
{
endian = Endian.big;
sourceEncoding = SourceEncoding.utf16;
}
else if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
{
endian = Endian.big;
sourceEncoding = SourceEncoding.utf32;
}
else if (buf.length >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
{
needsReencoding = false;//utf8 with BOM
}
else
{
/* There is no BOM. Make use of Arcane Jill's insight that
* the first char of D source must be ASCII to
* figure out the encoding.
*/
hasBOM = false;
if (buf.length >= 4 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
{
endian = Endian.little;
sourceEncoding = SourceEncoding.utf32;
}
else if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
{
endian = Endian.big;
sourceEncoding = SourceEncoding.utf32;
}
else if (buf.length >= 2 && buf[1] == 0) //try to check for UTF-16
{
endian = Endian.little;
sourceEncoding = SourceEncoding.utf16;
}
else if (buf[0] == 0)
{
endian = Endian.big;
sourceEncoding = SourceEncoding.utf16;
}
else {
// It's UTF-8
needsReencoding = false;
if (buf[0] >= 0x80)
{
error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
return null;
}
}
}
//throw away BOM
if (hasBOM)
{
if (!needsReencoding) buf = buf[3..$];// utf-8 already
else if (sourceEncoding == SourceEncoding.utf32) buf = buf[4..$];
else buf = buf[2..$]; //utf 16
}
}
// Assume the buffer is from memory and has not be read from disk. Assume UTF-8.
else if (buf.length >= 1 && (buf[0] == '\0' || buf[0] == 0x1A))
needsReencoding = false;
//printf("%s, %d, %d, %d\n", srcfile.name.toChars(), needsReencoding, endian == Endian.little, sourceEncoding == SourceEncoding.utf16);
if (needsReencoding)
{
if (sourceEncoding == SourceEncoding.utf16)
{
buf = endian == Endian.little
? UTF16ToUTF8!(Endian.little)(buf)
: UTF16ToUTF8!(Endian.big)(buf);
}
else
{
buf = endian == Endian.little
? UTF32ToUTF8!(Endian.little)(buf)
: UTF32ToUTF8!(Endian.big)(buf);
}
// an error happened on UTF conversion
if (buf is null) return null;
}
const(char)[] buf = processSource(src, this);
// an error happened on UTF conversion
if (buf is null) return null;
/* If it starts with the string "Ddoc", then it's a documentation
* source file.
@ -1533,3 +1323,192 @@ extern (C++) struct ModuleDeclaration
return this.toChars().toDString;
}
}
/**
* Process the content of a source file
*
* Attempts to find which encoding it is using, if it has BOM,
* and then normalize the source to UTF-8. If no encoding is required,
* a slice of `src` will be returned without extra allocation.
*
* Params:
* src = Content of the source file to process
* mod = Module matching `src`, used for error handling
*
* Returns:
* UTF-8 encoded variant of `src`, stripped of any BOM,
* or `null` if an error happened.
*/
private const(char)[] processSource (const(ubyte)[] src, Module mod)
{
enum SourceEncoding { utf16, utf32}
enum Endian { little, big}
/*
* Convert a buffer from UTF32 to UTF8
* Params:
* Endian = is the buffer big/little endian
* buf = buffer of UTF32 data
* Returns:
* input buffer reencoded as UTF8
*/
char[] UTF32ToUTF8(Endian endian)(const(char)[] buf)
{
static if (endian == Endian.little)
alias readNext = Port.readlongLE;
else
alias readNext = Port.readlongBE;
if (buf.length & 3)
{
mod.error("odd length of UTF-32 char source %llu", cast(ulong) buf.length);
return null;
}
const (uint)[] eBuf = cast(const(uint)[])buf;
OutBuffer dbuf;
dbuf.reserve(eBuf.length);
foreach (i; 0 .. eBuf.length)
{
const u = readNext(&eBuf[i]);
if (u & ~0x7F)
{
if (u > 0x10FFFF)
{
mod.error("UTF-32 value %08x greater than 0x10FFFF", u);
return null;
}
dbuf.writeUTF8(u);
}
else
dbuf.writeByte(u);
}
dbuf.writeByte(0); //add null terminator
return dbuf.extractSlice();
}
/*
* Convert a buffer from UTF16 to UTF8
* Params:
* Endian = is the buffer big/little endian
* buf = buffer of UTF16 data
* Returns:
* input buffer reencoded as UTF8
*/
char[] UTF16ToUTF8(Endian endian)(const(char)[] buf)
{
static if (endian == Endian.little)
alias readNext = Port.readwordLE;
else
alias readNext = Port.readwordBE;
if (buf.length & 1)
{
mod.error("odd length of UTF-16 char source %llu", cast(ulong) buf.length);
return null;
}
const (ushort)[] eBuf = cast(const(ushort)[])buf;
OutBuffer dbuf;
dbuf.reserve(eBuf.length);
//i will be incremented in the loop for high codepoints
foreach (ref i; 0 .. eBuf.length)
{
uint u = readNext(&eBuf[i]);
if (u & ~0x7F)
{
if (0xD800 <= u && u < 0xDC00)
{
i++;
if (i >= eBuf.length)
{
mod.error("surrogate UTF-16 high value %04x at end of file", u);
return null;
}
const u2 = readNext(&eBuf[i]);
if (u2 < 0xDC00 || 0xE000 <= u2)
{
mod.error("surrogate UTF-16 low value %04x out of range", u2);
return null;
}
u = (u - 0xD7C0) << 10;
u |= (u2 - 0xDC00);
}
else if (u >= 0xDC00 && u <= 0xDFFF)
{
mod.error("unpaired surrogate UTF-16 value %04x", u);
return null;
}
else if (u == 0xFFFE || u == 0xFFFF)
{
mod.error("illegal UTF-16 value %04x", u);
return null;
}
dbuf.writeUTF8(u);
}
else
dbuf.writeByte(u);
}
dbuf.writeByte(0); //add a terminating null byte
return dbuf.extractSlice();
}
const(char)[] buf = cast(const(char)[]) src;
// Assume the buffer is from memory and has not be read from disk. Assume UTF-8.
if (buf.length < 2)
return buf;
/* Convert all non-UTF-8 formats to UTF-8.
* BOM : https://www.unicode.org/faq/utf_bom.html
* 00 00 FE FF UTF-32BE, big-endian
* FF FE 00 00 UTF-32LE, little-endian
* FE FF UTF-16BE, big-endian
* FF FE UTF-16LE, little-endian
* EF BB BF UTF-8
*/
if (buf[0] == 0xFF && buf[1] == 0xFE)
{
if (buf.length >= 4 && buf[2] == 0 && buf[3] == 0)
return UTF32ToUTF8!(Endian.little)(buf[4 .. $]);
return UTF16ToUTF8!(Endian.little)(buf[2 .. $]);
}
if (buf[0] == 0xFE && buf[1] == 0xFF)
return UTF16ToUTF8!(Endian.big)(buf[2 .. $]);
if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
return UTF32ToUTF8!(Endian.big)(buf[4 .. $]);
if (buf.length >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
return buf[3 .. $];
/* There is no BOM. Make use of Arcane Jill's insight that
* the first char of D source must be ASCII to
* figure out the encoding.
*/
if (buf.length >= 4 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
return UTF32ToUTF8!(Endian.little)(buf);
if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
return UTF32ToUTF8!(Endian.big)(buf);
// try to check for UTF-16
if (buf.length >= 2 && buf[1] == 0)
return UTF16ToUTF8!(Endian.little)(buf);
if (buf[0] == 0)
return UTF16ToUTF8!(Endian.big)(buf);
// It's UTF-8
if (buf[0] >= 0x80)
{
mod.error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
return null;
}
return buf;
}

View file

@ -63,17 +63,13 @@ enum SCOPE
free = 0x8000, /// is on free list
fullinst = 0x10000, /// fully instantiate templates
// The following are mutually exclusive
printf = 0x4_0000, /// printf-style function
scanf = 0x8_0000, /// scanf-style function
}
/// Flags that are carried along with a scope push()
private enum PersistentFlags =
SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility |
SCOPE.printf | SCOPE.scanf | SCOPE.Cfile;
SCOPE.Cfile;
struct Scope
{

View file

@ -216,6 +216,11 @@ extern (C++) class StructDeclaration : AggregateDeclaration
bool hasIdentityEquals; // true if has identity opEquals
bool hasNoFields; // has no fields
bool hasCopyCtor; // copy constructor
bool hasPointerField; // members with indirections
bool hasVoidInitPointers; // void-initialized unsafe fields
bool hasSystemFields; // @system members
bool hasFieldWithInvariant; // invariants
bool computedTypeProperties;// the above 3 fields are computed
// Even if struct is defined as non-root symbol, some built-in operations
// (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
// For those, today TypeInfo_Struct is generated in COMDAT.
@ -223,7 +228,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
}
import dmd.common.bitfields : generateBitFields;
mixin(generateBitFields!(BitFields, ubyte));
mixin(generateBitFields!(BitFields, ushort));
extern (D) this(const ref Loc loc, Identifier id, bool inObject)
{
@ -391,9 +396,35 @@ extern (C++) class StructDeclaration : AggregateDeclaration
}
}
argTypes = target.toArgTypes(type);
}
/// Compute cached type properties for `TypeStruct`
extern(D) final void determineTypeProperties()
{
if (computedTypeProperties)
return;
foreach (vd; fields)
{
if (vd.storage_class & STC.ref_ || vd.hasPointers())
hasPointerField = true;
if (vd._init && vd._init.isVoidInitializer() && vd.type.hasPointers())
hasVoidInitPointers = true;
if (vd.storage_class & STC.system || vd.type.hasSystemFields())
hasSystemFields = true;
if (!vd._init && vd.type.hasVoidInitPointers())
hasVoidInitPointers = true;
if (vd.type.hasInvariant())
hasFieldWithInvariant = true;
}
computedTypeProperties = true;
}
/***************************************
* Determine if struct is POD (Plain Old Data).
*

View file

@ -236,25 +236,33 @@ struct FieldState
bool inFlight; /// bit field is in flight
}
// 99.9% of Dsymbols don't have attributes (at least in druntime and Phobos),
// so save memory by grouping them into a separate struct
private struct DsymbolAttributes
{
/// C++ namespace this symbol belongs to
CPPNamespaceDeclaration cppnamespace;
/// customized deprecation message
DeprecatedDeclaration depdecl_;
/// user defined attributes
UserAttributeDeclaration userAttribDecl;
}
/***********************************************************
*/
extern (C++) class Dsymbol : ASTNode
{
Identifier ident;
Dsymbol parent;
/// C++ namespace this symbol belongs to
CPPNamespaceDeclaration cppnamespace;
Symbol* csym; // symbol for code generator
const Loc loc; // where defined
Scope* _scope; // !=null means context to use for semantic()
const(char)* prettystring; // cached value of toPrettyChars()
private DsymbolAttributes* atts; /// attached attribute declarations
bool errors; // this symbol failed to pass semantic()
PASS semanticRun = PASS.initial;
ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
DeprecatedDeclaration depdecl; // customized deprecation message
UserAttributeDeclaration userAttribDecl; // user defined attributes
final extern (D) this() nothrow
{
//printf("Dsymbol::Dsymbol(%p)\n", this);
@ -285,6 +293,42 @@ extern (C++) class Dsymbol : ASTNode
return ident ? ident.toChars() : "__anonymous";
}
// Getters / setters for fields stored in `DsymbolAttributes`
final nothrow pure @safe
{
private ref DsymbolAttributes getAtts()
{
if (!atts)
atts = new DsymbolAttributes();
return *atts;
}
inout(DeprecatedDeclaration) depdecl() inout { return atts ? atts.depdecl_ : null; }
inout(CPPNamespaceDeclaration) cppnamespace() inout { return atts ? atts.cppnamespace : null; }
inout(UserAttributeDeclaration) userAttribDecl() inout { return atts ? atts.userAttribDecl : null; }
DeprecatedDeclaration depdecl(DeprecatedDeclaration dd)
{
if (!dd && !atts)
return null;
return getAtts().depdecl_ = dd;
}
CPPNamespaceDeclaration cppnamespace(CPPNamespaceDeclaration ns)
{
if (!ns && !atts)
return null;
return getAtts().cppnamespace = ns;
}
UserAttributeDeclaration userAttribDecl(UserAttributeDeclaration uad)
{
if (!uad && !atts)
return null;
return getAtts().userAttribDecl = uad;
}
}
// helper to print fully qualified (template) arguments
const(char)* toPrettyCharsHelper()
{

View file

@ -167,25 +167,31 @@ struct FieldState
bool inFlight;
};
struct DsymbolAttributes;
class Dsymbol : public ASTNode
{
public:
Identifier *ident;
Dsymbol *parent;
/// C++ namespace this symbol belongs to
CPPNamespaceDeclaration *namespace_;
Symbol *csym; // symbol for code generator
Loc loc; // where defined
Scope *_scope; // !=NULL means context to use for semantic()
const utf8_t *prettystring;
private:
DsymbolAttributes* atts;
public:
bool errors; // this symbol failed to pass semantic()
PASS semanticRun;
unsigned short localNum; // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
DeprecatedDeclaration *depdecl; // customized deprecation message
UserAttributeDeclaration *userAttribDecl; // user defined attributes
static Dsymbol *create(Identifier *);
const char *toChars() const override;
DeprecatedDeclaration* depdecl();
CPPNamespaceDeclaration* cppnamespace();
UserAttributeDeclaration* userAttribDecl();
DeprecatedDeclaration* depdecl(DeprecatedDeclaration* dd);
CPPNamespaceDeclaration* cppnamespace(CPPNamespaceDeclaration* ns);
UserAttributeDeclaration* userAttribDecl(UserAttributeDeclaration* uad);
virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments
Loc getLoc();
const char *locToChars();

View file

@ -98,6 +98,29 @@ private uint setMangleOverride(Dsymbol s, const(char)[] sym)
return 0;
}
/**
* Apply pragma printf/scanf to FuncDeclarations under `s`,
* poking through attribute declarations such as `extern(C)`
* but not through aggregates or function bodies.
*
* Params:
* s = symbol to apply
* printf = `true` for printf, `false` for scanf
*/
private void setPragmaPrintf(Dsymbol s, bool printf)
{
if (auto fd = s.isFuncDeclaration())
{
fd.printf = printf;
fd.scanf = !printf;
}
if (auto ad = s.isAttribDeclaration())
{
ad.include(null).foreachDsymbol( (s) { setPragmaPrintf(s, printf); } );
}
}
/*************************************
* Does semantic analysis on the public face of declarations.
*/
@ -855,17 +878,20 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
// Calculate type size + safety checks
if (1)
if (sc && sc.func)
{
if (dsym._init && dsym._init.isVoidInitializer() &&
(dsym.type.hasPointers() || dsym.type.hasInvariant())) // also computes type size
if (dsym._init && dsym._init.isVoidInitializer())
{
if (dsym.type.hasPointers())
if (dsym.type.hasPointers()) // also computes type size
sc.setUnsafe(false, dsym.loc,
"`void` initializers for pointers not allowed in safe functions");
else
else if (dsym.type.hasInvariant())
sc.setUnsafe(false, dsym.loc,
"`void` initializers for structs with invariants are not allowed in safe functions");
else if (dsym.type.hasSystemFields())
sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
"`void` initializers for `@system` variables not allowed in safe functions");
}
else if (!dsym._init &&
!(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
@ -1036,6 +1062,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (f.tookAddressOf)
f.tookAddressOf--;
}
else if (auto ale = ex.isArrayLiteralExp())
{
// or an array literal assigned to a `scope` variable
if (!dsym.type.nextOf().needsDestruction())
ale.onstack = true;
}
}
Expression exp = ei.exp;
@ -1200,7 +1232,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(BitFieldDeclaration dsym)
{
//printf("BitField::semantic('%s') %s\n", toPrettyChars(), id.toChars());
//printf("BitField::semantic('%s')\n", dsym.toChars());
if (dsym.semanticRun >= PASS.semanticdone)
return;
@ -1558,6 +1590,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
foreach (s; (*pd.decl)[])
{
if (pd.ident == Id.printf || pd.ident == Id.scanf)
{
s.setPragmaPrintf(pd.ident == Id.printf);
continue;
}
s.dsymbolSemantic(sc2);
if (pd.ident != Id.mangle)
continue;
@ -1574,13 +1612,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
agg = tc.sym;
else if (auto ts = e.type.isTypeStruct())
agg = ts.sym;
ad.mangleOverride = new MangleOverride;
ad.pMangleOverride = new MangleOverride;
void setString(ref Expression e)
{
if (auto se = verifyMangleString(e))
{
const name = (cast(const(char)[])se.peekData()).xarraydup;
ad.mangleOverride.id = Identifier.idPool(name);
ad.pMangleOverride.id = Identifier.idPool(name);
e = se;
}
else
@ -1588,13 +1626,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
if (agg)
{
ad.mangleOverride.agg = agg;
ad.pMangleOverride.agg = agg;
if (pd.args.dim == 2)
{
setString((*pd.args)[1]);
}
else
ad.mangleOverride.id = agg.ident;
ad.pMangleOverride.id = agg.ident;
}
else
setString((*pd.args)[0]);
@ -1649,29 +1687,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (!pd.args)
return noDeclarations();
for (size_t i = 0; i < pd.args.dim; i++)
{
Expression e = (*pd.args)[i];
sc = sc.startCTFE();
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
e = ctfeInterpretForPragmaMsg(e);
if (e.op == EXP.error)
{
errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars());
return;
}
StringExp se = e.toStringExp();
if (se)
{
se = se.toUTF8(sc);
fprintf(stderr, "%.*s", cast(int)se.len, se.peekString().ptr);
}
else
fprintf(stderr, "%s", e.toChars());
}
fprintf(stderr, "\n");
if (!pragmaMsgSemantic(pd.loc, sc, pd.args))
return;
return noDeclarations();
}
@ -1707,33 +1724,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
else if (pd.ident == Id.startaddress)
{
if (!pd.args || pd.args.dim != 1)
pd.error("function name expected for start address");
else
{
/* https://issues.dlang.org/show_bug.cgi?id=11980
* resolveProperties and ctfeInterpret call are not necessary.
*/
Expression e = (*pd.args)[0];
sc = sc.startCTFE();
e = e.expressionSemantic(sc);
sc = sc.endCTFE();
(*pd.args)[0] = e;
Dsymbol sa = getDsymbol(e);
if (!sa || !sa.isFuncDeclaration())
pd.error("function name expected for start address, not `%s`", e.toChars());
}
pragmaStartAddressSemantic(pd.loc, sc, pd.args);
return noDeclarations();
}
else if (pd.ident == Id.Pinline)
{
if (pd.args && pd.args.dim > 1)
{
pd.error("one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) pd.args.dim);
pd.args.setDim(1);
(*pd.args)[0] = ErrorExp.get();
}
// this pragma now gets evaluated on demand in function semantic
return declarations();
@ -1774,7 +1769,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
else if (auto f = s.isFuncDeclaration())
{
f.flags |= isCtor ? FUNCFLAG.CRTCtor : FUNCFLAG.CRTDtor;
if (isCtor)
f.isCrtCtor = true;
else
f.isCrtDtor = true;
return 1;
}
else
@ -3048,7 +3047,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
//printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal());
if (sc.flags & SCOPE.compile)
funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function
funcdecl.isCompileTimeOnly = true; // don't emit code for this function
funcdecl._linkage = sc.linkage;
if (auto fld = funcdecl.isFuncLiteralDeclaration())
@ -3069,7 +3068,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// evaluate pragma(inline)
if (auto pragmadecl = sc.inlining)
funcdecl.inlining = pragmadecl.evalPragmaInline(sc);
funcdecl.inlining = evalPragmaInline(pragmadecl.loc, sc, pragmadecl.args);
funcdecl.visibility = sc.visibility;
funcdecl.userAttribDecl = sc.userAttribDecl;
@ -3269,9 +3268,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
// check pragma(crt_constructor) signature
if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor))
if (funcdecl.isCrtCtor || funcdecl.isCrtDtor)
{
const idStr = (funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor" : "crt_destructor";
const idStr = funcdecl.isCrtCtor ? "crt_constructor" : "crt_destructor";
if (f.nextOf().ty != Tvoid)
funcdecl.error("must return `void` for `pragma(%s)`", idStr.ptr);
if (funcdecl._linkage != LINK.c && f.parameterList.length != 0)
@ -3351,7 +3350,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
if (const pors = sc.flags & (SCOPE.printf | SCOPE.scanf))
if (funcdecl.printf || funcdecl.scanf)
{
/* printf/scanf-like functions must be of the form:
* extern (C/C++) T printf([parameters...], const(char)* format, ...);
@ -3387,11 +3386,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
)
)
{
funcdecl.flags |= (pors == SCOPE.printf) ? FUNCFLAG.printf : FUNCFLAG.scanf;
// the signature is valid for printf/scanf, no error
}
else
{
const p = (pors == SCOPE.printf ? Id.printf : Id.scanf).toChars();
const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars();
if (f.parameterList.varargs == VarArg.variadic)
{
funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`"
@ -3538,7 +3537,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
else
{
//printf("\tintroducing function %s\n", funcdecl.toChars());
funcdecl.flags |= FUNCFLAG.introducing;
funcdecl.isIntroducing = true;
if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads)
{
/* Overloaded functions with same name are grouped and in reverse order.
@ -4555,13 +4554,16 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (sd.semanticRun == PASS.initial)
sd.type = sd.type.addSTC(sc.stc | sd.storage_class);
sd.type = sd.type.typeSemantic(sd.loc, sc);
if (auto ts = sd.type.isTypeStruct())
auto ts = sd.type.isTypeStruct();
if (ts)
{
if (ts.sym != sd)
{
auto ti = ts.sym.isInstantiated();
if (ti && isError(ti))
ts.sym = sd;
}
}
// Ungag errors when not speculative
Ungag ungag = sd.ungagSpeculative();
@ -4699,16 +4701,26 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
if (sd.type.ty == Tstruct && (cast(TypeStruct)sd.type).sym != sd)
if (ts && ts.sym != sd)
{
// https://issues.dlang.org/show_bug.cgi?id=19024
StructDeclaration sym = (cast(TypeStruct)sd.type).sym;
version (none)
StructDeclaration sym = ts.sym;
if (sd.isCsymbol() && sym.isCsymbol())
{
printf("this = %p %s\n", sd, sd.toChars());
printf("type = %d sym = %p, %s\n", sd.type.ty, sym, sym.toPrettyChars());
/* This is two structs imported from different C files.
* Just ignore sd, the second one. The first one will always
* be found when going through the type.
*/
}
else
{
version (none)
{
printf("this = %p %s\n", sd, sd.toChars());
printf("type = %d sym = %p, %s\n", sd.type.ty, sym, sym.toPrettyChars());
}
// https://issues.dlang.org/show_bug.cgi?id=19024
sd.error("already exists at %s. Perhaps in another function with the same name?", sym.loc.toChars());
}
sd.error("already exists at %s. Perhaps in another function with the same name?", sym.loc.toChars());
}
if (global.errors != errors)
@ -5291,7 +5303,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf);
ctor.storage_class |= STC.inference;
ctor.flags |= FUNCFLAG.generated;
ctor.isGenerated = true;
ctor.fbody = new CompoundStatement(Loc.initial, new Statements());
cldec.members.push(ctor);
@ -7099,3 +7111,47 @@ private CallExp doAtomicOp (string op, Identifier var, Expression arg)
return CallExp.create(loc, dti, args);
}
/***************************************
* Interpret a `pragma(inline, x)`
*
* Params:
* loc = location for error messages
* sc = scope for evaluation of argument
* args = pragma arguments
* Returns: corresponding `PINLINE` state
*/
PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args)
{
if (!args || args.dim == 0)
return PINLINE.default_;
if (args && args.dim > 1)
{
.error(loc, "one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.dim);
args.setDim(1);
(*args)[0] = ErrorExp.get();
}
Expression e = (*args)[0];
if (!e.type)
{
sc = sc.startCTFE();
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
e = e.ctfeInterpret();
e = e.toBoolean(sc);
if (e.isErrorExp())
.error(loc, "pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars());
(*args)[0] = e;
}
const opt = e.toBool();
if (opt.isEmpty())
return PINLINE.default_;
else if (opt.get())
return PINLINE.always;
else
return PINLINE.never;
}

View file

@ -1173,7 +1173,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
fd.parent = ti;
fd.flags |= FUNCFLAG.inferRetType;
fd.inferRetType = true;
// Shouldn't run semantic on default arguments and return type.
foreach (ref param; *tf.parameterList.parameters)
@ -3901,7 +3901,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// https://issues.dlang.org/show_bug.cgi?id=2579
// Apply function parameter storage classes to parameter types
fparam.type = fparam.type.addStorageClass(fparam.storageClass);
fparam.storageClass &= ~(STC.TYPECTOR | STC.in_);
fparam.storageClass &= ~STC.TYPECTOR;
// https://issues.dlang.org/show_bug.cgi?id=15243
// Resolve parameter type if it's not related with template parameters

View file

@ -25,7 +25,7 @@ nothrow:
* code point corresponding to the named entity
* ~0 for not recognized as a named entity
*/
public uint HtmlNamedEntity(scope const char[] name) pure @nogc @safe
public uint[2] HtmlNamedEntity(scope const char[] name) pure @nogc @safe
{
const firstC = tolower(name[0]);
if (firstC >= 'a' && firstC <= 'z')
@ -34,10 +34,10 @@ public uint HtmlNamedEntity(scope const char[] name) pure @nogc @safe
foreach (entity; namesTable[firstC - 'a'])
{
if (entity.name == name)
return entity.value;
return [entity.value, entity.value2];
}
}
return ~0;
return [0, 0];
}
private:
@ -52,6 +52,7 @@ struct NameId
{
string name;
uint value;
uint value2;
}
// @todo@ order namesTable and names? by frequency
@ -72,7 +73,7 @@ immutable NameId[] namesA =
{"abreve", 0x00103}, // LATIN SMALL LETTER A WITH BREVE
{"ac", 0x0223E}, // INVERTED LAZY S
{"acd", 0x0223F}, // SINE WAVE
// {"acE", 0x0223E;0x00333}, // INVERTED LAZY S with double underline
{"acE", 0x0223E, 0x00333}, // INVERTED LAZY S with double underline
{"Acirc", 0x000C2}, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
{"acirc", 0x000E2}, // LATIN SMALL LETTER A WITH CIRCUMFLEX
{"acute", 0x000B4}, // ACUTE ACCENT
@ -157,42 +158,30 @@ immutable NameId[] namesB =
{"backsim", 0x0223D}, // REVERSED TILDE
{"backsimeq", 0x022CD}, // REVERSED TILDE EQUALS
{"Backslash", 0x02216}, // SET MINUS
// "b.alpha", 0x1D6C2}, // MATHEMATICAL BOLD SMALL ALPHA
{"Barv", 0x02AE7}, // SHORT DOWN TACK WITH OVERBAR
{"barvee", 0x022BD}, // NOR
{"barwed", 0x02305}, // PROJECTIVE
{"Barwed", 0x02306}, // PERSPECTIVE
{"barwedge", 0x02305}, // PROJECTIVE
// "b.beta", 0x1D6C3}, // MATHEMATICAL BOLD SMALL BETA
{"bbrk", 0x023B5}, // BOTTOM SQUARE BRACKET
{"bbrktbrk", 0x023B6}, // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET
// "b.chi", 0x1D6D8}, // MATHEMATICAL BOLD SMALL CHI
{"bcong", 0x0224C}, // ALL EQUAL TO
{"Bcy", 0x00411}, // CYRILLIC CAPITAL LETTER BE
{"bcy", 0x00431}, // CYRILLIC SMALL LETTER BE
// "b.Delta", 0x1D6AB}, // MATHEMATICAL BOLD CAPITAL DELTA
// "b.delta", 0x1D6C5}, // MATHEMATICAL BOLD SMALL DELTA
{"bdquo", 0x0201E}, // DOUBLE LOW-9 QUOTATION MARK
{"becaus", 0x02235}, // BECAUSE
{"because", 0x02235}, // BECAUSE
{"Because", 0x02235}, // BECAUSE
{"bemptyv", 0x029B0}, // REVERSED EMPTY SET
{"bepsi", 0x003F6}, // GREEK REVERSED LUNATE EPSILON SYMBOL
// "b.epsi", 0x1D6C6}, // MATHEMATICAL BOLD SMALL EPSILON
// "b.epsiv", 0x1D6DC}, // MATHEMATICAL BOLD EPSILON SYMBOL
{"bernou", 0x0212C}, // SCRIPT CAPITAL B
{"Bernoullis", 0x0212C}, // SCRIPT CAPITAL B
{"Beta", 0x00392}, // GREEK CAPITAL LETTER BETA
{"beta", 0x003B2}, // GREEK SMALL LETTER BETA
// "b.eta", 0x1D6C8}, // MATHEMATICAL BOLD SMALL ETA
{"beth", 0x02136}, // BET SYMBOL
{"between", 0x0226C}, // BETWEEN
{"Bfr", 0x1D505}, // MATHEMATICAL FRAKTUR CAPITAL B
{"bfr", 0x1D51F}, // MATHEMATICAL FRAKTUR SMALL B
// "b.Gamma", 0x1D6AA}, // MATHEMATICAL BOLD CAPITAL GAMMA
// "b.gamma", 0x1D6C4}, // MATHEMATICAL BOLD SMALL GAMMA
// "b.Gammad", 0x1D7CA}, // MATHEMATICAL BOLD CAPITAL DIGAMMA
// "b.gammad", 0x1D7CB}, // MATHEMATICAL BOLD SMALL DIGAMMA
{"Bgr", 0x00392}, // GREEK CAPITAL LETTER BETA
{"bgr", 0x003B2}, // GREEK SMALL LETTER BETA
{"bigcap", 0x022C2}, // N-ARY INTERSECTION
@ -208,9 +197,6 @@ immutable NameId[] namesB =
{"biguplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS
{"bigvee", 0x022C1}, // N-ARY LOGICAL OR
{"bigwedge", 0x022C0}, // N-ARY LOGICAL AND
// "b.iota", 0x1D6CA}, // MATHEMATICAL BOLD SMALL IOTA
// "b.kappa", 0x1D6CB}, // MATHEMATICAL BOLD SMALL KAPPA
// "b.kappav", 0x1D6DE}, // MATHEMATICAL BOLD KAPPA SYMBOL
{"bkarow", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW
{"blacklozenge", 0x029EB}, // BLACK LOZENGE
{"blacksquare", 0x025AA}, // BLACK SMALL SQUARE
@ -218,21 +204,15 @@ immutable NameId[] namesB =
{"blacktriangledown", 0x025BE}, // BLACK DOWN-POINTING SMALL TRIANGLE
{"blacktriangleleft", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE
{"blacktriangleright", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE
// "b.Lambda", 0x1D6B2}, // MATHEMATICAL BOLD CAPITAL LAMDA
// "b.lambda", 0x1D6CC}, // MATHEMATICAL BOLD SMALL LAMDA
{"blank", 0x02423}, // OPEN BOX
{"blk12", 0x02592}, // MEDIUM SHADE
{"blk14", 0x02591}, // LIGHT SHADE
{"blk34", 0x02593}, // DARK SHADE
{"block", 0x02588}, // FULL BLOCK
// "b.mu", 0x1D6CD}, // MATHEMATICAL BOLD SMALL MU
// "bne", 0x0003D;0x020E5}, // EQUALS SIGN with reverse slash
// "bnequiv", 0x02261;0x020E5}, // IDENTICAL TO with reverse slash
{"bne", 0x0003D, 0x020E5}, // EQUALS SIGN with reverse slash
{"bnequiv", 0x02261, 0x020E5}, // IDENTICAL TO with reverse slash
{"bnot", 0x02310}, // REVERSED NOT SIGN
{"bNot", 0x02AED}, // REVERSED DOUBLE STROKE NOT SIGN
// "b.nu", 0x1D6CE}, // MATHEMATICAL BOLD SMALL NU
// "b.Omega", 0x1D6C0}, // MATHEMATICAL BOLD CAPITAL OMEGA
// "b.omega", 0x1D6DA}, // MATHEMATICAL BOLD SMALL OMEGA
{"Bopf", 0x1D539}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL B
{"bopf", 0x1D553}, // MATHEMATICAL DOUBLE-STRUCK SMALL B
{"bot", 0x022A5}, // UP TACK
@ -282,35 +262,18 @@ immutable NameId[] namesB =
{"boxvR", 0x0255E}, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
{"boxVr", 0x0255F}, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
{"boxVR", 0x02560}, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
// "b.Phi", 0x1D6BD}, // MATHEMATICAL BOLD CAPITAL PHI
// "b.phi", 0x1D6D7}, // MATHEMATICAL BOLD SMALL PHI
// "b.phiv", 0x1D6DF}, // MATHEMATICAL BOLD PHI SYMBOL
// "b.Pi", 0x1D6B7}, // MATHEMATICAL BOLD CAPITAL PI
// "b.pi", 0x1D6D1}, // MATHEMATICAL BOLD SMALL PI
// "b.piv", 0x1D6E1}, // MATHEMATICAL BOLD PI SYMBOL
{"bprime", 0x02035}, // REVERSED PRIME
// "b.Psi", 0x1D6BF}, // MATHEMATICAL BOLD CAPITAL PSI
// "b.psi", 0x1D6D9}, // MATHEMATICAL BOLD SMALL PSI
{"breve", 0x002D8}, // BREVE
{"Breve", 0x002D8}, // BREVE
// "b.rho", 0x1D6D2}, // MATHEMATICAL BOLD SMALL RHO
// "b.rhov", 0x1D6E0}, // MATHEMATICAL BOLD RHO SYMBOL
{"brvbar", 0x000A6}, // BROKEN BAR
{"Bscr", 0x0212C}, // SCRIPT CAPITAL B
{"bscr", 0x1D4B7}, // MATHEMATICAL SCRIPT SMALL B
{"bsemi", 0x0204F}, // REVERSED SEMICOLON
// "b.Sigma", 0x1D6BA}, // MATHEMATICAL BOLD CAPITAL SIGMA
// "b.sigma", 0x1D6D4}, // MATHEMATICAL BOLD SMALL SIGMA
// "b.sigmav", 0x1D6D3}, // MATHEMATICAL BOLD SMALL FINAL SIGMA
{"bsim", 0x0223D}, // REVERSED TILDE
{"bsime", 0x022CD}, // REVERSED TILDE EQUALS
{"bsol", 0x0005C}, // REVERSE SOLIDUS
{"bsolb", 0x029C5}, // SQUARED FALLING DIAGONAL SLASH
{"bsolhsub", 0x027C8}, // REVERSE SOLIDUS PRECEDING SUBSET
// "b.tau", 0x1D6D5}, // MATHEMATICAL BOLD SMALL TAU
// "b.Theta", 0x1D6AF}, // MATHEMATICAL BOLD CAPITAL THETA
// "b.thetas", 0x1D6C9}, // MATHEMATICAL BOLD SMALL THETA
// "b.thetav", 0x1D6DD}, // MATHEMATICAL BOLD THETA SYMBOL
{"bull", 0x02022}, // BULLET
{"bullet", 0x02022}, // BULLET
{"bump", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
@ -318,11 +281,6 @@ immutable NameId[] namesB =
{"bumpE", 0x02AAE}, // EQUALS SIGN WITH BUMPY ABOVE
{"Bumpeq", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
{"bumpeq", 0x0224F}, // DIFFERENCE BETWEEN
// "b.Upsi", 0x1D6BC}, // MATHEMATICAL BOLD CAPITAL UPSILON
// "b.upsi", 0x1D6D6}, // MATHEMATICAL BOLD SMALL UPSILON
// "b.Xi", 0x1D6B5}, // MATHEMATICAL BOLD CAPITAL XI
// "b.xi", 0x1D6CF}, // MATHEMATICAL BOLD SMALL XI
// "b.zeta", 0x1D6C7}, // MATHEMATICAL BOLD SMALL ZETA
];
immutable NameId[] namesC =
@ -337,7 +295,7 @@ immutable NameId[] namesC =
{"capcup", 0x02A47}, // INTERSECTION ABOVE UNION
{"capdot", 0x02A40}, // INTERSECTION WITH DOT
{"CapitalDifferentialD", 0x02145}, // DOUBLE-STRUCK ITALIC CAPITAL D
// "caps", 0x02229;0x0FE00}, // INTERSECTION with serifs
{"caps", 0x02229, 0x0FE00}, // INTERSECTION with serifs
{"caret", 0x02041}, // CARET INSERTION POINT
{"caron", 0x002C7}, // CARON
{"Cayleys", 0x0212D}, // BLACK-LETTER CAPITAL C
@ -440,7 +398,7 @@ immutable NameId[] namesC =
{"cupcup", 0x02A4A}, // UNION BESIDE AND JOINED WITH UNION
{"cupdot", 0x0228D}, // MULTISET MULTIPLICATION
{"cupor", 0x02A45}, // UNION WITH LOGICAL OR
// "cups", 0x0222A;0x0FE00}, // UNION with serifs
{"cups", 0x0222A, 0x0FE00}, // UNION with serifs
{"curarr", 0x021B7}, // CLOCKWISE TOP SEMICIRCLE ARROW
{"curarrm", 0x0293C}, // TOP ARC CLOCKWISE ARROW WITH MINUS
{"curlyeqprec", 0x022DE}, // EQUAL TO OR PRECEDES
@ -694,7 +652,7 @@ immutable NameId[] namesF =
{"filig", 0x0FB01}, // LATIN SMALL LIGATURE FI
{"FilledSmallSquare", 0x025FC}, // BLACK MEDIUM SQUARE
{"FilledVerySmallSquare", 0x025AA}, // BLACK SMALL SQUARE
// "fjlig", 0x00066;0x0006A}, // fj ligature
{"fjlig", 0x00066, 0x0006A}, // fj ligature
{"flat", 0x0266D}, // MUSIC FLAT SIGN
{"fllig", 0x0FB02}, // LATIN SMALL LIGATURE FL
{"fltns", 0x025B1}, // WHITE PARALLELOGRAM
@ -757,7 +715,7 @@ immutable NameId[] namesG =
{"gesdot", 0x02A80}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
{"gesdoto", 0x02A82}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
{"gesdotol", 0x02A84}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT
// "gesl", 0x022DB;0x0FE00}, // GREATER-THAN slanted EQUAL TO OR LESS-THAN
{"gesl", 0x022DB, 0x0FE00}, // GREATER-THAN slanted EQUAL TO OR LESS-THAN
{"gesles", 0x02A94}, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL
{"Gfr", 0x1D50A}, // MATHEMATICAL FRAKTUR CAPITAL G
{"gfr", 0x1D524}, // MATHEMATICAL FRAKTUR SMALL G
@ -810,8 +768,8 @@ immutable NameId[] namesG =
{"gtreqqless", 0x02A8C}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
{"gtrless", 0x02277}, // GREATER-THAN OR LESS-THAN
{"gtrsim", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
// "gvertneqq", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
// "gvnE", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
{"gvertneqq", 0x02269, 0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
{"gvnE", 0x02269, 0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
];
immutable NameId[] namesH =
@ -1020,7 +978,7 @@ immutable NameId[] namesL =
{"latail", 0x02919}, // LEFTWARDS ARROW-TAIL
{"lAtail", 0x0291B}, // LEFTWARDS DOUBLE ARROW-TAIL
{"late", 0x02AAD}, // LARGER THAN OR EQUAL TO
// "lates", 0x02AAD;0x0FE00}, // LARGER THAN OR slanted EQUAL
{"lates", 0x02AAD, 0x0FE00}, // LARGER THAN OR slanted EQUAL
{"lbarr", 0x0290C}, // LEFTWARDS DOUBLE DASH ARROW
{"lBarr", 0x0290E}, // LEFTWARDS TRIPLE DASH ARROW
{"lbbrk", 0x02772}, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
@ -1091,7 +1049,7 @@ immutable NameId[] namesL =
{"lesdot", 0x02A7F}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
{"lesdoto", 0x02A81}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
{"lesdotor", 0x02A83}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT
// "lesg", 0x022DA;0x0FE00}, // LESS-THAN slanted EQUAL TO OR GREATER-THAN
{"lesg", 0x022DA, 0x0FE00}, // LESS-THAN slanted EQUAL TO OR GREATER-THAN
{"lesges", 0x02A93}, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL
{"lessapprox", 0x02A85}, // LESS-THAN OR APPROXIMATE
{"lessdot", 0x022D6}, // LESS-THAN WITH DOT
@ -1202,8 +1160,8 @@ immutable NameId[] namesL =
{"ltrPar", 0x02996}, // DOUBLE RIGHT ARC LESS-THAN BRACKET
{"lurdshar", 0x0294A}, // LEFT BARB UP RIGHT BARB DOWN HARPOON
{"luruhar", 0x02966}, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP
// "lvertneqq", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
// "lvnE", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
{"lvertneqq", 0x02268, 0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
{"lvnE", 0x02268, 0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
];
immutable NameId[] namesM =
@ -1263,25 +1221,25 @@ immutable NameId[] namesN =
{"nabla", 0x02207}, // NABLA
{"Nacute", 0x00143}, // LATIN CAPITAL LETTER N WITH ACUTE
{"nacute", 0x00144}, // LATIN SMALL LETTER N WITH ACUTE
// "nang", 0x02220;0x020D2}, // ANGLE with vertical line
{"nang", 0x02220, 0x020D2}, // ANGLE with vertical line
{"nap", 0x02249}, // NOT ALMOST EQUAL TO
// "napE", 0x02A70;0x00338}, // APPROXIMATELY EQUAL OR EQUAL TO with slash
// "napid", 0x0224B;0x00338}, // TRIPLE TILDE with slash
{"napE", 0x02A70, 0x00338}, // APPROXIMATELY EQUAL OR EQUAL TO with slash
{"napid", 0x0224B, 0x00338}, // TRIPLE TILDE with slash
{"napos", 0x00149}, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
{"napprox", 0x02249}, // NOT ALMOST EQUAL TO
{"natur", 0x0266E}, // MUSIC NATURAL SIGN
{"natural", 0x0266E}, // MUSIC NATURAL SIGN
{"naturals", 0x02115}, // DOUBLE-STRUCK CAPITAL N
{"nbsp", 0x000A0}, // NO-BREAK SPACE
// "nbump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
// "nbumpe", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash
{"nbump", 0x0224E, 0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
{"nbumpe", 0x0224F, 0x00338}, // DIFFERENCE BETWEEN with slash
{"ncap", 0x02A43}, // INTERSECTION WITH OVERBAR
{"Ncaron", 0x00147}, // LATIN CAPITAL LETTER N WITH CARON
{"ncaron", 0x00148}, // LATIN SMALL LETTER N WITH CARON
{"Ncedil", 0x00145}, // LATIN CAPITAL LETTER N WITH CEDILLA
{"ncedil", 0x00146}, // LATIN SMALL LETTER N WITH CEDILLA
{"ncong", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
// "ncongdot", 0x02A6D;0x00338}, // CONGRUENT WITH DOT ABOVE with slash
{"ncongdot", 0x02A6D, 0x00338}, // CONGRUENT WITH DOT ABOVE with slash
{"ncup", 0x02A42}, // UNION WITH OVERBAR
{"Ncy", 0x0041D}, // CYRILLIC CAPITAL LETTER EN
{"ncy", 0x0043D}, // CYRILLIC SMALL LETTER EN
@ -1291,14 +1249,14 @@ immutable NameId[] namesN =
{"nearr", 0x02197}, // NORTH EAST ARROW
{"neArr", 0x021D7}, // NORTH EAST DOUBLE ARROW
{"nearrow", 0x02197}, // NORTH EAST ARROW
// "nedot", 0x02250;0x00338}, // APPROACHES THE LIMIT with slash
{"nedot", 0x02250, 0x00338}, // APPROACHES THE LIMIT with slash
{"NegativeMediumSpace", 0x0200B}, // ZERO WIDTH SPACE
{"NegativeThickSpace", 0x0200B}, // ZERO WIDTH SPACE
{"NegativeThinSpace", 0x0200B}, // ZERO WIDTH SPACE
{"NegativeVeryThinSpace", 0x0200B}, // ZERO WIDTH SPACE
{"nequiv", 0x02262}, // NOT IDENTICAL TO
{"nesear", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW
// "nesim", 0x02242;0x00338}, // MINUS TILDE with slash
{"nesim", 0x02242, 0x00338}, // MINUS TILDE with slash
{"NestedGreaterGreater", 0x0226B}, // MUCH GREATER-THAN
{"NestedLessLess", 0x0226A}, // MUCH LESS-THAN
{"NewLine", 0x0000A}, // LINE FEED (LF)
@ -1306,20 +1264,20 @@ immutable NameId[] namesN =
{"nexists", 0x02204}, // THERE DOES NOT EXIST
{"Nfr", 0x1D511}, // MATHEMATICAL FRAKTUR CAPITAL N
{"nfr", 0x1D52B}, // MATHEMATICAL FRAKTUR SMALL N
// "ngE", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
{"ngE", 0x02267, 0x00338}, // GREATER-THAN OVER EQUAL TO with slash
{"nge", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
{"ngeq", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
// "ngeqq", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
// "ngeqslant", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
// "nges", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
// "nGg", 0x022D9;0x00338}, // VERY MUCH GREATER-THAN with slash
{"ngeqq", 0x02267, 0x00338}, // GREATER-THAN OVER EQUAL TO with slash
{"ngeqslant", 0x02A7E, 0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
{"nges", 0x02A7E, 0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
{"nGg", 0x022D9, 0x00338}, // VERY MUCH GREATER-THAN with slash
{"Ngr", 0x0039D}, // GREEK CAPITAL LETTER NU
{"ngr", 0x003BD}, // GREEK SMALL LETTER NU
{"ngsim", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
// "nGt", 0x0226B;0x020D2}, // MUCH GREATER THAN with vertical line
{"nGt", 0x0226B, 0x020D2}, // MUCH GREATER THAN with vertical line
{"ngt", 0x0226F}, // NOT GREATER-THAN
{"ngtr", 0x0226F}, // NOT GREATER-THAN
// "nGtv", 0x0226B;0x00338}, // MUCH GREATER THAN with slash
{"nGtv", 0x0226B, 0x00338}, // MUCH GREATER THAN with slash
{"nharr", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE
{"nhArr", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
{"nhpar", 0x02AF2}, // PARALLEL WITH HORIZONTAL STROKE
@ -1332,24 +1290,24 @@ immutable NameId[] namesN =
{"nlarr", 0x0219A}, // LEFTWARDS ARROW WITH STROKE
{"nlArr", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE
{"nldr", 0x02025}, // TWO DOT LEADER
// "nlE", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash
{"nlE", 0x02266, 0x00338}, // LESS-THAN OVER EQUAL TO with slash
{"nle", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
{"nleftarrow", 0x0219A}, // LEFTWARDS ARROW WITH STROKE
{"nLeftarrow", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE
{"nleftrightarrow", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE
{"nLeftrightarrow", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
{"nleq", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
// "nleqq", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash
// "nleqslant", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
// "nles", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
{"nleqq", 0x02266, 0x00338}, // LESS-THAN OVER EQUAL TO with slash
{"nleqslant", 0x02A7D, 0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
{"nles", 0x02A7D, 0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
{"nless", 0x0226E}, // NOT LESS-THAN
// "nLl", 0x022D8;0x00338}, // VERY MUCH LESS-THAN with slash
{"nLl", 0x022D8, 0x00338}, // VERY MUCH LESS-THAN with slash
{"nlsim", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO
// "nLt", 0x0226A;0x020D2}, // MUCH LESS THAN with vertical line
{"nLt", 0x0226A, 0x020D2}, // MUCH LESS THAN with vertical line
{"nlt", 0x0226E}, // NOT LESS-THAN
{"nltri", 0x022EA}, // NOT NORMAL SUBGROUP OF
{"nltrie", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
// "nLtv", 0x0226A;0x00338}, // MUCH LESS THAN with slash
{"nLtv", 0x0226A, 0x00338}, // MUCH LESS THAN with slash
{"nmid", 0x02224}, // DOES NOT DIVIDE
{"NoBreak", 0x02060}, // WORD JOINER
{"NonBreakingSpace", 0x000A0}, // NO-BREAK SPACE
@ -1362,56 +1320,56 @@ immutable NameId[] namesN =
{"NotDoubleVerticalBar", 0x02226}, // NOT PARALLEL TO
{"NotElement", 0x02209}, // NOT AN ELEMENT OF
{"NotEqual", 0x02260}, // NOT EQUAL TO
// "NotEqualTilde", 0x02242;0x00338}, // MINUS TILDE with slash
{"NotEqualTilde", 0x02242, 0x00338}, // MINUS TILDE with slash
{"NotExists", 0x02204}, // THERE DOES NOT EXIST
{"NotGreater", 0x0226F}, // NOT GREATER-THAN
{"NotGreaterEqual", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
// "NotGreaterFullEqual", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
// "NotGreaterGreater", 0x0226B;0x00338}, // MUCH GREATER THAN with slash
{"NotGreaterFullEqual", 0x02267, 0x00338}, // GREATER-THAN OVER EQUAL TO with slash
{"NotGreaterGreater", 0x0226B, 0x00338}, // MUCH GREATER THAN with slash
{"NotGreaterLess", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN
// "NotGreaterSlantEqual", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
{"NotGreaterSlantEqual", 0x02A7E, 0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
{"NotGreaterTilde", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
// "NotHumpDownHump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
// "NotHumpEqual", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash
{"NotHumpDownHump", 0x0224E, 0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
{"NotHumpEqual", 0x0224F, 0x00338}, // DIFFERENCE BETWEEN with slash
{"notin", 0x02209}, // NOT AN ELEMENT OF
// "notindot", 0x022F5;0x00338}, // ELEMENT OF WITH DOT ABOVE with slash
// "notinE", 0x022F9;0x00338}, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash
{"notindot", 0x022F5, 0x00338}, // ELEMENT OF WITH DOT ABOVE with slash
{"notinE", 0x022F9, 0x00338}, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash
{"notinva", 0x02209}, // NOT AN ELEMENT OF
{"notinvb", 0x022F7}, // SMALL ELEMENT OF WITH OVERBAR
{"notinvc", 0x022F6}, // ELEMENT OF WITH OVERBAR
{"NotLeftTriangle", 0x022EA}, // NOT NORMAL SUBGROUP OF
// "NotLeftTriangleBar", 0x029CF;0x00338}, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash
{"NotLeftTriangleBar", 0x029CF, 0x00338}, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash
{"NotLeftTriangleEqual", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
{"NotLess", 0x0226E}, // NOT LESS-THAN
{"NotLessEqual", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
{"NotLessGreater", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN
// "NotLessLess", 0x0226A;0x00338}, // MUCH LESS THAN with slash
// "NotLessSlantEqual", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
{"NotLessLess", 0x0226A, 0x00338}, // MUCH LESS THAN with slash
{"NotLessSlantEqual", 0x02A7D, 0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
{"NotLessTilde", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO
// "NotNestedGreaterGreater", 0x02AA2;0x00338}, // DOUBLE NESTED GREATER-THAN with slash
// "NotNestedLessLess", 0x02AA1;0x00338}, // DOUBLE NESTED LESS-THAN with slash
{"NotNestedGreaterGreater", 0x02AA2, 0x00338}, // DOUBLE NESTED GREATER-THAN with slash
{"NotNestedLessLess", 0x02AA1, 0x00338}, // DOUBLE NESTED LESS-THAN with slash
{"notni", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
{"notniva", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
{"notnivb", 0x022FE}, // SMALL CONTAINS WITH OVERBAR
{"notnivc", 0x022FD}, // CONTAINS WITH OVERBAR
{"NotPrecedes", 0x02280}, // DOES NOT PRECEDE
// "NotPrecedesEqual", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
{"NotPrecedesEqual", 0x02AAF, 0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
{"NotPrecedesSlantEqual", 0x022E0}, // DOES NOT PRECEDE OR EQUAL
{"NotReverseElement", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
{"NotRightTriangle", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
// "NotRightTriangleBar", 0x029D0;0x00338}, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash
{"NotRightTriangleBar", 0x029D0, 0x00338}, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash
{"NotRightTriangleEqual", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
// "NotSquareSubset", 0x0228F;0x00338}, // SQUARE IMAGE OF with slash
{"NotSquareSubset", 0x0228F, 0x00338}, // SQUARE IMAGE OF with slash
{"NotSquareSubsetEqual", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO
// "NotSquareSuperset", 0x02290;0x00338}, // SQUARE ORIGINAL OF with slash
{"NotSquareSuperset", 0x02290, 0x00338}, // SQUARE ORIGINAL OF with slash
{"NotSquareSupersetEqual", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
// "NotSubset", 0x02282;0x020D2}, // SUBSET OF with vertical line
{"NotSubset", 0x02282, 0x020D2}, // SUBSET OF with vertical line
{"NotSubsetEqual", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
{"NotSucceeds", 0x02281}, // DOES NOT SUCCEED
// "NotSucceedsEqual", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
{"NotSucceedsEqual", 0x02AB0, 0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
{"NotSucceedsSlantEqual", 0x022E1}, // DOES NOT SUCCEED OR EQUAL
// "NotSucceedsTilde", 0x0227F;0x00338}, // SUCCEEDS OR EQUIVALENT TO with slash
// "NotSuperset", 0x02283;0x020D2}, // SUPERSET OF with vertical line
{"NotSucceedsTilde", 0x0227F, 0x00338}, // SUCCEEDS OR EQUIVALENT TO with slash
{"NotSuperset", 0x02283, 0x020D2}, // SUPERSET OF with vertical line
{"NotSupersetEqual", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
{"NotTilde", 0x02241}, // NOT TILDE
{"NotTildeEqual", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
@ -1420,25 +1378,25 @@ immutable NameId[] namesN =
{"NotVerticalBar", 0x02224}, // DOES NOT DIVIDE
{"npar", 0x02226}, // NOT PARALLEL TO
{"nparallel", 0x02226}, // NOT PARALLEL TO
// "nparsl", 0x02AFD;0x020E5}, // DOUBLE SOLIDUS OPERATOR with reverse slash
// "npart", 0x02202;0x00338}, // PARTIAL DIFFERENTIAL with slash
{"nparsl", 0x02AFD, 0x020E5}, // DOUBLE SOLIDUS OPERATOR with reverse slash
{"npart", 0x02202, 0x00338}, // PARTIAL DIFFERENTIAL with slash
{"npolint", 0x02A14}, // LINE INTEGRATION NOT INCLUDING THE POLE
{"npr", 0x02280}, // DOES NOT PRECEDE
{"nprcue", 0x022E0}, // DOES NOT PRECEDE OR EQUAL
// "npre", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
{"npre", 0x02AAF, 0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
{"nprec", 0x02280}, // DOES NOT PRECEDE
// "npreceq", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
{"npreceq", 0x02AAF, 0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
{"nrarr", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE
{"nrArr", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
// "nrarrc", 0x02933;0x00338}, // WAVE ARROW POINTING DIRECTLY RIGHT with slash
// "nrarrw", 0x0219D;0x00338}, // RIGHTWARDS WAVE ARROW with slash
{"nrarrc", 0x02933, 0x00338}, // WAVE ARROW POINTING DIRECTLY RIGHT with slash
{"nrarrw", 0x0219D, 0x00338}, // RIGHTWARDS WAVE ARROW with slash
{"nrightarrow", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE
{"nRightarrow", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
{"nrtri", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
{"nrtrie", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
{"nsc", 0x02281}, // DOES NOT SUCCEED
{"nsccue", 0x022E1}, // DOES NOT SUCCEED OR EQUAL
// "nsce", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
{"nsce", 0x02AB0, 0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
{"Nscr", 0x1D4A9}, // MATHEMATICAL SCRIPT CAPITAL N
{"nscr", 0x1D4C3}, // MATHEMATICAL SCRIPT SMALL N
{"nshortmid", 0x02224}, // DOES NOT DIVIDE
@ -1452,18 +1410,18 @@ immutable NameId[] namesN =
{"nsqsupe", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
{"nsub", 0x02284}, // NOT A SUBSET OF
{"nsube", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
// "nsubE", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
// "nsubset", 0x02282;0x020D2}, // SUBSET OF with vertical line
{"nsubE", 0x02AC5, 0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
{"nsubset", 0x02282, 0x020D2}, // SUBSET OF with vertical line
{"nsubseteq", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
// "nsubseteqq", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
{"nsubseteqq", 0x02AC5, 0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
{"nsucc", 0x02281}, // DOES NOT SUCCEED
// "nsucceq", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
{"nsucceq", 0x02AB0, 0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
{"nsup", 0x02285}, // NOT A SUPERSET OF
{"nsupe", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
// "nsupE", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
// "nsupset", 0x02283;0x020D2}, // SUPERSET OF with vertical line
{"nsupE", 0x02AC6, 0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
{"nsupset", 0x02283, 0x020D2}, // SUPERSET OF with vertical line
{"nsupseteq", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
// "nsupseteqq", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
{"nsupseteqq", 0x02AC6, 0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
{"ntgl", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN
{"Ntilde", 0x000D1}, // LATIN CAPITAL LETTER N WITH TILDE
{"ntilde", 0x000F1}, // LATIN SMALL LETTER N WITH TILDE
@ -1477,22 +1435,22 @@ immutable NameId[] namesN =
{"num", 0x00023}, // NUMBER SIGN
{"numero", 0x02116}, // NUMERO SIGN
{"numsp", 0x02007}, // FIGURE SPACE
// "nvap", 0x0224D;0x020D2}, // EQUIVALENT TO with vertical line
{"nvap", 0x0224D, 0x020D2}, // EQUIVALENT TO with vertical line
{"nvdash", 0x022AC}, // DOES NOT PROVE
{"nvDash", 0x022AD}, // NOT TRUE
{"nVdash", 0x022AE}, // DOES NOT FORCE
{"nVDash", 0x022AF}, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
// "nvge", 0x02265;0x020D2}, // GREATER-THAN OR EQUAL TO with vertical line
// "nvgt", 0x0003E;0x020D2}, // GREATER-THAN SIGN with vertical line
{"nvge", 0x02265, 0x020D2}, // GREATER-THAN OR EQUAL TO with vertical line
{"nvgt", 0x0003E, 0x020D2}, // GREATER-THAN SIGN with vertical line
{"nvHarr", 0x02904}, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE
{"nvinfin", 0x029DE}, // INFINITY NEGATED WITH VERTICAL BAR
{"nvlArr", 0x02902}, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE
// "nvle", 0x02264;0x020D2}, // LESS-THAN OR EQUAL TO with vertical line
// "nvlt", 0x0003C;0x020D2}, // LESS-THAN SIGN with vertical line
// "nvltrie", 0x022B4;0x020D2}, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line
{"nvle", 0x02264, 0x020D2}, // LESS-THAN OR EQUAL TO with vertical line
{"nvlt", 0x0003C, 0x020D2}, // LESS-THAN SIGN with vertical line
{"nvltrie", 0x022B4, 0x020D2}, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line
{"nvrArr", 0x02903}, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE
// "nvrtrie", 0x022B5;0x020D2}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line
// "nvsim", 0x0223C;0x020D2}, // TILDE OPERATOR with vertical line
{"nvrtrie", 0x022B5, 0x020D2}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line
{"nvsim", 0x0223C, 0x020D2}, // TILDE OPERATOR with vertical line
{"nwarhk", 0x02923}, // NORTH WEST ARROW WITH HOOK
{"nwarr", 0x02196}, // NORTH WEST ARROW
{"nwArr", 0x021D6}, // NORTH WEST DOUBLE ARROW
@ -1704,7 +1662,7 @@ immutable NameId[] namesQ =
immutable NameId[] namesR =
[
{"rAarr", 0x021DB}, // RIGHTWARDS TRIPLE ARROW
// "race", 0x0223D;0x00331}, // REVERSED TILDE with underline
{"race", 0x0223D, 0x00331}, // REVERSED TILDE with underline
{"Racute", 0x00154}, // LATIN CAPITAL LETTER R WITH ACUTE
{"racute", 0x00155}, // LATIN SMALL LETTER R WITH ACUTE
{"radic", 0x0221A}, // SQUARE ROOT
@ -1932,7 +1890,7 @@ immutable NameId[] namesS =
{"smile", 0x02323}, // SMILE
{"smt", 0x02AAA}, // SMALLER THAN
{"smte", 0x02AAC}, // SMALLER THAN OR EQUAL TO
// "smtes", 0x02AAC;0x0FE00}, // SMALLER THAN OR slanted EQUAL
{"smtes", 0x02AAC, 0x0FE00}, // SMALLER THAN OR slanted EQUAL
{"SOFTcy", 0x0042C}, // CYRILLIC CAPITAL LETTER SOFT SIGN
{"softcy", 0x0044C}, // CYRILLIC SMALL LETTER SOFT SIGN
{"sol", 0x0002F}, // SOLIDUS
@ -1944,9 +1902,9 @@ immutable NameId[] namesS =
{"spadesuit", 0x02660}, // BLACK SPADE SUIT
{"spar", 0x02225}, // PARALLEL TO
{"sqcap", 0x02293}, // SQUARE CAP
// "sqcaps", 0x02293;0x0FE00}, // SQUARE CAP with serifs
{"sqcaps", 0x02293, 0x0FE00}, // SQUARE CAP with serifs
{"sqcup", 0x02294}, // SQUARE CUP
// "sqcups", 0x02294;0x0FE00}, // SQUARE CUP with serifs
{"sqcups", 0x02294, 0x0FE00}, // SQUARE CUP with serifs
{"Sqrt", 0x0221A}, // SQUARE ROOT
{"sqsub", 0x0228F}, // SQUARE IMAGE OF
{"sqsube", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
@ -2082,7 +2040,7 @@ immutable NameId[] namesT =
{"thgr", 0x003B8}, // GREEK SMALL LETTER THETA
{"thickapprox", 0x02248}, // ALMOST EQUAL TO
{"thicksim", 0x0223C}, // TILDE OPERATOR
// "ThickSpace", 0x0205F;0x0200A}, // space of width 5/18 em
{"ThickSpace", 0x0205F, 0x0200A}, // space of width 5/18 em
{"thinsp", 0x02009}, // THIN SPACE
{"ThinSpace", 0x02009}, // THIN SPACE
{"thkap", 0x02248}, // ALMOST EQUAL TO
@ -2245,10 +2203,10 @@ immutable NameId[] namesV =
{"vArr", 0x021D5}, // UP DOWN DOUBLE ARROW
{"varrho", 0x003F1}, // GREEK RHO SYMBOL
{"varsigma", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
// "varsubsetneq", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
// "varsubsetneqq", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
// "varsupsetneq", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
// "varsupsetneqq", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
{"varsubsetneq", 0x0228A, 0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
{"varsubsetneqq", 0x02ACB, 0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
{"varsupsetneq", 0x0228B, 0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
{"varsupsetneqq", 0x02ACC, 0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
{"vartheta", 0x003D1}, // GREEK THETA SYMBOL
{"vartriangleleft", 0x022B2}, // NORMAL SUBGROUP OF
{"vartriangleright", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
@ -2279,18 +2237,18 @@ immutable NameId[] namesV =
{"Vfr", 0x1D519}, // MATHEMATICAL FRAKTUR CAPITAL V
{"vfr", 0x1D533}, // MATHEMATICAL FRAKTUR SMALL V
{"vltri", 0x022B2}, // NORMAL SUBGROUP OF
// "vnsub", 0x02282;0x020D2}, // SUBSET OF with vertical line
// "vnsup", 0x02283;0x020D2}, // SUPERSET OF with vertical line
{"vnsub", 0x02282, 0x020D2}, // SUBSET OF with vertical line
{"vnsup", 0x02283, 0x020D2}, // SUPERSET OF with vertical line
{"Vopf", 0x1D54D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL V
{"vopf", 0x1D567}, // MATHEMATICAL DOUBLE-STRUCK SMALL V
{"vprop", 0x0221D}, // PROPORTIONAL TO
{"vrtri", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
{"Vscr", 0x1D4B1}, // MATHEMATICAL SCRIPT CAPITAL V
{"vscr", 0x1D4CB}, // MATHEMATICAL SCRIPT SMALL V
// "vsubne", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
// "vsubnE", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
// "vsupne", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
// "vsupnE", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
{"vsubne", 0x0228A, 0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
{"vsubnE", 0x02ACB, 0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
{"vsupne", 0x0228B, 0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
{"vsupnE", 0x02ACC, 0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
{"Vvdash", 0x022AA}, // TRIPLE VERTICAL BAR RIGHT TURNSTILE
{"vzigzag", 0x0299A}, // VERTICAL ZIGZAG LINE
];

View file

@ -409,23 +409,9 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Var
{
unsafeAssign!"scope variable"(v);
}
else if (v.isTypesafeVariadicParameter && p == sc.func)
else if (v.isTypesafeVariadicArray && p == sc.func)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
{
unsafeAssign!"variadic variable"(v);
}
}
else
{
/* v is not 'scope', and is assigned to a parameter that may escape.
* Therefore, v can never be 'scope'.
*/
if (log) printf("no infer for %s in %s loc %s, fdc %s, %d\n",
v.toChars(), sc.func.ident.toChars(), sc.func.loc.toChars(), fdc.ident.toChars(), __LINE__);
doNotInferScope(v, vPar);
unsafeAssign!"variadic variable"(v);
}
}
@ -673,9 +659,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
FuncDeclaration fd = sc.func;
// Determine if va is a parameter that is an indirect reference
const bool vaIsRef = va && va.storage_class & STC.parameter &&
(va.isReference() || va.type.toBasetype().isTypeClass()); // ref, out, or class
// Determine if va is a `ref` parameter, so it has a lifetime exceding the function scope
const bool vaIsRef = va && va.isParameter() && va.isReference();
if (log && vaIsRef) printf("va is ref `%s`\n", va.toChars());
/* Determine if va is the first parameter, through which other 'return' parameters
@ -717,7 +702,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
Dsymbol p = v.toParent2();
if (va && !vaIsRef && !va.isScope() && !v.isScope() &&
!v.isTypesafeVariadicParameter && !va.isTypesafeVariadicParameter &&
!v.isTypesafeVariadicArray && !va.isTypesafeVariadicArray &&
(va.isParameter() && va.maybeScope && v.isParameter() && v.maybeScope) &&
p == fd)
{
@ -727,16 +712,9 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
continue;
}
if (vaIsFirstRef &&
(v.isScope() || v.maybeScope) &&
!(v.storage_class & STC.return_) &&
v.isParameter() &&
fd.flags & FUNCFLAG.returnInprocess &&
p == fd &&
!v.isTypesafeVariadicParameter)
if (vaIsFirstRef && p == fd)
{
if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars());
inferReturn(fd, v, /*returnScope:*/ true); // infer addition of 'return' to make `return scope`
inferReturn(fd, v, /*returnScope:*/ true);
}
if (!(va && va.isScope()) || vaIsRef)
@ -744,82 +722,66 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
if (v.isScope())
{
if (vaIsFirstRef && v.isParameter() && v.storage_class & STC.return_)
if (vaIsFirstRef && v.isParameter() && v.isReturn())
{
// va=v, where v is `return scope`
if (va.isScope())
if (inferScope(va))
continue;
if (va.maybeScope)
{
if (log) printf("inferring scope for lvalue %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
continue;
}
}
if (va && va.isScope() && va.storage_class & STC.return_ && !(v.storage_class & STC.return_))
{
// va may return its value, but v does not allow that, so this is an error
if (sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to return scope `%s`", v, va))
{
result = true;
continue;
}
}
// If va's lifetime encloses v's, then error
if (va && !va.isDataseg() &&
((va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp)) || vaIsRef))
if (EnclosedBy eb = va.enclosesLifetimeOf(v))
{
if (sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to `%s` with longer lifetime", v, va))
const(char)* msg;
final switch (eb)
{
case EnclosedBy.none: assert(0);
case EnclosedBy.returnScope:
msg = "scope variable `%s` assigned to return scope `%s`";
break;
case EnclosedBy.longerScope:
if (v.storage_class & STC.temp)
continue;
msg = "scope variable `%s` assigned to `%s` with longer lifetime";
break;
case EnclosedBy.refVar:
msg = "scope variable `%s` assigned to `ref` variable `%s` with longer lifetime";
break;
case EnclosedBy.global:
msg = "scope variable `%s` assigned to global variable `%s`";
break;
}
if (sc.setUnsafeDIP1000(gag, ae.loc, msg, v, va))
{
result = true;
continue;
}
}
if (va && !va.isDataseg() && (va.isScope() || va.maybeScope))
// v = scope, va should be scope as well
const vaWasScope = va && va.isScope();
if (inferScope(va))
{
if (!va.isScope())
{ /* v is scope, and va is not scope, so va needs to
* infer scope
*/
if (log) printf("inferring scope for %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
/* v returns, and va does not return, so va needs
* to infer return
*/
if (v.storage_class & STC.return_ &&
!(va.storage_class & STC.return_))
{
if (log) printf("infer return for %s\n", va.toChars());
va.storage_class |= STC.return_ | STC.returninferred;
// In case of `scope local = returnScopeParam`, do not infer return scope for `x`
if (!vaWasScope && v.isReturn() && !va.isReturn())
{
if (log) printf("infer return for %s\n", va.toChars());
va.storage_class |= STC.return_ | STC.returninferred;
// Added "return scope" so don't confuse it with "return ref"
if (isRefReturnScope(va.storage_class))
va.storage_class |= STC.returnScope;
}
// Added "return scope" so don't confuse it with "return ref"
if (isRefReturnScope(va.storage_class))
va.storage_class |= STC.returnScope;
}
continue;
}
result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1);
}
else if (v.isTypesafeVariadicParameter && p == fd)
else if (v.isTypesafeVariadicArray && p == fd)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
{
if (va && !va.isDataseg() && (va.isScope() || va.maybeScope))
{
if (!va.isScope())
{ //printf("inferring scope for %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
}
continue;
}
result |= sc.setUnsafeDIP1000(gag, ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v, e1);
}
if (inferScope(va))
continue;
result |= sc.setUnsafeDIP1000(gag, ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v, e1);
}
else
{
@ -845,7 +807,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
if (va && va.isScope() && !v.isReference())
{
if (!(va.storage_class & STC.return_))
if (!va.isReturn())
{
va.doNotInferReturn = true;
}
@ -858,19 +820,14 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
Dsymbol p = v.toParent2();
if (vaIsFirstRef && v.isParameter() &&
!(v.storage_class & STC.return_) &&
fd.flags & FUNCFLAG.returnInprocess &&
p == fd)
if (vaIsFirstRef && p == fd)
{
//if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars());
inferReturn(fd, v, /*returnScope:*/ false);
}
// If va's lifetime encloses v's, then error
if (va &&
!(vaIsFirstRef && (v.storage_class & STC.return_)) &&
(va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()))
if (va && !(vaIsFirstRef && v.isReturn()) && va.enclosesLifetimeOf(v))
{
if (sc.setUnsafeDIP1000(gag, ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v, va))
{
@ -885,13 +842,9 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
if (p != sc.func)
continue;
if (va && !va.isDataseg() && (va.isScope() || va.maybeScope))
if (inferScope(va))
{
if (!va.isScope())
{ //printf("inferring scope for %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
}
if (v.storage_class & STC.return_ && !(va.storage_class & STC.return_))
if (v.isReturn() && !va.isReturn())
va.storage_class |= STC.return_ | STC.returninferred;
continue;
}
@ -912,7 +865,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
* then uncount that address of. This is so it won't cause a
* closure to be allocated.
*/
if (va && va.isScope() && !(va.storage_class & STC.return_) && func.tookAddressOf)
if (va && va.isScope() && !va.isReturn() && func.tookAddressOf)
--func.tookAddressOf;
foreach (v; vars)
@ -978,14 +931,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
}
}
if (va && !va.isDataseg() && (va.isScope() || va.maybeScope))
{
if (!va.isScope())
{ //printf("inferring scope for %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
}
if (inferScope(va))
continue;
}
result |= sc.setUnsafeDIP1000(gag, ee.loc,
"reference to stack allocated value returned by `%s` assigned to non-scope `%s`", ee, e1);
@ -1091,14 +1038,10 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
continue;
}
}
else if (v.isTypesafeVariadicParameter && p == sc.func)
else if (v.isTypesafeVariadicArray && p == sc.func)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
{
result |= sc.setUnsafeDIP1000(gag, e.loc,
"copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e, v);
}
result |= sc.setUnsafeDIP1000(gag, e.loc,
"copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e, v);
}
else
{
@ -1258,15 +1201,8 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
Dsymbol p = v.toParent2();
if ((v.isScope() || v.maybeScope) &&
!(v.storage_class & STC.return_) &&
v.isParameter() &&
!v.doNotInferReturn &&
sc.func.flags & FUNCFLAG.returnInprocess &&
p == sc.func &&
!v.isTypesafeVariadicParameter)
if (p == sc.func && inferReturn(sc.func, v, /*returnScope:*/ true))
{
inferReturn(sc.func, v, /*returnScope:*/ true); // infer addition of 'return'
continue;
}
@ -1300,7 +1236,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
!(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0)
)
{
if (v.isParameter() && !(v.storage_class & STC.return_))
if (v.isParameter() && !v.isReturn())
{
// https://issues.dlang.org/show_bug.cgi?id=23191
if (!gag)
@ -1320,15 +1256,11 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
}
}
}
else if (v.isTypesafeVariadicParameter && p == sc.func)
else if (v.isTypesafeVariadicArray && p == sc.func)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
{
if (!gag)
error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars());
result = false;
}
if (!gag)
error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars());
result = false;
}
else
{
@ -1414,7 +1346,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
continue;
}
FuncDeclaration fd = p.isFuncDeclaration();
if (fd && sc.func.flags & FUNCFLAG.returnInprocess)
if (fd && sc.func.returnInprocess)
{
/* Code like:
* int x;
@ -1435,10 +1367,10 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
vsr == ScopeRef.Ref_ReturnScope) &&
!(v.storage_class & STC.foreach_))
{
if (sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func &&
(vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope))
if (p == sc.func && (vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope) &&
inferReturn(sc.func, v, /*returnScope:*/ false))
{
inferReturn(sc.func, v, /*returnScope:*/ false); // infer addition of 'return'
continue;
}
else
{
@ -1488,6 +1420,26 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
return result;
}
/***********************************
* Infer `scope` for a variable
*
* Params:
* va = variable to infer scope for
* Returns: `true` if succesful or already `scope`
*/
bool inferScope(VarDeclaration va)
{
if (!va)
return false;
if (!va.isDataseg() && va.maybeScope && !va.isScope())
{
//printf("inferring scope for %s\n", va.toChars());
va.maybeScope = false;
va.storage_class |= STC.scope_ | STC.scopeinferred;
return true;
}
return va.isScope();
}
/*************************************
* Variable v needs to have 'return' inferred for it.
@ -1495,10 +1447,22 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
* fd = function that v is a parameter to
* v = parameter that needs to be STC.return_
* returnScope = infer `return scope` instead of `return ref`
*
* Returns: whether the inference on `v` was successful or `v` already was `return`
*/
private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
{
// v is a local in the current function
if (v.isReturn())
return !!(v.storage_class & STC.returnScope) == returnScope;
if (!v.isParameter() || v.isTypesafeVariadicArray || (returnScope && v.doNotInferReturn))
return false;
if (!fd.returnInprocess)
return false;
if (returnScope && !(v.isScope() || v.maybeScope))
return false;
//printf("for function '%s' inferring 'return' for variable '%s', returnScope: %d\n", fd.toChars(), v.toChars(), returnScope);
auto newStcs = STC.return_ | STC.returninferred | (returnScope ? STC.returnScope : 0);
@ -1532,6 +1496,7 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
}
}
}
return true;
}
@ -1694,7 +1659,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
{
if (tb.ty == Tsarray)
return;
if (v.isTypesafeVariadicParameter)
if (v.isTypesafeVariadicArray)
{
er.byvalue.push(v);
return;
@ -2008,13 +1973,10 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
if (auto ve = e.e1.isVarExp())
{
VarDeclaration v = ve.var.isVarDeclaration();
if (tb.ty == Tarray || tb.ty == Tsarray)
if (v && v.isTypesafeVariadicArray)
{
if (v && v.isTypesafeVariadicParameter)
{
er.pushRef(v, retRefTransition);
return;
}
er.pushRef(v, retRefTransition);
return;
}
}
if (tb.ty == Tsarray)
@ -2339,9 +2301,9 @@ private void doNotInferScope(VarDeclaration v, RootObject o)
void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
{
if (funcdecl.flags & FUNCFLAG.returnInprocess)
if (funcdecl.returnInprocess)
{
funcdecl.flags &= ~FUNCFLAG.returnInprocess;
funcdecl.returnInprocess = false;
if (funcdecl.storage_class & STC.return_)
{
if (funcdecl.type == f)
@ -2353,9 +2315,9 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
}
}
if (!(funcdecl.flags & FUNCFLAG.inferScope))
if (!funcdecl.inferScope)
return;
funcdecl.flags &= ~FUNCFLAG.inferScope;
funcdecl.inferScope = false;
// Eliminate maybescope's
{
@ -2387,22 +2349,19 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
foreach (u, p; f.parameterList)
{
auto v = (*funcdecl.parameters)[u];
if (v.maybeScope)
if (!v.isScope() && inferScope(v))
{
//printf("Inferring scope for %s\n", v.toChars());
notMaybeScope(v, null);
v.storage_class |= STC.scope_ | STC.scopeinferred;
p.storageClass |= STC.scope_ | STC.scopeinferred;
}
}
}
if (funcdecl.vthis && funcdecl.vthis.maybeScope)
if (funcdecl.vthis)
{
notMaybeScope(funcdecl.vthis, null);
funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred;
f.isScopeQual = true;
f.isscopeinferred = true;
inferScope(funcdecl.vthis);
f.isScopeQual = funcdecl.vthis.isScope();
f.isscopeinferred = !!(funcdecl.vthis.storage_class & STC.scopeinferred);
}
}
@ -2542,20 +2501,45 @@ bool isReferenceToMutable(Parameter p, Type t)
return isReferenceToMutable(p.type);
}
/**********************************
* Determine if `va` has a lifetime that lasts past
* the destruction of `v`
* Params:
* va = variable assigned to
* v = variable being assigned
* Returns:
* true if it does
*/
private bool enclosesLifetimeOf(const VarDeclaration va, const VarDeclaration v) pure
/// When checking lifetime for assignment `va=v`, the way `va` encloses `v`
private enum EnclosedBy
{
none = 0,
refVar, // `va` is a `ref` variable, which may link to a global variable
global, // `va` is a global variable
returnScope, // `va` is a scope variable that may be returned
longerScope, // `va` is another scope variable declared earlier than `v`
}
/**********************************
* Determine if `va` has a lifetime that lasts past
* the destruction of `v`
* Params:
* va = variable assigned to
* v = variable being assigned
* Returns:
* The way `va` encloses `v` (if any)
*/
private EnclosedBy enclosesLifetimeOf(VarDeclaration va, VarDeclaration v)
{
if (!va)
return EnclosedBy.none;
if (va.isDataseg())
return EnclosedBy.global;
if (va.isScope() && va.isReturn() && !v.isReturn())
return EnclosedBy.returnScope;
if (va.isReference() && va.isParameter())
return EnclosedBy.refVar;
assert(va.sequenceNumber != va.sequenceNumber.init);
assert(v.sequenceNumber != v.sequenceNumber.init);
return va.sequenceNumber < v.sequenceNumber;
if (va.sequenceNumber < v.sequenceNumber)
return EnclosedBy.longerScope;
return EnclosedBy.none;
}
/***************************************
@ -2576,53 +2560,6 @@ private void addMaybe(VarDeclaration va, VarDeclaration v)
va.maybes.push(v);
}
/***************************************
* Like `FuncDeclaration.setUnsafe`, but modified for dip25 / dip1000 by default transitions
*
* With `-preview=dip1000` it actually sets the function as unsafe / prints an error, while
* without it, it only prints a deprecation in a `@safe` function.
* With `-revert=preview=dip1000`, it doesn't do anything.
*
* Params:
* sc = used for checking whether we are in a deprecated scope
* fs = command line setting of dip1000 / dip25
* gag = surpress error message
* loc = location of error
* fmt = printf-style format string
* arg0 = (optional) argument for first %s format specifier
* arg1 = (optional) argument for second %s format specifier
* arg2 = (optional) argument for third %s format specifier
* Returns: whether an actual safe error (not deprecation) occured
*/
private bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
{
if (fs == FeatureState.disabled)
{
return false;
}
else if (fs == FeatureState.enabled)
{
return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
}
else
{
if (sc.func.isSafeBypassingInference())
{
if (!gag)
previewErrorFunc(sc.isDeprecated(), fs)(
loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""
);
}
else if (!sc.func.safetyViolation)
{
import dmd.func : AttributeViolation;
sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
}
return false;
}
}
// `setUnsafePreview` partially evaluated for dip1000
private bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg,
RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
@ -2671,13 +2608,19 @@ private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool g
}
/****************************
* Determine if `v` is a typesafe variadic parameter.
* Determine if `v` is a typesafe variadic array, which is implicitly `scope`
* Params:
* v = variable to check
* Returns:
* true if `v` is a variadic parameter
*/
bool isTypesafeVariadicParameter(VarDeclaration v)
private bool isTypesafeVariadicArray(VarDeclaration v)
{
return !!(v.storage_class & STC.variadic);
if (v.storage_class & STC.variadic)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
return true;
}
return false;
}

View file

@ -2949,7 +2949,7 @@ extern (C++) final class ArrayLiteralExp : Expression
Expressions* elements;
OwnedBy ownedByCtfe = OwnedBy.code;
bool onstack = false;
extern (D) this(const ref Loc loc, Type type, Expressions* elements)
{

View file

@ -419,6 +419,7 @@ public:
Expression *basis;
Expressions *elements;
OwnedBy ownedByCtfe;
bool onstack;
static ArrayLiteralExp *create(const Loc &loc, Expressions *elements);
static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements);

View file

@ -353,6 +353,37 @@ extern(D) bool arrayExpressionSemantic(
return err;
}
/*
Checks if `exp` contains a direct access to a `noreturn`
variable. If that is the case, an `assert(0)` expression
is generated and returned. This function should be called
only after semantic analysis has been performed on `exp`.
Params:
exp = expression that is checked
Returns:
An `assert(0)` expression if `exp` contains a `noreturn`
variable access, `exp` otherwise.
*/
Expression checkNoreturnVarAccess(Expression exp)
{
assert(exp.type);
Expression result = exp;
if (exp.type.isTypeNoreturn() && !exp.isAssertExp() &&
!exp.isThrowExp() && !exp.isCallExp())
{
auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`");
msg.type = Type.tstring;
result = new AssertExp(exp.loc, IntegerExp.literal!0, msg);
result.type = exp.type;
}
return result;
}
/******************************
* Check the tail CallExp is really property function call.
* Bugs:
@ -848,6 +879,18 @@ Lagain:
if (d)
d.checkDisabled(loc, sc);
}
if (auto sd = s.isDeclaration())
{
if (sd.isSystem())
{
if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
"cannot access `@system` variable `%s` in @safe code", sd))
{
return ErrorExp.get();
}
}
}
}
if (auto em = s.isEnumMember())
@ -1714,7 +1757,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
if (sc._module)
sc._module.hasAlwaysInlines = true;
if (sc.func)
sc.func.flags |= FUNCFLAG.hasAlwaysInline;
sc.func.hasAlwaysInlines = true;
}
const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
@ -2200,14 +2243,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
/* If calling C scanf(), printf(), or any variants, check the format string against the arguments
*/
const isVa_list = tf.parameterList.varargs == VarArg.none;
if (fd && fd.flags & FUNCFLAG.printf)
if (fd && fd.printf)
{
if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
{
checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
}
}
else if (fd && fd.flags & FUNCFLAG.scanf)
else if (fd && fd.scanf)
{
if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
{
@ -4628,8 +4671,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else if (exp.arguments.dim == 1)
{
e = (*exp.arguments)[0];
e = e.implicitCastTo(sc, t1);
e = new CastExp(exp.loc, e, t1);
if (!e.type.isTypeNoreturn())
e = e.implicitCastTo(sc, t1);
}
else
{
@ -7474,6 +7517,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
if (exp.e1.type.isTypeNoreturn() && (!exp.to || !exp.to.isTypeNoreturn()))
{
result = exp.e1;
return;
}
if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
exp.e1 = exp.e1.arrayFuncConv(sc);
@ -7889,7 +7937,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
}
else if (t1b.ty == Tvector)
else if (t1b.ty == Tvector && exp.e1.isLvalue())
{
// Convert e1 to corresponding static array
TypeVector tv1 = cast(TypeVector)t1b;
@ -8896,7 +8944,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.e1 = e1x;
assert(exp.e1.type);
}
Type t1 = exp.e1.type.toBasetype();
Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
/* Run this.e2 semantic.
* Different from other binary expressions, the analysis of e2
@ -8918,14 +8966,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e2x.checkSharedAccess(sc))
return setError();
if (e2x.type.isTypeNoreturn() && !e2x.isAssertExp() && !e2x.isThrowExp() && !e2x.isCallExp())
{
auto msg = new StringExp(e2x.loc, "Accessed expression of type `noreturn`");
msg.type = Type.tstring;
e2x = new AssertExp(e2x.loc, IntegerExp.literal!0, msg);
e2x.type = Type.tnoreturn;
return setResult(e2x);
}
auto etmp = checkNoreturnVarAccess(e2x);
if (etmp != e2x)
return setResult(etmp);
exp.e2 = e2x;
}
@ -9890,14 +9934,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.type = exp.e1.type;
assert(exp.type);
auto assignElem = exp.e2;
auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
Expression tmp;
/* https://issues.dlang.org/show_bug.cgi?id=22366
*
* `reorderSettingAAElem` creates a tree of comma expressions, however,
* `checkAssignExp` expects only AssignExps.
*/
checkAssignEscape(sc, Expression.extractLast(res, tmp), false, false);
if (res == exp) // no `AA[k] = v` rewrite was performed
checkAssignEscape(sc, res, false, false);
else
checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
if (auto ae = res.isConstructExp())
{
@ -9905,40 +9952,48 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (t1b.ty != Tsarray && t1b.ty != Tarray)
return setResult(res);
/* Do not lower Rvalues and references, as they need to be moved,
* not copied.
* Skip the lowering when the RHS is an array literal, as e2ir
* already handles such cases more elegantly.
*/
const isArrayCtor =
(ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
ae.e2.isLvalue &&
!(ae.e1.isVarExp &&
ae.e1.isVarExp.var.isVarDeclaration.isReference) &&
(ae.e2.isVarExp ||
ae.e2.isSliceExp ||
(ae.e2.type.ty == Tsarray && !ae.e2.isArrayLiteralExp)) &&
ae.e1.type.nextOf &&
ae.e2.type.nextOf &&
ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf);
// only non-trivial array constructions may need to be lowered (non-POD elements basically)
Type t1e = t1b.nextOf();
TypeStruct ts = t1e.baseElemOf().isTypeStruct();
if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
return setResult(res);
/* Unlike isArrayCtor above, lower all Rvalues. If the RHS is a literal,
* then we do want to make a temporary for it and call its destructor.
*/
const isArraySetCtor =
(ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
(ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) &&
ae.e1.type.nextOf &&
ae.e1.type.nextOf.equivalent(ae.e2.type);
// don't lower ref-constructions etc.
if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
(ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
return setResult(res);
if (isArrayCtor || isArraySetCtor)
// Construction from an equivalent other array?
// Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
Type t2b = ae.e2.type.toBasetype();
// skip over a (possibly implicit) cast of a static array RHS to a slice
Expression rhs = ae.e2;
Type rhsType = t2b;
if (t2b.ty == Tarray)
{
const ts = t1b.nextOf().baseElemOf().isTypeStruct();
if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
return setResult(res);
if (auto ce = rhs.isCastExp())
{
auto ct = ce.e1.type.toBasetype();
if (ct.ty == Tsarray)
{
rhs = ce.e1;
rhsType = ct;
}
}
}
const lowerToArrayCtor =
( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
(rhsType.ty == Tsarray && rhs.isLvalue) ) &&
t1e.equivalent(t2b.nextOf);
auto func = isArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
const other = isArrayCtor ? "other array" : "value";
// Construction from a single element?
// If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
if (lowerToArrayCtor || lowerToArraySetCtor)
{
auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
const other = lowerToArrayCtor ? "other array" : "value";
if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
return setError();
@ -9948,18 +10003,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
id = new DotIdExp(exp.loc, id, func);
auto arguments = new Expressions();
arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf).expressionSemantic(sc));
if (isArrayCtor)
arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
if (lowerToArrayCtor)
{
arguments.push(new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf).expressionSemantic(sc));
arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
Expression ce = new CallExp(exp.loc, id, arguments);
res = ce.expressionSemantic(sc);
}
else
{
Expression e0;
// If ae.e2 is not a variable, construct a temp variable, as _d_arraysetctor requires `ref` access
if (!ae.e2.isVarExp)
// promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
if (!ae.e2.isLvalue)
{
auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
@ -11759,6 +11814,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = arrayLowering;
return;
}
if (t1.isTypeVector())
exp.type = t1;
result = exp;
return;
}
@ -12038,6 +12097,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
if (t1.isTypeVector())
exp.type = t1;
result = exp;
}
@ -12490,8 +12552,7 @@ Expression semanticX(DotIdExp exp, Scope* sc)
if (f.checkForwardRef(loc))
return ErrorExp.get();
if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess |
FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess))
if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
{
f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes");
return ErrorExp.get();
@ -13099,7 +13160,7 @@ Lerr:
*/
bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
{
if (!global.params.noSharedAccess ||
if (global.params.noSharedAccess != FeatureState.enabled ||
sc.intypeof ||
sc.flags & SCOPE.ctfe)
{

View file

@ -182,7 +182,7 @@ public:
catches.push(ctch);
Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
fd.flags &= ~FUNCFLAG.noEH;
fd.hasNoEH = false;
replaceCurrent(s2);
s2.accept(this);
}
@ -191,31 +191,31 @@ public:
}
}
enum FUNCFLAG : uint
private struct FUNCFLAG
{
purityInprocess = 1, /// working on determining purity
safetyInprocess = 2, /// working on determining safety
nothrowInprocess = 4, /// working on determining nothrow
nogcInprocess = 8, /// working on determining @nogc
returnInprocess = 0x10, /// working on inferring 'return' for parameters
inlineScanned = 0x20, /// function has been scanned for inline possibilities
inferScope = 0x40, /// infer 'scope' for parameters
hasCatches = 0x80, /// function has try-catch statements
compileTimeOnly = 0x100, /// is a compile time only function; no code will be generated for it
printf = 0x200, /// is a printf-like function
scanf = 0x400, /// is a scanf-like function
noreturn = 0x800, /// the function does not return
NRVO = 0x1000, /// Support for named return value optimization
naked = 0x2000, /// The function is 'naked' (see inline ASM)
generated = 0x4000, /// The function is compiler generated (e.g. `opCmp`)
introducing = 0x8000, /// If this function introduces the overload set
semantic3Errors = 0x10000, /// If errors in semantic3 this function's frame ptr
noEH = 0x20000, /// No exception unwinding is needed
inferRetType = 0x40000, /// Return type is to be inferred
dualContext = 0x80000, /// has a dual-context 'this' parameter
hasAlwaysInline = 0x100000, /// Contains references to functions that must be inlined
CRTCtor = 0x200000, /// Has attribute pragma(crt_constructor)
CRTDtor = 0x400000, /// Has attribute pragma(crt_destructor)
bool purityInprocess; /// working on determining purity
bool safetyInprocess; /// working on determining safety
bool nothrowInprocess; /// working on determining nothrow
bool nogcInprocess; /// working on determining @nogc
bool returnInprocess; /// working on inferring 'return' for parameters
bool inlineScanned; /// function has been scanned for inline possibilities
bool inferScope; /// infer 'scope' for parameters
bool hasCatches; /// function has try-catch statements
bool isCompileTimeOnly; /// is a compile time only function; no code will be generated for it
bool printf; /// is a printf-like function
bool scanf; /// is a scanf-like function
bool noreturn; /// the function does not return
bool isNRVO = true; /// Support for named return value optimization
bool isNaked; /// The function is 'naked' (see inline ASM)
bool isGenerated; /// The function is compiler generated (e.g. `opCmp`)
bool isIntroducing; /// If this function introduces the overload set
bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr
bool hasNoEH; /// No exception unwinding is needed
bool inferRetType; /// Return type is to be inferred
bool hasDualContext; /// has a dual-context 'this' parameter
bool hasAlwaysInlines; /// Contains references to functions that must be inlined
bool isCrtCtor; /// Has attribute pragma(crt_constructor)
bool isCrtDtor; /// Has attribute pragma(crt_destructor)
}
/***********************************************************
@ -348,9 +348,9 @@ extern (C++) class FuncDeclaration : Declaration
/// better diagnostics
AttributeViolation* safetyViolation;
/// Function flags: A collection of boolean packed for memory efficiency
/// See the `FUNCFLAG` enum
uint flags = FUNCFLAG.NRVO;
/// See the `FUNCFLAG` struct
import dmd.common.bitfields;
mixin(generateBitFields!(FUNCFLAG, uint));
/**
* Data for a function declaration that is needed for the Objective-C
@ -373,13 +373,13 @@ extern (C++) class FuncDeclaration : Declaration
}
this.endloc = endloc;
if (noreturn)
this.flags |= FUNCFLAG.noreturn;
this.noreturn = true;
/* The type given for "infer the return type" is a TypeFunction with
* NULL for the return type.
*/
if (type && type.nextOf() is null)
this.flags |= FUNCFLAG.inferRetType;
this.inferRetType = true;
}
static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
@ -391,7 +391,7 @@ extern (C++) class FuncDeclaration : Declaration
{
//printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
FuncDeclaration f = s ? cast(FuncDeclaration)s
: new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), (flags & FUNCFLAG.noreturn) != 0);
: new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0);
f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
f.fbody = fbody ? fbody.syntaxCopy() : null;
@ -522,7 +522,7 @@ extern (C++) class FuncDeclaration : Declaration
{
const bool dualCtx = (toParent2() != toParentLocal());
if (dualCtx)
this.flags |= FUNCFLAG.dualContext;
this.hasDualContext = true;
auto ad = isThis();
if (!dualCtx && !ad && !isNested())
{
@ -1376,29 +1376,29 @@ extern (C++) class FuncDeclaration : Declaration
//printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
TypeFunction tf = type.toTypeFunction();
if (tf.purity == PURE.impure) // purity not specified
flags |= FUNCFLAG.purityInprocess;
purityInprocess = true;
if (tf.trust == TRUST.default_)
flags |= FUNCFLAG.safetyInprocess;
safetyInprocess = true;
if (!tf.isnothrow)
flags |= FUNCFLAG.nothrowInprocess;
nothrowInprocess = true;
if (!tf.isnogc)
flags |= FUNCFLAG.nogcInprocess;
nogcInprocess = true;
if (!isVirtual() || this.isIntroducing())
flags |= FUNCFLAG.returnInprocess;
returnInprocess = true;
// Initialize for inferring STC.scope_
flags |= FUNCFLAG.inferScope;
inferScope = true;
}
final PURE isPure()
{
//printf("FuncDeclaration::isPure() '%s'\n", toChars());
TypeFunction tf = type.toTypeFunction();
if (flags & FUNCFLAG.purityInprocess)
if (purityInprocess)
setImpure();
if (tf.purity == PURE.fwdref)
tf.purityLevel();
@ -1424,7 +1424,7 @@ extern (C++) class FuncDeclaration : Declaration
final PURE isPureBypassingInference()
{
if (flags & FUNCFLAG.purityInprocess)
if (purityInprocess)
return PURE.fwdref;
else
return isPure();
@ -1437,9 +1437,9 @@ extern (C++) class FuncDeclaration : Declaration
*/
extern (D) final bool setImpure()
{
if (flags & FUNCFLAG.purityInprocess)
if (purityInprocess)
{
flags &= ~FUNCFLAG.purityInprocess;
purityInprocess = false;
if (fes)
fes.func.setImpure();
}
@ -1448,21 +1448,32 @@ extern (C++) class FuncDeclaration : Declaration
return false;
}
extern (D) final uint flags()
{
return bitFields;
}
extern (D) final uint flags(uint f)
{
bitFields = f;
return bitFields;
}
final bool isSafe()
{
if (flags & FUNCFLAG.safetyInprocess)
if (safetyInprocess)
setUnsafe();
return type.toTypeFunction().trust == TRUST.safe;
}
final bool isSafeBypassingInference()
{
return !(flags & FUNCFLAG.safetyInprocess) && isSafe();
return !(safetyInprocess) && isSafe();
}
final bool isTrusted()
{
if (flags & FUNCFLAG.safetyInprocess)
if (safetyInprocess)
setUnsafe();
return type.toTypeFunction().trust == TRUST.trusted;
}
@ -1483,9 +1494,9 @@ extern (C++) class FuncDeclaration : Declaration
bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
{
if (flags & FUNCFLAG.safetyInprocess)
if (safetyInprocess)
{
flags &= ~FUNCFLAG.safetyInprocess;
safetyInprocess = false;
type.toTypeFunction().trust = TRUST.system;
if (fmt || arg0)
safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
@ -1518,99 +1529,14 @@ extern (C++) class FuncDeclaration : Declaration
final bool isNogc()
{
//printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
if (flags & FUNCFLAG.nogcInprocess)
if (nogcInprocess)
setGC();
return type.toTypeFunction().isnogc;
}
final bool isNogcBypassingInference()
{
return !(flags & FUNCFLAG.nogcInprocess) && isNogc();
}
final bool isNRVO() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.NRVO);
}
final void isNRVO(bool v) pure nothrow @safe @nogc
{
if (v) this.flags |= FUNCFLAG.NRVO;
else this.flags &= ~FUNCFLAG.NRVO;
}
final bool isNaked() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.naked);
}
final void isNaked(bool v) @safe pure nothrow @nogc
{
if (v) this.flags |= FUNCFLAG.naked;
else this.flags &= ~FUNCFLAG.naked;
}
final bool isGenerated() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.generated);
}
final void isGenerated(bool v) pure nothrow @safe @nogc
{
if (v) this.flags |= FUNCFLAG.generated;
else this.flags &= ~FUNCFLAG.generated;
}
final bool isIntroducing() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.introducing);
}
final bool hasSemantic3Errors() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.semantic3Errors);
}
final bool hasNoEH() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.noEH);
}
final bool inferRetType() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.inferRetType);
}
final bool hasDualContext() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.dualContext);
}
final bool hasAlwaysInlines() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.hasAlwaysInline);
}
final bool isCrtCtor() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.CRTCtor);
}
final void isCrtCtor(bool v) @safe pure nothrow @nogc
{
if (v) this.flags |= FUNCFLAG.CRTCtor;
else this.flags &= ~FUNCFLAG.CRTCtor;
}
final bool isCrtDtor() const scope @safe pure nothrow @nogc
{
return !!(this.flags & FUNCFLAG.CRTDtor);
}
final void isCrtDtor(bool v) @safe pure nothrow @nogc
{
if (v) this.flags |= FUNCFLAG.CRTDtor;
else this.flags &= ~FUNCFLAG.CRTDtor;
return !nogcInprocess && isNogc();
}
/**************************************
@ -1622,15 +1548,15 @@ extern (C++) class FuncDeclaration : Declaration
extern (D) final bool setGC()
{
//printf("setGC() %s\n", toChars());
if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope)
if (nogcInprocess && semanticRun < PASS.semantic3 && _scope)
{
this.semantic2(_scope);
this.semantic3(_scope);
}
if (flags & FUNCFLAG.nogcInprocess)
if (nogcInprocess)
{
flags &= ~FUNCFLAG.nogcInprocess;
nogcInprocess = false;
type.toTypeFunction().isnogc = false;
if (fes)
fes.func.setGC();
@ -3384,6 +3310,28 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
// re-resolve to check for supplemental message
if (!global.gag || global.params.showGaggedErrors)
{
if (tthis)
{
if (auto classType = tthis.isTypeClass())
{
if (auto baseClass = classType.sym.baseClass)
{
if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
{
MatchAccumulator mErr;
functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, fargs, null);
if (mErr.last > MATCH.nomatch && mErr.lastf)
{
errorSupplemental(loc, "%s `%s` hides base class function `%s`",
fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
return null;
}
}
}
}
}
const(char)* failMessage;
functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
if (failMessage)
@ -3767,7 +3715,7 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
this.fes = fes;
// Always infer scope for function literals
// See https://issues.dlang.org/show_bug.cgi?id=20362
this.flags |= FUNCFLAG.inferScope;
this.inferScope = true;
//printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
}
@ -4431,6 +4379,58 @@ bool setUnsafe(Scope* sc,
return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
}
/***************************************
* Like `setUnsafe`, but for safety errors still behind preview switches
*
* Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
* the behavior changes based on the setting:
*
* - In case of `-revert=fs`, it does nothing.
* - In case of `-preview=fs`, it's the same as `setUnsafe`
* - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
*
* Params:
* sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
* fs = feature state from the preview flag
* gag = surpress error message
* loc = location of error
* msg = printf-style format string
* arg0 = (optional) argument for first %s format specifier
* arg1 = (optional) argument for second %s format specifier
* arg2 = (optional) argument for third %s format specifier
* Returns: whether an actual safe error (not deprecation) occured
*/
bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
{
if (fs == FeatureState.disabled)
{
return false;
}
else if (fs == FeatureState.enabled)
{
return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
}
else
{
if (!sc.func)
return false;
if (sc.func.isSafeBypassingInference())
{
if (!gag)
previewErrorFunc(sc.isDeprecated(), fs)(
loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""
);
}
else if (!sc.func.safetyViolation)
{
import dmd.func : AttributeViolation;
sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
}
return false;
}
}
/// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
///
/// Has two modes:

View file

@ -160,15 +160,16 @@ extern (C++) struct Param
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
// Implementation: https://github.com/dlang/dmd/pull/9817
bool noSharedAccess; // read/write access to shared memory objects
FeatureState noSharedAccess; // read/write access to shared memory objects
bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
bool shortenedMethods; // allow => in normal function declarations
bool shortenedMethods = true; // allow => in normal function declarations
bool fixImmutableConv; // error on unsound immutable conversion - https://github.com/dlang/dmd/pull/14070
bool fix16997 = true; // fix integral promotions for unary + - ~ operators
// https://issues.dlang.org/show_bug.cgi?id=16997
FeatureState dtorFields; // destruct fields of partially constructed objects
// https://issues.dlang.org/show_bug.cgi?id=14246
FeatureState systemVariables; // limit access to variables marked @system from @safe code
CHECKENABLE useInvariants = CHECKENABLE._default; // generate class invariant checks
CHECKENABLE useIn = CHECKENABLE._default; // generate precondition checks

View file

@ -158,7 +158,7 @@ struct Param
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
// Implementation: https://github.com/dlang/dmd/pull/9817
bool noSharedAccess; // read/write access to shared memory objects
FeatureState noSharedAccess; // read/write access to shared memory objects
bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
bool shortenedMethods; // allow => in normal function declarations
@ -166,7 +166,9 @@ struct Param
bool fix16997; // fix integral promotions for unary + - ~ operators
// https://issues.dlang.org/show_bug.cgi?id=16997
FeatureState dtorFields; // destruct fields of partially constructed objects
// https://issues.dlang.org/show_bug.cgi?id=14246
// https://issues.dlang.org/show_bug.cgi?id=14246
FeatureState systemVariables; // limit access to variables marked @system from @safe code
CHECKENABLE useInvariants; // generate class invariant checks
CHECKENABLE useIn; // generate precondition checks
CHECKENABLE useOut; // generate postcondition checks

View file

@ -64,6 +64,7 @@ struct HdrGenState
int tpltMember;
int autoMember;
int forStmtInit;
int insideFuncBody;
bool declstring; // set while declaring alias for string,wstring or dstring
EnumDeclaration inEnumDecl;
@ -1045,8 +1046,18 @@ public:
buf.writestring(", ");
argsToBuffer(d.args, buf, hgs);
}
buf.writeByte(')');
// https://issues.dlang.org/show_bug.cgi?id=14690
// Unconditionally perform a full output dump
// for `pragma(inline)` declarations.
bool savedFullDump = global.params.dihdr.fullOutput;
if (d.ident == Id.Pinline)
global.params.dihdr.fullOutput = true;
visit(cast(AttribDeclaration)d);
global.params.dihdr.fullOutput = savedFullDump;
}
override void visit(ConditionalDeclaration d)
@ -1549,7 +1560,7 @@ public:
bodyToBuffer(f);
hgs.autoMember--;
}
else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false)
else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false && !hgs.insideFuncBody)
{
if (!f.fbody)
{
@ -1634,7 +1645,7 @@ public:
void bodyToBuffer(FuncDeclaration f)
{
if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember))
if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody))
{
if (!f.fbody && (f.fensures || f.frequires))
{
@ -1645,6 +1656,18 @@ public:
buf.writenl();
return;
}
// there is no way to know if a function is nested
// or not after parsing. We need scope information
// for that, which is avaible during semantic
// analysis. To overcome that, a simple mechanism
// is implemented: everytime we print a function
// body (templated or not) we increment a counter.
// We decredement the counter when we stop
// printing the function body.
++hgs.insideFuncBody;
scope(exit) { --hgs.insideFuncBody; }
const savetlpt = hgs.tpltMember;
const saveauto = hgs.autoMember;
hgs.tpltMember = 0;

View file

@ -1197,9 +1197,9 @@ class Lexer
/*******************************************
* Parse escape sequence.
*/
private uint escapeSequence()
private uint escapeSequence(out dchar c2)
{
return Lexer.escapeSequence(token.loc, p, Ccompile);
return Lexer.escapeSequence(token.loc, p, Ccompile, c2);
}
/********
@ -1211,10 +1211,11 @@ class Lexer
* sequence = pointer to string with escape sequence to parse. Updated to
* point past the end of the escape sequence
* Ccompile = true for compile C11 escape sequences
* c2 = returns second `dchar` of html entity with 2 code units, otherwise stays `dchar.init`
* Returns:
* the escape sequence as a single character
*/
private dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile)
private dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile, out dchar c2)
{
const(char)* p = sequence; // cache sequence reference on stack
scope(exit) sequence = p;
@ -1326,12 +1327,16 @@ class Lexer
switch (*p)
{
case ';':
c = HtmlNamedEntity(idstart[0 .. p - idstart]);
if (c == ~0)
auto entity = HtmlNamedEntity(idstart[0 .. p - idstart]);
c = entity[0];
if (entity == entity.init)
{
error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart);
c = '?';
}
if (entity[1] != entity.init[1])
c2 = entity[1];
p++;
break;
default:
@ -1665,6 +1670,7 @@ class Lexer
while (1)
{
dchar c = *p++;
dchar c2;
switch (c)
{
case '\\':
@ -1673,15 +1679,19 @@ class Lexer
case '&':
if (Ccompile)
goto default;
goto case;
c = escapeSequence(c2);
stringbuffer.writeUTF8(c);
if (c2 != dchar.init)
stringbuffer.writeUTF8(c2);
continue;
case 'u':
case 'U':
c = escapeSequence();
c = escapeSequence(c2);
stringbuffer.writeUTF8(c);
continue;
default:
c = escapeSequence();
c = escapeSequence(c2);
break;
}
break;
@ -1746,22 +1756,26 @@ class Lexer
//printf("Lexer::charConstant\n");
p++;
dchar c = *p++;
dchar c2;
switch (c)
{
case '\\':
switch (*p)
{
case 'u':
t.unsvalue = escapeSequence();
tk = TOK.wcharLiteral;
break;
goto default;
case 'U':
case '&':
t.unsvalue = escapeSequence();
tk = TOK.dcharLiteral;
break;
goto default;
default:
t.unsvalue = escapeSequence();
t.unsvalue = escapeSequence(c2);
if (c2 != c2.init)
{
error("html entity requires 2 code units, use a string instead of a character");
t.unsvalue = '?';
}
break;
}
break;
@ -1978,8 +1992,6 @@ class Lexer
break;
case 'b':
case 'B':
if (Ccompile)
error("binary constants not allowed");
++p;
base = 2;
break;
@ -3185,8 +3197,9 @@ unittest
static void test(T)(string sequence, T expected, bool Ccompile = false)
{
auto p = cast(const(char)*)sequence.ptr;
dchar c2;
Lexer lexer = new Lexer();
assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile));
assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile, c2));
assert(p == sequence.ptr + sequence.length);
}
@ -3253,7 +3266,8 @@ unittest
expected = expectedError;
auto p = cast(const(char)*)sequence.ptr;
Lexer lexer = new Lexer();
auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile);
dchar c2;
auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile, c2);
assert(gotError);
assert(expectedReturnValue == actualReturnValue);

View file

@ -116,7 +116,7 @@ public:
size_t namelen; // length of module name in characters
static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
static const char *find(const char *filename);
static Module *load(const Loc &loc, Identifiers *packages, Identifier *ident);
const char *kind() const override;

View file

@ -2488,6 +2488,16 @@ extern (C++) abstract class Type : ASTNode
return false;
}
/*************************************
* Detect if this is an unsafe type because of the presence of `@system` members
* Returns:
* true if so
*/
bool hasSystemFields()
{
return false;
}
/***************************************
* Returns: true if type has any invariants
*/
@ -3821,6 +3831,16 @@ extern (C++) final class TypeSArray : TypeArray
return next.hasPointers();
}
override bool hasSystemFields()
{
return next.hasSystemFields();
}
override bool hasVoidInitPointers()
{
return next.hasVoidInitPointers();
}
override bool hasInvariant()
{
return next.hasInvariant();
@ -5532,52 +5552,32 @@ extern (C++) final class TypeStruct : Type
override bool hasPointers()
{
// Probably should cache this information in sym rather than recompute
StructDeclaration s = sym;
if (sym.members && !sym.determineFields() && sym.type != Type.terror)
error(sym.loc, "no size because of forward references");
foreach (VarDeclaration v; s.fields)
{
if (v.storage_class & STC.ref_ || v.hasPointers())
return true;
}
return false;
sym.determineTypeProperties();
return sym.hasPointerField;
}
override bool hasVoidInitPointers()
{
// Probably should cache this information in sym rather than recompute
StructDeclaration s = sym;
sym.size(Loc.initial); // give error for forward references
foreach (VarDeclaration v; s.fields)
{
if (v._init && v._init.isVoidInitializer() && v.type.hasPointers())
return true;
if (!v._init && v.type.hasVoidInitPointers())
return true;
}
return false;
sym.determineTypeProperties();
return sym.hasVoidInitPointers;
}
override bool hasSystemFields()
{
sym.size(Loc.initial); // give error for forward references
sym.determineTypeProperties();
return sym.hasSystemFields;
}
override bool hasInvariant()
{
// Probably should cache this information in sym rather than recompute
StructDeclaration s = sym;
sym.size(Loc.initial); // give error for forward references
if (s.hasInvariant())
return true;
foreach (VarDeclaration v; s.fields)
{
if (v.type.hasInvariant())
return true;
}
return false;
sym.determineTypeProperties();
return sym.hasInvariant() || sym.hasFieldWithInvariant;
}
extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
@ -5857,6 +5857,11 @@ extern (C++) final class TypeEnum : Type
return memType().hasVoidInitPointers();
}
override bool hasSystemFields()
{
return memType().hasSystemFields();
}
override bool hasInvariant()
{
return memType().hasInvariant();

View file

@ -311,6 +311,7 @@ public:
virtual int hasWild() const;
virtual bool hasPointers();
virtual bool hasVoidInitPointers();
virtual bool hasSystemFields();
virtual bool hasInvariant();
virtual Type *nextOf();
Type *baseElemOf();
@ -458,6 +459,8 @@ public:
MATCH implicitConvTo(Type *to) override;
Expression *defaultInitLiteral(const Loc &loc) override;
bool hasPointers() override;
bool hasSystemFields() override;
bool hasVoidInitPointers() override;
bool hasInvariant() override;
bool needsDestruction() override;
bool needsCopyOrPostblit() override;
@ -794,6 +797,7 @@ public:
bool needsNested() override;
bool hasPointers() override;
bool hasVoidInitPointers() override;
bool hasSystemFields() override;
bool hasInvariant() override;
MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
@ -832,6 +836,7 @@ public:
bool isZeroInit(const Loc &loc) override;
bool hasPointers() override;
bool hasVoidInitPointers() override;
bool hasSystemFields() override;
bool hasInvariant() override;
Type *nextOf() override;

View file

@ -99,7 +99,7 @@ public:
override void visit(ArrayLiteralExp e)
{
if (e.type.ty != Tarray || !e.elements || !e.elements.dim)
if (e.type.ty != Tarray || !e.elements || !e.elements.dim || e.onstack)
return;
if (f.setGC())
{
@ -221,7 +221,7 @@ Expression checkGC(Scope* sc, Expression e)
FuncDeclaration f = sc.func;
if (e && e.op != EXP.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) &&
(f.type.ty == Tfunction &&
(cast(TypeFunction)f.type).isnogc || (f.flags & FUNCFLAG.nogcInprocess) || global.params.vgc) &&
(cast(TypeFunction)f.type).isnogc || f.nogcInprocess || global.params.vgc) &&
!(sc.flags & SCOPE.debug_))
{
scope NOGCVisitor gcv = new NOGCVisitor(f);

View file

@ -888,6 +888,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
error("redundant visibility attribute `%s`", AST.visibilityToChars(prot));
}
pAttrs.visibility.kind = prot;
const attrloc = token.loc;
nextToken();
@ -908,7 +909,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
}
const attrloc = token.loc;
a = parseBlock(pLastDecl, pAttrs);
if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined)
{
@ -3168,9 +3168,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (udas)
{
auto s = new AST.Dsymbols();
s.push(em);
auto uad = new AST.UserAttributeDeclaration(udas, s);
auto uad = new AST.UserAttributeDeclaration(udas, new AST.Dsymbols());
em.userAttribDecl = uad;
}

View file

@ -203,6 +203,13 @@ extern (C++) final class PrintASTVisitor : Visitor
printf(".func: %s\n", e.func ? e.func.toChars() : "");
}
override void visit(CompoundLiteralExp e)
{
visit(cast(Expression)e);
printIndent(indent + 2);
printf(".init: %s\n", e.initializer ? e.initializer.toChars() : "");
}
static void printIndent(int indent)
{
foreach (i; 0 .. indent)

View file

@ -288,7 +288,7 @@ bool isUniAlpha(dchar c)
// Binary search
while (low <= high)
{
size_t mid = (low + high) >> 1;
const size_t mid = low + ((high - low) >> 1);
if (c < ALPHA_TABLE[mid][0])
high = mid - 1;
else if (ALPHA_TABLE[mid][1] < c)

View file

@ -26,7 +26,7 @@ import dmd.identifier;
import dmd.mtype;
import dmd.target;
import dmd.tokens;
import dmd.func : setUnsafe;
import dmd.func : setUnsafe, setUnsafePreview;
/*************************************************************
* Check for unsafe access in @safe code:
@ -57,6 +57,14 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
if (!ad)
return false;
import dmd.globals : global;
if (v.isSystem())
{
if (sc.setUnsafePreview(global.params.systemVariables, !printmsg, e.loc,
"cannot access `@system` field `%s.%s` in `@safe` code", ad, v))
return true;
}
// needed to set v.overlapped and v.overlapUnsafe
if (ad.sizeok != Sizeok.done)
ad.determineSize(ad.loc);

View file

@ -282,7 +282,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
// Disable generated opAssign, because some members forbid identity assignment.
funcdecl.storage_class |= STC.disable;
funcdecl.fbody = null; // remove fbody which contains the error
funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
funcdecl.hasSemantic3Errors = false;
}
return;
}
@ -292,7 +292,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
if (funcdecl.semanticRun >= PASS.semantic3)
return;
funcdecl.semanticRun = PASS.semantic3;
funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
funcdecl.hasSemantic3Errors = false;
if (!funcdecl.type || funcdecl.type.ty != Tfunction)
return;
@ -650,7 +650,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
// handle NRVO
if (!target.isReturnOnStack(f, funcdecl.needThis()) || !funcdecl.checkNRVO())
funcdecl.flags &= ~FUNCFLAG.NRVO;
funcdecl.isNRVO = false;
if (funcdecl.fbody.isErrorStatement())
{
@ -753,15 +753,15 @@ private extern(C++) final class Semantic3Visitor : Visitor
if (f.isnothrow && blockexit & BE.throw_)
error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches))
if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.hasCatches))
{
/* Don't generate unwind tables for this function
* https://issues.dlang.org/show_bug.cgi?id=17997
*/
funcdecl.flags |= FUNCFLAG.noEH;
funcdecl.hasNoEH = true;
}
if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
if (funcdecl.nothrowInprocess)
{
if (funcdecl.type == f)
f = cast(TypeFunction)f.copy();
@ -976,7 +976,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
/* Do the semantic analysis on the [in] preconditions and
* [out] postconditions.
*/
immutable bool isnothrow = f.isnothrow && !(funcdecl.flags & FUNCFLAG.nothrowInprocess);
immutable bool isnothrow = f.isnothrow && !funcdecl.nothrowInprocess;
if (freq)
{
/* frequire is composed of the [in] contracts
@ -1001,11 +1001,11 @@ private extern(C++) final class Semantic3Visitor : Visitor
// Deprecated in 2.101, can be made an error in 2.111
deprecation(funcdecl.loc, "`%s`: `in` contract may throw but function is marked as `nothrow`",
funcdecl.toPrettyChars());
else if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
else if (funcdecl.nothrowInprocess)
f.isnothrow = false;
}
funcdecl.flags &= ~FUNCFLAG.noEH;
funcdecl.hasNoEH = false;
sc2 = sc2.pop();
@ -1048,11 +1048,11 @@ private extern(C++) final class Semantic3Visitor : Visitor
// Deprecated in 2.101, can be made an error in 2.111
deprecation(funcdecl.loc, "`%s`: `out` contract may throw but function is marked as `nothrow`",
funcdecl.toPrettyChars());
else if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
else if (funcdecl.nothrowInprocess)
f.isnothrow = false;
}
funcdecl.flags &= ~FUNCFLAG.noEH;
funcdecl.hasNoEH = false;
sc2 = sc2.pop();
@ -1180,10 +1180,10 @@ private extern(C++) final class Semantic3Visitor : Visitor
const blockexit = s.blockExit(funcdecl, isnothrow);
if (blockexit & BE.throw_)
{
funcdecl.flags &= ~FUNCFLAG.noEH;
funcdecl.hasNoEH = false;
if (isnothrow)
error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
else if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
else if (funcdecl.nothrowInprocess)
f.isnothrow = false;
}
@ -1195,7 +1195,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
}
}
// from this point on all possible 'throwers' are checked
funcdecl.flags &= ~FUNCFLAG.nothrowInprocess;
funcdecl.nothrowInprocess = false;
if (funcdecl.isSynchronized())
{
@ -1274,25 +1274,25 @@ private extern(C++) final class Semantic3Visitor : Visitor
/* If function survived being marked as impure, then it is pure
*/
if (funcdecl.flags & FUNCFLAG.purityInprocess)
if (funcdecl.purityInprocess)
{
funcdecl.flags &= ~FUNCFLAG.purityInprocess;
funcdecl.purityInprocess = false;
if (funcdecl.type == f)
f = cast(TypeFunction)f.copy();
f.purity = PURE.fwdref;
}
if (funcdecl.flags & FUNCFLAG.safetyInprocess)
if (funcdecl.safetyInprocess)
{
funcdecl.flags &= ~FUNCFLAG.safetyInprocess;
funcdecl.safetyInprocess = false;
if (funcdecl.type == f)
f = cast(TypeFunction)f.copy();
f.trust = TRUST.safe;
}
if (funcdecl.flags & FUNCFLAG.nogcInprocess)
if (funcdecl.nogcInprocess)
{
funcdecl.flags &= ~FUNCFLAG.nogcInprocess;
funcdecl.nogcInprocess = false;
if (funcdecl.type == f)
f = cast(TypeFunction)f.copy();
f.isnogc = true;
@ -1395,9 +1395,9 @@ private extern(C++) final class Semantic3Visitor : Visitor
*/
funcdecl.semanticRun = PASS.semantic3done;
if ((global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement()))
funcdecl.flags |= FUNCFLAG.semantic3Errors;
funcdecl.hasSemantic3Errors = true;
else
funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
funcdecl.hasSemantic3Errors = false;
if (funcdecl.type.ty == Terror)
funcdecl.errors = true;
//printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars());

View file

@ -2010,32 +2010,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
//printf("body = %p\n", ps._body);
if (ps.ident == Id.msg)
{
if (ps.args)
{
foreach (arg; *ps.args)
{
sc = sc.startCTFE();
auto e = arg.expressionSemantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
// pragma(msg) is allowed to contain types as well as expressions
e = ctfeInterpretForPragmaMsg(e);
if (e.op == EXP.error)
{
errorSupplemental(ps.loc, "while evaluating `pragma(msg, %s)`", arg.toChars());
return setError();
}
if (auto se = e.toStringExp())
{
const slice = se.toUTF8(sc).peekString();
fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr);
}
else
fprintf(stderr, "%s", e.toChars());
}
fprintf(stderr, "\n");
}
if (!pragmaMsgSemantic(ps.loc, sc, ps.args))
return setError();
}
else if (ps.ident == Id.lib)
{
@ -2075,75 +2051,19 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
else if (ps.ident == Id.startaddress)
{
if (!ps.args || ps.args.dim != 1)
ps.error("function name expected for start address");
else
{
Expression e = (*ps.args)[0];
sc = sc.startCTFE();
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
e = e.ctfeInterpret();
(*ps.args)[0] = e;
Dsymbol sa = getDsymbol(e);
if (!sa || !sa.isFuncDeclaration())
{
ps.error("function name expected for start address, not `%s`", e.toChars());
return setError();
}
if (ps._body)
{
ps._body = ps._body.statementSemantic(sc);
if (ps._body.isErrorStatement())
{
result = ps._body;
return;
}
}
result = ps;
return;
}
if (!pragmaStartAddressSemantic(ps.loc, sc, ps.args))
return setError();
}
else if (ps.ident == Id.Pinline)
{
PINLINE inlining = PINLINE.default_;
if (!ps.args || ps.args.dim == 0)
inlining = PINLINE.default_;
else if (!ps.args || ps.args.dim != 1)
if (auto fd = sc.func)
{
ps.error("boolean expression expected for `pragma(inline)`");
return setError();
fd.inlining = evalPragmaInline(ps.loc, sc, ps.args);
}
else
{
Expression e = (*ps.args)[0];
sc = sc.startCTFE();
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
e = e.ctfeInterpret();
e = e.toBoolean(sc);
if (e.isErrorExp())
{
ps.error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*ps.args)[0].toChars());
return setError();
}
const opt = e.toBool();
if (opt.hasValue(true))
inlining = PINLINE.always;
else if (opt.hasValue(false))
inlining = PINLINE.never;
FuncDeclaration fd = sc.func;
if (!fd)
{
ps.error("`pragma(inline)` is not inside a function");
return setError();
}
fd.inlining = inlining;
ps.error("`pragma(inline)` is not inside a function");
return setError();
}
}
else if (!global.params.ignoreUnsupportedPragmas)
@ -2932,13 +2852,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
}
// https://issues.dlang.org/show_bug.cgi?id=23063
if (texp.isTypeNoreturn() && !rs.exp.isAssertExp() && !rs.exp.isThrowExp() && !rs.exp.isCallExp())
{
auto msg = new StringExp(rs.exp.loc, "Accessed expression of type `noreturn`");
msg.type = Type.tstring;
rs.exp = new AssertExp(rs.loc, IntegerExp.literal!0, msg);
rs.exp.type = texp;
}
rs.exp = checkNoreturnVarAccess(rs.exp);
// @@@DEPRECATED_2.111@@@
const olderrors = global.startGagging();
@ -3022,7 +2936,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
// If we previously assumed the function could be ref when
// checking for `shared`, make sure we were right
if (global.params.noSharedAccess && rs.exp.type.isShared())
if (global.params.noSharedAccess == FeatureState.enabled && rs.exp.type.isShared())
{
fd.error("function returns `shared` but cannot be inferred `ref`");
supplemental();
@ -3648,7 +3562,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
if (sc.func)
{
sc.func.flags |= FUNCFLAG.hasCatches;
sc.func.hasCatches = true;
if (flags == (FLAGcpp | FLAGd))
{
tcs.error("cannot mix catching D and C++ exceptions in the same try-catch");
@ -4925,3 +4839,83 @@ private void debugThrowWalker(Statement s)
scope walker = new DebugWalker();
s.accept(walker);
}
/***********************************************************
* Evaluate and print a `pragma(msg, args)`
*
* Params:
* loc = location for error messages
* sc = scope for argument interpretation
* args = expressions to print
* Returns:
* `true` on success
*/
bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args)
{
if (!args)
return true;
foreach (arg; *args)
{
sc = sc.startCTFE();
auto e = arg.expressionSemantic(sc);
e = resolveProperties(sc, e);
sc = sc.endCTFE();
// pragma(msg) is allowed to contain types as well as expressions
e = ctfeInterpretForPragmaMsg(e);
if (e.op == EXP.error)
{
errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars());
return false;
}
if (auto se = e.toStringExp())
{
const slice = se.toUTF8(sc).peekString();
fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr);
}
else
fprintf(stderr, "%s", e.toChars());
}
fprintf(stderr, "\n");
return true;
}
/***********************************************************
* Evaluate `pragma(startAddress, func)` and store the resolved symbol in `args`
*
* Params:
* loc = location for error messages
* sc = scope for argument interpretation
* args = pragma arguments
* Returns:
* `true` on success
*/
bool pragmaStartAddressSemantic(Loc loc, Scope* sc, Expressions* args)
{
if (!args || args.dim != 1)
{
.error(loc, "function name expected for start address");
return false;
}
else
{
/* https://issues.dlang.org/show_bug.cgi?id=11980
* resolveProperties and ctfeInterpret call are not necessary.
*/
Expression e = (*args)[0];
sc = sc.startCTFE();
e = e.expressionSemantic(sc);
// e = resolveProperties(sc, e);
sc = sc.endCTFE();
// e = e.ctfeInterpret();
(*args)[0] = e;
Dsymbol sa = getDsymbol(e);
if (!sa || !sa.isFuncDeclaration())
{
.error(loc, "function name expected for start address, not `%s`", e.toChars());
return false;
}
}
return true;
}

View file

@ -73,6 +73,15 @@ private extern (C++) final class TemplateParameterSemanticVisitor : Visitor
result = !(ttp.specType && isError(ttp.specType));
}
override void visit(TemplateThisParameter ttp)
{
import dmd.errors;
if (!sc.getStructClassScope())
error(ttp.loc, "cannot use `this` outside an aggregate type");
visit(cast(TemplateTypeParameter)ttp);
}
override void visit(TemplateValueParameter tvp)
{
tvp.valType = tvp.valType.typeSemantic(tvp.loc, sc);

View file

@ -799,6 +799,15 @@ package mixin template ParseVisitMethods(AST)
s.accept(this);
}
override void visit(AST.InterfaceDeclaration d)
{
//printf("Visiting InterfaceDeclaration\n");
visitBaseClasses(d);
if (d.members)
foreach (s; *d.members)
s.accept(this);
}
override void visit(AST.AliasDeclaration d)
{
//printf("Visting AliasDeclaration\n");

View file

@ -1099,6 +1099,7 @@ public:
this assignment should call dtors on old assigned elements. */
if ((!postblit && !destructor)
|| (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral)
|| (e->op == EXP::construct && e->e2->op == EXP::call)
|| (e->op == EXP::construct && !lvalue && postblit)
|| (e->op == EXP::blit || e->e1->type->size () == 0))
{
@ -2704,6 +2705,14 @@ public:
this->result_ = compound_expr (saved_elems, d_convert (type, ctor));
}
else if (e->onstack)
{
/* Array literal for a `scope' dynamic array. */
gcc_assert (tb->ty == TY::Tarray);
ctor = force_target_expr (ctor);
this->result_ = d_array_value (type, size_int (e->elements->length),
build_address (ctor));
}
else
{
/* Allocate space on the memory managed heap. */

View file

@ -344,6 +344,9 @@ Turns on generation of struct equality to use field-wise comparisons.
@item fixaliasthis
Implements new lookup rules that check the current scope for @code{alias this}
before searching in upper scopes.
@item fiximmutableconv
Disallows unsound immutable conversions that were formerly incorrectly
permitted.
@item in
Implements @code{in} parameters to mean @code{scope const [ref]} and accepts
rvalues.
@ -357,9 +360,8 @@ expressions.
Turns off and disallows all access to shared memory objects.
@item rvaluerefparam
Implements rvalue arguments to @code{ref} parameters.
@item shortenedmethods
Implements use of @code{=>} for methods and top-level functions in addition to
lambdas.
@item systemvariables
Disables access to variables marked @code{@@system} from @code{@@safe} code.
@end table
@item -frelease

View file

@ -396,9 +396,9 @@ fpreview=rvaluerefparam
D RejectNegative
Enable rvalue arguments to ref parameters.
fpreview=shortenedmethods
fpreview=systemvariables
D RejectNegative
Allow use of '=>' for methods and top-level functions in addition to lambdas.
Disable access to variables marked `@system' from @safe code.
frelease
D

View file

@ -0,0 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=18867
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
import core.simd;
ulong2 test18867(ulong s)
{
ulong2 v;
v[0] = s;
return v;
}

View file

@ -3,19 +3,13 @@
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
import core.simd;
enum fail19630a = int4.init[1..2];
enum fail19630b = int4.init.array[1..2];
enum fail19630c = (cast(int[4])int4.init.array)[1..2];
enum fail19630d = (cast(int[4])int4.init)[1..2];
enum fail19630e = int4(0)[1..2];
enum fail19630f = int4(0).array[1..2];
enum fail19630g = (cast(int[4])int4(0).array)[1..2];
enum fail19630h = (cast(int[4])int4(0))[1..2];
enum int4 v19630a = int4.init;
enum slice19630a = v19630a[1..2];
static assert(slice19630a == [0]);
enum int[4] v19630b = int4.init.array;
enum slice19630b = v19630b[1..2];
static assert(slice19630b == [0]);
@ -28,10 +22,6 @@ enum int[4] v19630d = cast(int[4])int4.init;
enum slice19630d = v19630d[1..2];
static assert(slice19630d == [0]);
enum int4 v19630e = int4(0);
enum slice19630e = v19630e[1..2];
static assert(slice19630e == [0]);
enum int[4] v19630f = int4(0).array;
enum slice19630f = v19630f[1..2];
static assert(slice19630f == [0]);

View file

@ -0,0 +1,17 @@
// https://issues.dlang.org/show_bug.cgi?id=19630
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
import core.simd;
enum fail19630a = int4.init[1..2];
// { dg-error "'__vector\\\(int\\\[4\\\]\\\)' cannot be sliced with '\\\[\\\]'" "" { target *-*-* } .-1 }
enum fail19630e = int4(0)[1..2];
// { dg-error "'__vector\\\(int\\\[4\\\]\\\)' cannot be sliced with '\\\[\\\]'" "" { target *-*-* } .-1 }
enum int4 v19630a = int4.init;
enum slice19630a = v19630a[1..2];
// { dg-error "'__vector\\\(int\\\[4\\\]\\\)' cannot be sliced with '\\\[\\\]'" "" { target *-*-* } .-1 }
enum int4 v19630e = int4(0);
enum slice19630e = v19630e[1..2];
// { dg-error "'__vector\\\(int\\\[4\\\]\\\)' cannot be sliced with '\\\[\\\]'" "" { target *-*-* } .-1 }

View file

@ -0,0 +1,15 @@
// https://issues.dlang.org/show_bug.cgi?id=19630
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
import core.simd;
int4 testz19630()
{
return [0,0,0,0];
}
void test19630()
{
assert(testz19630()[] == [0,0,0,0]);
// { dg-error "'__vector\\\(int\\\[4\\\]\\\)' cannot be sliced with '\\\[\\\]'" "" { target *-*-* } .-1 }
}

View file

@ -0,0 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=19788
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
void test19788()
{
enum v = __vector(float[4]).init;
const(float)[] a = v[];
// { dg-error "'__vector\\\(float\\\[4\\\]\\\)' cannot be sliced with '\\\[\\\]'" "" { target *-*-* } .-1 }
}

View file

@ -0,0 +1,9 @@
// https://issues.dlang.org/show_bug.cgi?id=18867
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
import core.simd;
int4 test21469(short a)
{
return cast(int4)(short8(a));
}

View file

@ -0,0 +1,17 @@
// https://bugzilla.gdcproject.org/show_bug.cgi?id=213
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
import core.simd;
struct S213
{
int4 vec;
}
void test213()
{
S213 s, b;
assert(s == b);
}

View file

@ -0,0 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=23077
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
float test23077(float x)
{
short i = *cast(short*)&x;
++i;
return *cast(float*)&i; // this cast is not allowed in @safe code
}

View file

@ -0,0 +1,17 @@
// https://issues.dlang.org/show_bug.cgi?id=23084
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
import core.simd;
__vector(int[4]) test23084a(__vector(int[4]) a)
{
__vector(short[8]) r = cast(short)(a.array[0]);
return cast(__vector(int[4]))r;
}
__vector(int[4]) test23084b(__vector(int[4]) a)
{
__vector(byte[16]) r = cast(byte)(a.array[0]);
return cast(__vector(int[4]))r;
}

View file

@ -0,0 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=23085
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
float test23085(float x)
{
byte i = *cast(byte*)&x;
++i;
return *cast(float*)&i; // this cast is not allowed in @safe code
}

View file

@ -1,88 +0,0 @@
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } }
import core.simd;
// https://issues.dlang.org/show_bug.cgi?id=19627
enum int[4] fail19627 = cast(int[4])int4(0);
// https://issues.dlang.org/show_bug.cgi?id=19628
enum ice19628a = int4.init[0];
enum ice19628b = int4.init.array[0];
enum ice19628c = (cast(int[4])int4.init.array)[0];
enum ice19628d = (cast(int[4])int4.init)[0];
// https://issues.dlang.org/show_bug.cgi?id=19629
enum fail19629a = int4(0)[0];
enum fail19629b = int4(0).array[0];
enum fail19629c = (cast(int[4])int4(0).array)[0];
enum fail19628d = (cast(int[4])int4(0))[0];
// https://issues.dlang.org/show_bug.cgi?id=19630
enum fail19630a = int4.init[1..2];
enum fail19630b = int4.init.array[1..2];
enum fail19630c = (cast(int[4])int4.init.array)[1..2];
enum fail19630d = int4(0)[1..2];
enum fail19630e = int4(0).array[1..2];
enum fail19630f = (cast(int[4])int4(0).array)[1..2];
enum fail19630g = (cast(int[4])int4.init)[1..2];
enum fail19630h = (cast(int[4])int4(0))[1..2];
// Same tests as above, but use access via enum.
enum int4 V1 = int4.init;
enum int[4] V2 = int4.init.array;
enum int[4] V3 = cast(int[4])int4.init;
enum int[4] V4 = cast(int[4])int4.init.array;
enum int4 V5 = int4(0);
enum int[4] V6 = int4(0).array;
enum int[4] V7 = cast(int[4])int4(0);
enum int[4] V8 = cast(int[4])int4(0).array;
// CTFE index tests
enum I1 = V1[0]; static assert(I1 == 0);
enum I2 = V2[0]; static assert(I2 == 0);
enum I3 = V3[0]; static assert(I3 == 0);
enum I4 = V4[0]; static assert(I4 == 0);
enum I5 = V5[0]; static assert(I5 == 0);
enum I6 = V6[0]; static assert(I6 == 0);
enum I7 = V7[0]; static assert(I7 == 0);
enum I8 = V8[0]; static assert(I8 == 0);
// CTFE slice tests
enum S1 = V1[1..2]; static assert(S1 == [0]);
enum S2 = V2[1..2]; static assert(S2 == [0]);
enum S3 = V3[1..2]; static assert(S3 == [0]);
enum S4 = V4[1..2]; static assert(S4 == [0]);
enum S5 = V5[1..2]; static assert(S5 == [0]);
enum S6 = V6[1..2]; static assert(S6 == [0]);
enum S7 = V7[1..2]; static assert(S7 == [0]);
enum S8 = V8[1..2]; static assert(S8 == [0]);
// Same tests as above, but use access via immutable.
//immutable int4 v1 = int4.init; // Cannot cast to immutable at compile time
immutable int[4] v2 = int4.init.array;
immutable int[4] v3 = cast(int[4])int4.init;
immutable int[4] v4 = cast(int[4])int4.init.array;
//immutable int4 v5 = int4(0); // Cannot cast to immutable at compile time
immutable int[4] v6 = int4(0).array;
immutable int[4] v7 = cast(int[4])int4(0);
immutable int[4] v8 = cast(int[4])int4(0).array;
// CTFE index tests
//immutable i1 = v1[0]; static assert(i1 == 0);
immutable i2 = v2[0]; static assert(i2 == 0);
immutable i3 = v3[0]; static assert(i3 == 0);
immutable i4 = v4[0]; static assert(i4 == 0);
//immutable i5 = v5[0]; static assert(i5 == 0);
immutable i6 = v6[0]; static assert(i6 == 0);
immutable i7 = v7[0]; static assert(i7 == 0);
immutable i8 = v8[0]; static assert(i8 == 0);
// CTFE slice tests
//immutable s1 = v1[1..2]; static assert(s1 == [0]);
immutable s2 = v2[1..2]; static assert(s2 == [0]);
immutable s3 = v3[1..2]; static assert(s3 == [0]);
immutable s4 = v4[1..2]; static assert(s4 == [0]);
//immutable s5 = v5[1..2]; static assert(s5 == [0]);
immutable s6 = v6[1..2]; static assert(s6 == [0]);
immutable s7 = v7[1..2]; static assert(s7 == [0]);
immutable s8 = v8[1..2]; static assert(s8 == [0]);

View file

@ -0,0 +1,15 @@
// https://issues.dlang.org/show_bug.cgi?id=19632
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
import core.simd;
void main()
{
int4 v = [1, 2, 3, 4];
int sum = 0;
foreach (ref e; v)
sum += (e *= 2);
assert(v.array[] == [2, 4, 6, 8]);
assert(sum == 20);
}

View file

@ -0,0 +1,22 @@
// https://issues.dlang.org/show_bug.cgi?id=20041
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
import core.simd;
immutable(float4) test20041()
{
float4 raw = 2.0f;
raw.array[0] = 1;
return cast(immutable)raw;
}
void main()
{
static immutable float4 v = test20041();
assert(v.array[0] == 1);
assert(v.array[1] == 2);
assert(v.array[2] == 2);
assert(v.array[3] == 2);
}

View file

@ -0,0 +1,20 @@
// https://issues.dlang.org/show_bug.cgi?id=21673
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
import core.simd;
float4 _mm_move_ss(float4 a, float4 b)
{
a.ptr[0] = b.array[0];
return a;
}
void main()
{
float4 A = [1.0f, 2.0f, 3.0f, 4.0f];
float4 B = [5.0f, 6.0f, 7.0f, 8.0f];
float4 R = _mm_move_ss(A, B);
float[4] correct = [5.0f, 2.0f, 3.0f, 4.0f];
assert(R.array == correct);
}

View file

@ -0,0 +1,36 @@
// https://issues.dlang.org/show_bug.cgi?id=23009
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
import core.simd;
double2 loadUnaligned21676(const(double)* pvec)
{
double2 result;
foreach(i; 0..2)
{
result[i] = pvec[i];
}
return result;
}
double2 _mm_setr_pd(double e1, double e0)
{
double[2] result = [e1, e0];
return loadUnaligned21676(result.ptr);
}
double2 fun(double2 a, double2 b)
{
a[0] = (a[0] < b[0]) ? a[0] : b[0];
return a;
}
void main()
{
double2 A = _mm_setr_pd(1.0, 2.0);
double2 B = _mm_setr_pd(4.0, 1.0);
double2 C = fun(A, B);
assert(C.array[0] == 1.0);
assert(C.array[1] == 2.0);
}

View file

@ -0,0 +1,18 @@
// https://issues.dlang.org/show_bug.cgi?id=22438
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do run }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
struct T22438 { int x; double d; }
T22438 foo22438(int x, double d) { return T22438(x, d); }
struct S22438 { T22438 t; string r; }
void main()
{
S22438 s = S22438(foo22438(10, 3.14), "str");
assert(s.t.x == 10);
assert(s.t.d == 3.14);
assert(s.r == "str");
}

View file

@ -0,0 +1,22 @@
// https://issues.dlang.org/show_bug.cgi?id=23009
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
import core.simd;
double2 _mm_loadl_pd(double2 a, const(double)* mem_addr)
{
a[0] = *mem_addr;
return a;
}
void main()
{
double A = 7.0;
double2 B;
B[0] = 4.0;
B[1] = -5.0;
double2 R = _mm_loadl_pd(B, &A);
double[2] correct = [ 7.0, -5.0 ];
assert(R.array == correct);
}

View file

@ -0,0 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=23077
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do compile }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
float test23077(float x)
{
short i = *cast(short*)&x;
++i;
return *cast(float*)&i; // this cast is not allowed in @safe code
}

View file

@ -0,0 +1,26 @@
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
import gcc.simd;
alias __m128 = __vector(float[4]);
__m128 _mm_setr_ps (float e3, float e2, float e1, float e0) pure @trusted
{
float[4] result = [e3, e2, e1, e0];
return loadUnaligned!(__m128)(cast(__m128*)result.ptr);
}
__m128 _mm_movehdup_ps (__m128 a) pure @trusted
{
a.ptr[0] = a.array[1];
a.ptr[2] = a.array[3];
return a;
}
void main()
{
__m128 A = _mm_movehdup_ps(_mm_setr_ps(1, 2, 3, 4));
float[4] correct = [2.0f, 2, 4, 4 ];
assert(A.array == correct);
}

View file

@ -0,0 +1,46 @@
// { dg-additional-options "-mavx" { target avx_runtime } }
// { dg-do run }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
__gshared int testsroa_x;
template SROA(T1, T2)
{
struct FPoint
{
T1 x;
T2 y;
}
void sroa(FPoint p1, ref FPoint quad)
{
quad = FPoint(p1.x, p1.y);
}
void testit()
{
FPoint p1 = FPoint(1, 2);
FPoint quad;
sroa(p1, quad);
if (quad != p1)
{
assert(0);
}
++testsroa_x;
}
}
void main()
{
SROA!(int, int ).testit();
SROA!(int, float).testit();
SROA!(float, float).testit();
SROA!(float, int ).testit();
SROA!(long, long ).testit();
SROA!(long, double).testit();
SROA!(double, double).testit();
SROA!(double, long ).testit();
}

View file

@ -0,0 +1,21 @@
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
import gcc.simd;
int testprefetch(byte a)
{
prefetch!(false, 0)(&a);
prefetch!(false, 1)(&a);
prefetch!(false, 2)(&a);
prefetch!(false, 3)(&a);
prefetch!(true, 0)(&a);
prefetch!(true, 1)(&a);
prefetch!(true, 2)(&a);
prefetch!(true, 3)(&a);
return 3;
}
void main()
{
int i = testprefetch(1);
assert(i == 3);
}

View file

@ -60,20 +60,6 @@ bool test_nez(long x) { return x != 0; }
bool test_gez(long x) { return x >= 0; }
bool test_gtz(long x) { return x > 0; }
bool test_ltz(float x) { return x < 0; }
bool test_lez(float x) { return x <= 0; }
bool test_eqz(float x) { return x == 0; }
bool test_nez(float x) { return x != 0; }
bool test_gez(float x) { return x >= 0; }
bool test_gtz(float x) { return x > 0; }
bool test_ltz(double x) { return x < 0; }
bool test_lez(double x) { return x <= 0; }
bool test_eqz(double x) { return x == 0; }
bool test_nez(double x) { return x != 0; }
bool test_gez(double x) { return x >= 0; }
bool test_gtz(double x) { return x > 0; }
/* ----------------------------------- */
bool test_lt(ubyte x, ubyte y) { return x < y; }

View file

@ -162,6 +162,18 @@ align(2) struct S12200_2
align(1):
}
// https://issues.dlang.org/show_bug.cgi?id=14694
inout(T)[] overlap(T)(inout(T)[] r1, inout(T)[] r2) @trusted pure nothrow
{
alias U = inout(T);
static U* max(U* a, U* b) nothrow { return a > b ? a : b; }
static U* min(U* a, U* b) nothrow { return a < b ? a : b; }
auto b = max(r1.ptr, r2.ptr);
auto e = min(r1.ptr + r1.length, r2.ptr + r2.length);
return b < e ? b[0 .. e - b] : null;
}
// https://issues.dlang.org/show_bug.cgi?id=16140
void gun()()
{
@ -173,6 +185,13 @@ void gun()()
else break;
}
// https://issues.dlang.org/show_bug.cgi?id=14690
pragma(inline, true)
int fun(int a, int b)
{
return 3;
}
// https://issues.dlang.org/show_bug.cgi?id=16649
void leFoo()()
{

View file

@ -2,3 +2,10 @@ extern int xx;
typedef struct Foo *FooRef;
FooRef make_foo(void);
typedef struct Foo2 *FooRef2;
struct Foo2 {
int x;
};
FooRef2 make_foo2(void);

View file

@ -2,3 +2,11 @@ extern int xx;
typedef struct Foo *FooRef;
void free_foo(FooRef foo);
/****************************/
typedef struct Foo2 *FooRef2;
struct Foo2 {
int x;
};
void free_foo2(FooRef2 foo);

View file

@ -0,0 +1 @@
module lib;

View file

@ -0,0 +1,257 @@
/*
REQUIRED_ARGS: -w -o- -d
More complex examples from the DIP
https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1034.md
*/
alias noreturn = typeof(*null);
static assert (!is(noreturn == void));
void initialize()
{
noreturn a;
noreturn b = noreturn.init;
}
void foo(const noreturn);
void foo(const int);
noreturn bar();
void overloads()
{
noreturn n;
foo(n);
foo(bar());
}
// /*****************************************************************************/
auto inferNoreturn(int i)
{
if (i < 0)
return assert(false);
else if (i == 0)
return assert(false);
else
return assert(false);
}
auto inferReturn(int i)
{
if (i < 0)
return assert(false);
else if (i == 0)
return i;
else
return assert(false);
}
// /*****************************************************************************/
// // https://issues.dlang.org/show_bug.cgi?id=22004
alias fun22004 = _ => {}();
alias gun22004 = _ => assert(0);
auto bun22004(bool b)
{
if (b)
return gun22004(0);
else
return fun22004(0);
}
static assert(is(typeof(bun22004(true)) == void));
// // Reversed order
auto bun22004_reversed(bool b)
{
if (b)
return fun22004(0);
else
return gun22004(0);
}
static assert(is(typeof(bun22004_reversed(true)) == void));
// /*****************************************************************************/
// // Also works fine with non-void types and ref inference
int global;
auto ref forwardOrExit(ref int num)
{
if (num)
return num;
else
return assert(false);
}
static assert( is(typeof(forwardOrExit(global)) == int));
// // Must not infer ref due to the noreturn rvalue
static assert(!is(typeof(&forwardOrExit(global))));
auto ref forwardOrExit2(ref int num)
{
if (num)
return assert(false);
else
return num;
}
static assert( is(typeof(forwardOrExit2(global)) == int));
// // Must not infer ref due to the noreturn rvalue
static assert(!is(typeof(&forwardOrExit2(global))));
/*****************************************************************************/
void inference()
{
auto inf = cast(noreturn) 1;
static assert(is(typeof(inf) == noreturn));
noreturn n;
auto c = cast(const shared noreturn) n;
static assert(is(typeof(c) == const shared noreturn));
static assert(is(typeof(n) == noreturn));
auto c2 = cast(immutable noreturn) n;
static assert(is(typeof(c) == const shared noreturn));
static assert(is(typeof(c2) == immutable noreturn));
static assert(is(typeof(n) == noreturn));
}
/******************************************************************************/
// https://issues.dlang.org/show_bug.cgi?id=21957
// Calculate proper alignment and size for noreturn members
enum longPad = long.alignof - int.sizeof;
struct BasicStruct
{
int firstInt;
noreturn noRet;
long lastLong;
}
static assert(BasicStruct.sizeof == (int.sizeof + longPad + long.sizeof));
static assert(BasicStruct.firstInt.offsetof == 0);
static assert(BasicStruct.noRet.offsetof == 4);
static assert(BasicStruct.lastLong.offsetof == (4 + longPad));
struct AlignedStruct
{
int firstInt;
align(16) noreturn noRet;
long lastLong;
}
static assert(AlignedStruct.sizeof == 32);
static assert(AlignedStruct.firstInt.offsetof == 0);
static assert(AlignedStruct.noRet.offsetof == 16);
static assert(AlignedStruct.lastLong.offsetof == 16);
union BasicUnion
{
int firstInt;
noreturn noRet;
long lastLong;
}
static assert(BasicUnion.sizeof == 8);
static assert(BasicUnion.firstInt.offsetof == 0);
static assert(BasicUnion.noRet.offsetof == 0);
static assert(BasicUnion.lastLong.offsetof == 0);
union AlignedUnion
{
int firstInt;
align(16) noreturn noRet;
long lastLong;
}
static assert(AlignedUnion.sizeof == 16);
static assert(AlignedUnion.firstInt.offsetof == 0);
static assert(AlignedUnion.noRet.offsetof == 0);
static assert(AlignedUnion.lastLong.offsetof == 0);
class BasicClass
{
int firstInt;
noreturn noRet;
long lastLong;
}
enum objectMemberSize = __traits(classInstanceSize, Object);
static assert(__traits(classInstanceSize, BasicClass) == objectMemberSize + (int.sizeof + longPad + long.sizeof));
static assert(BasicClass.firstInt.offsetof == objectMemberSize + 0);
static assert(BasicClass.noRet.offsetof == objectMemberSize + 4);
static assert(BasicClass.lastLong.offsetof == objectMemberSize + (4 + longPad));
class AlignedClass
{
int firstInt;
align(16) noreturn noRet;
long lastLong;
}
enum offset = (objectMemberSize + 4 + 16) & ~15;
static assert(__traits(classInstanceSize, AlignedClass) == offset + 8);
static assert(AlignedClass.firstInt.offsetof == objectMemberSize + 0);
static assert(AlignedClass.noRet.offsetof == offset);
static assert(AlignedClass.lastLong.offsetof == offset);
struct EmptyStruct
{
noreturn noRet;
}
static assert(EmptyStruct.sizeof == 1);
static assert(EmptyStruct.noRet.offsetof == 0);
struct EmptyStruct2
{
noreturn[4] noRet;
}
static assert(EmptyStruct2.sizeof == 1);
static assert(EmptyStruct2.noRet.offsetof == 0);
// https://issues.dlang.org/show_bug.cgi?id=22858
// Shouldn't mess with the alignment of other zero-sized types.
struct S22858
{
int a;
void*[0] arr;
char c;
noreturn[0] arr2;
char c2;
}
static assert (S22858.arr.offsetof % size_t.sizeof == 0);
static assert (S22858.arr2.offsetof == S22858.c.offsetof + 1);
static assert (S22858.arr2.offsetof == S22858.c2.offsetof);
// https://issues.dlang.org/show_bug.cgi?id=23331
auto fun() { return double(new noreturn[](0)[0]); }
auto gun() { return double(assert(0)); }
auto hun() { return int(assert(0)); }
// https://issues.dlang.org/show_bug.cgi?id=23379
void casting_noreturn() { auto b = cast(double)(assert(0)); }

View file

@ -0,0 +1,21 @@
// REQUIRED_ARGS: -preview=dip1000
// Reduced from `std.systime`.
// Tuple expansion can trip up scope checking with errors like:
// Error: scope variable `__tup4` assigned to `found` with longer lifetime
struct Tuple(T...)
{
T t;
alias t this;
}
Tuple!(int*, int) find(return scope int* x) @safe
{
assert(0);
}
void fromISOExtString(scope int* str) @safe
{
int* found = str.find()[0];
}

View file

@ -1,4 +1,4 @@
// REQUIRED_ARGS: -preview=shortenedMethods
// N.B. Shortened methods are no longer under a preview flag
class A {
int _x = 34;
// short syntax works in all contexts

View file

@ -1,2 +1,5 @@
void start() {}
void start()
{
pragma(startaddress, start);
}
pragma(startaddress, start);

View file

@ -8,3 +8,10 @@ void do_foo(){
FooRef f = make_foo(); // use_foo.d(5)
free_foo(f); // use_foo.d(6)
}
// https://issues.dlang.org/show_bug.cgi?id=23357
void do_foo2(){
FooRef2 f = make_foo2();
free_foo2(f);
}

View file

@ -0,0 +1,10 @@
// Issue 22784 - pragma(printf) applies to nested functions
// https://issues.dlang.org/show_bug.cgi?id=22784
import core.stdc.stdarg;
extern(C)
pragma(printf)
void fn(const(char)* fmt, ...)
{
void inner(){}
}

View file

@ -0,0 +1,10 @@
/*
REQUIRED_ARGS: -Icompilable/imports -mv=lib=pkg22952
EXTRA_FILES: imports/pkg22952/package.d
*/
// Issue 22952 - Compiler fails to find package.d modules via -mv map
// https://issues.dlang.org/show_bug.cgi?id=22952
module test22952;
import lib;

View file

@ -0,0 +1,9 @@
// REQUIRED_ARGS: -preview=dip1000
// https://issues.dlang.org/show_bug.cgi?id=23380
// Issue 23380 - [dip1000] class parameter should not be treated as ref qua lifetime
@safe void test(scope Object o0, scope Object o1)
{
o1 = o0;
}

View file

@ -0,0 +1,12 @@
// https://issues.dlang.org/show_bug.cgi?id=23386
// Segfault on enum member UDA inside template
template E()
{
enum E : byte
{
@(1) none,
}
}
alias T = E!();

View file

@ -0,0 +1,29 @@
// https://issues.dlang.org/show_bug.cgi?id=23384
/*
TEST_OUTPUT:
---
fail_compilation/diag23384.d(28): Error: function `diag23384.Derived.fun(B b)` is not callable using argument types `(A)`
fail_compilation/diag23384.d(28): function `diag23384.Derived.fun` hides base class function `diag23384.Base.fun`
fail_compilation/diag23384.d(28): add `alias fun = diag23384.Base.fun` to `diag23384.Derived`'s body to merge the overload sets
---
*/
struct A {}
struct B {}
class Base
{
void fun(A a) {}
}
class Derived : Base
{
void fun(B b) {}
}
void main()
{
Derived d;
d.fun(A());
}

View file

@ -1,22 +0,0 @@
/*
REQUIRED_ARGS: -m64
TEST_OUTPUT:
---
fail_compilation/fail10905.d(20): Error: incompatible types for `(this.x) == (cast(const(__vector(long[2])))cast(__vector(long[2]))1L)`: both operands are of type `const(__vector(long[2]))`
---
*/
struct Foo
{
enum __vector(long[2]) y = 1;
}
struct Bar
{
__vector(long[2]) x;
bool spam() const
{
return x == Foo.y;
}
}

View file

@ -2,7 +2,7 @@
REQUIRED_ARGS: -m64
TEST_OUTPUT:
---
fail_compilation/fail19898a.d(10): Error: incompatible types for `(__key2) < (__limit3)`: both operands are of type `__vector(int[4])`
fail_compilation/fail19898a.d(10): Error: expression `__key2 < __limit3` of type `__vector(int[4])` does not have a boolean value
---
*/
void f (__vector(int[4]) n)

View file

@ -3,7 +3,7 @@ REQUIRED_ARGS: -m64
TEST_OUTPUT:
---
fail_compilation/fail19898b.d(17): Error: cannot implicitly convert expression `m` of type `S` to `__vector(int[4])`
fail_compilation/fail19898b.d(17): Error: incompatible types for `(__key2) != (__limit3)`: both operands are of type `__vector(int[4])`
fail_compilation/fail19898b.d(17): Error: expression `__key2 != __limit3` of type `__vector(int[4])` does not have a boolean value
fail_compilation/fail19898b.d(17): Error: cannot cast expression `__key2` of type `__vector(int[4])` to `S`
---
*/

View file

@ -3,7 +3,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail22366.d(13): Error: scope variable `__aaval2` assigned to non-scope `aa[0]`
fail_compilation/fail22366.d(13): Error: scope variable `x` may not be copied into allocated memory
---
*/

View file

@ -0,0 +1,40 @@
// https://issues.dlang.org/show_bug.cgi?id=23406
/*
TEST_OUTPUT:
---
fail_compilation/fail23406.d(39): Error: cannot implicitly convert expression `0` of type `int` to `alphakey`
---
*/
struct flagenum
{
int i = 1;
alias i this;
auto opBinary(string s)(int j)
{
assert(j == 1);
return typeof(this)(i*2);
}
auto opEquals(int a)
{
return false;
}
}
enum alphakey
{
a = flagenum(),
b,c,d,e,f,g,h,i,
k,l,m,n,o,p,q,r,
s,t,u,v,w,x,y,z
}
alphakey alpha;
void main()
{
alpha = 0;
}

View file

@ -3,7 +3,7 @@ TEST_OUTPUT:
---
fail_compilation/issue21378.d(13): Error: function `issue21378.fn` circular dependency. Functions cannot be interpreted while being compiled
fail_compilation/issue21378.d(12): called from here: `fn()`
fail_compilation/issue21378.d(12): Error: pragma `inline` pragma(`inline`, `true` or `false`) expected, not `fn()`
fail_compilation/issue21378.d(12): Error: pragma(`inline`, `true` or `false`) expected, not `fn()`
---
*/

View file

@ -23,9 +23,9 @@ fail_compilation/lexer1.d(49): Error: unterminated named entity &*;
fail_compilation/lexer1.d(50): Error: unterminated named entity &s1";
fail_compilation/lexer1.d(51): Error: unterminated named entity &2;
fail_compilation/lexer1.d(52): Error: escape octal sequence \400 is larger than \377
fail_compilation/lexer1.d(53): Error: html entity requires 2 code units, use a string instead of a character
---
*/
// https://dlang.dawg.eu/coverage/src/lexer.c.gcov.html
x"01 02 03"w;
0x80000001;
@ -50,3 +50,4 @@ static s5 = "\&*";
static s6 = "\&s1";
static s7 = "\&2;";
static s7 = "\400;";
dchar s8 = '\&acE;';

View file

@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/pragmainline.d(8): Error: pragma `inline` one boolean expression expected for `pragma(inline)`, not 3
fail_compilation/pragmainline.d(8): Error: one boolean expression expected for `pragma(inline)`, not 3
---
*/

View file

@ -3,8 +3,8 @@
/*
TEST_OUTPUT:
---
fail_compilation/pragmas.d(103): Error: boolean expression expected for `pragma(inline)`
fail_compilation/pragmas.d(108): Error: boolean expression expected for `pragma(inline)`
fail_compilation/pragmas.d(103): Error: one boolean expression expected for `pragma(inline)`, not 2
fail_compilation/pragmas.d(108): Error: one boolean expression expected for `pragma(inline)`, not 2
fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)`
---
*/

View file

@ -8,10 +8,10 @@ fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void fu
fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref const(real) x) pure nothrow @nogc @safe)`
fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to non-scope `myGlobal`
fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to non-scope `myGlobal`
fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to global variable `myGlobal`
fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to global variable `myGlobal`
fail_compilation/previewin.d(17): Error: scope parameter `arg` may not be returned
fail_compilation/previewin.d(18): Error: scope variable `arg` assigned to `escape` with longer lifetime
fail_compilation/previewin.d(18): Error: scope variable `arg` assigned to `ref` variable `escape` with longer lifetime
fail_compilation/previewin.d(22): Error: returning `arg` escapes a reference to parameter `arg`
fail_compilation/previewin.d(22): perhaps annotate the parameter with `return`
---

View file

@ -117,6 +117,7 @@ fail_compilation/reserved_version.d(218): Error: version identifier `D_PreCondit
fail_compilation/reserved_version.d(219): Error: version identifier `D_PostConditions` is reserved and cannot be set
fail_compilation/reserved_version.d(220): Error: version identifier `D_ProfileGC` is reserved and cannot be set
fail_compilation/reserved_version.d(221): Error: version identifier `D_Invariants` is reserved and cannot be set
fail_compilation/reserved_version.d(222): Error: version identifier `D_Optimized` is reserved and cannot be set
---
*/
@ -240,6 +241,7 @@ version = D_PreConditions;
version = D_PostConditions;
version = D_ProfileGC;
version = D_Invariants;
version = D_Optimized;
// This should work though
debug = DigitalMars;
@ -351,3 +353,4 @@ debug = AVR;
debug = D_PreConditions;
debug = D_PostConditions;
debug = D_ProfileGC;
debug = D_Optimized;

View file

@ -107,6 +107,7 @@
// REQUIRED_ARGS: -version=D_PostConditions
// REQUIRED_ARGS: -version=D_ProfileGC
// REQUIRED_ARGS: -version=D_Invariants
// REQUIRED_ARGS: -version=D_Optimized
// REQUIRED_ARGS: -debug=DigitalMars
// REQUIRED_ARGS: -debug=GNU
// REQUIRED_ARGS: -debug=LDC
@ -211,6 +212,7 @@
// REQUIRED_ARGS: -debug=D_PostConditions
// REQUIRED_ARGS: -debug=D_ProfileGC
// REQUIRED_ARGS: -debug=D_Invariants
// REQUIRED_ARGS: -debug=D_Optimized
/*
TEST_OUTPUT:
---
@ -321,5 +323,6 @@ Error: version identifier `D_PreConditions` is reserved and cannot be set
Error: version identifier `D_PostConditions` is reserved and cannot be set
Error: version identifier `D_ProfileGC` is reserved and cannot be set
Error: version identifier `D_Invariants` is reserved and cannot be set
Error: version identifier `D_Optimized` is reserved and cannot be set
---
*/

View file

@ -4,9 +4,9 @@ TEST_OUTPUT:
---
fail_compilation/retscope.d(22): Error: scope parameter `p` may not be returned
fail_compilation/retscope.d(32): Error: returning `b ? nested1(& i) : nested2(& j)` escapes a reference to local variable `j`
fail_compilation/retscope.d(45): Error: scope variable `p` assigned to non-scope `q`
fail_compilation/retscope.d(45): Error: scope variable `p` assigned to global variable `q`
fail_compilation/retscope.d(47): Error: address of variable `i` assigned to `q` with longer lifetime
fail_compilation/retscope.d(48): Error: scope variable `a` assigned to non-scope `b`
fail_compilation/retscope.d(48): Error: scope variable `a` assigned to global variable `b`
fail_compilation/retscope.d(49): Error: address of struct temporary returned by `(*fp2)()` assigned to longer lived variable `q`
---
*/
@ -662,7 +662,7 @@ int test21()
/*********************************************
TEST_OUTPUT:
---
fail_compilation/retscope.d(1907): Error: scope variable `x` assigned to `this` with longer lifetime
fail_compilation/retscope.d(1907): Error: scope variable `x` assigned to `ref` variable `this` with longer lifetime
fail_compilation/retscope.d(1913): Error: scope variable `x` may not be returned
---
*/

View file

@ -2,7 +2,7 @@
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
fail_compilation/retscope2.d(102): Error: scope variable `s` assigned to `p` with longer lifetime
fail_compilation/retscope2.d(102): Error: scope variable `s` assigned to `ref` variable `p` with longer lifetime
fail_compilation/retscope2.d(107): Error: address of variable `s` assigned to `p` with longer lifetime
---
*/

Some files were not shown because too many files have changed in this diff Show more