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:
Iain Buclaw 2022-03-21 16:52:40 +01:00
parent 4a3073f04e
commit fbdaa58162
78 changed files with 1098 additions and 744 deletions

View file

@ -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)
{

View file

@ -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 ());

View file

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

View file

@ -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);

View file

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

View file

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

View 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;

View file

@ -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);

View file

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

View file

@ -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.
*/

View file

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

View file

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

View file

@ -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 ***************************/

View file

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

View file

@ -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());

View file

@ -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);

View file

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

View file

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

View file

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

View file

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

View file

@ -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);

View file

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

View file

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

View file

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

View file

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

View file

@ -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");

View file

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

View file

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

View file

@ -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())

View file

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

View file

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

View file

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

View file

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

View file

@ -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"),

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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);

View file

@ -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)
{

View file

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

View file

@ -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)
{

View file

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

View file

@ -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);

View file

@ -314,3 +314,4 @@ Tuple *isTuple(RootObject *o);
Parameter *isParameter(RootObject *o);
TemplateParameter *isTemplateParameter(RootObject *o);
bool isError(const RootObject *const o);
void printTemplateStats();

View file

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

View file

@ -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);

View file

@ -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);

View file

@ -125,7 +125,6 @@ typedef /* noreturn */ char Impossible[0];
template <typename T>
struct Array final
{
// Ignoring var length alignment 0
uint32_t length;
Array()
{

View file

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

View file

@ -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()
{

View file

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

View file

@ -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()
{

View file

@ -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()

View file

@ -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()

View file

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

View file

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

View 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)) {}

View 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];

View file

@ -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)`

View file

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

View file

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

View file

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

View 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;
}

View file

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

View file

@ -0,0 +1,7 @@
int testCppCMangle (unsigned long long val, char ch)
{
int vch = (char)val;
if (vch != ch)
return 0;
return vch;
}

View 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);
}

View file

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

View file

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

View file

@ -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...);

View file

@ -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)[]));
}

View file

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