Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Commit 6e23b3e

Browse files
committed
Fix Issue 19902 - hasElaborateCopyConstructor doesn't know about copy constructors
1 parent bb0bce7 commit 6e23b3e

File tree

1 file changed

+250
-1
lines changed

1 file changed

+250
-1
lines changed

src/core/internal/traits.d

Lines changed: 250 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,64 @@ template hasElaborateCopyConstructor(S)
258258
}
259259
else static if (is(S == struct))
260260
{
261-
enum hasElaborateCopyConstructor = __traits(hasMember, S, "__xpostblit");
261+
enum hasElaborateCopyConstructor = __traits(hasMember, S, "__xpostblit") ||
262+
() {
263+
static if (__traits(hasMember, S, "__ctor"))
264+
{
265+
static foreach (f; __traits(getOverloads, S, "__ctor"))
266+
{{
267+
enum isVoid(alias T) = is (T == void);
268+
static if (Parameters!f.length == 1 ||
269+
(Parameters!f.length > 1 && !anySatisfy!(isVoid, ParameterDefaults!f[1 .. $])))
270+
{
271+
bool r = is (typeof((Parameters!f x) {
272+
static if (!(__traits(isRef, x[0]) && is (Parameters!f[0] : S)))
273+
{
274+
static assert(0);
275+
}
276+
}));
277+
if (r) return true;
278+
}
279+
}}
280+
}
281+
return false;
282+
}();
262283
}
263284
else
264285
{
265286
enum bool hasElaborateCopyConstructor = false;
266287
}
267288
}
268289

290+
@safe unittest
291+
{
292+
static struct S
293+
{
294+
int x;
295+
this(return scope ref typeof(this) rhs) { }
296+
this(int x, int y) {}
297+
}
298+
299+
static assert(hasElaborateCopyConstructor!S);
300+
301+
static struct S2
302+
{
303+
int x;
304+
this(int x, int y) {}
305+
}
306+
307+
static assert(!hasElaborateCopyConstructor!S2);
308+
309+
static struct S3
310+
{
311+
int x;
312+
this(return scope ref typeof(this) rhs, int x = 42) { }
313+
this(int x, int y) {}
314+
}
315+
316+
static assert(hasElaborateCopyConstructor!S3);
317+
}
318+
269319
template hasElaborateAssign(S)
270320
{
271321
static if (__traits(isStaticArray, S) && S.length)
@@ -284,6 +334,205 @@ template hasElaborateAssign(S)
284334
}
285335
}
286336

337+
// std.traits.isFunctionPointer
338+
/**
339+
Detect whether symbol or type `T` is a function pointer.
340+
*/
341+
template isFunctionPointer(T...)
342+
if (T.length == 1)
343+
{
344+
static if (is(T[0] U) || is(typeof(T[0]) U))
345+
{
346+
static if (is(U F : F*) && is(F == function))
347+
enum bool isFunctionPointer = true;
348+
else
349+
enum bool isFunctionPointer = false;
350+
}
351+
else
352+
enum bool isFunctionPointer = false;
353+
}
354+
355+
///
356+
@safe unittest
357+
{
358+
static void foo() {}
359+
void bar() {}
360+
361+
auto fpfoo = &foo;
362+
static assert( isFunctionPointer!fpfoo);
363+
static assert( isFunctionPointer!(void function()));
364+
365+
auto dgbar = &bar;
366+
static assert(!isFunctionPointer!dgbar);
367+
static assert(!isFunctionPointer!(void delegate()));
368+
static assert(!isFunctionPointer!foo);
369+
static assert(!isFunctionPointer!bar);
370+
371+
static assert( isFunctionPointer!((int a) {}));
372+
}
373+
374+
// std.traits.isDelegate
375+
/**
376+
Detect whether symbol or type `T` is a delegate.
377+
*/
378+
template isDelegate(T...)
379+
if (T.length == 1)
380+
{
381+
static if (is(typeof(& T[0]) U : U*) && is(typeof(& T[0]) U == delegate))
382+
{
383+
// T is a (nested) function symbol.
384+
enum bool isDelegate = true;
385+
}
386+
else static if (is(T[0] W) || is(typeof(T[0]) W))
387+
{
388+
// T is an expression or a type. Take the type of it and examine.
389+
enum bool isDelegate = is(W == delegate);
390+
}
391+
else
392+
enum bool isDelegate = false;
393+
}
394+
395+
///
396+
@safe unittest
397+
{
398+
static void sfunc() { }
399+
int x;
400+
void func() { x++; }
401+
402+
int delegate() dg;
403+
assert(isDelegate!dg);
404+
assert(isDelegate!(int delegate()));
405+
assert(isDelegate!(typeof(&func)));
406+
407+
int function() fp;
408+
assert(!isDelegate!fp);
409+
assert(!isDelegate!(int function()));
410+
assert(!isDelegate!(typeof(&sfunc)));
411+
}
412+
413+
// std.traits.ParameterIdentifierTuple
414+
/**
415+
Get, as a tuple, the identifiers of the parameters to a function symbol.
416+
*/
417+
template ParameterIdentifierTuple(func...)
418+
if (func.length == 1/* && isCallable!func*/)
419+
{
420+
static if (is(FunctionTypeOf!func PT == __parameters))
421+
{
422+
template Get(size_t i)
423+
{
424+
static if (!isFunctionPointer!func && !isDelegate!func
425+
// Unnamed parameters yield CT error.
426+
&& is(typeof(__traits(identifier, PT[i .. i+1])))
427+
// Filter out unnamed args, which look like (Type) instead of (Type name).
428+
&& PT[i].stringof != PT[i .. i+1].stringof[1..$-1])
429+
{
430+
enum Get = __traits(identifier, PT[i .. i+1]);
431+
}
432+
else
433+
{
434+
enum Get = "";
435+
}
436+
}
437+
}
438+
else
439+
{
440+
static assert(0, func[0].stringof ~ "is not a function");
441+
442+
// Define dummy entities to avoid pointless errors
443+
template Get(size_t i) { enum Get = ""; }
444+
alias PT = AliasSeq!();
445+
}
446+
447+
template Impl(size_t i = 0)
448+
{
449+
static if (i == PT.length)
450+
alias Impl = AliasSeq!();
451+
else
452+
alias Impl = AliasSeq!(Get!i, Impl!(i+1));
453+
}
454+
455+
alias ParameterIdentifierTuple = Impl!();
456+
}
457+
458+
///
459+
@safe unittest
460+
{
461+
int foo(int num, string name, int);
462+
static assert([ParameterIdentifierTuple!foo] == ["num", "name", ""]);
463+
}
464+
465+
// std.traits.ParameterDefaults
466+
/**
467+
Get, as a tuple, the default value of the parameters to a function symbol.
468+
If a parameter doesn't have the default value, `void` is returned instead.
469+
*/
470+
template ParameterDefaults(func...)
471+
if (func.length == 1/* && isCallable!func*/)
472+
{
473+
alias param_names = ParameterIdentifierTuple!func;
474+
static if (is(FunctionTypeOf!(func[0]) PT == __parameters))
475+
{
476+
template Get(size_t i)
477+
{
478+
// `PT[i .. i+1]` declares a parameter with an arbitrary name.
479+
// To avoid a name clash, generate local names that are distinct
480+
// from the parameter name, and mix them in.
481+
enum name = param_names[i];
482+
enum args = "args" ~ (name == "args" ? "_" : "");
483+
enum val = "val" ~ (name == "val" ? "_" : "");
484+
enum ptr = "ptr" ~ (name == "ptr" ? "_" : "");
485+
mixin("
486+
// workaround scope escape check, see
487+
// https://issues.dlang.org/show_bug.cgi?id=16582
488+
// should use return scope once available
489+
enum get = (PT[i .. i+1] " ~ args ~ ") @trusted
490+
{
491+
// If the parameter is lazy, we force it to be evaluated
492+
// like this.
493+
auto " ~ val ~ " = " ~ args ~ "[0];
494+
auto " ~ ptr ~ " = &" ~ val ~ ";
495+
// workaround Bugzilla 16582
496+
return *" ~ ptr ~ ";
497+
};
498+
");
499+
static if (is(typeof(get())))
500+
enum Get = get();
501+
else
502+
alias Get = void;
503+
// If default arg doesn't exist, returns void instead.
504+
}
505+
}
506+
else
507+
{
508+
static assert(0, func[0].stringof ~ "is not a function");
509+
510+
// Define dummy entities to avoid pointless errors
511+
template Get(size_t i) { enum Get = ""; }
512+
alias PT = AliasSeq!();
513+
}
514+
515+
template Impl(size_t i = 0)
516+
{
517+
static if (i == PT.length)
518+
alias Impl = AliasSeq!();
519+
else
520+
alias Impl = AliasSeq!(Get!i, Impl!(i+1));
521+
}
522+
523+
alias ParameterDefaults = Impl!();
524+
}
525+
526+
///
527+
@safe unittest
528+
{
529+
int foo(int num, string name = "hello", int[] = [1,2,3], lazy int x = 0);
530+
static assert(is(ParameterDefaults!foo[0] == void));
531+
static assert( ParameterDefaults!foo[1] == "hello");
532+
static assert( ParameterDefaults!foo[2] == [1,2,3]);
533+
static assert( ParameterDefaults!foo[3] == 0);
534+
}
535+
287536
// std.meta.Filter
288537
template Filter(alias pred, TList...)
289538
{

0 commit comments

Comments
 (0)