d: Merge upstream dmd 52844d4b1, druntime dbd0c874, phobos 896b1d0e1.

D front-end changes:

    - Parsing and compiling C code is now possible using `import'.
    - `throw' statements can now be used as an expression.
    - Improvements to the D template emission strategy when compiling
      with `-funittest'.

D Runtime changes:

    - New core.int128 module for implementing intrinsics to support
      128-bit integer types.
    - C bindings for the kernel and C runtime have been better separated
      to allow compiling for hybrid targets, such as kFreeBSD.

Phobos changes:

    - The std.experimental.checkedint module has been renamed to
      std.checkedint.

gcc/d/ChangeLog:

	* d-builtins.cc (d_build_builtins_module): Set purity of DECL_PURE_P
	functions to PURE::const_.
	* d-gimplify.cc (bit_field_ref): New function.
	(d_gimplify_modify_expr): Handle implicit casting for assignments to
	bit-fields.
	(d_gimplify_unary_expr): New function.
	(d_gimplify_binary_expr): New function.
	(d_gimplify_expr): Handle UNARY_CLASS_P and BINARY_CLASS_P.
	* d-target.cc (Target::_init): Initialize bitFieldStyle.
	(TargetCPP::parameterType): Update signature.
	(Target::supportsLinkerDirective): New function.
	* dmd/MERGE: Merge upstream dmd 52844d4b1.
	* expr.cc (ExprVisitor::visit (ThrowExp *)): New function.
	* types.cc (d_build_bitfield_integer_type): New function.
	(insert_aggregate_bitfield): New function.
	(layout_aggregate_members): Handle inserting bit-fields into an
	aggregate type.

libphobos/ChangeLog:

	* Makefile.in: Regenerate.
	* libdruntime/MERGE: Merge upstream druntime dbd0c874.
	* libdruntime/Makefile.am (DRUNTIME_CSOURCES): Add core/int128.d.
	(DRUNTIME_DISOURCES): Add __builtins.di.
	* libdruntime/Makefile.in: Regenerate.
	* src/MERGE: Merge upstream phobos 896b1d0e1.
	* src/Makefile.am (PHOBOS_DSOURCES): Add std/checkedint.d.
	* src/Makefile.in: Regenerate.
	* testsuite/testsuite_flags.in: Add -fall-instantiations to
	--gdcflags.
This commit is contained in:
Iain Buclaw 2022-02-13 20:17:53 +01:00
parent 0233276439
commit d75691877c
289 changed files with 10868 additions and 10528 deletions

View File

@ -543,7 +543,7 @@ d_build_builtins_module (Module *m)
flag_unsafe_math_optimizations.
- Built-ins never use the GC or raise a D exception, and so are always
marked as `nothrow' and `@nogc'. */
tf->purity = DECL_PURE_P (decl) ? PURE::strong
tf->purity = DECL_PURE_P (decl) ? PURE::const_
: TREE_READONLY (decl) ? PURE::const_
: DECL_IS_NOVOPS (decl) ? PURE::weak
: !DECL_ASSEMBLER_NAME_SET_P (decl) ? PURE::weak

View File

@ -62,6 +62,18 @@ empty_modify_p (tree type, tree op)
return empty_aggregate_p (type);
}
/* Return TRUE if EXPR is a COMPONENT_REF to a bit-field declaration. */
static bool
bit_field_ref (const_tree expr)
{
if (TREE_CODE (expr) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (expr, 1)))
return true;
return false;
}
/* Gimplify assignment from an INIT_EXPR or MODIFY_EXPR. */
static gimplify_status
@ -96,6 +108,13 @@ d_gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
return GS_OK;
}
/* Same as above, but for bit-field assignments. */
if (bit_field_ref (op0) && TREE_TYPE (op0) != TREE_TYPE (op1))
{
TREE_OPERAND (*expr_p, 1) = convert (TREE_TYPE (op0), op1);
return GS_OK;
}
return GS_UNHANDLED;
}
@ -178,6 +197,54 @@ d_gimplify_unsigned_rshift_expr (tree *expr_p)
return GS_OK;
}
/* Gimplify an unary expression node. */
static gimplify_status
d_gimplify_unary_expr (tree *expr_p)
{
tree op0 = TREE_OPERAND (*expr_p, 0);
if (error_operand_p (op0))
return GS_UNHANDLED;
/* Front end doesn't know that bit-field types are really different
from basic types, add an explicit conversion in unary expressions. */
if (bit_field_ref (op0) && TREE_TYPE (op0) != TREE_TYPE (*expr_p))
{
TREE_OPERAND (*expr_p, 0) = convert (TREE_TYPE (*expr_p), op0);
return GS_OK;
}
return GS_UNHANDLED;
}
/* Gimplify a binary expression node. */
static gimplify_status
d_gimplify_binary_expr (tree *expr_p)
{
tree op0 = TREE_OPERAND (*expr_p, 0);
tree op1 = TREE_OPERAND (*expr_p, 1);
if (error_operand_p (op0) || error_operand_p (op1))
return GS_UNHANDLED;
/* Front end doesn't know that bit-field types are really different
from basic types, add an explicit conversion in binary expressions. */
if (bit_field_ref (op0) || bit_field_ref (op1))
{
if (TREE_TYPE (op0) != TREE_TYPE (*expr_p))
TREE_OPERAND (*expr_p, 0) = convert (TREE_TYPE (*expr_p), op0);
if (TREE_TYPE (op1) != TREE_TYPE (*expr_p))
TREE_OPERAND (*expr_p, 1) = convert (TREE_TYPE (*expr_p), op1);
return GS_OK;
}
return GS_UNHANDLED;
}
/* Implements the lang_hooks.gimplify_expr routine for language D.
Do gimplification of D specific expression trees in EXPR_P. */
@ -203,6 +270,10 @@ d_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
gcc_unreachable ();
default:
if (UNARY_CLASS_P (*expr_p) && !CONVERT_EXPR_P (*expr_p))
return d_gimplify_unary_expr (expr_p);
if (BINARY_CLASS_P (*expr_p))
return d_gimplify_binary_expr (expr_p);
break;
}

View File

@ -161,6 +161,8 @@ Target::_init (const Param &)
this->c.longsize = int_size_in_bytes (long_integer_type_node);
this->c.long_doublesize = int_size_in_bytes (long_double_type_node);
this->c.wchar_tsize = (WCHAR_TYPE_SIZE / BITS_PER_UNIT);
this->c.bitFieldStyle = targetm.ms_bitfield_layout_p (unknown_type_node)
? TargetC::BitFieldStyle::MS : TargetC::BitFieldStyle::Gcc_Clang;
/* Set-up target C++ ABI. */
this->cpp.reverseOverloads = false;
@ -379,32 +381,21 @@ TargetCPP::typeMangle (Type *type)
ARG to an extern(C++) function. */
Type *
TargetCPP::parameterType (Parameter *arg)
TargetCPP::parameterType (Type *type)
{
Type *t = arg->type->merge2 ();
if (arg->storageClass & (STCout | STCref))
t = t->referenceTo ();
else if (arg->storageClass & STClazy)
{
/* Mangle as delegate. */
TypeFunction *tf = TypeFunction::create (NULL, t, VARARGnone, LINK::d);
TypeDelegate *td = TypeDelegate::create (tf);
t = td->merge2 ();
}
/* Could be a va_list, which we mangle as a pointer. */
Type *tvalist = target.va_listType (Loc (), NULL);
if (t->ty == TY::Tsarray && tvalist->ty == TY::Tsarray)
if (type->ty == TY::Tsarray && tvalist->ty == TY::Tsarray)
{
Type *tb = t->toBasetype ()->mutableOf ();
Type *tb = type->toBasetype ()->mutableOf ();
if (tb == tvalist)
{
tb = t->nextOf ()->pointerTo ();
t = tb->castMod (t->mod);
tb = type->nextOf ()->pointerTo ();
type = tb->castMod (type->mod);
}
}
return t;
return type;
}
/* Checks whether TYPE is a vendor-specific fundamental type. Stores the result
@ -579,6 +570,14 @@ Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
return true;
}
/* Returns true if the target supports `pragma(linkerDirective)'. */
bool
Target::supportsLinkerDirective (void) const
{
return false;
}
/* Decides whether an `in' parameter of the specified POD type PARAM_TYPE is to
be passed by reference or by valie. This is used only when compiling with
`-fpreview=in' enabled. */

View File

@ -1,4 +1,4 @@
001bfd97b0e75423970260dac54f453be9b57f4c
52844d4b1e9d6714bfd2e535f25a72074a046209
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View File

@ -33,6 +33,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
|-----------------------------------------------------------------------------|-----------------------------------------------------------------------|
| [mars.d](https://github.com/dlang/dmd/blob/master/src/dmd/mars.d) | The entry point. Contains `main`. |
| [cli.d](https://github.com/dlang/dmd/blob/master/src/dmd/cli.d) | Define the command line interface |
| [dmdparams.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmdparams.d) | DMD-specific parameters |
| [globals.d](https://github.com/dlang/dmd/blob/master/src/dmd/globals.d) | Define a structure storing command line options |
| [dinifile.d](https://github.com/dlang/dmd/blob/master/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) |
| [vsoptions.d](https://github.com/dlang/dmd/blob/master/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking |

View File

@ -51,15 +51,7 @@ bool checkAccess(AggregateDeclaration ad, Loc loc, Scope* sc, Dsymbol smember)
if (!symbolIsVisible(sc, smember))
{
// when in @safe code or with -preview=dip1000
if (sc.flags & SCOPE.onlysafeaccess)
{
// if there is a func. ask for it's opinion of safety, and if it considers the access @safe accept it.
if (sc.func && !sc.func.setUnsafe())
return false;
}
ad.error(loc, "%s `%s` is not accessible%s", smember.kind(), smember.toChars(), (sc.flags & SCOPE.onlysafeaccess) ? " from `@safe` code".ptr : "".ptr);
ad.error(loc, "%s `%s` is not accessible", smember.kind(), smember.toChars());
//printf("smember = %s %s, vis = %d, semanticRun = %d\n",
// smember.kind(), smember.toPrettyChars(), smember.visible() smember.semanticRun);
return true;

View File

@ -134,6 +134,8 @@ enum STC : ulong // transfer changes to declaration.h
}
alias StorageClass = ulong;
/********
* Determine if it's the ambigous case of where `return` attaches to.
* Params:
@ -302,8 +304,7 @@ enum PURE : ubyte
impure = 0, // not pure at all
fwdref = 1, // it's pure, but not known which level yet
weak = 2, // no mutable globals are read or written
const_ = 3, // parameters are values or const
strong = 4, // parameters are values or immutable
const_ = 3, // parameters are values or const = strongly pure
}
// Whether alias this dependency is recursive or not
@ -389,3 +390,43 @@ enum InitKind : ubyte
C_,
}
/// A linkage attribute as defined by `extern(XXX)`
///
/// https://dlang.org/spec/attribute.html#linkage
enum LINK : ubyte
{
default_,
d,
c,
cpp,
windows,
objc,
system,
}
/// Whether to mangle an external aggregate as a struct or class, as set by `extern(C++, struct)`
enum CPPMANGLE : ubyte
{
def, /// default
asStruct, /// `extern(C++, struct)`
asClass, /// `extern(C++, class)`
}
/// Function match levels
///
/// https://dlang.org/spec/function.html#function-overloading
enum MATCH : int
{
nomatch, /// no match
convert, /// match with conversions
constant, /// match with conversion to const
exact, /// exact match
}
/// Inline setting as defined by `pragma(inline, XXX)`
enum PINLINE : ubyte
{
default_, /// as specified on the command line
never, /// never inline
always, /// always inline
}

View File

@ -43,6 +43,7 @@ import dmd.identifier;
import dmd.mtype;
import dmd.objc; // for objc.addSymbols
import dmd.common.outbuffer;
import dmd.root.array; // for each
import dmd.target; // for target.systemLinkage
import dmd.tokens;
import dmd.visitor;
@ -1519,3 +1520,60 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
}
}
}
/**
* Returns `true` if the given symbol is a symbol declared in
* `core.attribute` and has the given identifier.
*
* This is used to determine if a symbol is a UDA declared in
* `core.attribute`.
*
* Params:
* sym = the symbol to check
* ident = the name of the expected UDA
*/
bool isCoreUda(Dsymbol sym, Identifier ident)
{
if (sym.ident != ident || !sym.parent)
return false;
auto _module = sym.parent.isModule();
return _module && _module.isCoreModule(Id.attribute);
}
/**
* Iterates the UDAs attached to the given symbol.
*
* If `dg` returns `!= 0`, it will stop the iteration and return that
* value, otherwise it will return 0.
*
* Params:
* sym = the symbol to get the UDAs from
* sc = scope to use for semantic analysis of UDAs
* dg = called once for each UDA. If `dg` returns `!= 0`, it will stop the
* iteration and return that value, otherwise it will return `0`.
*/
int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
{
if (!sym.userAttribDecl)
return 0;
auto udas = sym.userAttribDecl.getAttributes();
arrayExpressionSemantic(udas, sc, true);
return udas.each!((uda) {
if (!uda.isTupleExp())
return 0;
auto exps = uda.isTupleExp().exps;
return exps.each!((e) {
assert(e);
if (auto result = dg(e))
return result;
return 0;
});
});
}

View File

@ -110,8 +110,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
}
if (s.exp.type && s.exp.type.toBasetype().isTypeNoreturn())
result = BE.halt;
if (canThrow(s.exp, func, mustNotThrow))
result |= BE.throw_;
result |= canThrow(s.exp, func, mustNotThrow);
}
}
@ -149,7 +149,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
else if (!func.getModule().isCFile)
{
const(char)* gototype = s.isCaseStatement() ? "case" : "default";
s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
}
}
}
@ -214,8 +214,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result = BE.fallthru;
if (result & BE.fallthru)
{
if (canThrow(s.condition, func, mustNotThrow))
result |= BE.throw_;
result |= canThrow(s.condition, func, mustNotThrow);
if (!(result & BE.break_) && s.condition.toBool().hasValue(true))
result &= ~BE.fallthru;
}
@ -233,8 +233,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
}
if (s.condition)
{
if (canThrow(s.condition, func, mustNotThrow))
result |= BE.throw_;
result |= canThrow(s.condition, func, mustNotThrow);
const opt = s.condition.toBool();
if (opt.hasValue(true))
result &= ~BE.fallthru;
@ -250,15 +250,15 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
result |= BE.fallthru;
result |= r & ~(BE.fallthru | BE.break_ | BE.continue_);
}
if (s.increment && canThrow(s.increment, func, mustNotThrow))
result |= BE.throw_;
if (s.increment)
result |= canThrow(s.increment, func, mustNotThrow);
}
override void visit(ForeachStatement s)
{
result = BE.fallthru;
if (canThrow(s.aggr, func, mustNotThrow))
result |= BE.throw_;
result |= canThrow(s.aggr, func, mustNotThrow);
if (s._body)
result |= blockExit(s._body, func, mustNotThrow) & ~(BE.break_ | BE.continue_);
}
@ -273,8 +273,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
{
//printf("IfStatement::blockExit(%p)\n", s);
result = BE.none;
if (canThrow(s.condition, func, mustNotThrow))
result |= BE.throw_;
result |= canThrow(s.condition, func, mustNotThrow);
const opt = s.condition.toBool();
if (opt.hasValue(true))
@ -313,8 +312,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
override void visit(SwitchStatement s)
{
result = BE.none;
if (canThrow(s.condition, func, mustNotThrow))
result |= BE.throw_;
result |= canThrow(s.condition, func, mustNotThrow);
if (s._body)
{
result |= blockExit(s._body, func, mustNotThrow);
@ -357,8 +356,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
override void visit(ReturnStatement s)
{
result = BE.return_;
if (s.exp && canThrow(s.exp, func, mustNotThrow))
result |= BE.throw_;
if (s.exp)
result |= canThrow(s.exp, func, mustNotThrow);
}
override void visit(BreakStatement s)
@ -380,8 +379,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
override void visit(WithStatement s)
{
result = BE.none;
if (canThrow(s.exp, func, mustNotThrow))
result = BE.throw_;
result |= canThrow(s.exp, func, mustNotThrow);
result |= blockExit(s._body, func, mustNotThrow);
}
@ -483,19 +481,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
return;
}
Type t = s.exp.type.toBasetype();
ClassDeclaration cd = t.isClassHandle();
assert(cd);
if (cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null))
{
result = BE.errthrow;
return;
}
if (mustNotThrow)
s.error("`%s` is thrown but not caught", s.exp.type.toChars());
result = BE.throw_;
result = checkThrow(s.loc, s.exp, mustNotThrow);
}
override void visit(GotoStatement s)
@ -537,3 +523,32 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
s.accept(be);
return be.result;
}
/++
+ Checks whether `throw <exp>` throws an `Exception` or an `Error`
+ and raises an error if this violates `nothrow`.
+
+ Params:
+ loc = location of the `throw`
+ exp = expression yielding the throwable
+ mustNotThrow = inside of a `nothrow` scope?
+
+ Returns: `BE.[err]throw` depending on the type of `exp`
+/
BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow)
{
import dmd.errors : error;
Type t = exp.type.toBasetype();
ClassDeclaration cd = t.isClassHandle();
assert(cd);
if (cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null))
{
return BE.errthrow;
}
if (mustNotThrow)
loc.error("`%s` is thrown but not caught", exp.type.toChars());
return BE.throw_;
}

View File

@ -18,6 +18,7 @@ import dmd.apply;
import dmd.arraytypes;
import dmd.attrib;
import dmd.astenums;
import dmd.blockexit : BE, checkThrow;
import dmd.declaration;
import dmd.dsymbol;
import dmd.expression;
@ -29,11 +30,28 @@ import dmd.root.rootobject;
import dmd.tokens;
import dmd.visitor;
/**
* Status indicating what kind of throwable might be caused by an expression.
*
* This is a subset of `BE` restricted to the values actually used by `canThrow`.
*/
enum CT : BE
{
/// Never throws an `Exception` or `Throwable`
none = BE.none,
/// Might throw an `Exception`
exception = BE.throw_,
// Might throw an `Error`
error = BE.errthrow,
}
/********************************************
* Returns true if the expression may throw exceptions.
* If 'mustNotThrow' is true, generate an error if it throws
*/
extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow)
extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustNotThrow)
{
//printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
// stop walking if we determine this expression can throw
@ -42,6 +60,7 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
alias visit = typeof(super).visit;
FuncDeclaration func;
bool mustNotThrow;
CT result;
public:
extern (D) this(FuncDeclaration func, bool mustNotThrow)
@ -62,7 +81,7 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
e.checkOverridenDtor(null, f, dd => dd.type.toTypeFunction().isnothrow, "not nothrow");
}
stop = true; // if any function throws, then the whole expression throws
result |= CT.exception;
}
}
@ -72,7 +91,7 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
override void visit(DeclarationExp de)
{
stop = Dsymbol_canThrow(de.declaration, func, mustNotThrow);
result |= Dsymbol_canThrow(de.declaration, func, mustNotThrow);
}
override void visit(CallExp ce)
@ -83,18 +102,27 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
if (global.errors && !ce.e1.type)
return; // error recovery
import dmd.id : Id;
if (ce.f && ce.f.ident == Id._d_delstruct)
if (ce.f && ce.arguments.dim > 0)
{
// Only check if the dtor throws.
Type tb = (*ce.arguments)[0].type.toBasetype();
auto ts = tb.nextOf().baseElemOf().isTypeStruct();
if (ts)
auto tbNext = tb.nextOf();
if (tbNext)
{
auto sd = ts.sym;
if (sd.dtor)
checkFuncThrows(ce, sd.dtor);
auto ts = tbNext.baseElemOf().isTypeStruct();
if (ts)
{
import dmd.id : Id;
auto sd = ts.sym;
if (sd.dtor && ce.f.ident == Id._d_delstruct)
checkFuncThrows(ce, sd.dtor);
else if (sd.postblit &&
(ce.f.ident == Id._d_arrayctor || ce.f.ident == Id._d_arraysetctor))
{
checkFuncThrows(ce, sd.postblit);
return;
}
}
}
}
@ -124,7 +152,7 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
e1 = pe.e1;
ce.error("`%s` is not `nothrow`", e1.toChars());
}
stop = true;
result |= CT.exception;
}
override void visit(NewExp ne)
@ -187,6 +215,13 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
checkFuncThrows(ae, postblit);
}
override void visit(ThrowExp te)
{
const res = checkThrow(te.loc, te.e1, mustNotThrow);
assert((res & ~(CT.exception | CT.error)) == 0);
result |= res;
}
override void visit(NewAnonClassExp)
{
assert(0); // should have been lowered by semantic()
@ -194,18 +229,22 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
}
scope CanThrow ct = new CanThrow(func, mustNotThrow);
return walkPostorder(e, ct);
walkPostorder(e, ct);
return ct.result;
}
/**************************************
* Does symbol, when initialized, throw?
* Mirrors logic in Dsymbol_toElem().
*/
private bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow)
private CT Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow)
{
CT result;
int symbolDg(Dsymbol s)
{
return Dsymbol_canThrow(s, func, mustNotThrow);
result |= Dsymbol_canThrow(s, func, mustNotThrow);
return 0;
}
//printf("Dsymbol_toElem() %s\n", s.toChars());
@ -225,20 +264,19 @@ private bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow
if (vd._init)
{
if (auto ie = vd._init.isExpInitializer())
if (canThrow(ie.exp, func, mustNotThrow))
return true;
result |= canThrow(ie.exp, func, mustNotThrow);
}
if (vd.needsScopeDtor())
return canThrow(vd.edtor, func, mustNotThrow);
result |= canThrow(vd.edtor, func, mustNotThrow);
}
}
else if (auto ad = s.isAttribDeclaration())
{
return ad.include(null).foreachDsymbol(&symbolDg) != 0;
ad.include(null).foreachDsymbol(&symbolDg);
}
else if (auto tm = s.isTemplateMixin())
{
return tm.members.foreachDsymbol(&symbolDg) != 0;
tm.members.foreachDsymbol(&symbolDg);
}
else if (auto td = s.isTupleDeclaration())
{
@ -250,11 +288,10 @@ private bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow
Expression eo = cast(Expression)o;
if (auto se = eo.isDsymbolExp())
{
if (Dsymbol_canThrow(se.s, func, mustNotThrow))
return true;
result |= Dsymbol_canThrow(se.s, func, mustNotThrow);
}
}
}
}
return false;
return result;
}

View File

@ -120,18 +120,13 @@ UnionExp Not(Type type, Expression e1)
{
UnionExp ue = void;
Loc loc = e1.loc;
// BUG: Should be replaced with e1.toBool().get(), but this is apparently
// executed for some expressions that cannot be const-folded
// To be fixed in another PR
emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(false) ? 1 : 0, type);
return ue;
}
private UnionExp Bool(Type type, Expression e1)
{
UnionExp ue = void;
Loc loc = e1.loc;
emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(true) ? 1 : 0, type);
return ue;
}
UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
@ -1093,19 +1088,14 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
}
else if (tb.ty == Tbool)
{
bool val = void;
const opt = e1.toBool();
if (opt.hasValue(true))
val = true;
else if (opt.hasValue(false))
val = false;
else
if (opt.isEmpty())
{
cantExp(ue);
return ue;
}
emplaceExp!(IntegerExp)(&ue, loc, val, type);
emplaceExp!(IntegerExp)(&ue, loc, opt.get(), type);
}
else if (type.isintegral())
{

View File

@ -35,7 +35,8 @@ final class CParser(AST) : Parser!AST
{
AST.Dsymbols* symbols; // symbols declared in current scope
bool addFuncName; /// add declaration of __func__ to function symbol table
bool addFuncName; /// add declaration of __func__ to function symbol table
bool importBuiltins; /// seen use of C compiler builtins, so import __builtins;
extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
const ref TARGET target)
@ -72,7 +73,6 @@ final class CParser(AST) : Parser!AST
{
//printf("cparseTranslationUnit()\n");
symbols = new AST.Dsymbols();
addBuiltinDeclarations();
while (1)
{
if (token.value == TOK.endOfFile)
@ -82,6 +82,15 @@ final class CParser(AST) : Parser!AST
auto ld = new AST.LinkDeclaration(token.loc, LINK.c, symbols);
wrap.push(ld);
if (importBuiltins)
{
/* Seen references to C builtin functions.
* Import their definitions
*/
auto s = new AST.Import(Loc.initial, null, Id.builtins, null, false);
wrap.push(s);
}
return wrap;
}
@ -596,6 +605,7 @@ final class CParser(AST) : Parser!AST
* string-literal
* ( expression )
* generic-selection
* __builtin_va_arg(assign_expression, type)
*/
AST.Expression cparsePrimaryExp()
{
@ -606,9 +616,20 @@ final class CParser(AST) : Parser!AST
switch (token.value)
{
case TOK.identifier:
if (token.ident is Id.__func__)
const id = token.ident.toString();
if (id.length > 2 && id[0] == '_' && id[1] == '_') // leading double underscore
{
addFuncName = true; // implicitly declare __func__
if (token.ident is Id.__func__)
{
addFuncName = true; // implicitly declare __func__
}
else if (token.ident is Id.builtin_va_arg)
{
e = cparseBuiltin_va_arg();
break;
}
else
importBuiltins = true; // probably one of those compiler extensions
}
e = new AST.IdentifierExp(loc, token.ident);
nextToken();
@ -1449,6 +1470,40 @@ final class CParser(AST) : Parser!AST
return cparseAssignExp();
}
/*****************************
* gcc extension:
* type __builtin_va_arg(assign-expression, type)
* Rewrite as `va_arg` template from `core.stdc.stdarg`:
* va_arg!(type)(assign-expression);
* Lexer is on `__builtin_va_arg`
*/
private AST.Expression cparseBuiltin_va_arg()
{
importBuiltins = true; // need core.stdc.stdarg
nextToken();
check(TOK.leftParenthesis);
auto arguments = new AST.Expressions();
auto arg = cparseAssignExp();
arguments.push(arg);
check(TOK.comma);
auto t = cparseTypeName();
auto tiargs = new AST.Objects();
tiargs.push(t);
const loc = loc;
auto ti = new AST.TemplateInstance(loc, Id.va_arg, tiargs);
auto tie = new AST.ScopeExp(loc, ti);
AST.Expression e = new AST.CallExp(loc, tie, arguments);
check(TOK.rightParenthesis);
return e;
}
//}
/********************************************************************************/
/********************************* Declaration Parser ***************************/
@ -1481,6 +1536,14 @@ final class CParser(AST) : Parser!AST
return;
}
if (token.value == TOK._import) // import declaration extension
{
auto a = parseImport();
if (a && a.length)
symbols.append(a);
return;
}
auto symbolsSave = symbols;
Specifier specifier;
specifier.packalign = this.packalign;
@ -1504,7 +1567,7 @@ final class CParser(AST) : Parser!AST
*/
auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
(tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) :
new AST.EnumDeclaration(tt.loc, tt.id, AST.Type.tint32);
new AST.EnumDeclaration(tt.loc, tt.id, tt.base);
stag.members = tt.members;
if (!symbols)
symbols = new AST.Dsymbols();
@ -1550,26 +1613,18 @@ final class CParser(AST) : Parser!AST
case TOK.semicolon:
case TOK.asm_:
case TOK.__attribute__:
/* This is a data definition, there cannot now be a
* function definition.
*/
first = false;
if (token.value == TOK.asm_)
asmname = cparseSimpleAsmExpr();
if (token.value == TOK.__attribute__)
{
cparseGnuAttributes(specifier);
if (token.value == TOK.leftCurly)
{
error("attributes should be specified before the function definition");
auto t = &token;
if (skipBraces(t))
{
token = *t;
return;
}
}
break; // function definition
}
/* This is a data definition, there cannot now be a
* function definition.
*/
first = false;
break;
default:
@ -1636,6 +1691,30 @@ final class CParser(AST) : Parser!AST
isalias = false;
}
}
else if (auto tt = dt.isTypeTag())
{
if (tt.id || tt.tok == TOK.enum_)
{
/* `struct tag;` and `struct tag { ... };`
* always result in a declaration in the current scope
*/
auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
(tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) :
new AST.EnumDeclaration(tt.loc, tt.id, tt.base);
stag.members = tt.members;
tt.members = null;
if (!symbols)
symbols = new AST.Dsymbols();
symbols.push(stag);
if (tt.tok == TOK.enum_)
{
if (!tt.members)
error(tt.loc, "`enum %s` has no members", stag.toChars());
isalias = false;
s = new AST.AliasDeclaration(token.loc, id, stag);
}
}
}
if (isalias)
s = new AST.AliasDeclaration(token.loc, id, dt);
}
@ -1768,6 +1847,7 @@ final class CParser(AST) : Parser!AST
if (pl.varargs != AST.VarArg.none && pl.length)
error("function identifier-list cannot end with `...`");
ft.parameterList.varargs = AST.VarArg.variadic; // but C11 allows extra arguments
importBuiltins = true; // will need __va_list_tag
auto plLength = pl.length;
if (symbols.length != plLength)
error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
@ -2230,8 +2310,14 @@ final class CParser(AST) : Parser!AST
case TKW.xcomplex | TKW.xdouble: t = AST.Type.tcomplex64; break;
case TKW.xcomplex | TKW.xlong | TKW.xdouble: t = realType(RTFlags.complex); break;
case TKW.xident: t = new AST.TypeIdentifier(loc, previd);
case TKW.xident:
{
const idx = previd.toString();
if (idx.length > 2 && idx[0] == '_' && idx[1] == '_') // leading double underscore
importBuiltins = true; // probably one of those compiler extensions
t = new AST.TypeIdentifier(loc, previd);
break;
}
case TKW.xtag:
break; // t is already set
@ -2599,6 +2685,7 @@ final class CParser(AST) : Parser!AST
if (token.value == TOK.rightParenthesis) // func()
{
nextToken();
importBuiltins = true; // will need __va_list_tag
return AST.ParameterList(parameters, AST.VarArg.variadic, varargsStc);
}
@ -2613,6 +2700,7 @@ final class CParser(AST) : Parser!AST
{
if (parameters.length == 0) // func(...)
error("named parameter required before `...`");
importBuiltins = true; // will need __va_list_tag
varargs = AST.VarArg.variadic; // C-style variadics
nextToken();
check(TOK.rightParenthesis);
@ -3011,6 +3099,17 @@ final class CParser(AST) : Parser!AST
nextToken();
}
/* clang extension: add optional base type after the identifier
* https://en.cppreference.com/w/cpp/language/enum
* enum Identifier : Type
*/
AST.Type base = AST.Type.tint32; // C11 6.7.2.2-4 implementation defined default base type
if (token.value == TOK.colon)
{
nextToken();
base = cparseTypeName();
}
AST.Dsymbols* members;
if (token.value == TOK.leftCurly)
{
@ -3084,7 +3183,7 @@ final class CParser(AST) : Parser!AST
* redeclaration, or reference to existing declaration.
* Defer to the semantic() pass with a TypeTag.
*/
return new AST.TypeTag(loc, TOK.enum_, tag, members);
return new AST.TypeTag(loc, TOK.enum_, tag, base, members);
}
/*************************************
@ -3124,17 +3223,14 @@ final class CParser(AST) : Parser!AST
if (token.value == TOK.leftCurly)
{
nextToken();
auto symbolsSave = symbols;
symbols = new AST.Dsymbols();
members = new AST.Dsymbols(); // so `members` will be non-null even with 0 members
while (token.value != TOK.rightCurly)
{
cparseStructDeclaration();
cparseStructDeclaration(members);
if (token.value == TOK.endOfFile)
break;
}
members = symbols; // `members` will be non-null even with 0 members
symbols = symbolsSave;
check(TOK.rightCurly);
if ((*members).length == 0) // C11 6.7.2.1-8
@ -3152,7 +3248,7 @@ final class CParser(AST) : Parser!AST
* redeclaration, or reference to existing declaration.
* Defer to the semantic() pass with a TypeTag.
*/
return new AST.TypeTag(loc, structOrUnion, tag, members);
return new AST.TypeTag(loc, structOrUnion, tag, null, members);
}
/*************************************
@ -3169,18 +3265,19 @@ final class CParser(AST) : Parser!AST
* struct-declarator:
* declarator
* declarator (opt) : constant-expression
* Params:
* members = where to put the fields (members)
*/
void cparseStructDeclaration()
void cparseStructDeclaration(AST.Dsymbols* members)
{
//printf("cparseStructDeclaration()\n");
if (token.value == TOK._Static_assert)
{
auto s = cparseStaticAssert();
symbols.push(s);
members.push(s);
return;
}
auto symbolsSave = symbols;
Specifier specifier;
specifier.packalign = this.packalign;
auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
@ -3209,10 +3306,8 @@ final class CParser(AST) : Parser!AST
* the containing struct
*/
auto ad = new AST.AnonDeclaration(tt.loc, tt.tok == TOK.union_, tt.members);
if (!symbols)
symbols = new AST.Dsymbols();
auto s = applySpecifier(ad, specifier);
symbols.push(s);
members.push(s);
return;
}
if (!tt.id && !tt.members)
@ -3270,18 +3365,14 @@ final class CParser(AST) : Parser!AST
if (token.value == TOK.__attribute__)
cparseGnuAttributes(specifier);
AST.Dsymbol s = null;
symbols = symbolsSave;
if (!symbols)
symbols = new AST.Dsymbols; // lazilly create it
if (!tspec && !specifier.scw && !specifier.mod)
error("specifier-qualifier-list required");
else if (width)
{
if (specifier.alignExps)
error("no alignment-specifier for bit field declaration"); // C11 6.7.5-2
s = new AST.BitFieldDeclaration(width.loc, dt, id, width);
auto s = new AST.BitFieldDeclaration(width.loc, dt, id, width);
members.push(s);
}
else if (id)
{
@ -3291,11 +3382,10 @@ final class CParser(AST) : Parser!AST
// declare the symbol
// Give member variables an implicit void initializer
auto initializer = new AST.VoidInitializer(token.loc);
s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(LVL.member, specifier));
AST.Dsymbol s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(LVL.member, specifier));
s = applySpecifier(s, specifier);
members.push(s);
}
if (s !is null)
symbols.push(s);
switch (token.value)
{
@ -4391,39 +4481,5 @@ final class CParser(AST) : Parser!AST
return s;
}
/***********************************
* Add global target-dependent builtin declarations.
*/
private void addBuiltinDeclarations()
{
void genBuiltinFunc(Identifier id, AST.VarArg va)
{
auto tva_list = new AST.TypeIdentifier(Loc.initial, Id.builtin_va_list);
auto parameters = new AST.Parameters();
parameters.push(new AST.Parameter(STC.parameter | STC.ref_, tva_list, null, null, null));
auto pl = AST.ParameterList(parameters, va, 0);
auto tf = new AST.TypeFunction(pl, AST.Type.tvoid, LINK.c, 0);
auto s = new AST.FuncDeclaration(Loc.initial, Loc.initial, id, AST.STC.static_, tf, false);
symbols.push(s);
}
/* void __builtin_va_start(__builtin_va_list, ...);
* The second argument is supposed to be of any type, so fake it with the ...
*/
genBuiltinFunc(Id.builtin_va_start, AST.VarArg.variadic);
/* void __builtin_va_end(__builtin_va_list);
*/
genBuiltinFunc(Id.builtin_va_end, AST.VarArg.none);
/* struct __va_list_tag
* {
* uint, uint, void*, void*
* }
*/
auto s = new AST.StructDeclaration(Loc.initial, Id.va_list_tag, false);
symbols.push(s);
}
//}
}

View File

@ -1315,7 +1315,18 @@ private final class CppMangleVisitor : Visitor
foreach (n, fparam; parameterList)
{
Type t = target.cpp.parameterType(fparam);
Type t = fparam.type.merge2();
if (fparam.isReference())
t = t.referenceTo();
else if (fparam.storageClass & STC.lazy_)
{
// Mangle as delegate
auto tf = new TypeFunction(ParameterList(), t, LINK.d);
auto td = new TypeDelegate(tf);
t = td.merge();
}
else if (Type cpptype = target.cpp.parameterType(t))
t = cpptype;
if (t.ty == Tsarray)
{
// Static arrays in D are passed by value; no counterpart in C++

View File

@ -858,11 +858,8 @@ MATCH implicitConvTo(Expression e, Type t)
* convert to immutable
*/
if (e.f &&
(global.params.useDIP1000 != FeatureState.enabled || // lots of legacy code breaks with the following purity check
e.f.isPure() >= PURE.strong ||
// Special case exemption for Object.dup() which we assume is implemented correctly
e.f.ident == Id.dup &&
e.f.toParent2() == ClassDeclaration.object.toParent()) &&
// lots of legacy code breaks with the following purity check
(global.params.useDIP1000 != FeatureState.enabled || e.f.isPure() >= PURE.const_) &&
e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive.
)
{
@ -2245,9 +2242,12 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t);
(*te.exps)[i] = ex;
}
if (totuple)
te.type = totuple;
result = te;
/* Questionable behavior: In here, result.type is not set to t.
/* Questionable behavior: In here, result.type is not set to t
* if target type is not a tuple of same length.
* Therefoe:
* TypeTuple!(int, int) values;
* auto values2 = cast(long)values;

View File

@ -446,6 +446,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
*poffset = 0;
while (cd)
{
assert(cd.baseClass || cd.semanticRun >= PASS.semanticdone || cd.isInterfaceDeclaration());
if (this == cd.baseClass)
return true;

View File

@ -1048,7 +1048,6 @@ extern (C++) class VarDeclaration : Declaration
uint endlinnum; // line number of end of scope that this var lives in
uint offset;
uint sequenceNumber; // order the variables are declared
__gshared uint nextSequenceNumber; // the counter for sequenceNumber
structalign_t alignment;
// When interpreting, these point to the value (NULL if value not determinable)
@ -1099,7 +1098,6 @@ extern (C++) class VarDeclaration : Declaration
this._init = _init;
ctfeAdrOnStack = AdrOnStackNone;
this.storage_class = storage_class;
sequenceNumber = ++nextSequenceNumber;
}
static VarDeclaration create(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
@ -1657,12 +1655,10 @@ extern (C++) class VarDeclaration : Declaration
// Sequence numbers work when there are no special VarDeclaration's involved
if (!((this.storage_class | v.storage_class) & special))
{
// FIXME: VarDeclaration's for parameters are created in semantic3, so
// they will have a greater sequence number than local variables.
// Hence reverse the result for mixed comparisons.
const exp = this.isParameter() == v.isParameter();
assert(this.sequenceNumber != this.sequenceNumber.init);
assert(v.sequenceNumber != v.sequenceNumber.init);
return (this.sequenceNumber < v.sequenceNumber) == exp;
return (this.sequenceNumber < v.sequenceNumber);
}
// Assume that semantic produces temporaries according to their lifetime

View File

@ -16,6 +16,7 @@ module dmd.denum;
import core.stdc.stdio;
import dmd.astenums;
import dmd.attrib;
import dmd.gluelayer;
import dmd.declaration;
@ -60,7 +61,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
extern (D) this(const ref Loc loc, Identifier ident, Type memtype)
{
super(loc, ident);
//printf("EnumDeclaration() %s\n", toChars());
//printf("EnumDeclaration() %p %s : %s\n", this, toChars(), memtype.toChars());
type = new TypeEnum(this);
this.memtype = memtype;
visibility = Visibility(Visibility.Kind.undefined);

View File

@ -99,7 +99,15 @@ public Expression ctfeInterpret(Expression e)
Expression result = interpret(e, null);
result = copyRegionExp(result);
// Report an error if the expression contained a `ThrowException` and
// hence generated an uncaught exception
if (auto tee = result.isThrownExceptionExp())
{
tee.generateUncaughtError();
result = CTFEExp.cantexp;
}
else
result = copyRegionExp(result);
if (!CTFEExp.isCantExp(result))
result = scrubReturnValue(e.loc, result);
@ -1601,14 +1609,20 @@ public:
istate.start = null;
}
incUsageCtfe(istate, s.loc);
interpretThrow(s.exp, s.loc);
}
Expression e = interpretRegion(s.exp, istate);
/// Interpret `throw <exp>` found at the specified location `loc`
private void interpretThrow(Expression exp, const ref Loc loc)
{
incUsageCtfe(istate, loc);
Expression e = interpretRegion(exp, istate);
if (exceptionOrCant(e))
return;
assert(e.op == EXP.classReference);
result = ctfeEmplaceExp!ThrownExceptionExp(s.loc, e.isClassReferenceExp());
result = ctfeEmplaceExp!ThrownExceptionExp(loc, e.isClassReferenceExp());
}
override void visit(ScopeGuardStatement s)
@ -6149,6 +6163,15 @@ public:
return;
}
override void visit(ThrowExp te)
{
debug (LOG)
{
printf("%s ThrowExpression::interpret()\n", e.loc.toChars());
}
interpretThrow(te.e1, te.loc);
}
override void visit(PtrExp e)
{
debug (LOG)

View File

@ -59,7 +59,6 @@ enum SCOPE
compile = 0x0100, /// inside __traits(compile)
ignoresymbolvisibility = 0x0200, /// ignore symbol visibility
/// https://issues.dlang.org/show_bug.cgi?id=15907
onlysafeaccess = 0x0400, /// unsafe access is not allowed for @safe code
Cfile = 0x0800, /// C semantics apply
free = 0x8000, /// is on free list
@ -74,7 +73,7 @@ enum SCOPE
/// Flags that are carried along with a scope push()
private enum PersistentFlags =
SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
SCOPE.noaccesscheck | SCOPE.onlysafeaccess | SCOPE.ignoresymbolvisibility |
SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility |
SCOPE.printf | SCOPE.scanf | SCOPE.Cfile;
struct Scope

View File

@ -2345,7 +2345,7 @@ extern (C++) final class DsymbolTable : RootObject
Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
{
enum log = false;
if (log) printf("handleTagSymbols('%s')\n", s.toChars());
if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
auto sd = s.isScopeDsymbol(); // new declaration
auto sd2 = s2.isScopeDsymbol(); // existing declaration

View File

@ -356,6 +356,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (sc && sc.inunion && sc.inunion.isAnonDeclaration())
dsym.overlapped = true;
dsym.sequenceNumber = global.varSequenceNumber++;
Scope* scx = null;
if (dsym._scope)
{
@ -1636,7 +1638,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// Should be merged with PragmaStatement
//printf("\tPragmaDeclaration::semantic '%s'\n", pd.toChars());
if (target.mscoff)
if (target.supportsLinkerDirective())
{
if (pd.ident == Id.linkerDirective)
{
@ -2177,7 +2179,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
/* C11 6.7.2.2
*/
ed.memtype = Type.tint32; // C11 6.7.2.2-4 implementation defined
assert(ed.memtype);
int nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0
void emSemantic(EnumMember em, ref int nextValue)
@ -3457,9 +3459,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}
/* These quirky conditions mimic what VC++ appears to do
/* These quirky conditions mimic what happens when virtual
inheritance is implemented by producing a virtual base table
with offsets to each of the virtual bases.
*/
if (target.mscoff && cd.classKind == ClassKind.cpp &&
if (target.cpp.splitVBasetable && cd.classKind == ClassKind.cpp &&
cd.baseClass && cd.baseClass.vtbl.dim)
{
/* if overriding an interface function, then this is not
@ -3557,7 +3561,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
goto Lintro;
}
if (fdv.isDeprecated)
if (fdv.isDeprecated && !funcdecl.isDeprecated)
deprecation(funcdecl.loc, "`%s` is overriding the deprecated method `%s`",
funcdecl.toPrettyChars, fdv.toPrettyChars);
@ -3646,11 +3650,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
funcdecl.tintro = fdv.tintro;
else if (!funcdecl.type.equals(fdv.type))
{
auto tnext = funcdecl.type.nextOf();
if (auto handle = tnext.isClassHandle())
{
if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
handle.dsymbolSemantic(null);
}
/* Only need to have a tintro if the vptr
* offsets differ
*/
int offset;
if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset))
if (fdv.type.nextOf().isBaseOf(tnext, &offset))
{
funcdecl.tintro = fdv.type;
}
@ -3812,7 +3822,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
deprecation(funcdecl.loc,
"`%s` cannot be annotated with `@disable` because it is overriding a function in the base class",
funcdecl.toPrettyChars);
if (funcdecl.isDeprecated)
if (funcdecl.isDeprecated && !(funcdecl.foverrides.length && funcdecl.foverrides[0].isDeprecated))
deprecation(funcdecl.loc,
"`%s` cannot be marked as `deprecated` because it is overriding a function in the base class",
funcdecl.toPrettyChars);

View File

@ -6223,114 +6223,62 @@ extern (C++) class TemplateInstance : ScopeDsymbol
*/
final bool needsCodegen()
{
if (!minst)
// minst is finalized after the 1st invocation.
// tnext and tinst are only needed for the 1st invocation and
// cleared for further invocations.
TemplateInstance tnext = this.tnext;
TemplateInstance tinst = this.tinst;
this.tnext = null;
this.tinst = null;
if (errors || (inst && inst.isDiscardable()))
{
// If this is a speculative instantiation,
// 1. do codegen if ancestors really needs codegen.
// 2. become non-speculative if siblings are not speculative
TemplateInstance tnext = this.tnext;
TemplateInstance tinst = this.tinst;
// At first, disconnect chain first to prevent infinite recursion.
this.tnext = null;
this.tinst = null;
// Determine necessity of tinst before tnext.
if (tinst && tinst.needsCodegen())
{
minst = tinst.minst; // cache result
if (global.params.allInst && minst)
{
return true;
}
assert(minst);
assert(minst.isRoot() || minst.rootImports());
return true;
}
if (tnext && (tnext.needsCodegen() || tnext.minst))
{
minst = tnext.minst; // cache result
if (global.params.allInst && minst)
{
return true;
}
assert(minst);
return minst.isRoot() || minst.rootImports();
}
// Elide codegen because this is really speculative.
minst = null; // mark as speculative
return false;
}
if (global.params.allInst)
{
return true;
}
// Do codegen if there is an instantiation from a root module, to maximize link-ability.
if (isDiscardable())
{
return false;
}
/* Even when this is reached to the codegen pass,
* a non-root nested template should not generate code,
* due to avoid ODR violation.
*/
if (enclosing && enclosing.inNonRoot())
{
if (tinst)
{
auto r = tinst.needsCodegen();
minst = tinst.minst; // cache result
return r;
}
if (tnext)
{
auto r = tnext.needsCodegen();
minst = tnext.minst; // cache result
return r;
}
return false;
}
if (global.params.useUnitTests)
{
// Prefer instantiations from root modules, to maximize link-ability.
if (minst.isRoot())
// Do codegen if `this` is instantiated from a root module.
if (minst && minst.isRoot())
return true;
TemplateInstance tnext = this.tnext;
TemplateInstance tinst = this.tinst;
this.tnext = null;
this.tinst = null;
// Do codegen if the ancestor needs it.
if (tinst && tinst.needsCodegen())
{
minst = tinst.minst; // cache result
assert(minst);
assert(minst.isRoot() || minst.rootImports());
assert(minst.isRoot());
return true;
}
if (tnext && tnext.needsCodegen())
// Do codegen if a sibling needs it.
if (tnext)
{
minst = tnext.minst; // cache result
assert(minst);
assert(minst.isRoot() || minst.rootImports());
return true;
if (tnext.needsCodegen())
{
minst = tnext.minst; // cache result
assert(minst);
assert(minst.isRoot());
return true;
}
else if (!minst && tnext.minst)
{
minst = tnext.minst; // cache result from non-speculative sibling
return false;
}
}
// https://issues.dlang.org/show_bug.cgi?id=2500 case
if (minst.rootImports())
return true;
// Elide codegen because this is not included in root instances.
// Elide codegen because there's no instantiation from any root modules.
return false;
}
else
{
// Prefer instantiations from non-root module, to minimize object code size.
// Prefer instantiations from non-root modules, to minimize object code size.
/* If a TemplateInstance is ever instantiated by non-root modules,
/* If a TemplateInstance is ever instantiated from a non-root module,
* we do not have to generate code for it,
* because it will be generated when the non-root module is compiled.
*
@ -6341,22 +6289,51 @@ extern (C++) class TemplateInstance : ScopeDsymbol
* or the compilation of B do the actual instantiation?
*
* See https://issues.dlang.org/show_bug.cgi?id=2500.
*
* => Elide codegen if there is at least one instantiation from a non-root module
* which doesn't import any root modules.
*/
if (!minst.isRoot() && !minst.rootImports())
return false;
TemplateInstance tnext = this.tnext;
this.tnext = null;
if (tnext && !tnext.needsCodegen() && tnext.minst)
// If the ancestor isn't speculative,
// 1. do codegen if the ancestor needs it
// 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
if (tinst)
{
minst = tnext.minst; // cache result
assert(!minst.isRoot());
return false;
const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
if (tinst.minst) // not speculative
{
minst = tinst.minst; // cache result
return needsCodegen;
}
}
// Do codegen because this is not included in non-root instances.
return true;
// Elide codegen if `this` doesn't need it.
if (minst && !minst.isRoot() && !minst.rootImports())
return false;
// Elide codegen if a (non-speculative) sibling doesn't need it.
if (tnext)
{
const needsCodegen = tnext.needsCodegen(); // sets tnext.minst
if (tnext.minst) // not speculative
{
if (!needsCodegen)
{
minst = tnext.minst; // cache result
assert(!minst.isRoot() && !minst.rootImports());
return false;
}
else if (!minst)
{
minst = tnext.minst; // cache result from non-speculative sibling
return true;
}
}
}
// Unless `this` is still speculative (=> all further siblings speculative too),
// do codegen because we found no guaranteed-codegen'd non-root instantiation.
return minst !is null;
}
}
@ -7311,7 +7288,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
if ((td && td.literal) || (ti && ti.enclosing) || (d && !d.isDataseg() && !(d.storage_class & STC.manifest) && (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && !isTemplateMixin()))
{
Dsymbol dparent = sa.toParent2();
if (!dparent)
if (!dparent || dparent.isModule)
goto L1;
else if (!enclosing)
enclosing = dparent;
@ -7370,13 +7347,6 @@ extern (C++) class TemplateInstance : ScopeDsymbol
{
Module mi = minst; // instantiated . inserted module
if (global.params.useUnitTests)
{
// Turn all non-root instances to speculative
if (mi && !mi.isRoot())
mi = null;
}
//printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
// toPrettyChars(),
// enclosing ? enclosing.toPrettyChars() : null,

View File

@ -16,6 +16,7 @@ import core.stdc.string;
import core.stdc.ctype;
import dmd.astcodegen;
import dmd.astenums;
import dmd.arraytypes;
import dmd.attrib;
import dmd.dsymbol;

View File

@ -691,11 +691,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
}
// If va's lifetime encloses v's, then error
if (va &&
(va.enclosesLifetimeOf(v) && !(v.storage_class & (STC.parameter | STC.temp)) ||
// va is class reference
ae.e1.isDotVarExp() && va.type.toBasetype().isTypeClass() && (va.enclosesLifetimeOf(v) ||
!va.isScope()) ||
if (va && !va.isDataseg() &&
(va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp) ||
vaIsRef ||
va.isReference() && !(v.storage_class & (STC.parameter | STC.temp))) &&
fd.setUnsafe())
@ -768,7 +765,6 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
}
}
ByRef:
foreach (VarDeclaration v; er.byref)
{
if (log) printf("byref: %s\n", v.toChars());
@ -797,8 +793,7 @@ ByRef:
// If va's lifetime encloses v's, then error
if (va &&
(va.enclosesLifetimeOf(v) && !(v.isParameter() && v.isRef()) ||
va.isDataseg()) &&
(va.enclosesLifetimeOf(v) || (va.isRef() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
fd.setUnsafe())
{
if (!gag)
@ -807,26 +802,6 @@ ByRef:
continue;
}
if (va && v.isReference())
{
Dsymbol pva = va.toParent2();
for (Dsymbol pv = p; pv; )
{
pv = pv.toParent2();
if (pva == pv) // if v is nested inside pva
{
if (fd.setUnsafe())
{
if (!gag)
error(ae.loc, "reference `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars());
result = true;
continue ByRef;
}
break;
}
}
}
if (!(va && va.isScope()))
notMaybeScope(v);
@ -1323,7 +1298,9 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
msg = "returning `%s` escapes a reference to parameter `%s`";
supplemental = vsr == ScopeRef.Ref_ReturnScope
? "perhaps remove `scope` parameter annotation so `return` applies to `ref`"
: "perhaps annotate the parameter with `return`";
: v.ident is Id.This
? "perhaps annotate the function with `return`"
: "perhaps annotate the parameter with `return`";
}
else
{

View File

@ -25,7 +25,6 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.gluelayer;
import dmd.canthrow;
import dmd.constfold;
import dmd.ctfeexpr;
import dmd.ctorflow;
@ -466,7 +465,17 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
*/
auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
if (sd.hasCopyCtor && destinationType)
tmp.type = destinationType;
{
// https://issues.dlang.org/show_bug.cgi?id=22619
// If the destination type is inout we can preserve it
// only if inside an inout function; if we are not inside
// an inout function, then we will preserve the type of
// the source
if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
tmp.type = e.type;
else
tmp.type = destinationType;
}
tmp.storage_class |= STC.nodtor;
tmp.dsymbolSemantic(sc);
Expression de = new DeclarationExp(e.loc, tmp);
@ -4680,6 +4689,31 @@ extern (C++) final class AssertExp : UnaExp
}
}
/***********************************************************
* `throw <e1>` as proposed by DIP 1034.
*
* Replacement for the deprecated `ThrowStatement` that can be nested
* in other expression.
*/
extern (C++) final class ThrowExp : UnaExp
{
extern (D) this(const ref Loc loc, Expression e)
{
super(loc, EXP.throw_, __traits(classInstanceSize, ThrowExp), e);
this.type = Type.tnoreturn;
}
override ThrowExp syntaxCopy()
{
return new ThrowExp(loc, e1.syntaxCopy());
}
override void accept(Visitor v)
{
v.visit(this);
}
}
/***********************************************************
*/
extern (C++) final class DotIdExp : UnaExp

View File

@ -48,7 +48,9 @@ struct Symbol; // back end symbol
void expandTuples(Expressions *exps);
bool isTrivialExp(Expression *e);
bool hasSideEffect(Expression *e, bool assumeImpureCalls = false);
bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow);
enum BE : int32_t;
BE canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow);
typedef unsigned char OwnedBy;
enum
@ -742,6 +744,14 @@ public:
void accept(Visitor *v) { v->visit(this); }
};
class ThrowExp : public UnaExp
{
public:
ThrowExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class DotIdExp : public UnaExp
{
public:

View File

@ -3604,16 +3604,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
if (!cdthis)
{
if (!sc.hasThis)
{
string msg = "cannot construct " ~
(cd.isAnonymous ? "anonymous nested class" : "nested class `%s`") ~
" because no implicit `this` reference to outer class" ~
(cdn.isAnonymous ? "" : " `%s`") ~ " is available\0";
exp.error(msg.ptr, cd.toChars, cdn.toChars);
return setError();
}
// Supply an implicit 'this' and try again
exp.thisexp = new ThisExp(exp.loc);
for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
{
if (!sp)
{
exp.error("outer class `%s` `this` needed to `new` nested class `%s`",
cdn.toChars(), cd.toChars());
return setError();
}
ClassDeclaration cdp = sp.isClassDeclaration();
if (!cdp)
continue;
@ -5702,12 +5707,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|| global.params.useDeprecated != DiagnosticReporting.error;
const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
// baseClass might not be set if either targ or tspec is forward referenced.
if (auto tc = e.targ.isTypeClass())
tc.sym.dsymbolSemantic(null);
if (auto tc = e.tspec.isTypeClass())
tc.sym.dsymbolSemantic(null);
if (preventAliasThis && e.targ.ty == Tstruct)
{
if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
@ -6396,6 +6395,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
: Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
}
override void visit(ThrowExp te)
{
import dmd.statementsem;
if (StatementSemanticVisitor.throwSemantic(te.loc, te.e1, sc))
result = te;
else
setError();
}
override void visit(DotIdExp exp)
{
static if (LOGSEMANTIC)
@ -6913,6 +6922,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.error("cannot take address of `%s`", exp.e1.toChars());
return setError();
}
if (auto dve = exp.e1.isDotVarExp())
{
/* https://issues.dlang.org/show_bug.cgi?id=22749
* Error about taking address of any bit-field, regardless of
* whether SCOPE.Cfile is set.
*/
if (auto bf = dve.var.isBitFieldDeclaration())
{
exp.error("cannot take address of bit-field `%s`", bf.toChars());
return setError();
}
}
bool hasOverloads;
if (auto f = isFuncAddress(exp, &hasOverloads))
@ -7511,6 +7532,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// https://issues.dlang.org/show_bug.cgi?id=19954
if (exp.e1.type.ty == Ttuple)
{
if (exp.to)
{
if (TypeTuple tt = exp.to.isTypeTuple())
{
if (exp.e1.type.implicitConvTo(tt))
{
result = exp.e1.castTo(sc, tt);
return;
}
}
}
TupleExp te = exp.e1.isTupleExp();
if (te.exps.dim == 1)
exp.e1 = (*te.exps)[0];
@ -7531,7 +7563,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (exp.to.ty == Ttuple)
{
exp.error("cannot cast `%s` to tuple type `%s`", exp.e1.toChars(), exp.to.toChars());
exp.error("cannot cast `%s` of type `%s` to tuple type `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
return setError();
}
@ -8016,7 +8048,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression el = new ArrayLengthExp(exp.loc, exp.e1);
el = el.expressionSemantic(sc);
el = el.optimize(WANTvalue);
if (el.op == EXP.int64)
if (el.op == EXP.int64 && t1b.ty == Tsarray)
{
// Array length is known at compile-time. Upper is in bounds if it fits length.
dinteger_t length = el.toInteger();
@ -9894,7 +9926,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Expression id = new IdentifierExp(exp.loc, Id.empty);
id = new DotIdExp(exp.loc, id, Id.object);
id = new DotIdExp(exp.loc, id, func);
id = id.expressionSemantic(sc);
auto arguments = new Expressions();
arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf).expressionSemantic(sc));
@ -11355,7 +11386,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
EXP cmpop;
EXP cmpop = exp.op;
if (auto e = exp.op_overload(sc, &cmpop))
{
if (!e.type.isscalar() && e.type.equals(exp.e1.type))
@ -11365,6 +11397,38 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
if (e.op == EXP.call)
{
if (t1.ty == Tclass && t2.ty == Tclass)
{
// Lower to object.__cmp(e1, e2)
Expression cl = new IdentifierExp(exp.loc, Id.empty);
cl = new DotIdExp(exp.loc, cl, Id.object);
cl = new DotIdExp(exp.loc, cl, Id.__cmp);
cl = cl.expressionSemantic(sc);
auto arguments = new Expressions();
// Check if op_overload found a better match by calling e2.opCmp(e1)
// If the operands were swapped, then the result must be reversed
// e1.opCmp(e2) == -e2.opCmp(e1)
// cmpop takes care of this
if (exp.op == cmpop)
{
arguments.push(exp.e1);
arguments.push(exp.e2);
}
else
{
// Use better match found by op_overload
arguments.push(exp.e2);
arguments.push(exp.e1);
}
cl = new CallExp(exp.loc, cl, arguments);
cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
result = cl.expressionSemantic(sc);
return;
}
e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
e = e.expressionSemantic(sc);
}
@ -11372,6 +11436,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
}
if (Expression ex = typeCombine(exp, sc))
{
result = ex;
@ -13213,7 +13278,16 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
if (em.errors)
return ErrorExp.get();
Expression e = new VarExp(loc, em);
return e.expressionSemantic(sc);
e = e.expressionSemantic(sc);
if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
{
/* C11 types them as int. But if in D file,
* type qualified names as the enum
*/
e.type = em.parent.isEnumDeclaration().type;
assert(e.type);
}
return e;
}
@ -13245,6 +13319,8 @@ Expression toBoolean(Expression exp, Scope* sc)
case EXP.assign:
case EXP.construct:
case EXP.blit:
if (sc.flags & SCOPE.Cfile)
return exp;
// Things like:
// if (a = b) ...
// are usually mistakes.

View File

@ -3052,7 +3052,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
// all of overloads are templates
if (td)
{
.error(loc, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`",
.error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
tiargsBuf.peekChars(), fargsBuf.peekChars());

View File

@ -327,6 +327,7 @@ extern (C++) struct Global
Array!Identifier* debugids; /// command line debug versions and predefined versions
bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch)
uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks
enum recursionLimit = 500; /// number of recursive template expansions before abort
@ -614,48 +615,5 @@ nothrow:
}
}
/// A linkage attribute as defined by `extern(XXX)`
///
/// https://dlang.org/spec/attribute.html#linkage
enum LINK : ubyte
{
default_,
d,
c,
cpp,
windows,
objc,
system,
}
/// Whether to mangle an external aggregate as a struct or class, as set by `extern(C++, struct)`
enum CPPMANGLE : ubyte
{
def, /// default
asStruct, /// `extern(C++, struct)`
asClass, /// `extern(C++, class)`
}
/// Function match levels
///
/// https://dlang.org/spec/function.html#function-overloading
enum MATCH : int
{
nomatch, /// no match
convert, /// match with conversions
constant, /// match with conversion to const
exact, /// exact match
}
/// Inline setting as defined by `pragma(inline, XXX)`
enum PINLINE : ubyte
{
default_, /// as specified on the command line
never, /// never inline
always, /// always inline
}
alias StorageClass = ulong;
/// Collection of global state
extern (C++) __gshared Global global;

View File

@ -290,6 +290,7 @@ struct Global
Array<class Identifier*>* debugids; // command line debug versions and predefined versions
bool hasMainFunction;
unsigned varSequenceNumber;
/* Start gagging. Return the current number of gagged errors
*/

View File

@ -2364,6 +2364,12 @@ public:
buf.writeByte(')');
}
override void visit(ThrowExp e)
{
buf.writestring("throw ");
expToBuffer(e.e1, PREC.unary, buf, hgs);
}
override void visit(DotIdExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
@ -3896,6 +3902,11 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
buf.writeByte(' ');
if (t.id)
buf.writestring(t.id.toChars());
if (t.base.ty != TY.Tint32)
{
buf.writestring(" : ");
visitWithMask(t.base, t.mod, buf, hgs);
}
}
void visitTuple(TypeTuple t)

View File

@ -478,6 +478,7 @@ immutable Msgtable[] msgtable =
{ "hasCopyConstructor" },
{ "isCopyable" },
{ "toType" },
{ "parameters" },
// For C++ mangling
{ "allocator" },
@ -507,12 +508,11 @@ immutable Msgtable[] msgtable =
{ "__func__" },
{ "noreturn" },
{ "__pragma", "pragma" },
{ "builtins", "__builtins" },
{ "builtin_va_list", "__builtin_va_list" },
{ "builtin_va_start", "__builtin_va_start" },
{ "builtin_va_arg", "__builtin_va_arg" },
{ "builtin_va_copy", "__builtin_va_copy" },
{ "builtin_va_end", "__builtin_va_end" },
{ "va_list_tag", "__va_list_tag" },
{ "va_arg" },
{ "pack" },
{ "show" },
{ "push" },

View File

@ -302,8 +302,7 @@ public:
//property(name, "impure");
break;
case PURE.weak: return property(name, "weak");
case PURE.const_: return property(name, "const");
case PURE.strong: return property(name, "strong");
case PURE.const_: return property(name, "strong");
case PURE.fwdref: return property(name, "fwdref");
}
}

View File

@ -230,6 +230,57 @@ bool isSomeChar(TY ty) pure nothrow @nogc @safe
return ty == Tchar || ty == Twchar || ty == Tdchar;
}
/************************************
* Determine mutability of indirections in (ref) t.
*
* Returns: When the type has any mutable indirections, returns 0.
* When all indirections are immutable, returns 2.
* Otherwise, when the type has const/inout indirections, returns 1.
*
* Params:
* isref = if true, check `ref t`; otherwise, check just `t`
* t = the type that is being checked
*/
int mutabilityOfType(bool isref, Type t)
{
if (isref)
{
if (t.mod & MODFlags.immutable_)
return 2;
if (t.mod & (MODFlags.const_ | MODFlags.wild))
return 1;
return 0;
}
t = t.baseElemOf();
if (!t.hasPointers() || t.mod & MODFlags.immutable_)
return 2;
/* Accept immutable(T)[] and immutable(T)* as being strongly pure
*/
if (t.ty == Tarray || t.ty == Tpointer)
{
Type tn = t.nextOf().toBasetype();
if (tn.mod & MODFlags.immutable_)
return 2;
if (tn.mod & (MODFlags.const_ | MODFlags.wild))
return 1;
}
/* The rest of this is too strict; fix later.
* For example, the only pointer members of a struct may be immutable,
* which would maintain strong purity.
* (Just like for dynamic arrays and pointers above.)
*/
if (t.mod & (MODFlags.const_ | MODFlags.wild))
return 1;
/* Should catch delegates and function pointers, and fold in their purity
*/
return 0;
}
/****************
* dotExp() bit flags
*/
@ -4217,54 +4268,11 @@ extern (C++) final class TypeFunction : TypeNext
if (tf.purity != PURE.fwdref)
return;
/* Determine purity level based on mutability of t
* and whether it is a 'ref' type or not.
*/
static PURE purityOfType(bool isref, Type t)
{
if (isref)
{
if (t.mod & MODFlags.immutable_)
return PURE.strong;
if (t.mod & (MODFlags.const_ | MODFlags.wild))
return PURE.const_;
return PURE.weak;
}
t = t.baseElemOf();
if (!t.hasPointers() || t.mod & MODFlags.immutable_)
return PURE.strong;
/* Accept immutable(T)[] and immutable(T)* as being strongly pure
*/
if (t.ty == Tarray || t.ty == Tpointer)
{
Type tn = t.nextOf().toBasetype();
if (tn.mod & MODFlags.immutable_)
return PURE.strong;
if (tn.mod & (MODFlags.const_ | MODFlags.wild))
return PURE.const_;
}
/* The rest of this is too strict; fix later.
* For example, the only pointer members of a struct may be immutable,
* which would maintain strong purity.
* (Just like for dynamic arrays and pointers above.)
*/
if (t.mod & (MODFlags.const_ | MODFlags.wild))
return PURE.const_;
/* Should catch delegates and function pointers, and fold in their purity
*/
return PURE.weak;
}
purity = PURE.strong; // assume strong until something weakens it
purity = PURE.const_; // assume strong until something weakens it
/* Evaluate what kind of purity based on the modifiers for the parameters
*/
Lloop: foreach (i, fparam; tf.parameterList)
foreach (i, fparam; tf.parameterList)
{
Type t = fparam.type;
if (!t)
@ -4275,33 +4283,11 @@ extern (C++) final class TypeFunction : TypeNext
purity = PURE.weak;
break;
}
switch (purityOfType((fparam.storageClass & STC.ref_) != 0, t))
{
case PURE.weak:
purity = PURE.weak;
break Lloop; // since PURE.weak, no need to check further
case PURE.const_:
purity = PURE.const_;
continue;
case PURE.strong:
continue;
default:
assert(0);
}
const pref = (fparam.storageClass & STC.ref_) != 0;
if (mutabilityOfType(pref, t) == 0)
purity = PURE.weak;
}
if (purity > PURE.weak && tf.nextOf())
{
/* Adjust purity based on mutability of return type.
* https://issues.dlang.org/show_bug.cgi?id=15862
*/
const purity2 = purityOfType(tf.isref, tf.nextOf());
if (purity2 < purity)
purity = purity2;
}
tf.purity = purity;
}
@ -6306,10 +6292,7 @@ extern (C++) final class TypeClass : Type
extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
{
MATCH m = constConv(to);
if (m > MATCH.nomatch)
return m;
// Run semantic before checking whether class is convertible
ClassDeclaration cdto = to.isClassHandle();
if (cdto)
{
@ -6318,11 +6301,15 @@ extern (C++) final class TypeClass : Type
cdto.dsymbolSemantic(null);
if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
sym.dsymbolSemantic(null);
if (cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod))
{
//printf("'to' is base\n");
return MATCH.convert;
}
}
MATCH m = constConv(to);
if (m > MATCH.nomatch)
return m;
if (cdto && cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod))
{
//printf("'to' is base\n");
return MATCH.convert;
}
return MATCH.nomatch;
}
@ -6373,6 +6360,9 @@ extern (C++) final class TypeClass : Type
override MOD deduceWild(Type t, bool isRef)
{
// If sym is forward referenced:
if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
sym.dsymbolSemantic(null);
ClassDeclaration cd = t.isClassHandle();
if (cd && (sym == cd || cd.isBaseOf(sym, null)))
return Type.deduceWild(t, isRef);
@ -6760,19 +6750,21 @@ extern (C++) final class TypeTag : Type
Loc loc; /// location of declaration
TOK tok; /// TOK.struct_, TOK.union_, TOK.enum_
Identifier id; /// tag name identifier
Type base; /// base type for enums otherwise null
Dsymbols* members; /// members of struct, null if none
Type resolved; /// type after semantic() in case there are more others
/// pointing to this instance, which can happen with
/// struct S { int a; } s1, *s2;
extern (D) this(const ref Loc loc, TOK tok, Identifier id, Dsymbols* members)
extern (D) this(const ref Loc loc, TOK tok, Identifier id, Type base, Dsymbols* members)
{
//printf("TypeTag %p\n", this);
super(Ttag);
this.loc = loc;
this.tok = tok;
this.id = id;
this.base = base;
this.members = members;
}

View File

@ -553,7 +553,6 @@ enum class PURE : unsigned char
fwdref = 1, // it's pure, but not known which level yet
weak = 2, // no mutable globals are read or written
const_ = 3, // parameters are values or const
strong = 4 // parameters are values or immutable
};
class Parameter : public ASTNode

View File

@ -71,6 +71,7 @@ public:
if (!e.f)
return;
// Treat lowered hook calls as their original expressions.
auto fd = stripHookTraceImpl(e.f);
if (fd.ident == Id._d_arraysetlengthT)
{

View File

@ -48,6 +48,7 @@ module dmd.nspace;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.dscope;
import dmd.dsymbol;
import dmd.dsymbolsem;

View File

@ -818,64 +818,6 @@ extern(C++) private final class Supported : Objc
expression.errorSupplemental("`tupleof` is not available for members " ~
"of Objective-C classes. Please use the Objective-C runtime instead");
}
extern(D) private:
/**
* Returns `true` if the given symbol is a symbol declared in
* `core.attribute` and has the given identifier.
*
* This is used to determine if a symbol is a UDA declared in
* `core.attribute`.
*
* Params:
* sd = the symbol to check
* ident = the name of the expected UDA
*/
bool isCoreUda(ScopeDsymbol sd, Identifier ident) const
{
if (sd.ident != ident || !sd.parent)
return false;
auto _module = sd.parent.isModule();
return _module && _module.isCoreModule(Id.attribute);
}
/**
* Iterates the UDAs attached to the given function declaration.
*
* If `dg` returns `!= 0`, it will stop the iteration and return that
* value, otherwise it will return 0.
*
* Params:
* fd = the function declaration to get the UDAs from
* dg = called once for each UDA. If `dg` returns `!= 0`, it will stop the
* iteration and return that value, otherwise it will return `0`.
*/
int foreachUda(FuncDeclaration fd, Scope* sc, int delegate(Expression) dg) const
{
if (!fd.userAttribDecl)
return 0;
auto udas = fd.userAttribDecl.getAttributes();
arrayExpressionSemantic(udas, sc, true);
return udas.each!((uda) {
if (!uda.isTupleExp())
return 0;
auto exps = uda.isTupleExp().exps;
return exps.each!((e) {
assert(e);
if (auto result = dg(e))
return result;
return 0;
});
});
}
}
/*

View File

@ -853,11 +853,11 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
{
// Rewrite (e1 op e2) as e2.opfunc(e1)
result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s);
// When reversing operands of comparison operators,
// need to reverse the sense of the op
if (pop)
*pop = reverseRelation(e.op);
}
// When reversing operands of comparison operators,
// need to reverse the sense of the op
if (pop)
*pop = reverseRelation(e.op);
return;
}
}
@ -1052,7 +1052,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof);
auto sc2 = sc.push();
sc2.flags = (sc2.flags & ~SCOPE.onlysafeaccess) | SCOPE.noaccesscheck;
sc2.flags |= SCOPE.noaccesscheck;
result = e.expressionSemantic(sc2);
sc2.pop();

View File

@ -1130,8 +1130,8 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
const e1Opt = e.e1.toBool();
if (e.e2.isConst())
{
bool n1 = e1Opt.hasValue(true);
bool n2 = e.e2.toBool().hasValue(true);
bool n1 = e1Opt.get();
bool n2 = e.e2.toBool().get();
ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type);
}
else if (e1Opt.hasValue(!oror))

View File

@ -128,6 +128,7 @@ immutable PREC[EXP.max + 1] precedence =
EXP.new_ : PREC.unary,
EXP.newAnonymousClass : PREC.unary,
EXP.cast_ : PREC.unary,
EXP.throw_ : PREC.unary,
EXP.vector : PREC.unary,
EXP.pow : PREC.pow,
@ -443,6 +444,13 @@ class Parser(AST) : Lexer
}
decldefs = parseDeclDefs(0, &lastDecl);
if (token.value == TOK.rightCurly)
{
error(token.loc, "unmatched closing brace");
goto Lerr;
}
if (token.value != TOK.endOfFile)
{
error(token.loc, "unrecognized declaration");
@ -643,7 +651,43 @@ class Parser(AST) : Lexer
goto Lerror;
case TOK.unittest_:
if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
/**
* Ignore unittests in non-root modules.
*
* This mainly means that unittests *inside templates* are only
* ever instantiated if the module lexically declaring the
* template is one of the root modules.
*
* E.g., compiling some project with `-unittest` does NOT
* compile and later run any unittests in instantiations of
* templates declared in other libraries.
*
* Declaring unittests *inside* templates is considered an anti-
* pattern. In almost all cases, the unittests don't depend on
* the template parameters, but instantiate the template with
* fixed arguments (e.g., Nullable!T unittests instantiating
* Nullable!int), so compiling and running identical tests for
* each template instantiation is hardly desirable.
* But adding a unittest right below some function being tested
* is arguably good for locality, so unittests end up inside
* templates.
* To make sure a template's unittests are run, it should be
* instantiated in the same module, e.g., some module-level
* unittest.
*
* Another reason for ignoring unittests in templates from non-
* root modules is for template codegen culling via
* TemplateInstance.needsCodegen(). If the compiler decides not
* to emit some Nullable!bool because there's an existing
* instantiation in some non-root module, it has no idea whether
* that module was compiled with -unittest too, and so whether
* Nullable!int (instantiated in some unittest inside the
* Nullable template) can be culled too. By ignoring unittests
* in non-root modules, the compiler won't consider any
* template instantiations in these unittests as candidates for
* further codegen culling.
*/
if (mod.isRoot() && (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration))
{
s = parseUnitTest(pAttrs);
if (*pLastDecl)
@ -1530,6 +1574,8 @@ class Parser(AST) : Lexer
case TOK.return_:
stc = STC.return_;
if (peekNext() == TOK.scope_)
stc |= STC.returnScope; // recognize `return scope`
break;
case TOK.scope_:
@ -2880,7 +2926,7 @@ class Parser(AST) : Lexer
StorageClass varargsStc;
// Attributes allowed for ...
enum VarArgsStc = STC.const_ | STC.immutable_ | STC.shared_ | STC.scope_ | STC.return_;
enum VarArgsStc = STC.const_ | STC.immutable_ | STC.shared_ | STC.scope_ | STC.return_ | STC.returnScope;
check(TOK.leftParenthesis);
while (1)
@ -2988,6 +3034,8 @@ class Parser(AST) : Lexer
case TOK.return_:
stc = STC.return_;
if (peekNext() == TOK.scope_)
stc |= STC.returnScope;
goto L2;
L2:
storageClass = appendStorageClass(storageClass, stc);
@ -3491,7 +3539,7 @@ class Parser(AST) : Lexer
return baseclasses;
}
private AST.Dsymbols* parseImport()
AST.Dsymbols* parseImport()
{
auto decldefs = new AST.Dsymbols();
Identifier aliasid = null;
@ -4453,7 +4501,6 @@ class Parser(AST) : Lexer
private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment)
{
StorageClass storage_class = STC.undefined_;
TOK tok = TOK.reserved;
LINK link = linkage;
Loc linkloc = this.linkLoc;
bool setAlignment = false;
@ -4464,245 +4511,22 @@ class Parser(AST) : Lexer
if (!comment)
comment = token.blockComment.ptr;
/* Look for AliasAssignment:
* identifier = type;
/* Look for AliasReassignment
*/
if (token.value == TOK.identifier && peekNext() == TOK.assign)
{
const loc = token.loc;
auto ident = token.ident;
nextToken();
nextToken(); // advance past =
auto t = parseType();
AST.Dsymbol s = new AST.AliasAssign(loc, ident, t, null);
check(TOK.semicolon);
addComment(s, comment);
auto a = new AST.Dsymbols();
a.push(s);
return a;
}
return parseAliasReassignment(comment);
/* Declarations that start with `alias`
*/
bool isAliasDeclaration = false;
if (token.value == TOK.alias_)
{
const loc = token.loc;
tok = token.value;
nextToken();
/* Look for:
* alias identifier this;
*/
if (token.value == TOK.identifier && peekNext() == TOK.this_)
{
auto s = new AST.AliasThis(loc, token.ident);
nextToken();
check(TOK.this_);
check(TOK.semicolon);
auto a = new AST.Dsymbols();
a.push(s);
addComment(s, comment);
if (auto a = parseAliasDeclarations(comment))
return a;
}
version (none)
{
/* Look for:
* alias this = identifier;
*/
if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier)
{
check(TOK.this_);
check(TOK.assign);
auto s = new AliasThis(loc, token.ident);
nextToken();
check(TOK.semicolon);
auto a = new Dsymbols();
a.push(s);
addComment(s, comment);
return a;
}
}
/* Look for:
* alias identifier = type;
* alias identifier(...) = type;
/* Handle these later:
* alias StorageClasses type ident;
*/
if (token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
{
auto a = new AST.Dsymbols();
while (1)
{
auto ident = token.ident;
nextToken();
AST.TemplateParameters* tpl = null;
if (token.value == TOK.leftParenthesis)
tpl = parseTemplateParameterList();
check(TOK.assign);
bool hasParsedAttributes;
void parseAttributes()
{
if (hasParsedAttributes) // only parse once
return;
hasParsedAttributes = true;
udas = null;
storage_class = STC.undefined_;
link = linkage;
linkloc = this.linkLoc;
setAlignment = false;
ealign = null;
parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
}
if (token.value == TOK.at)
parseAttributes;
AST.Declaration v;
AST.Dsymbol s;
// try to parse function type:
// TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
bool attributesAppended;
const StorageClass funcStc = parseTypeCtor();
Token* tlu = &token;
Token* tk;
if (token.value != TOK.function_ &&
token.value != TOK.delegate_ &&
isBasicType(&tlu) && tlu &&
tlu.value == TOK.leftParenthesis)
{
AST.Type tret = parseBasicType();
auto parameterList = parseParameterList(null);
parseAttributes();
if (udas)
error("user-defined attributes not allowed for `alias` declarations");
attributesAppended = true;
storage_class = appendStorageClass(storage_class, funcStc);
AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class);
v = new AST.AliasDeclaration(loc, ident, tf);
}
else if (token.value == TOK.function_ ||
token.value == TOK.delegate_ ||
token.value == TOK.leftParenthesis &&
skipAttributes(peekPastParen(&token), &tk) &&
(tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
token.value == TOK.leftCurly ||
token.value == TOK.identifier && peekNext() == TOK.goesTo ||
token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis &&
skipAttributes(peekPastParen(peek(&token)), &tk) &&
(tk.value == TOK.goesTo || tk.value == TOK.leftCurly)
)
{
// function (parameters) { statements... }
// delegate (parameters) { statements... }
// (parameters) { statements... }
// (parameters) => expression
// { statements... }
// identifier => expression
// ref (parameters) { statements... }
// ref (parameters) => expression
s = parseFunctionLiteral();
if (udas !is null)
{
if (storage_class != 0)
error("Cannot put a storage-class in an alias declaration.");
// parseAttributes shouldn't have set these variables
assert(link == linkage && !setAlignment && ealign is null);
auto tpl_ = cast(AST.TemplateDeclaration) s;
assert(tpl_ !is null && tpl_.members.dim == 1);
auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
auto tf = cast(AST.TypeFunction) fd.type;
assert(tf.parameterList.parameters.dim > 0);
auto as = new AST.Dsymbols();
(*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
}
v = new AST.AliasDeclaration(loc, ident, s);
}
else
{
parseAttributes();
// type
if (udas)
error("user-defined attributes not allowed for `%s` declarations", Token.toChars(tok));
auto t = parseType();
// Disallow meaningless storage classes on type aliases
if (storage_class)
{
// Don't raise errors for STC that are part of a function/delegate type, e.g.
// `alias F = ref pure nothrow @nogc @safe int function();`
auto tp = t.isTypePointer;
const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
if (remStc)
{
OutBuffer buf;
AST.stcToBuffer(&buf, remStc);
// @@@DEPRECATED_2.093@@@
// Deprecated in 2020-07, can be made an error in 2.103
deprecation("storage class `%s` has no effect in type aliases", buf.peekChars());
}
}
v = new AST.AliasDeclaration(loc, ident, t);
}
if (!attributesAppended)
storage_class = appendStorageClass(storage_class, funcStc);
v.storage_class = storage_class;
s = v;
if (tpl)
{
auto a2 = new AST.Dsymbols();
a2.push(s);
auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2);
s = tempdecl;
}
if (link != linkage)
{
auto a2 = new AST.Dsymbols();
a2.push(s);
s = new AST.LinkDeclaration(linkloc, link, a2);
}
a.push(s);
switch (token.value)
{
case TOK.semicolon:
nextToken();
addComment(s, comment);
break;
case TOK.comma:
nextToken();
addComment(s, comment);
if (token.value != TOK.identifier)
{
error("identifier expected following comma, not `%s`", token.toChars());
break;
}
if (peekNext() != TOK.assign && peekNext() != TOK.leftParenthesis)
{
error("`=` expected following identifier");
nextToken();
break;
}
continue;
default:
error("semicolon expected to close `%s` declaration", Token.toChars(tok));
break;
}
break;
}
return a;
}
// alias StorageClasses type ident;
isAliasDeclaration = true;
}
AST.Type ts;
@ -4839,7 +4663,7 @@ class Parser(AST) : Lexer
else if (!isThis && (t != AST.Type.terror))
error("no identifier for declarator `%s`", t.toChars());
if (tok == TOK.alias_)
if (isAliasDeclaration)
{
AST.Declaration v;
AST.Initializer _init = null;
@ -4852,7 +4676,7 @@ class Parser(AST) : Lexer
*/
if (udas)
error("user-defined attributes not allowed for `%s` declarations", Token.toChars(tok));
error("user-defined attributes not allowed for `alias` declarations");
if (token.value == TOK.assign)
{
@ -4901,7 +4725,7 @@ class Parser(AST) : Lexer
continue;
default:
error("semicolon expected to close `%s` declaration", Token.toChars(tok));
error("semicolon expected to close `alias` declaration");
break;
}
}
@ -5018,7 +4842,15 @@ class Parser(AST) : Lexer
continue;
default:
error("semicolon expected, not `%s`", token.toChars());
if (loc.linnum != token.loc.linnum)
{
error("semicolon needed to end declaration of `%s`, instead of `%s`", v.toChars(), token.toChars());
errorSupplemental(loc, "`%s` declared here", v.toChars());
}
else
{
error("semicolon needed to end declaration of `%s` instead of `%s`", v.toChars(), token.toChars());
}
break;
}
}
@ -5027,6 +4859,271 @@ class Parser(AST) : Lexer
return a;
}
/********************************
* Parse AliasReassignment:
* identifier = type;
* Parser is sitting on the identifier.
* https://dlang.org/spec/declaration.html#alias-reassignment
* Params:
* comment = if not null, comment to attach to symbol
* Returns:
* array of symbols
*/
private AST.Dsymbols* parseAliasReassignment(const(char)* comment)
{
const loc = token.loc;
auto ident = token.ident;
nextToken();
nextToken(); // advance past =
auto t = parseType();
AST.Dsymbol s = new AST.AliasAssign(loc, ident, t, null);
check(TOK.semicolon);
addComment(s, comment);
auto a = new AST.Dsymbols();
a.push(s);
return a;
}
/********************************
* Parse declarations that start with `alias`
* Parser is sitting on the `alias`.
* https://dlang.org/spec/declaration.html#alias
* Params:
* comment = if not null, comment to attach to symbol
* Returns:
* array of symbols
*/
private AST.Dsymbols* parseAliasDeclarations(const(char)* comment)
{
const loc = token.loc;
nextToken();
Loc linkloc = this.linkLoc;
AST.Expressions* udas;
LINK link = linkage;
StorageClass storage_class = STC.undefined_;
AST.Expression ealign;
bool setAlignment = false;
/* Look for:
* alias Identifier this;
* https://dlang.org/spec/class.html#alias-this
*/
if (token.value == TOK.identifier && peekNext() == TOK.this_)
{
auto s = new AST.AliasThis(loc, token.ident);
nextToken();
check(TOK.this_);
check(TOK.semicolon);
auto a = new AST.Dsymbols();
a.push(s);
addComment(s, comment);
return a;
}
version (none)
{
/* Look for:
* alias this = identifier;
*/
if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier)
{
check(TOK.this_);
check(TOK.assign);
auto s = new AliasThis(loc, token.ident);
nextToken();
check(TOK.semicolon);
auto a = new Dsymbols();
a.push(s);
addComment(s, comment);
return a;
}
}
/* Look for:
* alias identifier = type;
* alias identifier(...) = type;
* https://dlang.org/spec/declaration.html#alias
*/
if (token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
{
auto a = new AST.Dsymbols();
while (1)
{
auto ident = token.ident;
nextToken();
AST.TemplateParameters* tpl = null;
if (token.value == TOK.leftParenthesis)
tpl = parseTemplateParameterList();
check(TOK.assign);
bool hasParsedAttributes;
void parseAttributes()
{
if (hasParsedAttributes) // only parse once
return;
hasParsedAttributes = true;
udas = null;
storage_class = STC.undefined_;
link = linkage;
linkloc = this.linkLoc;
setAlignment = false;
ealign = null;
parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
}
if (token.value == TOK.at)
parseAttributes;
AST.Declaration v;
AST.Dsymbol s;
// try to parse function type:
// TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
bool attributesAppended;
const StorageClass funcStc = parseTypeCtor();
Token* tlu = &token;
Token* tk;
if (token.value != TOK.function_ &&
token.value != TOK.delegate_ &&
isBasicType(&tlu) && tlu &&
tlu.value == TOK.leftParenthesis)
{
AST.Type tret = parseBasicType();
auto parameterList = parseParameterList(null);
parseAttributes();
if (udas)
error("user-defined attributes not allowed for `alias` declarations");
attributesAppended = true;
storage_class = appendStorageClass(storage_class, funcStc);
AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class);
v = new AST.AliasDeclaration(loc, ident, tf);
}
else if (token.value == TOK.function_ ||
token.value == TOK.delegate_ ||
token.value == TOK.leftParenthesis &&
skipAttributes(peekPastParen(&token), &tk) &&
(tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
token.value == TOK.leftCurly ||
token.value == TOK.identifier && peekNext() == TOK.goesTo ||
token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis &&
skipAttributes(peekPastParen(peek(&token)), &tk) &&
(tk.value == TOK.goesTo || tk.value == TOK.leftCurly)
)
{
// function (parameters) { statements... }
// delegate (parameters) { statements... }
// (parameters) { statements... }
// (parameters) => expression
// { statements... }
// identifier => expression
// ref (parameters) { statements... }
// ref (parameters) => expression
s = parseFunctionLiteral();
if (udas !is null)
{
if (storage_class != 0)
error("Cannot put a storage-class in an alias declaration.");
// parseAttributes shouldn't have set these variables
assert(link == linkage && !setAlignment && ealign is null);
auto tpl_ = cast(AST.TemplateDeclaration) s;
assert(tpl_ !is null && tpl_.members.dim == 1);
auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
auto tf = cast(AST.TypeFunction) fd.type;
assert(tf.parameterList.parameters.dim > 0);
auto as = new AST.Dsymbols();
(*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
}
v = new AST.AliasDeclaration(loc, ident, s);
}
else
{
parseAttributes();
// type
if (udas)
error("user-defined attributes not allowed for alias declarations");
auto t = parseType();
// Disallow meaningless storage classes on type aliases
if (storage_class)
{
// Don't raise errors for STC that are part of a function/delegate type, e.g.
// `alias F = ref pure nothrow @nogc @safe int function();`
auto tp = t.isTypePointer;
const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
if (remStc)
{
OutBuffer buf;
AST.stcToBuffer(&buf, remStc);
// @@@DEPRECATED_2.093@@@
// Deprecated in 2020-07, can be made an error in 2.103
deprecation("storage class `%s` has no effect in type aliases", buf.peekChars());
}
}
v = new AST.AliasDeclaration(loc, ident, t);
}
if (!attributesAppended)
storage_class = appendStorageClass(storage_class, funcStc);
v.storage_class = storage_class;
s = v;
if (tpl)
{
auto a2 = new AST.Dsymbols();
a2.push(s);
auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2);
s = tempdecl;
}
if (link != linkage)
{
auto a2 = new AST.Dsymbols();
a2.push(s);
s = new AST.LinkDeclaration(linkloc, link, a2);
}
a.push(s);
switch (token.value)
{
case TOK.semicolon:
nextToken();
addComment(s, comment);
break;
case TOK.comma:
nextToken();
addComment(s, comment);
if (token.value != TOK.identifier)
{
error("identifier expected following comma, not `%s`", token.toChars());
break;
}
if (peekNext() != TOK.assign && peekNext() != TOK.leftParenthesis)
{
error("`=` expected following identifier");
nextToken();
break;
}
continue;
default:
error("semicolon expected to close `alias` declaration");
break;
}
break;
}
return a;
}
// alias StorageClasses type ident;
return null;
}
private AST.Dsymbol parseFunctionLiteral()
{
const loc = token.loc;
@ -5390,6 +5487,7 @@ class Parser(AST) : Lexer
check(TOK.leftParenthesis);
auto parameters = new AST.Parameters();
Identifier lastai;
while (1)
{
Identifier ai = null;
@ -5465,8 +5563,9 @@ class Parser(AST) : Lexer
if (token.value == TOK.identifier)
{
const tv = peekNext();
if (tv == TOK.comma || tv == TOK.semicolon)
if (tv == TOK.comma || tv == TOK.semicolon || tv == TOK.rightParenthesis)
{
lastai = token.ident;
ai = token.ident;
at = null; // infer argument type
nextToken();
@ -5486,7 +5585,17 @@ class Parser(AST) : Lexer
}
break;
}
check(TOK.semicolon);
if (token.value != TOK.semicolon)
{
error("missing `; expression` before `)` of `foreach`");
nextToken();
if (lastai && parameters.length >= 2)
{
errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars());
}
return null;
}
nextToken();
AST.Expression aggr = parseExpression();
if (token.value == TOK.slice && parameters.dim == 1)
@ -8473,6 +8582,7 @@ LagainStc:
e = new AST.FuncExp(loc, s);
break;
}
default:
error("expression expected, not `%s`", token.toChars());
Lerr:
@ -8766,6 +8876,17 @@ LagainStc:
e = parsePostExp(e);
break;
}
case TOK.throw_:
{
nextToken();
// Deviation from the DIP:
// Parse AssignExpression instead of Expression to avoid conflicts for comma
// separated lists, e.g. function arguments
AST.Expression exp = parseAssignExp();
e = new AST.ThrowExp(loc, exp);
break;
}
default:
e = parsePrimaryExp();
e = parsePostExp(e);

View File

@ -220,6 +220,7 @@ public:
void visit(AST.CallExp e) { visit(cast(AST.UnaExp)e); }
void visit(AST.DotIdExp e) { visit(cast(AST.UnaExp)e); }
void visit(AST.AssertExp e) { visit(cast(AST.UnaExp)e); }
void visit(AST.ThrowExp e) { visit(cast(AST.UnaExp)e); }
void visit(AST.ImportExp e) { visit(cast(AST.UnaExp)e); }
void visit(AST.DotTemplateInstanceExp e) { visit(cast(AST.UnaExp)e); }
void visit(AST.ArrayExp e) { visit(cast(AST.UnaExp)e); }

View File

@ -13,6 +13,7 @@
| [hash.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d) | Calculate a hash for a byte array |
| [longdouble.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/longdouble.d) | 80-bit floating point number implementation in case they are not natively supported |
| [man.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/man.d) | Opens an online manual page |
| [optional.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.d) | Implementation of an 'Optional' type |
| [port.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d) | Portable routines for functions that have different implementations on different platforms |
| [region.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d) | A region allocator |
| [response.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/response.d) | Parse command line arguments from response files |

View File

@ -1,5 +1,5 @@
/**
* Optional implementation.
* Implementation of an 'Optional' type
*
* Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)

View File

@ -94,8 +94,9 @@ extern (C++) bool hasSideEffect(Expression e, bool assumeImpureCalls = false)
* Determine if the call of f, or function type or delegate type t1, has any side effects.
* Returns:
* 0 has any side effects
* 1 nothrow + constant purity
* 2 nothrow + strong purity
* 1 nothrow + strongly pure
* 2 nothrow + strongly pure + only immutable indirections in the return
* type
*/
int callSideEffectLevel(FuncDeclaration f)
{
@ -106,15 +107,18 @@ int callSideEffectLevel(FuncDeclaration f)
return 0;
assert(f.type.ty == Tfunction);
TypeFunction tf = cast(TypeFunction)f.type;
if (tf.isnothrow)
if (!tf.isnothrow)
return 0;
final switch (f.isPure())
{
PURE purity = f.isPure();
if (purity == PURE.strong)
return 2;
if (purity == PURE.const_)
return 1;
case PURE.impure:
case PURE.fwdref:
case PURE.weak:
return 0;
case PURE.const_:
return mutabilityOfType(tf.isref, tf.next) == 2 ? 2 : 1;
}
return 0;
}
int callSideEffectLevel(Type t)
@ -141,10 +145,9 @@ int callSideEffectLevel(Type t)
purity = PURE.const_;
}
if (purity == PURE.strong)
return 2;
if (purity == PURE.const_)
return 1;
return mutabilityOfType(tf.isref, tf.next) == 2 ? 2 : 1;
return 0;
}
@ -178,6 +181,7 @@ private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false)
case EXP.remove:
case EXP.assert_:
case EXP.halt:
case EXP.throw_:
case EXP.delete_:
case EXP.new_:
case EXP.newAnonymousClass:

View File

@ -21,7 +21,6 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.gluelayer;
import dmd.canthrow;
import dmd.cond;
import dmd.dclass;
import dmd.declaration;

View File

@ -45,7 +45,7 @@ struct code;
/* How a statement exits; this is returned by blockExit()
*/
enum BE
enum BE : int32_t
{
BEnone = 0,
BEfallthru = 1,

View File

@ -122,8 +122,10 @@ private LabelStatement checkLabeledLoop(Scope* sc, Statement statement)
* Returns:
* `e` or ErrorExp.
*/
private Expression checkAssignmentAsCondition(Expression e)
private Expression checkAssignmentAsCondition(Expression e, Scope* sc)
{
if (sc.flags & SCOPE.Cfile)
return e;
auto ec = lastComma(e);
if (ec.op == EXP.assign)
{
@ -148,7 +150,7 @@ extern(C++) Statement statementSemantic(Statement s, Scope* sc)
return v.result;
}
private extern (C++) final class StatementSemanticVisitor : Visitor
package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
{
alias visit = Visitor.visit;
@ -550,7 +552,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
(cast(DotIdExp)ds.condition).noderef = true;
// check in syntax level
ds.condition = checkAssignmentAsCondition(ds.condition);
ds.condition = checkAssignmentAsCondition(ds.condition, sc);
ds.condition = ds.condition.expressionSemantic(sc);
ds.condition = resolveProperties(sc, ds.condition);
@ -623,7 +625,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
(cast(DotIdExp)fs.condition).noderef = true;
// check in syntax level
fs.condition = checkAssignmentAsCondition(fs.condition);
fs.condition = checkAssignmentAsCondition(fs.condition, sc);
fs.condition = fs.condition.expressionSemantic(sc);
fs.condition = resolveProperties(sc, fs.condition);
@ -1867,7 +1869,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
*/
// check in syntax level
ifs.condition = checkAssignmentAsCondition(ifs.condition);
ifs.condition = checkAssignmentAsCondition(ifs.condition, sc);
auto sym = new ScopeDsymbol();
sym.parent = sc.scopesym;
@ -3732,44 +3734,61 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
*/
//printf("ThrowStatement::semantic()\n");
if (throwSemantic(ts.loc, ts.exp, sc))
result = ts;
else
setError();
}
/**
* Run semantic on `throw <exp>`.
*
* Params:
* loc = location of the `throw`
* exp = value to be thrown
* sc = enclosing scope
*
* Returns: true if the `throw` is valid, or false if an error was found
*/
extern(D) static bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
{
if (!global.params.useExceptions)
{
ts.error("Cannot use `throw` statements with -betterC");
return setError();
loc.error("Cannot use `throw` statements with -betterC");
return false;
}
if (!ClassDeclaration.throwable)
{
ts.error("Cannot use `throw` statements because `object.Throwable` was not declared");
return setError();
loc.error("Cannot use `throw` statements because `object.Throwable` was not declared");
return false;
}
FuncDeclaration fd = sc.parent.isFuncDeclaration();
fd.hasReturnExp |= 2;
if (FuncDeclaration fd = sc.parent.isFuncDeclaration())
fd.hasReturnExp |= 2;
if (ts.exp.op == EXP.new_)
if (exp.op == EXP.new_)
{
NewExp ne = cast(NewExp)ts.exp;
NewExp ne = cast(NewExp) exp;
ne.thrownew = true;
}
ts.exp = ts.exp.expressionSemantic(sc);
ts.exp = resolveProperties(sc, ts.exp);
ts.exp = checkGC(sc, ts.exp);
if (ts.exp.op == EXP.error)
return setError();
exp = exp.expressionSemantic(sc);
exp = resolveProperties(sc, exp);
exp = checkGC(sc, exp);
if (exp.op == EXP.error)
return false;
checkThrowEscape(sc, ts.exp, false);
checkThrowEscape(sc, exp, false);
ClassDeclaration cd = ts.exp.type.toBasetype().isClassHandle();
ClassDeclaration cd = exp.type.toBasetype().isClassHandle();
if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null)))
{
ts.error("can only throw class objects derived from `Throwable`, not type `%s`", ts.exp.type.toChars());
return setError();
loc.error("can only throw class objects derived from `Throwable`, not type `%s`", exp.type.toChars());
return false;
}
result = ts;
return true;
}
override void visit(DebugStatement ds)

View File

@ -109,18 +109,16 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
e = e.ctfeInterpret();
const opt = e.toBool();
if (opt.hasValue(true))
return true;
else if (opt.hasValue(false))
if (opt.isEmpty())
{
if (negatives)
negatives.push(before);
e.error("expression `%s` is not constant", e.toChars());
errors = true;
return false;
}
e.error("expression `%s` is not constant", e.toChars());
errors = true;
return false;
if (negatives && !opt.get())
negatives.push(before);
return opt.get();
}
return impl(e);
}

View File

@ -61,8 +61,8 @@ extern (C++) struct Target
import dmd.dscope : Scope;
import dmd.expression : Expression;
import dmd.func : FuncDeclaration;
import dmd.globals : LINK, Loc, d_int64;
import dmd.astenums : TY;
import dmd.globals : Loc, d_int64;
import dmd.astenums : LINK, TY;
import dmd.mtype : Type, TypeFunction, TypeTuple;
import dmd.root.ctfloat : real_t;
import dmd.statement : Statement;
@ -119,7 +119,7 @@ extern (C++) struct Target
const(char)[] lib_ext; /// extension for static library files
const(char)[] dll_ext; /// extension for dynamic library files
bool run_noext; /// allow -run sources without extensions
bool mscoff = false; // for Win32: write MsCoff object files instead of OMF
bool omfobj = false; // for Win32: write OMF object files instead of MsCoff
/**
* Values representing all properties for floating point types
*/
@ -293,6 +293,13 @@ extern (C++) struct Target
* `false` if the target backend handles synchronizing monitors.
*/
extern (C++) bool libraryObjectMonitors(FuncDeclaration fd, Statement fbody);
/**
* Returns true if the target supports `pragma(linkerDirective)`.
* Returns:
* `false` if the target does not support `pragma(linkerDirective)`.
*/
extern (C++) bool supportsLinkerDirective() const;
}
////////////////////////////////////////////////////////////////////////////////
@ -340,7 +347,7 @@ struct TargetCPP
import dmd.dsymbol : Dsymbol;
import dmd.dclass : ClassDeclaration;
import dmd.func : FuncDeclaration;
import dmd.mtype : Parameter, Type;
import dmd.mtype : Type;
enum Runtime : ubyte
{
@ -354,6 +361,7 @@ struct TargetCPP
bool reverseOverloads; /// set if overloaded functions are grouped and in reverse order (such as in dmc and cl)
bool exceptions; /// set if catching C++ exceptions is supported
bool twoDtorInVtable; /// target C++ ABI puts deleting and non-deleting destructor into vtable
bool splitVBasetable; /// set if C++ ABI uses separate tables for virtual functions and virtual bases
bool wrapDtorInExternD; /// set if C++ dtors require a D wrapper to be callable from runtime
Runtime runtime; /// vendor of the C++ runtime to link against
@ -398,13 +406,13 @@ struct TargetCPP
/**
* Get the type that will really be used for passing the given argument
* to an `extern(C++)` function.
* to an `extern(C++)` function, or `null` if unhandled.
* Params:
* p = parameter to be passed.
* t = type to be passed.
* Returns:
* `Type` to use for parameter `p`.
* `Type` to use for type `t`.
*/
extern (C++) Type parameterType(Parameter p);
extern (C++) Type parameterType(Type t);
/**
* Checks whether type is a vendor-specific fundamental type.

View File

@ -20,7 +20,6 @@ class ClassDeclaration;
class Dsymbol;
class Expression;
class FuncDeclaration;
class Parameter;
class Statement;
class Type;
class TypeTuple;
@ -92,6 +91,7 @@ struct TargetCPP
bool reverseOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order
bool exceptions; // set if catching C++ exceptions is supported
bool twoDtorInVtable; // target C++ ABI puts deleting and non-deleting destructor into vtable
bool splitVBasetable; // set if C++ ABI uses separate tables for virtual functions and virtual bases
bool wrapDtorInExternD; // set if C++ dtors require a D wrapper to be callable from runtime
Runtime runtime;
@ -99,7 +99,7 @@ struct TargetCPP
const char *typeInfoMangle(ClassDeclaration *cd);
const char *thunkMangle(FuncDeclaration *fd, int offset);
const char *typeMangle(Type *t);
Type *parameterType(Parameter *p);
Type *parameterType(Type *p);
bool fundamentalType(const Type *t, bool& isFundamental);
unsigned derivedClassOffset(ClassDeclaration *baseClass);
};
@ -160,7 +160,7 @@ struct Target
DString lib_ext; /// extension for static library files
DString dll_ext; /// extension for dynamic library files
bool run_noext; /// allow -run sources without extensions
bool mscoff; /// for Win32: write COFF object files instead of OMF
bool omfobj; /// for Win32: write OMF object files instead of COFF
template <typename T>
struct FPTypeProperties
@ -205,6 +205,7 @@ public:
Expression *getTargetInfo(const char* name, const Loc& loc);
bool isCalleeDestroyingArgs(TypeFunction* tf);
bool libraryObjectMonitors(FuncDeclaration *fd, Statement *fbody);
bool supportsLinkerDirective() const;
void addPredefinedGlobalIdentifiers() const;
};

View File

@ -284,6 +284,7 @@ public:
Identifier *getIdent();
hash_t toHash();
bool isDiscardable();
bool needsCodegen();
TemplateInstance *isTemplateInstance() { return this; }

View File

@ -278,6 +278,7 @@ enum TOK : ubyte
_Thread_local,
// C only extended keywords
_import,
__cdecl,
__declspec,
__attribute__,
@ -585,6 +586,7 @@ private immutable TOK[] keywords =
TOK._Thread_local,
// C only extended keywords
TOK._import,
TOK.__cdecl,
TOK.__declspec,
TOK.__attribute__,
@ -615,7 +617,7 @@ static immutable TOK[TOK.max + 1] Ckeywords =
restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_,
union_, unsigned, void_, volatile, while_, asm_,
_Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
_Static_assert, _Thread_local, __cdecl, __declspec, __attribute__ ];
_Static_assert, _Thread_local, _import, __cdecl, __declspec, __attribute__ ];
foreach (kw; Ckwds)
tab[kw] = cast(TOK) kw;
@ -891,6 +893,7 @@ extern (C++) struct Token
TOK._Thread_local : "_Thread_local",
// C only extended keywords
TOK._import : "__import",
TOK.__cdecl : "__cdecl",
TOK.__declspec : "__declspec",
TOK.__attribute__ : "__attribute__",

View File

@ -287,6 +287,7 @@ enum class TOK : unsigned char
_Thread_local_,
// C only extended keywords
_import,
cdecl,
declspec,
attribute__,

View File

@ -150,6 +150,7 @@ shared static this()
"hasPostblit",
"hasCopyConstructor",
"isCopyable",
"parameters"
];
StringTable!(bool)* stringTable = cast(StringTable!(bool)*) &traitsStringTable;
@ -998,7 +999,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
e.error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b.toChars(), b.type.toChars());
return ErrorExp.get();
}
includeTemplates = b.toBool().hasValue(true);
includeTemplates = b.toBool().get();
}
StringExp se = ex.toStringExp();
@ -2090,7 +2091,43 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
auto tup = new TupleExp(e.loc, exps);
return tup.expressionSemantic(sc);
}
//https://issues.dlang.org/show_bug.cgi?id=22291
if (e.ident == Id.parameters)
{
//No args are valid
if (e.args)
{
char[] contents = cast(char[]) e.args.toString();
contents = contents[1..$];
contents[$-1] = '\0';
e.error("`__traits(parameters)` cannot have arguments, but `%s` was supplied", contents.ptr);
return ErrorExp.get();
}
if (sc.func is null)
{
e.error("`__traits(parameters)` may only be used inside a function");
return ErrorExp.get();
}
assert(sc.func && sc.parent.isFuncDeclaration());
auto tf = sc.parent.isFuncDeclaration.type.isTypeFunction();
assert(tf);
auto exps = new Expressions(0);
int addParameterDG(size_t idx, Parameter x)
{
assert(x.ident);
exps.push(new IdentifierExp(e.loc, x.ident));
return 0;
}
/*
This is required since not all "parameters" actually have a name
until they (tuples) are expanded e.g. an anonymous tuple parameter's
contents get given names but not the tuple itself.
*/
Parameter._foreach(tf.parameterList.parameters, &addParameterDG);
auto tup = new TupleExp(e.loc, exps);
return tup.expressionSemantic(sc);
}
static const(char)[] trait_search_fp(const(char)[] seed, out int cost)
{
//printf("trait_search_fp('%s')\n", seed);

View File

@ -1141,6 +1141,12 @@ package mixin template ParseVisitMethods(AST)
}
}
override void visit(AST.ThrowExp e)
{
//printf("Visiting ThrowExp\n");
e.e1.accept(this);
}
// Template Parameter
//===========================================================

View File

@ -2062,7 +2062,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
switch (mtype.tok)
{
case TOK.enum_:
auto ed = new EnumDeclaration(mtype.loc, mtype.id, Type.tint32);
auto ed = new EnumDeclaration(mtype.loc, mtype.id, mtype.base);
declare(ed);
mtype.resolved = visitEnum(new TypeEnum(ed));
break;
@ -3940,7 +3940,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
e = new TupleExp(e.loc, e0, exps);
Scope* sc2 = sc.push();
sc2.flags |= global.params.useDIP1000 == FeatureState.enabled ? SCOPE.onlysafeaccess : SCOPE.noaccesscheck;
sc2.flags |= SCOPE.noaccesscheck;
e = e.expressionSemantic(sc2);
sc2.pop();
return e;
@ -4201,7 +4201,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
e = new TupleExp(e.loc, e0, exps);
Scope* sc2 = sc.push();
sc2.flags |= global.params.useDIP1000 == FeatureState.enabled ? SCOPE.onlysafeaccess : SCOPE.noaccesscheck;
sc2.flags |= SCOPE.noaccesscheck;
e = e.expressionSemantic(sc2);
sc2.pop();
return e;

View File

@ -220,6 +220,7 @@ class BinAssignExp;
class MixinExp;
class ImportExp;
class AssertExp;
class ThrowExp;
class DotIdExp;
class DotTemplateExp;
class DotVarExp;
@ -511,6 +512,7 @@ public:
virtual void visit(CallExp *e) { visit((UnaExp *)e); }
virtual void visit(DotIdExp *e) { visit((UnaExp *)e); }
virtual void visit(AssertExp *e) { visit((UnaExp *)e); }
virtual void visit(ThrowExp *e) { visit((UnaExp *)e); }
virtual void visit(ImportExp *e) { visit((UnaExp *)e); }
virtual void visit(DotTemplateInstanceExp *e) { visit((UnaExp *)e); }
virtual void visit(ArrayExp *e) { visit((UnaExp *)e); }

View File

@ -1186,6 +1186,14 @@ public:
this->result_ = build_assign (modifycode, t1, t2);
}
/* Build a throw expression. */
void visit (ThrowExp *e)
{
tree arg = build_expr_dtor (e->e1);
this->result_ = build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg);
}
/* Build a postfix expression. */
void visit (PostExp *e)

View File

@ -274,6 +274,72 @@ insert_aggregate_field (tree type, tree field, size_t offset)
TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), field);
}
/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP. */
static tree
d_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp)
{
/* Same as d_type_for_size, but uses exact match for size. */
if (width == TYPE_PRECISION (d_byte_type))
return unsignedp ? d_ubyte_type : d_byte_type;
if (width == TYPE_PRECISION (d_short_type))
return unsignedp ? d_ushort_type : d_short_type;
if (width == TYPE_PRECISION (d_int_type))
return unsignedp ? d_uint_type : d_int_type;
if (width == TYPE_PRECISION (d_long_type))
return unsignedp ? d_ulong_type : d_long_type;
if (width == TYPE_PRECISION (d_cent_type))
return unsignedp ? d_ucent_type : d_cent_type;
for (int i = 0; i < NUM_INT_N_ENTS; i ++)
{
if (int_n_enabled_p[i] && width == int_n_data[i].bitsize)
{
if (unsignedp)
return int_n_trees[i].unsigned_type;
else
return int_n_trees[i].signed_type;
}
}
return build_nonstandard_integer_type (width, unsignedp);
}
/* Adds BITFIELD into the aggregate TYPE at OFFSET+BITOFFSET. */
static void
insert_aggregate_bitfield (tree type, tree bitfield, size_t width,
size_t offset, size_t bitoffset)
{
DECL_FIELD_CONTEXT (bitfield) = type;
SET_DECL_OFFSET_ALIGN (bitfield, TYPE_ALIGN (TREE_TYPE (bitfield)));
DECL_SIZE (bitfield) = bitsize_int (width);
DECL_FIELD_OFFSET (bitfield) = size_int (offset);
DECL_FIELD_BIT_OFFSET (bitfield) = bitsize_int (bitoffset);
TREE_ADDRESSABLE (bitfield) = TYPE_SHARED (TREE_TYPE (bitfield));
DECL_BIT_FIELD (bitfield) = 1;
DECL_BIT_FIELD_TYPE (bitfield) = TREE_TYPE (bitfield);
layout_decl (bitfield, 0);
/* Give bit-field its proper type after layout_decl. */
tree orig_type = DECL_BIT_FIELD_TYPE (bitfield);
if (width != TYPE_PRECISION (orig_type))
{
TREE_TYPE (bitfield)
= d_build_bitfield_integer_type (width, TYPE_UNSIGNED (orig_type));
SET_DECL_MODE (bitfield, TYPE_MODE (TREE_TYPE (bitfield)));
}
TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), bitfield);
}
/* For all decls in the FIELDS chain, adjust their field offset by OFFSET.
This is done as the frontend puts fields into the outer struct, and so
their offset is from the beginning of the aggregate.
@ -356,7 +422,16 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
tree field = create_field_decl (declaration_type (var), ident,
inherited_p, inherited_p);
apply_user_attributes (var, field);
insert_aggregate_field (context, field, var->offset);
if (BitFieldDeclaration *bf = var->isBitFieldDeclaration ())
{
/* Bit-fields come from an ImportC context, and require the
field be correctly adjusted. */
insert_aggregate_bitfield (context, field, bf->fieldWidth,
bf->offset, bf->bitOffset);
}
else
insert_aggregate_field (context, field, var->offset);
/* Because the front-end shares field decls across classes, don't
create the corresponding back-end symbol unless we are adding

View File

@ -0,0 +1,31 @@
alias tuple(T...) = T;
void exactMatch()
{
tuple!int tup_1;
auto i = cast() tup_1;
static assert(is(typeof(i) == int));
const i_const = cast(const) tup_1;
static assert(is(typeof(i_const) == const int));
auto totup_1 = cast(tuple!int) tup_1;
static assert(is(typeof(totup_1) == tuple!int));
tuple!(int, int) tup_2;
auto totup_2 = cast(tuple!(int, int)) tup_2;
static assert(is(typeof(totup_2) == tuple!(int, int)));
}
void implicitConv()
{
tuple!short tup_1;
auto totup_1 = cast(tuple!int) tup_1;
static assert(is(typeof(tup_1) == tuple!short));
static assert(is(typeof(totup_1) == tuple!int));
tuple!(short, short) tup_2;
auto totup_2 = cast(tuple!(int, int)) tup_2;
static assert(is(typeof(tup_2) == tuple!(short, short)));
static assert(is(typeof(totup_2) == tuple!(int, int)));
}

View File

@ -0,0 +1,97 @@
// https://issues.dlang.org/show_bug.cgi?id=22668
// Overrides with same deprecated'ness are allowed
class SameParent
{
deprecated void foo() {}
void foo(int) {}
void bar(int) {}
deprecated void bar() {}
}
class SameChild : SameParent
{
deprecated override void foo() {}
override void foo(int) {}
override void bar(int) {}
deprecated override void bar() {}
}
/**
Only the parent declaration is deprecated
TEST_OUTPUT:
----
compilable/deprecated_override.d(44): Deprecation: `deprecated_override.IntroducingChild.foo` is overriding the deprecated method `deprecated_override.IntroducingParent.foo`
compilable/deprecated_override.d(48): Deprecation: `deprecated_override.IntroducingChild.bar` is overriding the deprecated method `deprecated_override.IntroducingParent.bar`
----
**/
class IntroducingParent
{
deprecated void foo() {}
void foo(int) {}
void bar(int) {}
deprecated void bar() {}
}
class IntroducingChild : IntroducingParent
{
override void foo() {}
override void foo(int) {}
override void bar(int) {}
override void bar() {}
}
// Unrelated to this path but should this error as well?
class IntroducingGrandchild : IntroducingChild
{
override void foo() {}
override void foo(int) {}
override void bar(int) {}
override void bar() {}
}
/**
Only the overriding declaration is deprecated
TEST_OUTPUT:
----
compilable/deprecated_override.d(83): Deprecation: `deprecated_override.OverrideChild.foo` cannot be marked as `deprecated` because it is overriding a function in the base class
compilable/deprecated_override.d(87): Deprecation: `deprecated_override.OverrideChild.bar` cannot be marked as `deprecated` because it is overriding a function in the base class
----
**/
class OverrideParent
{
void foo() {}
void foo(int) {}
void bar(int) {}
void bar() {}
}
class OverrideChild : OverrideParent
{
deprecated override void foo() {}
override void foo(int) {}
override void bar(int) {}
deprecated override void bar() {}
}
class OverrideGrandChild : OverrideChild
{
deprecated override void foo() {}
override void foo(int) {}
override void bar(int) {}
deprecated override void bar() {}
}

View File

@ -600,3 +600,9 @@ struct Test14UDA4(string v){}
void test14x(@Test14UDA1 int, @Test14UDA2("1") int, @test14uda3("2") int, @Test14UDA4!"3" int) {}
void test15x(@(20) void delegate(int) @safe dg){}
T throwStuff(T)(T t)
{
if (false) test13x(1, throw new Exception(""), 2);
return t ? t : throw new Exception("Bad stuff happens!");
}

View File

@ -0,0 +1,16 @@
// https://issues.dlang.org/show_bug.cgi?id=17635
alias T = immutable int;
T** f(const T** input) pure
{
T** output;
return output;
}
void main()
{
T i;
T* p = &i;
immutable T** r = f(&p);
}

View File

@ -0,0 +1,134 @@
//https://issues.dlang.org/show_bug.cgi?id=22291
alias AliasSeq(T...) = T;
void noParameters()
{
static assert(typeof(__traits(parameters)).length == 0);
}
void noArgs()
{
//Arguments are not valid, this should not compile
static assert(!__traits(compiles, __traits(parameters, 456)));
}
shared static this()
{
static assert(typeof(__traits(parameters)).length == 0);
}
int echoPlusOne(int x)
{
__traits(parameters)[0] += 1;
return x;
}
static assert(echoPlusOne(1) == 2);
class Tree {
int opApply(int delegate(size_t, Tree) dg) {
if (dg(0, this)) return 1;
return 0;
}
}
void useOpApply(Tree top, int x)
{
foreach(idx; 0..5)
{
static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
}
foreach(idx, elem; top)
{
static assert(is(typeof(__traits(parameters)) == AliasSeq!(size_t, Tree)));
}
}
class Test
{
static assert(!__traits(compiles, __traits(parameters)));
void handle(int x)
{
static assert(typeof(__traits(parameters)).length == 1);
}
}
int add(int x, int y)
{
return x + y;
}
auto forwardToAdd(int x, int y)
{
return add(__traits(parameters));
}
static assert(forwardToAdd(2, 3) == 5);
struct TestConstructor
{
int x;
string y;
//This parameter will not have a name but it's (tuple) members
//will
this(typeof(this.tupleof))
{
this.tupleof = __traits(parameters);
}
}
bool test(int x, string y)
{
auto s = TestConstructor(2, "pi");
return s.x == x && s.y == y;
}
static assert(test(2, "pi"));
int testNested(int x)
{
static assert(typeof(__traits(parameters)).length == 1);
int add(int x, int y)
{
static assert(typeof(__traits(parameters)).length == 2);
return x + y;
}
return add(x + 2, x + 3);
}
void testPack(Pack...)(Pack x)
{
static assert(is(typeof(__traits(parameters)) == typeof(AliasSeq!(x))));
}
ref int forwardTest(return ref int x)
{
static assert(__traits(isRef, x) == __traits(isRef, __traits(parameters)[0]));
return x;
}
int testRefness(int x, ref int monkey)
{
{
//monkey = x;
__traits(parameters)[1] = __traits(parameters)[0];
}
return x;
}
int refTest()
{
int x;
testRefness(45, x);
return x;
}
auto packLength(Pack...)(Pack x)
{
return typeof(__traits(parameters)).length;
}
static assert(packLength(2, 3) == 2);
alias lambda = (x) => typeof(__traits(parameters)).stringof;
static assert(lambda(1) == "(int)");
static assert(refTest() == 45);
T testTemplate(T)(scope T input)
{
void chimpInASuit(float set)
{
static assert(is(typeof(__traits(parameters)) == AliasSeq!(float)));
}
{
__traits(parameters) = AliasSeq!(T.max);
}
__traits(parameters) = AliasSeq!(T.init);
return input;
}
static assert(testTemplate!long(420) == 0);

View File

@ -0,0 +1,6 @@
// check bugs in importing C files
int squared(int a)
{
return a * a;
}

View File

@ -0,0 +1 @@
typedef struct S { int x; } T;

View File

@ -0,0 +1 @@
enum E { A };

View File

@ -0,0 +1,5 @@
module imports.test22685b;
import imports.test22685c : overloaded;
void overloaded()() { }

View File

@ -0,0 +1,3 @@
module imports.test22685c;
void overloaded()() { }

View File

@ -0,0 +1,12 @@
// https://issues.dlang.org/show_bug.cgi?id=22130
int* f(const int* input) pure nothrow @safe
{
int* output;
return output;
}
void main() pure nothrow @safe
{
int* c = new int;
immutable int* i = f(c);
}

View File

@ -20,8 +20,7 @@ static assert(!is(noreturn == void));
static assert(is( typeof(assert(0)) == noreturn ));
// Does not parse yet
// static assert(is( typeof(throw new Exception()) == noreturn ));
static assert(is( typeof(throw new Exception("")) == noreturn ));
static assert(is(noreturn == noreturn));
static assert(!is(noreturn == const noreturn));

View File

@ -1,10 +1,6 @@
// REQUIRED_ARGS: -o-
// PERMUTE_ARGS: -d -de -dw
/*
TEST_OUTPUT*
---
---
*/
deprecated class Dep { }
deprecated Dep depFunc1(); // error
deprecated void depFunc2(Dep); // error

View File

@ -1,4 +1,4 @@
// REQUIRED_ARGS : -c
// REQUIRED_ARGS: -c
// EXTRA_FILES: imports/test18771a.d imports/test18771b.d imports/test18771c.d imports/test18771d.d
// https://issues.dlang.org/show_bug.cgi?id=18771

View File

@ -1,7 +1,7 @@
// https://issues.dlang.org/show_bug.cgi?id=19609
// EXTRA_FILES: imports/test19609a.d imports/test19609b.d imports/test19609c.d
/*
TEST_OUTPUT
TEST_OUTPUT:
---
compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated -
compilable/test19609.d(12): Deprecation: module `imports.test19609b` is deprecated - hello

View File

@ -1,4 +1,4 @@
// PERMUTE_ARGS -preview=dip1000
// PERMUTE_ARGS: -preview=dip1000
// https://issues.dlang.org/show_bug.cgi?id=19873
int* ed(scope int* x)
{

View File

@ -1,4 +1,4 @@
// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/func.d imports/test21299/rootstringtable.d
// REQUIRED_ARGS: -main
// LINK
// LINK:
module test21299a;

View File

@ -0,0 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=22619
struct W1 {
int x;
this(ref inout W1 rhs) inout { this.x = rhs.x; }
}
inout(W1) f(inout W1 x) { return x; }
void g(W1 x) {
auto r = f(x);
}

View File

@ -0,0 +1,4 @@
// https://issues.dlang.org/show_bug.cgi?id=22625
// EXTRA_FILES: imports/imp22625.c
import imports.imp22625 : S, T;

View File

@ -0,0 +1,21 @@
// https://issues.dlang.org/show_bug.cgi?id=22646
/*
TEST_OUTPUT:
---
true
true
false
false
---
*/
static template Bug(string name)
{
enum bool ok = name.length < 3 || name[0..3] != "pad";
}
pragma(msg, Bug!"x".ok);
pragma(msg, Bug!"foo".ok);
pragma(msg, Bug!"pad".ok);
pragma(msg, Bug!"pad123".ok);

View File

@ -0,0 +1,22 @@
// EXTRA_FILES: imports/imp22665.c
// https://issues.dlang.org/show_bug.cgi?id=22665
import imports.imp22665;
E foo1(E e)
{
return e.A; // with qualification, it is an enum
}
int foo2()
{
return A; // without qualification, it is an int
}
E foo3(E e)
{
return E.A; // with qualification, it is an enum
}

View File

@ -0,0 +1,25 @@
// https://issues.dlang.org/show_bug.cgi?id=22676
template fullyQualifiedName(T)
{
static if (is(T : real))
enum fullyQualifiedName;
enum fullyQualifiedName = null;
}
static auto _inst()
{
return fullyQualifiedName!(frop);
}
alias attr = __traits(getAttributes, _inst);
class frop
{
alias type_id = registry!frop;
}
template registry(T)
{
enum string FOO = fullyQualifiedName!T;
}

View File

@ -0,0 +1,11 @@
// EXTRA_FILES: imports/test22685b.d imports/test22685c.d
module test22685;
import imports.test22685b;
void twoArgs(alias a, alias b)() { }
void main() {
twoArgs!(a => 1, overloaded);
}

View File

@ -1,4 +1,4 @@
// COMPILE_SEPARATELY
// COMPILE_SEPARATELY:
// COMPILED_IMPORTS: imports/test55a.d
// PERMUTE_ARGS: -dw
// REQUIRED_ARGS: -d
@ -17,4 +17,3 @@ class Queue2 {
alias int ListHead;
Arm2 a;
}

View File

@ -0,0 +1,4 @@
// EXTRA_FILES: imports/cstuff3.c
import imports.cstuff3;
static assert(squared(4) == 16);

View File

@ -0,0 +1,7 @@
/* PERMUTE_ARGS: -os=host -os=linux -os=osx -os=freebsd -os=solaris
* DISABLED: win32 win64
*/
void test()
{
}

View File

@ -1,9 +1,8 @@
/*
* REQUIRED_ARGS: -c
* TEST_OUTPUT:
---
compilable/b16967.d(16): Deprecation: switch case fallthrough - use 'goto default;' if intended
compilable/b16967.d(26): Deprecation: switch case fallthrough - use 'goto default;' if intended
fail_compilation/b16967.d(15): Error: switch case fallthrough - use 'goto default;' if intended
fail_compilation/b16967.d(25): Error: switch case fallthrough - use 'goto default;' if intended
---
*/
int foo(int x)

View File

@ -0,0 +1,14 @@
/*
TEST_OUTPUT:
---
fail_compilation/bug5096.d(13): Error: unmatched closing brace
---
*/
void foo(int x)
in {
assert(x > 0);
} do {
x++;
}
}
void main() {}

View File

@ -91,9 +91,9 @@ TEST_OUTPUT:
---
fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S _param_0)` is not callable using argument types `(S)`
fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S _param_0`
fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` cannot deduce function from argument types `!()(S)`
fail_compilation/bug9631.d(107): Error: none of the overloads of template `bug9631.targ.ft` are callable using argument types `!()(S)`
fail_compilation/bug9631.d(105): Candidate is: `ft()(tem!().S)`
fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` cannot deduce function from argument types `!()(S, int)`
fail_compilation/bug9631.d(109): Error: none of the overloads of template `bug9631.targ.ft2` are callable using argument types `!()(S, int)`
fail_compilation/bug9631.d(108): Candidate is: `ft2(T)(S, T)`
---
*/

View File

@ -0,0 +1,25 @@
/*
TEST_OUTPUT:
---
fail_compilation/casttuple.d(104): Error: cannot cast `__tup1_field_0` of type `int` to tuple type `(string)`
fail_compilation/casttuple.d(107): Error: cannot cast `tuple(__tup2_field_0, __tup2_field_1)` of type `(int, int)` to tuple type `(string, string)`
fail_compilation/casttuple.d(111): Error: cannot cast `tuple(foo, 123)` of type `(int, int)` to tuple type `(string, string)`
---
*/
alias tuple(T...) = T;
#line 100
void nomatch()
{
tuple!int tup1;
auto x = cast(tuple!string) tup1;
tuple!(int, int) tup2;
auto y = cast(tuple!(string, string)) tup2;
int foo;
alias tup3 = tuple!(foo, 123);
auto z = cast(tuple!(string, string)) tup3;
}

View File

@ -2,12 +2,12 @@
EXTRA_FILES: imports/constraints.d
TEST_OUTPUT:
---
fail_compilation/constraints_aggr.d(32): Error: template `imports.constraints.C.f` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_aggr.d(32): Error: none of the overloads of template `imports.constraints.C.f` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(60): Candidate is: `f(T)(T v)`
with `T = int`
must satisfy the following constraint:
` !P!T`
fail_compilation/constraints_aggr.d(33): Error: template `imports.constraints.C.g` cannot deduce function from argument types `!()()`
fail_compilation/constraints_aggr.d(33): Error: none of the overloads of template `imports.constraints.C.g` are callable using argument types `!()()`
fail_compilation/imports/constraints.d(63): Candidate is: `g(this T)()`
with `T = imports.constraints.C`
must satisfy the following constraint:

View File

@ -2,72 +2,72 @@
EXTRA_FILES: imports/constraints.d
TEST_OUTPUT:
---
fail_compilation/constraints_func1.d(79): Error: template `imports.constraints.test1` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(79): Error: none of the overloads of template `imports.constraints.test1` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)`
with `T = int`
must satisfy the following constraint:
` N!T`
fail_compilation/constraints_func1.d(80): Error: template `imports.constraints.test2` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(80): Error: none of the overloads of template `imports.constraints.test2` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(10): Candidate is: `test2(T)(T v)`
with `T = int`
must satisfy the following constraint:
` !P!T`
fail_compilation/constraints_func1.d(81): Error: template `imports.constraints.test3` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(81): Error: none of the overloads of template `imports.constraints.test3` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(11): Candidate is: `test3(T)(T v)`
with `T = int`
must satisfy the following constraint:
` N!T`
fail_compilation/constraints_func1.d(82): Error: template `imports.constraints.test4` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(82): Error: none of the overloads of template `imports.constraints.test4` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(12): Candidate is: `test4(T)(T v)`
with `T = int`
must satisfy the following constraint:
` N!T`
fail_compilation/constraints_func1.d(83): Error: template `imports.constraints.test5` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(83): Error: none of the overloads of template `imports.constraints.test5` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(13): Candidate is: `test5(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
N!T`
fail_compilation/constraints_func1.d(84): Error: template `imports.constraints.test6` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(84): Error: none of the overloads of template `imports.constraints.test6` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(14): Candidate is: `test6(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
N!T
!P!T`
fail_compilation/constraints_func1.d(85): Error: template `imports.constraints.test7` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(85): Error: none of the overloads of template `imports.constraints.test7` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(15): Candidate is: `test7(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
N!T`
fail_compilation/constraints_func1.d(86): Error: template `imports.constraints.test8` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(86): Error: none of the overloads of template `imports.constraints.test8` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(16): Candidate is: `test8(T)(T v)`
with `T = int`
must satisfy the following constraint:
` N!T`
fail_compilation/constraints_func1.d(87): Error: template `imports.constraints.test9` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(87): Error: none of the overloads of template `imports.constraints.test9` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(17): Candidate is: `test9(T)(T v)`
with `T = int`
must satisfy the following constraint:
` !P!T`
fail_compilation/constraints_func1.d(88): Error: template `imports.constraints.test10` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(88): Error: none of the overloads of template `imports.constraints.test10` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(18): Candidate is: `test10(T)(T v)`
with `T = int`
must satisfy the following constraint:
` !P!T`
fail_compilation/constraints_func1.d(89): Error: template `imports.constraints.test11` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(89): Error: none of the overloads of template `imports.constraints.test11` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(19): Candidate is: `test11(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
!P!T`
fail_compilation/constraints_func1.d(90): Error: template `imports.constraints.test12` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func1.d(90): Error: none of the overloads of template `imports.constraints.test12` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(20): Candidate is: `test12(T)(T v)`
with `T = int`
must satisfy the following constraint:
` !P!T`
fail_compilation/constraints_func1.d(92): Error: template `imports.constraints.test1` cannot deduce function from argument types `!()(int, int)`
fail_compilation/constraints_func1.d(92): Error: none of the overloads of template `imports.constraints.test1` are callable using argument types `!()(int, int)`
fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)`
---
*/

View File

@ -2,83 +2,83 @@
EXTRA_FILES: imports/constraints.d
TEST_OUTPUT:
---
fail_compilation/constraints_func2.d(94): Error: template `imports.constraints.test13` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(94): Error: none of the overloads of template `imports.constraints.test13` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(23): Candidate is: `test13(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
!P!T`
fail_compilation/constraints_func2.d(95): Error: template `imports.constraints.test14` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(95): Error: none of the overloads of template `imports.constraints.test14` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(24): Candidate is: `test14(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` !P!T
N!T`
fail_compilation/constraints_func2.d(96): Error: template `imports.constraints.test15` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(96): Error: none of the overloads of template `imports.constraints.test15` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(25): Candidate is: `test15(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` !P!T
!P!T`
fail_compilation/constraints_func2.d(97): Error: template `imports.constraints.test16` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(97): Error: none of the overloads of template `imports.constraints.test16` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(26): Candidate is: `test16(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
N!T`
fail_compilation/constraints_func2.d(98): Error: template `imports.constraints.test17` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(98): Error: none of the overloads of template `imports.constraints.test17` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(27): Candidate is: `test17(T)(T v)`
with `T = int`
must satisfy the following constraint:
` N!T`
fail_compilation/constraints_func2.d(99): Error: template `imports.constraints.test18` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(99): Error: none of the overloads of template `imports.constraints.test18` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(28): Candidate is: `test18(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
N!T`
fail_compilation/constraints_func2.d(100): Error: template `imports.constraints.test19` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(100): Error: none of the overloads of template `imports.constraints.test19` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(29): Candidate is: `test19(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
!P!T
N!T`
fail_compilation/constraints_func2.d(101): Error: template `imports.constraints.test20` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(101): Error: none of the overloads of template `imports.constraints.test20` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(30): Candidate is: `test20(T)(T v)`
with `T = int`
must satisfy the following constraint:
` N!T`
fail_compilation/constraints_func2.d(102): Error: template `imports.constraints.test21` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(102): Error: none of the overloads of template `imports.constraints.test21` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(31): Candidate is: `test21(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` N!T
N!T`
fail_compilation/constraints_func2.d(103): Error: template `imports.constraints.test22` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(103): Error: none of the overloads of template `imports.constraints.test22` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(32): Candidate is: `test22(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` !P!T
!P!T`
fail_compilation/constraints_func2.d(104): Error: template `imports.constraints.test23` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(104): Error: none of the overloads of template `imports.constraints.test23` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(33): Candidate is: `test23(T)(T v)`
with `T = int`
must satisfy one of the following constraints:
` !P!T
N!T
!P!T`
fail_compilation/constraints_func2.d(105): Error: template `imports.constraints.test24` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(105): Error: none of the overloads of template `imports.constraints.test24` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(34): Candidate is: `test24(R)(R r)`
with `R = int`
must satisfy the following constraint:
` __traits(hasMember, R, "stuff")`
fail_compilation/constraints_func2.d(106): Error: template `imports.constraints.test25` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func2.d(106): Error: none of the overloads of template `imports.constraints.test25` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(35): Candidate is: `test25(T)(T v)`
with `T = int`
must satisfy the following constraint:
` N!T`
fail_compilation/constraints_func2.d(107): Error: template `imports.constraints.test26` cannot deduce function from argument types `!(float)(int)`
fail_compilation/constraints_func2.d(107): Error: none of the overloads of template `imports.constraints.test26` are callable using argument types `!(float)(int)`
fail_compilation/imports/constraints.d(36): Candidate is: `test26(T, U)(U u)`
with `T = float,
U = int`

View File

@ -2,7 +2,7 @@
EXTRA_FILES: imports/constraints.d
TEST_OUTPUT:
---
fail_compilation/constraints_func3.d(53): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func3.d(53): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)`
with `T = int`
must satisfy the following constraint:
@ -13,7 +13,7 @@ fail_compilation/imports/constraints.d(40): `overload(T)(
` !P!T`
fail_compilation/imports/constraints.d(41): `overload(T)(T v1, T v2)`
fail_compilation/imports/constraints.d(42): `overload(T, V)(T v1, V v2)`
fail_compilation/constraints_func3.d(54): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int, string)`
fail_compilation/constraints_func3.d(54): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int, string)`
fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)`
fail_compilation/imports/constraints.d(40): `overload(T)(T v)`
fail_compilation/imports/constraints.d(41): `overload(T)(T v1, T v2)`
@ -23,21 +23,21 @@ fail_compilation/imports/constraints.d(42): `overload(T,
must satisfy one of the following constraints:
` N!T
N!V`
fail_compilation/constraints_func3.d(56): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()()`
fail_compilation/constraints_func3.d(56): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()()`
fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
fail_compilation/constraints_func3.d(57): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func3.d(57): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int)`
fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
with `A = int,
T = ()`
must satisfy the following constraint:
` N!int`
fail_compilation/constraints_func3.d(58): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int)`
fail_compilation/constraints_func3.d(58): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int, int)`
fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
with `A = int,
T = (int)`
must satisfy the following constraint:
` N!int`
fail_compilation/constraints_func3.d(59): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int, int)`
fail_compilation/constraints_func3.d(59): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int, int, int)`
fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
with `A = int,
T = (int, int)`

View File

@ -3,7 +3,7 @@ EXTRA_FILES: imports/constraints.d
REQUIRED_ARGS: -verrors=context
TEST_OUTPUT:
---
fail_compilation/constraints_func4.d(90): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func4.d(90): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int)`
overload(0);
^
fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)`
@ -24,7 +24,7 @@ void overload(T)(T v1, T v2) if (N!T);
fail_compilation/imports/constraints.d(42): `overload(T, V)(T v1, V v2)`
void overload(T, V)(T v1, V v2) if (N!T || N!V);
^
fail_compilation/constraints_func4.d(91): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int, string)`
fail_compilation/constraints_func4.d(91): Error: none of the overloads of template `imports.constraints.overload` are callable using argument types `!()(int, string)`
overload(0, "");
^
fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)`
@ -44,13 +44,13 @@ fail_compilation/imports/constraints.d(42): `overload(T,
N!V`
void overload(T, V)(T v1, V v2) if (N!T || N!V);
^
fail_compilation/constraints_func4.d(93): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()()`
fail_compilation/constraints_func4.d(93): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()()`
variadic();
^
fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
void variadic(A, T...)(A a, T v) if (N!int);
^
fail_compilation/constraints_func4.d(94): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int)`
fail_compilation/constraints_func4.d(94): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int)`
variadic(0);
^
fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
@ -60,7 +60,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T.
` N!int`
void variadic(A, T...)(A a, T v) if (N!int);
^
fail_compilation/constraints_func4.d(95): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int)`
fail_compilation/constraints_func4.d(95): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int, int)`
variadic(0, 1);
^
fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
@ -70,7 +70,7 @@ fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T.
` N!int`
void variadic(A, T...)(A a, T v) if (N!int);
^
fail_compilation/constraints_func4.d(96): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int, int)`
fail_compilation/constraints_func4.d(96): Error: none of the overloads of template `imports.constraints.variadic` are callable using argument types `!()(int, int, int)`
variadic(0, 1, 2);
^
fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`

View File

@ -1,25 +1,24 @@
/*
TEST_OUTPUT:
---
fail_compilation/diag11819b.d(28): Error: unrecognized trait `HasMember`, did you mean `hasMember`?
fail_compilation/diag11819b.d(29): Error: unrecognized trait `Identifier`, did you mean `identifier`?
fail_compilation/diag11819b.d(30): Error: unrecognized trait `GetProtection`, did you mean `getProtection`?
fail_compilation/diag11819b.d(31): Error: unrecognized trait `Parent`, did you mean `parent`?
fail_compilation/diag11819b.d(32): Error: unrecognized trait `GetMember`, did you mean `getMember`?
fail_compilation/diag11819b.d(33): Error: unrecognized trait `GetOverloads`, did you mean `getOverloads`?
fail_compilation/diag11819b.d(34): Error: unrecognized trait `GetVirtualFunctions`, did you mean `getVirtualFunctions`?
fail_compilation/diag11819b.d(35): Error: unrecognized trait `GetVirtualMethods`, did you mean `getVirtualMethods`?
fail_compilation/diag11819b.d(36): Error: unrecognized trait `ClassInstanceSize`, did you mean `classInstanceSize`?
fail_compilation/diag11819b.d(37): Error: unrecognized trait `AllMembers`, did you mean `allMembers`?
fail_compilation/diag11819b.d(38): Error: unrecognized trait `DerivedMembers`, did you mean `derivedMembers`?
fail_compilation/diag11819b.d(39): Error: unrecognized trait `IsSame`, did you mean `isSame`?
fail_compilation/diag11819b.d(40): Error: unrecognized trait `Compiles`, did you mean `compiles`?
fail_compilation/diag11819b.d(41): Error: unrecognized trait `Parameters`
fail_compilation/diag11819b.d(42): Error: unrecognized trait `GetAliasThis`, did you mean `getAliasThis`?
fail_compilation/diag11819b.d(43): Error: unrecognized trait `GetAttributes`, did you mean `getAttributes`?
fail_compilation/diag11819b.d(44): Error: unrecognized trait `GetFunctionAttributes`, did you mean `getFunctionAttributes`?
fail_compilation/diag11819b.d(45): Error: unrecognized trait `GetUnitTests`, did you mean `getUnitTests`?
fail_compilation/diag11819b.d(46): Error: unrecognized trait `GetVirtualIndex`, did you mean `getVirtualIndex`?
fail_compilation/diag11819b.d(27): Error: unrecognized trait `HasMember`, did you mean `hasMember`?
fail_compilation/diag11819b.d(28): Error: unrecognized trait `Identifier`, did you mean `identifier`?
fail_compilation/diag11819b.d(29): Error: unrecognized trait `GetProtection`, did you mean `getProtection`?
fail_compilation/diag11819b.d(30): Error: unrecognized trait `Parent`, did you mean `parent`?
fail_compilation/diag11819b.d(31): Error: unrecognized trait `GetMember`, did you mean `getMember`?
fail_compilation/diag11819b.d(32): Error: unrecognized trait `GetOverloads`, did you mean `getOverloads`?
fail_compilation/diag11819b.d(33): Error: unrecognized trait `GetVirtualFunctions`, did you mean `getVirtualFunctions`?
fail_compilation/diag11819b.d(34): Error: unrecognized trait `GetVirtualMethods`, did you mean `getVirtualMethods`?
fail_compilation/diag11819b.d(35): Error: unrecognized trait `ClassInstanceSize`, did you mean `classInstanceSize`?
fail_compilation/diag11819b.d(36): Error: unrecognized trait `AllMembers`, did you mean `allMembers`?
fail_compilation/diag11819b.d(37): Error: unrecognized trait `DerivedMembers`, did you mean `derivedMembers`?
fail_compilation/diag11819b.d(38): Error: unrecognized trait `IsSame`, did you mean `isSame`?
fail_compilation/diag11819b.d(39): Error: unrecognized trait `Compiles`, did you mean `compiles`?
fail_compilation/diag11819b.d(40): Error: unrecognized trait `GetAliasThis`, did you mean `getAliasThis`?
fail_compilation/diag11819b.d(41): Error: unrecognized trait `GetAttributes`, did you mean `getAttributes`?
fail_compilation/diag11819b.d(42): Error: unrecognized trait `GetFunctionAttributes`, did you mean `getFunctionAttributes`?
fail_compilation/diag11819b.d(43): Error: unrecognized trait `GetUnitTests`, did you mean `getUnitTests`?
fail_compilation/diag11819b.d(44): Error: unrecognized trait `GetVirtualIndex`, did you mean `getVirtualIndex`?
---
*/
@ -38,7 +37,6 @@ void main()
if (__traits(DerivedMembers)) { }
if (__traits(IsSame)) { }
if (__traits(Compiles)) { }
if (__traits(Parameters)) { }
if (__traits(GetAliasThis)) { }
if (__traits(GetAttributes)) { }
if (__traits(GetFunctionAttributes)) { }

View File

@ -1,5 +1,5 @@
/*
TEST_OUTPUT*
TEST_OUTPUT:
---
fail_compilation/diag13333.d(29): Error: template instance `VariantN!(maxSize!(S), T)` recursive template expansion
fail_compilation/diag13333.d(29): Error: template instance `diag13333.maxSize!(S)` error instantiating

View File

@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/diag13942.d(18): Error: template instance `isRawStaticArray!()` does not match template declaration `isRawStaticArray(T, A...)`
fail_compilation/diag13942.d(26): Error: template `diag13942.to!double.to` cannot deduce function from argument types `!()()`
fail_compilation/diag13942.d(26): Error: none of the overloads of template `diag13942.to!double.to` are callable using argument types `!()()`
fail_compilation/diag13942.d(17): Candidate is: `to(A...)(A args)`
---
*/

View File

@ -1,5 +1,5 @@
/*
TEST_OUTPUT
TEST_OUTPUT:
---
fail_compilation/diag16271.d(10): Error: found `x` when expecting function literal following `ref`
---

View File

@ -3,7 +3,7 @@ TEST_OUTPUT:
---
fail_compilation/diag16977.d(25): Error: undefined identifier `undefined`, did you mean function `undefinedId`?
fail_compilation/diag16977.d(26): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int`
fail_compilation/diag16977.d(27): Error: template `diag16977.templ` cannot deduce function from argument types `!()(int)`
fail_compilation/diag16977.d(27): Error: none of the overloads of template `diag16977.templ` are callable using argument types `!()(int)`
fail_compilation/diag16977.d(20): Candidate is: `templ(S)(S s)`
with `S = int`
must satisfy the following constraint:

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