35 changes: 21 additions & 14 deletions src/mtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -1363,26 +1363,30 @@ bool MODimplicitConv(MOD modfrom, MOD modto)
}

/***************************
* Return !=0 if a method of type '() modfrom' can call a method of type '() modto'.
* Return MATCHexact or MATCHconst if a method of type '() modfrom' can call a method of type '() modto'.
*/
bool MODmethodConv(MOD modfrom, MOD modto)
MATCH MODmethodConv(MOD modfrom, MOD modto)
{
if (modfrom == modto)
return MATCHexact;
if (MODimplicitConv(modfrom, modto))
return true;
return MATCHconst;

#define X(m, n) (((m) << 4) | (n))
switch (X(modfrom, modto))
{
case X(0, MODwild):
case X(0, MODwild):
case X(MODimmutable, MODwild):
case X(MODconst, MODwild):
case X(MODshared, MODshared|MODwild):
case X(MODconst, MODwild):
case X(MODwildconst, MODwild):
case X(MODshared, MODshared|MODwild):
case X(MODshared|MODimmutable, MODshared|MODwild):
case X(MODshared|MODconst, MODshared|MODwild):
return true;
case X(MODshared|MODconst, MODshared|MODwild):
case X(MODshared|MODwildconst, MODshared|MODwild):
return MATCHconst;

default:
return false;
return MATCHnomatch;
}
#undef X
}
Expand Down Expand Up @@ -5738,7 +5742,6 @@ void TypeFunction::purityLevel()
}
}


/********************************
* 'args' are being matched to function 'this'
* Determine match level.
Expand All @@ -5755,7 +5758,8 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
unsigned char wildmatch = 0;

if (tthis)
{ Type *t = tthis;
{
Type *t = tthis;
if (t->toBasetype()->ty == Tpointer)
t = t->toBasetype()->nextOf(); // change struct* to struct
if (t->mod != mod)
Expand Down Expand Up @@ -5821,7 +5825,8 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
else if (wildmatch & MODwild)
wildmatch = MODwild;
else
{ assert(wildmatch & MODmutable);
{
assert(wildmatch & MODmutable);
wildmatch = MODmutable;
}
}
Expand Down Expand Up @@ -5935,7 +5940,8 @@ MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
{
L1:
if (varargs == 2 && u + 1 == nparams) // if last varargs param
{ Type *tb = p->type->toBasetype();
{
Type *tb = p->type->toBasetype();
TypeSArray *tsa;
dinteger_t sz;

Expand Down Expand Up @@ -6012,7 +6018,8 @@ bool TypeFunction::hasLazyParameters()
{
size_t dim = Parameter::dim(parameters);
for (size_t i = 0; i < dim; i++)
{ Parameter *fparam = Parameter::getNth(parameters, i);
{
Parameter *fparam = Parameter::getNth(parameters, i);
if (fparam->storageClass & STClazy)
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/mtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -930,7 +930,7 @@ bool arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2);
void MODtoBuffer(OutBuffer *buf, MOD mod);
char *MODtoChars(MOD mod);
bool MODimplicitConv(MOD modfrom, MOD modto);
bool MODmethodConv(MOD modfrom, MOD modto);
MATCH MODmethodConv(MOD modfrom, MOD modto);
MOD MODmerge(MOD mod1, MOD mod2);

#endif /* DMD_MTYPE_H */
12 changes: 5 additions & 7 deletions src/template.c
Original file line number Diff line number Diff line change
Expand Up @@ -1351,13 +1351,11 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(
unsigned char thismod = tthis->mod;
if (hasttp)
mod = MODmerge(thismod, mod);
if (thismod != mod)
{
if (!MODmethodConv(thismod, mod))
goto Lnomatch;
if (MATCHconst < match)
match = MATCHconst;
}
MATCH m = MODmethodConv(thismod, mod);
if (m <= MATCHnomatch)
goto Lnomatch;
if (m < match)
match = m;
}
}

Expand Down
40 changes: 40 additions & 0 deletions test/fail_compilation/testInference.d
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,43 @@ int* f14160() pure
{
return &g14160; // should be rejected
}

/*
TEST_OUTPUT:
---
fail_compilation/testInference.d(180): Error: pure function 'testInference.test12422' cannot call impure function 'testInference.test12422.bar12422!().bar12422'
---
*/
int g12422;
void foo12422() { ++g12422; }
void test12422() pure
{
void bar12422()() { foo12422(); }
bar12422();
}

/*
TEST_OUTPUT:
---
fail_compilation/testInference.d(196): Error: pure function 'testInference.test13729a' cannot access mutable static data 'g13729'
fail_compilation/testInference.d(206): Error: pure function 'testInference.test13729b' cannot call impure function 'testInference.test13729b.foo!().foo'
---
*/
int g13729;

void test13729a() pure
{
static void foo() // typed as impure
{
g13729++; // disallowed
}
foo();
}
void test13729b() pure
{
static void foo()() // inferred to impure
{
g13729++;
}
foo(); // cannot call impure function
}
50 changes: 50 additions & 0 deletions test/runnable/aliasthis.d
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,56 @@ void test11355()
assert(A11355.postblit == 1);
}

/***************************************************/
// 13009

struct T13009
{
void put(char c) {}
}

struct S13009
{
T13009 t;

@property
T13009 getT()
{
return t;
}

@property
inout(T13009) getT() inout
{
return t;
}

alias getT this;
}

void test13009()
{
alias MS = S13009;
alias CS = const(S13009);
alias WS = inout( S13009);
alias WCS = inout(const S13009);
alias SMS = shared( S13009);
alias SCS = shared( const S13009);
alias SWS = shared(inout S13009);
alias SWCS = shared(inout const S13009);
alias IS = immutable(S13009);

alias MSput = MS .put;
alias CSput = CS .put;
alias WSput = WS .put;
alias WCSput = WCS.put;
static assert(!__traits(compiles, { alias SMSput = SMS .put; }));
static assert(!__traits(compiles, { alias SCSput = SCS .put; }));
static assert(!__traits(compiles, { alias SWSput = SWS .put; }));
static assert(!__traits(compiles, { alias SWCSput = SWCS.put; }));
alias ISput = IS .put;
}

/***************************************************/

int main()
Expand Down
29 changes: 29 additions & 0 deletions test/runnable/casting.d
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,34 @@ void test11722()
shared C11722 sc = cast(shared)c;
}

/***************************************************/
// 14218

void test14218()
{
foreach (To; Seq!( byte, short, int, long,
ubyte, ushort, uint, ulong,
char, wchar, dchar, bool))
{
auto x = cast(To)null;
assert(x == 0); // false, '0x00'
}

// Questionable but currently accepted
foreach (To; Seq!( float, double, real,
ifloat, idouble, ireal))
{
auto x = cast(To)null;
assert(x == 0); // 0i
}

// Internal error: backend/el.c in el_long()
//foreach (To; Seq!(cfloat, cdouble, creal))
//{
// static assert(!__traits(compiles, { auto x = cast(To)null; }));
//}
}

/***************************************************/

int main()
Expand All @@ -210,6 +238,7 @@ int main()
test10834();
test10842();
test11722();
test14218();

printf("Success\n");
return 0;
Expand Down
23 changes: 23 additions & 0 deletions test/runnable/variadic.d
Original file line number Diff line number Diff line change
Expand Up @@ -1669,6 +1669,28 @@ void test10414()
);
}

/***************************************/

import core.stdc.stdarg;

struct S14179
{
const(char)* filename;
uint linnum;
uint charnum;
}

extern(C++) const(char)* func14179(S14179 x, const(char)* string, ...)
{
return string;
}

void test14179()
{
const(char)* s = "hello";
assert(func14179(S14179(), s) == s);
}

/***************************************/
// 10722

Expand Down Expand Up @@ -1768,6 +1790,7 @@ int main()
test10414();
test9495();
testCopy();
test14179();

printf("Success\n");
return 0;
Expand Down
10 changes: 10 additions & 0 deletions test/runnable/xtest46.d
Original file line number Diff line number Diff line change
Expand Up @@ -7247,6 +7247,15 @@ static this()
wordsAA14038["zero"] = 0;
}

/***************************************************/
// 14192

void test14192()
{
shared int[int] map;
map[1] = 1;
}

/***************************************************/
// 13952

Expand Down Expand Up @@ -7578,6 +7587,7 @@ int main()
test8917();
test8945();
test11805();
test14192();
test163();
test9428();
test9477();
Expand Down