-423f19b41089f627808bf16ff21c60c0791712ba
+cbba5f41a32cfed7f22a213d537f8e2dee0b92f7
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
return cast(char)data[i];
}
+ alias opDollar = length;
+
/***********************************
* Extract the data as a slice and take ownership of it.
*
s = unsignedToTempString(29, buf[], 16);
assert(s == "1d");
}
+
+unittest
+{
+ OutBuffer buf;
+ buf.writeUTF8(0x0000_0011);
+ buf.writeUTF8(0x0000_0111);
+ buf.writeUTF8(0x0000_1111);
+ buf.writeUTF8(0x0001_1111);
+ buf.writeUTF8(0x0010_0000);
+ assert(buf[] == "\x11\U00000111\U00001111\U00011111\U00100000");
+
+ buf.reset();
+ buf.writeUTF16(0x0000_0011);
+ buf.writeUTF16(0x0010_FFFF);
+ assert(buf[] == cast(string) "\u0011\U0010FFFF"w);
+}
+
+unittest
+{
+ OutBuffer buf;
+ buf.doindent = true;
+
+ const(char)[] s = "abc";
+ buf.writestring(s);
+ buf.level += 1;
+ buf.indent();
+ buf.writestring("abs");
+
+ assert(buf[] == "abc\tabs");
+
+ buf.setsize(4);
+ assert(buf.length == 4);
+}
/* Also return EXP.cantExpression if this fails
*/
-UnionExp Index(Type type, Expression e1, Expression e2)
+UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
{
UnionExp ue = void;
Loc loc = e1.loc;
TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
uinteger_t length = tsa.dim.toInteger();
uinteger_t i = e2.toInteger();
- if (i >= length)
+ if (i >= length && (e1.op == EXP.arrayLiteral || !indexIsInBounds))
{
+ // C code only checks bounds if an ArrayLiteralExp
e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
emplaceExp!(ErrorExp)(&ue);
}
import dmd.lexer;
import dmd.parse;
import dmd.errors;
+import dmd.root.array;
import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.root.rmem;
bool addFuncName; /// add declaration of __func__ to function symbol table
bool importBuiltins; /// seen use of C compiler builtins, so import __builtins;
+ private
+ {
+ structalign_t packalign; // current state of #pragma pack alignment
+
+ // #pragma pack stack
+ Array!Identifier* records; // identifers (or null)
+ Array!structalign_t* packs; // parallel alignment values
+ }
+
+ /** C allows declaring a function with a typedef:
+ * typedef int (myfunc)(); myfunc fun;
+ * but we need to distinguish `fun` being a function as opposed to a variable in the
+ * parse pass. This is accomplished by having a simple symbol table of typedefs
+ * where we know, by syntax, if they are function types or non-function types.
+ * funcTypeIds is the symbol table, of the identifiers of typedefs of function types.
+ */
+ AST.Identifiers funcTypeIds; /// Identifiers in this are typedefs of function types
+
extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
const ref TARGET target)
{
mod = _module;
linkage = LINK.c;
Ccompile = true;
+ this.packalign.setDefault();
// Configure sizes for C `long`, `long double`, `wchar_t`, ...
this.boolsize = target.boolsize;
//printf("cparseStatement()\n");
+ const funcTypeIdsLengthSave = funcTypeIds.length;
auto symbolsSave = symbols;
if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)))
symbols = new AST.Dsymbols();
if (pEndloc)
*pEndloc = prevloc;
symbols = symbolsSave;
+ funcTypeIds.setDim(funcTypeIdsLengthSave);
return s;
}
return;
}
+ const funcTypeIdsLengthSave = funcTypeIds.length;
auto symbolsSave = symbols;
Specifier specifier;
specifier.packalign = this.packalign;
t.value == TOK.leftCurly) // start of compound-statement
{
auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
+ funcTypeIds.setDim(funcTypeIdsLengthSave);
symbols = symbolsSave;
symbols.push(s);
return;
}
AST.Dsymbol s = null;
+ funcTypeIds.setDim(funcTypeIdsLengthSave);
symbols = symbolsSave;
if (!symbols)
symbols = new AST.Dsymbols; // lazilly create it
}
}
}
+ else if (isFunctionTypedef(dt))
+ {
+ funcTypeIds.push(id); // remember function typedefs
+ }
if (isalias)
s = new AST.AliasDeclaration(token.loc, id, dt);
}
}
// declare the symbol
assert(id);
- if (dt.isTypeFunction())
+
+ if (isFunctionTypedef(dt))
{
if (hasInitializer)
error("no initializer for function declaration");
return s;
}
+ /********************************
+ * Determines if type t is a function type.
+ * Make this work without needing semantic analysis.
+ * Params:
+ * t = type to test
+ * Returns:
+ * true if it represents a function
+ */
+ bool isFunctionTypedef(AST.Type t)
+ {
+ //printf("isFunctionTypedef() %s\n", t.toChars());
+ if (t.isTypeFunction())
+ return true;
+ if (auto tid = t.isTypeIdentifier())
+ {
+ /* Scan array of typedef identifiers that are an alias for
+ * a function type
+ */
+ foreach (ftid; funcTypeIds[])
+ {
+ if (tid.ident == ftid)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ //}
+
+ /******************************************************************************/
+ /********************************* Directive Parser ***************************/
+ //{
+
+ override bool parseSpecialTokenSequence()
+ {
+ Token n;
+ scan(&n);
+ if (n.value == TOK.int32Literal)
+ {
+ poundLine(n, true);
+ return true;
+ }
+ if (n.value == TOK.identifier)
+ {
+ if (n.ident == Id.line)
+ {
+ poundLine(n, false);
+ return true;
+ }
+ else if (n.ident == Id.__pragma)
+ {
+ pragmaDirective(scanloc);
+ return true;
+ }
+ }
+ error("C preprocessor directive `#%s` is not supported", n.toChars());
+ return false;
+ }
+
+ /*********************************************
+ * C11 6.10.6 Pragma directive
+ * # pragma pp-tokens(opt) new-line
+ * The C preprocessor sometimes leaves pragma directives in
+ * the preprocessed output. Ignore them.
+ * Upon return, p is at start of next line.
+ */
+ private void pragmaDirective(const ref Loc loc)
+ {
+ Token n;
+ scan(&n);
+ if (n.value == TOK.identifier && n.ident == Id.pack)
+ return pragmaPack(loc);
+ skipToNextLine();
+ }
+
+ /*********
+ * # pragma pack
+ * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
+ * https://docs.microsoft.com/en-us/cpp/preprocessor/pack
+ * Scanner is on the `pack`
+ * Params:
+ * startloc = location to use for error messages
+ */
+ private void pragmaPack(const ref Loc startloc)
+ {
+ const loc = startloc;
+ Token n;
+ scan(&n);
+ if (n.value != TOK.leftParenthesis)
+ {
+ error(loc, "left parenthesis expected to follow `#pragma pack`");
+ skipToNextLine();
+ return;
+ }
+
+ void closingParen()
+ {
+ if (n.value != TOK.rightParenthesis)
+ {
+ error(loc, "right parenthesis expected to close `#pragma pack(`");
+ }
+ skipToNextLine();
+ }
+
+ void setPackAlign(ref const Token t)
+ {
+ const n = t.unsvalue;
+ if (n < 1 || n & (n - 1) || ushort.max < n)
+ error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
+ packalign.set(cast(uint)n);
+ packalign.setPack(true);
+ }
+
+ scan(&n);
+
+ if (!records)
+ {
+ records = new Array!Identifier;
+ packs = new Array!structalign_t;
+ }
+
+ /* # pragma pack ( show )
+ */
+ if (n.value == TOK.identifier && n.ident == Id.show)
+ {
+ if (packalign.isDefault())
+ warning(startloc, "current pack attribute is default");
+ else
+ warning(startloc, "current pack attribute is %d", packalign.get());
+ scan(&n);
+ return closingParen();
+ }
+ /* # pragma pack ( push )
+ * # pragma pack ( push , identifier )
+ * # pragma pack ( push , integer )
+ * # pragma pack ( push , identifier , integer )
+ */
+ if (n.value == TOK.identifier && n.ident == Id.push)
+ {
+ scan(&n);
+ Identifier record = null;
+ if (n.value == TOK.comma)
+ {
+ scan(&n);
+ if (n.value == TOK.identifier)
+ {
+ record = n.ident;
+ scan(&n);
+ if (n.value == TOK.comma)
+ {
+ scan(&n);
+ if (n.value == TOK.int32Literal)
+ {
+ setPackAlign(n);
+ scan(&n);
+ }
+ else
+ error(loc, "alignment value expected, not `%s`", n.toChars());
+ }
+ }
+ else if (n.value == TOK.int32Literal)
+ {
+ setPackAlign(n);
+ scan(&n);
+ }
+ else
+ error(loc, "alignment value expected, not `%s`", n.toChars());
+ }
+ this.records.push(record);
+ this.packs.push(packalign);
+ return closingParen();
+ }
+ /* # pragma pack ( pop )
+ * # pragma pack ( pop PopList )
+ * PopList :
+ * , IdentifierOrInteger
+ * , IdentifierOrInteger PopList
+ * IdentifierOrInteger:
+ * identifier
+ * integer
+ */
+ if (n.value == TOK.identifier && n.ident == Id.pop)
+ {
+ scan(&n);
+ while (n.value == TOK.comma)
+ {
+ scan(&n);
+ if (n.value == TOK.identifier)
+ {
+ for (size_t len = this.records.length; len; --len)
+ {
+ if ((*this.records)[len - 1] == n.ident)
+ {
+ packalign = (*this.packs)[len - 1];
+ this.records.setDim(len - 1);
+ this.packs.setDim(len - 1);
+ break;
+ }
+ }
+ scan(&n);
+ }
+ else if (n.value == TOK.int32Literal)
+ {
+ setPackAlign(n);
+ this.records.push(null);
+ this.packs.push(packalign);
+ scan(&n);
+ }
+ }
+ return closingParen();
+ }
+ /* # pragma pack ( integer )
+ */
+ if (n.value == TOK.int32Literal)
+ {
+ setPackAlign(n);
+ scan(&n);
+ return closingParen();
+ }
+ /* # pragma pack ( )
+ */
+ if (n.value == TOK.rightParenthesis)
+ {
+ packalign.setDefault();
+ return closingParen();
+ }
+
+ error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
+ skipToNextLine();
+ }
+
//}
}
{
printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
}
- __gshared const(char)* msg = "cannot form delegate due to covariant return type";
+ static immutable msg = "cannot form delegate due to covariant return type";
Type tb = t.toBasetype();
Type typeb = e.type.toBasetype();
int offset;
e.func.tookAddressOf++;
if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset)
- e.error("%s", msg);
+ e.error("%s", msg.ptr);
auto result = e.copy();
result.type = t;
return result;
{
int offset;
if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset)
- e.error("%s", msg);
+ e.error("%s", msg.ptr);
if (f != e.func) // if address not already marked as taken
f.tookAddressOf++;
auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2);
return result;
}
if (e.func.tintro)
- e.error("%s", msg);
+ e.error("%s", msg.ptr);
}
}
super(loc, id);
- __gshared const(char)* msg = "only object.d can define this reserved class name";
+ static immutable msg = "only object.d can define this reserved class name";
if (baseclasses)
{
if (id == Id.TypeInfo)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.dtypeinfo = this;
}
if (id == Id.TypeInfo_Class)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfoclass = this;
}
if (id == Id.TypeInfo_Interface)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfointerface = this;
}
if (id == Id.TypeInfo_Struct)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfostruct = this;
}
if (id == Id.TypeInfo_Pointer)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfopointer = this;
}
if (id == Id.TypeInfo_Array)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfoarray = this;
}
if (id == Id.TypeInfo_StaticArray)
if (id == Id.TypeInfo_AssociativeArray)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfoassociativearray = this;
}
if (id == Id.TypeInfo_Enum)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfoenum = this;
}
if (id == Id.TypeInfo_Function)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfofunction = this;
}
if (id == Id.TypeInfo_Delegate)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfodelegate = this;
}
if (id == Id.TypeInfo_Tuple)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfotypelist = this;
}
if (id == Id.TypeInfo_Const)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfoconst = this;
}
if (id == Id.TypeInfo_Invariant)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfoinvariant = this;
}
if (id == Id.TypeInfo_Shared)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfoshared = this;
}
if (id == Id.TypeInfo_Wild)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfowild = this;
}
if (id == Id.TypeInfo_Vector)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
Type.typeinfovector = this;
}
}
if (id == Id.Object)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
object = this;
}
if (id == Id.Throwable)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
throwable = this;
}
if (id == Id.Exception)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
exception = this;
}
if (id == Id.Error)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
errorException = this;
}
if (id == Id.cpp_type_info_ptr)
{
if (!inObject)
- error("%s", msg);
+ error("%s", msg.ptr);
cpp_type_info_ptr = this;
}
import dmd.expression;
import dmd.func;
import dmd.globals;
+import dmd.gluelayer;
import dmd.id;
import dmd.identifier;
import dmd.init;
enum wasRead = 1; // set if AliasDeclaration was read
enum ignoreRead = 2; // ignore any reads of AliasDeclaration
+ Symbol* isym; // import version of csym
+
// overridden symbol with pragma(mangle, "...")
const(char)[] mangleOverride;
}
/***********************************************************
+ * https://dlang.org/spec/declaration.html#AliasDeclaration
*/
extern (C++) final class AliasDeclaration : Declaration
{
- Dsymbol aliassym;
+ Dsymbol aliassym; // alias ident = aliassym;
+
Dsymbol overnext; // next in overload list
Dsymbol _import; // !=null if unresolved internal alias for selective import
LINK linkage;
short inuse; // used to detect cycles
uint8_t adFlags;
+ Symbol* isym; // import version of csym
DString mangleOverride; // overridden symbol with pragma(mangle, "...")
const char *kind() const;
//printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
- if (global.params.emitMakeDeps)
- {
- global.params.makeDeps.push(srcfile.toChars());
- }
+
+ bool success;
if (auto readResult = FileManager.fileManager.lookup(srcfile))
{
srcBuffer = readResult;
- return true;
+ success = true;
}
-
- auto readResult = File.read(srcfile.toChars());
- if (loadSourceBuffer(loc, readResult))
+ else
{
- FileManager.fileManager.add(srcfile, srcBuffer);
- return true;
+ auto readResult = File.read(srcfile.toChars());
+ if (loadSourceBuffer(loc, readResult))
+ {
+ FileManager.fileManager.add(srcfile, srcBuffer);
+ success = true;
+ }
}
- return false;
+ if (success && global.params.emitMakeDeps)
+ {
+ global.params.makeDeps.push(srcfile.toChars());
+ }
+ return success;
}
/// syntactic parse
/// C++ namespace this symbol belongs to
CPPNamespaceDeclaration cppnamespace;
Symbol* csym; // symbol for code generator
- Symbol* isym; // import version of csym
- const(char)* comment; // documentation comment for this Dsymbol
const Loc loc; // where defined
Scope* _scope; // !=null means context to use for semantic()
const(char)* prettystring; // cached value of toPrettyChars()
DeprecatedDeclaration depdecl; // customized deprecation message
UserAttributeDeclaration userAttribDecl; // user defined attributes
- // !=null means there's a ddoc unittest associated with this symbol
- // (only use this with ddoc)
- UnitTestDeclaration ddocUnittest;
-
final extern (D) this()
{
//printf("Dsymbol::Dsymbol(%p)\n", this);
Dsymbol s2 = sds.symtabLookup(this,ident);
// If using C tag/prototype/forward declaration rules
- if (sc.flags & SCOPE.Cfile)
+ if (sc.flags & SCOPE.Cfile && !this.isImport())
{
if (handleTagSymbols(*sc, this, s2, sds))
return;
*/
void addComment(const(char)* comment)
{
- //if (comment)
- // printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
- if (!this.comment)
- this.comment = comment;
- else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0)
+ if (!comment || !*comment)
+ return;
+
+ //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
+ void* h = cast(void*)this; // just the pointer is the key
+ auto p = h in commentHashTable;
+ if (!p)
+ {
+ commentHashTable[h] = comment;
+ return;
+ }
+ if (strcmp(*p, comment) != 0)
{
// Concatenate the two
- this.comment = Lexer.combineComments(this.comment.toDString(), comment.toDString(), true);
+ *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
}
}
+ /// get documentation comment for this Dsymbol
+ final const(char)* comment()
+ {
+ //printf("getcomment: %p '%s'\n", this, this.toChars());
+ if (auto p = cast(void*)this in commentHashTable)
+ {
+ //printf("comment: '%s'\n", *p);
+ return *p;
+ }
+ return null;
+ }
+
+ /* Shell around addComment() to avoid disruption for the moment */
+ final void comment(const(char)* comment) { addComment(comment); }
+
+ private extern (D) __gshared const(char)*[void*] commentHashTable;
+
+
+ /**********************************
+ * Get ddoc unittest associated with this symbol.
+ * (only use this with ddoc)
+ * Returns: ddoc unittest, null if none
+ */
+ final UnitTestDeclaration ddocUnittest()
+ {
+ if (auto p = cast(void*)this in ddocUnittestHashTable)
+ return *p;
+ return null;
+ }
+
+ /**********************************
+ * Set ddoc unittest associated with this symbol.
+ */
+ final void ddocUnittest(UnitTestDeclaration utd)
+ {
+ ddocUnittestHashTable[cast(void*)this] = utd;
+ }
+
+ private extern (D) __gshared UnitTestDeclaration[void*] ddocUnittestHashTable;
+
+
/****************************************
* Returns true if this symbol is defined in a non-root module without instantiation.
*/
return false;
}
+ /**
+ * Deinitializes the global state of the compiler.
+ *
+ * This can be used to restore the state set by `_init` to its original
+ * state.
+ */
+ static void deinitialize()
+ {
+ commentHashTable = commentHashTable.init;
+ ddocUnittestHashTable = ddocUnittestHashTable.init;
+ }
+
/************
*/
override void accept(Visitor v)
/// C++ namespace this symbol belongs to
CPPNamespaceDeclaration *namespace_;
Symbol *csym; // symbol for code generator
- Symbol *isym; // import version of csym
- const utf8_t *comment; // documentation comment for this Dsymbol
Loc loc; // where defined
Scope *_scope; // !=NULL means context to use for semantic()
const utf8_t *prettystring;
unsigned short localNum; // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
DeprecatedDeclaration *depdecl; // customized deprecation message
UserAttributeDeclaration *userAttribDecl; // user defined attributes
- UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc)
static Dsymbol *create(Identifier *);
const char *toChars() const;
virtual void checkCtorConstInit() { }
virtual void addComment(const utf8_t *comment);
+ const utf8_t *comment(); // current value of comment
+
+ UnitTestDeclaration *ddocUnittest();
+ void ddocUnittest(UnitTestDeclaration *);
bool inNonRoot();
Module.dprogress++;
+ // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+ // Deprecated in 2.100
+ // Make an error in 2.110
+ if (sc.stc & STC.scope_)
+ deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
+
Scope* sce;
if (ed.isAnonymous())
sce = sc;
return null;
}
+ if (sc.flags & SCOPE.Cfile)
+ {
+ /* C11 allows a function to be declared with a typedef, D does not.
+ */
+ if (auto ti = funcdecl.type.isTypeIdentifier())
+ {
+ auto tj = ti.typeSemantic(funcdecl.loc, sc);
+ if (auto tjf = tj.isTypeFunction())
+ {
+ /* Copy the type instead of just pointing to it,
+ * as we don't merge function types
+ */
+ auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage);
+ funcdecl.type = tjf2;
+ funcdecl.originalType = tjf2;
+ }
+ }
+ }
+
if (!getFunctionType(funcdecl))
return;
default:
{
+ if (vi >= cd.vtbl.length)
+ {
+ /* the derived class cd doesn't have its vtbl[] allocated yet.
+ * https://issues.dlang.org/show_bug.cgi?id=21008
+ */
+ funcdecl.error("circular reference to class `%s`", cd.toChars());
+ funcdecl.errors = true;
+ return;
+ }
FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration();
FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration();
// This function is covariant with fdv
sd.deferred.semantic2(sc);
sd.deferred.semantic3(sc);
}
+
+ // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+ // Deprecated in 2.100
+ // Make an error in 2.110
+ if (sd.storage_class & STC.scope_)
+ deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
}
void interfaceSemantic(ClassDeclaration cd)
}
//printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
- // @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
- // Deprecated in 2.087
- // Make an error in 2.091
+ // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+ // Deprecated in 2.100
+ // Make an error in 2.110
// Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036
- if (0 && // deprecation disabled for now to accommodate existing extensive use
- cldec.storage_class & STC.scope_)
+ if (cldec.storage_class & STC.scope_)
deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
}
/* Used when a proposed instance is used to see if there's
* an existing instance.
*/
- static if (__VERSION__ >= 2099)
- res = (cast()ti).equalsx(cast()s.ti);
- else // https://issues.dlang.org/show_bug.cgi?id=22717
+ static if (__VERSION__ < 2099) // https://issues.dlang.org/show_bug.cgi?id=22717
res = (cast()s.ti).equalsx(cast()ti);
+ else
+ res = (cast()ti).equalsx(cast()s.ti);
}
debug (FindExistingInstance) ++(res ? nHits : nCollisions);
`);
}
+ // prevent trailing newlines
+ version (Windows)
+ while (buf.length >= 4 && buf[$-4..$] == "\r\n\r\n")
+ buf.remove(buf.length - 2, 2);
+ else
+ while (buf.length >= 2 && buf[$-2..$] == "\n\n")
+ buf.remove(buf.length - 1, 1);
+
+
if (global.params.cxxhdrname is null)
{
// Write to stdout; assume it succeeds
{
Expression arg = (*ce.arguments)[i];
if (!arg.type.hasPointers())
- return false;
+ continue;
//printf("\targ[%d]: %s\n", i, arg.toChars());
return false;
if (va == fd.vthis) // `this` of a non-static member function is considered to be the first parameter
return true;
- if (fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter
+ if (!fd.vthis && fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter
return true;
}
return false;
*/
!(p.parent == sc.func))
{
- // Only look for errors if in module listed on command line
if (global.params.useDIP1000 == FeatureState.enabled // https://issues.dlang.org/show_bug.cgi?id=17029
&& sc.func.setUnsafe()) // https://issues.dlang.org/show_bug.cgi?id=20868
{
continue;
// https://dlang.org/spec/function.html#return-ref-parameters
- // Only look for errors if in module listed on command line
if (p == sc.func)
{
//printf("escaping reference to local ref variable %s\n", v.toChars());
!(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0)
)
{
- // Only look for errors if in module listed on command line
// https://issues.dlang.org/show_bug.cgi?id=17029
if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
{
{
if (log)
{
- printf("byref `%s`\n", v.toChars());
- if (v.storage_class & STC.return_) printf(" return");
- if (v.storage_class & STC.ref_) printf(" ref");
- if (v.storage_class & STC.scope_) printf(" scope");
- printf("\n");
+ printf("byref `%s` %s\n", v.toChars(), toChars(buildScopeRef(v.storage_class)));
}
// 'featureState' tells us whether to emit an error or a deprecation,
{
Parameter p = tf.parameterList[i - j];
const stc = tf.parameterStorageClass(null, p);
- if ((stc & (STC.scope_)) && (stc & STC.return_))
+ ScopeRef psr = buildScopeRef(stc);
+ if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
arg.accept(this);
- else if ((stc & (STC.ref_)) && (stc & STC.return_))
+ else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
{
if (tf.isref)
{
{
Parameter p = tf.parameterList[i - j];
const stc = tf.parameterStorageClass(null, p);
- if ((stc & (STC.out_ | STC.ref_)) && (stc & STC.return_))
+ ScopeRef psr = buildScopeRef(stc);
+ if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
arg.accept(this);
- else if ((stc & STC.scope_) && (stc & STC.return_))
+ else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
{
if (auto de = arg.isDelegateExp())
{
import dmd.visitor;
enum LOGSEMANTIC = false;
+
void emplaceExp(T : Expression, Args...)(void* p, Args args)
{
- scope tmp = new T(args);
- memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T));
+ static if (__VERSION__ < 2099)
+ const init = typeid(T).initializer;
+ else
+ const init = __traits(initSymbol, T);
+ p[0 .. __traits(classInstanceSize, T)] = init[];
+ (cast(T)p).__ctor(args);
}
void emplaceExp(T : UnionExp)(T* p, Expression e)
//printf("IndexExp::IndexExp('%s')\n", toChars());
}
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds)
+ {
+ super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
+ this.indexIsInBounds = indexIsInBounds;
+ //printf("IndexExp::IndexExp('%s')\n", toChars());
+ }
+
override IndexExp syntaxCopy()
{
auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
// The mangling change only works for D mangling
}
+ if (!(sc.flags & SCOPE.Cfile))
{
/* https://issues.dlang.org/show_bug.cgi?id=21272
* If we are in a foreach body we need to extract the
return setError();
}
}
- else if (exp.e1.op == EXP.call)
+ else if (auto ce = exp.e1.isCallExp())
{
- CallExp ce = cast(CallExp)exp.e1;
- if (ce.e1.type.ty == Tfunction)
- {
- TypeFunction tf = cast(TypeFunction)ce.e1.type;
- if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)
- && tf.next.hasPointers() && sc.func.setUnsafe())
- {
- exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`",
- ce.e1.toChars(), sc.func.toChars());
- }
- }
+ if (!checkAddressCall(sc, ce, "take address of"))
+ return setError();
}
else if (exp.e1.op == EXP.index)
{
return setError();
Type t1b = exp.e1.type.toBasetype();
- if (t1b.ty == Tpointer)
+ if (auto tp = t1b.isTypePointer())
{
if (t1b.isPtrToFunction())
{
}
if (!exp.lwr || !exp.upr)
{
- exp.error("need upper and lower bound to slice pointer");
+ exp.error("upper and lower bounds are needed to slice a pointer");
+ if (auto ad = isAggregate(tp.next.toBasetype()))
+ {
+ auto s = search_function(ad, Id.index);
+ if (!s) s = search_function(ad, Id.slice);
+ if (s)
+ {
+ auto fd = s.isFuncDeclaration();
+ if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
+ {
+ exp.errorSupplemental(
+ "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
+ exp.e1.toChars(),
+ s.ident.toChars(),
+ exp.e1.toChars()
+ );
+ }
+
+ }
+ }
+
return setError();
}
if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
if (v && !checkAddressVar(sc, exp.e1, v))
return setError();
}
+ // https://issues.dlang.org/show_bug.cgi?id=22539
+ if (auto ce = exp.e1.isCallExp())
+ {
+ if (!checkAddressCall(sc, ce, "slice static array of"))
+ return setError();
+ }
}
}
else if (t1b.ty == Ttuple)
if (length)
{
auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
- exp.indexIsInBounds = bounds.contains(getIntRange(exp.e2));
+ // OR it in, because it might already be set for C array indexing
+ exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
}
}
}
return true;
}
+/****************************************************
+ * Determine if the address of a `ref return` value of
+ * a function call with type `tf` can be taken safely.
+ *
+ * This is currently stricter than necessary: it can be safe to take the
+ * address of a `ref` with pointer type when the pointer isn't `scope`, but
+ * that involves inspecting the function arguments and parameter types, which
+ * is left as a future enhancement.
+ *
+ * Params:
+ * sc = context
+ * ce = function call in question
+ * action = for the error message, how the pointer is taken, e.g. "slice static array of"
+ * Returns:
+ * `true` if ok, `false` for error
+ */
+private bool checkAddressCall(Scope* sc, CallExp ce, const(char)* action)
+{
+ if (auto tf = ce.e1.type.isTypeFunction())
+ {
+ if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)
+ && tf.next.hasPointers() && sc.func.setUnsafe())
+ {
+ ce.error("cannot %s `ref return` of `%s()` in `@safe` function `%s`",
+ action, ce.e1.toChars(), sc.func.toChars());
+ ce.errorSupplemental("return type `%s` has pointers that may be `scope`", tf.next.toChars());
+ return false;
+ }
+ }
+ return true;
+}
+
/*******************************
* Checks the attributes of a function.
* Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
if (t1.isTypeDArray() || t1.isTypeSArray())
{
e2 = e2.expressionSemantic(sc).arrayFuncConv(sc);
- return new IndexExp(ae.loc, e1, e2).expressionSemantic(sc);
+ // C doesn't do array bounds checking, so `true` turns it off
+ return new IndexExp(ae.loc, e1, e2, true).expressionSemantic(sc);
}
e1 = e1.arrayFuncConv(sc); // e1 might still be a function call
auto t2 = e2.type.toBasetype();
if (t2.isTypeDArray() || t2.isTypeSArray())
{
- return new IndexExp(ae.loc, e2, e1).expressionSemantic(sc); // swap operands
+ return new IndexExp(ae.loc, e2, e1, true).expressionSemantic(sc); // swap operands
}
e2 = e2.arrayFuncConv(sc);
ubyte long_doublesize; /// size of C long double, 8 or D real.sizeof
ubyte wchar_tsize; /// size of C wchar_t, 2 or 4
- structalign_t packalign; /// current state of #pragma pack alignment (ImportC)
-
private
{
const(char)* base; // pointer to start of buffer
int lastDocLine; // last line of previous doc comment
Token* tokenFreelist;
-
- // ImportC #pragma pack stack
- Array!Identifier* records; // identifers (or null)
- Array!structalign_t* packs; // parallel alignment values
}
nothrow:
this.commentToken = commentToken;
this.inTokenStringConstant = 0;
this.lastDocLine = 0;
- this.packalign.setDefault();
//initKeywords();
/* If first line starts with '#!', ignore the line
*/
goto case_ident;
case 'r':
- if (p[1] != '"')
+ if (Ccompile || p[1] != '"')
goto case_ident;
p++;
goto case '`';
case '`':
+ if (Ccompile)
+ goto default;
wysiwygStringConstant(t);
return;
- case 'x':
- if (p[1] != '"')
- goto case_ident;
- p++;
- auto start = p;
- OutBuffer hexString;
- t.value = hexStringConstant(t);
- hexString.write(start[0 .. p - start]);
- error("Built-in hex string literals are obsolete, use `std.conv.hexString!%s` instead.", hexString.extractChars());
- return;
case 'q':
+ if (Ccompile)
+ goto case_ident;
if (p[1] == '"')
{
p++;
//case 'u':
case 'v':
case 'w':
- /*case 'x':*/
+ case 'x':
case 'y':
case 'z':
case 'A':
endOfLine();
continue;
case '+':
+ if (!Ccompile)
{
int nest;
startLoc = loc();
}
continue;
}
+ break;
default:
break;
}
case '#':
{
p++;
- Token n;
- scan(&n);
- if (Ccompile && n.value == TOK.int32Literal)
- {
- poundLine(n, true);
+ if (parseSpecialTokenSequence())
continue;
- }
- if (n.value == TOK.identifier)
- {
- if (n.ident == Id.line)
- {
- poundLine(n, false);
- continue;
- }
- else if (n.ident == Id.__pragma && Ccompile)
- {
- pragmaDirective(scanloc);
- continue;
- }
- else
- {
- const locx = loc();
- warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars());
- }
- }
- else if (n.value == TOK.if_)
- {
- error("C preprocessor directive `#if` is not supported, use `version` or `static if`");
- }
t.value = TOK.pound;
return;
}
}
}
- /**************************************
- * Lex hex strings:
- * x"0A ae 34FE BD"
- */
- private TOK hexStringConstant(Token* t)
- {
- Loc start = loc();
- uint n = 0;
- uint v = ~0; // dead assignment, needed to suppress warning
- p++;
- stringbuffer.setsize(0);
- while (1)
- {
- dchar c = *p++;
- switch (c)
- {
- case ' ':
- case '\t':
- case '\v':
- case '\f':
- continue; // skip white space
- case '\r':
- if (*p == '\n')
- continue; // ignore '\r' if followed by '\n'
- // Treat isolated '\r' as if it were a '\n'
- goto case '\n';
- case '\n':
- endOfLine();
- continue;
- case 0:
- case 0x1A:
- error("unterminated string constant starting at %s", start.toChars());
- t.setString();
- // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token).
- p--;
- return TOK.hexadecimalString;
- case '"':
- if (n & 1)
- {
- error("odd number (%d) of hex characters in hex string", n);
- stringbuffer.writeByte(v);
- }
- t.setString(stringbuffer);
- stringPostfix(t);
- return TOK.hexadecimalString;
- default:
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'a' && c <= 'f')
- c -= 'a' - 10;
- else if (c >= 'A' && c <= 'F')
- c -= 'A' - 10;
- else if (c & 0x80)
- {
- p--;
- const u = decodeUTF();
- p++;
- if (u == PS || u == LS)
- endOfLine();
- else
- error("non-hex character \\u%04x in hex string", u);
- }
- else
- error("non-hex character '%c' in hex string", c);
- if (n & 1)
- {
- v = (v << 4) | c;
- stringbuffer.writeByte(v);
- }
- else
- v = c;
- n++;
- break;
- }
- }
- assert(0); // see bug 15731
- }
-
/**
Lex a delimited string. Some examples of delimited strings are:
---
va_end(args);
}
+ /***************************************
+ * Parse special token sequence:
+ * Returns:
+ * true if the special token sequence was handled
+ * References:
+ * https://dlang.org/spec/lex.html#special-token-sequence
+ */
+ bool parseSpecialTokenSequence()
+ {
+ Token n;
+ scan(&n);
+ if (n.value == TOK.identifier)
+ {
+ if (n.ident == Id.line)
+ {
+ poundLine(n, false);
+ return true;
+ }
+ else
+ {
+ const locx = loc();
+ warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars());
+ }
+ }
+ else if (n.value == TOK.if_)
+ {
+ error("C preprocessor directive `#if` is not supported, use `version` or `static if`");
+ }
+ return false;
+ }
+
/*********************************************
* Parse line/file preprocessor directive:
* #line linnum [filespec]
* References:
* linemarker https://gcc.gnu.org/onlinedocs/gcc-11.1.0/cpp/Preprocessor-Output.html
*/
- private void poundLine(ref Token tok, bool linemarker)
+ final void poundLine(ref Token tok, bool linemarker)
{
auto linnum = this.scanloc.linnum;
const(char)* filespec = null;
error(loc, "#line integer [\"filespec\"]\\n expected");
}
- /*********************************************
- * C11 6.10.6 Pragma directive
- * # pragma pp-tokens(opt) new-line
- * The C preprocessor sometimes leaves pragma directives in
- * the preprocessed output. Ignore them.
- * Upon return, p is at start of next line.
- */
- private void pragmaDirective(const ref Loc loc)
- {
- Token n;
- scan(&n);
- if (n.value == TOK.identifier && n.ident == Id.pack)
- return pragmaPack(loc);
- skipToNextLine();
- }
-
- /*********
- * ImportC
- * # pragma pack
- * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
- * https://docs.microsoft.com/en-us/cpp/preprocessor/pack
- * Scanner is on the `pack`
- * Params:
- * startloc = location to use for error messages
- */
- private void pragmaPack(const ref Loc startloc)
- {
- const loc = startloc;
- Token n;
- scan(&n);
- if (n.value != TOK.leftParenthesis)
- {
- error(loc, "left parenthesis expected to follow `#pragma pack`");
- skipToNextLine();
- return;
- }
-
- void closingParen()
- {
- if (n.value != TOK.rightParenthesis)
- {
- error(loc, "right parenthesis expected to close `#pragma pack(`");
- }
- skipToNextLine();
- }
-
- void setPackAlign(ref const Token t)
- {
- const n = t.unsvalue;
- if (n < 1 || n & (n - 1) || ushort.max < n)
- error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
- packalign.set(cast(uint)n);
- packalign.setPack(true);
- }
-
- scan(&n);
-
- if (!records)
- {
- records = new Array!Identifier;
- packs = new Array!structalign_t;
- }
-
- /* # pragma pack ( show )
- */
- if (n.value == TOK.identifier && n.ident == Id.show)
- {
- if (packalign.isDefault())
- warning(startloc, "current pack attribute is default");
- else
- warning(startloc, "current pack attribute is %d", packalign.get());
- scan(&n);
- return closingParen();
- }
- /* # pragma pack ( push )
- * # pragma pack ( push , identifier )
- * # pragma pack ( push , integer )
- * # pragma pack ( push , identifier , integer )
- */
- if (n.value == TOK.identifier && n.ident == Id.push)
- {
- scan(&n);
- Identifier record = null;
- if (n.value == TOK.comma)
- {
- scan(&n);
- if (n.value == TOK.identifier)
- {
- record = n.ident;
- scan(&n);
- if (n.value == TOK.comma)
- {
- scan(&n);
- if (n.value == TOK.int32Literal)
- {
- setPackAlign(n);
- scan(&n);
- }
- else
- error(loc, "alignment value expected, not `%s`", n.toChars());
- }
- }
- else if (n.value == TOK.int32Literal)
- {
- setPackAlign(n);
- scan(&n);
- }
- else
- error(loc, "alignment value expected, not `%s`", n.toChars());
- }
- this.records.push(record);
- this.packs.push(packalign);
- return closingParen();
- }
- /* # pragma pack ( pop )
- * # pragma pack ( pop PopList )
- * PopList :
- * , IdentifierOrInteger
- * , IdentifierOrInteger PopList
- * IdentifierOrInteger:
- * identifier
- * integer
- */
- if (n.value == TOK.identifier && n.ident == Id.pop)
- {
- scan(&n);
- while (n.value == TOK.comma)
- {
- scan(&n);
- if (n.value == TOK.identifier)
- {
- for (size_t len = this.records.length; len; --len)
- {
- if ((*this.records)[len - 1] == n.ident)
- {
- packalign = (*this.packs)[len - 1];
- this.records.setDim(len - 1);
- this.packs.setDim(len - 1);
- break;
- }
- }
- scan(&n);
- }
- else if (n.value == TOK.int32Literal)
- {
- setPackAlign(n);
- this.records.push(null);
- this.packs.push(packalign);
- scan(&n);
- }
- }
- return closingParen();
- }
- /* # pragma pack ( integer )
- */
- if (n.value == TOK.int32Literal)
- {
- setPackAlign(n);
- scan(&n);
- return closingParen();
- }
- /* # pragma pack ( )
- */
- if (n.value == TOK.rightParenthesis)
- {
- packalign.setDefault();
- return closingParen();
- }
-
- error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
- skipToNextLine();
- }
-
/***************************************
* Scan forward to start of next line.
*/
- private void skipToNextLine()
+ final void skipToNextLine()
{
while (1)
{
assert(tok == TOK.endOfFile);
}
}
-
-
inoutParam = 0x0400, // inout on the parameters
inoutQual = 0x0800, // inout on the qualifier
isctor = 0x1000, // the function is a constructor
+ isreturnscope = 0x2000, // `this` is returned by value
}
LINK linkage; // calling convention
this.isref = true;
if (stc & STC.return_)
this.isreturn = true;
+ if (stc & STC.returnScope)
+ this.isreturnscope = true;
if (stc & STC.returninferred)
this.isreturninferred = true;
if (stc & STC.scope_)
t.isproperty = isproperty;
t.isref = isref;
t.isreturn = isreturn;
+ t.isreturnscope = isreturnscope;
t.isScopeQual = isScopeQual;
t.isreturninferred = isreturninferred;
t.isscopeinferred = isscopeinferred;
tf.isproperty = t.isproperty;
tf.isref = t.isref;
tf.isreturn = t.isreturn;
+ tf.isreturnscope = t.isreturnscope;
tf.isScopeQual = t.isScopeQual;
tf.isreturninferred = t.isreturninferred;
tf.isscopeinferred = t.isscopeinferred;
t.isproperty = isproperty;
t.isref = isref;
t.isreturn = isreturn;
+ t.isreturnscope = isreturnscope;
t.isScopeQual = isScopeQual;
t.isreturninferred = isreturninferred;
t.isscopeinferred = isscopeinferred;
else funcFlags &= ~FunctionFlag.isreturn;
}
+ /// set or get if the function has the `returnscope` attribute
+ bool isreturnscope() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isreturnscope) != 0;
+ }
+ /// ditto
+ void isreturnscope(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isreturnscope;
+ else funcFlags &= ~FunctionFlag.isreturnscope;
+ }
+
/// set or get if the function has the `scope` attribute
bool isScopeQual() const pure nothrow @safe @nogc
{
/* Conversion derived to const(base)
*/
int offset = 0;
- if (to.isBaseOf(this, &offset) && MODimplicitConv(mod, to.mod))
+ if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod))
{
// Disallow:
// derived to base
void isref(bool v);
bool isreturn() const;
void isreturn(bool v);
+ bool isreturnscope() const;
+ void isreturnscope(bool v);
bool isScopeQual() const;
void isScopeQual(bool v);
bool isreturninferred() const;
fd = search_function(ad, id);
if (fd)
{
- // @@@DEPRECATED_2.098@@@.
- // Deprecated in 2.088
- // Make an error in 2.098
- e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
- // Rewrite +e1 as e1.add()
- result = build_overload(e.loc, sc, e.e1, null, fd);
- return result;
+ // @@@DEPRECATED_2.110@@@.
+ // Deprecated in 2.088, made an error in 2.100
+ e.error("`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
+ return ErrorExp.get();
}
}
// Didn't find it. Forward to aliasthis
s = search_function(ad1, id);
if (s && id != Id.assign)
{
- // @@@DEPRECATED_2.098@@@.
- // Deprecated in 2.088
- // Make an error in 2.098
+ // @@@DEPRECATED_2.110@@@.
+ // Deprecated in 2.088, made an error in 2.100
if (id == Id.postinc || id == Id.postdec)
- e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
+ e.error("`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
else
- e.deprecation("`%s` is deprecated. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
+ e.error("`%s` is obsolete. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
+ return ErrorExp.get();
}
}
if (ad2 && id_r)
s_r = null;
if (s_r)
{
- // @@@DEPRECATED_2.098@@@.
- // Deprecated in 2.088
- // Make an error in 2.098
- e.deprecation("`%s` is deprecated. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr);
+ // @@@DEPRECATED_2.110@@@.
+ // Deprecated in 2.088, made an error in 2.100
+ e.error("`%s` is obsolete. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr);
+ return ErrorExp.get();
}
}
}
s = search_function(ad1, id);
if (s)
{
- // @@@DEPRECATED_2.098@@@.
- // Deprecated in 2.088
- // Make an error in 2.098
+ // @@@DEPRECATED_2.110@@@.
+ // Deprecated in 2.088, made an error in 2.100
scope char[] op = EXPtoString(e.op).dup;
op[$-1] = '\0'; // remove trailing `=`
- e.deprecation("`%s` is deprecated. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr);
+ e.error("`%s` is obsolete. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr);
+ return ErrorExp.get();
}
}
* Params:
* fes = the foreach statement
* sc = context
- * sapply = null or opApply or delegate
+ * sapply = null or opApply or delegate, overload resolution has not been done.
+ * Do overload resolution on sapply.
* Returns:
* false for errors
*/
*/
if (FuncDeclaration fd = sapply.isFuncDeclaration())
{
- auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters);
- if (fdapply)
+ if (auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters))
{
// Fill in any missing types on foreach parameters[]
matchParamsToOpApply(fdapply.type.isTypeFunction(), fes.parameters, true);
}
return false;
}
- return sapply !is null;
+ return true; // shouldn't this be false?
}
Parameter p = (*fes.parameters)[0];
void visitTuple(TupleExp e)
{
expOptimize(e.e0, WANTvalue);
- for (size_t i = 0; i < e.exps.dim; i++)
+ foreach (ref ex; (*e.exps)[])
{
- expOptimize((*e.exps)[i], WANTvalue);
+ expOptimize(ex, WANTvalue);
}
}
if (e.elements)
{
expOptimize(e.basis, result & WANTexpand);
- for (size_t i = 0; i < e.elements.dim; i++)
+ foreach (ref ex; (*e.elements)[])
{
- expOptimize((*e.elements)[i], result & WANTexpand);
+ expOptimize(ex, result & WANTexpand);
}
}
}
void visitAssocArrayLiteral(AssocArrayLiteralExp e)
{
assert(e.keys.dim == e.values.dim);
- for (size_t i = 0; i < e.keys.dim; i++)
+ foreach (i, ref ekey; (*e.keys)[])
{
- expOptimize((*e.keys)[i], result & WANTexpand);
+ expOptimize(ekey, result & WANTexpand);
expOptimize((*e.values)[i], result & WANTexpand);
}
}
e.stageflags |= stageOptimize;
if (e.elements)
{
- for (size_t i = 0; i < e.elements.dim; i++)
+ foreach (ref ex; (*e.elements)[])
{
- expOptimize((*e.elements)[i], result & WANTexpand);
+ expOptimize(ex, result & WANTexpand);
}
}
e.stageflags = old;
// Optimize parameters
if (e.arguments)
{
- for (size_t i = 0; i < e.arguments.dim; i++)
+ foreach (ref arg; (*e.arguments)[])
{
- expOptimize((*e.arguments)[i], WANTvalue);
+ expOptimize(arg, WANTvalue);
}
}
}
if (e.arguments)
{
Type t1 = e.e1.type.toBasetype();
- if (t1.ty == Tdelegate)
- t1 = t1.nextOf();
+ if (auto td = t1.isTypeDelegate())
+ t1 = td.next;
// t1 can apparently be void for __ArrayDtor(T) calls
if (auto tf = t1.isTypeFunction())
{
- for (size_t i = 0; i < e.arguments.dim; i++)
+ foreach (i, ref arg; (*e.arguments)[])
{
Parameter p = tf.parameterList[i];
bool keep = p && p.isReference();
- expOptimize((*e.arguments)[i], WANTvalue, keep);
+ expOptimize(arg, WANTvalue, keep);
}
}
}
}
}
- if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
+ // Returning e.e1 with changing its type
+ void returnE_e1()
{
- //printf(" returning2 %s\n", e.e1.toChars());
- L1:
- // Returning e1 with changing its type
ret = (e1old == e.e1 ? e.e1.copy() : e.e1);
ret.type = e.type;
- return;
+ }
+
+ if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
+ {
+ //printf(" returning2 %s\n", e.e1.toChars());
+ return returnE_e1();
}
/* The first test here is to prevent infinite loops
*/
if (e.e1.op == EXP.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray))
{
//printf(" returning3 %s\n", e.e1.toChars());
- goto L1;
+ return returnE_e1();
}
if (e.type.ty == Tclass && e.e1.type.ty == Tclass)
{
if (cdfrom.errors || cdto.errors)
return error();
if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
- goto L1; // can always convert a class to Object
+ return returnE_e1(); // can always convert a class to Object
// Need to determine correct offset before optimizing away the cast.
// https://issues.dlang.org/show_bug.cgi?id=16980
cdfrom.size(e.loc);
if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
{
//printf(" returning4 %s\n", e.e1.toChars());
- goto L1;
+ return returnE_e1();
}
}
if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf()))
{
//printf(" returning5 %s\n", e.e1.toChars());
- goto L1;
+ return returnE_e1();
}
if (e.e1.isConst())
{
return error();
if (esz == e1sz)
- goto L1;
+ return returnE_e1();
}
return;
}
// Don't optimize to an array literal element directly in case an lvalue is requested
if (keepLvalue && ex.op == EXP.arrayLiteral)
return;
- ret = Index(e.type, ex, e.e2).copy();
+ ret = Index(e.type, ex, e.e2, e.indexIsInBounds).copy();
if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue()))
ret = e;
}
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.string_:
- case TOK.hexadecimalString:
case TOK.file:
case TOK.fileFullPath:
case TOK.line:
case TOK.true_:
case TOK.false_:
case TOK.string_:
- case TOK.hexadecimalString:
case TOK.leftParenthesis:
case TOK.cast_:
case TOK.mul:
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.string_:
- case TOK.hexadecimalString:
case TOK.file:
case TOK.fileFullPath:
case TOK.line:
break;
case TOK.string_:
- case TOK.hexadecimalString:
{
// cat adjacent strings
auto s = token.ustring;
{
const prev = token;
nextToken();
- if (token.value == TOK.string_ || token.value == TOK.hexadecimalString)
+ if (token.value == TOK.string_)
{
if (token.postfix)
{
assert(t.ty == Tdelegate);
tfld = cast(TypeFunction)t.nextOf();
}
- //printf("tfld = %s\n", tfld.toChars());
}
}
}
/* Call:
* _aApply(aggr, flde)
*/
- __gshared const(char)** fntab =
+ static immutable fntab =
[
"cc", "cw", "cd",
"wc", "cc", "wd",
"dc", "dw", "dd"
- ];
+ ];
const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1;
char[BUFFER_LEN] fdname;
assert(0);
}
const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : "";
- int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag], cast(ulong)dim);
+ int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim);
assert(j < BUFFER_LEN);
FuncDeclaration fdapply;
Expression initialExp = cs.exp;
// The switch'ed value has errors and doesn't provide the actual type
- // Don't touch the case to not replace it with an `ErrorExp` even if it is valid
+ // Omit the cast to enable further semantic (exluding the check for matching types)
if (sw.condition.type && !sw.condition.type.isTypeError())
- {
cs.exp = cs.exp.implicitCastTo(sc, sw.condition.type);
- cs.exp = cs.exp.optimize(WANTvalue | WANTexpand);
+ cs.exp = cs.exp.optimize(WANTvalue | WANTexpand);
+
+ Expression e = cs.exp;
+ // Remove all the casts the user and/or implicitCastTo may introduce
+ // otherwise we'd sometimes fail the check below.
+ while (e.op == EXP.cast_)
+ e = (cast(CastExp)e).e1;
+
+ /* This is where variables are allowed as case expressions.
+ */
+ if (e.op == EXP.variable)
+ {
+ VarExp ve = cast(VarExp)e;
+ VarDeclaration v = ve.var.isVarDeclaration();
+ Type t = cs.exp.type.toBasetype();
+ if (v && (t.isintegral() || t.ty == Tclass))
+ {
+ /* Flag that we need to do special code generation
+ * for this, i.e. generate a sequence of if-then-else
+ */
+ sw.hasVars = 1;
+
+ /* TODO check if v can be uninitialized at that point.
+ */
+ if (!v.isConst() && !v.isImmutable())
+ {
+ cs.error("`case` variables have to be `const` or `immutable`");
+ }
- Expression e = cs.exp;
- // Remove all the casts the user and/or implicitCastTo may introduce
- // otherwise we'd sometimes fail the check below.
- while (e.op == EXP.cast_)
- e = (cast(CastExp)e).e1;
+ if (sw.isFinal)
+ {
+ cs.error("`case` variables not allowed in `final switch` statements");
+ errors = true;
+ }
- /* This is where variables are allowed as case expressions.
- */
- if (e.op == EXP.variable)
- {
- VarExp ve = cast(VarExp)e;
- VarDeclaration v = ve.var.isVarDeclaration();
- Type t = cs.exp.type.toBasetype();
- if (v && (t.isintegral() || t.ty == Tclass))
+ /* Find the outermost scope `scx` that set `sw`.
+ * Then search scope `scx` for a declaration of `v`.
+ */
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
{
- /* Flag that we need to do special code generation
- * for this, i.e. generate a sequence of if-then-else
- */
- sw.hasVars = 1;
-
- /* TODO check if v can be uninitialized at that point.
- */
- if (!v.isConst() && !v.isImmutable())
- {
- cs.error("`case` variables have to be `const` or `immutable`");
- }
+ if (scx.enclosing && scx.enclosing.sw == sw)
+ continue;
+ assert(scx.sw == sw);
- if (sw.isFinal)
+ if (!scx.search(cs.exp.loc, v.ident, null))
{
- cs.error("`case` variables not allowed in `final switch` statements");
+ cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body",
+ v.toChars(), v.loc.toChars());
errors = true;
}
-
- /* Find the outermost scope `scx` that set `sw`.
- * Then search scope `scx` for a declaration of `v`.
- */
- for (Scope* scx = sc; scx; scx = scx.enclosing)
- {
- if (scx.enclosing && scx.enclosing.sw == sw)
- continue;
- assert(scx.sw == sw);
-
- if (!scx.search(cs.exp.loc, v.ident, null))
- {
- cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body",
- v.toChars(), v.loc.toChars());
- errors = true;
- }
- break;
- }
- goto L1;
+ break;
}
+ goto L1;
}
- else
- cs.exp = cs.exp.ctfeInterpret();
}
+ else
+ cs.exp = cs.exp.ctfeInterpret();
if (StringExp se = cs.exp.toStringExp())
cs.exp = se;
// Leaf operators
identifier,
string_,
- hexadecimalString,
this_,
super_,
error,
TOK.wchar_tLiteral: "wchar_tv",
TOK.whitespace: "whitespace",
- TOK.hexadecimalString: "xstring",
-
// C only keywords
TOK.inline : "inline",
TOK.register : "register",
p = buf.extractSlice().ptr;
}
break;
- case TOK.hexadecimalString:
- {
- OutBuffer buf;
- buf.writeByte('x');
- buf.writeByte('"');
- foreach (size_t i; 0 .. len)
- {
- if (i)
- buf.writeByte(' ');
- buf.printf("%02x", ustring[i]);
- }
- buf.writeByte('"');
- if (postfix)
- buf.writeByte(postfix);
- buf.writeByte(0);
- p = buf.extractSlice().ptr;
- break;
- }
case TOK.identifier:
case TOK.enum_:
case TOK.struct_:
// Leaf operators
identifier,
string_,
- hexadecimalString,
this_,
super_,
error,
Type visitType(Type t)
{
+ // @@@DEPRECATED_2.110@@@
+ // Use of `cent` and `ucent` has always been an error.
+ // Starting from 2.100, recommend core.int128 as a replace for the
+ // lack of compiler support.
if (t.ty == Tint128 || t.ty == Tuns128)
{
- .error(loc, "`cent` and `ucent` types not implemented");
+ .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
return error();
}
tf.isref = true;
if (sc.stc & STC.return_)
tf.isreturn = true;
+ if (sc.stc & STC.returnScope)
+ tf.isreturnscope = true;
if (sc.stc & STC.returninferred)
tf.isreturninferred = true;
if (sc.stc & STC.scope_)
* e.opDot().ident
*/
e = build_overload(e.loc, sc, e, null, fd);
- // @@@DEPRECATED_2.092@@@.
- e.deprecation("`opDot` is deprecated. Use `alias this`");
- e = new DotIdExp(e.loc, e, ident);
- return returnExp(e.expressionSemantic(sc));
+ // @@@DEPRECATED_2.110@@@.
+ // Deprecated in 2.082, made an error in 2.100.
+ e.error("`opDot` is obsolete. Use `alias this`");
+ return ErrorExp.get();
}
/* Look for overloaded opDispatch to see if we should forward request
tree type = build_ctype (d->type);
/* Not all kinds of D enums create a TYPE_DECL. */
if (TREE_CODE (type) == ENUMERAL_TYPE)
- d->isym = this->make_import (TYPE_STUB_DECL (type));
+ this->result_ = this->make_import (TYPE_STUB_DECL (type));
}
void visit (AggregateDeclaration *d)
{
tree type = build_ctype (d->type);
- d->isym = this->make_import (TYPE_STUB_DECL (type));
+ this->result_ = this->make_import (TYPE_STUB_DECL (type));
}
void visit (ClassDeclaration *d)
{
/* Want the RECORD_TYPE, not POINTER_TYPE. */
tree type = TREE_TYPE (build_ctype (d->type));
- d->isym = this->make_import (TYPE_STUB_DECL (type));
+ this->result_ = this->make_import (TYPE_STUB_DECL (type));
}
/* For now, ignore importing other kinds of dsymbols. */
static assert(is( X!( C*, I* ) == I* ));
static assert(is( X!( I*, C* ) == I* ));
-//static assert(Error!( C**, I** ));
-static assert(is( X!( C**, I** ) == const(I*)* ));
+static assert(Error!( C**, I** ));
static assert(Error!( C*, D* )); // should work
static assert(Error!( C[4], I[4] ));
static assert(Error!( C[4], D[4] ));
static assert(is( X!( C[4], const(B)[4] ) == const(B)[4] ));
-//static assert(Error!( C[4], const(I)[4] ));
-static assert(is( X!( C[4], const(I)[4] ) == const(I)[] ));
+static assert(Error!( C[4], const(I)[4] ));
static assert(Error!( C[4], const(D)[4] ));
static assert(Error!( C*[4], B*[4] ));
static assert(Error!( C*[4], I*[4] ));
static assert(Error!( C*[4], D*[4] ));
static assert(is( X!( C*[4], const(B*)[4] ) == const(B*)[] )); // !?
-//static assert(Error!( C*[4], const(I*)[4] ));
-static assert(is( X!( C*[4], const(I*)[4] ) == const(I*)[] ));
+static assert(Error!( C*[4], const(I*)[4] ));
static assert(Error!( C*[4], const(D*)[4] ));
static assert(Error!( C*[4], B**[4] ));
static assert(Error!( C*[4], const(B*)*[4] ));
+/* TEST_OUTPUT:
+---
+compilable/test7172.d(14): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
+---
+*/
void main()
{
abstract class AbstractC{}
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
-fail_compilation/dep_d1_ops.d(105): Deprecation: `opAdd` is deprecated. Use `opBinary(string op)(...) if (op == "+")` instead.
-fail_compilation/dep_d1_ops.d(106): Deprecation: `opAdd_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "+")` instead.
-fail_compilation/dep_d1_ops.d(107): Deprecation: `opSub` is deprecated. Use `opBinary(string op)(...) if (op == "-")` instead.
-fail_compilation/dep_d1_ops.d(108): Deprecation: `opSub_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "-")` instead.
-fail_compilation/dep_d1_ops.d(109): Deprecation: `opMul` is deprecated. Use `opBinary(string op)(...) if (op == "*")` instead.
-fail_compilation/dep_d1_ops.d(110): Deprecation: `opMul_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "*")` instead.
-fail_compilation/dep_d1_ops.d(111): Deprecation: `opDiv` is deprecated. Use `opBinary(string op)(...) if (op == "/")` instead.
-fail_compilation/dep_d1_ops.d(112): Deprecation: `opDiv_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "/")` instead.
-fail_compilation/dep_d1_ops.d(113): Deprecation: `opMod` is deprecated. Use `opBinary(string op)(...) if (op == "%")` instead.
-fail_compilation/dep_d1_ops.d(114): Deprecation: `opMod_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "%")` instead.
-fail_compilation/dep_d1_ops.d(116): Deprecation: `opAnd` is deprecated. Use `opBinary(string op)(...) if (op == "&")` instead.
-fail_compilation/dep_d1_ops.d(117): Deprecation: `opOr` is deprecated. Use `opBinary(string op)(...) if (op == "|")` instead.
-fail_compilation/dep_d1_ops.d(118): Deprecation: `opXor` is deprecated. Use `opBinary(string op)(...) if (op == "^")` instead.
-fail_compilation/dep_d1_ops.d(120): Deprecation: `opShl` is deprecated. Use `opBinary(string op)(...) if (op == "<<")` instead.
-fail_compilation/dep_d1_ops.d(121): Deprecation: `opShl_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "<<")` instead.
-fail_compilation/dep_d1_ops.d(122): Deprecation: `opShr` is deprecated. Use `opBinary(string op)(...) if (op == ">>")` instead.
-fail_compilation/dep_d1_ops.d(123): Deprecation: `opShr_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == ">>")` instead.
-fail_compilation/dep_d1_ops.d(124): Deprecation: `opUShr` is deprecated. Use `opBinary(string op)(...) if (op == ">>>")` instead.
-fail_compilation/dep_d1_ops.d(125): Deprecation: `opUShr_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == ">>>")` instead.
-fail_compilation/dep_d1_ops.d(127): Deprecation: `opCat` is deprecated. Use `opBinary(string op)(...) if (op == "~")` instead.
-fail_compilation/dep_d1_ops.d(128): Deprecation: `opCat_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "~")` instead.
-fail_compilation/dep_d1_ops.d(130): Deprecation: `opNeg` is deprecated. Use `opUnary(string op)() if (op == "-")` instead.
-fail_compilation/dep_d1_ops.d(131): Deprecation: `opCom` is deprecated. Use `opUnary(string op)() if (op == "~")` instead.
-fail_compilation/dep_d1_ops.d(132): Deprecation: `opPostInc` is deprecated. Use `opUnary(string op)() if (op == "++")` instead.
-fail_compilation/dep_d1_ops.d(133): Deprecation: `opPostDec` is deprecated. Use `opUnary(string op)() if (op == "--")` instead.
-fail_compilation/dep_d1_ops.d(134): Deprecation: `opStar` is deprecated. Use `opUnary(string op)() if (op == "*")` instead.
-fail_compilation/dep_d1_ops.d(136): Deprecation: `opIn` is deprecated. Use `opBinary(string op)(...) if (op == "in")` instead.
-fail_compilation/dep_d1_ops.d(137): Deprecation: `opIn_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "in")` instead.
-fail_compilation/dep_d1_ops.d(139): Deprecation: `opAddAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "+")` instead.
-fail_compilation/dep_d1_ops.d(140): Deprecation: `opSubAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "-")` instead.
-fail_compilation/dep_d1_ops.d(141): Deprecation: `opMulAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "*")` instead.
-fail_compilation/dep_d1_ops.d(142): Deprecation: `opDivAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "/")` instead.
-fail_compilation/dep_d1_ops.d(143): Deprecation: `opModAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "%")` instead.
-fail_compilation/dep_d1_ops.d(144): Deprecation: `opAndAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "&")` instead.
-fail_compilation/dep_d1_ops.d(145): Deprecation: `opOrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "|")` instead.
-fail_compilation/dep_d1_ops.d(146): Deprecation: `opXorAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "^")` instead.
-fail_compilation/dep_d1_ops.d(147): Deprecation: `opShlAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "<<")` instead.
-fail_compilation/dep_d1_ops.d(148): Deprecation: `opShrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == ">>")` instead.
-fail_compilation/dep_d1_ops.d(149): Deprecation: `opUShrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == ">>>")` instead.
-fail_compilation/dep_d1_ops.d(150): Deprecation: `opCatAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "~")` instead.
-fail_compilation/dep_d1_ops.d(158): Deprecation: `opCom` is deprecated. Use `opUnary(string op)() if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(105): Error: `opAdd` is obsolete. Use `opBinary(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(106): Error: `opAdd_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(107): Error: `opSub` is obsolete. Use `opBinary(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(108): Error: `opSub_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(109): Error: `opMul` is obsolete. Use `opBinary(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(110): Error: `opMul_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(111): Error: `opDiv` is obsolete. Use `opBinary(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(112): Error: `opDiv_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(113): Error: `opMod` is obsolete. Use `opBinary(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(114): Error: `opMod_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(116): Error: `opAnd` is obsolete. Use `opBinary(string op)(...) if (op == "&")` instead.
+fail_compilation/dep_d1_ops.d(117): Error: `opOr` is obsolete. Use `opBinary(string op)(...) if (op == "|")` instead.
+fail_compilation/dep_d1_ops.d(118): Error: `opXor` is obsolete. Use `opBinary(string op)(...) if (op == "^")` instead.
+fail_compilation/dep_d1_ops.d(120): Error: `opShl` is obsolete. Use `opBinary(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(121): Error: `opShl_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(122): Error: `opShr` is obsolete. Use `opBinary(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(123): Error: `opShr_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(124): Error: `opUShr` is obsolete. Use `opBinary(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(125): Error: `opUShr_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(127): Error: `opCat` is obsolete. Use `opBinary(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(128): Error: `opCat_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(130): Error: `opNeg` is obsolete. Use `opUnary(string op)() if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(131): Error: `opCom` is obsolete. Use `opUnary(string op)() if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(132): Error: `opPostInc` is obsolete. Use `opUnary(string op)() if (op == "++")` instead.
+fail_compilation/dep_d1_ops.d(133): Error: `opPostDec` is obsolete. Use `opUnary(string op)() if (op == "--")` instead.
+fail_compilation/dep_d1_ops.d(134): Error: `opStar` is obsolete. Use `opUnary(string op)() if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(136): Error: `opIn` is obsolete. Use `opBinary(string op)(...) if (op == "in")` instead.
+fail_compilation/dep_d1_ops.d(137): Error: `opIn_r` is obsolete. Use `opBinaryRight(string op)(...) if (op == "in")` instead.
+fail_compilation/dep_d1_ops.d(139): Error: `opAddAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(140): Error: `opSubAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(141): Error: `opMulAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(142): Error: `opDivAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(143): Error: `opModAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(144): Error: `opAndAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "&")` instead.
+fail_compilation/dep_d1_ops.d(145): Error: `opOrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "|")` instead.
+fail_compilation/dep_d1_ops.d(146): Error: `opXorAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "^")` instead.
+fail_compilation/dep_d1_ops.d(147): Error: `opShlAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(148): Error: `opShrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(149): Error: `opUShrAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(150): Error: `opCatAssign` is obsolete. Use `opOpAssign(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(158): Error: `opCom` is obsolete. Use `opUnary(string op)() if (op == "~")` instead.
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/dephexstrings.d(8): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"60"` instead.
+fail_compilation/dephexstrings.d(9): Error: semicolon expected following auto declaration, not `"60"`
+fail_compilation/dephexstrings.d(9): Error: declaration expected, not `"60"`
---
*/
enum xstr = x"60";
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
-fail_compilation/deprecateopdot.d(27): Deprecation: `opDot` is deprecated. Use `alias this`
-fail_compilation/deprecateopdot.d(28): Deprecation: `opDot` is deprecated. Use `alias this`
-fail_compilation/deprecateopdot.d(29): Deprecation: `opDot` is deprecated. Use `alias this`
+fail_compilation/deprecateopdot.d(27): Error: `opDot` is obsolete. Use `alias this`
+fail_compilation/deprecateopdot.d(28): Error: `opDot` is obsolete. Use `alias this`
+fail_compilation/deprecateopdot.d(29): Error: `opDot` is obsolete. Use `alias this`
---
*/
struct S6
/*
TEST_OUTPUT:
---
-fail_compilation/fail136.d(10): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"EF BB BF"` instead.
+fail_compilation/fail136.d(10): Error: found `"EF BB BF"` when expecting `;` following statement
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail18.d(14): Error: need upper and lower bound to slice pointer
+fail_compilation/fail18.d(14): Error: upper and lower bounds are needed to slice a pointer
---
*/
// https://issues.dlang.org/show_bug.cgi?id=22780
/* TEST_OUTPUT:
---
-fail_compilation/fail22780.d(11): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope`
+fail_compilation/fail22780.d(8): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
+fail_compilation/fail22780.d(12): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope`
---
*/
scope class C10717 { }
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22827
+/* TEST_OUTPUT:
+---
+fail_compilation/fail22827.d(8): Error: `cent` and `ucent` types are obsolete, use `core.int128.Cent` instead
+fail_compilation/fail22827.d(9): Error: `cent` and `ucent` types are obsolete, use `core.int128.Cent` instead
+---
+*/
+cent i22827;
+ucent j22827;
--- /dev/null
+/*
+TEST_OUTPUT:
+---
+fail_compilation/issue22820.d(138): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(138): pointer `s1` points to an aggregate that defines an `opIndex`, perhaps you meant `(*s1)[]`
+fail_compilation/issue22820.d(139): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(139): pointer `s2` points to an aggregate that defines an `opSlice`, perhaps you meant `(*s2)[]`
+fail_compilation/issue22820.d(140): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(140): pointer `s3` points to an aggregate that defines an `opIndex`, perhaps you meant `(*s3)[]`
+fail_compilation/issue22820.d(141): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(141): pointer `cp` points to an aggregate that defines an `opIndex`, perhaps you meant `(*cp)[]`
+fail_compilation/issue22820.d(142): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(142): pointer `e` points to an aggregate that defines an `opIndex`, perhaps you meant `(*e)[]`
+---
+*/
+
+#line 100
+
+// normal functions
+struct S1 {
+ int[] opIndex() { return a; }
+ int[] a;
+}
+
+// opSlice alternative
+struct S2 {
+ int[] opSlice() { return a; }
+ int[] a;
+}
+
+// templates
+struct S3 {
+ int[] opIndex()() { return a; }
+ int[] a;
+}
+
+class C {
+ int[] opIndex()() { return a; }
+ int[] a;
+}
+
+enum E : S1
+{
+ a = S1([1])
+}
+
+void main() {
+ S1* s1 = new S1;
+ S2* s2 = new S2;
+ S3* s3 = new S3;
+ C c = new C;
+ C* cp = &c;
+ E* e = new E;
+ int* p;
+
+ p = s1[].ptr;
+ p = s2[].ptr;
+ p = s3[].ptr;
+ p = cp[].ptr;
+ p = e[].ptr;
+
+ p = (*s1)[].ptr;
+ p = (*s2)[].ptr;
+ p = (*s3)[].ptr;
+ p = (*cp)[].ptr;
+ p = (*e)[].ptr;
+}
+
/*
TEST_OUTPUT:
---
-fail_compilation/lexer1.d(30): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"01 02 03"w` instead.
-fail_compilation/lexer1.d(30): Error: declaration expected, not `x"01 02 03"w`
+fail_compilation/lexer1.d(30): Error: no identifier for declarator `x`
+fail_compilation/lexer1.d(30): Error: declaration expected, not `"01 02 03"w`
fail_compilation/lexer1.d(31): Error: declaration expected, not `2147483649U`
fail_compilation/lexer1.d(32): Error: declaration expected, not `0.1`
fail_compilation/lexer1.d(33): Error: declaration expected, not `0.1f`
/*
TEST_OUTPUT:
---
-fail_compilation/lexer2.d(16): Error: odd number (3) of hex characters in hex string
-fail_compilation/lexer2.d(16): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"123"` instead.
-fail_compilation/lexer2.d(17): Error: non-hex character 'G' in hex string
-fail_compilation/lexer2.d(17): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"123G"` instead.
+fail_compilation/lexer2.d(16): Error: semicolon expected following auto declaration, not `"123"`
+fail_compilation/lexer2.d(16): Error: declaration expected, not `"123"`
+fail_compilation/lexer2.d(17): Error: semicolon expected following auto declaration, not `"123G"`
+fail_compilation/lexer2.d(17): Error: declaration expected, not `"123G"`
fail_compilation/lexer2.d(18): Error: heredoc rest of line should be blank
fail_compilation/lexer2.d(20): Error: unterminated delimited string constant starting at fail_compilation/lexer2.d(20)
fail_compilation/lexer2.d(22): Error: semicolon expected following auto declaration, not `End of File`
--- /dev/null
+/* TEST_OUTPUT:
+---
+fail_compilation/opapplyscope.d(113): Error: function `opapplyscope.S.opApply(scope int delegate(scope int* ptr) @safe dg)` is not callable using argument types `(int delegate(int* x) nothrow @nogc @safe)`
+fail_compilation/opapplyscope.d(113): cannot pass argument `__foreachbody3` of type `int delegate(int* x) nothrow @nogc @safe` to parameter `scope int delegate(scope int* ptr) @safe dg`
+---
+ */
+
+#line 100
+
+struct S
+{
+ int opApply(scope int delegate (scope int* ptr) @safe dg) @safe
+ {
+ return 0;
+ }
+}
+
+void test() @safe
+{
+ static int* global;
+ S s;
+ foreach (/*scope*/ int* x; s)
+ {
+ global = x;
+ }
+}
+
/*
TEST_OUTPUT:
---
-fail_compilation/scope_class.d(11): Error: functions cannot return `scope scope_class.C`
+fail_compilation/scope_class.d(10): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
+fail_compilation/scope_class.d(12): Error: functions cannot return `scope scope_class.C`
---
*/
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
-fail_compilation/scope_type.d(11): Error: `scope` as a type constraint is obsolete. Use `scope` at the usage site.
+fail_compilation/scope_type.d(13): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
+fail_compilation/scope_type.d(14): Error: `scope` as a type constraint is obsolete. Use `scope` at the usage site.
+fail_compilation/scope_type.d(15): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
+fail_compilation/scope_type.d(16): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
---
*/
scope class C { }
scope interface I { }
-//scope struct S { }
+scope struct S { }
+scope enum E { e }
/* TEST_OUTPUT:
-PERMUTE_ARGS: -dip1000
+REQUIRED_ARGS: -preview=dip1000
---
-fail_compilation/test15191.d(31): Error: returning `&identity(x)` escapes a reference to local variable `x`
-fail_compilation/test15191.d(37): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
-fail_compilation/test15191.d(43): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive`
-fail_compilation/test15191.d(43): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(35): Error: returning `&identity(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(41): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(47): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive`
+fail_compilation/test15191.d(47): return type `int*` has pointers that may be `scope`
+fail_compilation/test15191.d(68): Error: cannot slice static array of `ref return` of `identityArr()` in `@safe` function `sliceOfRefEscape`
+fail_compilation/test15191.d(68): return type `int*[1]` has pointers that may be `scope`
---
*/
+// Test taking the address of a `ref return` using & and [] operators
// https://issues.dlang.org/show_bug.cgi?id=15191
// https://issues.dlang.org/show_bug.cgi?id=22519
+// https://issues.dlang.org/show_bug.cgi?id=22539
@safe:
ref int foo(return ref int s)
{
return &getGlobalInt();
}
+
+// Slice:
+ref int*[1] identityArr(ref return scope int*[1] x)
+{
+ return x;
+}
+
+int* sliceOfRefEscape()
+{
+ int stackVar = 0xFF;
+ scope int*[1] x = [&stackVar];
+ int*[] y = identityArr(x)[];
+ return y[0];
+}
/* REQUIRED_ARGS: -preview=dip1000
* TEST_OUTPUT:
---
-fail_compilation/test19097.d(35): Error: scope variable `s` may not be returned
+fail_compilation/test19097.d(37): Error: scope variable `s` may not be returned
+fail_compilation/test19097.d(66): Error: scope variable `z` assigned to `refPtr` with longer lifetime
+fail_compilation/test19097.d(97): Error: scope variable `s` may not be returned
---
*/
S2!int s2;
+/************************/
+struct S3
+{
+ int* ptr;
+ void assign(ref int* refPtr, return scope int* z) scope @safe
+ {
+ this.ptr = z; // allowed, first ref
+ refPtr = z; // should not be allowed
+ }
+}
+
+int* escape() @safe
+{
+ int local;
+
+ S3 escapeThis;
+ int* escapeRef;
+
+ escapeThis.assign(escapeRef, &local);
+
+ return escapeRef;
+}
+
+/************************/
+// https://issues.dlang.org/show_bug.cgi?id=22837
+struct S4
+{
+ int* p;
+ this(int dummy, return scope int* p) @safe
+ {
+ this.p = p;
+ }
+}
+
+int* escape2()
+{
+ int x;
+ auto s = S4(0, &x);
+ return s.p;
+}
--- /dev/null
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21008.d(110): Error: function `test21008.C.after` circular reference to class `C`
+fail_compilation/test21008.d(117): Error: need `this` for `toString` of type `string()`
+fail_compilation/test21008.d(117): Error: need `this` for `toHash` of type `nothrow @trusted $?:32=uint|64=ulong$()`
+fail_compilation/test21008.d(117): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `()`
+fail_compilation/test21008.d(117): missing argument for parameter #1: `Object o`
+fail_compilation/test21008.d(117): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `()`
+fail_compilation/test21008.d(117): missing argument for parameter #1: `Object o`
+fail_compilation/test21008.d(117): Error: `Monitor` has no effect
+fail_compilation/test21008.d(117): Error: function `object.Object.factory(string classname)` is not callable using argument types `()`
+fail_compilation/test21008.d(117): missing argument for parameter #1: `string classname`
+fail_compilation/test21008.d(105): called from here: `handleMiddlewareAnnotation()`
+fail_compilation/test21008.d(108): Error: class `test21008.C` no size because of forward reference
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=21008
+
+#line 100
+
+class Base
+{
+ bool after();
+
+ mixin(handleMiddlewareAnnotation);
+}
+
+class C : Base
+{
+ override bool after();
+}
+
+string handleMiddlewareAnnotation()
+{
+ foreach (member; __traits(allMembers, C))
+ {
+ __traits(getMember, C, member);
+ }
+}
}
}
+
+/++
+TEST_OUTPUT:
+---
+fail_compilation/test_switch_error.d(513): Error: undefined identifier `undefinedFunc`
+fail_compilation/test_switch_error.d(517): Error: `case` must be a `string` or an integral constant, not `Strukt(1)`
+fail_compilation/test_switch_error.d(518): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/test_switch_error.d(518): Error: `case` variables not allowed in `final switch` statements
+fail_compilation/test_switch_error.d(519): Error: `case` variables not allowed in `final switch` statements
+fail_compilation/test_switch_error.d(522): Error: undefined identifier `undefinedFunc2`
+---
+++/
+#line 500
+
+enum Foo
+{
+ one, two
+}
+
+struct Strukt
+{
+ int i;
+}
+
+void errorsWithErrors(int param, immutable int constant)
+{
+ final switch(undefinedFunc())
+ {
+ case Foo.one: break;
+ case Foo.two: break;
+ case Strukt(1): break;
+ case param: break;
+ case constant: break;
+ }
+
+ switch (undefinedFunc2())
+ {
+ case constant: break;
+ }
+}
+
+/++
+TEST_OUTPUT:
+---
+fail_compilation/test_switch_error.d(622): Error: undefined identifier `undefinedFunc`
+fail_compilation/test_switch_error.d(624): Error: `case` must be a `string` or an integral constant, not `SubtypeOfInt(2)`
+fail_compilation/test_switch_error.d(625): Error: `case` must be a `string` or an integral constant, not `SubtypeOfIntMethod()`
+---
+++/
+#line 600
+
+struct SubtypeOfInt
+{
+ int i;
+ alias i this;
+}
+
+struct SubtypeOfIntMethod
+{
+ int getI() { return 0; }
+ alias getI this;
+}
+
+void errorsWithErrors2(int param)
+{
+ final switch(param)
+ {
+ case SubtypeOfInt(1): break;
+ case SubtypeOfIntMethod(): break;
+ }
+
+ // This snippet causes somewhat misleading error messages
+ final switch(undefinedFunc())
+ {
+ case SubtypeOfInt(2): break;
+ case SubtypeOfIntMethod(): break;
+ }
+}
/*
TEST_OUTPUT:
---
-fail_compilation/typeerrors.d(36): Error: tuple index 4 exceeds 4
-fail_compilation/typeerrors.d(38): Error: variable `x` cannot be read at compile time
-fail_compilation/typeerrors.d(39): Error: cannot have array of `void()`
-fail_compilation/typeerrors.d(40): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(32): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
+fail_compilation/typeerrors.d(37): Error: tuple index 4 exceeds 4
+fail_compilation/typeerrors.d(39): Error: variable `x` cannot be read at compile time
+fail_compilation/typeerrors.d(40): Error: cannot have array of `void()`
fail_compilation/typeerrors.d(41): Error: cannot have array of scope `typeerrors.C`
-fail_compilation/typeerrors.d(44): Error: `int[5]` is not an expression
-fail_compilation/typeerrors.d(46): Error: variable `x` is used as a type
-fail_compilation/typeerrors.d(37): variable `x` is declared here
-fail_compilation/typeerrors.d(47): Error: cannot have associative array key of `void()`
-fail_compilation/typeerrors.d(48): Error: cannot have associative array key of `void`
-fail_compilation/typeerrors.d(49): Error: cannot have array of scope `typeerrors.C`
-fail_compilation/typeerrors.d(50): Error: cannot have associative array of `void`
-fail_compilation/typeerrors.d(51): Error: cannot have associative array of `void()`
-fail_compilation/typeerrors.d(53): Error: cannot have parameter of type `void`
-fail_compilation/typeerrors.d(55): Error: slice `[1..5]` is out of range of [0..4]
-fail_compilation/typeerrors.d(56): Error: slice `[2..1]` is out of range of [0..4]
+fail_compilation/typeerrors.d(42): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(45): Error: `int[5]` is not an expression
+fail_compilation/typeerrors.d(47): Error: variable `x` is used as a type
+fail_compilation/typeerrors.d(38): variable `x` is declared here
+fail_compilation/typeerrors.d(48): Error: cannot have associative array key of `void()`
+fail_compilation/typeerrors.d(49): Error: cannot have associative array key of `void`
+fail_compilation/typeerrors.d(50): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(51): Error: cannot have associative array of `void`
+fail_compilation/typeerrors.d(52): Error: cannot have associative array of `void()`
+fail_compilation/typeerrors.d(54): Error: cannot have parameter of type `void`
+fail_compilation/typeerrors.d(56): Error: slice `[1..5]` is out of range of [0..4]
+fail_compilation/typeerrors.d(57): Error: slice `[2..1]` is out of range of [0..4]
---
*/
/******************************************/
-scope class Foo
+class Foo
{
static int x;
int ax;
-scope class A2
+class A2
{
this()
{
int status3;
-scope class Parent3
+class Parent3
{
}
-scope class Child3 : Parent3
+class Child3 : Parent3
{
this(){
assert(status3==0);
}
{
S1* p = new S1();
- if (__ctfe)
+ if (__ctfe)
{
(*p).__dtor();
destroy(p);
class A1
{
- int opAdd(int i) { return 7 + i; }
+ int opBinary(string op)(int i) if (op == "+") { return 7 + i; }
+ alias opBinaryRight = opBinary;
}
void test1()
class A2
{
- int opDiv(int i) { return 9 + i; }
- int opDiv_r(int i) { return 17 + i; }
+ int opBinary(string op)(int i) if (op == "/") { return 9 + i; }
+ int opBinaryRight(string op)(int i) if (op == "/") { return 17 + i; }
}
void test2()
class C2
{
- int opAdd(D1 d) { return 1; }
- int opAdd(D2 d) { return 2; }
- int opAdd(D3 d) { return 3; }
- int opAdd(D4 d) { return 4; }
+ int opBinary(string op)(D1 d) if (op == "+") { return 1; }
+ int opBinary(string op)(D2 d) if (op == "+") { return 2; }
+ int opBinary(string op)(D3 d) if (op == "+") { return 3; }
+ int opBinary(string op)(D4 d) if (op == "+") { return 4; }
}
class C3
{
- int opAdd_r(D1 d) { return 5; }
- int opAdd_r(D2 d) { return 6; }
- int opAdd_r(D3 d) { return 7; }
- int opAdd_r(D4 d) { return 8; }
+ int opBinaryRight(string op)(D1 d) if (op == "+") { return 5; }
+ int opBinaryRight(string op)(D2 d) if (op == "+") { return 6; }
+ int opBinaryRight(string op)(D3 d) if (op == "+") { return 7; }
+ int opBinaryRight(string op)(D4 d) if (op == "+") { return 8; }
}
class C4
{
- int opAdd(D1 d) { return 9; }
- int opAdd(D2 d) { return 10; }
- int opAdd(D3 d) { return 11; }
- int opAdd(D4 d) { return 12; }
+ int opBinary(string op)(D1 d) if (op == "+") { return 9; }
+ int opBinary(string op)(D2 d) if (op == "+") { return 10; }
+ int opBinary(string op)(D3 d) if (op == "+") { return 11; }
+ int opBinary(string op)(D4 d) if (op == "+") { return 12; }
- int opAdd_r(D1 d) { return 13; }
- int opAdd_r(D2 d) { return 14; }
- int opAdd_r(D3 d) { return 15; }
- int opAdd_r(D4 d) { return 16; }
+ int opBinaryRight(string op)(D1 d) if (op == "+") { return 13; }
+ int opBinaryRight(string op)(D2 d) if (op == "+") { return 14; }
+ int opBinaryRight(string op)(D3 d) if (op == "+") { return 15; }
+ int opBinaryRight(string op)(D4 d) if (op == "+") { return 16; }
}
class D1
class D2
{
- int opAdd(C1 c) { return 17; }
- int opAdd(C2 d) { return 18; }
- int opAdd(C3 d) { return 19; }
- int opAdd(C4 d) { return 20; }
+ int opBinary(string op)(C1 d) if (op == "+") { return 17; }
+ int opBinary(string op)(C2 d) if (op == "+") { return 18; }
+ int opBinary(string op)(C3 d) if (op == "+") { return 19; }
+ int opBinary(string op)(C4 d) if (op == "+") { return 20; }
}
class D3
{
- int opAdd_r(C1 d) { return 21; }
- int opAdd_r(C2 d) { return 22; }
- int opAdd_r(C3 d) { return 23; }
- int opAdd_r(C4 d) { return 24; }
+ int opBinaryRight(string op)(C1 d) if (op == "+") { return 21; }
+ int opBinaryRight(string op)(C2 d) if (op == "+") { return 22; }
+ int opBinaryRight(string op)(C3 d) if (op == "+") { return 23; }
+ int opBinaryRight(string op)(C4 d) if (op == "+") { return 24; }
}
class D4
{
- int opAdd(C1 d) { return 25; }
- int opAdd(C2 d) { return 26; }
- int opAdd(C3 d) { return 27; }
- int opAdd(C4 d) { return 28; }
+ int opBinary(string op)(C1 d) if (op == "+") { return 25; }
+ int opBinary(string op)(C2 d) if (op == "+") { return 26; }
+ int opBinary(string op)(C3 d) if (op == "+") { return 27; }
+ int opBinary(string op)(C4 d) if (op == "+") { return 28; }
- int opAdd_r(C1 d) { return 29; }
- int opAdd_r(C2 d) { return 30; }
- int opAdd_r(C3 d) { return 31; }
- int opAdd_r(C4 d) { return 32; }
+ int opBinaryRight(string op)(C1 d) if (op == "+") { return 29; }
+ int opBinaryRight(string op)(C2 d) if (op == "+") { return 30; }
+ int opBinaryRight(string op)(C3 d) if (op == "+") { return 31; }
+ int opBinaryRight(string op)(C4 d) if (op == "+") { return 32; }
}
int i;
- version (ADD_R)
- {
//i = c1 + d1; assert(i == );
- i = c1 + d2; assert(i == 17);
+ //i = c1 + d2; assert(i == );
i = c1 + d3; assert(i == 21);
i = c1 + d4; assert(i == 29);
i = c2 + d1; assert(i == 1);
i = c2 + d2; assert(i == 2);
- i = c2 + d3; assert(i == 3);
- i = c2 + d4; assert(i == 4);
+ i = c2 + d3; assert(i == 22);
+ i = c2 + d4; assert(i == 30);
//i = c3 + d1; assert(i == );
- i = c3 + d2; assert(i == 19);
+ //i = c3 + d2; assert(i == );
i = c3 + d3; assert(i == 23);
i = c3 + d4; assert(i == 31);
i = c4 + d1; assert(i == 9);
i = c4 + d2; assert(i == 10);
- i = c4 + d3; assert(i == 11);
- i = c4 + d4; assert(i == 12);
+ i = c4 + d3; assert(i == 24);
+ i = c4 + d4; assert(i == 32);
//i = d1 + c1; assert(i == );
- i = d1 + c2; assert(i == 1);
+ //i = d1 + c2; assert(i == );
i = d1 + c3; assert(i == 5);
i = d1 + c4; assert(i == 13);
i = d2 + c1; assert(i == 17);
i = d2 + c2; assert(i == 18);
- i = d2 + c3; assert(i == 19);
- i = d2 + c4; assert(i == 20);
+ i = d2 + c3; assert(i == 6);
+ i = d2 + c4; assert(i == 14);
//i = d3 + c1; assert(i == );
- i = d3 + c2; assert(i == 3);
+ //i = d3 + c2; assert(i == );
i = d3 + c3; assert(i == 7);
i = d3 + c4; assert(i == 15);
i = d4 + c1; assert(i == 25);
i = d4 + c2; assert(i == 26);
- i = d4 + c3; assert(i == 27);
- i = d4 + c4; assert(i == 28);
- }
- else
- {
- //i = c1 + d1; assert(i == );
- i = c1 + d2; assert(i == 17);
-// i = c1 + d3; assert(i == 21);
- i = c1 + d4; assert(i == 29);
-
- i = c2 + d1; assert(i == 1);
- i = c2 + d2; assert(i == 2);
-// i = c2 + d3; assert(i == 3);
-// i = c2 + d4; assert(i == 4);
-
- //i = c3 + d1; assert(i == );
-// i = c3 + d2; printf("i = %d\n", i); assert(i == 19);
-// i = c3 + d3; assert(i == 23);
- i = c3 + d4; assert(i == 31);
-
- i = c4 + d1; assert(i == 9);
- i = c4 + d2; assert(i == 10);
-// i = c4 + d3; assert(i == 11);
-// i = c4 + d4; assert(i == 12);
-
- //i = d1 + c1; assert(i == );
- i = d1 + c2; assert(i == 1);
-// i = d1 + c3; assert(i == 5);
- i = d1 + c4; assert(i == 13);
-
- i = d2 + c1; assert(i == 17);
- i = d2 + c2; assert(i == 18);
-// i = d2 + c3; assert(i == 19);
-// i = d2 + c4; assert(i == 20);
-
- //i = d3 + c1; assert(i == );
-// i = d3 + c2; assert(i == 3);
-// i = d3 + c3; assert(i == 7);
- i = d3 + c4; assert(i == 15);
-
- i = d4 + c1; assert(i == 25);
- i = d4 + c2; assert(i == 26);
-// i = d4 + c3; assert(i == 27);
-// i = d4 + c4; assert(i == 28);
- }
+ i = d4 + c3; assert(i == 8);
+ i = d4 + c4; assert(i == 16);
}
/**************************************/
class A5
{
- int opNeg() { return 10; }
- int opCom() { return 11; }
- int opPostInc() { return 12; }
- int opPostDec() { return 13; }
-
- int opAdd(int j) { return 14; }
- int opSub(int j) { return 15; }
- int opSub_r(int j) { return 16; }
- int opMul(int j) { return 17; }
- int opDiv(int j) { return 18; }
- int opDiv_r(int j) { return 19; }
- int opMod(int j) { return 20; }
- int opMod_r(int j) { return 21; }
- int opAnd(int j) { return 22; }
- int opOr(int j) { return 23; }
- int opXor(int j) { return 24; }
- int opShl(int j) { return 25; }
- int opShl_r(int j) { return 26; }
- int opShr(int j) { return 27; }
- int opShr_r(int j) { return 28; }
- int opUShr(int j) { return 29; }
- int opUShr_r(int j) { return 30; }
- int opCat(int j) { return 31; }
- int opCat_r(int j) { return 32; }
+ int opUnary(string op)() if (op == "-") { return 10; }
+ int opUnary(string op)() if (op == "~") { return 11; }
+ int opUnary(string op)() if (op == "++") { return 12; }
+ int opUnary(string op)() if (op == "--") { return 13; }
+
+
+ int opBinary(string op)(int j) if (op == "+") { return 14; }
+ int opBinary(string op)(int j) if (op == "-") { return 15; }
+ int opBinaryRight(string op)(int j) if (op == "-") { return 16; }
+ int opBinary(string op)(int j) if (op == "*") { return 17; }
+ int opBinary(string op)(int j) if (op == "/") { return 18; }
+ int opBinaryRight(string op)(int j) if (op == "/") { return 19; }
+ int opBinary(string op)(int j) if (op == "%") { return 20; }
+ int opBinaryRight(string op)(int j) if (op == "%") { return 21; }
+ int opBinary(string op)(int j) if (op == "&") { return 22; }
+ int opBinary(string op)(int j) if (op == "|") { return 23; }
+ int opBinary(string op)(int j) if (op == "^") { return 24; }
+ int opBinary(string op)(int j) if (op == "<<") { return 25; }
+ int opBinaryRight(string op)(int j) if (op == "<<") { return 26; }
+ int opBinary(string op)(int j) if (op == ">>") { return 27; }
+ int opBinaryRight(string op)(int j) if (op == ">>") { return 28; }
+ int opBinary(string op)(int j) if (op == ">>>") { return 29; }
+ int opBinaryRight(string op)(int j) if (op == ">>>") { return 30; }
+ int opBinary(string op)(int j) if (op == "~") { return 31; }
+ int opBinaryRight(string op)(int j) if (op == "~") { return 32; }
int opEquals(int j) { return 33; }
int opCmp(int j) { return 34; }
- int opAddAssign(int j) { return 35; }
- int opSubAssign(int j) { return 36; }
- int opMulAssign(int j) { return 37; }
- int opDivAssign(int j) { return 38; }
- int opModAssign(int j) { return 39; }
- int opAndAssign(int j) { return 40; }
- int opOrAssign(int j) { return 41; }
- int opXorAssign(int j) { return 42; }
- int opShlAssign(int j) { return 43; }
- int opShrAssign(int j) { return 44; }
- int opUShrAssign(int j) { return 45; }
- int opCatAssign(int j) { return 46; }
+ int opOpAssign(string op)(int j) if (op == "+") { return 35; }
+ int opOpAssign(string op)(int j) if (op == "-") { return 36; }
+ int opOpAssign(string op)(int j) if (op == "*") { return 37; }
+ int opOpAssign(string op)(int j) if (op == "/") { return 38; }
+ int opOpAssign(string op)(int j) if (op == "%") { return 39; }
+ int opOpAssign(string op)(int j) if (op == "&") { return 40; }
+ int opOpAssign(string op)(int j) if (op == "|") { return 41; }
+ int opOpAssign(string op)(int j) if (op == "^") { return 42; }
+ int opOpAssign(string op)(int j) if (op == "<<") { return 43; }
+ int opOpAssign(string op)(int j) if (op == ">>") { return 44; }
+ int opOpAssign(string op)(int j) if (op == ">>>") { return 45; }
+ int opOpAssign(string op)(int j) if (op == "~") { return 46; }
}
void test5()
i = ~a;
assert(i == 11);
- i = a++;
+ i = ++a;
assert(i == 12);
- i = a--;
+ i = --a;
assert(i == 13);
i = a + 1;
i = (a += 1);
assert(i == 35);
- i = ++a;
- assert(i == 35);
i = (a -= 1);
assert(i == 36);
- i = --a;
- assert(i == 36);
i = (a *= 1);
assert(i == 37);
struct A6
{
- int opNeg() { return 10; }
- int opCom() { return 11; }
- int opPostInc() { return 12; }
- int opPostDec() { return 13; }
-
- int opAdd(int j) { return 14; }
- int opSub(int j) { return 15; }
- int opSub_r(int j) { return 16; }
- int opMul(int j) { return 17; }
- int opDiv(int j) { return 18; }
- int opDiv_r(int j) { return 19; }
- int opMod(int j) { return 20; }
- int opMod_r(int j) { return 21; }
- int opAnd(int j) { return 22; }
- int opOr(int j) { return 23; }
- int opXor(int j) { return 24; }
- int opShl(int j) { return 25; }
- int opShl_r(int j) { return 26; }
- int opShr(int j) { return 27; }
- int opShr_r(int j) { return 28; }
- int opUShr(int j) { return 29; }
- int opUShr_r(int j) { return 30; }
- int opCat(int j) { return 31; }
- int opCat_r(int j) { return 32; }
- int opEquals(int j) { return 33; }
+ int opUnary(string op)() if (op == "-") { return 10; }
+ int opUnary(string op)() if (op == "~") { return 11; }
+ int opUnary(string op)() if (op == "++") { return 12; }
+ int opUnary(string op)() if (op == "--") { return 13; }
+
+ int opBinary(string op)(int j) if (op == "+") { return 14; }
+ int opBinary(string op)(int j) if (op == "-") { return 15; }
+ int opBinaryRight(string op)(int j) if (op == "-") { return 16; }
+ int opBinary(string op)(int j) if (op == "*") { return 17; }
+ int opBinary(string op)(int j) if (op == "/") { return 18; }
+ int opBinaryRight(string op)(int j) if (op == "/") { return 19; }
+ int opBinary(string op)(int j) if (op == "%") { return 20; }
+ int opBinaryRight(string op)(int j) if (op == "%") { return 21; }
+ int opBinary(string op)(int j) if (op == "&") { return 22; }
+ int opBinary(string op)(int j) if (op == "|") { return 23; }
+ int opBinary(string op)(int j) if (op == "^") { return 24; }
+ int opBinary(string op)(int j) if (op == "<<") { return 25; }
+ int opBinaryRight(string op)(int j) if (op == "<<") { return 26; }
+ int opBinary(string op)(int j) if (op == ">>") { return 27; }
+ int opBinaryRight(string op)(int j) if (op == ">>") { return 28; }
+ int opBinary(string op)(int j) if (op == ">>>") { return 29; }
+ int opBinaryRight(string op)(int j) if (op == ">>>") { return 30; }
+ int opBinary(string op)(int j) if (op == "~") { return 31; }
+ int opBinaryRight(string op)(int j) if (op == "~") { return 32; }
+ int opEquals(int j) { return 33; }
const bool opEquals(const ref A6) { return false; }
int opCmp(int j) { return 34; }
- int opAddAssign(int j) { return 35; }
- int opSubAssign(int j) { return 36; }
- int opMulAssign(int j) { return 37; }
- int opDivAssign(int j) { return 38; }
- int opModAssign(int j) { return 39; }
- int opAndAssign(int j) { return 40; }
- int opOrAssign(int j) { return 41; }
- int opXorAssign(int j) { return 42; }
- int opShlAssign(int j) { return 43; }
- int opShrAssign(int j) { return 44; }
- int opUShrAssign(int j) { return 45; }
- int opCatAssign(int j) { return 46; }
+ int opOpAssign(string op)(int j) if (op == "+") { return 35; }
+ int opOpAssign(string op)(int j) if (op == "-") { return 36; }
+ int opOpAssign(string op)(int j) if (op == "*") { return 37; }
+ int opOpAssign(string op)(int j) if (op == "/") { return 38; }
+ int opOpAssign(string op)(int j) if (op == "%") { return 39; }
+ int opOpAssign(string op)(int j) if (op == "&") { return 40; }
+ int opOpAssign(string op)(int j) if (op == "|") { return 41; }
+ int opOpAssign(string op)(int j) if (op == "^") { return 42; }
+ int opOpAssign(string op)(int j) if (op == "<<") { return 43; }
+ int opOpAssign(string op)(int j) if (op == ">>") { return 44; }
+ int opOpAssign(string op)(int j) if (op == ">>>") { return 45; }
+ int opOpAssign(string op)(int j) if (op == "~") { return 46; }
}
void test6()
i = ~a;
assert(i == 11);
- i = a++;
+ i = ++a;
assert(i == 12);
- i = a--;
+ i = --a;
assert(i == 13);
i = a + 1;
i = (a += 1);
assert(i == 35);
- i = ++a;
- assert(i == 35);
i = (a -= 1);
assert(i == 36);
- i = --a;
- assert(i == 36);
i = (a *= 1);
assert(i == 37);
interface IWriter
{
- int opShl (string i);
- int opShl (int i);
+ int opBinary(string op)(string i) if (op == "<<");
+ int opBinary(string op)(int i) if (op == "<<");
}
class Writer : IWriter
{
- int opShl (string i)
+ int opBinary(string op)(string i) if (op == "<<")
{
printf("Writer.opShl(char[])\n");
return 1;
}
- int opShl (int i)
+ int opBinary(string op)(int i) if (op == "<<")
{
printf("Writer.opShl(int)\n");
return 2;
class BinaryWriter : Writer
{
- alias Writer.opShl opShl;
+ int opBinary(string op)(string i) if (op == "<<")
+ {
+ printf("Writer.opShl(char[])\n");
+ return 1;
+ }
- override int opShl (int i)
+ int opBinary(string op)(int i) if (op == "<<")
{
printf("BinaryWriter.opShl(int)\n");
return 3;
class A10
{
- int opAdd(int i) { return i + 1; }
+ int opBinary(string op)(int i) if (op == "+") { return i + 1; }
+ alias opBinaryRight = opBinary;
}
class B10
{
- int opAdd_r(A10 a) { return 3; }
+ int opBinaryRight(string op)(A10 a) if (op == "+") { return 3; }
+ alias opBinary = opBinaryRight;
}
void test10()
class A13
{
- A13 opShl(int x)
+ A13 opBinary(string op)(int x) if (op == "<<")
{
printf("A::opShl(int %d)\n", x);
printf("%d",x);
return this;
}
- A13 opShl(string x)
+ A13 opBinary(string op)(string x) if (op == "<<")
{
printf("A::opShl(char[])\n");
printf("%.*s", cast(int)x.length, x.ptr);
class B13
{
- A13 opShl_r(A13 a)
+ A13 opBinaryRight(string op)(A13 a) if (op == "<<")
{
printf("B::opShl_r(A)\n");
return a;
class Foo14
{ int a;
- int opIn(int x)
+ int opBinary(string op)(int x) if (op == "in")
{
return a + x;
}
float x = 0, y = 0;
}
-struct Vec12778Y
-{
- Vec12778Y opAdd()(Vec12778Y b) const
- {
- enum op = "+";
- mixin("return Vec12778Y(this.x " ~ op ~ " b.x, this.y " ~ op ~ " b.y);");
- }
- alias opAdd_r = opAdd;
-
- float x = 0, y = 0;
-}
-
void test12778()
{
struct S
void test1()
{
Vec12778X vx = vx1 + vx2; // ok
- Vec12778Y vy = vy1 + vy2; // ok
}
void test2() const
{
Vec12778X vx = vx1 + vx2; // ok <- error
- Vec12778Y vy = vy1 + vy2; // ok <- error
}
Vec12778X vx1, vx2;
- Vec12778Y vy1, vy2;
}
}
int i;
immutable(Object) o;
- void opAddAssign(int j) { i += j; }
- S14343b opPostInc() { ++i; return this; }
+ void opOpAssign(string op)(int j) if (op == "+") { i += j; }
+ S14343b opUnary(string op)() if (op == "++") { ++i; return this; }
void opAssign(S14343b other) {}
}
-// REQUIRED_ARGS: -w -de
+// REQUIRED_ARGS: -w -dw
// PERMUTE_ARGS:
+/* TEST_OUTPUT:
+---
+runnable/sctor2.d(12): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
+---
+*/
/***************************************************/
// 15665
+++ /dev/null
-
-interface IObject
-{
- size_t toHash() @trusted nothrow;
-}
-
-interface Dummy {}
-interface Bug(E) : Dummy, IObject {}
-interface OK(E) : IObject, Dummy {}
-
-void main()
-{
-
- {
- Bug!string s;
- size_t t = hashOf(s);
- }
- {
- OK!string s;
- size_t t = hashOf(s);
- }
-
- static assert(is(immutable Bug!string* : immutable IObject*));
- static assert(is(immutable OK!string* : immutable IObject*));
-}
// derived class to const(base interface) in tail
interface I {}
class X : I {}
- static assert(is( X[] : const(I)[] ));
+ static assert(!is( X[] : const(I)[] ));
// interface to const(base interface) in tail
interface J {}
interface K : I, J {}
static assert( is( K[] : const(I)[] )); // OK, runtime offset is same
- static assert(is( K[] : const(J)[] )); // !? NG, runtime offset is different
+ static assert(!is( K[] : const(J)[] )); // NG, runtime offset is different
}
/************************************/
tuple(get, get)
tuple(clear)
tuple(draw, draw)
-runnable/xtest46.d(149): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(151): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(152): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(154): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(181): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(183): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(184): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(186): Deprecation: `opDot` is deprecated. Use `alias this`
const(int)
string[]
double[]
S6 s;
int b = 7;
- S6* opDot() return
- {
- return &s;
- }
+ alias s this;
}
void test6()
S7 s;
int b = 7;
- S7* opDot()
- {
- return &s;
- }
+ alias s this;
}
void test7()
tuple(get, get)
tuple(clear)
tuple(draw, draw)
-runnable/xtest46_gc.d-mixin-$n$(185): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(187): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(188): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(190): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(217): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(219): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(220): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(222): Deprecation: `opDot` is deprecated. Use `alias this`
const(int)
string[]
double[]
-0316b981e5f2fa1525e893c5d94c59c847a8c386
+26b581670ef6e2643d74078f200d1cd21fa40e90
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
size_t cntWords = lastWord - firstWord;
copyWordsShifted(firstWord, cntWords, firstOff, source);
- wordtype src = (source[cntWords - 1] >> (BITS_PER_WORD - firstOff)) | (source[cntWords] << firstOff);
+ wordtype src = (source[cntWords - 1] >> (BITS_PER_WORD - firstOff));
+ if (lastOff >= firstOff) // prevent buffer overread
+ src |= (source[cntWords] << firstOff);
wordtype mask = (BITS_2 << lastOff) - 1;
data[lastWord] = (data[lastWord] & ~mask) | (src & mask);
}
alias ddoc_long = int;
alias ddoc_ulong = uint;
}
- struct ddoc_complex(T) { T re; T im; };
+ struct ddoc_complex(T) { T re; T im; }
}
/***
// https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/sparc/fpu/bits/fenv.h
else version (SPARC_Any)
{
+ import core.stdc.config : c_ulong;
+
alias fenv_t = c_ulong;
alias fexcept_t = c_ulong;
}
nothrow:
@nogc:
-// These are defined the same way as D basic types, so the definition is
-// platform-independant
-alias int8_t = byte; ///
-alias int16_t = short; ///
-alias uint8_t = ubyte; ///
-alias uint16_t = ushort; ///
-
-// 32 bit types and need to be defined on-platform basis, because
-// they might have C++ binary mangling of `int` or `long`.
-// 64-bit types respectively might be mangled as `long` or `long long`
-
-// It would seem correct to define intmax_t and uintmax_t here, but C and C++
-// compilers don't in practice always set them to the maximum supported value.
-// See https://quuxplusone.github.io/blog/2019/02/28/is-int128-integral/
+
static if (is(ucent))
{
alias int128_t = cent; ///
version (Windows)
{
+ alias int8_t = byte; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
version (CRuntime_DigitalMars)
{
alias int32_t = cpp_long; ///
alias int64_t = long; ///
alias uint64_t = ulong; ///
- alias int_least8_t = byte; ///
- alias uint_least8_t = ubyte; ///
- alias int_least16_t = short; ///
- alias uint_least16_t = ushort; ///
- alias int_least32_t = int32_t; ///
+ alias int_least8_t = byte; ///
+ alias uint_least8_t = ubyte; ///
+ alias int_least16_t = short; ///
+ alias uint_least16_t = ushort; ///
+ alias int_least32_t = int32_t; ///
alias uint_least32_t = uint32_t; ///
- alias int_least64_t = long; ///
- alias uint_least64_t = ulong; ///
+ alias int_least64_t = long; ///
+ alias uint_least64_t = ulong; ///
- alias int_fast8_t = byte; ///
- alias uint_fast8_t = ubyte; ///
- alias int_fast16_t = int; ///
- alias uint_fast16_t = uint; ///
- alias int_fast32_t = int32_t; ///
+ alias int_fast8_t = byte; ///
+ alias uint_fast8_t = ubyte; ///
+ version (MinGW)
+ {
+ alias int_fast16_t = short; ///
+ alias uint_fast16_t = ushort; ///
+ }
+ else
+ {
+ alias int_fast16_t = int; ///
+ alias uint_fast16_t = uint; ///
+ }
+ alias int_fast32_t = int32_t; ///
alias uint_fast32_t = uint32_t; ///
- alias int_fast64_t = long; ///
- alias uint_fast64_t = ulong; ///
+ alias int_fast64_t = long; ///
+ alias uint_fast64_t = ulong; ///
alias intptr_t = ptrdiff_t; ///
alias uintptr_t = size_t; ///
}
else version (Darwin)
{
+ alias int8_t = byte; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
alias int32_t = int; ///
alias uint32_t = uint; ///
alias int64_t = cpp_longlong; ///
alias intmax_t = long; ///
alias uintmax_t = ulong; ///
}
-else version (Posix)
+else version (linux)
{
- alias int32_t = int; ///
- alias uint32_t = uint; ///
- alias int64_t = long; ///
- alias uint64_t = ulong; ///
-
- alias int_least8_t = byte; ///
- alias uint_least8_t = ubyte; ///
- alias int_least16_t = short; ///
+ alias int8_t = byte; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
+ alias int32_t = int; ///
+ alias uint32_t = uint; ///
+ alias int64_t = long; ///
+ alias uint64_t = ulong; ///
+
+ alias int_least8_t = byte; ///
+ alias uint_least8_t = ubyte; ///
+ alias int_least16_t = short; ///
alias uint_least16_t = ushort; ///
- alias int_least32_t = int; ///
- alias uint_least32_t = uint; ///
- alias int_least64_t = long; ///
- alias uint_least64_t = ulong;///
+ alias int_least32_t = int; ///
+ alias uint_least32_t = uint; ///
+ alias int_least64_t = long; ///
+ alias uint_least64_t = ulong; ///
- version (FreeBSD)
- {
- alias int_fast8_t = int; ///
- alias uint_fast8_t = uint; ///
- alias int_fast16_t = int; ///
- alias uint_fast16_t = uint; ///
- alias int_fast32_t = int; ///
- alias uint_fast32_t = uint; ///
- }
- else version (CRuntime_Musl)
+ version (CRuntime_Musl)
{
alias int_fast8_t = byte; ///
alias uint_fast8_t = ubyte; ///
alias int_fast32_t = ptrdiff_t; ///
alias uint_fast32_t = size_t; ///
}
- alias int_fast64_t = long; ///
+ alias int_fast64_t = long; ///
+ alias uint_fast64_t = ulong; ///
+
+ alias intptr_t = ptrdiff_t; ///
+ alias uintptr_t = size_t; ///
+ alias intmax_t = long; ///
+ alias uintmax_t = ulong; ///
+}
+else version (CRuntime_Glibc)
+{
+ alias int8_t = byte; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
+ alias int32_t = int; ///
+ alias uint32_t = uint; ///
+ alias int64_t = long; ///
+ alias uint64_t = ulong; ///
+
+ alias int_least8_t = byte; ///
+ alias uint_least8_t = ubyte; ///
+ alias int_least16_t = short; ///
+ alias uint_least16_t = ushort; ///
+ alias int_least32_t = int; ///
+ alias uint_least32_t = uint; ///
+ alias int_least64_t = long; ///
+ alias uint_least64_t = ulong; ///
+
+ alias int_fast8_t = byte; ///
+ alias uint_fast8_t = ubyte; ///
+ alias int_fast16_t = ptrdiff_t; ///
+ alias uint_fast16_t = size_t; ///
+ alias int_fast32_t = ptrdiff_t; ///
+ alias uint_fast32_t = size_t; ///
+ alias int_fast64_t = long; ///
+ alias uint_fast64_t = ulong; ///
+
+ alias intptr_t = ptrdiff_t; ///
+ alias uintptr_t = size_t; ///
+ alias intmax_t = long; ///
+ alias uintmax_t = ulong; ///
+}
+else version (DragonFlyBSD)
+{
+ alias int8_t = byte; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
+ alias int32_t = int; ///
+ alias uint32_t = uint; ///
+ alias int64_t = long; ///
+ alias uint64_t = ulong; ///
+
+ alias int_least8_t = int8_t; ///
+ alias uint_least8_t = uint8_t; ///
+ alias int_least16_t = int16_t; ///
+ alias uint_least16_t = uint16_t; ///
+ alias int_least32_t = int32_t; ///
+ alias uint_least32_t = uint32_t; ///
+ alias int_least64_t = int64_t; ///
+ alias uint_least64_t = uint64_t; ///
+
+ alias int_fast8_t = int32_t; ///
+ alias uint_fast8_t = uint32_t; ///
+ alias int_fast16_t = int32_t; ///
+ alias uint_fast16_t = uint32_t; ///
+ alias int_fast32_t = int32_t; ///
+ alias uint_fast32_t = uint32_t; ///
+ alias int_fast64_t = int64_t; ///
+ alias uint_fast64_t = uint64_t; ///
+
+ alias intptr_t = ptrdiff_t; ///
+ alias uintptr_t = size_t; ///
+ alias intmax_t = long; ///
+ alias uintmax_t = ulong; ///
+}
+else version (FreeBSD)
+{
+ alias int8_t = byte; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
+ alias int32_t = int; ///
+ alias uint32_t = uint; ///
+ alias int64_t = long; ///
+ alias uint64_t = ulong; ///
+
+ alias int_least8_t = byte; ///
+ alias uint_least8_t = ubyte; ///
+ alias int_least16_t = short; ///
+ alias uint_least16_t = ushort; ///
+ alias int_least32_t = int; ///
+ alias uint_least32_t = uint; ///
+ alias int_least64_t = long; ///
+ alias uint_least64_t = ulong; ///
+
+ alias int_fast8_t = int; ///
+ alias uint_fast8_t = uint; ///
+ alias int_fast16_t = int; ///
+ alias uint_fast16_t = uint; ///
+ alias int_fast32_t = int; ///
+ alias uint_fast32_t = uint; ///
+ alias int_fast64_t = long; ///
alias uint_fast64_t = ulong; ///
alias intptr_t = ptrdiff_t; ///
- alias uintptr_t = size_t; ///
- alias intmax_t = long; ///
- alias uintmax_t = ulong; ///
+ alias uintptr_t = size_t; ///
+ alias intmax_t = long; ///
+ alias uintmax_t = ulong; ///
+}
+else version (NetBSD)
+{
+ alias int8_t = byte; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
+ alias int32_t = int; ///
+ alias uint32_t = uint; ///
+ alias int64_t = long; ///
+ alias uint64_t = ulong; ///
+
+ alias int_least8_t = int8_t; ///
+ alias uint_least8_t = uint8_t; ///
+ alias int_least16_t = int16_t; ///
+ alias uint_least16_t = uint16_t; ///
+ alias int_least32_t = int32_t; ///
+ alias uint_least32_t = uint32_t; ///
+ alias int_least64_t = int64_t; ///
+ alias uint_least64_t = uint64_t; ///
+
+ alias int_fast8_t = int32_t; ///
+ alias uint_fast8_t = uint32_t; ///
+ alias int_fast16_t = int32_t; ///
+ alias uint_fast16_t = uint32_t; ///
+ alias int_fast32_t = int32_t; ///
+ alias uint_fast32_t = uint32_t; ///
+ alias int_fast64_t = int64_t; ///
+ alias uint_fast64_t = uint64_t; ///
+
+ alias intptr_t = ptrdiff_t; ///
+ alias uintptr_t = size_t; ///
+ alias intmax_t = long; ///
+ alias uintmax_t = ulong; ///
+}
+else version (OpenBSD)
+{
+ alias int8_t = byte; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
+ alias int32_t = int; ///
+ alias uint32_t = uint; ///
+ alias int64_t = cpp_longlong; ///
+ alias uint64_t = cpp_ulonglong; ///
+
+ alias int_least8_t = byte; ///
+ alias uint_least8_t = ubyte; ///
+ alias int_least16_t = short; ///
+ alias uint_least16_t = ushort; ///
+ alias int_least32_t = int; ///
+ alias uint_least32_t = uint; ///
+ alias int_least64_t = cpp_longlong; ///
+ alias uint_least64_t = cpp_ulonglong; ///
+
+ alias int_fast8_t = int; ///
+ alias uint_fast8_t = uint; ///
+ alias int_fast16_t = int; ///
+ alias uint_fast16_t = uint; ///
+ alias int_fast32_t = int; ///
+ alias uint_fast32_t = uint; ///
+ alias int_fast64_t = cpp_longlong; ///
+ alias uint_fast64_t = cpp_ulonglong; ///
+
+ alias intptr_t = cpp_long; ///
+ alias uintptr_t = cpp_ulong; ///
+ alias intmax_t = cpp_longlong; ///
+ alias uintmax_t = cpp_ulonglong; ///
+}
+else version (Solaris)
+{
+ alias int8_t = char; ///
+ alias int16_t = short; ///
+ alias uint8_t = ubyte; ///
+ alias uint16_t = ushort; ///
+ alias int32_t = int; ///
+ alias uint32_t = uint; ///
+ alias int64_t = long; ///
+ alias uint64_t = ulong; ///
+
+ alias int_least8_t = char; ///
+ alias uint_least8_t = ubyte; ///
+ alias int_least16_t = short; ///
+ alias uint_least16_t = ushort; ///
+ alias int_least32_t = int; ///
+ alias uint_least32_t = uint; ///
+ alias int_least64_t = long; ///
+ alias uint_least64_t = ulong; ///
+
+ alias int_fast8_t = char; ///
+ alias uint_fast8_t = ubyte; ///
+ alias int_fast16_t = int; ///
+ alias uint_fast16_t = uint; ///
+ alias int_fast32_t = int; ///
+ alias uint_fast32_t = uint; ///
+ alias int_fast64_t = long; ///
+ alias uint_fast64_t = ulong; ///
+
+ alias intptr_t = ptrdiff_t; ///
+ alias uintptr_t = size_t; ///
+ alias intmax_t = long; ///
+ alias uintmax_t = ulong; ///
}
else
{
- static assert(0);
+ static assert(false, "Unsupported architecture.");
}
struct nothrow_t {}
///
- enum align_val_t : size_t { defaultAlignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__ };
+ enum align_val_t : size_t { defaultAlignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__ }
///
class bad_alloc : exception
extern (C) nothrow @nogc:
@system:
+import core.sys.windows.stdc.time;
+
// Posix version is in core.sys.posix.sys.stat
enum S_IFMT = 0xF000;
int S_ISCHR(int m) { return (m & S_IFMT) == S_IFCHR; }
}
-struct struct_stat
+version (CRuntime_DigitalMars)
{
- short st_dev;
- ushort st_ino;
- ushort st_mode;
- short st_nlink;
- ushort st_uid;
- ushort st_gid;
- short st_rdev;
- short dummy;
- int st_size;
- int st_atime;
- int st_mtime;
- int st_ctime;
+ struct struct_stat
+ {
+ short st_dev;
+ ushort st_ino;
+ ushort st_mode;
+ short st_nlink;
+ ushort st_uid;
+ ushort st_gid;
+ short st_rdev;
+ short dummy;
+ int st_size;
+ time_t st_atime;
+ time_t st_mtime;
+ time_t st_ctime;
+ }
+
+ int stat(const(char)*, struct_stat *);
+ int fstat(int, struct_stat *) @trusted;
+ int _wstat(const(wchar)*, struct_stat *);
}
+else version (CRuntime_Microsoft)
+{
+ struct struct_stat
+ {
+ uint st_dev;
+ ushort st_ino;
+ ushort st_mode;
+ short st_nlink;
+ short st_uid;
+ short st_gid;
+ uint st_rdev;
+ int st_size;
+ time_t st_atime;
+ time_t st_mtime;
+ time_t st_ctime;
+ }
-int stat(const(char)*, struct_stat *);
-int fstat(int, struct_stat *) @trusted;
-int _wstat(const(wchar)*, struct_stat *);
+ // These assume time_t is 32 bits (which druntime's definition currently is)
+ // Add pragma(mangle) to use _stat64 etc. when time_t is made 64-bit
+ // See also: https://issues.dlang.org/show_bug.cgi?id=21134
+ int stat(const(char)*, struct_stat *);
+ int fstat(int, struct_stat *) @trusted;
+ int _wstat(const(wchar)*, struct_stat *);
+}
foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
{
case T.sizeof:
- (cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr;
- return result;
+ if (tinext.talign % T.alignof == 0)
+ {
+ (cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr;
+ return result;
+ }
+ goto default;
}
default:
if (tiSize)
{
- *cast(TypeInfo*)(p + itemSize) = null; // the GC might not have cleared this area
+ // the GC might not have cleared the padding area in the block
+ *cast(TypeInfo*)(p + (itemSize & ~(size_t.sizeof - 1))) = null;
*cast(TypeInfo*)(p + blkInf.size - tiSize) = cast() ti;
}
-a1f8c4c0700ce4e256f4130ad7883c6ea3890901
+16cb085b584f100fa677e2e64ff6b6dbb4921ad1
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
r = ranges[i].save; // rollover
}
}
- @property Result save() scope return
+ @property Result save() return scope
{
Result copy = this;
foreach (i, r; ranges)
size_t bitCount;
foreach (i; 0 .. fullWords)
bitCount += countBitsSet(_ptr[i]);
- bitCount += countBitsSet(_ptr[fullWords] & endMask);
+ if (endBits)
+ bitCount += countBitsSet(_ptr[fullWords] & endMask);
return bitCount;
}
else
duration = The duration which separates each successive time point in
the range.
+/
-TP delegate(scope const TP) everyDuration(TP, Direction dir = Direction.fwd, D)(D duration) nothrow
+TP delegate(return scope const TP) everyDuration(TP, Direction dir = Direction.fwd, D)(D duration) nothrow
if (isTimePoint!TP &&
__traits(compiles, TP.init + duration) &&
(dir == Direction.fwd || dir == Direction.bwd))
{
- TP func(scope const TP tp)
+ TP func(return scope const TP tp)
{
static if (dir == Direction.fwd)
return tp + duration;
duration = The $(REF Duration, core,time) to add to or subtract from
this $(LREF SysTime).
+/
- SysTime opBinary(string op)(Duration duration) @safe const pure nothrow scope
+ SysTime opBinary(string op)(Duration duration) @safe const pure nothrow return scope
if (op == "+" || op == "-")
{
SysTime retval = SysTime(this._stdTime, this._timezone);
$(LREF SysTime) for the last day in the month that this Date is in.
The time portion of endOfMonth is always 23:59:59.9999999.
+/
- @property SysTime endOfMonth() @safe const nothrow scope
+ @property SysTime endOfMonth() @safe const nothrow return scope
{
immutable hnsecs = adjTime;
immutable days = getUnitsFromHNSecs!"days"(hnsecs);
AlignedMallocator.instance.alignedReallocate(c, 32, 32);
assert(c.ptr);
+ version (LDC_AddressSanitizer) {} else // AddressSanitizer does not support such large memory allocations (0x10000000000 max)
version (DragonFlyBSD) {} else /* FIXME: Malloc on DragonFly does not return NULL when allocating more than UINTPTR_MAX
* $(LINK: https://bugs.dragonflybsd.org/issues/3114, dragonfly bug report)
* $(LINK: https://github.com/dlang/druntime/pull/1999#discussion_r157536030, PR Discussion) */
static assert(! is(typeof(dg_xtrnC) == typeof(dg_xtrnD)));
}
}
+
+// Converts an unsigned integer to a compile-time string constant.
+private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
+
+// Check that .stringof does what we expect, since it's not guaranteed by the
+// language spec.
+@safe unittest
+{
+ assert(toCtString!0 == "0");
+ assert(toCtString!123456 == "123456");
+}
+
+/**
+ * Passes the fields of a struct as arguments to a function.
+ *
+ * Can be used with a $(LINK2 https://dlang.org/spec/expression.html#function_literals,
+ * function literal) to give temporary names to the fields of a struct or
+ * tuple.
+ *
+ * Params:
+ * fun = Callable that the struct's fields will be passed to.
+ *
+ * Returns:
+ * A function that accepts a single struct as an argument and passes its
+ * fields to `fun` when called.
+ */
+template bind(alias fun)
+{
+ /**
+ * Params:
+ * args = The struct or tuple whose fields will be used as arguments.
+ *
+ * Returns: `fun(args.tupleof)`
+ */
+ auto ref bind(T)(auto ref T args)
+ if (is(T == struct))
+ {
+ import std.meta : Map = staticMap;
+ import core.lifetime : move;
+
+ // Forwards the i'th member of `args`
+ // Needed because core.lifetime.forward doesn't work on struct members
+ template forwardArg(size_t i)
+ {
+ static if (__traits(isRef, args) || !is(typeof(move(args.tupleof[i]))))
+ enum forwardArg = "args.tupleof[" ~ toCtString!i ~ "], ";
+ else
+ enum forwardArg = "move(args.tupleof[" ~ toCtString!i ~ "]), ";
+ }
+
+ static if (args.tupleof.length == 0)
+ enum argList = "";
+ else
+ alias argList = Map!(forwardArg, Iota!(args.tupleof.length));
+
+ return mixin("fun(", argList, ")");
+ }
+}
+
+/// Giving names to tuple elements
+@safe unittest
+{
+ import std.typecons : tuple;
+
+ auto name = tuple("John", "Doe");
+ string full = name.bind!((first, last) => first ~ " " ~ last);
+ assert(full == "John Doe");
+}
+
+/// Passing struct fields to a function
+@safe unittest
+{
+ import std.algorithm.comparison : min, max;
+
+ struct Pair
+ {
+ int a;
+ int b;
+ }
+
+ auto p = Pair(123, 456);
+ assert(p.bind!min == 123); // min(p.a, p.b)
+ assert(p.bind!max == 456); // max(p.a, p.b)
+}
+
+/// In a range pipeline
+@safe unittest
+{
+ import std.algorithm.iteration : map, filter;
+ import std.algorithm.comparison : equal;
+ import std.typecons : tuple;
+
+ auto ages = [
+ tuple("Alice", 35),
+ tuple("Bob", 64),
+ tuple("Carol", 21),
+ tuple("David", 39),
+ tuple("Eve", 50)
+ ];
+
+ auto overForty = ages
+ .filter!(bind!((name, age) => age > 40))
+ .map!(bind!((name, age) => name));
+
+ assert(overForty.equal(["Bob", "Eve"]));
+}
+
+// Zero arguments
+@safe unittest
+{
+ struct Empty {}
+
+ assert(Empty().bind!(() => 123) == 123);
+}
+
+// Non-copyable arguments
+@safe unittest
+{
+ import std.typecons : tuple;
+
+ static struct NoCopy
+ {
+ int n;
+ @disable this(this);
+ }
+
+ static struct Pair
+ {
+ NoCopy a, b;
+ }
+
+ static auto fun(NoCopy a, NoCopy b)
+ {
+ return tuple(a.n, b.n);
+ }
+
+ auto expected = fun(NoCopy(1), NoCopy(2));
+ assert(Pair(NoCopy(1), NoCopy(2)).bind!fun == expected);
+}
+
+// ref arguments
+@safe unittest
+{
+ import std.typecons : tuple;
+
+ auto t = tuple(123, 456);
+ t.bind!((ref int a, int b) { a = 789; b = 1011; });
+
+ assert(t[0] == 789);
+ assert(t[1] == 456);
+}
+
+// auto ref arguments
+@safe unittest
+{
+ import std.typecons : tuple;
+
+ auto t = tuple(123);
+ t.bind!((auto ref x) {
+ static assert(__traits(isRef, x));
+ });
+ tuple(123).bind!((auto ref x) {
+ static assert(!__traits(isRef, x));
+ });
+}
License: Boost License 1.0
Authors: Paul Backus
+Source: $(PHOBOSSRC std/sumtype.d)
+/
module std.sumtype;
assert("ë"w.decode(i) == 'ë' && i == 1);
}
+@safe pure unittest // https://issues.dlang.org/show_bug.cgi?id=22867
+{
+ import std.conv : hexString;
+ string data = hexString!"f787a598";
+ size_t offset = 0;
+ try data.decode(offset);
+ catch (UTFException ex) assert(offset == 0);
+}
+
/++
`decodeFront` is a variant of $(LREF decode) which specifically decodes
the first code point. Unlike $(LREF decode), `decodeFront` accepts any
}
}
- index += i + 1;
static if (i == 3)
{
if (d > dchar.max)
throw invalidUTF();
}
}
+
+ index += i + 1;
return d;
}
}