From e6e6e8e1748cb03acc674b89f73ce5e900718c28 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Fri, 26 Dec 2025 22:11:20 +0100 Subject: [PATCH] Update traits completion --- common/src/dcd/common/constants2.d | 384 ++++++++++++++++++++------- constants-gen/pragma.dd | 2 +- constants-gen/traits.dd | 403 ++++++++++++++++++++++------- tests/tc_traits/expected.txt | 5 + 4 files changed, 618 insertions(+), 176 deletions(-) diff --git a/common/src/dcd/common/constants2.d b/common/src/dcd/common/constants2.d index 8f958ad..ed7a52a 100644 --- a/common/src/dcd/common/constants2.d +++ b/common/src/dcd/common/constants2.d @@ -23,7 +23,8 @@ immutable ConstantCompletion[] traits = [ ConstantCompletion("allMembers", `$(P Takes a single argument, which must evaluate to either a module, a struct, a union, a class, an interface, an enum, or a template instantiation. - +) +$(P A sequence of string literals is returned, each of which is the name of a member of that argument combined with all of the members of its base classes (if the argument is a class). @@ -120,14 +121,27 @@ polymorphic type. compile (are semantically correct). The arguments can be symbols, types, or expressions that are syntactically correct. -The arguments cannot be statements or declarations. +The arguments cannot be statements or declarations - instead +these can be wrapped in a $(DDSUBLINK spec/expression, function_literals, +function literal) expression. ) $(P If there are no arguments, the result is $(D false).) $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- -import std.stdio; +static assert(!__traits(compiles)); +static assert(__traits(compiles, 1 + 1)); // expression +static assert(__traits(compiles, typeof(1))); // type +static assert(__traits(compiles, object)); // symbol +static assert(__traits(compiles, 1, 2, 3, int, long)); +static assert(!__traits(compiles, 3[1])); // semantic error +static assert(!__traits(compiles, 1, 2, 3, int, long, 3[1])); + +enum n = 3; +// wrap a declaration/statement in a function literal +static assert(__traits(compiles, { int[n] arr; })); +static assert(!__traits(compiles, { foreach (e; n) {} })); struct S { @@ -135,29 +149,23 @@ struct S int s2; } -int foo(); -int bar(); +static assert(__traits(compiles, S.s1 = 0)); +static assert(!__traits(compiles, S.s2 = 0)); +static assert(!__traits(compiles, S.s3)); -void main() -{ - writeln(__traits(compiles)); // false - writeln(__traits(compiles, foo)); // true - writeln(__traits(compiles, foo + 1)); // true - writeln(__traits(compiles, &foo + 1)); // false - writeln(__traits(compiles, typeof(1))); // true - writeln(__traits(compiles, S.s1)); // true - writeln(__traits(compiles, S.s3)); // false - writeln(__traits(compiles, 1,2,3,int,long,std)); // true - writeln(__traits(compiles, 3[1])); // false - writeln(__traits(compiles, 1,2,3,int,long,3[1])); // false -} +int foo(); + +static assert(__traits(compiles, foo)); +static assert(__traits(compiles, foo + 1)); // call foo with optional parens +static assert(!__traits(compiles, &foo + 1)); --- ) $(P This is useful for:) $(UL -$(LI Giving better error messages inside generic code than +$(LI Giving better error messages (using $(DDSUBLINK spec/version, static-assert, +` ~ "`" ~ `static assert` ~ "`" ~ `)) inside generic code than the sometimes hard to follow compiler ones.) $(LI Doing a finer grained specialization than template partial specialization allows for.) @@ -193,6 +201,53 @@ void main() $(P The order in which the strings appear in the result is not defined.)`), + ConstantCompletion("fullyQualifiedName", `$(P Gets the fully qualified name of a type or symbol.) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +----------------- +module myModule; + +int i; +static assert(__traits(fullyQualifiedName, i) == "myModule.i"); + +struct MyStruct {} +static assert(__traits(fullyQualifiedName, const MyStruct[]) == "const(myModule.MyStruct[])"); +----------------- +)`), + ConstantCompletion("fullyQualifiedName", `$(P Takes one argument, which can be a type, expression, or symbol, and returns a string.) + +$(UL +$(LI A $(D type) returns a string representing the type.) +$(LI A $(D expression) returns a string representing the type of the expression.) +$(LI A $(D symbol) returns a string representing the fully qualified name of the symbol.) +) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +module plugh; +import std.stdio; + +void main() +{ + auto s = __traits(fullyQualifiedName, int); + writeln(s); + + auto t = __traits(fullyQualifiedName, 1.0); + writeln(t); + + auto u = __traits(fullyQualifiedName, t); + writeln(u); +} +--- +) + +Prints: + +$(CONSOLE +int +double +plugh.main.t +)`), ConstantCompletion("getAliasThis", `$(P Takes one argument, a type. If the type has ` ~ "`" ~ `alias this` ~ "`" ~ ` declarations, returns a *ValueSeq* of the names (as ` ~ "`" ~ `string` ~ "`" ~ `s) of the members used in those declarations. Otherwise returns an empty sequence. @@ -251,6 +306,49 @@ tuple(3) tuple("string", 7) tuple((Foo)) ) +)`), + ConstantCompletion("getBitfieldOffset", `$(P Takes one argument, a qualified name that resolve to a field in a struct or class. +) +$(P If the field is a bitfield, it returns as a ` ~ "`" ~ `uint` ~ "`" ~ ` the bit number of the least significant +bit in the field. The rightmost bit is at offset 0, the leftmost bit is at offset 31 (for +32 bit int fields). +) +$(P If the field is a not bitfield, it returns as a ` ~ "`" ~ `uint` ~ "`" ~ ` the number 0. +) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +struct S +{ + int a,b; + int :2, c:3; +} + +static assert(__traits(getBitfieldOffset, S.b) == 0); +static assert(__traits(getBitfieldOffset, S.c) == 2); +--- +) + +)`), + ConstantCompletion("getBitfieldWidth", `$(P Takes one argument, a qualified name that resolve to a field in a struct or class. +) +$(P If the field is a bitfield, it returns as a ` ~ "`" ~ `uint` ~ "`" ~ ` the width of the bit field as +a number of bits. +) +$(P If the field is a not bitfield, it returns the number of bits in the type. +) +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +struct S +{ + int a,b; + int :2, c:3; +} + +static assert(__traits(getBitfieldWidth, S.b) == 32); +static assert(__traits(getBitfieldWidth, S.c) == 3); +--- +) )`), ConstantCompletion("getCppNamespaces", `$(P The argument is a symbol. The result is a *ValueSeq* of strings, possibly empty, that correspond to the namespaces the symbol resides in. @@ -432,13 +530,13 @@ void main() } --- )`), - ConstantCompletion("getOverloads", `$(P The first argument is an aggregate (e.g. struct/class/module). -The second argument is a ` ~ "`" ~ `string` ~ "`" ~ ` that matches the name of -the member(s) to return. -The third argument is a ` ~ "`" ~ `bool` ~ "`" ~ `, and is optional. If ` ~ "`" ~ `true` ~ "`" ~ `, the -result will also include template overloads. -The result is a symbol sequence of all the overloads of the supplied name. -) + ConstantCompletion("getOverloads", `* The first argument is an aggregate type or instance, or a module. +* The second argument is a ` ~ "`" ~ `string` ~ "`" ~ ` that matches the name of + the member(s) to return. +* The third argument is a ` ~ "`" ~ `bool` ~ "`" ~ `, and is optional. If ` ~ "`" ~ `true` ~ "`" ~ `, the + result will also include template overloads. +* The result is a $(DDSUBLINK spec/template, homogeneous_sequences, symbol sequence) + of all the overloads of the supplied name. $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- @@ -446,8 +544,6 @@ import std.stdio; class D { - this() { } - ~this() { } void foo() { } int foo(int) { return 2; } void bar(T)() { return T.init; } @@ -458,18 +554,24 @@ void main() { D d = new D(); - foreach (t; __traits(getOverloads, D, "foo")) - writeln(typeid(typeof(t))); + alias fooOverloads = __traits(getOverloads, D, "foo"); + foreach (o; fooOverloads) + writeln(typeid(typeof(o))); - alias b = typeof(__traits(getOverloads, D, "foo")); - foreach (t; b) - writeln(typeid(t)); + // typeof on a symbol sequence gives a type sequence + foreach (T; typeof(fooOverloads)) + writeln(typeid(T)); - auto i = __traits(getOverloads, d, "foo")[1](1); - writeln(i); + // calls d.foo(3) + auto i = __traits(getOverloads, d, "foo")[1](3); + assert(i == 2); - foreach (t; __traits(getOverloads, D, "bar", true)) - writeln(t.stringof); + // pass true to include templates + // calls std.stdio.writeln(i) + __traits(getOverloads, std.stdio, "writeln", true)[0](i); + + foreach (o; __traits(getOverloads, D, "bar", true)) + writeln(o.stringof); } --- ) @@ -477,10 +579,10 @@ void main() Prints: $(CONSOLE -void() -int() -void() -int() +void function() +int function(int) +void function() +int function(int) 2 bar(T)() bar(int n) @@ -577,15 +679,13 @@ $(LI $(D "objectFormat") - Target object format) Takes one argument, a symbol of an aggregate (e.g. struct/class/module). The result is a symbol sequence of all the unit test functions of that aggregate. The functions returned are like normal nested static functions, - $(DDSUBLINK glossary, ctfe, CTFE) will work and + $(DDSUBLINK spec/glossary, ctfe, CTFE) will work and $(DDSUBLINK spec/attribute, uda, UDAs) will be accessible. ) -$(H4 Note:) - -$(P - The -unittest flag needs to be passed to the compiler. If the flag - is not passed $(CODE __traits(getUnitTests)) will always return an +$(NOTE + The ` ~ "`" ~ `-unittest` ~ "`" ~ ` flag needs to be passed to the compiler. If the flag + is not passed, $(CODE __traits(getUnitTests)) will always return an empty sequence. ) @@ -737,7 +837,9 @@ $(CONSOLE export public )`), - ConstantCompletion("hasCopyConstructor", `$(P The argument is a type. If it is a struct with a copy constructor, returns $(D true). Otherwise, return $(D false). Note that a copy constructor is distinct from a postblit. + ConstantCompletion("hasCopyConstructor", `$(P The argument is a type. +If it is a struct with a copy constructor, returns $(D true). Otherwise, return $(D false). +A copy constructor is distinct from a move constructor or a postblit. ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE @@ -745,22 +847,18 @@ $(SPEC_RUNNABLE_EXAMPLE_COMPILE import std.stdio; -struct S -{ -} +struct S { } -class C -{ -} +class C { } struct P { - this(ref P rhs) {} + this(ref P rhs) {} // copy constructor } struct B { - this(this) {} + this(this) {} // postblit } void main() @@ -792,11 +890,48 @@ void main() { S s; - writeln(__traits(hasMember, S, "m")); // true - writeln(__traits(hasMember, s, "m")); // true - writeln(__traits(hasMember, S, "y")); // false - writeln(__traits(hasMember, S, "write")); // false, but callable like a member via UFCS - writeln(__traits(hasMember, int, "sizeof")); // true + static assert(__traits(hasMember, S, "m")); + static assert(__traits(hasMember, s, "m")); + static assert(!__traits(hasMember, S, "y")); + static assert(!__traits(hasMember, S, "write")); // false, but callable like a member via UFCS + static assert(__traits(hasMember, int, "sizeof")); + static assert(__traits(hasMember, 5, "sizeof")); +} +--- +)`), + ConstantCompletion("hasMoveConstructor", `$(P The argument is a type. +If it is a struct with a move constructor, returns $(D true). Otherwise, return $(D false). +A move constructor is distinct from a copy constructor or a postblit. +) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- + +import std.stdio; + +struct S +{ + this(S rhs) {} // move constructor +} + +class C { } + +struct P +{ + this(ref P rhs) {} // copy constructor +} + +struct B +{ + this(this) {} // postblit +} + +void main() +{ + writeln(__traits(hasMoveConstructor, S)); // true + writeln(__traits(hasMoveConstructor, C)); // false + writeln(__traits(hasMoveConstructor, P)); // false + writeln(__traits(hasMoveConstructor, B)); // false, this is a postblit } --- )`), @@ -839,25 +974,22 @@ void main() ConstantCompletion("identifier", `$(P Takes one argument, a symbol. Returns the identifier for that symbol as a string literal. ) -$(SPEC_RUNNABLE_EXAMPLE_RUN +$(SPEC_RUNNABLE_EXAMPLE_COMPILE --- int var = 123; -pragma(msg, typeof(var)); // int -pragma(msg, typeof(__traits(identifier, var))); // string -writeln(var); // 123 -writeln(__traits(identifier, var)); // "var" +static assert(__traits(identifier, var) == "var"); --- )`), ConstantCompletion("initSymbol", `$(P Takes a single argument, which must evaluate to a ` ~ "`" ~ `class` ~ "`" ~ `, ` ~ "`" ~ `struct` ~ "`" ~ ` or ` ~ "`" ~ `union` ~ "`" ~ ` type. Returns a ` ~ "`" ~ `const(void)[]` ~ "`" ~ ` that holds the initial state of any instance of the supplied type. The slice is constructed for any type ` ~ "`" ~ `T` ~ "`" ~ ` as follows: +) - ` ~ "`" ~ `ptr` ~ "`" ~ ` points to either the initializer symbol of ` ~ "`" ~ `T` ~ "`" ~ ` - or ` ~ "`" ~ `null` ~ "`" ~ ` if ` ~ "`" ~ `T` ~ "`" ~ ` is a zero-initialized struct / unions. + or ` ~ "`" ~ `null` ~ "`" ~ ` if ` ~ "`" ~ `T` ~ "`" ~ ` is a $(RELATIVE_LINK2 isZeroInit, zero-initialized) struct/union. - - ` ~ "`" ~ `length` ~ "`" ~ ` is equal to the size of an instance, i.e. ` ~ "`" ~ `T.sizeof` ~ "`" ~ ` for structs / unions and - $(RELATIVE_LINK2 classInstanceSize, $(D __traits(classInstanceSize, T)` ~ "`" ~ `)) for classes. -) + - ` ~ "`" ~ `length` ~ "`" ~ ` is equal to the size of an instance, i.e. ` ~ "`" ~ `T.sizeof` ~ "`" ~ ` for a struct/union and + $(RELATIVE_LINK2 classInstanceSize, $(D __traits(classInstanceSize, T))) for a class. $(P This trait matches the behaviour of ` ~ "`" ~ `TypeInfo.initializer()` ~ "`" ~ ` but can also be used when @@ -865,11 +997,14 @@ $(P ) $(P - This traits is not available during $(DDSUBLINK glossary, ctfe, CTFE) because the actual address + This trait is not available during $(DDSUBLINK spec/glossary, ctfe, CTFE) because the actual address of the initializer symbol will be set by the linker and hence is not available at compile time. ) +$(SPEC_RUNNABLE_EXAMPLE_RUN --- +import core.stdc.stdlib; + class C { int i = 4; @@ -883,12 +1018,14 @@ void main() void* ptr = malloc(initSym.length); scope (exit) free(ptr); - ptr[0..initSym.length] = initSym[]; + // Note: allocated memory will only be written to through ` ~ "`" ~ `c` ~ "`" ~ `, so cast is safe + ptr[0..initSym.length] = cast(void[]) initSym[]; C c = cast(C) ptr; assert(c.i == 4); } ----`), +--- +)`), ConstantCompletion("isAbstractClass", `$(P If the arguments are all either types that are abstract classes, or expressions that are typed as abstract classes, then $(D true) is returned. @@ -984,6 +1121,10 @@ false )`), ConstantCompletion("isAssociativeArray", `$(P Works like $(D isArithmetic), except it's for associative array types.)`), + ConstantCompletion("isCOMClass", `$(P Takes one argument. If that argument is a symbol that refers to a +$(DDSUBLINK spec/class, ClassDeclaration, class declaration) and is a COM class then $(D true) is retuned, +otherwise $(D false). +)`), ConstantCompletion("isCopyable", `$(P Takes one argument. If that argument is a copyable type then $(D true) is returned, otherwise $(D false). ) @@ -1003,7 +1144,26 @@ static assert(!__traits(isCopyable, T)); --- )`), ConstantCompletion("isDeprecated", `$(P Takes one argument. It returns ` ~ "`" ~ `true` ~ "`" ~ ` if the argument is a symbol -marked with the ` ~ "`" ~ `deprecated` ~ "`" ~ ` keyword, otherwise ` ~ "`" ~ `false` ~ "`" ~ `.)`), +marked with the ` ~ "`" ~ `deprecated` ~ "`" ~ ` keyword, otherwise ` ~ "`" ~ `false` ~ "`" ~ `.) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +deprecated("No longer supported") +int i; + +struct A +{ + int foo() { return 1; } + + deprecated("please use foo") + int bar() { return 1; } +} + +static assert(__traits(isDeprecated, i)); +static assert(!__traits(isDeprecated, A.foo)); +static assert(__traits(isDeprecated, A.bar)); +--- +)`), ConstantCompletion("isDisabled", `$(P Takes one argument and returns ` ~ "`" ~ `true` ~ "`" ~ ` if it's a function declaration marked with ` ~ "`" ~ `@disable` ~ "`" ~ `.) @@ -1020,8 +1180,8 @@ static assert(!__traits(isDisabled, Foo.bar)); --- ) -$(P For any other declaration even if ` ~ "`" ~ `@disable` ~ "`" ~ ` is a syntactically valid -attribute ` ~ "`" ~ `false` ~ "`" ~ ` is returned because the annotation has no effect.) +$(P For any other declaration, even if ` ~ "`" ~ `@disable` ~ "`" ~ ` is a syntactically valid +attribute, ` ~ "`" ~ `false` ~ "`" ~ ` is returned because the annotation has no effect.) $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- @@ -1091,8 +1251,9 @@ static assert(!__traits(isFloating, float[4])); --- )`), ConstantCompletion("isFuture", `$(P Takes one argument. It returns ` ~ "`" ~ `true` ~ "`" ~ ` if the argument is a symbol -marked with the ` ~ "`" ~ `@future` ~ "`" ~ ` keyword, otherwise ` ~ "`" ~ `false` ~ "`" ~ `. Currently, only -functions and variable declarations have support for the ` ~ "`" ~ `@future` ~ "`" ~ ` keyword.)`), +marked with the $(DDSUBLINK spec/attribute, future, ` ~ "`" ~ `@__future` ~ "`" ~ ` attribute), +otherwise ` ~ "`" ~ `false` ~ "`" ~ `. Currently, only +functions and variable declarations have support for the ` ~ "`" ~ `@__future` ~ "`" ~ ` keyword.)`), ConstantCompletion("isIntegral", `$(P If the arguments are all either types that are integral types, or expressions that are typed as integral types, then $(D true) is returned. @@ -1234,18 +1395,20 @@ void main() --- )`), ConstantCompletion("isPOD", `$(P Takes one argument, which must be a type. It returns -$(D true) if the type is a $(DDSUBLINK glossary, pod, POD) type, otherwise $(D false).)`), +$(D true) if the type is a $(DDSUBLINK spec/glossary, pod, POD) type, otherwise $(D false).)`), ConstantCompletion("isPackage", `$(P Takes one argument. If that argument is a symbol that refers to a $(DDSUBLINK spec/module, PackageName, package) then $(D true) is returned, otherwise $(D false). ) +$(SPEC_RUNNABLE_EXAMPLE_COMPILE --- import std.algorithm.sorting; static assert(__traits(isPackage, std)); static assert(__traits(isPackage, std.algorithm)); static assert(!__traits(isPackage, std.algorithm.sorting)); ----`), +--- +)`), ConstantCompletion("isRef", `$(P Takes one argument. If that argument is a declaration, $(D true) is returned if it is $(D_KEYWORD ref), $(D_KEYWORD out), or $(D_KEYWORD lazy), otherwise $(D false). @@ -1330,6 +1493,30 @@ alias daz = foo; static assert(__traits(isSame, foo, daz)); --- ) +$(P isSame matches against non-instantiated templates.) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +struct Foo(T){ + T x; +} + +struct Bar(T){ + T x; +} + +struct Point(T){ + T x; + T y; +} + +enum isFooOrBar(alias FB) = __traits(isSame, FB, Foo) || __traits(isSame, FB, Bar); + +static assert(isFooOrBar!(Foo)); +static assert(isFooOrBar!(Bar)); +static assert(!isFooOrBar!(Point)); +--- +) $(P The result is ` ~ "`" ~ `true` ~ "`" ~ ` if the two arguments are expressions made up of literals or enums that evaluate to the same value.) @@ -1515,9 +1702,9 @@ then $(D true) is returned, otherwise $(D false). $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- void foo(T)(){} -static assert(__traits(isTemplate,foo)); -static assert(!__traits(isTemplate,foo!int())); -static assert(!__traits(isTemplate,"string")); +static assert(__traits(isTemplate, foo)); +static assert(!__traits(isTemplate, foo!int())); +static assert(!__traits(isTemplate, "string")); --- )`), ConstantCompletion("isUnsigned", `$(P If the arguments are all either types that are unsigned types, @@ -1610,12 +1797,26 @@ static assert(__traits(isZeroInit, void)); --- )`), ConstantCompletion("parameters", `$(P May only be used inside a function. Takes no arguments, and returns -a sequence of the enclosing function's parameters.) - -$(P If the function is nested, the parameters returned are those of the -inner function, not the outer one.) +an $(DDSUBLINK spec/template, lvalue-sequences, lvalue sequence) of the +enclosing function's parameters.) +$(SPEC_RUNNABLE_EXAMPLE_COMPILE --- +alias AliasSeq(A...) = A; + +void f(int n, char c) +{ + alias PS = __traits(parameters); + PS[0]++; // increment n + static assert(is(typeof(PS) == AliasSeq!(int, char))); + + // output parameter names + static foreach (i, p; PS) + { + pragma(msg, __traits(identifier, p)); + } +} + int add(int x, int y) { return x + y; @@ -1627,7 +1828,13 @@ int forwardToAdd(int x, int y) // equivalent to; //return add(x, y); } +--- +) +$(P If the function is nested, the parameters returned are those of the +inner function, not the outer one.) + +--- int nestedExample(int x) { // outer function's parameters @@ -1642,7 +1849,8 @@ int nestedExample(int x) return add(x, x); } - +--- +--- class C { int opApply(int delegate(size_t, C) dg) diff --git a/constants-gen/pragma.dd b/constants-gen/pragma.dd index f8516f6..985ecaf 100644 --- a/constants-gen/pragma.dd +++ b/constants-gen/pragma.dd @@ -493,5 +493,5 @@ $(SPEC_SUBNAV_PREV_NEXT attribute, Attributes, expression, Expressions) ) Macros: - CHAPTER=9 + CHAPTER=10 TITLE=Pragmas diff --git a/constants-gen/traits.dd b/constants-gen/traits.dd index 888b05c..b7c100e 100644 --- a/constants-gen/traits.dd +++ b/constants-gen/traits.dd @@ -49,12 +49,17 @@ $(GNAME TraitsKeyword): $(RELATIVE_LINK2 isZeroInit, $(D isZeroInit)) $(RELATIVE_LINK2 isModule, $(D isModule)) $(RELATIVE_LINK2 isPackage, $(D isPackage)) + $(RELATIVE_LINK2 isCOMClass, $(D isCOMClass)) $(RELATIVE_LINK2 hasMember, $(D hasMember)) $(RELATIVE_LINK2 hasCopyConstructor, $(D hasCopyConstructor)) + $(RELATIVE_LINK2 hasMoveConstructor, $(D hasMoveConstructor)) $(RELATIVE_LINK2 hasPostblit, $(D hasPostblit)) $(RELATIVE_LINK2 identifier, $(D identifier)) + $(RELATIVE_LINK2 fullyQualifiedName, $(D fullyQualifiedName)) $(RELATIVE_LINK2 getAliasThis, $(D getAliasThis)) $(RELATIVE_LINK2 getAttributes, $(D getAttributes)) + $(RELATIVE_LINK2 getBitfieldOffset, $(D getBitfieldOffset)) + $(RELATIVE_LINK2 getBitfieldWidth, $(D getBitfieldWidth)) $(RELATIVE_LINK2 getFunctionAttributes, $(D getFunctionAttributes)) $(RELATIVE_LINK2 getFunctionVariadicStyle, $(D getFunctionVariadicStyle)) $(RELATIVE_LINK2 getLinkage, $(D getLinkage)) @@ -82,6 +87,7 @@ $(GNAME TraitsKeyword): $(RELATIVE_LINK2 toType, $(D toType)) $(RELATIVE_LINK2 initSymbol, $(D initSymbol)) $(RELATIVE_LINK2 parameters, $(D parameters)) + $(RELATIVE_LINK2 fullyQualifiedName, $(D fullyQualifiedName)) $(GNAME TraitsArguments): $(GLINK TraitsArgument) @@ -346,7 +352,7 @@ static assert(!__traits(isCopyable, T)); $(H3 $(GNAME isPOD)) $(P Takes one argument, which must be a type. It returns - $(D true) if the type is a $(DDSUBLINK glossary, pod, POD) type, otherwise $(D false).) + $(D true) if the type is a $(DDSUBLINK spec/glossary, pod, POD) type, otherwise $(D false).) $(H3 $(GNAME toType)) @@ -404,7 +410,45 @@ static assert(__traits(isZeroInit, void)); $(H3 $(GNAME hasCopyConstructor)) - $(P The argument is a type. If it is a struct with a copy constructor, returns $(D true). Otherwise, return $(D false). Note that a copy constructor is distinct from a postblit. + $(P The argument is a type. + If it is a struct with a copy constructor, returns $(D true). Otherwise, return $(D false). + A copy constructor is distinct from a move constructor or a postblit. + ) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- + +import std.stdio; + +struct S { } + +class C { } + +struct P +{ + this(ref P rhs) {} // copy constructor +} + +struct B +{ + this(this) {} // postblit +} + +void main() +{ + writeln(__traits(hasCopyConstructor, S)); // false + writeln(__traits(hasCopyConstructor, C)); // false + writeln(__traits(hasCopyConstructor, P)); // true + writeln(__traits(hasCopyConstructor, B)); // false, this is a postblit +} +--- +) + +$(H3 $(GNAME hasMoveConstructor)) + + $(P The argument is a type. + If it is a struct with a move constructor, returns $(D true). Otherwise, return $(D false). + A move constructor is distinct from a copy constructor or a postblit. ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE @@ -414,28 +458,27 @@ import std.stdio; struct S { + this(S rhs) {} // move constructor } -class C -{ -} +class C { } struct P { - this(ref P rhs) {} + this(ref P rhs) {} // copy constructor } struct B { - this(this) {} + this(this) {} // postblit } void main() { - writeln(__traits(hasCopyConstructor, S)); // false - writeln(__traits(hasCopyConstructor, C)); // false - writeln(__traits(hasCopyConstructor, P)); // true - writeln(__traits(hasCopyConstructor, B)); // false, this is a postblit + writeln(__traits(hasMoveConstructor, S)); // true + writeln(__traits(hasMoveConstructor, C)); // false + writeln(__traits(hasMoveConstructor, P)); // false + writeln(__traits(hasMoveConstructor, B)); // false, this is a postblit } --- ) @@ -633,13 +676,13 @@ $(H3 $(GNAME initSymbol)) $(P Takes a single argument, which must evaluate to a `class`, `struct` or `union` type. Returns a `const(void)[]` that holds the initial state of any instance of the supplied type. The slice is constructed for any type `T` as follows: + ) - `ptr` points to either the initializer symbol of `T` - or `null` if `T` is a zero-initialized struct / unions. + or `null` if `T` is a $(RELATIVE_LINK2 isZeroInit, zero-initialized) struct/union. - - `length` is equal to the size of an instance, i.e. `T.sizeof` for structs / unions and - $(RELATIVE_LINK2 classInstanceSize, $(D __traits(classInstanceSize, T)`)) for classes. - ) + - `length` is equal to the size of an instance, i.e. `T.sizeof` for a struct/union and + $(RELATIVE_LINK2 classInstanceSize, $(D __traits(classInstanceSize, T))) for a class. $(P This trait matches the behaviour of `TypeInfo.initializer()` but can also be used when @@ -647,11 +690,14 @@ $(H3 $(GNAME initSymbol)) ) $(P - This traits is not available during $(DDSUBLINK glossary, ctfe, CTFE) because the actual address + This trait is not available during $(DDSUBLINK spec/glossary, ctfe, CTFE) because the actual address of the initializer symbol will be set by the linker and hence is not available at compile time. ) + $(SPEC_RUNNABLE_EXAMPLE_RUN --- + import core.stdc.stdlib; + class C { int i = 4; @@ -665,12 +711,14 @@ $(H3 $(GNAME initSymbol)) void* ptr = malloc(initSym.length); scope (exit) free(ptr); - ptr[0..initSym.length] = initSym[]; + // Note: allocated memory will only be written to through `c`, so cast is safe + ptr[0..initSym.length] = cast(void[]) initSym[]; C c = cast(C) ptr; assert(c.i == 4); } --- + ) $(H2 $(LNAME2 functions, Function Traits)) @@ -693,8 +741,8 @@ static assert(!__traits(isDisabled, Foo.bar)); --- ) - $(P For any other declaration even if `@disable` is a syntactically valid - attribute `false` is returned because the annotation has no effect.) + $(P For any other declaration, even if `@disable` is a syntactically valid + attribute, `false` is returned because the annotation has no effect.) $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- @@ -1076,12 +1124,26 @@ static assert(__traits(getParameterStorageClasses, foo(p, a, b, c), 3)[0] == "la $(H3 $(GNAME parameters)) $(P May only be used inside a function. Takes no arguments, and returns - a sequence of the enclosing function's parameters.) - - $(P If the function is nested, the parameters returned are those of the - inner function, not the outer one.) + an $(DDSUBLINK spec/template, lvalue-sequences, lvalue sequence) of the + enclosing function's parameters.) + $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- + alias AliasSeq(A...) = A; + + void f(int n, char c) + { + alias PS = __traits(parameters); + PS[0]++; // increment n + static assert(is(typeof(PS) == AliasSeq!(int, char))); + + // output parameter names + static foreach (i, p; PS) + { + pragma(msg, __traits(identifier, p)); + } + } + int add(int x, int y) { return x + y; @@ -1093,7 +1155,13 @@ $(H3 $(GNAME parameters)) // equivalent to; //return add(x, y); } + --- + ) + $(P If the function is nested, the parameters returned are those of the + inner function, not the outer one.) + + --- int nestedExample(int x) { // outer function's parameters @@ -1108,7 +1176,8 @@ $(H3 $(GNAME parameters)) return add(x, x); } - + --- + --- class C { int opApply(int delegate(size_t, C) dg) @@ -1135,6 +1204,22 @@ $(H3 $(GNAME parameters)) $(H2 $(LNAME2 symbols, Symbol Traits)) +$(H3 $(GNAME fullyQualifiedName)) + + $(P Gets the fully qualified name of a type or symbol.) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +----------------- +module myModule; + +int i; +static assert(__traits(fullyQualifiedName, i) == "myModule.i"); + +struct MyStruct {} +static assert(__traits(fullyQualifiedName, const MyStruct[]) == "const(myModule.MyStruct[])"); +----------------- +) + $(H3 $(GNAME isNested)) $(P Takes one argument. @@ -1147,14 +1232,34 @@ $(H3 $(GNAME isNested)) $(H3 $(GNAME isFuture)) $(P Takes one argument. It returns `true` if the argument is a symbol - marked with the `@future` keyword, otherwise `false`. Currently, only - functions and variable declarations have support for the `@future` keyword.) + marked with the $(DDSUBLINK spec/attribute, future, `@__future` attribute), + otherwise `false`. Currently, only + functions and variable declarations have support for the `@__future` keyword.) $(H3 $(GNAME isDeprecated)) $(P Takes one argument. It returns `true` if the argument is a symbol marked with the `deprecated` keyword, otherwise `false`.) +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +deprecated("No longer supported") +int i; + +struct A +{ + int foo() { return 1; } + + deprecated("please use foo") + int bar() { return 1; } +} + +static assert(__traits(isDeprecated, i)); +static assert(!__traits(isDeprecated, A.foo)); +static assert(__traits(isDeprecated, A.bar)); +--- +) + $(H3 $(GNAME isTemplate)) $(P Takes one argument. If that argument or any of its overloads is a template @@ -1164,9 +1269,9 @@ $(H3 $(GNAME isTemplate)) $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- void foo(T)(){} -static assert(__traits(isTemplate,foo)); -static assert(!__traits(isTemplate,foo!int())); -static assert(!__traits(isTemplate,"string")); +static assert(__traits(isTemplate, foo)); +static assert(!__traits(isTemplate, foo!int())); +static assert(!__traits(isTemplate, "string")); --- ) @@ -1201,12 +1306,20 @@ $(H3 $(GNAME isPackage)) otherwise $(D false). ) +$(SPEC_RUNNABLE_EXAMPLE_COMPILE --- import std.algorithm.sorting; static assert(__traits(isPackage, std)); static assert(__traits(isPackage, std.algorithm)); static assert(!__traits(isPackage, std.algorithm.sorting)); --- +) + +$(H3 $(GNAME isCOMClass)) + $(P Takes one argument. If that argument is a symbol that refers to a + $(DDSUBLINK spec/class, ClassDeclaration, class declaration) and is a COM class then $(D true) is retuned, + otherwise $(D false). + ) $(H3 $(GNAME hasMember)) @@ -1230,11 +1343,12 @@ void main() { S s; - writeln(__traits(hasMember, S, "m")); // true - writeln(__traits(hasMember, s, "m")); // true - writeln(__traits(hasMember, S, "y")); // false - writeln(__traits(hasMember, S, "write")); // false, but callable like a member via UFCS - writeln(__traits(hasMember, int, "sizeof")); // true + static assert(__traits(hasMember, S, "m")); + static assert(__traits(hasMember, s, "m")); + static assert(!__traits(hasMember, S, "y")); + static assert(!__traits(hasMember, S, "write")); // false, but callable like a member via UFCS + static assert(__traits(hasMember, int, "sizeof")); + static assert(__traits(hasMember, 5, "sizeof")); } --- ) @@ -1244,13 +1358,10 @@ $(H3 $(GNAME identifier)) $(P Takes one argument, a symbol. Returns the identifier for that symbol as a string literal. ) -$(SPEC_RUNNABLE_EXAMPLE_RUN +$(SPEC_RUNNABLE_EXAMPLE_COMPILE --- int var = 123; -pragma(msg, typeof(var)); // int -pragma(msg, typeof(__traits(identifier, var))); // string -writeln(var); // 123 -writeln(__traits(identifier, var)); // "var" +static assert(__traits(identifier, var) == "var"); --- ) @@ -1287,6 +1398,53 @@ tuple((Foo)) ) ) +$(SECTION3 $(GNAME getBitfieldOffset), + $(P Takes one argument, a qualified name that resolve to a field in a struct or class. + ) + $(P If the field is a bitfield, it returns as a `uint` the bit number of the least significant + bit in the field. The rightmost bit is at offset 0, the leftmost bit is at offset 31 (for + 32 bit int fields). + ) + $(P If the field is a not bitfield, it returns as a `uint` the number 0. + ) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +struct S +{ + int a,b; + int :2, c:3; +} + +static assert(__traits(getBitfieldOffset, S.b) == 0); +static assert(__traits(getBitfieldOffset, S.c) == 2); +--- +) + +) + +$(SECTION3 $(GNAME getBitfieldWidth), + $(P Takes one argument, a qualified name that resolve to a field in a struct or class. + ) + $(P If the field is a bitfield, it returns as a `uint` the width of the bit field as + a number of bits. + ) + $(P If the field is a not bitfield, it returns the number of bits in the type. + ) +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +struct S +{ + int a,b; + int :2, c:3; +} + +static assert(__traits(getBitfieldWidth, S.b) == 32); +static assert(__traits(getBitfieldWidth, S.c) == 3); +--- +) +) + $(H3 $(GNAME getLinkage)) $(P Takes one argument, which is a declaration symbol, or the type of a function, delegate, @@ -1363,13 +1521,13 @@ void main() $(H3 $(GNAME getOverloads)) - $(P The first argument is an aggregate (e.g. struct/class/module). - The second argument is a `string` that matches the name of - the member(s) to return. - The third argument is a `bool`, and is optional. If `true`, the - result will also include template overloads. - The result is a symbol sequence of all the overloads of the supplied name. - ) + * The first argument is an aggregate type or instance, or a module. + * The second argument is a `string` that matches the name of + the member(s) to return. + * The third argument is a `bool`, and is optional. If `true`, the + result will also include template overloads. + * The result is a $(DDSUBLINK spec/template, homogeneous_sequences, symbol sequence) + of all the overloads of the supplied name. $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- @@ -1377,8 +1535,6 @@ import std.stdio; class D { - this() { } - ~this() { } void foo() { } int foo(int) { return 2; } void bar(T)() { return T.init; } @@ -1389,18 +1545,24 @@ void main() { D d = new D(); - foreach (t; __traits(getOverloads, D, "foo")) - writeln(typeid(typeof(t))); + alias fooOverloads = __traits(getOverloads, D, "foo"); + foreach (o; fooOverloads) + writeln(typeid(typeof(o))); - alias b = typeof(__traits(getOverloads, D, "foo")); - foreach (t; b) - writeln(typeid(t)); + // typeof on a symbol sequence gives a type sequence + foreach (T; typeof(fooOverloads)) + writeln(typeid(T)); - auto i = __traits(getOverloads, d, "foo")[1](1); - writeln(i); + // calls d.foo(3) + auto i = __traits(getOverloads, d, "foo")[1](3); + assert(i == 2); - foreach (t; __traits(getOverloads, D, "bar", true)) - writeln(t.stringof); + // pass true to include templates + // calls std.stdio.writeln(i) + __traits(getOverloads, std.stdio, "writeln", true)[0](i); + + foreach (o; __traits(getOverloads, D, "bar", true)) + writeln(o.stringof); } --- ) @@ -1408,10 +1570,10 @@ void main() Prints: $(CONSOLE -void() -int() -void() -int() +void function() +int function(int) +void function() +int function(int) 2 bar(T)() bar(int n) @@ -1473,6 +1635,43 @@ export public ) +$(H3 $(GNAME fullyQualifiedName)) + + $(P Takes one argument, which can be a type, expression, or symbol, and returns a string.) + + $(UL + $(LI A $(D type) returns a string representing the type.) + $(LI A $(D expression) returns a string representing the type of the expression.) + $(LI A $(D symbol) returns a string representing the fully qualified name of the symbol.) + ) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +module plugh; +import std.stdio; + +void main() +{ + auto s = __traits(fullyQualifiedName, int); + writeln(s); + + auto t = __traits(fullyQualifiedName, 1.0); + writeln(t); + + auto u = __traits(fullyQualifiedName, t); + writeln(u); +} +--- +) + + Prints: + +$(CONSOLE +int +double +plugh.main.t +) + $(H3 $(GNAME getProtection)) $(P A backward-compatible alias for $(GLINK getVisibility).) @@ -1507,15 +1706,13 @@ $(H3 $(GNAME getUnitTests)) Takes one argument, a symbol of an aggregate (e.g. struct/class/module). The result is a symbol sequence of all the unit test functions of that aggregate. The functions returned are like normal nested static functions, - $(DDSUBLINK glossary, ctfe, CTFE) will work and + $(DDSUBLINK spec/glossary, ctfe, CTFE) will work and $(DDSUBLINK spec/attribute, uda, UDAs) will be accessible. ) - $(H4 Note:) - - $(P - The -unittest flag needs to be passed to the compiler. If the flag - is not passed $(CODE __traits(getUnitTests)) will always return an + $(NOTE + The `-unittest` flag needs to be passed to the compiler. If the flag + is not passed, $(CODE __traits(getUnitTests)) will always return an empty sequence. ) @@ -1639,7 +1836,8 @@ $(H3 $(GNAME allMembers)) $(P Takes a single argument, which must evaluate to either a module, a struct, a union, a class, an interface, an enum, or a template instantiation. - + ) + $(P A sequence of string literals is returned, each of which is the name of a member of that argument combined with all of the members of its base classes (if the argument is a class). @@ -1730,6 +1928,30 @@ static assert(__traits(isSame, object, object)); alias daz = foo; static assert(__traits(isSame, foo, daz)); --- +) + $(P isSame matches against non-instantiated templates.) + +$(SPEC_RUNNABLE_EXAMPLE_COMPILE +--- +struct Foo(T){ + T x; +} + +struct Bar(T){ + T x; +} + +struct Point(T){ + T x; + T y; +} + +enum isFooOrBar(alias FB) = __traits(isSame, FB, Foo) || __traits(isSame, FB, Bar); + +static assert(isFooOrBar!(Foo)); +static assert(isFooOrBar!(Bar)); +static assert(!isFooOrBar!(Point)); +--- ) $(P The result is `true` if the two arguments are expressions @@ -1845,14 +2067,27 @@ $(H3 $(GNAME compiles)) compile (are semantically correct). The arguments can be symbols, types, or expressions that are syntactically correct. - The arguments cannot be statements or declarations. + The arguments cannot be statements or declarations - instead + these can be wrapped in a $(DDSUBLINK spec/expression, function_literals, + function literal) expression. ) $(P If there are no arguments, the result is $(D false).) $(SPEC_RUNNABLE_EXAMPLE_COMPILE --- -import std.stdio; +static assert(!__traits(compiles)); +static assert(__traits(compiles, 1 + 1)); // expression +static assert(__traits(compiles, typeof(1))); // type +static assert(__traits(compiles, object)); // symbol +static assert(__traits(compiles, 1, 2, 3, int, long)); +static assert(!__traits(compiles, 3[1])); // semantic error +static assert(!__traits(compiles, 1, 2, 3, int, long, 3[1])); + +enum n = 3; +// wrap a declaration/statement in a function literal +static assert(__traits(compiles, { int[n] arr; })); +static assert(!__traits(compiles, { foreach (e; n) {} })); struct S { @@ -1860,29 +2095,23 @@ struct S int s2; } -int foo(); -int bar(); +static assert(__traits(compiles, S.s1 = 0)); +static assert(!__traits(compiles, S.s2 = 0)); +static assert(!__traits(compiles, S.s3)); -void main() -{ - writeln(__traits(compiles)); // false - writeln(__traits(compiles, foo)); // true - writeln(__traits(compiles, foo + 1)); // true - writeln(__traits(compiles, &foo + 1)); // false - writeln(__traits(compiles, typeof(1))); // true - writeln(__traits(compiles, S.s1)); // true - writeln(__traits(compiles, S.s3)); // false - writeln(__traits(compiles, 1,2,3,int,long,std)); // true - writeln(__traits(compiles, 3[1])); // false - writeln(__traits(compiles, 1,2,3,int,long,3[1])); // false -} +int foo(); + +static assert(__traits(compiles, foo)); +static assert(__traits(compiles, foo + 1)); // call foo with optional parens +static assert(!__traits(compiles, &foo + 1)); --- ) $(P This is useful for:) $(UL - $(LI Giving better error messages inside generic code than + $(LI Giving better error messages (using $(DDSUBLINK spec/version, static-assert, + `static assert`)) inside generic code than the sometimes hard to follow compiler ones.) $(LI Doing a finer grained specialization than template partial specialization allows for.) @@ -1891,5 +2120,5 @@ void main() $(SPEC_SUBNAV_PREV_NEXT version, Conditional Compilation, errors, Error Handling) Macros: - CHAPTER=25 + CHAPTER=26 TITLE=Traits diff --git a/tests/tc_traits/expected.txt b/tests/tc_traits/expected.txt index 631b258..e645c5e 100644 --- a/tests/tc_traits/expected.txt +++ b/tests/tc_traits/expected.txt @@ -5,8 +5,11 @@ classInstanceAlignment k classInstanceSize k compiles k derivedMembers k +fullyQualifiedName k getAliasThis k getAttributes k +getBitfieldOffset k +getBitfieldWidth k getCppNamespaces k getFunctionAttributes k getFunctionVariadicStyle k @@ -25,6 +28,7 @@ getVirtualMethods k getVisibility k hasCopyConstructor k hasMember k +hasMoveConstructor k hasPostblit k identifier k initSymbol k @@ -32,6 +36,7 @@ isAbstractClass k isAbstractFunction k isArithmetic k isAssociativeArray k +isCOMClass k isCopyable k isDeprecated k isDisabled k