d: Merge upstream dmd 2503f17e5, phobos a74fa63e6.
D front-end changes: - Import dmd mainline development. - Removed internal d_intN and d_unsN aliases to stdint types, which caused a regression on Solaris where int8_t is a char (PR104911). Phobos changes: - Import phobos mainline development. PR d/104911 gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 2503f17e5. * d-convert.cc (convert_expr): Replace d_uns64 with dinteger_t. * d-lang.cc: Remove dmd/root/file.h include. (d_handle_option): Update for new front-end interface. (d_parse_file): Likewise. libphobos/ChangeLog: * src/MERGE: Merge upstream phobos a74fa63e6.
This commit is contained in:
parent
4a3073f04e
commit
fbdaa58162
78 changed files with 1098 additions and 744 deletions
|
@ -518,8 +518,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
|
|||
else if (tbtype->ty == TY::Tarray)
|
||||
{
|
||||
/* Assume tvoid->size() == 1. */
|
||||
d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size ();
|
||||
d_uns64 tsize = tbtype->nextOf ()->toBasetype ()->size ();
|
||||
dinteger_t fsize = ebtype->nextOf ()->toBasetype ()->size ();
|
||||
dinteger_t tsize = tbtype->nextOf ()->toBasetype ()->size ();
|
||||
|
||||
if (fsize != tsize)
|
||||
{
|
||||
|
|
|
@ -32,7 +32,6 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "dmd/mangle.h"
|
||||
#include "dmd/module.h"
|
||||
#include "dmd/mtype.h"
|
||||
#include "dmd/root/file.h"
|
||||
#include "dmd/target.h"
|
||||
|
||||
#include "opts.h"
|
||||
|
@ -579,7 +578,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
global.params.fix16997 = value;
|
||||
global.params.markdown = value;
|
||||
global.params.noSharedAccess = value;
|
||||
global.params.rvalueRefParam = value;
|
||||
global.params.rvalueRefParam = FeatureState::enabled;
|
||||
global.params.inclusiveInContracts = value;
|
||||
global.params.shortenedMethods = value;
|
||||
break;
|
||||
|
@ -625,7 +624,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
break;
|
||||
|
||||
case OPT_fpreview_rvaluerefparam:
|
||||
global.params.rvalueRefParam = value;
|
||||
global.params.rvalueRefParam = FeatureState::enabled;
|
||||
break;
|
||||
|
||||
case OPT_fpreview_shortenedmethods:
|
||||
|
@ -1069,9 +1068,8 @@ d_parse_file (void)
|
|||
|
||||
/* Overwrite the source file for the module, the one created by
|
||||
Module::create would have a forced a `.d' suffix. */
|
||||
m->srcBuffer = FileBuffer::create ();
|
||||
m->srcBuffer->data.length = len;
|
||||
m->srcBuffer->data.ptr = buffer;
|
||||
m->src.length = len;
|
||||
m->src.ptr = buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1108,7 +1106,7 @@ d_parse_file (void)
|
|||
m->importedFrom = m;
|
||||
m->parse ();
|
||||
|
||||
if (m->isDocFile)
|
||||
if (m->filetype == FileType::ddoc)
|
||||
{
|
||||
gendocfile (m);
|
||||
/* Remove M from list of modules. */
|
||||
|
@ -1146,7 +1144,8 @@ d_parse_file (void)
|
|||
for (size_t i = 0; i < modules.length; i++)
|
||||
{
|
||||
Module *m = modules[i];
|
||||
if (m->isHdrFile || (d_option.fonly && m != Module::rootModule))
|
||||
if (m->filetype == FileType::dhdr
|
||||
|| (d_option.fonly && m != Module::rootModule))
|
||||
continue;
|
||||
|
||||
if (global.params.verbose)
|
||||
|
@ -1374,7 +1373,7 @@ d_parse_file (void)
|
|||
|
||||
/* Skip generating code for header files, or when the module wasn't
|
||||
specified by `-fonly=`. */
|
||||
if ((m->isHdrFile && m != main_module)
|
||||
if ((m->filetype == FileType::dhdr && m != main_module)
|
||||
|| (d_option.fonly && m != Module::rootModule))
|
||||
continue;
|
||||
|
||||
|
@ -1421,7 +1420,8 @@ d_parse_file (void)
|
|||
for (size_t i = 0; i < modules.length; i++)
|
||||
{
|
||||
Module *m = modules[i];
|
||||
if (m->isHdrFile || (d_option.fonly && m != Module::rootModule))
|
||||
if (m->filetype == FileType::dhdr
|
||||
|| (d_option.fonly && m != Module::rootModule))
|
||||
continue;
|
||||
|
||||
remove (m->hdrfile.toChars ());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
cbba5f41a32cfed7f22a213d537f8e2dee0b92f7
|
||||
2503f17e5767bc4fcd0cf3889c90fa0415b0edaa
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -234,7 +234,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
|
|||
|
||||
abstract void finalizeSize();
|
||||
|
||||
override final d_uns64 size(const ref Loc loc)
|
||||
override final uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
//printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
|
||||
bool ok = determineSize(loc);
|
||||
|
|
|
@ -124,7 +124,7 @@ public:
|
|||
size_t nonHiddenFields();
|
||||
bool determineSize(const Loc &loc);
|
||||
virtual void finalizeSize() = 0;
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
bool fill(const Loc &loc, Expressions *elements, bool ctorinit);
|
||||
Type *getType();
|
||||
bool isDeprecated() const; // is aggregate deprecated?
|
||||
|
|
|
@ -430,3 +430,12 @@ enum PINLINE : ubyte
|
|||
never, /// never inline
|
||||
always, /// always inline
|
||||
}
|
||||
|
||||
/// Source file type
|
||||
enum FileType : ubyte
|
||||
{
|
||||
d, /// normal D source file
|
||||
dhdr, /// D header file (.di)
|
||||
ddoc, /// Ddoc documentation file (.dd)
|
||||
c, /// C source file
|
||||
}
|
||||
|
|
|
@ -247,12 +247,12 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration
|
|||
*/
|
||||
if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
|
||||
scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
|
||||
if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared))
|
||||
scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared);
|
||||
if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared))
|
||||
scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared);
|
||||
if (stc & (STC.const_ | STC.immutable_ | STC.manifest))
|
||||
scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
|
||||
if (stc & (STC.gshared | STC.shared_ | STC.tls))
|
||||
scstc &= ~(STC.gshared | STC.shared_ | STC.tls);
|
||||
if (stc & (STC.gshared | STC.shared_))
|
||||
scstc &= ~(STC.gshared | STC.shared_);
|
||||
if (stc & (STC.safe | STC.trusted | STC.system))
|
||||
scstc &= ~(STC.safe | STC.trusted | STC.system);
|
||||
scstc |= stc;
|
||||
|
|
|
@ -146,7 +146,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
|
|||
else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
|
||||
{
|
||||
}
|
||||
else if (!func.getModule().isCFile)
|
||||
else if (func.getModule().filetype != FileType.c)
|
||||
{
|
||||
const(char)* gototype = s.isCaseStatement() ? "case" : "default";
|
||||
s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
|
||||
|
|
|
@ -246,7 +246,7 @@ private CT Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow)
|
|||
if (vd.storage_class & STC.manifest)
|
||||
{
|
||||
}
|
||||
else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.tls | STC.gshared))
|
||||
else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.gshared))
|
||||
{
|
||||
}
|
||||
else
|
||||
|
|
|
@ -619,31 +619,31 @@ UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
|
|||
switch (e1.type.toBasetype().ty)
|
||||
{
|
||||
case Tint8:
|
||||
value = cast(d_int8)value >> count;
|
||||
value = cast(byte)value >> count;
|
||||
break;
|
||||
case Tuns8:
|
||||
case Tchar:
|
||||
value = cast(d_uns8)value >> count;
|
||||
value = cast(ubyte)value >> count;
|
||||
break;
|
||||
case Tint16:
|
||||
value = cast(d_int16)value >> count;
|
||||
value = cast(short)value >> count;
|
||||
break;
|
||||
case Tuns16:
|
||||
case Twchar:
|
||||
value = cast(d_uns16)value >> count;
|
||||
value = cast(ushort)value >> count;
|
||||
break;
|
||||
case Tint32:
|
||||
value = cast(d_int32)value >> count;
|
||||
value = cast(int)value >> count;
|
||||
break;
|
||||
case Tuns32:
|
||||
case Tdchar:
|
||||
value = cast(d_uns32)value >> count;
|
||||
value = cast(uint)value >> count;
|
||||
break;
|
||||
case Tint64:
|
||||
value = cast(d_int64)value >> count;
|
||||
value = cast(long)value >> count;
|
||||
break;
|
||||
case Tuns64:
|
||||
value = cast(d_uns64)value >> count;
|
||||
value = cast(ulong)value >> count;
|
||||
break;
|
||||
case Terror:
|
||||
emplaceExp!(ErrorExp)(&ue);
|
||||
|
@ -1106,31 +1106,31 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
|
|||
switch (typeb.ty)
|
||||
{
|
||||
case Tint8:
|
||||
result = cast(d_int8)cast(sinteger_t)r;
|
||||
result = cast(byte)cast(sinteger_t)r;
|
||||
break;
|
||||
case Tchar:
|
||||
case Tuns8:
|
||||
result = cast(d_uns8)cast(dinteger_t)r;
|
||||
result = cast(ubyte)cast(dinteger_t)r;
|
||||
break;
|
||||
case Tint16:
|
||||
result = cast(d_int16)cast(sinteger_t)r;
|
||||
result = cast(short)cast(sinteger_t)r;
|
||||
break;
|
||||
case Twchar:
|
||||
case Tuns16:
|
||||
result = cast(d_uns16)cast(dinteger_t)r;
|
||||
result = cast(ushort)cast(dinteger_t)r;
|
||||
break;
|
||||
case Tint32:
|
||||
result = cast(d_int32)r;
|
||||
result = cast(int)r;
|
||||
break;
|
||||
case Tdchar:
|
||||
case Tuns32:
|
||||
result = cast(d_uns32)r;
|
||||
result = cast(uint)r;
|
||||
break;
|
||||
case Tint64:
|
||||
result = cast(d_int64)r;
|
||||
result = cast(long)r;
|
||||
break;
|
||||
case Tuns64:
|
||||
result = cast(d_uns64)r;
|
||||
result = cast(ulong)r;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
|
@ -1348,14 +1348,6 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
|
|||
}
|
||||
}
|
||||
|
||||
static bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure
|
||||
{
|
||||
assert(lwr <= upr);
|
||||
return !(newlwr <= newupr &&
|
||||
lwr <= newlwr &&
|
||||
newupr <= upr);
|
||||
}
|
||||
|
||||
if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
|
||||
{
|
||||
StringExp es1 = cast(StringExp)e1;
|
||||
|
@ -1395,6 +1387,16 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
|
|||
return ue;
|
||||
}
|
||||
|
||||
/* Check whether slice `[newlwr .. newupr]` is in the range `[lwr .. upr]`
|
||||
*/
|
||||
bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure
|
||||
{
|
||||
assert(lwr <= upr);
|
||||
return !(newlwr <= newupr &&
|
||||
lwr <= newlwr &&
|
||||
newupr <= upr);
|
||||
}
|
||||
|
||||
/* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
|
||||
* existingAE[firstIndex..firstIndex+newval.length] = newval.
|
||||
*/
|
||||
|
|
|
@ -48,14 +48,16 @@ final class CParser(AST) : Parser!AST
|
|||
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.
|
||||
/* C cannot be parsed without determining if an identifier is a type or a variable.
|
||||
* For expressions like `(T)-3`, is it a cast or a minus expression?
|
||||
* It also occurs with `typedef int (F)(); F fun;`
|
||||
* but to build the AST we need to distinguish `fun` being a function as opposed to a variable.
|
||||
* To fix, build a symbol table for the typedefs.
|
||||
* Symbol table of typedefs indexed by Identifier cast to void*.
|
||||
* 1. if an identifier is a typedef, then it will return a non-null Type
|
||||
* 2. if an identifier is not a typedef, then it will return null
|
||||
*/
|
||||
AST.Identifiers funcTypeIds; /// Identifiers in this are typedefs of function types
|
||||
Array!(void*) typedefTab; /// Array of AST.Type[Identifier], typedef's indexed by Identifier
|
||||
|
||||
extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
|
||||
const ref TARGET target)
|
||||
|
@ -97,6 +99,7 @@ final class CParser(AST) : Parser!AST
|
|||
{
|
||||
//printf("cparseTranslationUnit()\n");
|
||||
symbols = new AST.Dsymbols();
|
||||
typedefTab.push(null); // C11 6.2.1-3 symbol table for "file scope"
|
||||
while (1)
|
||||
{
|
||||
if (token.value == TOK.endOfFile)
|
||||
|
@ -115,6 +118,10 @@ final class CParser(AST) : Parser!AST
|
|||
wrap.push(s);
|
||||
}
|
||||
|
||||
// end of file scope
|
||||
typedefTab.pop();
|
||||
assert(typedefTab.length == 0);
|
||||
|
||||
return wrap;
|
||||
}
|
||||
|
||||
|
@ -150,10 +157,17 @@ final class CParser(AST) : Parser!AST
|
|||
|
||||
//printf("cparseStatement()\n");
|
||||
|
||||
const funcTypeIdsLengthSave = funcTypeIds.length;
|
||||
const typedefTabLengthSave = typedefTab.length;
|
||||
auto symbolsSave = symbols;
|
||||
if (flags & ParseStatementFlags.scope_)
|
||||
{
|
||||
typedefTab.push(null); // introduce new block scope
|
||||
}
|
||||
|
||||
if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)))
|
||||
{
|
||||
symbols = new AST.Dsymbols();
|
||||
}
|
||||
|
||||
switch (token.value)
|
||||
{
|
||||
|
@ -593,7 +607,7 @@ final class CParser(AST) : Parser!AST
|
|||
if (pEndloc)
|
||||
*pEndloc = prevloc;
|
||||
symbols = symbolsSave;
|
||||
funcTypeIds.setDim(funcTypeIdsLengthSave);
|
||||
typedefTab.setDim(typedefTabLengthSave);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -1002,8 +1016,18 @@ final class CParser(AST) : Parser!AST
|
|||
{
|
||||
if (token.value == TOK.leftParenthesis)
|
||||
{
|
||||
auto tk = peek(&token);
|
||||
if (tk.value == TOK.identifier &&
|
||||
!isTypedef(tk.ident) &&
|
||||
peek(tk).value == TOK.rightParenthesis)
|
||||
{
|
||||
// ( identifier ) is an expression
|
||||
return cparseUnaryExp();
|
||||
}
|
||||
|
||||
// If ( type-name )
|
||||
auto pt = &token;
|
||||
|
||||
if (isCastExpression(pt))
|
||||
{
|
||||
// Expression may be either a cast or a compound literal, which
|
||||
|
@ -1573,7 +1597,7 @@ final class CParser(AST) : Parser!AST
|
|||
return;
|
||||
}
|
||||
|
||||
const funcTypeIdsLengthSave = funcTypeIds.length;
|
||||
const typedefTabLengthSave = typedefTab.length;
|
||||
auto symbolsSave = symbols;
|
||||
Specifier specifier;
|
||||
specifier.packalign = this.packalign;
|
||||
|
@ -1683,13 +1707,13 @@ final class CParser(AST) : Parser!AST
|
|||
t.value == TOK.leftCurly) // start of compound-statement
|
||||
{
|
||||
auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
|
||||
funcTypeIds.setDim(funcTypeIdsLengthSave);
|
||||
typedefTab.setDim(typedefTabLengthSave);
|
||||
symbols = symbolsSave;
|
||||
symbols.push(s);
|
||||
return;
|
||||
}
|
||||
AST.Dsymbol s = null;
|
||||
funcTypeIds.setDim(funcTypeIdsLengthSave);
|
||||
typedefTab.setDim(typedefTabLengthSave);
|
||||
symbols = symbolsSave;
|
||||
if (!symbols)
|
||||
symbols = new AST.Dsymbols; // lazilly create it
|
||||
|
@ -1747,12 +1771,9 @@ final class CParser(AST) : Parser!AST
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (isFunctionTypedef(dt))
|
||||
{
|
||||
funcTypeIds.push(id); // remember function typedefs
|
||||
}
|
||||
if (isalias)
|
||||
s = new AST.AliasDeclaration(token.loc, id, dt);
|
||||
insertTypedefToTypedefTab(id, dt); // remember typedefs
|
||||
}
|
||||
else if (id)
|
||||
{
|
||||
|
@ -1791,6 +1812,8 @@ final class CParser(AST) : Parser!AST
|
|||
initializer = new AST.VoidInitializer(token.loc);
|
||||
s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier));
|
||||
}
|
||||
if (level != LVL.global)
|
||||
insertIdToTypedefTab(id); // non-typedef declarations can hide typedefs in outer scopes
|
||||
}
|
||||
if (s !is null)
|
||||
{
|
||||
|
@ -1868,6 +1891,10 @@ final class CParser(AST) : Parser!AST
|
|||
*/
|
||||
AST.Dsymbol cparseFunctionDefinition(Identifier id, AST.TypeFunction ft, ref Specifier specifier)
|
||||
{
|
||||
/* Start function scope
|
||||
*/
|
||||
typedefTab.push(null);
|
||||
|
||||
if (token.value != TOK.leftCurly) // if not start of a compound-statement
|
||||
{
|
||||
// Do declaration-list
|
||||
|
@ -1930,6 +1957,8 @@ final class CParser(AST) : Parser!AST
|
|||
const locFunc = token.loc;
|
||||
|
||||
auto body = cparseStatement(ParseStatementFlags.curly); // don't start a new scope; continue with parameter scope
|
||||
typedefTab.pop(); // end of function scope
|
||||
|
||||
auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, specifiersToSTC(LVL.global, specifier), ft, specifier.noreturn);
|
||||
|
||||
if (addFuncName)
|
||||
|
@ -2737,6 +2766,16 @@ final class CParser(AST) : Parser!AST
|
|||
return AST.ParameterList(parameters, AST.VarArg.variadic, varargsStc);
|
||||
}
|
||||
|
||||
/* Create function prototype scope
|
||||
*/
|
||||
typedefTab.push(null);
|
||||
|
||||
AST.ParameterList finish()
|
||||
{
|
||||
typedefTab.pop();
|
||||
return AST.ParameterList(parameters, varargs, varargsStc);
|
||||
}
|
||||
|
||||
/* The check for identifier-list comes later,
|
||||
* when doing the trailing declaration-list (opt)
|
||||
*/
|
||||
|
@ -2752,7 +2791,7 @@ final class CParser(AST) : Parser!AST
|
|||
varargs = AST.VarArg.variadic; // C-style variadics
|
||||
nextToken();
|
||||
check(TOK.rightParenthesis);
|
||||
return AST.ParameterList(parameters, varargs, varargsStc);
|
||||
return finish();
|
||||
}
|
||||
|
||||
Specifier specifier;
|
||||
|
@ -2777,7 +2816,7 @@ final class CParser(AST) : Parser!AST
|
|||
check(TOK.comma);
|
||||
}
|
||||
nextToken();
|
||||
return AST.ParameterList(parameters, varargs, varargsStc);
|
||||
return finish();
|
||||
}
|
||||
|
||||
/***********************************
|
||||
|
@ -4121,12 +4160,14 @@ final class CParser(AST) : Parser!AST
|
|||
* ( expression )
|
||||
* Params:
|
||||
* pt = starting token, updated to one past end of constant-expression if true
|
||||
* afterParenType = true if already seen ( type-name )
|
||||
* afterParenType = true if already seen `( type-name )`
|
||||
* Returns:
|
||||
* true if matches ( type-name ) ...
|
||||
*/
|
||||
private bool isCastExpression(ref Token* pt, bool afterParenType = false)
|
||||
{
|
||||
enum log = false;
|
||||
if (log) printf("isCastExpression(tk: `%s`, afterParenType: %d)\n", token.toChars(pt.value), afterParenType);
|
||||
auto t = pt;
|
||||
switch (t.value)
|
||||
{
|
||||
|
@ -4144,19 +4185,23 @@ final class CParser(AST) : Parser!AST
|
|||
{
|
||||
// ( type-name ) { initializer-list }
|
||||
if (!isInitializer(tk))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
t = tk;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tk.value == TOK.leftParenthesis && peek(tk).value == TOK.rightParenthesis)
|
||||
{
|
||||
return false; // (type-name)() is not a cast (it might be a function call)
|
||||
}
|
||||
|
||||
if (!isCastExpression(tk, true))
|
||||
{
|
||||
if (afterParenType) // could be ( type-name ) ( unary-expression )
|
||||
goto default; // where unary-expression also matched type-name
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// ( type-name ) cast-expression
|
||||
t = tk;
|
||||
|
@ -4164,11 +4209,14 @@ final class CParser(AST) : Parser!AST
|
|||
|
||||
default:
|
||||
if (!afterParenType || !isUnaryExpression(t, afterParenType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// if we've already seen ( type-name ), then this is a cast
|
||||
break;
|
||||
}
|
||||
pt = t;
|
||||
if (log) printf("isCastExpression true\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4576,9 +4624,14 @@ final class CParser(AST) : Parser!AST
|
|||
return s;
|
||||
}
|
||||
|
||||
//}
|
||||
|
||||
/******************************************************************************/
|
||||
/************************** typedefTab symbol table ***************************/
|
||||
//{
|
||||
|
||||
/********************************
|
||||
* Determines if type t is a function type.
|
||||
* Make this work without needing semantic analysis.
|
||||
* Params:
|
||||
* t = type to test
|
||||
* Returns:
|
||||
|
@ -4591,20 +4644,84 @@ final class CParser(AST) : Parser!AST
|
|||
return true;
|
||||
if (auto tid = t.isTypeIdentifier())
|
||||
{
|
||||
/* Scan array of typedef identifiers that are an alias for
|
||||
* a function type
|
||||
*/
|
||||
foreach (ftid; funcTypeIds[])
|
||||
auto pt = lookupTypedef(tid.ident);
|
||||
if (pt && *pt)
|
||||
{
|
||||
if (tid.ident == ftid)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return (*pt).isTypeFunction() !is null;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/********************************
|
||||
* Determine if `id` is a symbol for a Typedef.
|
||||
* Params:
|
||||
* id = possible typedef
|
||||
* Returns:
|
||||
* true if id is a Type
|
||||
*/
|
||||
bool isTypedef(Identifier id)
|
||||
{
|
||||
auto pt = lookupTypedef(id);
|
||||
return (pt && *pt);
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Add `id` to typedefTab[], but only if it will mask an existing typedef.
|
||||
* Params: id = identifier for non-typedef symbol
|
||||
*/
|
||||
void insertIdToTypedefTab(Identifier id)
|
||||
{
|
||||
//printf("insertIdToTypedefTab(id: %s) level %d\n", id.toChars(), cast(int)typedefTab.length - 1);
|
||||
if (isTypedef(id)) // if existing typedef
|
||||
{
|
||||
/* Add id as null, so we can later distinguish it from a non-null typedef
|
||||
*/
|
||||
auto tab = cast(void*[void*])(typedefTab[$ - 1]);
|
||||
tab[cast(void*)id] = cast(void*)null;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* Add `id` to typedefTab[]
|
||||
* Params:
|
||||
* id = identifier for typedef symbol
|
||||
* t = type of the typedef symbol
|
||||
*/
|
||||
void insertTypedefToTypedefTab(Identifier id, AST.Type t)
|
||||
{
|
||||
//printf("insertTypedefToTypedefTab(id: %s, t: %s) level %d\n", id.toChars(), t ? t.toChars() : "null".ptr, cast(int)typedefTab.length - 1);
|
||||
if (auto tid = t.isTypeIdentifier())
|
||||
{
|
||||
// Try to resolve the TypeIdentifier to its type
|
||||
auto pt = lookupTypedef(tid.ident);
|
||||
if (pt && *pt)
|
||||
t = *pt;
|
||||
}
|
||||
auto tab = cast(void*[void*])(typedefTab[$ - 1]);
|
||||
tab[cast(void*)id] = cast(void*)t;
|
||||
typedefTab[$ - 1] = cast(void*)tab;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* Lookup id in typedefTab[].
|
||||
* Returns:
|
||||
* if not found, then null.
|
||||
* if found, then Type*. Deferencing it will yield null if it is not
|
||||
* a typedef, and a type if it is a typedef.
|
||||
*/
|
||||
AST.Type* lookupTypedef(Identifier id)
|
||||
{
|
||||
foreach_reverse (tab; typedefTab[])
|
||||
{
|
||||
if (auto pt = cast(void*)id in cast(void*[void*])tab)
|
||||
{
|
||||
return cast(AST.Type*)pt;
|
||||
}
|
||||
}
|
||||
return null; // not found
|
||||
}
|
||||
|
||||
//}
|
||||
|
||||
/******************************************************************************/
|
||||
|
|
|
@ -1908,6 +1908,8 @@ extern(C++):
|
|||
return writeBasicType(t, 0, 'l');
|
||||
else if (id == Id.__c_ulong)
|
||||
return writeBasicType(t, 0, 'm');
|
||||
else if (id == Id.__c_char)
|
||||
return writeBasicType(t, 0, 'c');
|
||||
else if (id == Id.__c_wchar_t)
|
||||
return writeBasicType(t, 0, 'w');
|
||||
else if (id == Id.__c_longlong)
|
||||
|
|
|
@ -343,10 +343,9 @@ UnionExp copyLiteral(Expression e)
|
|||
{
|
||||
auto tsa = v.type.isTypeSArray();
|
||||
auto len = cast(size_t)tsa.dim.toInteger();
|
||||
UnionExp uex = void;
|
||||
m = createBlockDuplicatedArrayLiteral(&uex, e.loc, v.type, m, len);
|
||||
if (m == uex.exp())
|
||||
m = uex.copy();
|
||||
m = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, m, len);
|
||||
if (m == ue.exp())
|
||||
m = ue.copy();
|
||||
}
|
||||
}
|
||||
el = m;
|
||||
|
@ -583,10 +582,9 @@ ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, const ref Loc l
|
|||
// If it is a multidimensional array literal, do it recursively
|
||||
auto tsa = type.nextOf().isTypeSArray();
|
||||
const len = cast(size_t)tsa.dim.toInteger();
|
||||
UnionExp ue = void;
|
||||
elem = createBlockDuplicatedArrayLiteral(&ue, loc, type.nextOf(), elem, len);
|
||||
if (elem == ue.exp())
|
||||
elem = ue.copy();
|
||||
elem = createBlockDuplicatedArrayLiteral(pue, loc, type.nextOf(), elem, len);
|
||||
if (elem == pue.exp())
|
||||
elem = pue.copy();
|
||||
}
|
||||
|
||||
// Buzilla 15681
|
||||
|
@ -791,9 +789,8 @@ bool pointToSameMemoryBlock(Expression agg1, Expression agg2)
|
|||
}
|
||||
|
||||
// return e1 - e2 as an integer, or error if not possible
|
||||
UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expression e1, Expression e2)
|
||||
{
|
||||
UnionExp ue = void;
|
||||
dinteger_t ofs1, ofs2;
|
||||
Expression agg1 = getAggregateFromPointer(e1, &ofs1);
|
||||
Expression agg2 = getAggregateFromPointer(e2, &ofs2);
|
||||
|
@ -801,39 +798,38 @@ UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expressi
|
|||
{
|
||||
Type pointee = (cast(TypePointer)agg1.type).next;
|
||||
const sz = pointee.size();
|
||||
emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type);
|
||||
emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
|
||||
}
|
||||
else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
|
||||
(cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr)
|
||||
{
|
||||
Type pointee = (cast(TypePointer)agg1.type).next;
|
||||
const sz = pointee.size();
|
||||
emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type);
|
||||
emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
|
||||
}
|
||||
else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset &&
|
||||
(cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
|
||||
{
|
||||
emplaceExp!(IntegerExp)(&ue, loc, ofs1 - ofs2, type);
|
||||
emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars());
|
||||
emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
|
||||
emplaceExp!(CTFEExp)(pue, EXP.cantExpression);
|
||||
}
|
||||
return ue;
|
||||
return pue.exp();
|
||||
}
|
||||
|
||||
// Return eptr op e2, where eptr is a pointer, e2 is an integer,
|
||||
// and op is EXP.add or EXP.min
|
||||
UnionExp pointerArithmetic(const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2)
|
||||
Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2)
|
||||
{
|
||||
UnionExp ue;
|
||||
if (eptr.type.nextOf().ty == Tvoid)
|
||||
{
|
||||
error(loc, "cannot perform arithmetic on `void*` pointers at compile time");
|
||||
Lcant:
|
||||
emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
|
||||
return ue;
|
||||
emplaceExp!(CTFEExp)(pue, EXP.cantExpression);
|
||||
return pue.exp();
|
||||
}
|
||||
if (eptr.op == EXP.address)
|
||||
eptr = (cast(AddrExp)eptr).e1;
|
||||
|
@ -885,10 +881,10 @@ UnionExp pointerArithmetic(const ref Loc loc, EXP op, Type type, Expression eptr
|
|||
}
|
||||
if (agg1.op == EXP.symbolOffset)
|
||||
{
|
||||
emplaceExp!(SymOffExp)(&ue, loc, (cast(SymOffExp)agg1).var, indx * sz);
|
||||
SymOffExp se = cast(SymOffExp)ue.exp();
|
||||
emplaceExp!(SymOffExp)(pue, loc, (cast(SymOffExp)agg1).var, indx * sz);
|
||||
SymOffExp se = cast(SymOffExp)pue.exp();
|
||||
se.type = type;
|
||||
return ue;
|
||||
return pue.exp();
|
||||
}
|
||||
if (agg1.op != EXP.arrayLiteral && agg1.op != EXP.string_)
|
||||
{
|
||||
|
@ -903,17 +899,17 @@ UnionExp pointerArithmetic(const ref Loc loc, EXP op, Type type, Expression eptr
|
|||
ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t),
|
||||
ctfeEmplaceExp!IntegerExp(loc, indx + dim, Type.tsize_t));
|
||||
se.type = type.toBasetype().nextOf();
|
||||
emplaceExp!(AddrExp)(&ue, loc, se);
|
||||
ue.exp().type = type;
|
||||
return ue;
|
||||
emplaceExp!(AddrExp)(pue, loc, se);
|
||||
pue.exp().type = type;
|
||||
return pue.exp();
|
||||
}
|
||||
// Create a CTFE pointer &agg1[indx]
|
||||
auto ofs = ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t);
|
||||
Expression ie = ctfeEmplaceExp!IndexExp(loc, agg1, ofs);
|
||||
ie.type = type.toBasetype().nextOf(); // https://issues.dlang.org/show_bug.cgi?id=13992
|
||||
emplaceExp!(AddrExp)(&ue, loc, ie);
|
||||
ue.exp().type = type;
|
||||
return ue;
|
||||
emplaceExp!(AddrExp)(pue, loc, ie);
|
||||
pue.exp().type = type;
|
||||
return pue.exp();
|
||||
}
|
||||
|
||||
// Return 1 if true, 0 if false
|
||||
|
@ -1755,9 +1751,8 @@ Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae,
|
|||
/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
|
||||
/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
|
||||
/// all new elements will be set to the default initializer for the element type.
|
||||
UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen)
|
||||
Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen)
|
||||
{
|
||||
UnionExp ue;
|
||||
Type elemType = arrayType.next;
|
||||
assert(elemType);
|
||||
Expression defaultElem = elemType.defaultInitLiteral(loc);
|
||||
|
@ -1794,8 +1789,8 @@ UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expres
|
|||
assert(0);
|
||||
}
|
||||
}
|
||||
emplaceExp!(StringExp)(&ue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz);
|
||||
StringExp se = cast(StringExp)ue.exp();
|
||||
emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz);
|
||||
StringExp se = cast(StringExp)pue.exp();
|
||||
se.type = arrayType;
|
||||
se.sz = oldse.sz;
|
||||
se.committed = oldse.committed;
|
||||
|
@ -1823,11 +1818,11 @@ UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expres
|
|||
foreach (size_t i; copylen .. newlen)
|
||||
(*elements)[i] = defaultElem;
|
||||
}
|
||||
emplaceExp!(ArrayLiteralExp)(&ue, loc, arrayType, elements);
|
||||
ArrayLiteralExp aae = cast(ArrayLiteralExp)ue.exp();
|
||||
emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements);
|
||||
ArrayLiteralExp aae = cast(ArrayLiteralExp)pue.exp();
|
||||
aae.ownedByCtfe = OwnedBy.ctfe;
|
||||
}
|
||||
return ue;
|
||||
return pue.exp();
|
||||
}
|
||||
|
||||
/*************************** CTFE Sanity Checks ***************************/
|
||||
|
|
|
@ -1894,7 +1894,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
|
|||
if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray)
|
||||
{
|
||||
se = e.copy().isStringExp();
|
||||
d_uns64 szx = tb.nextOf().size();
|
||||
uinteger_t szx = tb.nextOf().size();
|
||||
assert(szx <= 255);
|
||||
se.sz = cast(ubyte)szx;
|
||||
se.len = cast(size_t)tb.isTypeSArray().dim.toInteger();
|
||||
|
@ -2059,7 +2059,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
|
|||
}
|
||||
|
||||
{
|
||||
d_uns64 szx = tb.nextOf().size();
|
||||
uinteger_t szx = tb.nextOf().size();
|
||||
assert(szx <= 255);
|
||||
se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx);
|
||||
}
|
||||
|
@ -2742,7 +2742,7 @@ Expression scaleFactor(BinExp be, Scope* sc)
|
|||
// Replace (ptr + int) with (ptr + (int * stride))
|
||||
Type t = Type.tptrdiff_t;
|
||||
|
||||
d_uns64 stride = t1b.nextOf().size(be.loc);
|
||||
uinteger_t stride = t1b.nextOf().size(be.loc);
|
||||
if (!t.equals(t2b))
|
||||
be.e2 = be.e2.castTo(sc, t);
|
||||
eoff = be.e2;
|
||||
|
@ -2757,7 +2757,7 @@ Expression scaleFactor(BinExp be, Scope* sc)
|
|||
Type t = Type.tptrdiff_t;
|
||||
Expression e;
|
||||
|
||||
d_uns64 stride = t2b.nextOf().size(be.loc);
|
||||
uinteger_t stride = t2b.nextOf().size(be.loc);
|
||||
if (!t.equals(t1b))
|
||||
e = be.e1.castTo(sc, t);
|
||||
else
|
||||
|
|
|
@ -250,7 +250,7 @@ extern (C++) abstract class Declaration : Dsymbol
|
|||
return "declaration";
|
||||
}
|
||||
|
||||
override final d_uns64 size(const ref Loc loc)
|
||||
override final uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
assert(type);
|
||||
const sz = type.size();
|
||||
|
@ -1141,7 +1141,7 @@ extern (C++) class VarDeclaration : Declaration
|
|||
|
||||
if (!isField())
|
||||
return;
|
||||
assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter | STC.tls)));
|
||||
assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter)));
|
||||
|
||||
//printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
|
||||
|
||||
|
@ -1217,7 +1217,7 @@ extern (C++) class VarDeclaration : Declaration
|
|||
|
||||
override final inout(AggregateDeclaration) isThis() inout
|
||||
{
|
||||
if (!(storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe)))
|
||||
if (!(storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.gshared | STC.ctfe)))
|
||||
{
|
||||
/* The casting is necessary because `s = s.parent` is otherwise rejected
|
||||
*/
|
||||
|
@ -1285,7 +1285,7 @@ extern (C++) class VarDeclaration : Declaration
|
|||
error("forward referenced");
|
||||
type = Type.terror;
|
||||
}
|
||||
else if (storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared) ||
|
||||
else if (storage_class & (STC.static_ | STC.extern_ | STC.gshared) ||
|
||||
parent.isModule() || parent.isTemplateInstance() || parent.isNspace())
|
||||
{
|
||||
assert(!isParameter() && !isResult());
|
||||
|
|
|
@ -71,7 +71,6 @@ struct IntRange;
|
|||
#define STCnodtor 0x10000000ULL /// do not run destructor
|
||||
#define STCnothrow 0x20000000ULL /// `nothrow` meaning never throws exceptions
|
||||
#define STCpure 0x40000000ULL /// `pure` function
|
||||
#define STCtls 0x80000000ULL /// thread local
|
||||
|
||||
#define STCalias 0x100000000ULL /// `alias` parameter
|
||||
#define STCshared 0x200000000ULL /// accessible from multiple threads
|
||||
|
@ -123,7 +122,7 @@ public:
|
|||
DString mangleOverride; // overridden symbol with pragma(mangle, "...")
|
||||
|
||||
const char *kind() const;
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
|
||||
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
|
||||
|
||||
|
|
|
@ -1886,7 +1886,7 @@ public:
|
|||
{
|
||||
// Check for unsupported type painting operations
|
||||
Type elemtype = (cast(TypeArray)val.type).next;
|
||||
d_uns64 elemsize = elemtype.size();
|
||||
const elemsize = elemtype.size();
|
||||
|
||||
// It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
|
||||
if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size())
|
||||
|
@ -2981,8 +2981,7 @@ public:
|
|||
Expression e2 = interpret(&ue2, e.e2, istate);
|
||||
if (exceptionOrCant(e2))
|
||||
return;
|
||||
*pue = pointerDifference(e.loc, e.type, e1, e2);
|
||||
result = (*pue).exp();
|
||||
result = pointerDifference(pue, e.loc, e.type, e1, e2);
|
||||
return;
|
||||
}
|
||||
if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
|
||||
|
@ -2995,8 +2994,7 @@ public:
|
|||
Expression e2 = interpret(&ue2, e.e2, istate);
|
||||
if (exceptionOrCant(e2))
|
||||
return;
|
||||
*pue = pointerArithmetic(e.loc, e.op, e.type, e1, e2);
|
||||
result = (*pue).exp();
|
||||
result = pointerArithmetic(pue, e.loc, e.op, e.type, e1, e2);
|
||||
return;
|
||||
}
|
||||
if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
|
||||
|
@ -3009,8 +3007,7 @@ public:
|
|||
Expression e2 = interpret(&ue2, e.e2, istate);
|
||||
if (exceptionOrCant(e2))
|
||||
return;
|
||||
*pue = pointerArithmetic(e.loc, e.op, e.type, e2, e1);
|
||||
result = (*pue).exp();
|
||||
result = pointerArithmetic(pue, e.loc, e.op, e.type, e2, e1);
|
||||
return;
|
||||
}
|
||||
if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
|
||||
|
@ -3041,7 +3038,7 @@ public:
|
|||
if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
|
||||
{
|
||||
const sinteger_t i2 = e2.toInteger();
|
||||
const d_uns64 sz = e1.type.size() * 8;
|
||||
const uinteger_t sz = e1.type.size() * 8;
|
||||
if (i2 < 0 || i2 >= sz)
|
||||
{
|
||||
e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
|
||||
|
@ -3602,7 +3599,9 @@ public:
|
|||
e.op == EXP.plusPlus ||
|
||||
e.op == EXP.minusMinus))
|
||||
{
|
||||
newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy();
|
||||
newval = pointerArithmetic(pue, e.loc, e.op, e.type, oldval, newval).copy();
|
||||
if (newval == pue.exp())
|
||||
newval = pue.copy();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3675,7 +3674,9 @@ public:
|
|||
UnionExp utmp = void;
|
||||
oldval = resolveSlice(oldval, &utmp);
|
||||
|
||||
newval = changeArrayLiteralLength(e.loc, cast(TypeArray)t, oldval, oldlen, newlen).copy();
|
||||
newval = changeArrayLiteralLength(pue, e.loc, cast(TypeArray)t, oldval, oldlen, newlen);
|
||||
if (newval == pue.exp())
|
||||
newval = pue.copy();
|
||||
|
||||
e1 = assignToLvalue(e, e1, newval);
|
||||
if (exceptionOrCant(e1))
|
||||
|
@ -3994,61 +3995,18 @@ public:
|
|||
// aggregate[] = newval
|
||||
// aggregate[low..upp] = newval
|
||||
// ------------------------------
|
||||
version (all) // should be move in interpretAssignCommon as the evaluation of e1
|
||||
{
|
||||
Expression oldval = interpretRegion(se.e1, istate);
|
||||
|
||||
// Set the $ variable
|
||||
uinteger_t dollar = resolveArrayLength(oldval);
|
||||
if (se.lengthVar)
|
||||
{
|
||||
Expression dollarExp = ctfeEmplaceExp!IntegerExp(e1.loc, dollar, Type.tsize_t);
|
||||
ctfeGlobals.stack.push(se.lengthVar);
|
||||
setValue(se.lengthVar, dollarExp);
|
||||
}
|
||||
Expression lwr = interpretRegion(se.lwr, istate);
|
||||
if (exceptionOrCantInterpret(lwr))
|
||||
{
|
||||
if (se.lengthVar)
|
||||
ctfeGlobals.stack.pop(se.lengthVar);
|
||||
return lwr;
|
||||
}
|
||||
Expression upr = interpretRegion(se.upr, istate);
|
||||
if (exceptionOrCantInterpret(upr))
|
||||
{
|
||||
if (se.lengthVar)
|
||||
ctfeGlobals.stack.pop(se.lengthVar);
|
||||
return upr;
|
||||
}
|
||||
if (se.lengthVar)
|
||||
ctfeGlobals.stack.pop(se.lengthVar); // $ is defined only in [L..U]
|
||||
|
||||
const dim = dollar;
|
||||
lowerbound = lwr ? lwr.toInteger() : 0;
|
||||
upperbound = upr ? upr.toInteger() : dim;
|
||||
|
||||
if (lowerbound < 0 || dim < upperbound)
|
||||
{
|
||||
e.error("array bounds `[0..%llu]` exceeded in slice `[%llu..%llu]`",
|
||||
ulong(dim), ulong(lowerbound), ulong(upperbound));
|
||||
return CTFEExp.cantexp;
|
||||
}
|
||||
}
|
||||
aggregate = oldval;
|
||||
firstIndex = lowerbound;
|
||||
aggregate = interpretRegion(se.e1, istate);
|
||||
lowerbound = se.lwr ? se.lwr.toInteger() : 0;
|
||||
upperbound = se.upr ? se.upr.toInteger() : resolveArrayLength(aggregate);
|
||||
|
||||
// Slice of a slice --> change the bounds
|
||||
if (auto oldse = aggregate.isSliceExp())
|
||||
{
|
||||
// Slice of a slice --> change the bounds
|
||||
if (oldse.upr.toInteger() < upperbound + oldse.lwr.toInteger())
|
||||
{
|
||||
e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`",
|
||||
ulong(lowerbound), ulong(upperbound), oldse.upr.toInteger() - oldse.lwr.toInteger());
|
||||
return CTFEExp.cantexp;
|
||||
}
|
||||
aggregate = oldse.e1;
|
||||
firstIndex = lowerbound + oldse.lwr.toInteger();
|
||||
}
|
||||
else
|
||||
firstIndex = lowerbound;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5520,7 +5478,7 @@ public:
|
|||
assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
|
||||
dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
|
||||
//Type *pointee = ((TypePointer *)agg.type)->next;
|
||||
if (iupr > (len + 1) || iupr < ilwr)
|
||||
if (sliceBoundsCheck(0, len, ilwr, iupr))
|
||||
{
|
||||
e.error("pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len);
|
||||
result = CTFEExp.cantexp;
|
||||
|
@ -5624,9 +5582,9 @@ public:
|
|||
// aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
|
||||
uinteger_t lo1 = se.lwr.toInteger();
|
||||
uinteger_t up1 = se.upr.toInteger();
|
||||
if (ilwr > iupr || iupr > up1 - lo1)
|
||||
if (sliceBoundsCheck(0, up1 - lo1, ilwr, iupr))
|
||||
{
|
||||
e.error("slice `[%llu..%llu]` exceeds array bounds `[%llu..%llu]`", ilwr, iupr, lo1, up1);
|
||||
e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", ilwr, iupr, up1 - lo1);
|
||||
result = CTFEExp.cantexp;
|
||||
return;
|
||||
}
|
||||
|
@ -5641,7 +5599,7 @@ public:
|
|||
}
|
||||
if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
|
||||
{
|
||||
if (iupr < ilwr || dollar < iupr)
|
||||
if (sliceBoundsCheck(0, dollar, ilwr, iupr))
|
||||
{
|
||||
e.error("slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar);
|
||||
result = CTFEExp.cantexp;
|
||||
|
|
|
@ -31,18 +31,12 @@ extern (C++) struct MacroTable
|
|||
extern (D) void define(const(char)[] name, const(char)[] text)
|
||||
{
|
||||
//printf("MacroTable::define('%.*s' = '%.*s')\n", cast(int)name.length, name.ptr, text.length, text.ptr);
|
||||
Macro* table;
|
||||
for (table = mactab; table; table = table.next)
|
||||
if (auto table = name in mactab)
|
||||
{
|
||||
if (table.name == name)
|
||||
{
|
||||
table.text = text;
|
||||
return;
|
||||
}
|
||||
(*table).text = text;
|
||||
return;
|
||||
}
|
||||
table = new Macro(name, text);
|
||||
table.next = mactab;
|
||||
mactab = table;
|
||||
mactab[name] = new Macro(name, text);
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
|
@ -266,20 +260,16 @@ extern (C++) struct MacroTable
|
|||
|
||||
extern (D) Macro* search(const(char)[] name)
|
||||
{
|
||||
Macro* table;
|
||||
//printf("Macro::search(%.*s)\n", cast(int)name.length, name.ptr);
|
||||
for (table = mactab; table; table = table.next)
|
||||
if (auto table = name in mactab)
|
||||
{
|
||||
if (table.name == name)
|
||||
{
|
||||
//printf("\tfound %d\n", table.textlen);
|
||||
break;
|
||||
}
|
||||
//printf("\tfound %d\n", table.textlen);
|
||||
return *table;
|
||||
}
|
||||
return table;
|
||||
return null;
|
||||
}
|
||||
|
||||
Macro* mactab;
|
||||
private Macro*[const(char)[]] mactab;
|
||||
}
|
||||
|
||||
/* ************************************************************************ */
|
||||
|
@ -288,7 +278,6 @@ private:
|
|||
|
||||
struct Macro
|
||||
{
|
||||
Macro* next; // next in list
|
||||
const(char)[] name; // macro name
|
||||
const(char)[] text; // macro replacement text
|
||||
int inuse; // macro is in use (don't expand)
|
||||
|
|
|
@ -75,7 +75,7 @@ void removeHdrFilesAndFail(ref Param params, ref Modules modules)
|
|||
{
|
||||
foreach (m; modules)
|
||||
{
|
||||
if (m.isHdrFile)
|
||||
if (m.filetype == FileType.dhdr)
|
||||
continue;
|
||||
File.remove(m.hdrfile.toChars());
|
||||
}
|
||||
|
@ -351,12 +351,10 @@ extern (C++) final class Module : Package
|
|||
const FileName objfile; // output .obj file
|
||||
const FileName hdrfile; // 'header' file
|
||||
FileName docfile; // output documentation file
|
||||
FileBuffer* srcBuffer; // set during load(), free'd in parse()
|
||||
const(ubyte)[] src; /// Raw content of the file
|
||||
uint errors; // if any errors in file
|
||||
uint numlines; // number of lines in source file
|
||||
bool isHdrFile; // if it is a header (.di) file
|
||||
bool isCFile; // if it is a C (.c) file
|
||||
bool isDocFile; // if it is a documentation input file, not D source
|
||||
FileType filetype; // source file type
|
||||
bool hasAlwaysInlines; // contains references to functions that must be inlined
|
||||
bool isPackageFile; // if it is a package.d
|
||||
Package pkg; // if isPackageFile is true, the Package that contains this package.d
|
||||
|
@ -590,24 +588,17 @@ extern (C++) final class Module : Package
|
|||
}
|
||||
|
||||
/**
|
||||
* Loads the source buffer from the given read result into `this.srcBuffer`.
|
||||
* Trigger the relevant semantic error when a file cannot be read
|
||||
*
|
||||
* Will take ownership of the buffer located inside `readResult`.
|
||||
* We special case `object.d` as a failure is likely to be a rare
|
||||
* but difficult to diagnose case for the user. Packages also require
|
||||
* special handling to avoid exposing the compiler's internals.
|
||||
*
|
||||
* Params:
|
||||
* loc = the location
|
||||
* readResult = the result of reading a file containing the source code
|
||||
*
|
||||
* Returns: `true` if successful
|
||||
* loc = The location at which the file read originated (e.g. import)
|
||||
*/
|
||||
bool loadSourceBuffer(const ref Loc loc, ref File.ReadResult readResult)
|
||||
private void onFileReadError(const ref Loc loc)
|
||||
{
|
||||
//printf("Module::loadSourceBuffer('%s') file '%s'\n", toChars(), srcfile.toChars());
|
||||
// take ownership of buffer
|
||||
srcBuffer = new FileBuffer(readResult.extractSlice());
|
||||
if (readResult.success)
|
||||
return true;
|
||||
|
||||
if (FileName.equals(srcfile.toString(), "object.d"))
|
||||
{
|
||||
.error(loc, "cannot find source code for runtime library file 'object.d'");
|
||||
|
@ -621,7 +612,6 @@ extern (C++) final class Module : Package
|
|||
// have a valid location come from the command-line.
|
||||
// Error that their file cannot be found and return early.
|
||||
.error(loc, "cannot find input file `%s`", srcfile.toChars());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -653,7 +643,6 @@ extern (C++) final class Module : Package
|
|||
|
||||
removeHdrFilesAndFail(global.params, Module.amodules);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -666,37 +655,23 @@ extern (C++) final class Module : Package
|
|||
* loc = the location
|
||||
*
|
||||
* Returns: `true` if successful
|
||||
* See_Also: loadSourceBuffer
|
||||
*/
|
||||
bool read(const ref Loc loc)
|
||||
{
|
||||
if (srcBuffer)
|
||||
if (this.src)
|
||||
return true; // already read
|
||||
|
||||
//printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
|
||||
|
||||
|
||||
|
||||
bool success;
|
||||
if (auto readResult = FileManager.fileManager.lookup(srcfile))
|
||||
if (auto result = FileManager.fileManager.lookup(srcfile))
|
||||
{
|
||||
srcBuffer = readResult;
|
||||
success = true;
|
||||
this.src = result.data;
|
||||
if (global.params.emitMakeDeps)
|
||||
global.params.makeDeps.push(srcfile.toChars());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto readResult = File.read(srcfile.toChars());
|
||||
if (loadSourceBuffer(loc, readResult))
|
||||
{
|
||||
FileManager.fileManager.add(srcfile, srcBuffer);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
if (success && global.params.emitMakeDeps)
|
||||
{
|
||||
global.params.makeDeps.push(srcfile.toChars());
|
||||
}
|
||||
return success;
|
||||
|
||||
this.onFileReadError(loc);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// syntactic parse
|
||||
|
@ -830,7 +805,7 @@ extern (C++) final class Module : Package
|
|||
//printf("Module::parse(srcname = '%s')\n", srcname);
|
||||
isPackageFile = (strcmp(srcfile.name(), package_d) == 0 ||
|
||||
strcmp(srcfile.name(), package_di) == 0);
|
||||
const(char)[] buf = cast(const(char)[]) srcBuffer.data;
|
||||
const(char)[] buf = cast(const(char)[]) this.src;
|
||||
|
||||
bool needsReencoding = true;
|
||||
bool hasBOM = true; //assume there's a BOM
|
||||
|
@ -942,7 +917,7 @@ extern (C++) final class Module : Package
|
|||
if (buf.length>= 4 && buf[0..4] == "Ddoc")
|
||||
{
|
||||
comment = buf.ptr + 4;
|
||||
isDocFile = true;
|
||||
filetype = FileType.ddoc;
|
||||
if (!docfile)
|
||||
setDocfile();
|
||||
return this;
|
||||
|
@ -955,7 +930,7 @@ extern (C++) final class Module : Package
|
|||
if (FileName.equalsExt(arg, dd_ext))
|
||||
{
|
||||
comment = buf.ptr; // the optional Ddoc, if present, is handled above.
|
||||
isDocFile = true;
|
||||
filetype = FileType.ddoc;
|
||||
if (!docfile)
|
||||
setDocfile();
|
||||
return this;
|
||||
|
@ -963,9 +938,7 @@ extern (C++) final class Module : Package
|
|||
/* If it has the extension ".di", it is a "header" file.
|
||||
*/
|
||||
if (FileName.equalsExt(arg, hdr_ext))
|
||||
{
|
||||
isHdrFile = true;
|
||||
}
|
||||
filetype = FileType.dhdr;
|
||||
|
||||
/// Promote `this` to a root module if requested via `-i`
|
||||
void checkCompiledImport()
|
||||
|
@ -982,7 +955,7 @@ extern (C++) final class Module : Package
|
|||
*/
|
||||
if (FileName.equalsExt(arg, c_ext) || FileName.equalsExt(arg, i_ext))
|
||||
{
|
||||
isCFile = true;
|
||||
filetype = FileType.c;
|
||||
|
||||
scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c);
|
||||
p.nextToken();
|
||||
|
@ -1014,8 +987,7 @@ extern (C++) final class Module : Package
|
|||
members = p.parseModuleContent();
|
||||
numlines = p.scanloc.linnum;
|
||||
}
|
||||
srcBuffer.destroy();
|
||||
srcBuffer = null;
|
||||
|
||||
/* The symbol table into which the module is to be inserted.
|
||||
*/
|
||||
|
||||
|
@ -1141,7 +1113,7 @@ extern (C++) final class Module : Package
|
|||
//printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
|
||||
if (_scope)
|
||||
return; // already done
|
||||
if (isDocFile)
|
||||
if (filetype == FileType.ddoc)
|
||||
{
|
||||
error("is a Ddoc file, cannot import it");
|
||||
return;
|
||||
|
|
|
@ -425,7 +425,7 @@ extern(C++) void gendocfile(Module m)
|
|||
dc.copyright.nooutput = 1;
|
||||
m.macrotable.define("COPYRIGHT", dc.copyright.body_);
|
||||
}
|
||||
if (m.isDocFile)
|
||||
if (m.filetype == FileType.ddoc)
|
||||
{
|
||||
const ploc = m.md ? &m.md.loc : &m.loc;
|
||||
const loc = Loc(ploc.filename ? ploc.filename : srcfilename.ptr,
|
||||
|
@ -4991,7 +4991,7 @@ private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s
|
|||
|
||||
default:
|
||||
leadingBlank = false;
|
||||
if (sc._module.isDocFile || inCode)
|
||||
if (sc._module.filetype == FileType.ddoc || inCode)
|
||||
break;
|
||||
const start = cast(char*)buf[].ptr + i;
|
||||
if (isIdStart(start))
|
||||
|
|
|
@ -174,7 +174,7 @@ struct Scope
|
|||
m = m.parent;
|
||||
m.addMember(null, sc.scopesym);
|
||||
m.parent = null; // got changed by addMember()
|
||||
if (_module.isCFile)
|
||||
if (_module.filetype == FileType.c)
|
||||
sc.flags |= SCOPE.Cfile;
|
||||
// Create the module scope underneath the global scope
|
||||
sc = sc.push(_module);
|
||||
|
|
|
@ -465,10 +465,7 @@ extern (C++) class Dsymbol : ASTNode
|
|||
final bool isCsymbol()
|
||||
{
|
||||
if (Module m = getModule())
|
||||
{
|
||||
if (m.isCFile)
|
||||
return true;
|
||||
}
|
||||
return m.filetype == FileType.c;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -975,7 +972,7 @@ extern (C++) class Dsymbol : ASTNode
|
|||
* Returns:
|
||||
* SIZE_INVALID when the size cannot be determined
|
||||
*/
|
||||
d_uns64 size(const ref Loc loc)
|
||||
uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
error("Dsymbol `%s` has no size", toChars());
|
||||
return SIZE_INVALID;
|
||||
|
|
|
@ -223,7 +223,7 @@ public:
|
|||
virtual void importAll(Scope *sc);
|
||||
virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
|
||||
virtual bool overloadInsert(Dsymbol *s);
|
||||
virtual d_uns64 size(const Loc &loc);
|
||||
virtual uinteger_t size(const Loc &loc);
|
||||
virtual bool isforwardRef();
|
||||
virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member
|
||||
virtual bool isExport() const; // is Dsymbol exported?
|
||||
|
|
|
@ -716,7 +716,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
|
||||
if (dsym.storage_class & STC.scope_)
|
||||
{
|
||||
StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.tls | STC.gshared);
|
||||
StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.gshared);
|
||||
if (stc)
|
||||
{
|
||||
OutBuffer buf;
|
||||
|
@ -733,7 +733,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
}
|
||||
}
|
||||
|
||||
if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe))
|
||||
if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.gshared | STC.ctfe))
|
||||
{
|
||||
}
|
||||
else
|
||||
|
@ -794,7 +794,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
|
||||
if (dsym.type.hasWild())
|
||||
{
|
||||
if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg())
|
||||
if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg())
|
||||
{
|
||||
dsym.error("only parameters or stack based variables can be `inout`");
|
||||
}
|
||||
|
@ -841,7 +841,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
FuncDeclaration fd = parent.isFuncDeclaration();
|
||||
if (dsym.type.isscope() && !(dsym.storage_class & STC.nodtor))
|
||||
{
|
||||
if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.tls | STC.gshared) || !fd)
|
||||
if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.gshared) || !fd)
|
||||
{
|
||||
dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`");
|
||||
}
|
||||
|
@ -871,7 +871,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
}
|
||||
}
|
||||
else if (!dsym._init &&
|
||||
!(dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
|
||||
!(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
|
||||
dsym.type.hasVoidInitPointers())
|
||||
{
|
||||
if (sc.func.setUnsafe())
|
||||
|
@ -891,7 +891,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
dsym.error("manifest constants must have initializers");
|
||||
|
||||
bool isBlit = false;
|
||||
d_uns64 sz;
|
||||
uinteger_t sz;
|
||||
if (sc.flags & SCOPE.Cfile && !dsym._init)
|
||||
{
|
||||
addDefaultCInitializer(dsym);
|
||||
|
@ -977,7 +977,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
{
|
||||
// If local variable, use AssignExp to handle all the various
|
||||
// possibilities.
|
||||
if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.tls | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer())
|
||||
if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer())
|
||||
{
|
||||
//printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars());
|
||||
if (!ei)
|
||||
|
@ -1476,7 +1476,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
if (scd.decl)
|
||||
{
|
||||
sc = sc.push();
|
||||
sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.gshared);
|
||||
sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.gshared);
|
||||
sc.inunion = scd.isunion ? scd : null;
|
||||
sc.flags = 0;
|
||||
for (size_t i = 0; i < scd.decl.dim; i++)
|
||||
|
@ -4233,21 +4233,41 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
*/
|
||||
if (scd.isInstantiated() && scd.semanticRun < PASS.semantic)
|
||||
{
|
||||
/* Add this prefix to the function:
|
||||
* static int gate;
|
||||
* if (++gate != 1) return;
|
||||
* Note that this is not thread safe; should not have threads
|
||||
* during static construction.
|
||||
/* Add this prefix to the constructor:
|
||||
* ```
|
||||
* static int gate;
|
||||
* if (++gate != 1) return;
|
||||
* ```
|
||||
* or, for shared constructor:
|
||||
* ```
|
||||
* shared int gate;
|
||||
* if (core.atomic.atomicOp!"+="(gate, 1) != 1) return;
|
||||
* ```
|
||||
*/
|
||||
const bool isShared = !!scd.isSharedStaticCtorDeclaration();
|
||||
auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null);
|
||||
v.storage_class = STC.temp | (scd.isSharedStaticCtorDeclaration() ? STC.static_ : STC.tls);
|
||||
v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : 0);
|
||||
|
||||
auto sa = new Statements();
|
||||
Statement s = new ExpStatement(Loc.initial, v);
|
||||
sa.push(s);
|
||||
|
||||
Expression e = new IdentifierExp(Loc.initial, v.ident);
|
||||
e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!1);
|
||||
Expression e;
|
||||
if (isShared)
|
||||
{
|
||||
e = doAtomicOp("+=", v.ident, IntegerExp.literal!(1));
|
||||
if (e is null)
|
||||
{
|
||||
scd.error("shared static constructor within a template require `core.atomic : atomicOp` to be present");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e = new AddAssignExp(
|
||||
Loc.initial, new IdentifierExp(Loc.initial, v.ident), IntegerExp.literal!1);
|
||||
}
|
||||
|
||||
e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!1);
|
||||
s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
|
||||
|
||||
|
@ -4309,22 +4329,41 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
*/
|
||||
if (sdd.isInstantiated() && sdd.semanticRun < PASS.semantic)
|
||||
{
|
||||
/* Add this prefix to the function:
|
||||
* static int gate;
|
||||
* if (--gate != 0) return;
|
||||
* Increment gate during constructor execution.
|
||||
* Note that this is not thread safe; should not have threads
|
||||
* during static destruction.
|
||||
/* Add this prefix to the constructor:
|
||||
* ```
|
||||
* static int gate;
|
||||
* if (--gate != 0) return;
|
||||
* ```
|
||||
* or, for shared constructor:
|
||||
* ```
|
||||
* shared int gate;
|
||||
* if (core.atomic.atomicOp!"-="(gate, 1) != 0) return;
|
||||
* ```
|
||||
*/
|
||||
const bool isShared = !!sdd.isSharedStaticDtorDeclaration();
|
||||
auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null);
|
||||
v.storage_class = STC.temp | (sdd.isSharedStaticDtorDeclaration() ? STC.static_ : STC.tls);
|
||||
v.storage_class = STC.temp | STC.static_ | (isShared ? STC.shared_ : 0);
|
||||
|
||||
auto sa = new Statements();
|
||||
Statement s = new ExpStatement(Loc.initial, v);
|
||||
sa.push(s);
|
||||
|
||||
Expression e = new IdentifierExp(Loc.initial, v.ident);
|
||||
e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!(-1));
|
||||
Expression e;
|
||||
if (isShared)
|
||||
{
|
||||
e = doAtomicOp("-=", v.ident, IntegerExp.literal!(1));
|
||||
if (e is null)
|
||||
{
|
||||
sdd.error("shared static destructo within a template require `core.atomic : atomicOp` to be present");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e = new AddAssignExp(
|
||||
Loc.initial, new IdentifierExp(Loc.initial, v.ident), IntegerExp.literal!(-1));
|
||||
}
|
||||
|
||||
e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!0);
|
||||
s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
|
||||
|
||||
|
@ -6833,3 +6872,48 @@ bool determineFields(AggregateDeclaration ad)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Do an atomic operation (currently tailored to [shared] static ctors|dtors) needs
|
||||
private CallExp doAtomicOp (string op, Identifier var, Expression arg)
|
||||
{
|
||||
__gshared Import imp = null;
|
||||
__gshared Identifier[1] id;
|
||||
|
||||
assert(op == "-=" || op == "+=");
|
||||
|
||||
const loc = Loc.initial;
|
||||
|
||||
// Below code is similar to `loadStdMath` (used for `^^` operator)
|
||||
if (!imp)
|
||||
{
|
||||
id[0] = Id.core;
|
||||
auto s = new Import(Loc.initial, id[], Id.atomic, null, true);
|
||||
// Module.load will call fatal() if there's no std.math available.
|
||||
// Gag the error here, pushing the error handling to the caller.
|
||||
uint errors = global.startGagging();
|
||||
s.load(null);
|
||||
if (s.mod)
|
||||
{
|
||||
s.mod.importAll(null);
|
||||
s.mod.dsymbolSemantic(null);
|
||||
}
|
||||
global.endGagging(errors);
|
||||
imp = s;
|
||||
}
|
||||
// Module couldn't be loaded
|
||||
if (imp.mod is null)
|
||||
return null;
|
||||
|
||||
Objects* tiargs = new Objects(1);
|
||||
(*tiargs)[0] = new StringExp(loc, op);
|
||||
|
||||
Expressions* args = new Expressions(2);
|
||||
(*args)[0] = new IdentifierExp(loc, var);
|
||||
(*args)[1] = arg;
|
||||
|
||||
auto sc = new ScopeExp(loc, imp.mod);
|
||||
auto dti = new DotTemplateInstanceExp(
|
||||
loc, sc, Id.atomicOp, tiargs);
|
||||
|
||||
return CallExp.create(loc, dti, args);
|
||||
}
|
||||
|
|
|
@ -1943,7 +1943,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
|
|||
{
|
||||
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
|
||||
}
|
||||
else if (global.params.rvalueRefParam)
|
||||
else if (global.params.rvalueRefParam == FeatureState.enabled)
|
||||
{
|
||||
// Allow implicit conversion to ref
|
||||
}
|
||||
|
@ -8346,7 +8346,7 @@ struct TemplateStats
|
|||
}
|
||||
}
|
||||
|
||||
void printTemplateStats()
|
||||
extern (C++) void printTemplateStats()
|
||||
{
|
||||
static struct TemplateDeclarationStats
|
||||
{
|
||||
|
|
|
@ -860,7 +860,7 @@ public:
|
|||
origType = vd.originalType;
|
||||
scope(exit) origType = null;
|
||||
|
||||
if (!vd.alignment.isDefault())
|
||||
if (!vd.alignment.isDefault() && !vd.alignment.isUnknown())
|
||||
{
|
||||
buf.printf("// Ignoring var %s alignment %d", vd.toChars(), vd.alignment.get());
|
||||
buf.writenl();
|
||||
|
@ -940,7 +940,7 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.tls | AST.STC.gshared) ||
|
||||
if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.gshared) ||
|
||||
vd.parent && vd.parent.isModule())
|
||||
{
|
||||
if (vd.linkage != LINK.c && vd.linkage != LINK.cpp && !(tdparent && (this.linkage == LINK.c || this.linkage == LINK.cpp)))
|
||||
|
@ -948,11 +948,6 @@ public:
|
|||
ignored("variable %s because of linkage", vd.toPrettyChars());
|
||||
return;
|
||||
}
|
||||
if (vd.storage_class & AST.STC.tls)
|
||||
{
|
||||
ignored("variable %s because of thread-local storage", vd.toPrettyChars());
|
||||
return;
|
||||
}
|
||||
if (!isSupportedType(type))
|
||||
{
|
||||
ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars());
|
||||
|
@ -1934,6 +1929,8 @@ public:
|
|||
buf.writestring("unsigned long long");
|
||||
else if (ed.ident == DMDType.c_long_double)
|
||||
buf.writestring("long double");
|
||||
else if (ed.ident == DMDType.c_char)
|
||||
buf.writestring("char");
|
||||
else if (ed.ident == DMDType.c_wchar_t)
|
||||
buf.writestring("wchar_t");
|
||||
else if (ed.ident == DMDType.c_complex_float)
|
||||
|
@ -2681,6 +2678,18 @@ public:
|
|||
{
|
||||
if (vd._init && !vd._init.isVoidInitializer())
|
||||
return AST.initializerToExpression(vd._init);
|
||||
else if (auto ts = vd.type.isTypeStruct())
|
||||
{
|
||||
if (!ts.sym.noDefaultCtor && !ts.sym.isUnionDeclaration())
|
||||
{
|
||||
// Generate a call to the default constructor that we've generated.
|
||||
auto sle = new AST.StructLiteralExp(Loc.initial, ts.sym, new AST.Expressions(0));
|
||||
sle.type = vd.type;
|
||||
return sle;
|
||||
}
|
||||
else
|
||||
return vd.type.defaultInitLiteral(Loc.initial);
|
||||
}
|
||||
else
|
||||
return vd.type.defaultInitLiteral(Loc.initial);
|
||||
}
|
||||
|
@ -2971,6 +2980,7 @@ struct DMDType
|
|||
__gshared Identifier c_longlong;
|
||||
__gshared Identifier c_ulonglong;
|
||||
__gshared Identifier c_long_double;
|
||||
__gshared Identifier c_char;
|
||||
__gshared Identifier c_wchar_t;
|
||||
__gshared Identifier c_complex_float;
|
||||
__gshared Identifier c_complex_double;
|
||||
|
@ -2984,6 +2994,7 @@ struct DMDType
|
|||
c_ulonglong = Identifier.idPool("__c_ulonglong");
|
||||
c_long_double = Identifier.idPool("__c_long_double");
|
||||
c_wchar_t = Identifier.idPool("__c_wchar_t");
|
||||
c_char = Identifier.idPool("__c_char");
|
||||
c_complex_float = Identifier.idPool("__c_complex_float");
|
||||
c_complex_double = Identifier.idPool("__c_complex_double");
|
||||
c_complex_real = Identifier.idPool("__c_complex_real");
|
||||
|
|
|
@ -658,7 +658,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
|
|||
p == fd)
|
||||
{
|
||||
if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars());
|
||||
inferReturn(fd, v); // infer addition of 'return' to make `return scope`
|
||||
inferReturn(fd, v, /*returnScope:*/ true); // infer addition of 'return' to make `return scope`
|
||||
}
|
||||
|
||||
if (!(va && va.isScope()) || vaIsRef)
|
||||
|
@ -1215,7 +1215,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
|
|||
sc.func.flags & FUNCFLAG.returnInprocess &&
|
||||
p == sc.func)
|
||||
{
|
||||
inferReturn(sc.func, v); // infer addition of 'return'
|
||||
inferReturn(sc.func, v, /*returnScope:*/ true); // infer addition of 'return'
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1355,7 +1355,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
|
|||
if (sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func &&
|
||||
(vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope))
|
||||
{
|
||||
inferReturn(sc.func, v); // infer addition of 'return'
|
||||
inferReturn(sc.func, v, /*returnScope:*/ false); // infer addition of 'return'
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1404,23 +1404,25 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
|
|||
* Params:
|
||||
* fd = function that v is a parameter to
|
||||
* v = parameter that needs to be STC.return_
|
||||
* returnScope = infer `return scope` instead of `return ref`
|
||||
*/
|
||||
|
||||
private void inferReturn(FuncDeclaration fd, VarDeclaration v)
|
||||
private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
|
||||
{
|
||||
// v is a local in the current function
|
||||
|
||||
//printf("for function '%s' inferring 'return' for variable '%s'\n", fd.toChars(), v.toChars());
|
||||
v.storage_class |= STC.return_ | STC.returninferred;
|
||||
//printf("for function '%s' inferring 'return' for variable '%s', returnScope: %d\n", fd.toChars(), v.toChars(), returnScope);
|
||||
auto newStcs = STC.return_ | STC.returninferred | (returnScope ? STC.returnScope : 0);
|
||||
v.storage_class |= newStcs;
|
||||
|
||||
if (v == fd.vthis)
|
||||
{
|
||||
/* v is the 'this' reference, so mark the function
|
||||
*/
|
||||
fd.storage_class |= STC.return_ | STC.returninferred;
|
||||
fd.storage_class |= newStcs;
|
||||
if (auto tf = fd.type.isTypeFunction())
|
||||
{
|
||||
//printf("'this' too %p %s\n", tf, sc.func.toChars());
|
||||
tf.isreturnscope = returnScope;
|
||||
tf.isreturn = true;
|
||||
tf.isreturninferred = true;
|
||||
}
|
||||
|
@ -1434,7 +1436,7 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v)
|
|||
{
|
||||
if (p.ident == v.ident)
|
||||
{
|
||||
p.storageClass |= STC.return_ | STC.returninferred;
|
||||
p.storageClass |= newStcs;
|
||||
break; // there can be only one
|
||||
}
|
||||
}
|
||||
|
@ -1732,33 +1734,69 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
|
|||
{
|
||||
DotVarExp dve = e.e1.isDotVarExp();
|
||||
FuncDeclaration fd = dve.var.isFuncDeclaration();
|
||||
AggregateDeclaration ad;
|
||||
if (global.params.useDIP1000 == FeatureState.enabled && tf.isreturn && fd && (ad = fd.isThis()) !is null)
|
||||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
{
|
||||
if (ad.isClassDeclaration() || tf.isScopeQual) // this is 'return scope'
|
||||
dve.e1.accept(this);
|
||||
else if (ad.isStructDeclaration()) // this is 'return ref'
|
||||
{
|
||||
if (tf.isref)
|
||||
if (fd && fd.isThis())
|
||||
{
|
||||
/* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this`
|
||||
*/
|
||||
|
||||
/*****************************
|
||||
* Concoct storage class for member function's implicit `this` parameter.
|
||||
* Params:
|
||||
* fd = member function
|
||||
* Returns:
|
||||
* storage class for fd's `this`
|
||||
*/
|
||||
StorageClass getThisStorageClass(FuncDeclaration fd)
|
||||
{
|
||||
/* Treat calling:
|
||||
* struct S { ref S foo() return; }
|
||||
* as:
|
||||
* this;
|
||||
*/
|
||||
dve.e1.accept(this);
|
||||
StorageClass stc;
|
||||
auto tf = fd.type.toBasetype().isTypeFunction();
|
||||
if (tf.isreturn)
|
||||
stc |= STC.return_;
|
||||
if (tf.isreturnscope)
|
||||
stc |= STC.returnScope;
|
||||
auto ad = fd.isThis();
|
||||
if (ad.isClassDeclaration() || tf.isScopeQual)
|
||||
stc |= STC.scope_;
|
||||
if (ad.isStructDeclaration())
|
||||
stc |= STC.ref_; // `this` for a struct member function is passed by `ref`
|
||||
return stc;
|
||||
}
|
||||
|
||||
const psr = buildScopeRef(getThisStorageClass(fd));
|
||||
if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
|
||||
dve.e1.accept(this);
|
||||
else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
|
||||
{
|
||||
if (tf.isref)
|
||||
{
|
||||
/* Treat calling:
|
||||
* struct S { ref S foo() return; }
|
||||
* as:
|
||||
* this;
|
||||
*/
|
||||
dve.e1.accept(this);
|
||||
}
|
||||
else
|
||||
escapeByRef(dve.e1, er, live);
|
||||
}
|
||||
else
|
||||
escapeByRef(dve.e1, er, live);
|
||||
}
|
||||
}
|
||||
else if (dve.var.storage_class & STC.return_ || tf.isreturn)
|
||||
else
|
||||
{
|
||||
if (dve.var.storage_class & STC.scope_)
|
||||
// Calling member function before dip1000
|
||||
StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_);
|
||||
if (tf.isreturn)
|
||||
stc |= STC.return_;
|
||||
|
||||
const psr = buildScopeRef(stc);
|
||||
if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
|
||||
dve.e1.accept(this);
|
||||
else if (dve.var.storage_class & STC.ref_)
|
||||
else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
|
||||
escapeByRef(dve.e1, er, live);
|
||||
}
|
||||
|
||||
// If it's also a nested function that is 'return scope'
|
||||
if (fd && fd.isNested())
|
||||
{
|
||||
|
@ -1996,19 +2034,29 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
|
|||
return;
|
||||
}
|
||||
|
||||
if (dve.var.storage_class & STC.return_ || tf.isreturn)
|
||||
{
|
||||
if (dve.var.storage_class & STC.ref_ || tf.isref)
|
||||
dve.e1.accept(this);
|
||||
else if (dve.var.storage_class & STC.scope_ || tf.isScopeQual)
|
||||
escapeByValue(dve.e1, er, live);
|
||||
}
|
||||
StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_);
|
||||
if (tf.isreturn)
|
||||
stc |= STC.return_;
|
||||
if (tf.isref)
|
||||
stc |= STC.ref_;
|
||||
if (tf.isScopeQual)
|
||||
stc |= STC.scope_;
|
||||
if (tf.isreturnscope)
|
||||
stc |= STC.returnScope;
|
||||
|
||||
const psr = buildScopeRef(stc);
|
||||
if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
|
||||
dve.e1.accept(this);
|
||||
else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
|
||||
escapeByValue(dve.e1, er, live);
|
||||
|
||||
// If it's also a nested function that is 'return ref'
|
||||
FuncDeclaration fd = dve.var.isFuncDeclaration();
|
||||
if (fd && fd.isNested())
|
||||
if (FuncDeclaration fd = dve.var.isFuncDeclaration())
|
||||
{
|
||||
if (tf.isreturn)
|
||||
if (fd.isNested() && tf.isreturn)
|
||||
{
|
||||
er.byexp.push(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If it's a delegate, check it too
|
||||
|
|
|
@ -1797,7 +1797,7 @@ extern (C++) final class IntegerExp : Expression
|
|||
{
|
||||
super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp));
|
||||
this.type = Type.tint32;
|
||||
this.value = cast(d_int32)value;
|
||||
this.value = cast(int)value;
|
||||
}
|
||||
|
||||
static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
|
||||
|
@ -1838,8 +1838,8 @@ extern (C++) final class IntegerExp : Expression
|
|||
const val = normalize(ty, value);
|
||||
value = val;
|
||||
return (ty == Tuns64)
|
||||
? real_t(cast(d_uns64)val)
|
||||
: real_t(cast(d_int64)val);
|
||||
? real_t(cast(ulong)val)
|
||||
: real_t(cast(long)val);
|
||||
}
|
||||
|
||||
override real_t toImaginary()
|
||||
|
@ -1895,38 +1895,38 @@ extern (C++) final class IntegerExp : Expression
|
|||
break;
|
||||
|
||||
case Tint8:
|
||||
result = cast(d_int8)value;
|
||||
result = cast(byte)value;
|
||||
break;
|
||||
|
||||
case Tchar:
|
||||
case Tuns8:
|
||||
result = cast(d_uns8)value;
|
||||
result = cast(ubyte)value;
|
||||
break;
|
||||
|
||||
case Tint16:
|
||||
result = cast(d_int16)value;
|
||||
result = cast(short)value;
|
||||
break;
|
||||
|
||||
case Twchar:
|
||||
case Tuns16:
|
||||
result = cast(d_uns16)value;
|
||||
result = cast(ushort)value;
|
||||
break;
|
||||
|
||||
case Tint32:
|
||||
result = cast(d_int32)value;
|
||||
result = cast(int)value;
|
||||
break;
|
||||
|
||||
case Tdchar:
|
||||
case Tuns32:
|
||||
result = cast(d_uns32)value;
|
||||
result = cast(uint)value;
|
||||
break;
|
||||
|
||||
case Tint64:
|
||||
result = cast(d_int64)value;
|
||||
result = cast(long)value;
|
||||
break;
|
||||
|
||||
case Tuns64:
|
||||
result = cast(d_uns64)value;
|
||||
result = cast(ulong)value;
|
||||
break;
|
||||
|
||||
case Tpointer:
|
||||
|
|
|
@ -1992,7 +1992,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
|||
}
|
||||
else if (p.storageClass & STC.ref_)
|
||||
{
|
||||
if (global.params.rvalueRefParam &&
|
||||
if (global.params.rvalueRefParam == FeatureState.enabled &&
|
||||
!arg.isLvalue() &&
|
||||
targ.isCopyable())
|
||||
{ /* allow rvalues to be passed to ref parameters by copying
|
||||
|
@ -7118,6 +7118,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
return;
|
||||
}
|
||||
|
||||
exp.e1 = exp.e1.arrayFuncConv(sc);
|
||||
|
||||
Type tb = exp.e1.type.toBasetype();
|
||||
switch (tb.ty)
|
||||
{
|
||||
|
@ -7441,6 +7443,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
return;
|
||||
}
|
||||
|
||||
if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
|
||||
exp.e1 = exp.e1.arrayFuncConv(sc);
|
||||
|
||||
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
|
||||
if (exp.e1.op == EXP.type)
|
||||
exp.e1 = resolveAliasThis(sc, exp.e1);
|
||||
|
@ -10336,7 +10341,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
|
||||
// Need to divide the result by the stride
|
||||
// Replace (ptr - ptr) with (ptr - ptr) / stride
|
||||
d_int64 stride;
|
||||
long stride;
|
||||
|
||||
// make sure pointer types are compatible
|
||||
if (Expression ex = typeCombine(exp, sc))
|
||||
|
@ -10351,7 +10356,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
{
|
||||
e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
|
||||
}
|
||||
else if (stride == cast(d_int64)SIZE_INVALID)
|
||||
else if (stride == cast(long)SIZE_INVALID)
|
||||
e = ErrorExp.get();
|
||||
else
|
||||
{
|
||||
|
@ -12575,6 +12580,13 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
|
|||
Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
|
||||
return e;
|
||||
}
|
||||
else if (sc.flags & SCOPE.Cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
|
||||
{
|
||||
// Sizeof string literal includes the terminating 0
|
||||
auto se = exp.e1.isStringExp();
|
||||
Expression e = new IntegerExp(exp.loc, (se.len + 1) * se.sz, Type.tsize_t);
|
||||
return e;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
|
||||
|
|
|
@ -20,38 +20,12 @@ import dmd.identifier;
|
|||
enum package_d = "package." ~ mars_ext;
|
||||
enum package_di = "package." ~ hdr_ext;
|
||||
|
||||
extern(C++) struct FileManager
|
||||
struct FileManager
|
||||
{
|
||||
private StringTable!(FileBuffer*) files;
|
||||
private __gshared bool initialized = false;
|
||||
|
||||
nothrow:
|
||||
extern(D) private FileBuffer* readToFileBuffer(const(char)[] filename)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
auto readResult = File.read(filename);
|
||||
if (readResult.success)
|
||||
{
|
||||
FileBuffer* fb;
|
||||
if (auto val = files.lookup(filename))
|
||||
fb = val.value;
|
||||
|
||||
if (!fb)
|
||||
fb = FileBuffer.create();
|
||||
|
||||
fb.data = readResult.extractSlice();
|
||||
|
||||
return files.insert(filename, fb) == null ? null : fb;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Look for the source file if it's different from filename.
|
||||
* Look for .di, .d, directory, and along global.path.
|
||||
|
@ -63,7 +37,7 @@ nothrow:
|
|||
* the found file name or
|
||||
* `null` if it is not different from filename.
|
||||
*/
|
||||
extern(D) static const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
|
||||
static const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
|
||||
{
|
||||
//printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
|
||||
/* Search along path[] for .di file, then .d file, then .i file, then .c file.
|
||||
|
@ -74,6 +48,9 @@ nothrow:
|
|||
scope(exit) FileName.free(sdi.ptr);
|
||||
|
||||
const sd = FileName.forceExt(filename, mars_ext);
|
||||
// Special file name representing `stdin`, always assume its presence
|
||||
if (sd == "__stdin.d")
|
||||
return sd;
|
||||
if (FileName.exists(sd) == 1)
|
||||
return sd;
|
||||
scope(exit) FileName.free(sd.ptr);
|
||||
|
@ -164,33 +141,35 @@ nothrow:
|
|||
* Returns: the loaded source file if it was found in memory,
|
||||
* otherwise `null`
|
||||
*/
|
||||
extern(D) FileBuffer* lookup(FileName filename)
|
||||
const(FileBuffer)* lookup(FileName filename)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
if (auto val = files.lookup(filename.toString))
|
||||
const name = filename.toString;
|
||||
if (auto val = files.lookup(name))
|
||||
return val.value;
|
||||
|
||||
if (name == "__stdin.d")
|
||||
{
|
||||
// There is a chance that the buffer could've been
|
||||
// stolen by a reader with extractSlice, so we should
|
||||
// try and do our reading logic if that happens.
|
||||
if (val !is null && val.value.data !is null)
|
||||
{
|
||||
return val.value;
|
||||
}
|
||||
auto buffer = new FileBuffer(readFromStdin().extractSlice());
|
||||
if (this.files.insert(name, buffer) is null)
|
||||
assert(0, "stdin: Insert after lookup failure should never return `null`");
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const name = filename.toString;
|
||||
auto res = FileName.exists(name);
|
||||
if (res == 1)
|
||||
return readToFileBuffer(name);
|
||||
if (FileName.exists(name) != 1)
|
||||
return null;
|
||||
|
||||
return null;
|
||||
}
|
||||
auto readResult = File.read(name);
|
||||
if (!readResult.success)
|
||||
return null;
|
||||
|
||||
extern(C++) FileBuffer* lookup(const(char)* filename)
|
||||
{
|
||||
return lookup(FileName(filename.toDString));
|
||||
FileBuffer* fb = new FileBuffer(readResult.extractSlice());
|
||||
if (files.insert(name, fb) is null)
|
||||
assert(0, "Insert after lookup failure should never return `null`");
|
||||
|
||||
return fb;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,15 +180,15 @@ nothrow:
|
|||
* Returns: the loaded source file if it was found in memory,
|
||||
* otherwise `null`
|
||||
*/
|
||||
extern(D) const(char)[][] getLines(FileName file)
|
||||
const(char)[][] getLines(FileName file)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
const(char)[][] lines;
|
||||
if (FileBuffer* buffer = lookup(file))
|
||||
if (const buffer = lookup(file))
|
||||
{
|
||||
ubyte[] slice = buffer.data[0 .. buffer.data.length];
|
||||
const slice = buffer.data[0 .. buffer.data.length];
|
||||
size_t start, end;
|
||||
ubyte c;
|
||||
for (auto i = 0; i < slice.length; i++)
|
||||
|
@ -260,7 +239,7 @@ nothrow:
|
|||
*
|
||||
* Returns: The FileBuffer added, or null
|
||||
*/
|
||||
extern(D) FileBuffer* add(FileName filename, FileBuffer* filebuffer)
|
||||
FileBuffer* add(FileName filename, FileBuffer* filebuffer)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
@ -269,19 +248,10 @@ nothrow:
|
|||
return val == null ? null : val.value;
|
||||
}
|
||||
|
||||
extern(C++) FileBuffer* add(const(char)* filename, FileBuffer* filebuffer)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
auto val = files.insert(filename.toDString, filebuffer);
|
||||
return val == null ? null : val.value;
|
||||
}
|
||||
|
||||
__gshared fileManager = FileManager();
|
||||
|
||||
// Initialize the global FileManager singleton
|
||||
extern(C++) static __gshared void _init()
|
||||
private void _init()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
|
@ -295,3 +265,46 @@ nothrow:
|
|||
files._init();
|
||||
}
|
||||
}
|
||||
|
||||
private FileBuffer readFromStdin() nothrow
|
||||
{
|
||||
import core.stdc.stdio;
|
||||
import dmd.errors;
|
||||
import dmd.root.rmem;
|
||||
|
||||
enum bufIncrement = 128 * 1024;
|
||||
size_t pos = 0;
|
||||
size_t sz = bufIncrement;
|
||||
|
||||
ubyte* buffer = null;
|
||||
for (;;)
|
||||
{
|
||||
buffer = cast(ubyte*)mem.xrealloc(buffer, sz + 4); // +2 for sentinel and +2 for lexer
|
||||
|
||||
// Fill up buffer
|
||||
do
|
||||
{
|
||||
assert(sz > pos);
|
||||
size_t rlen = fread(buffer + pos, 1, sz - pos, stdin);
|
||||
pos += rlen;
|
||||
if (ferror(stdin))
|
||||
{
|
||||
import core.stdc.errno;
|
||||
error(Loc.initial, "cannot read from stdin, errno = %d", errno);
|
||||
fatal();
|
||||
}
|
||||
if (feof(stdin))
|
||||
{
|
||||
// We're done
|
||||
assert(pos < sz + 2);
|
||||
buffer[pos .. pos + 4] = '\0';
|
||||
return FileBuffer(buffer[0 .. pos]);
|
||||
}
|
||||
} while (pos < sz);
|
||||
|
||||
// Buffer full, expand
|
||||
sz += bufIncrement;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
}
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
|
||||
/* Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* https://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* https://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "root/file.h"
|
||||
|
||||
struct FileManager
|
||||
{
|
||||
static void _init();
|
||||
FileBuffer* lookup(const char* filename);
|
||||
FileBuffer* add(const char* filename, FileBuffer* filebuffer);
|
||||
};
|
|
@ -161,11 +161,11 @@ extern (C++) struct Param
|
|||
FeatureState dtorFields; // destruct fields of partially constructed objects
|
||||
// https://issues.dlang.org/show_bug.cgi?id=14246
|
||||
bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
|
||||
bool rvalueRefParam; // allow rvalues to be arguments to ref parameters
|
||||
// https://dconf.org/2019/talks/alexandrescu.html
|
||||
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
|
||||
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
|
||||
// Implementation: https://github.com/dlang/dmd/pull/9817
|
||||
FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters
|
||||
// https://dconf.org/2019/talks/alexandrescu.html
|
||||
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
|
||||
// https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
|
||||
// Implementation: https://github.com/dlang/dmd/pull/9817
|
||||
|
||||
CppStdRevision cplusplus = CppStdRevision.cpp11; // version of C++ standard to support
|
||||
|
||||
|
@ -486,15 +486,6 @@ alias dinteger_t = ulong;
|
|||
alias sinteger_t = long;
|
||||
alias uinteger_t = ulong;
|
||||
|
||||
alias d_int8 = int8_t;
|
||||
alias d_uns8 = uint8_t;
|
||||
alias d_int16 = int16_t;
|
||||
alias d_uns16 = uint16_t;
|
||||
alias d_int32 = int32_t;
|
||||
alias d_uns32 = uint32_t;
|
||||
alias d_int64 = int64_t;
|
||||
alias d_uns64 = uint64_t;
|
||||
|
||||
version (DMDLIB)
|
||||
{
|
||||
version = LocOffset;
|
||||
|
|
|
@ -145,7 +145,7 @@ struct Param
|
|||
FeatureState dtorFields; // destruct fields of partially constructed objects
|
||||
// https://issues.dlang.org/show_bug.cgi?id=14246
|
||||
bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
|
||||
bool rvalueRefParam; // allow rvalues to be arguments to ref parameters
|
||||
FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters
|
||||
CppStdRevision cplusplus; // version of C++ name mangling to support
|
||||
bool markdown; // enable Markdown replacements in Ddoc
|
||||
bool vmarkdown; // list instances of Markdown replacements in Ddoc
|
||||
|
@ -346,15 +346,6 @@ typedef long long sinteger_t;
|
|||
typedef unsigned long long uinteger_t;
|
||||
#endif
|
||||
|
||||
typedef int8_t d_int8;
|
||||
typedef uint8_t d_uns8;
|
||||
typedef int16_t d_int16;
|
||||
typedef uint16_t d_uns16;
|
||||
typedef int32_t d_int32;
|
||||
typedef uint32_t d_uns32;
|
||||
typedef int64_t d_int64;
|
||||
typedef uint64_t d_uns64;
|
||||
|
||||
// file location
|
||||
struct Loc
|
||||
{
|
||||
|
@ -415,4 +406,12 @@ enum class PINLINE : uint8_t
|
|||
always // always inline
|
||||
};
|
||||
|
||||
enum class FileType : uint8_t
|
||||
{
|
||||
d, /// normal D source file
|
||||
dhdr, /// D header file (.di)
|
||||
ddoc, /// Ddoc documentation file (.dd)
|
||||
c, /// C source file
|
||||
};
|
||||
|
||||
typedef uinteger_t StorageClass;
|
||||
|
|
|
@ -2843,7 +2843,6 @@ string stcToString(ref StorageClass stc)
|
|||
SCstring(STC.pure_, Token.toString(TOK.pure_)),
|
||||
SCstring(STC.ref_, Token.toString(TOK.ref_)),
|
||||
SCstring(STC.return_, Token.toString(TOK.return_)),
|
||||
SCstring(STC.tls, "__thread"),
|
||||
SCstring(STC.gshared, Token.toString(TOK.gshared)),
|
||||
SCstring(STC.nogc, "@nogc"),
|
||||
SCstring(STC.live, "@live"),
|
||||
|
|
|
@ -123,6 +123,7 @@ immutable Msgtable[] msgtable =
|
|||
{ "__c_longlong" },
|
||||
{ "__c_ulonglong" },
|
||||
{ "__c_long_double" },
|
||||
{ "__c_char" },
|
||||
{ "__c_wchar_t" },
|
||||
{ "__c_complex_float" },
|
||||
{ "__c_complex_double" },
|
||||
|
@ -359,6 +360,8 @@ immutable Msgtable[] msgtable =
|
|||
{ "core" },
|
||||
{ "etc" },
|
||||
{ "attribute" },
|
||||
{ "atomic" },
|
||||
{ "atomicOp" },
|
||||
{ "math" },
|
||||
{ "sin" },
|
||||
{ "cos" },
|
||||
|
|
|
@ -274,6 +274,7 @@ Expression castCallAmbiguity(Expression e, Scope* sc)
|
|||
|
||||
bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2)
|
||||
{
|
||||
//printf("cFuncEquivalence()\n %s\n %s\n", tf1.toChars(), tf2.toChars());
|
||||
if (tf1.equals(tf2))
|
||||
return true;
|
||||
|
||||
|
@ -284,22 +285,31 @@ bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2)
|
|||
if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0)
|
||||
return true;
|
||||
|
||||
if (!tf1.parameterList.hasIdentifierList &&
|
||||
!tf2.parameterList.hasIdentifierList)
|
||||
return false; // both functions are prototyped
|
||||
|
||||
// Otherwise ignore variadicness, as K+R functions are all variadic
|
||||
|
||||
if (!tf1.nextOf().equals(tf2.nextOf()))
|
||||
return false; // function return types don't match
|
||||
|
||||
if (tf1.parameterList.length != tf2.parameterList.length)
|
||||
return false;
|
||||
|
||||
if (!tf1.parameterList.hasIdentifierList && !tf2.parameterList.hasIdentifierList) // if both are prototyped
|
||||
{
|
||||
if (tf1.parameterList.varargs != tf2.parameterList.varargs)
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (i, fparam ; tf1.parameterList)
|
||||
{
|
||||
Type t1 = fparam.type;
|
||||
Type t2 = tf2.parameterList[i].type;
|
||||
|
||||
/* Strip off head const.
|
||||
* Not sure if this is C11, but other compilers treat
|
||||
* `void fn(int)` and `fn(const int x)`
|
||||
* as equivalent.
|
||||
*/
|
||||
t1 = t1.mutableOf();
|
||||
t2 = t2.mutableOf();
|
||||
|
||||
if (!t1.equals(t2))
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -371,6 +371,12 @@ class Lexer
|
|||
'd';
|
||||
return;
|
||||
}
|
||||
else if (p[1] == '8' && p[2] == '\"') // C UTF-8 string literal
|
||||
{
|
||||
p += 2;
|
||||
escapeStringConstant(t);
|
||||
return;
|
||||
}
|
||||
goto case_ident;
|
||||
|
||||
case 'r':
|
||||
|
@ -1979,8 +1985,8 @@ class Lexer
|
|||
if (base <= 10 && n > 0 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
|
||||
{
|
||||
if (Ccompile && base == 10 &&
|
||||
(p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L'))
|
||||
goto Lreal; // if `1.f` or `1.L`
|
||||
(p[1] == 'e' || p[1] == 'E' || p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L'))
|
||||
goto Lreal; // if `1.e6` or `1.f` or `1.L`
|
||||
goto Ldone; // if ".identifier" or ".unicode"
|
||||
}
|
||||
if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80))
|
||||
|
@ -2495,8 +2501,10 @@ class Lexer
|
|||
}
|
||||
}
|
||||
const isLong = (result == TOK.float80Literal || result == TOK.imaginary80Literal);
|
||||
if (isOutOfRange && !isLong)
|
||||
if (isOutOfRange && !isLong && (!Ccompile || hex))
|
||||
{
|
||||
/* C11 6.4.4.2 doesn't actually care if it is not representable if it is not hex
|
||||
*/
|
||||
const char* suffix = (result == TOK.float32Literal || result == TOK.imaginary32Literal) ? "f" : "";
|
||||
error(scanloc, "number `%s%s` is not representable", sbufptr, suffix);
|
||||
}
|
||||
|
|
|
@ -71,12 +71,10 @@ public:
|
|||
FileName objfile; // output .obj file
|
||||
FileName hdrfile; // 'header' file
|
||||
FileName docfile; // output documentation file
|
||||
FileBuffer *srcBuffer; // set during load(), free'd in parse()
|
||||
DArray<unsigned char> src; // Raw content of the file
|
||||
unsigned errors; // if any errors in file
|
||||
unsigned numlines; // number of lines in source file
|
||||
bool isHdrFile; // if it is a header (.di) file
|
||||
bool isCFile; // if it is a C (.c) file
|
||||
bool isDocFile; // if it is a documentation input file, not D source
|
||||
FileType filetype; // source file type
|
||||
bool hasAlwaysInlines; // contains references to functions that must be inlined
|
||||
bool isPackageFile; // if it is a package.d
|
||||
Package *pkg; // if isPackageFile is true, the Package that contains this package.d
|
||||
|
|
|
@ -55,7 +55,7 @@ import dmd.visitor;
|
|||
enum LOGDOTEXP = 0; // log ::dotExp()
|
||||
enum LOGDEFAULTINIT = 0; // log ::defaultInit()
|
||||
|
||||
enum SIZE_INVALID = (~cast(d_uns64)0); // error return from size() functions
|
||||
enum SIZE_INVALID = (~cast(uinteger_t)0); // error return from size() functions
|
||||
|
||||
|
||||
/***************************
|
||||
|
@ -887,12 +887,12 @@ extern (C++) abstract class Type : ASTNode
|
|||
stringtable = stringtable.init;
|
||||
}
|
||||
|
||||
final d_uns64 size()
|
||||
final uinteger_t size()
|
||||
{
|
||||
return size(Loc.initial);
|
||||
}
|
||||
|
||||
d_uns64 size(const ref Loc loc)
|
||||
uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
error(loc, "no size for type `%s`", toChars());
|
||||
return SIZE_INVALID;
|
||||
|
@ -2770,7 +2770,7 @@ extern (C++) final class TypeError : Type
|
|||
return this;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc)
|
||||
override uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
return SIZE_INVALID;
|
||||
}
|
||||
|
@ -3237,7 +3237,7 @@ extern (C++) final class TypeBasic : Type
|
|||
return this;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
uint size;
|
||||
//printf("TypeBasic::size()\n");
|
||||
|
@ -3411,8 +3411,8 @@ extern (C++) final class TypeBasic : Type
|
|||
// If converting from integral to integral
|
||||
if (tob.flags & TFlags.integral)
|
||||
{
|
||||
d_uns64 sz = size(Loc.initial);
|
||||
d_uns64 tosz = tob.size(Loc.initial);
|
||||
const sz = size(Loc.initial);
|
||||
const tosz = tob.size(Loc.initial);
|
||||
|
||||
/* Can't convert to smaller size
|
||||
*/
|
||||
|
@ -3512,7 +3512,7 @@ extern (C++) final class TypeVector : Type
|
|||
return new TypeVector(basetype.syntaxCopy());
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc)
|
||||
override uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
return basetype.size();
|
||||
}
|
||||
|
@ -3661,7 +3661,7 @@ extern (C++) final class TypeSArray : TypeArray
|
|||
return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc)
|
||||
override uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
//printf("TypeSArray::size()\n");
|
||||
const n = numberOfElems(loc);
|
||||
|
@ -3860,7 +3860,7 @@ extern (C++) final class TypeDArray : TypeArray
|
|||
return result;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
//printf("TypeDArray::size()\n");
|
||||
return target.ptrsize * 2;
|
||||
|
@ -3964,7 +3964,7 @@ extern (C++) final class TypeAArray : TypeArray
|
|||
return result;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
return target.ptrsize;
|
||||
}
|
||||
|
@ -4056,7 +4056,7 @@ extern (C++) final class TypePointer : TypeNext
|
|||
return result;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
return target.ptrsize;
|
||||
}
|
||||
|
@ -4159,7 +4159,7 @@ extern (C++) final class TypeReference : TypeNext
|
|||
return result;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
return target.ptrsize;
|
||||
}
|
||||
|
@ -4596,8 +4596,10 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
if (global.gag && !global.params.showGaggedErrors)
|
||||
return null;
|
||||
// show qualification when toChars() is the same but types are different
|
||||
auto at = arg.type.toChars();
|
||||
bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.toChars()) == 0;
|
||||
// https://issues.dlang.org/show_bug.cgi?id=19948
|
||||
// when comparing the type with strcmp, we need to drop the qualifier
|
||||
auto at = arg.type.mutableOf().toChars();
|
||||
bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.mutableOf().toChars()) == 0;
|
||||
if (qual)
|
||||
at = arg.type.toPrettyChars(true);
|
||||
OutBuffer buf;
|
||||
|
@ -4845,7 +4847,7 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
// Need to make this a rvalue through a temporary
|
||||
m = MATCH.convert;
|
||||
}
|
||||
else if (!global.params.rvalueRefParam ||
|
||||
else if (global.params.rvalueRefParam != FeatureState.enabled ||
|
||||
p.storageClass & STC.out_ ||
|
||||
!arg.type.isCopyable()) // can't copy to temp for ref parameter
|
||||
{
|
||||
|
@ -5328,7 +5330,7 @@ extern (C++) final class TypeDelegate : TypeNext
|
|||
return t;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
return target.ptrsize * 2;
|
||||
}
|
||||
|
@ -5435,7 +5437,7 @@ extern (C++) final class TypeTraits : Type
|
|||
v.visit(this);
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc)
|
||||
override uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
return SIZE_INVALID;
|
||||
}
|
||||
|
@ -5562,7 +5564,7 @@ extern (C++) abstract class TypeQualified : Type
|
|||
idents.push(e);
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc)
|
||||
override uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
error(this.loc, "size of type `%s` is not known", toChars());
|
||||
return SIZE_INVALID;
|
||||
|
@ -5717,7 +5719,7 @@ extern (C++) final class TypeTypeof : TypeQualified
|
|||
return s;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc)
|
||||
override uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
if (exp.type)
|
||||
return exp.type.size(loc);
|
||||
|
@ -5792,7 +5794,7 @@ extern (C++) final class TypeStruct : Type
|
|||
return "struct";
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc)
|
||||
override uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
return sym.size(loc);
|
||||
}
|
||||
|
@ -6148,7 +6150,7 @@ extern (C++) final class TypeEnum : Type
|
|||
return this;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc)
|
||||
override uinteger_t size(const ref Loc loc)
|
||||
{
|
||||
return sym.getMemtype(loc).size(loc);
|
||||
}
|
||||
|
@ -6315,7 +6317,7 @@ extern (C++) final class TypeClass : Type
|
|||
return "class";
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
return target.ptrsize;
|
||||
}
|
||||
|
@ -6718,7 +6720,7 @@ extern (C++) final class TypeNull : Type
|
|||
return true;
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
return tvoidptr.size(loc);
|
||||
}
|
||||
|
@ -6777,7 +6779,7 @@ extern (C++) final class TypeNoreturn : Type
|
|||
return true; // bottom type can be implicitly converted to any other type
|
||||
}
|
||||
|
||||
override d_uns64 size(const ref Loc loc) const
|
||||
override uinteger_t size(const ref Loc loc) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ enum class TY : uint8_t
|
|||
TMAX
|
||||
};
|
||||
|
||||
#define SIZE_INVALID (~(d_uns64)0) // error return from size() functions
|
||||
#define SIZE_INVALID (~(uinteger_t)0) // error return from size() functions
|
||||
|
||||
|
||||
/**
|
||||
|
@ -230,8 +230,8 @@ public:
|
|||
char *toPrettyChars(bool QualifyTypes = false);
|
||||
static void _init();
|
||||
|
||||
d_uns64 size();
|
||||
virtual d_uns64 size(const Loc &loc);
|
||||
uinteger_t size();
|
||||
virtual uinteger_t size(const Loc &loc);
|
||||
virtual unsigned alignsize();
|
||||
Type *trySemantic(const Loc &loc, Scope *sc);
|
||||
Type *merge2();
|
||||
|
@ -357,7 +357,7 @@ public:
|
|||
const char *kind();
|
||||
TypeError *syntaxCopy();
|
||||
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
Expression *defaultInitLiteral(const Loc &loc);
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
@ -393,7 +393,7 @@ public:
|
|||
|
||||
const char *kind();
|
||||
TypeBasic *syntaxCopy();
|
||||
d_uns64 size(const Loc &loc) /*const*/;
|
||||
uinteger_t size(const Loc &loc) /*const*/;
|
||||
unsigned alignsize();
|
||||
bool isintegral();
|
||||
bool isfloating() /*const*/;
|
||||
|
@ -418,7 +418,7 @@ public:
|
|||
static TypeVector *create(Type *basetype);
|
||||
const char *kind();
|
||||
TypeVector *syntaxCopy();
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
unsigned alignsize();
|
||||
bool isintegral();
|
||||
bool isfloating();
|
||||
|
@ -448,7 +448,7 @@ public:
|
|||
const char *kind();
|
||||
TypeSArray *syntaxCopy();
|
||||
bool isIncomplete();
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
unsigned alignsize();
|
||||
bool isString();
|
||||
bool isZeroInit(const Loc &loc);
|
||||
|
@ -471,7 +471,7 @@ class TypeDArray : public TypeArray
|
|||
public:
|
||||
const char *kind();
|
||||
TypeDArray *syntaxCopy();
|
||||
d_uns64 size(const Loc &loc) /*const*/;
|
||||
uinteger_t size(const Loc &loc) /*const*/;
|
||||
unsigned alignsize() /*const*/;
|
||||
bool isString();
|
||||
bool isZeroInit(const Loc &loc) /*const*/;
|
||||
|
@ -491,7 +491,7 @@ public:
|
|||
static TypeAArray *create(Type *t, Type *index);
|
||||
const char *kind();
|
||||
TypeAArray *syntaxCopy();
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
bool isZeroInit(const Loc &loc) /*const*/;
|
||||
bool isBoolean() /*const*/;
|
||||
bool hasPointers() /*const*/;
|
||||
|
@ -507,7 +507,7 @@ public:
|
|||
static TypePointer *create(Type *t);
|
||||
const char *kind();
|
||||
TypePointer *syntaxCopy();
|
||||
d_uns64 size(const Loc &loc) /*const*/;
|
||||
uinteger_t size(const Loc &loc) /*const*/;
|
||||
MATCH implicitConvTo(Type *to);
|
||||
MATCH constConv(Type *to);
|
||||
bool isscalar() /*const*/;
|
||||
|
@ -522,7 +522,7 @@ class TypeReference : public TypeNext
|
|||
public:
|
||||
const char *kind();
|
||||
TypeReference *syntaxCopy();
|
||||
d_uns64 size(const Loc &loc) /*const*/;
|
||||
uinteger_t size(const Loc &loc) /*const*/;
|
||||
bool isZeroInit(const Loc &loc) /*const*/;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
@ -655,7 +655,7 @@ public:
|
|||
const char *kind();
|
||||
TypeDelegate *syntaxCopy();
|
||||
Type *addStorageClass(StorageClass stc);
|
||||
d_uns64 size(const Loc &loc) /*const*/;
|
||||
uinteger_t size(const Loc &loc) /*const*/;
|
||||
unsigned alignsize() /*const*/;
|
||||
MATCH implicitConvTo(Type *to);
|
||||
bool isZeroInit(const Loc &loc) /*const*/;
|
||||
|
@ -675,7 +675,7 @@ class TypeTraits : public Type
|
|||
|
||||
const char *kind();
|
||||
TypeTraits *syntaxCopy();
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
@ -704,7 +704,7 @@ public:
|
|||
void addIdent(Identifier *ident);
|
||||
void addInst(TemplateInstance *inst);
|
||||
void addIndex(RootObject *expr);
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
@ -744,7 +744,7 @@ public:
|
|||
const char *kind();
|
||||
TypeTypeof *syntaxCopy();
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
|
@ -778,7 +778,7 @@ public:
|
|||
|
||||
static TypeStruct *create(StructDeclaration *sym);
|
||||
const char *kind();
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
unsigned alignsize();
|
||||
TypeStruct *syntaxCopy();
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
|
@ -808,7 +808,7 @@ public:
|
|||
|
||||
const char *kind();
|
||||
TypeEnum *syntaxCopy();
|
||||
d_uns64 size(const Loc &loc);
|
||||
uinteger_t size(const Loc &loc);
|
||||
unsigned alignsize();
|
||||
Type *memType(const Loc &loc = Loc());
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
|
@ -844,7 +844,7 @@ public:
|
|||
CPPMANGLE cppmangle;
|
||||
|
||||
const char *kind();
|
||||
d_uns64 size(const Loc &loc) /*const*/;
|
||||
uinteger_t size(const Loc &loc) /*const*/;
|
||||
TypeClass *syntaxCopy();
|
||||
Dsymbol *toDsymbol(Scope *sc);
|
||||
ClassDeclaration *isClassHandle();
|
||||
|
@ -899,7 +899,7 @@ public:
|
|||
MATCH implicitConvTo(Type *to);
|
||||
bool isBoolean() /*const*/;
|
||||
|
||||
d_uns64 size(const Loc &loc) /*const*/;
|
||||
uinteger_t size(const Loc &loc) /*const*/;
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
};
|
||||
|
||||
|
@ -911,7 +911,7 @@ public:
|
|||
MATCH implicitConvTo(Type* to);
|
||||
MATCH constConv(Type* to);
|
||||
bool isBoolean() /* const */;
|
||||
d_uns64 size(const Loc& loc) /* const */;
|
||||
uinteger_t size(const Loc& loc) /* const */;
|
||||
unsigned alignsize();
|
||||
|
||||
void accept(Visitor *v) { v->visit(this); }
|
||||
|
|
|
@ -221,7 +221,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr)
|
|||
return;
|
||||
if (lengthVar._init && !lengthVar._init.isVoidInitializer())
|
||||
return; // we have previously calculated the length
|
||||
d_uns64 len;
|
||||
dinteger_t len;
|
||||
if (auto se = arr.isStringExp())
|
||||
len = se.len;
|
||||
else if (auto ale = arr.isArrayLiteralExp())
|
||||
|
@ -253,7 +253,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type)
|
|||
auto tsa = type.toBasetype().isTypeSArray();
|
||||
if (!tsa)
|
||||
return; // we don't know the length yet
|
||||
d_uns64 len = tsa.dim.toInteger();
|
||||
const len = tsa.dim.toInteger();
|
||||
Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t);
|
||||
lengthVar._init = new ExpInitializer(Loc.initial, dollar);
|
||||
lengthVar.storage_class |= STC.static_ | STC.const_;
|
||||
|
@ -809,7 +809,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
if (e.e2.isConst() == 1)
|
||||
{
|
||||
sinteger_t i2 = e.e2.toInteger();
|
||||
d_uns64 sz = e.e1.type.size(e.e1.loc);
|
||||
uinteger_t sz = e.e1.type.size(e.e1.loc);
|
||||
assert(sz != SIZE_INVALID);
|
||||
sz *= 8;
|
||||
if (i2 < 0 || i2 >= sz)
|
||||
|
@ -895,7 +895,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
if (e.e2.isConst() == 1)
|
||||
{
|
||||
sinteger_t i2 = e.e2.toInteger();
|
||||
d_uns64 sz = e.e1.type.size(e.e1.loc);
|
||||
uinteger_t sz = e.e1.type.size(e.e1.loc);
|
||||
assert(sz != SIZE_INVALID);
|
||||
sz *= 8;
|
||||
if (i2 < 0 || i2 >= sz)
|
||||
|
|
|
@ -30,7 +30,7 @@ import dmd.tokens;
|
|||
|
||||
/***********************************************************
|
||||
*/
|
||||
class Parser(AST) : Lexer
|
||||
class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
||||
{
|
||||
AST.ModuleDeclaration* md;
|
||||
|
||||
|
@ -1263,7 +1263,7 @@ class Parser(AST) : Lexer
|
|||
}
|
||||
|
||||
checkConflictSTCGroup(STC.const_ | STC.immutable_ | STC.manifest);
|
||||
checkConflictSTCGroup(STC.gshared | STC.shared_ | STC.tls);
|
||||
checkConflictSTCGroup(STC.gshared | STC.shared_);
|
||||
checkConflictSTCGroup!true(STC.safeGroup);
|
||||
|
||||
return orig;
|
||||
|
@ -9599,5 +9599,3 @@ private bool writeMixin(const(char)[] s, ref Loc loc)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
|
||||
/* Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* https://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* https://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/dlang/dmd/blob/master/src/dmd/root/file.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "array.h"
|
||||
#include "filename.h"
|
||||
|
||||
struct FileBuffer
|
||||
{
|
||||
DArray<unsigned char> data;
|
||||
|
||||
FileBuffer(const FileBuffer &) /* = delete */;
|
||||
~FileBuffer() { mem.xfree(data.ptr); }
|
||||
|
||||
static FileBuffer *create();
|
||||
};
|
||||
|
||||
struct File
|
||||
{
|
||||
struct ReadResult
|
||||
{
|
||||
bool success;
|
||||
FileBuffer buffer;
|
||||
};
|
||||
|
||||
// Read the full content of a file.
|
||||
static ReadResult read(const char *name);
|
||||
|
||||
// Write a file, returning `true` on success.
|
||||
static bool write(const char *name, const void *data, d_size_t size);
|
||||
|
||||
// Delete a file.
|
||||
static void remove(const char *name);
|
||||
};
|
|
@ -36,6 +36,8 @@ version (Windows)
|
|||
import core.sys.windows.windef;
|
||||
import core.sys.windows.winnls;
|
||||
|
||||
import dmd.common.string : extendedPathThen;
|
||||
|
||||
extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc;
|
||||
extern (Windows) void SetLastError(DWORD) nothrow @nogc;
|
||||
extern (C) char* getcwd(char* buffer, size_t maxlen) nothrow;
|
||||
|
@ -855,7 +857,7 @@ nothrow:
|
|||
}
|
||||
else version (Windows)
|
||||
{
|
||||
return name.toWStringzThen!((wname)
|
||||
return name.extendedPathThen!((wname)
|
||||
{
|
||||
const dw = GetFileAttributesW(&wname[0]);
|
||||
if (dw == -1)
|
||||
|
@ -1005,7 +1007,7 @@ nothrow:
|
|||
// Have canonicalize_file_name, which malloc's memory.
|
||||
// We need a dmd.root.rmem allocation though.
|
||||
auto path = name.toCStringThen!((n) => canonicalize_file_name(n.ptr));
|
||||
scope(exit) .free(path.ptr);
|
||||
scope(exit) .free(path);
|
||||
if (path !is null)
|
||||
return xarraydup(path.toDString);
|
||||
}
|
||||
|
@ -1124,7 +1126,6 @@ version(Windows)
|
|||
*/
|
||||
private int _mkdir(const(char)[] path) nothrow
|
||||
{
|
||||
import dmd.common.string : extendedPathThen;
|
||||
const createRet = path.extendedPathThen!(
|
||||
p => CreateDirectoryW(&p[0], null /*securityAttributes*/));
|
||||
// different conventions for CreateDirectory and mkdir
|
||||
|
|
|
@ -201,10 +201,10 @@ int dstrcmp()( scope const char[] s1, scope const char[] s2 ) @trusted
|
|||
unittest
|
||||
{
|
||||
assert(dstrcmp("Fraise", "Fraise") == 0);
|
||||
assert(dstrcmp("Baguette", "Croissant") == -1);
|
||||
assert(dstrcmp("Croissant", "Baguette") == 1);
|
||||
assert(dstrcmp("Baguette", "Croissant") < 0);
|
||||
assert(dstrcmp("Croissant", "Baguette") > 0);
|
||||
|
||||
static assert(dstrcmp("Baguette", "Croissant") == -1);
|
||||
static assert(dstrcmp("Baguette", "Croissant") < 0);
|
||||
|
||||
// UTF-8 decoding for the CT variant
|
||||
assert(dstrcmp("안녕하세요!", "안녕하세요!") == 0);
|
||||
|
|
|
@ -330,11 +330,14 @@ private extern(C++) final class Semantic2Visitor : Visitor
|
|||
// gets imported, it is unaffected by context.
|
||||
Scope* sc = Scope.createGlobal(mod); // create root scope
|
||||
//printf("Module = %p\n", sc.scopesym);
|
||||
// Pass 2 semantic routines: do initializers and function bodies
|
||||
for (size_t i = 0; i < mod.members.dim; i++)
|
||||
if (mod.members)
|
||||
{
|
||||
Dsymbol s = (*mod.members)[i];
|
||||
s.semantic2(sc);
|
||||
// Pass 2 semantic routines: do initializers and function bodies
|
||||
for (size_t i = 0; i < mod.members.dim; i++)
|
||||
{
|
||||
Dsymbol s = (*mod.members)[i];
|
||||
s.semantic2(sc);
|
||||
}
|
||||
}
|
||||
if (mod.userAttribDecl)
|
||||
{
|
||||
|
|
|
@ -187,14 +187,17 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
|||
// gets imported, it is unaffected by context.
|
||||
Scope* sc = Scope.createGlobal(mod); // create root scope
|
||||
//printf("Module = %p\n", sc.scopesym);
|
||||
// Pass 3 semantic routines: do initializers and function bodies
|
||||
for (size_t i = 0; i < mod.members.dim; i++)
|
||||
if (mod.members)
|
||||
{
|
||||
Dsymbol s = (*mod.members)[i];
|
||||
//printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
|
||||
s.semantic3(sc);
|
||||
// Pass 3 semantic routines: do initializers and function bodies
|
||||
for (size_t i = 0; i < mod.members.dim; i++)
|
||||
{
|
||||
Dsymbol s = (*mod.members)[i];
|
||||
//printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
|
||||
s.semantic3(sc);
|
||||
|
||||
mod.runDeferredSemantic2();
|
||||
mod.runDeferredSemantic2();
|
||||
}
|
||||
}
|
||||
if (mod.userAttribDecl)
|
||||
{
|
||||
|
@ -1282,6 +1285,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
|
|||
if (funcdecl.type == f)
|
||||
f = cast(TypeFunction)f.copy();
|
||||
f.isreturn = true;
|
||||
f.isreturnscope = cast(bool) (funcdecl.storage_class & STC.returnScope);
|
||||
if (funcdecl.storage_class & STC.returninferred)
|
||||
f.isreturninferred = true;
|
||||
}
|
||||
|
|
|
@ -987,18 +987,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
|||
if (dim == 2)
|
||||
{
|
||||
Parameter p = (*fs.parameters)[0];
|
||||
auto var = new VarDeclaration(loc, p.type.mutableOf(), Identifier.generateId("__key"), null);
|
||||
var.storage_class |= STC.temp | STC.foreach_;
|
||||
if (var.storage_class & (STC.ref_ | STC.out_))
|
||||
var.storage_class |= STC.nodtor;
|
||||
fs.key = new VarDeclaration(loc, p.type.mutableOf(), Identifier.generateId("__key"), null);
|
||||
fs.key.storage_class |= STC.temp | STC.foreach_;
|
||||
if (fs.key.isReference())
|
||||
fs.key.storage_class |= STC.nodtor;
|
||||
|
||||
fs.key = var;
|
||||
if (p.storageClass & STC.ref_)
|
||||
{
|
||||
if (var.type.constConv(p.type) == MATCH.nomatch)
|
||||
if (fs.key.type.constConv(p.type) == MATCH.nomatch)
|
||||
{
|
||||
fs.error("key type mismatch, `%s` to `ref %s`",
|
||||
var.type.toChars(), p.type.toChars());
|
||||
fs.key.type.toChars(), p.type.toChars());
|
||||
return retError();
|
||||
}
|
||||
}
|
||||
|
@ -1008,7 +1007,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
|||
IntRange dimrange = getIntRange(ta.dim);
|
||||
// https://issues.dlang.org/show_bug.cgi?id=12504
|
||||
dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
|
||||
if (!IntRange.fromType(var.type).contains(dimrange))
|
||||
if (!IntRange.fromType(fs.key.type).contains(dimrange))
|
||||
{
|
||||
fs.error("index type `%s` cannot cover index range 0..%llu",
|
||||
p.type.toChars(), ta.dim.toInteger());
|
||||
|
@ -1020,17 +1019,15 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
|||
// Now declare the value
|
||||
{
|
||||
Parameter p = (*fs.parameters)[dim - 1];
|
||||
auto var = new VarDeclaration(loc, p.type, p.ident, null);
|
||||
var.storage_class |= STC.foreach_;
|
||||
var.storage_class |= p.storageClass & (STC.scope_ | STC.IOR | STC.TYPECTOR);
|
||||
if (var.isReference())
|
||||
var.storage_class |= STC.nodtor;
|
||||
|
||||
fs.value = var;
|
||||
if (var.storage_class & STC.ref_)
|
||||
fs.value = new VarDeclaration(loc, p.type, p.ident, null);
|
||||
fs.value.storage_class |= STC.foreach_;
|
||||
fs.value.storage_class |= p.storageClass & (STC.scope_ | STC.IOR | STC.TYPECTOR);
|
||||
if (fs.value.isReference())
|
||||
{
|
||||
fs.value.storage_class |= STC.nodtor;
|
||||
|
||||
if (fs.aggr.checkModifiable(sc2, ModifyFlags.noError) == Modifiable.initialization)
|
||||
var.setInCtorOnly = true;
|
||||
fs.value.setInCtorOnly = true;
|
||||
|
||||
Type t = tab.nextOf();
|
||||
if (t.constConv(p.type) == MATCH.nomatch)
|
||||
|
@ -1053,7 +1050,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
|
|||
*/
|
||||
auto id = Identifier.generateId("__r");
|
||||
auto ie = new ExpInitializer(loc, new SliceExp(loc, fs.aggr, null, null));
|
||||
const valueIsRef = cast(bool) ((*fs.parameters)[dim - 1].storageClass & STC.ref_);
|
||||
const valueIsRef = (*fs.parameters)[$ - 1].isReference();
|
||||
VarDeclaration tmp;
|
||||
if (fs.aggr.op == EXP.arrayLiteral && !valueIsRef)
|
||||
{
|
||||
|
|
|
@ -61,7 +61,7 @@ extern (C++) struct Target
|
|||
import dmd.dscope : Scope;
|
||||
import dmd.expression : Expression;
|
||||
import dmd.func : FuncDeclaration;
|
||||
import dmd.globals : Loc, d_int64;
|
||||
import dmd.globals : Loc;
|
||||
import dmd.astenums : LINK, TY;
|
||||
import dmd.mtype : Type, TypeFunction, TypeTuple;
|
||||
import dmd.root.ctfloat : real_t;
|
||||
|
@ -125,18 +125,18 @@ extern (C++) struct Target
|
|||
*/
|
||||
extern (C++) struct FPTypeProperties(T)
|
||||
{
|
||||
real_t max; /// largest representable value that's not infinity
|
||||
real_t min_normal; /// smallest representable normalized value that's not 0
|
||||
real_t nan; /// NaN value
|
||||
real_t infinity; /// infinity value
|
||||
real_t epsilon; /// smallest increment to the value 1
|
||||
real_t max; /// largest representable value that's not infinity
|
||||
real_t min_normal; /// smallest representable normalized value that's not 0
|
||||
real_t nan; /// NaN value
|
||||
real_t infinity; /// infinity value
|
||||
real_t epsilon; /// smallest increment to the value 1
|
||||
|
||||
d_int64 dig; /// number of decimal digits of precision
|
||||
d_int64 mant_dig; /// number of bits in mantissa
|
||||
d_int64 max_exp; /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable
|
||||
d_int64 min_exp; /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value
|
||||
d_int64 max_10_exp; /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable)
|
||||
d_int64 min_10_exp; /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value
|
||||
long dig; /// number of decimal digits of precision
|
||||
long mant_dig; /// number of bits in mantissa
|
||||
long max_exp; /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable
|
||||
long min_exp; /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value
|
||||
long max_10_exp; /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable)
|
||||
long min_10_exp; /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value
|
||||
}
|
||||
|
||||
FPTypeProperties!float FloatProperties; ///
|
||||
|
@ -245,17 +245,6 @@ extern (C++) struct Target
|
|||
*/
|
||||
extern (C++) bool isReturnOnStack(TypeFunction tf, bool needsThis);
|
||||
|
||||
/***
|
||||
* Determine the size a value of type `t` will be when it
|
||||
* is passed on the function parameter stack.
|
||||
* Params:
|
||||
* loc = location to use for error messages
|
||||
* t = type of parameter
|
||||
* Returns:
|
||||
* size used on parameter stack
|
||||
*/
|
||||
extern (C++) ulong parameterSize(const ref Loc loc, Type t);
|
||||
|
||||
/**
|
||||
* Decides whether an `in` parameter of the specified POD type is to be
|
||||
* passed by reference or by value. To be used with `-preview=in` only!
|
||||
|
|
|
@ -175,12 +175,12 @@ struct Target
|
|||
real_t infinity;
|
||||
real_t epsilon;
|
||||
|
||||
d_int64 dig;
|
||||
d_int64 mant_dig;
|
||||
d_int64 max_exp;
|
||||
d_int64 min_exp;
|
||||
d_int64 max_10_exp;
|
||||
d_int64 min_10_exp;
|
||||
int64_t dig;
|
||||
int64_t mant_dig;
|
||||
int64_t max_exp;
|
||||
int64_t min_exp;
|
||||
int64_t max_10_exp;
|
||||
int64_t min_10_exp;
|
||||
};
|
||||
|
||||
FPTypeProperties<float> FloatProperties;
|
||||
|
@ -194,7 +194,6 @@ private:
|
|||
public:
|
||||
void _init(const Param& params);
|
||||
// Type sizes and support.
|
||||
void setTriple(const char* _triple);
|
||||
unsigned alignsize(Type *type);
|
||||
unsigned fieldalign(Type *type);
|
||||
Type *va_listType(const Loc &loc, Scope *sc); // get type of va_list
|
||||
|
@ -204,7 +203,6 @@ public:
|
|||
LINK systemLinkage();
|
||||
TypeTuple *toArgTypes(Type *t);
|
||||
bool isReturnOnStack(TypeFunction *tf, bool needsThis);
|
||||
d_uns64 parameterSize(const Loc& loc, Type *t);
|
||||
bool preferPassByRef(Type *t);
|
||||
Expression *getTargetInfo(const char* name, const Loc& loc);
|
||||
bool isCalleeDestroyingArgs(TypeFunction* tf);
|
||||
|
|
|
@ -314,3 +314,4 @@ Tuple *isTuple(RootObject *o);
|
|||
Parameter *isParameter(RootObject *o);
|
||||
TemplateParameter *isTemplateParameter(RootObject *o);
|
||||
bool isError(const RootObject *const o);
|
||||
void printTemplateStats();
|
||||
|
|
|
@ -942,17 +942,17 @@ nothrow:
|
|||
switch (value)
|
||||
{
|
||||
case TOK.int32Literal:
|
||||
sprintf(&buffer[0], "%d", cast(d_int32)intvalue);
|
||||
sprintf(&buffer[0], "%d", cast(int)intvalue);
|
||||
break;
|
||||
case TOK.uns32Literal:
|
||||
case TOK.wcharLiteral:
|
||||
case TOK.dcharLiteral:
|
||||
case TOK.wchar_tLiteral:
|
||||
sprintf(&buffer[0], "%uU", cast(d_uns32)unsvalue);
|
||||
sprintf(&buffer[0], "%uU", cast(uint)unsvalue);
|
||||
break;
|
||||
case TOK.charLiteral:
|
||||
{
|
||||
const v = cast(d_int32)intvalue;
|
||||
const v = cast(int)intvalue;
|
||||
if (v >= ' ' && v <= '~')
|
||||
sprintf(&buffer[0], "'%c'", v);
|
||||
else
|
||||
|
|
|
@ -166,28 +166,28 @@ shared static this()
|
|||
/**
|
||||
* get an array of size_t values that indicate possible pointer words in memory
|
||||
* if interpreted as the type given as argument
|
||||
* Returns: the size of the type in bytes, d_uns64.max on error
|
||||
* Returns: the size of the type in bytes, ulong.max on error
|
||||
*/
|
||||
d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data)
|
||||
ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
|
||||
{
|
||||
d_uns64 sz;
|
||||
ulong sz;
|
||||
if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration())
|
||||
sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc);
|
||||
else
|
||||
sz = t.size(loc);
|
||||
if (sz == SIZE_INVALID)
|
||||
return d_uns64.max;
|
||||
return ulong.max;
|
||||
|
||||
const sz_size_t = Type.tsize_t.size(loc);
|
||||
if (sz > sz.max - sz_size_t)
|
||||
{
|
||||
error(loc, "size overflow for type `%s`", t.toChars());
|
||||
return d_uns64.max;
|
||||
return ulong.max;
|
||||
}
|
||||
|
||||
d_uns64 bitsPerWord = sz_size_t * 8;
|
||||
d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t;
|
||||
d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
|
||||
ulong bitsPerWord = sz_size_t * 8;
|
||||
ulong cntptr = (sz + sz_size_t - 1) / sz_size_t;
|
||||
ulong cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
|
||||
|
||||
data.setDim(cast(size_t)cntdata);
|
||||
data.zero();
|
||||
|
@ -196,15 +196,15 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data)
|
|||
{
|
||||
alias visit = Visitor.visit;
|
||||
public:
|
||||
extern (D) this(Array!(d_uns64)* _data, d_uns64 _sz_size_t)
|
||||
extern (D) this(Array!(ulong)* _data, ulong _sz_size_t)
|
||||
{
|
||||
this.data = _data;
|
||||
this.sz_size_t = _sz_size_t;
|
||||
}
|
||||
|
||||
void setpointer(d_uns64 off)
|
||||
void setpointer(ulong off)
|
||||
{
|
||||
d_uns64 ptroff = off / sz_size_t;
|
||||
ulong ptroff = off / sz_size_t;
|
||||
(*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t));
|
||||
}
|
||||
|
||||
|
@ -242,12 +242,12 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data)
|
|||
|
||||
override void visit(TypeSArray t)
|
||||
{
|
||||
d_uns64 arrayoff = offset;
|
||||
d_uns64 nextsize = t.next.size();
|
||||
ulong arrayoff = offset;
|
||||
ulong nextsize = t.next.size();
|
||||
if (nextsize == SIZE_INVALID)
|
||||
error = true;
|
||||
d_uns64 dim = t.dim.toInteger();
|
||||
for (d_uns64 i = 0; i < dim; i++)
|
||||
ulong dim = t.dim.toInteger();
|
||||
for (ulong i = 0; i < dim; i++)
|
||||
{
|
||||
offset = arrayoff + i * nextsize;
|
||||
t.next.accept(this);
|
||||
|
@ -340,7 +340,7 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data)
|
|||
|
||||
override void visit(TypeStruct t)
|
||||
{
|
||||
d_uns64 structoff = offset;
|
||||
ulong structoff = offset;
|
||||
foreach (v; t.sym.fields)
|
||||
{
|
||||
offset = structoff + v.offset;
|
||||
|
@ -355,7 +355,7 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data)
|
|||
// a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
|
||||
void visitClass(TypeClass t)
|
||||
{
|
||||
d_uns64 classoff = offset;
|
||||
ulong classoff = offset;
|
||||
// skip vtable-ptr and monitor
|
||||
if (t.sym.baseClass)
|
||||
visitClass(cast(TypeClass)t.sym.baseClass.type);
|
||||
|
@ -367,9 +367,9 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data)
|
|||
offset = classoff;
|
||||
}
|
||||
|
||||
Array!(d_uns64)* data;
|
||||
d_uns64 offset;
|
||||
d_uns64 sz_size_t;
|
||||
Array!(ulong)* data;
|
||||
ulong offset;
|
||||
ulong sz_size_t;
|
||||
bool error;
|
||||
}
|
||||
|
||||
|
@ -378,7 +378,7 @@ d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data)
|
|||
pbv.visitClass(cast(TypeClass)t);
|
||||
else
|
||||
t.accept(pbv);
|
||||
return pbv.error ? d_uns64.max : sz;
|
||||
return pbv.error ? ulong.max : sz;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -406,9 +406,9 @@ private Expression pointerBitmap(TraitsExp e)
|
|||
return ErrorExp.get();
|
||||
}
|
||||
|
||||
Array!(d_uns64) data;
|
||||
d_uns64 sz = getTypePointerBitmap(e.loc, t, &data);
|
||||
if (sz == d_uns64.max)
|
||||
Array!(ulong) data;
|
||||
ulong sz = getTypePointerBitmap(e.loc, t, &data);
|
||||
if (sz == ulong.max)
|
||||
return ErrorExp.get();
|
||||
|
||||
auto exps = new Expressions(data.dim + 1);
|
||||
|
|
|
@ -1304,7 +1304,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
|||
// default arg must be an lvalue
|
||||
if (isRefOrOut && !isAuto &&
|
||||
!(global.params.previewIn && (fparam.storageClass & STC.in_)) &&
|
||||
!(global.params.rvalueRefParam))
|
||||
global.params.rvalueRefParam != FeatureState.enabled)
|
||||
e = e.toLvalue(sc, e);
|
||||
|
||||
fparam.defaultArg = e;
|
||||
|
@ -1504,16 +1504,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
|||
|
||||
/* Scope attribute is not necessary if the parameter type does not have pointers
|
||||
*/
|
||||
/* Constructors are treated as if they are being returned through the hidden parameter,
|
||||
* which is by ref, and the ref there is ignored.
|
||||
*/
|
||||
const returnByRef = tf.isref && !tf.isctor;
|
||||
if (!returnByRef && isRefReturnScope(fparam.storageClass))
|
||||
{
|
||||
/* if `ref return scope`, evaluate to `ref` `return scope`
|
||||
*/
|
||||
fparam.storageClass |= STC.returnScope;
|
||||
}
|
||||
const sr = buildScopeRef(fparam.storageClass);
|
||||
switch (sr)
|
||||
{
|
||||
|
@ -1534,17 +1524,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
|||
break;
|
||||
}
|
||||
|
||||
/* now set STC.returnScope based only on tf.isref. This is inconsistent, as mentioned above,
|
||||
* but necessary for compatibility for now.
|
||||
*/
|
||||
fparam.storageClass &= ~STC.returnScope;
|
||||
if (!tf.isref && isRefReturnScope(fparam.storageClass))
|
||||
{
|
||||
/* if `ref return scope`, evaluate to `ref` `return scope`
|
||||
*/
|
||||
fparam.storageClass |= STC.returnScope;
|
||||
}
|
||||
|
||||
// Remove redundant storage classes for type, they are already applied
|
||||
fparam.storageClass &= ~(STC.TYPECTOR);
|
||||
|
||||
|
@ -2411,7 +2390,7 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
|
|||
}
|
||||
if (ident == Id.__sizeof)
|
||||
{
|
||||
d_uns64 sz = mt.size(loc);
|
||||
const sz = mt.size(loc);
|
||||
if (sz == SIZE_INVALID)
|
||||
return ErrorExp.get();
|
||||
e = new IntegerExp(loc, sz, Type.tsize_t);
|
||||
|
|
|
@ -125,7 +125,6 @@ typedef /* noreturn */ char Impossible[0];
|
|||
template <typename T>
|
||||
struct Array final
|
||||
{
|
||||
// Ignoring var length alignment 0
|
||||
uint32_t length;
|
||||
Array()
|
||||
{
|
||||
|
|
|
@ -175,7 +175,7 @@ struct A final
|
|||
s()
|
||||
{
|
||||
}
|
||||
A(int32_t a, S s = S(0, 0, 0LL, {})) :
|
||||
A(int32_t a, S s = S()) :
|
||||
a(a),
|
||||
s(s)
|
||||
{}
|
||||
|
@ -186,6 +186,37 @@ union U
|
|||
int32_t i;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct Array final
|
||||
{
|
||||
uint32_t length;
|
||||
private:
|
||||
_d_dynamicArray< char > data;
|
||||
char smallarray[1$?:32=u|64=LLU$];
|
||||
public:
|
||||
Array() :
|
||||
length()
|
||||
{
|
||||
}
|
||||
Array(uint32_t length) :
|
||||
length(length)
|
||||
{}
|
||||
};
|
||||
|
||||
struct Params final
|
||||
{
|
||||
bool obj;
|
||||
Array ddocfiles;
|
||||
Params() :
|
||||
obj(true),
|
||||
ddocfiles()
|
||||
{
|
||||
}
|
||||
Params(bool obj, Array ddocfiles = Array()) :
|
||||
obj(obj),
|
||||
ddocfiles(ddocfiles)
|
||||
{}
|
||||
};
|
||||
---
|
||||
*/
|
||||
|
||||
|
@ -284,3 +315,17 @@ extern(C++) union U
|
|||
int i;
|
||||
char c;
|
||||
}
|
||||
|
||||
extern (C++) struct Array
|
||||
{
|
||||
uint length;
|
||||
private:
|
||||
char[] data;
|
||||
char[1] smallarray;
|
||||
}
|
||||
|
||||
extern (C++) struct Params
|
||||
{
|
||||
bool obj = true;
|
||||
Array ddocfiles;
|
||||
}
|
||||
|
|
|
@ -73,14 +73,10 @@ struct ActualBuffer final
|
|||
template <typename T>
|
||||
struct A final
|
||||
{
|
||||
// Ignoring var x alignment 0
|
||||
T x;
|
||||
// Ignoring var Enum alignment 0
|
||||
enum : int32_t { Enum = 42 };
|
||||
|
||||
// Ignoring var GsharedNum alignment 0
|
||||
static int32_t GsharedNum;
|
||||
// Ignoring var MemNum alignment 0
|
||||
const int32_t MemNum;
|
||||
void foo();
|
||||
A()
|
||||
|
@ -91,8 +87,6 @@ struct A final
|
|||
template <typename T>
|
||||
struct NotInstantiated final
|
||||
{
|
||||
// Ignoring var noInit alignment 0
|
||||
// Ignoring var missingSem alignment 0
|
||||
NotInstantiated()
|
||||
{
|
||||
}
|
||||
|
@ -113,7 +107,6 @@ struct B final
|
|||
template <typename T>
|
||||
struct Foo final
|
||||
{
|
||||
// Ignoring var val alignment 0
|
||||
T val;
|
||||
Foo()
|
||||
{
|
||||
|
@ -123,7 +116,6 @@ struct Foo final
|
|||
template <typename T>
|
||||
struct Bar final
|
||||
{
|
||||
// Ignoring var v alignment 0
|
||||
Foo<T > v;
|
||||
Bar()
|
||||
{
|
||||
|
@ -141,9 +133,7 @@ struct Array final
|
|||
void get() const;
|
||||
template <typename T>
|
||||
bool opCast() const;
|
||||
// Ignoring var i alignment 0
|
||||
typename T::Member i;
|
||||
// Ignoring var j alignment 0
|
||||
typename Outer::Member::Nested j;
|
||||
void visit(typename T::Member::Nested i);
|
||||
Array()
|
||||
|
@ -159,7 +149,6 @@ extern A<A<int32_t > > aaint;
|
|||
template <typename T>
|
||||
class Parent
|
||||
{
|
||||
// Ignoring var parentMember alignment 0
|
||||
public:
|
||||
T parentMember;
|
||||
void parentFinal();
|
||||
|
@ -169,7 +158,6 @@ public:
|
|||
template <typename T>
|
||||
class Child final : public Parent<T >
|
||||
{
|
||||
// Ignoring var childMember alignment 0
|
||||
public:
|
||||
T childMember;
|
||||
void parentVirtual();
|
||||
|
@ -207,14 +195,10 @@ extern HasMixinsTemplate<bool > hmti;
|
|||
template <typename T>
|
||||
struct NotAA final
|
||||
{
|
||||
// Ignoring var length alignment 0
|
||||
enum : int32_t { length = 12 };
|
||||
|
||||
// Ignoring var buffer alignment 0
|
||||
T buffer[length];
|
||||
// Ignoring var otherBuffer alignment 0
|
||||
T otherBuffer[SomeOtherLength];
|
||||
// Ignoring var calcBuffer alignment 0
|
||||
T calcBuffer[foo(1)];
|
||||
NotAA()
|
||||
{
|
||||
|
@ -224,9 +208,7 @@ struct NotAA final
|
|||
template <typename Buffer>
|
||||
struct BufferTmpl final
|
||||
{
|
||||
// Ignoring var buffer alignment 0
|
||||
Buffer buffer;
|
||||
// Ignoring var buffer2 alignment 0
|
||||
Buffer buffer2;
|
||||
BufferTmpl()
|
||||
{
|
||||
|
|
|
@ -86,7 +86,6 @@ struct ExternDStructRequired final
|
|||
template <typename T>
|
||||
struct ExternDTemplStruct final
|
||||
{
|
||||
// Ignoring var member alignment 0
|
||||
T member;
|
||||
ExternDTemplStruct()
|
||||
{
|
||||
|
@ -129,7 +128,6 @@ extern TemplClass<int32_t >* templClass;
|
|||
template <typename T>
|
||||
class TemplClass
|
||||
{
|
||||
// Ignoring var member alignment 0
|
||||
public:
|
||||
T member;
|
||||
};
|
||||
|
@ -139,7 +137,6 @@ extern TemplStruct<int32_t >* templStruct;
|
|||
template <typename T>
|
||||
class TemplStruct
|
||||
{
|
||||
// Ignoring var member alignment 0
|
||||
public:
|
||||
T member;
|
||||
};
|
||||
|
|
|
@ -62,11 +62,9 @@ private:
|
|||
template <typename T>
|
||||
struct WithImaginaryTemplate final
|
||||
{
|
||||
// Ignoring var member alignment 0
|
||||
float member;
|
||||
// Ignored function onReturn because its return type cannot be mapped to C++
|
||||
// Ignored function onParam because one of its parameters has type `ifloat` which cannot be mapped to C++
|
||||
// Ignoring var onVariable alignment 0
|
||||
// Ignored variable onVariable because its type cannot be mapped to C++
|
||||
WithImaginaryTemplate()
|
||||
{
|
||||
|
|
|
@ -58,7 +58,6 @@ namespace const_cast
|
|||
template <typename register_>
|
||||
struct S final
|
||||
{
|
||||
// Ignoring var x alignment 0
|
||||
register_ x;
|
||||
S()
|
||||
{
|
||||
|
@ -104,7 +103,6 @@ extern void user(Alias<Base* >* i);
|
|||
template <typename typename_>
|
||||
struct InvalidNames final
|
||||
{
|
||||
// Ignoring var register alignment 0
|
||||
typename_ register_;
|
||||
void foo(typename_ and_);
|
||||
InvalidNames()
|
||||
|
|
|
@ -63,13 +63,9 @@ struct Outer final
|
|||
template <typename U>
|
||||
struct InnerTmpl final
|
||||
{
|
||||
// Ignoring var innerTmplOuterPtr alignment 0
|
||||
static Outer* innerTmplOuterPtr;
|
||||
// Ignoring var innerTmplPtr alignment 0
|
||||
static Middle* innerTmplPtr;
|
||||
// Ignoring var innerTmplInnerPtr alignment 0
|
||||
static Inner* innerTmplInnerPtr;
|
||||
// Ignoring var innerTmplInnerTmplPtr alignment 0
|
||||
static InnerTmpl* innerTmplInnerTmplPtr;
|
||||
InnerTmpl()
|
||||
{
|
||||
|
@ -84,15 +80,11 @@ struct Outer final
|
|||
template <typename T>
|
||||
struct MiddleTmpl final
|
||||
{
|
||||
// Ignoring var middleTmplPtr alignment 0
|
||||
static MiddleTmpl<T >* middleTmplPtr;
|
||||
// Ignoring var middleTmplInnerTmplPtr alignment 0
|
||||
static MiddleTmpl<T >* middleTmplInnerTmplPtr;
|
||||
struct Inner final
|
||||
{
|
||||
// Ignoring var ptr alignment 0
|
||||
static Inner* ptr;
|
||||
// Ignoring var ptr2 alignment 0
|
||||
static MiddleTmpl<T >* ptr2;
|
||||
Inner()
|
||||
{
|
||||
|
@ -102,13 +94,9 @@ struct Outer final
|
|||
template <typename U>
|
||||
struct InnerTmpl final
|
||||
{
|
||||
// Ignoring var innerTmplPtr alignment 0
|
||||
static InnerTmpl* innerTmplPtr;
|
||||
// Ignoring var innerTmplPtrDiff alignment 0
|
||||
static InnerTmpl<char >* innerTmplPtrDiff;
|
||||
// Ignoring var middleTmplInnerTmplPtr alignment 0
|
||||
static MiddleTmpl<T >* middleTmplInnerTmplPtr;
|
||||
// Ignoring var a alignment 0
|
||||
static T a;
|
||||
static U bar();
|
||||
InnerTmpl()
|
||||
|
|
|
@ -65,9 +65,7 @@ enum class ExternDEnum
|
|||
template <>
|
||||
struct ExternDStructTemplate final
|
||||
{
|
||||
// Ignoring var i alignment 0
|
||||
int32_t i;
|
||||
// Ignoring var d alignment 0
|
||||
double d;
|
||||
ExternDStructTemplate()
|
||||
{
|
||||
|
@ -131,7 +129,7 @@ struct ExternCppStruct final
|
|||
st()
|
||||
{
|
||||
}
|
||||
ExternCppStruct(ExternDStruct s, ExternDEnum e = (ExternDEnum)0, ExternDStructTemplate< > st = ExternDStructTemplate< >(0, NAN)) :
|
||||
ExternCppStruct(ExternDStruct s, ExternDEnum e = (ExternDEnum)0, ExternDStructTemplate< > st = ExternDStructTemplate< >()) :
|
||||
s(s),
|
||||
e(e),
|
||||
st(st)
|
||||
|
|
|
@ -142,7 +142,7 @@ int f1_20682(return scope ref D d) @safe
|
|||
return d.pos;
|
||||
}
|
||||
|
||||
ref int f2_20682(return scope ref D d) @safe
|
||||
ref int f2_20682(return ref scope D d) @safe
|
||||
{
|
||||
return d.pos;
|
||||
}
|
||||
|
|
18
gcc/testsuite/gdc.test/fail_compilation/fail19948.d
Normal file
18
gcc/testsuite/gdc.test/fail_compilation/fail19948.d
Normal file
|
@ -0,0 +1,18 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=19948
|
||||
|
||||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail19948.d(15): Error: function `fail19948.func(const(X))` is not callable using argument types `(X)`
|
||||
fail_compilation/fail19948.d(15): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)`
|
||||
---
|
||||
*/
|
||||
|
||||
struct X {}
|
||||
void main()
|
||||
{
|
||||
struct X {}
|
||||
func(X());
|
||||
}
|
||||
|
||||
void func(const(X)) {}
|
60
gcc/testsuite/gdc.test/fail_compilation/fail22881.d
Normal file
60
gcc/testsuite/gdc.test/fail_compilation/fail22881.d
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail22881.d(101): Error: pointer slice `[0..6]` exceeds allocated memory block `[0..5]`
|
||||
fail_compilation/fail22881.d(102): Error: pointer slice `[0..6]` exceeds allocated memory block `[0..5]`
|
||||
fail_compilation/fail22881.d(110): Error: pointer slice `[3..5]` exceeds allocated memory block `[0..4]`
|
||||
fail_compilation/fail22881.d(113): called from here: `ptr22881()`
|
||||
fail_compilation/fail22881.d(113): while evaluating: `static assert(ptr22881())`
|
||||
fail_compilation/fail22881.d(203): Error: slice `[0..2]` is out of bounds
|
||||
fail_compilation/fail22881.d(207): called from here: `null22881()`
|
||||
fail_compilation/fail22881.d(207): while evaluating: `static assert(null22881())`
|
||||
fail_compilation/fail22881.d(305): Error: slice `[2..4]` exceeds array bounds `[0..3]`
|
||||
fail_compilation/fail22881.d(308): called from here: `slice22881()`
|
||||
fail_compilation/fail22881.d(308): while evaluating: `static assert(slice22881())`
|
||||
fail_compilation/fail22881.d(401): Error: slice `[0..1]` exceeds array bounds `[0..0]`
|
||||
fail_compilation/fail22881.d(403): Error: slice `[0..1]` exceeds array bounds `[0..0]`
|
||||
---
|
||||
*/
|
||||
#line 100
|
||||
// SliceExp: e1.type.ty == pointer
|
||||
static pstr22881 = "hello".ptr[0 .. 6];
|
||||
static parr22881 = ['h','e','l','l','o'].ptr[0 .. 6];
|
||||
|
||||
bool ptr22881()
|
||||
{
|
||||
char *p1 = new char[4].ptr;
|
||||
p1[0 .. 4] = "str\0";
|
||||
char *s1 = p1[1 .. 3].ptr;
|
||||
char *s2 = s1[1 .. 3].ptr; // = p1[2 .. 4]
|
||||
char *s3 = s2[1 .. 3].ptr; // = p1[3 .. 5]
|
||||
return true;
|
||||
}
|
||||
static assert(ptr22881());
|
||||
|
||||
|
||||
#line 200
|
||||
// SliceExp: e1.op == null
|
||||
bool null22881()
|
||||
{
|
||||
string[][1] nullexp;
|
||||
nullexp[0][0 .. 2] = "st";
|
||||
return true;
|
||||
}
|
||||
static assert(null22881());
|
||||
|
||||
#line 300
|
||||
// SliceExp: e1.op == slice
|
||||
bool slice22881()
|
||||
{
|
||||
char[] str = "abcd".dup;
|
||||
char[] slice = str[1 .. 4];
|
||||
slice[2 .. 4] = "ab";
|
||||
return true;
|
||||
}
|
||||
static assert(slice22881());
|
||||
|
||||
#line 400
|
||||
// SliceExp: e1.op == arrayLiteral
|
||||
static arr22881 = [][0 .. 1];
|
||||
// SliceExp: e1.op == string_
|
||||
static str22881 = ""[0 .. 1];
|
|
@ -1,9 +1,9 @@
|
|||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/pull12941.d(110): Error: `pull12941.foo` called with argument types `(int*)` matches both:
|
||||
fail_compilation/pull12941.d(101): `pull12941.foo(ref return scope int* p)`
|
||||
fail_compilation/pull12941.d(101): `pull12941.foo(return ref scope int* p)`
|
||||
and:
|
||||
fail_compilation/pull12941.d(102): `pull12941.foo(out return scope int* p)`
|
||||
fail_compilation/pull12941.d(102): `pull12941.foo(return out scope int* p)`
|
||||
fail_compilation/pull12941.d(111): Error: function `pull12941.bar(return scope int* p)` is not callable using argument types `(int)`
|
||||
fail_compilation/pull12941.d(111): cannot pass argument `1` of type `int` to parameter `return scope int* p`
|
||||
fail_compilation/pull12941.d(112): Error: function `pull12941.abc(return ref int* p)` is not callable using argument types `(int)`
|
||||
|
|
|
@ -130,7 +130,7 @@ fail_compilation/retscope2.d(721): Error: returning `s.get1()` escapes a referen
|
|||
|
||||
struct S700
|
||||
{
|
||||
@safe S700* get1() return scope
|
||||
@safe S700* get1() scope return
|
||||
{
|
||||
return &this;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ int* addrOfRefGlobal()
|
|||
}
|
||||
|
||||
// Slice:
|
||||
ref int*[1] identityArr(ref return scope int*[1] x)
|
||||
ref int*[1] identityArr(return ref scope int*[1] x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ fail_compilation/test17422.d(23): Error: scope variable `p` may not be returned
|
|||
*/
|
||||
struct RC
|
||||
{
|
||||
Object get() return scope @trusted
|
||||
Object get() return @trusted
|
||||
{
|
||||
return cast(Object) &store[0];
|
||||
}
|
||||
|
|
30
gcc/testsuite/gdc.test/fail_compilation/test20881.d
Normal file
30
gcc/testsuite/gdc.test/fail_compilation/test20881.d
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
REQUIRED_ARGS: -preview=dip1000
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test20881.d(27): Error: address of variable `s` assigned to `global` with longer lifetime
|
||||
fail_compilation/test20881.d(28): Error: address of variable `s` assigned to `global` with longer lifetime
|
||||
fail_compilation/test20881.d(29): Error: address of variable `s` assigned to `global` with longer lifetime
|
||||
---
|
||||
*/
|
||||
@safe:
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20881
|
||||
|
||||
struct S
|
||||
{
|
||||
int* ptr;
|
||||
|
||||
auto borrowA() return /*scope inferred*/ { return ptr; }
|
||||
int* borrowB() return { return ptr; }
|
||||
int* borrowC() scope return { return ptr; }
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
static int* global;
|
||||
S s;
|
||||
global = s.borrowA;
|
||||
global = s.borrowB;
|
||||
global = s.borrowC;
|
||||
}
|
|
@ -32,12 +32,12 @@ Dg escapeAssign(int i, return scope Dg dg)
|
|||
return dg;
|
||||
}
|
||||
|
||||
ref Dg identityR(ref return scope Dg dg)
|
||||
ref Dg identityR(return ref scope Dg dg)
|
||||
{
|
||||
return dg;
|
||||
}
|
||||
|
||||
ref Dg escapeAssignRef(int i, ref return scope Dg dg)
|
||||
ref Dg escapeAssignRef(int i, return ref scope Dg dg)
|
||||
{
|
||||
dg = () => i;
|
||||
return dg;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
int testCppCMangle (unsigned long long val, char ch)
|
||||
{
|
||||
int vch = (char)val;
|
||||
if (vch != ch)
|
||||
return 0;
|
||||
return vch;
|
||||
}
|
28
gcc/testsuite/gdc.test/runnable_cxx/test22898.d
Normal file
28
gcc/testsuite/gdc.test/runnable_cxx/test22898.d
Normal file
|
@ -0,0 +1,28 @@
|
|||
// EXTRA_CPP_SOURCES: test22898.cpp
|
||||
|
||||
import core.stdc.config;
|
||||
|
||||
extern(C++):
|
||||
|
||||
version (AArch64) version = UnsignedChar;
|
||||
version (ARM) version = UnsignedChar;
|
||||
version (RISCV32) version = UnsignedChar;
|
||||
version (RISCV64) version = UnsignedChar;
|
||||
version (PPC) version = UnsignedChar;
|
||||
version (PPC64) version = UnsignedChar;
|
||||
version (S390) version = UnsignedChar;
|
||||
version (SystemZ) version = UnsignedChar;
|
||||
|
||||
version (UnsignedChar)
|
||||
enum __c_char : ubyte;
|
||||
else
|
||||
enum __c_char : byte;
|
||||
|
||||
int testCppCMangle (cpp_ulonglong, __c_char);
|
||||
|
||||
void main()
|
||||
{
|
||||
auto val = cast(cpp_ulonglong)18446744073709551488UL;
|
||||
auto ch = cast(__c_char)val;
|
||||
assert(testCppCMangle(val, ch) == cast(int)ch);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
16cb085b584f100fa677e2e64ff6b6dbb4921ad1
|
||||
a74fa63e6775d626850d8ebd854d9803c7ffb97d
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/phobos repository.
|
||||
|
|
|
@ -1153,7 +1153,7 @@ if (!(isImplicitlyConvertible!(S, T) &&
|
|||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=16108
|
||||
@system unittest
|
||||
@safe unittest
|
||||
{
|
||||
static struct A
|
||||
{
|
||||
|
@ -1341,12 +1341,12 @@ if (is (T == immutable) && isExactSomeString!T && is(S == enum))
|
|||
assert(to!string(a) == "[1.5, 2.5]");
|
||||
}
|
||||
|
||||
@system unittest
|
||||
@safe unittest
|
||||
{
|
||||
// Conversion representing class object with string
|
||||
class A
|
||||
{
|
||||
override string toString() const { return "an A"; }
|
||||
override string toString() @safe const { return "an A"; }
|
||||
}
|
||||
A a;
|
||||
assert(to!string(a) == "null");
|
||||
|
@ -1354,7 +1354,7 @@ if (is (T == immutable) && isExactSomeString!T && is(S == enum))
|
|||
assert(to!string(a) == "an A");
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=7660
|
||||
class C { override string toString() const { return "C"; } }
|
||||
class C { override string toString() @safe const { return "C"; } }
|
||||
struct S { C c; alias c this; }
|
||||
S s; s.c = new C();
|
||||
assert(to!string(s) == "C");
|
||||
|
@ -1739,10 +1739,10 @@ if (!isImplicitlyConvertible!(S, T) && isAssociativeArray!S &&
|
|||
foreach (k1, v1; value)
|
||||
{
|
||||
// Cast values temporarily to Unqual!V2 to store them to result variable
|
||||
result[to!K2(k1)] = cast(Unqual!V2) to!V2(v1);
|
||||
result[to!K2(k1)] = to!(Unqual!V2)(v1);
|
||||
}
|
||||
// Cast back to original type
|
||||
return cast(T) result;
|
||||
return () @trusted { return cast(T) result; }();
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
|
@ -3105,7 +3105,7 @@ if (isSomeString!Source && !is(Source == enum) &&
|
|||
* A $(LREF ConvException) if `source` is empty, if no number could be
|
||||
* parsed, or if an overflow occurred.
|
||||
*/
|
||||
auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
|
||||
auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref scope Source source)
|
||||
if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
|
||||
isFloatingPoint!Target && !is(Target == enum))
|
||||
{
|
||||
|
@ -3122,6 +3122,13 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
|
|||
alias p = source;
|
||||
}
|
||||
|
||||
void advanceSource() @trusted
|
||||
{
|
||||
// p is assigned from source.representation above so the cast is valid
|
||||
static if (isNarrowString!Source)
|
||||
source = cast(Source) p;
|
||||
}
|
||||
|
||||
static immutable real[14] negtab =
|
||||
[ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L,
|
||||
1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ];
|
||||
|
@ -3138,6 +3145,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
|
|||
|
||||
enforce(!p.empty, bailOut());
|
||||
|
||||
|
||||
size_t count = 0;
|
||||
bool sign = false;
|
||||
switch (p.front)
|
||||
|
@ -3168,8 +3176,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
|
|||
// skip past the last 'f'
|
||||
++count;
|
||||
p.popFront();
|
||||
static if (isNarrowString!Source)
|
||||
source = cast(Source) p;
|
||||
advanceSource();
|
||||
static if (doCount)
|
||||
{
|
||||
return tuple!("data", "count")(sign ? -Target.infinity : Target.infinity, count);
|
||||
|
@ -3189,8 +3196,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
|
|||
p.popFront();
|
||||
if (p.empty)
|
||||
{
|
||||
static if (isNarrowString!Source)
|
||||
source = cast(Source) p;
|
||||
advanceSource();
|
||||
static if (doCount)
|
||||
{
|
||||
return tuple!("data", "count")(cast (Target) (sign ? -0.0 : 0.0), count);
|
||||
|
@ -3222,8 +3228,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
|
|||
// skip past the last 'n'
|
||||
++count;
|
||||
p.popFront();
|
||||
static if (isNarrowString!Source)
|
||||
source = cast(Source) p;
|
||||
advanceSource();
|
||||
static if (doCount)
|
||||
{
|
||||
return tuple!("data", "count")(Target.nan, count);
|
||||
|
@ -3418,8 +3423,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
|
|||
// if overflow occurred
|
||||
enforce(ldval != real.infinity, new ConvException("Range error"));
|
||||
|
||||
static if (isNarrowString!Source)
|
||||
source = cast(Source) p;
|
||||
advanceSource();
|
||||
static if (doCount)
|
||||
{
|
||||
return tuple!("data", "count")(cast (Target) (sign ? -ldval : ldval), count);
|
||||
|
@ -3430,6 +3434,7 @@ if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
{
|
||||
|
|
|
@ -234,7 +234,7 @@ import std.meta : anySatisfy, allSatisfy;
|
|||
import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor;
|
||||
import std.traits : isAssignable, isCopyable, isStaticArray, isRvalueAssignable;
|
||||
import std.traits : ConstOf, ImmutableOf, InoutOf, TemplateArgsOf;
|
||||
import std.traits : CommonType;
|
||||
import std.traits : CommonType, DeducedParameterType;
|
||||
import std.typecons : ReplaceTypeUnless;
|
||||
import std.typecons : Flag;
|
||||
|
||||
|
@ -359,6 +359,10 @@ public:
|
|||
|
||||
/// ditto
|
||||
this(immutable(T) value) immutable;
|
||||
|
||||
/// ditto
|
||||
this(Value)(Value value) inout
|
||||
if (is(Value == DeducedParameterType!(inout(T))));
|
||||
}
|
||||
|
||||
static foreach (tid, T; Types)
|
||||
|
@ -414,6 +418,25 @@ public:
|
|||
{
|
||||
@disable this(immutable(T) value) immutable;
|
||||
}
|
||||
|
||||
static if (isCopyable!(inout(T)))
|
||||
{
|
||||
static if (IndexOf!(inout(T), Map!(InoutOf, Types)) == tid)
|
||||
{
|
||||
/// ditto
|
||||
this(Value)(Value value) inout
|
||||
if (is(Value == DeducedParameterType!(inout(T))))
|
||||
{
|
||||
__traits(getMember, storage, Storage.memberName!T) = value;
|
||||
tag = tid;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@disable this(Value)(Value value) inout
|
||||
if (is(Value == DeducedParameterType!(inout(T))));
|
||||
}
|
||||
}
|
||||
|
||||
static if (anySatisfy!(hasElaborateCopyConstructor, Types))
|
||||
|
@ -1554,6 +1577,16 @@ version (D_BetterC) {} else
|
|||
SumType!Value s;
|
||||
}
|
||||
|
||||
// Construction of inout-qualified SumTypes
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22901
|
||||
@safe unittest
|
||||
{
|
||||
static inout(SumType!(int[])) example(inout(int[]) arr)
|
||||
{
|
||||
return inout(SumType!(int[]))(arr);
|
||||
}
|
||||
}
|
||||
|
||||
/// True if `T` is an instance of the `SumType` template, otherwise false.
|
||||
private enum bool isSumTypeInstance(T) = is(T == SumType!Args, Args...);
|
||||
|
||||
|
|
|
@ -9080,3 +9080,43 @@ enum isCopyable(S) = __traits(isCopyable, S);
|
|||
static assert(isCopyable!int);
|
||||
static assert(isCopyable!(int[]));
|
||||
}
|
||||
|
||||
/**
|
||||
* The parameter type deduced by IFTI when an expression of type T is passed as
|
||||
* an argument to a template function.
|
||||
*
|
||||
* For all types other than pointer and slice types, `DeducedParameterType!T`
|
||||
* is the same as `T`. For pointer and slice types, it is `T` with the
|
||||
* outer-most layer of qualifiers dropped.
|
||||
*/
|
||||
package(std) template DeducedParameterType(T)
|
||||
{
|
||||
static if (is(T == U*, U) || is(T == U[], U))
|
||||
alias DeducedParameterType = Unqual!T;
|
||||
else
|
||||
alias DeducedParameterType = T;
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
static assert(is(DeducedParameterType!(const(int)) == const(int)));
|
||||
static assert(is(DeducedParameterType!(const(int[2])) == const(int[2])));
|
||||
|
||||
static assert(is(DeducedParameterType!(const(int*)) == const(int)*));
|
||||
static assert(is(DeducedParameterType!(const(int[])) == const(int)[]));
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
static struct NoCopy
|
||||
{
|
||||
@disable this(this);
|
||||
}
|
||||
|
||||
static assert(is(DeducedParameterType!NoCopy == NoCopy));
|
||||
}
|
||||
|
||||
@safe unittest
|
||||
{
|
||||
static assert(is(DeducedParameterType!(inout(int[])) == inout(int)[]));
|
||||
}
|
||||
|
|
|
@ -9824,7 +9824,7 @@ dchar toLower(dchar c)
|
|||
|
||||
/++
|
||||
Creates a new array which is identical to `s` except that all of its
|
||||
characters are converted to lowercase (by preforming Unicode lowercase mapping).
|
||||
characters are converted to lowercase (by performing Unicode lowercase mapping).
|
||||
If none of `s` characters were affected, then `s` itself is returned if `s` is a
|
||||
`string`-like type.
|
||||
|
||||
|
@ -10028,7 +10028,7 @@ dchar toUpper(dchar c)
|
|||
|
||||
/++
|
||||
Allocates a new array which is identical to `s` except that all of its
|
||||
characters are converted to uppercase (by preforming Unicode uppercase mapping).
|
||||
characters are converted to uppercase (by performing Unicode uppercase mapping).
|
||||
If none of `s` characters were affected, then `s` itself is returned if `s`
|
||||
is a `string`-like type.
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue