update constants
This commit is contained in:
parent
a9de09c4dc
commit
932adb3313
|
@ -49,9 +49,9 @@ pragma(ident) // influence block of statements
|
|||
-----------------
|
||||
|
||||
$(P The kind of pragma it is determined by the $(I Identifier).
|
||||
$(I ExpressionList) is a comma-separated list of
|
||||
$(GLINK2 expression, ArgumentList) is a comma-separated list of
|
||||
$(ASSIGNEXPRESSION)s. The $(ASSIGNEXPRESSION)s must be
|
||||
parsable as expressions, but what they mean semantically
|
||||
parsable as expressions, but their meaning
|
||||
is up to the individual pragma semantics.
|
||||
)
|
||||
|
||||
|
@ -62,18 +62,19 @@ $(P All implementations must support these, even if by just ignoring them:)
|
|||
$(UL
|
||||
$(LI $(LINK2 #inline, pragma inline))
|
||||
$(LI $(LINK2 #lib, pragma lib))
|
||||
$(LI $(LINK2 #linkerDirective, pragma linkerDirective))
|
||||
$(LI $(LINK2 #mangle, pragma mangle))
|
||||
$(LI $(LINK2 #msg, pragma msg))
|
||||
$(LI $(LINK2 #startaddress, pragma startaddress))
|
||||
)
|
||||
|
||||
$(DL
|
||||
$(IMPLEMENTATION_DEFINED An implementation may ignore these pragmas.)
|
||||
|
||||
$(DT $(LNAME2 inline, $(D inline)))
|
||||
$(DD $(P Affects whether functions are inlined or not. If at the declaration level, it
|
||||
$(H3 $(LNAME2 inline, $(D pragma inline)))
|
||||
|
||||
$(P Affects whether functions are inlined or not. If at the declaration level, it
|
||||
affects the functions declared in the block it controls. If inside a function, it
|
||||
affects the function it is enclosed by. If there are multiple pragma inlines in a function,
|
||||
the lexically last one takes effect.)
|
||||
affects the function it is enclosed by.)
|
||||
|
||||
$(P It takes three forms:)
|
||||
$(OL
|
||||
|
@ -81,8 +82,7 @@ $(UL
|
|||
---
|
||||
pragma(inline)
|
||||
---
|
||||
Sets the behavior to match the default behavior set by the compiler switch
|
||||
$(DDSUBLINK dmd, switch-inline, $(TT -inline)).
|
||||
Sets the behavior to match the implementation's default behavior.
|
||||
)
|
||||
$(LI
|
||||
---
|
||||
|
@ -94,12 +94,16 @@ pragma(inline, false)
|
|||
---
|
||||
pragma(inline, true)
|
||||
---
|
||||
If a function cannot be inlined with the $(DDSUBLINK dmd, switch-inline, $(TT -inline))
|
||||
switch, an error message is issued. This is expected to be improved in the future to causing
|
||||
functions to always be inlined regardless of compiler switch settings. Whether a compiler can
|
||||
inline a particular function or not is implementation defined.
|
||||
Always inline the functions.
|
||||
)
|
||||
)
|
||||
|
||||
$(P There can be only zero or one $(I AssignExpression)s. If one is there, it must
|
||||
be `true`, `false`, or an integer value. An integer value is implicitly converted
|
||||
to a bool.)
|
||||
|
||||
$(P If there are multiple pragma inlines in a function,
|
||||
the lexically last one takes effect.)
|
||||
---
|
||||
pragma(inline):
|
||||
int foo(int x) // foo() is never inlined
|
||||
|
@ -110,52 +114,96 @@ int foo(int x) // foo() is never inlined
|
|||
return x + 3;
|
||||
}
|
||||
---
|
||||
|
||||
$(IMPLEMENTATION_DEFINED
|
||||
$(OL
|
||||
$(LI The default inline behavior is typically selectable with a compiler switch
|
||||
such as $(DDSUBLINK dmd, switch-inline, $(TT -inline).))
|
||||
$(LI Whether a particular function can be inlined or not is implementation defined.)
|
||||
$(LI What happens for `pragma(inline, true)` if the function cannot be inlined.
|
||||
An error message is typical.)
|
||||
))
|
||||
|
||||
$(H3 $(LNAME2 lib, $(D pragma lib)))
|
||||
|
||||
$(P There must be one $(ASSIGNEXPRESSION) and it must evaluate at compile time to a string literal.
|
||||
)
|
||||
|
||||
|
||||
$(DT $(LNAME2 lib, $(D lib)))
|
||||
$(DD Inserts a directive in the object file to link in the library
|
||||
specified by the $(ASSIGNEXPRESSION).
|
||||
The $(ASSIGNEXPRESSION)s must be a string literal:
|
||||
-----------------
|
||||
pragma(lib, "foo.lib");
|
||||
-----------------
|
||||
|
||||
$(IMPLEMENTATION_DEFINED
|
||||
Typically, the string literal specifies the file name of a library file. This name
|
||||
is inserted into the generated object file, or otherwise is passed to the linker,
|
||||
so the linker automatically links in that library.
|
||||
)
|
||||
|
||||
$(H3 $(LNAME2 linkerDirective, $(D pragma linkerDirective)))
|
||||
|
||||
$(DT $(LNAME2 mangle, $(D mangle)))
|
||||
$(DD Overrides the default mangling for a symbol. It's only effective
|
||||
$(P There must be one $(ASSIGNEXPRESSION) and it must evaluate at compile time to a string literal.
|
||||
)
|
||||
-----------------
|
||||
pragma(linkerDirective, "/FAILIFMISMATCH:_ITERATOR_DEBUG_LEVEL=2");
|
||||
-----------------
|
||||
|
||||
$(IMPLEMENTATION_DEFINED
|
||||
$(P The string literal specifies a linker directive to be embedded in the generated object file.)
|
||||
|
||||
$(P Linker directives are only supported for MS-COFF output.)
|
||||
)
|
||||
|
||||
$(H3 $(LNAME2 mangle, $(D pragma mangle)))
|
||||
|
||||
$(P Overrides the default mangling for a symbol.)
|
||||
|
||||
$(P There must be one $(ASSIGNEXPRESSION) and it must evaluate at compile time to a string literal.
|
||||
)
|
||||
|
||||
$(IMPLEMENTATION_DEFINED On macOS and Win32, an extra underscore (`_`) is prepended to the string
|
||||
since 2.079, as is done by the C/C++ toolchain. This allows using the same `pragma(mangle)`
|
||||
for all compatible (POSIX in one case, win64 in another) platforms instead of having to special-case.
|
||||
)
|
||||
|
||||
$(IMPLEMENTATION_DEFINED It's only effective
|
||||
when the symbol is a function declaration or a variable declaration.
|
||||
For example this allows linking to a symbol which is a D keyword, which would normally
|
||||
be disallowed as a symbol name:
|
||||
)
|
||||
-----------------
|
||||
pragma(mangle, "body")
|
||||
extern(C) void body_func();
|
||||
-----------------
|
||||
)
|
||||
|
||||
|
||||
$(DT $(LNAME2 msg, $(D msg)))
|
||||
$(DD Constructs a message from the arguments and prints to the standard error stream while compiling:
|
||||
$(H3 $(LNAME2 msg, $(D pragma msg)))
|
||||
|
||||
$(P Constructs a message from the $(I ArgumentList).)
|
||||
|
||||
-----------------
|
||||
pragma(msg, "compiling...", 1, 1.0);
|
||||
-----------------
|
||||
)
|
||||
|
||||
$(IMPLEMENTATION_DEFINED The arguments are typically presented to the user during compilation,
|
||||
such as by printing them to the standard error stream.)
|
||||
|
||||
|
||||
$(DT $(LNAME2 startaddress, $(D startaddress)))
|
||||
$(DD Puts a directive into the object file saying that the
|
||||
function specified in the first argument will be the
|
||||
start address for the program:
|
||||
$(H3 $(LNAME2 startaddress, $(D pragma startaddress)))
|
||||
|
||||
$(P There must be one $(ASSIGNEXPRESSION) and it must evaluate at compile time to a function symbol.)
|
||||
|
||||
$(IMPLEMENTATION_DEFINED The function symbol specifies the start address for the program.
|
||||
The symbol is inserted into the object file or is otherwise presented to the linker to
|
||||
set the start address.
|
||||
This is not normally used for application level programming,
|
||||
but is for specialized systems work.
|
||||
For applications code, the start address is taken care of
|
||||
by the runtime library.
|
||||
|
||||
-----------------
|
||||
void foo() { ... }
|
||||
pragma(startaddress, foo);
|
||||
-----------------
|
||||
This is not normally used for application level programming,
|
||||
but is for specialized systems work.
|
||||
For applications code, the start address is taken care of
|
||||
by the runtime library.
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
$(H2 $(LNAME2 vendor_specific_pragmas, Vendor Specific Pragmas))
|
||||
|
@ -165,22 +213,28 @@ $(H2 $(LNAME2 vendor_specific_pragmas, Vendor Specific Pragmas))
|
|||
to version identifiers:
|
||||
)
|
||||
|
||||
-----------------
|
||||
pragma(DigitalMars_funky_extension) { ... }
|
||||
-----------------
|
||||
---
|
||||
pragma(DigitalMars_extension) { ... }
|
||||
---
|
||||
|
||||
$(P Compilers must diagnose an error for unrecognized $(I Pragma)s,
|
||||
even if they are vendor specific ones. This implies that vendor
|
||||
specific pragmas should be wrapped in version statements:
|
||||
)
|
||||
$(P Implementations must diagnose an error for unrecognized $(I Pragma)s,
|
||||
even if they are vendor specific ones.
|
||||
)
|
||||
|
||||
-----------------
|
||||
version (DigitalMars)
|
||||
{
|
||||
pragma(DigitalMars_funky_extension)
|
||||
{ ... }
|
||||
}
|
||||
-----------------
|
||||
$(IMPLEMENTATION_DEFINED Vendor specific pragmas.)
|
||||
|
||||
|
||||
$(BEST_PRACTICE vendor
|
||||
specific pragmas should be wrapped in version statements
|
||||
|
||||
---
|
||||
version (DigitalMars)
|
||||
{
|
||||
pragma(DigitalMars_extension)
|
||||
{ ... }
|
||||
}
|
||||
---
|
||||
)
|
||||
|
||||
$(SPEC_SUBNAV_PREV_NEXT attribute, Attributes, expression, Expressions)
|
||||
)
|
||||
|
|
|
@ -18,52 +18,54 @@ $(GNAME TraitsExpression):
|
|||
$(D __traits) $(D $(LPAREN)) $(GLINK TraitsKeyword) $(D ,) $(GLINK TraitsArguments) $(D $(RPAREN))
|
||||
|
||||
$(GNAME TraitsKeyword):
|
||||
$(GBLINK isAbstractClass)
|
||||
$(GBLINK isArithmetic)
|
||||
$(GBLINK isAssociativeArray)
|
||||
$(GBLINK isFinalClass)
|
||||
$(GBLINK isPOD)
|
||||
$(GBLINK isNested)
|
||||
$(GBLINK isFuture)
|
||||
$(GBLINK isDeprecated)
|
||||
$(GBLINK isFloating)
|
||||
$(GBLINK isIntegral)
|
||||
$(GBLINK isScalar)
|
||||
$(GBLINK isStaticArray)
|
||||
$(GBLINK isUnsigned)
|
||||
$(GBLINK isDisabled)
|
||||
$(GBLINK isVirtualFunction)
|
||||
$(GBLINK isVirtualMethod)
|
||||
$(GBLINK isAbstractFunction)
|
||||
$(GBLINK isFinalFunction)
|
||||
$(GBLINK isStaticFunction)
|
||||
$(GBLINK isOverrideFunction)
|
||||
$(GBLINK isTemplate)
|
||||
$(GBLINK isRef)
|
||||
$(GBLINK isOut)
|
||||
$(GBLINK isLazy)
|
||||
$(GBLINK hasMember)
|
||||
$(GBLINK identifier)
|
||||
$(GBLINK getAliasThis)
|
||||
$(GBLINK getAttributes)
|
||||
$(GBLINK getFunctionAttributes)
|
||||
$(GBLINK getFunctionVariadicStyle)
|
||||
$(GBLINK getLinkage)
|
||||
$(GBLINK getMember)
|
||||
$(GBLINK getOverloads)
|
||||
$(GBLINK getParameterStorageClasses)
|
||||
$(GBLINK getPointerBitmap)
|
||||
$(GBLINK getProtection)
|
||||
$(GBLINK getVirtualFunctions)
|
||||
$(GBLINK getVirtualMethods)
|
||||
$(GBLINK getUnitTests)
|
||||
$(GBLINK parent)
|
||||
$(GBLINK classInstanceSize)
|
||||
$(GBLINK getVirtualIndex)
|
||||
$(GBLINK allMembers)
|
||||
$(GBLINK derivedMembers)
|
||||
$(GBLINK isSame)
|
||||
$(GBLINK compiles)
|
||||
$(GLINK isAbstractClass)
|
||||
$(GLINK isArithmetic)
|
||||
$(GLINK isAssociativeArray)
|
||||
$(GLINK isFinalClass)
|
||||
$(GLINK isPOD)
|
||||
$(GLINK isNested)
|
||||
$(GLINK isFuture)
|
||||
$(GLINK isDeprecated)
|
||||
$(GLINK isFloating)
|
||||
$(GLINK isIntegral)
|
||||
$(GLINK isScalar)
|
||||
$(GLINK isStaticArray)
|
||||
$(GLINK isUnsigned)
|
||||
$(GLINK isDisabled)
|
||||
$(GLINK isVirtualFunction)
|
||||
$(GLINK isVirtualMethod)
|
||||
$(GLINK isAbstractFunction)
|
||||
$(GLINK isFinalFunction)
|
||||
$(GLINK isStaticFunction)
|
||||
$(GLINK isOverrideFunction)
|
||||
$(GLINK isTemplate)
|
||||
$(GLINK isRef)
|
||||
$(GLINK isOut)
|
||||
$(GLINK isLazy)
|
||||
$(GLINK isReturnOnStack)
|
||||
$(GLINK isZeroInit)
|
||||
$(GLINK hasMember)
|
||||
$(GLINK identifier)
|
||||
$(GLINK getAliasThis)
|
||||
$(GLINK getAttributes)
|
||||
$(GLINK getFunctionAttributes)
|
||||
$(GLINK getFunctionVariadicStyle)
|
||||
$(GLINK getLinkage)
|
||||
$(GLINK getMember)
|
||||
$(GLINK getOverloads)
|
||||
$(GLINK getParameterStorageClasses)
|
||||
$(GLINK getPointerBitmap)
|
||||
$(GLINK getProtection)
|
||||
$(GLINK getVirtualFunctions)
|
||||
$(GLINK getVirtualMethods)
|
||||
$(GLINK getUnitTests)
|
||||
$(GLINK parent)
|
||||
$(GLINK classInstanceSize)
|
||||
$(GLINK getVirtualIndex)
|
||||
$(GLINK allMembers)
|
||||
$(GLINK derivedMembers)
|
||||
$(GLINK isSame)
|
||||
$(GLINK compiles)
|
||||
|
||||
$(GNAME TraitsArguments):
|
||||
$(GLINK TraitsArgument)
|
||||
|
@ -74,18 +76,6 @@ $(GNAME TraitsArgument):
|
|||
$(GLINK2 declaration, Type)
|
||||
)
|
||||
|
||||
$(P Additionally special keywords are provided for debugging purposes:)
|
||||
|
||||
$(GRAMMAR
|
||||
$(GNAME SpecialKeyword):
|
||||
$(D $(RELATIVE_LINK2 specialkeywords, __FILE__))
|
||||
$(D $(RELATIVE_LINK2 specialkeywords, __FILE_FULL_PATH__))
|
||||
$(D $(RELATIVE_LINK2 specialkeywords, __MODULE__))
|
||||
$(D $(RELATIVE_LINK2 specialkeywords, __LINE__))
|
||||
$(D $(RELATIVE_LINK2 specialkeywords, __FUNCTION__))
|
||||
$(D $(RELATIVE_LINK2 specialkeywords, __PRETTY_FUNCTION__))
|
||||
)
|
||||
|
||||
$(H2 $(GNAME isArithmetic))
|
||||
|
||||
$(P If the arguments are all either types that are arithmetic types,
|
||||
|
@ -411,6 +401,68 @@ static assert(!__traits(isTemplate,foo!int()));
|
|||
static assert(!__traits(isTemplate,"string"));
|
||||
---
|
||||
|
||||
$(H2 $(GNAME isZeroInit))
|
||||
|
||||
$(P Takes one argument which must be a type. If the type's
|
||||
$(DDSUBLINK spec/property, init, default initializer) is all zero
|
||||
bits then `true` is returned, otherwise `false`.)
|
||||
|
||||
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
|
||||
---
|
||||
struct S1 { int x; }
|
||||
struct S2 { int x = -1; }
|
||||
|
||||
static assert(__traits(isZeroInit, S1));
|
||||
static assert(!__traits(isZeroInit, S2));
|
||||
|
||||
void test()
|
||||
{
|
||||
int x = 3;
|
||||
static assert(__traits(isZeroInit, typeof(x)));
|
||||
}
|
||||
|
||||
// `isZeroInit` will always return true for a class C
|
||||
// because `C.init` is null reference.
|
||||
|
||||
class C { int x = -1; }
|
||||
|
||||
static assert(__traits(isZeroInit, C));
|
||||
---
|
||||
)
|
||||
|
||||
$(H2 $(GNAME isReturnOnStack))
|
||||
|
||||
$(P
|
||||
Takes one argument which must either be a function symbol, function literal,
|
||||
a delegate, or a function pointer.
|
||||
It returns a `bool` which is `true` if the return value of the function is
|
||||
returned on the stack via a pointer to it passed as a hidden extra
|
||||
parameter to the function.
|
||||
)
|
||||
|
||||
---
|
||||
struct S { int[20] a; }
|
||||
int test1();
|
||||
S test2();
|
||||
|
||||
static assert(__traits(isReturnOnStack, test1) == false);
|
||||
static assert(__traits(isReturnOnStack, test2) == true);
|
||||
---
|
||||
|
||||
$(IMPLEMENTATION_DEFINED
|
||||
This is determined by the function ABI calling convention in use,
|
||||
which is often complex.
|
||||
)
|
||||
|
||||
$(BEST_PRACTICE This has applications in:
|
||||
$(OL
|
||||
$(LI Returning values in registers is often faster, so this can be used as
|
||||
a check on a hot function to ensure it is using the fastest method.)
|
||||
$(LI When using inline assembly to correctly call a function.)
|
||||
$(LI Testing that the compiler does this correctly is normally hackish and awkward,
|
||||
this enables efficient, direct, and simple testing.)
|
||||
))
|
||||
|
||||
$(H2 $(GNAME hasMember))
|
||||
|
||||
$(P The first argument is a type that has members, or
|
||||
|
@ -426,6 +478,8 @@ import std.stdio;
|
|||
struct S
|
||||
{
|
||||
int m;
|
||||
|
||||
import std.stdio; // imports write
|
||||
}
|
||||
|
||||
void main()
|
||||
|
@ -435,6 +489,7 @@ void main()
|
|||
writeln(__traits(hasMember, S, "m")); // true
|
||||
writeln(__traits(hasMember, s, "m")); // true
|
||||
writeln(__traits(hasMember, S, "y")); // false
|
||||
writeln(__traits(hasMember, S, "write")); // true
|
||||
writeln(__traits(hasMember, int, "sizeof")); // true
|
||||
}
|
||||
---
|
||||
|
@ -578,8 +633,8 @@ pragma(msg, __traits(getFunctionAttributes, (int x) @trusted { return x * 2; }))
|
|||
|
||||
$(H2 $(GNAME getLinkage))
|
||||
|
||||
$(P Takes one argument, which is a declaration symbol, or the type of a function,
|
||||
delegate, or pointer to function.
|
||||
$(P Takes one argument, which is a declaration symbol, or the type of a function, delegate,
|
||||
pointer to function, struct, class, or interface.
|
||||
Returns a string representing the $(LINK2 attribute.html#LinkageAttribute, LinkageAttribute)
|
||||
of the declaration.
|
||||
The string is one of:
|
||||
|
@ -601,6 +656,14 @@ alias aliasc = fooc;
|
|||
|
||||
static assert(__traits(getLinkage, fooc) == "C");
|
||||
static assert(__traits(getLinkage, aliasc) == "C");
|
||||
|
||||
extern (C++) struct FooCPPStruct {}
|
||||
extern (C++) class FooCPPClass {}
|
||||
extern (C++) interface FooCPPInterface {}
|
||||
|
||||
static assert(__traits(getLinkage, FooCPPStruct) == "C++");
|
||||
static assert(__traits(getLinkage, FooCPPClass) == "C++");
|
||||
static assert(__traits(getLinkage, FooCPPInterface) == "C++");
|
||||
---
|
||||
|
||||
$(H2 $(GNAME getMember))
|
||||
|
@ -635,9 +698,11 @@ void main()
|
|||
$(H2 $(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
|
||||
one of the functions in that aggregate.
|
||||
The result is a tuple of all the overloads of that function.
|
||||
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 tuple of all the overloads of the supplied name.
|
||||
)
|
||||
|
||||
---
|
||||
|
@ -649,6 +714,8 @@ class D
|
|||
~this() { }
|
||||
void foo() { }
|
||||
int foo(int) { return 2; }
|
||||
void bar(T)() { return T.init; }
|
||||
class bar(int n) {}
|
||||
}
|
||||
|
||||
void main()
|
||||
|
@ -664,6 +731,9 @@ void main()
|
|||
|
||||
auto i = __traits(getOverloads, d, "foo")[1](1);
|
||||
writeln(i);
|
||||
|
||||
foreach (t; __traits(getOverloads, D, "bar", true))
|
||||
writeln(t.stringof);
|
||||
}
|
||||
---
|
||||
|
||||
|
@ -675,6 +745,8 @@ int()
|
|||
void()
|
||||
int()
|
||||
2
|
||||
bar(T)()
|
||||
bar(int n)
|
||||
)
|
||||
|
||||
$(H2 $(GNAME getParameterStorageClasses))
|
||||
|
@ -705,7 +777,7 @@ $(H2 $(GNAME getPointerBitmap))
|
|||
The result is an array of $(D size_t) describing the memory used by an instance of the given type.
|
||||
)
|
||||
$(P The first element of the array is the size of the type (for classes it is
|
||||
the $(GBLINK classInstanceSize)).)
|
||||
the $(GLINK classInstanceSize)).)
|
||||
$(P The following elements describe the locations of GC managed pointers within the
|
||||
memory occupied by an instance of the type.
|
||||
For type T, there are $(D T.sizeof / size_t.sizeof) possible pointers represented
|
||||
|
@ -1020,6 +1092,76 @@ void main()
|
|||
$(P If the two arguments are expressions made up of literals
|
||||
or enums that evaluate to the same value, true is returned.)
|
||||
|
||||
$(P If the two arguments are both lambda functions (or aliases
|
||||
to lambda functions), then they are compared for equality. For
|
||||
the comparison to be computed correctly, the following conditions
|
||||
must be met for both lambda functions:)
|
||||
|
||||
$(OL
|
||||
$(LI The lambda function arguments must not have a template
|
||||
instantiation as an explicit argument type. Any other argument
|
||||
types (basic, user-defined, template) are supported.)
|
||||
$(LI The lambda function body must contain a single expression
|
||||
(no return statement) which contains only numeric values,
|
||||
manifest constants, enum values, function arguments and function
|
||||
calls. If the expression contains local variables or return
|
||||
statements, the function is considered incomparable.)
|
||||
)
|
||||
|
||||
$(P If these constraints aren't fulfilled, the function is considered
|
||||
incomparable and `isSame` returns $(D false).)
|
||||
|
||||
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
|
||||
---
|
||||
int f() { return 2; }
|
||||
void test(alias pred)()
|
||||
{
|
||||
// f() from main is a different function from top-level f()
|
||||
static assert(!__traits(isSame, (int a) => a + f(), pred));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
static assert(__traits(isSame, (a, b) => a + b, (c, d) => c + d));
|
||||
static assert(__traits(isSame, a => ++a, b => ++b));
|
||||
static assert(!__traits(isSame, (int a, int b) => a + b, (a, b) => a + b));
|
||||
static assert(__traits(isSame, (a, b) => a + b + 10, (c, d) => c + d + 10));
|
||||
|
||||
// lambdas accessing local variables are considered incomparable
|
||||
int b;
|
||||
static assert(!__traits(isSame, a => a + b, a => a + b));
|
||||
|
||||
// lambdas calling other functions are comparable
|
||||
int f() { return 3;}
|
||||
static assert(__traits(isSame, a => a + f(), a => a + f()));
|
||||
test!((int a) => a + f())();
|
||||
|
||||
class A
|
||||
{
|
||||
int a;
|
||||
this(int a)
|
||||
{
|
||||
this.a = a;
|
||||
}
|
||||
}
|
||||
|
||||
class B
|
||||
{
|
||||
int a;
|
||||
this(int a)
|
||||
{
|
||||
this.a = a;
|
||||
}
|
||||
}
|
||||
|
||||
static assert(__traits(isSame, (A a) => ++a.a, (A b) => ++b.a));
|
||||
// lambdas with different data types are considered incomparable,
|
||||
// even if the memory layout is the same
|
||||
static assert(!__traits(isSame, (A a) => ++a.a, (B a) => ++a.a));
|
||||
}
|
||||
---
|
||||
)
|
||||
|
||||
$(H2 $(GNAME compiles))
|
||||
|
||||
$(P Returns a bool $(D true) if all of the arguments
|
||||
|
@ -1068,55 +1210,6 @@ void main()
|
|||
)
|
||||
|
||||
|
||||
$(H2 $(LNAME2 specialkeywords, Special Keywords))
|
||||
|
||||
$(P $(CODE __FILE__) and $(CODE __LINE__) expand to the source
|
||||
file name and line number at the point of instantiation. The path of
|
||||
the source file is left up to the compiler. )
|
||||
|
||||
$(P $(CODE __FILE_FULL_PATH__) expands to the absolute source
|
||||
file name at the point of instantiation.)
|
||||
|
||||
$(P $(CODE __MODULE__) expands to the module name at the point of
|
||||
instantiation.)
|
||||
|
||||
$(P $(CODE __FUNCTION__) expands to the fully qualified name of the
|
||||
function at the point of instantiation.)
|
||||
|
||||
$(P $(CODE __PRETTY_FUNCTION__) is similar to $(CODE __FUNCTION__),
|
||||
but also expands the function return type, its parameter types,
|
||||
and its attributes.)
|
||||
|
||||
$(P Example usage:)
|
||||
|
||||
-----
|
||||
module test;
|
||||
import std.stdio;
|
||||
|
||||
void test(string file = __FILE__, size_t line = __LINE__,
|
||||
string mod = __MODULE__, string func = __FUNCTION__,
|
||||
string pretty = __PRETTY_FUNCTION__,
|
||||
string fileFullPath = __FILE_FULL_PATH__)
|
||||
{
|
||||
writefln("file: '%s', line: '%s', module: '%s',\nfunction: '%s', " ~
|
||||
"pretty function: '%s',\nfile full path: '%s'",
|
||||
file, line, mod, func, pretty, fileFullPath);
|
||||
}
|
||||
|
||||
int main(string[] args)
|
||||
{
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
-----
|
||||
|
||||
$(P Assuming the file was at /example/test.d, this will output:)
|
||||
|
||||
$(CONSOLE
|
||||
file: 'test.d', line: '13', module: 'test',
|
||||
function: 'test.main', pretty function: 'int test.main(string[] args)',
|
||||
file full path: '/example/test.d'
|
||||
)
|
||||
|
||||
$(SPEC_SUBNAV_PREV_NEXT version, Conditional Compilation, errors, Error Handling)
|
||||
)
|
||||
|
@ -1124,4 +1217,3 @@ $(SPEC_SUBNAV_PREV_NEXT version, Conditional Compilation, errors, Error Handling
|
|||
Macros:
|
||||
CHAPTER=25
|
||||
TITLE=Traits
|
||||
GBLINK=$(RELATIVE_LINK2 $0, $(D $0))
|
||||
|
|
|
@ -13,101 +13,6 @@ import dcd.common.constants : ConstantCompletion;
|
|||
*/
|
||||
immutable ConstantCompletion[] pragmas = [
|
||||
// generated from pragma.dd
|
||||
ConstantCompletion("inline", `$(P Affects whether functions are inlined or not. If at the declaration level, it
|
||||
affects the functions declared in the block it controls. If inside a function, it
|
||||
affects the function it is enclosed by. If there are multiple pragma inlines in a function,
|
||||
the lexically last one takes effect.)
|
||||
|
||||
$(P It takes three forms:)
|
||||
$(OL
|
||||
$(LI
|
||||
---
|
||||
pragma(inline)
|
||||
---
|
||||
Sets the behavior to match the default behavior set by the compiler switch
|
||||
$(DDSUBLINK dmd, switch-inline, $(TT -inline)).
|
||||
)
|
||||
$(LI
|
||||
---
|
||||
pragma(inline, false)
|
||||
---
|
||||
Functions are never inlined.
|
||||
)
|
||||
$(LI
|
||||
---
|
||||
pragma(inline, true)
|
||||
---
|
||||
If a function cannot be inlined with the $(DDSUBLINK dmd, switch-inline, $(TT -inline))
|
||||
switch, an error message is issued. This is expected to be improved in the future to causing
|
||||
functions to always be inlined regardless of compiler switch settings. Whether a compiler can
|
||||
inline a particular function or not is implementation defined.
|
||||
)
|
||||
)
|
||||
---
|
||||
pragma(inline):
|
||||
int foo(int x) // foo() is never inlined
|
||||
{
|
||||
pragma(inline, true);
|
||||
++x;
|
||||
pragma(inline, false); // supercedes the others
|
||||
return x + 3;
|
||||
}
|
||||
---`),
|
||||
ConstantCompletion("lib", `Inserts a directive in the object file to link in the library
|
||||
specified by the $(ASSIGNEXPRESSION).
|
||||
The $(ASSIGNEXPRESSION)s must be a string literal:
|
||||
-----------------
|
||||
pragma(lib, "foo.lib");
|
||||
-----------------`),
|
||||
ConstantCompletion("mangle", `Overrides the default mangling for a symbol. It's only effective
|
||||
when the symbol is a function declaration or a variable declaration.
|
||||
For example this allows linking to a symbol which is a D keyword, which would normally
|
||||
be disallowed as a symbol name:
|
||||
-----------------
|
||||
pragma(mangle, "body")
|
||||
extern(C) void body_func();
|
||||
-----------------`),
|
||||
ConstantCompletion("msg", `Constructs a message from the arguments and prints to the standard error stream while compiling:
|
||||
-----------------
|
||||
pragma(msg, "compiling...", 1, 1.0);
|
||||
-----------------`),
|
||||
ConstantCompletion("startaddress", `Puts a directive into the object file saying that the
|
||||
function specified in the first argument will be the
|
||||
start address for the program:
|
||||
-----------------
|
||||
void foo() { ... }
|
||||
pragma(startaddress, foo);
|
||||
-----------------
|
||||
This is not normally used for application level programming,
|
||||
but is for specialized systems work.
|
||||
For applications code, the start address is taken care of
|
||||
by the runtime library.
|
||||
)
|
||||
)
|
||||
|
||||
$(H2 $(LNAME2 vendor_specific_pragmas, Vendor Specific Pragmas))
|
||||
|
||||
$(P Vendor specific pragma $(I Identifier)s can be defined if they
|
||||
are prefixed by the vendor's trademarked name, in a similar manner
|
||||
to version identifiers:
|
||||
)
|
||||
|
||||
-----------------
|
||||
pragma(DigitalMars_funky_extension) { ... }
|
||||
-----------------
|
||||
|
||||
$(P Compilers must diagnose an error for unrecognized $(I Pragma)s,
|
||||
even if they are vendor specific ones. This implies that vendor
|
||||
specific pragmas should be wrapped in version statements:
|
||||
)
|
||||
|
||||
-----------------
|
||||
version (DigitalMars)
|
||||
{
|
||||
pragma(DigitalMars_funky_extension)
|
||||
{ ... }
|
||||
}
|
||||
-----------------`),
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -197,57 +102,6 @@ $(LI Giving better error messages inside generic code than
|
|||
the sometimes hard to follow compiler ones.)
|
||||
$(LI Doing a finer grained specialization than template
|
||||
partial specialization allows for.)
|
||||
)
|
||||
|
||||
|
||||
$(H2 $(LNAME2 specialkeywords, Special Keywords))
|
||||
|
||||
$(P $(CODE __FILE__) and $(CODE __LINE__) expand to the source
|
||||
file name and line number at the point of instantiation. The path of
|
||||
the source file is left up to the compiler. )
|
||||
|
||||
$(P $(CODE __FILE_FULL_PATH__) expands to the absolute source
|
||||
file name at the point of instantiation.)
|
||||
|
||||
$(P $(CODE __MODULE__) expands to the module name at the point of
|
||||
instantiation.)
|
||||
|
||||
$(P $(CODE __FUNCTION__) expands to the fully qualified name of the
|
||||
function at the point of instantiation.)
|
||||
|
||||
$(P $(CODE __PRETTY_FUNCTION__) is similar to $(CODE __FUNCTION__),
|
||||
but also expands the function return type, its parameter types,
|
||||
and its attributes.)
|
||||
|
||||
$(P Example usage:)
|
||||
|
||||
-----
|
||||
module test;
|
||||
import std.stdio;
|
||||
|
||||
void test(string file = __FILE__, size_t line = __LINE__,
|
||||
string mod = __MODULE__, string func = __FUNCTION__,
|
||||
string pretty = __PRETTY_FUNCTION__,
|
||||
string fileFullPath = __FILE_FULL_PATH__)
|
||||
{
|
||||
writefln("file: '%s', line: '%s', module: '%s',\nfunction: '%s', " ~
|
||||
"pretty function: '%s',\nfile full path: '%s'",
|
||||
file, line, mod, func, pretty, fileFullPath);
|
||||
}
|
||||
|
||||
int main(string[] args)
|
||||
{
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
-----
|
||||
|
||||
$(P Assuming the file was at /example/test.d, this will output:)
|
||||
|
||||
$(CONSOLE
|
||||
file: 'test.d', line: '13', module: 'test',
|
||||
function: 'test.main', pretty function: 'int test.main(string[] args)',
|
||||
file full path: '/example/test.d'
|
||||
)`),
|
||||
ConstantCompletion("derivedMembers", `$(P Takes a single argument, which must evaluate to either
|
||||
a type or an expression of type.
|
||||
|
@ -391,8 +245,8 @@ static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe")
|
|||
static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg");
|
||||
---
|
||||
)`),
|
||||
ConstantCompletion("getLinkage", `$(P Takes one argument, which is a declaration symbol, or the type of a function,
|
||||
delegate, or pointer to function.
|
||||
ConstantCompletion("getLinkage", `$(P Takes one argument, which is a declaration symbol, or the type of a function, delegate,
|
||||
pointer to function, struct, class, or interface.
|
||||
Returns a string representing the $(LINK2 attribute.html#LinkageAttribute, LinkageAttribute)
|
||||
of the declaration.
|
||||
The string is one of:
|
||||
|
@ -414,6 +268,14 @@ alias aliasc = fooc;
|
|||
|
||||
static assert(__traits(getLinkage, fooc) == "C");
|
||||
static assert(__traits(getLinkage, aliasc) == "C");
|
||||
|
||||
extern (C++) struct FooCPPStruct {}
|
||||
extern (C++) class FooCPPClass {}
|
||||
extern (C++) interface FooCPPInterface {}
|
||||
|
||||
static assert(__traits(getLinkage, FooCPPStruct) == "C++");
|
||||
static assert(__traits(getLinkage, FooCPPClass) == "C++");
|
||||
static assert(__traits(getLinkage, FooCPPInterface) == "C++");
|
||||
---`),
|
||||
ConstantCompletion("getMember", `$(P Takes two arguments, the second must be a string.
|
||||
The result is an expression formed from the first
|
||||
|
@ -442,9 +304,11 @@ 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
|
||||
one of the functions in that aggregate.
|
||||
The result is a tuple of all the overloads of that function.
|
||||
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 tuple of all the overloads of the supplied name.
|
||||
)
|
||||
|
||||
---
|
||||
|
@ -456,6 +320,8 @@ class D
|
|||
~this() { }
|
||||
void foo() { }
|
||||
int foo(int) { return 2; }
|
||||
void bar(T)() { return T.init; }
|
||||
class bar(int n) {}
|
||||
}
|
||||
|
||||
void main()
|
||||
|
@ -471,6 +337,9 @@ void main()
|
|||
|
||||
auto i = __traits(getOverloads, d, "foo")[1](1);
|
||||
writeln(i);
|
||||
|
||||
foreach (t; __traits(getOverloads, D, "bar", true))
|
||||
writeln(t.stringof);
|
||||
}
|
||||
---
|
||||
|
||||
|
@ -482,6 +351,8 @@ int()
|
|||
void()
|
||||
int()
|
||||
2
|
||||
bar(T)()
|
||||
bar(int n)
|
||||
)`),
|
||||
ConstantCompletion("getParameterStorageClasses", `$(P
|
||||
Takes two arguments.
|
||||
|
@ -506,7 +377,7 @@ static assert(__traits(getParameterStorageClasses, typeof(&foo), 3)[0] == "lazy"
|
|||
The result is an array of $(D size_t) describing the memory used by an instance of the given type.
|
||||
)
|
||||
$(P The first element of the array is the size of the type (for classes it is
|
||||
the $(GBLINK classInstanceSize)).)
|
||||
the $(GLINK classInstanceSize)).)
|
||||
$(P The following elements describe the locations of GC managed pointers within the
|
||||
memory occupied by an instance of the type.
|
||||
For type T, there are $(D T.sizeof / size_t.sizeof) possible pointers represented
|
||||
|
@ -706,6 +577,8 @@ import std.stdio;
|
|||
struct S
|
||||
{
|
||||
int m;
|
||||
|
||||
import std.stdio; // imports write
|
||||
}
|
||||
|
||||
void main()
|
||||
|
@ -715,6 +588,7 @@ void main()
|
|||
writeln(__traits(hasMember, S, "m")); // true
|
||||
writeln(__traits(hasMember, s, "m")); // true
|
||||
writeln(__traits(hasMember, S, "y")); // false
|
||||
writeln(__traits(hasMember, S, "write")); // true
|
||||
writeln(__traits(hasMember, int, "sizeof")); // true
|
||||
}
|
||||
---`),
|
||||
|
@ -995,6 +869,36 @@ void foolazy(lazy int x)
|
|||
static assert(__traits(isLazy, x));
|
||||
}
|
||||
---`),
|
||||
ConstantCompletion("isReturnOnStack", `$(P
|
||||
Takes one argument which must either be a function symbol, function literal,
|
||||
a delegate, or a function pointer.
|
||||
It returns a ` ~ "`" ~ `bool` ~ "`" ~ ` which is ` ~ "`" ~ `true` ~ "`" ~ ` if the return value of the function is
|
||||
returned on the stack via a pointer to it passed as a hidden extra
|
||||
parameter to the function.
|
||||
)
|
||||
|
||||
---
|
||||
struct S { int[20] a; }
|
||||
int test1();
|
||||
S test2();
|
||||
|
||||
static assert(__traits(isReturnOnStack, test1) == false);
|
||||
static assert(__traits(isReturnOnStack, test2) == true);
|
||||
---
|
||||
|
||||
$(IMPLEMENTATION_DEFINED
|
||||
This is determined by the function ABI calling convention in use,
|
||||
which is often complex.
|
||||
)
|
||||
|
||||
$(BEST_PRACTICE This has applications in:
|
||||
$(OL
|
||||
$(LI Returning values in registers is often faster, so this can be used as
|
||||
a check on a hot function to ensure it is using the fastest method.)
|
||||
$(LI When using inline assembly to correctly call a function.)
|
||||
$(LI Testing that the compiler does this correctly is normally hackish and awkward,
|
||||
this enables efficient, direct, and simple testing.)
|
||||
))`),
|
||||
ConstantCompletion("isSame", `$(P Takes two arguments and returns bool $(D true) if they
|
||||
are the same symbol, $(D false) if not.)
|
||||
|
||||
|
@ -1018,7 +922,77 @@ void main()
|
|||
---
|
||||
|
||||
$(P If the two arguments are expressions made up of literals
|
||||
or enums that evaluate to the same value, true is returned.)`),
|
||||
or enums that evaluate to the same value, true is returned.)
|
||||
|
||||
$(P If the two arguments are both lambda functions (or aliases
|
||||
to lambda functions), then they are compared for equality. For
|
||||
the comparison to be computed correctly, the following conditions
|
||||
must be met for both lambda functions:)
|
||||
|
||||
$(OL
|
||||
$(LI The lambda function arguments must not have a template
|
||||
instantiation as an explicit argument type. Any other argument
|
||||
types (basic, user-defined, template) are supported.)
|
||||
$(LI The lambda function body must contain a single expression
|
||||
(no return statement) which contains only numeric values,
|
||||
manifest constants, enum values, function arguments and function
|
||||
calls. If the expression contains local variables or return
|
||||
statements, the function is considered incomparable.)
|
||||
)
|
||||
|
||||
$(P If these constraints aren't fulfilled, the function is considered
|
||||
incomparable and ` ~ "`" ~ `isSame` ~ "`" ~ ` returns $(D false).)
|
||||
|
||||
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
|
||||
---
|
||||
int f() { return 2; }
|
||||
void test(alias pred)()
|
||||
{
|
||||
// f() from main is a different function from top-level f()
|
||||
static assert(!__traits(isSame, (int a) => a + f(), pred));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
static assert(__traits(isSame, (a, b) => a + b, (c, d) => c + d));
|
||||
static assert(__traits(isSame, a => ++a, b => ++b));
|
||||
static assert(!__traits(isSame, (int a, int b) => a + b, (a, b) => a + b));
|
||||
static assert(__traits(isSame, (a, b) => a + b + 10, (c, d) => c + d + 10));
|
||||
|
||||
// lambdas accessing local variables are considered incomparable
|
||||
int b;
|
||||
static assert(!__traits(isSame, a => a + b, a => a + b));
|
||||
|
||||
// lambdas calling other functions are comparable
|
||||
int f() { return 3;}
|
||||
static assert(__traits(isSame, a => a + f(), a => a + f()));
|
||||
test!((int a) => a + f())();
|
||||
|
||||
class A
|
||||
{
|
||||
int a;
|
||||
this(int a)
|
||||
{
|
||||
this.a = a;
|
||||
}
|
||||
}
|
||||
|
||||
class B
|
||||
{
|
||||
int a;
|
||||
this(int a)
|
||||
{
|
||||
this.a = a;
|
||||
}
|
||||
}
|
||||
|
||||
static assert(__traits(isSame, (A a) => ++a.a, (A b) => ++b.a));
|
||||
// lambdas with different data types are considered incomparable,
|
||||
// even if the memory layout is the same
|
||||
static assert(!__traits(isSame, (A a) => ++a.a, (B a) => ++a.a));
|
||||
}
|
||||
---
|
||||
)`),
|
||||
ConstantCompletion("isScalar", `$(P Works like $(D isArithmetic), except it's for scalar
|
||||
types.)`),
|
||||
ConstantCompletion("isStaticArray", `$(P Works like $(D isArithmetic), except it's for static array
|
||||
|
@ -1066,6 +1040,32 @@ void main()
|
|||
writeln(__traits(isVirtualMethod, S.bar)); // false
|
||||
}
|
||||
---`),
|
||||
ConstantCompletion("isZeroInit", `$(P Takes one argument which must be a type. If the type's
|
||||
$(DDSUBLINK spec/property, init, default initializer) is all zero
|
||||
bits then ` ~ "`" ~ `true` ~ "`" ~ ` is returned, otherwise ` ~ "`" ~ `false` ~ "`" ~ `.)
|
||||
|
||||
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
|
||||
---
|
||||
struct S1 { int x; }
|
||||
struct S2 { int x = -1; }
|
||||
|
||||
static assert(__traits(isZeroInit, S1));
|
||||
static assert(!__traits(isZeroInit, S2));
|
||||
|
||||
void test()
|
||||
{
|
||||
int x = 3;
|
||||
static assert(__traits(isZeroInit, typeof(x)));
|
||||
}
|
||||
|
||||
// ` ~ "`" ~ `isZeroInit` ~ "`" ~ ` will always return true for a class C
|
||||
// because ` ~ "`" ~ `C.init` ~ "`" ~ ` is null reference.
|
||||
|
||||
class C { int x = -1; }
|
||||
|
||||
static assert(__traits(isZeroInit, C));
|
||||
---
|
||||
)`),
|
||||
ConstantCompletion("parent", `$(P Takes a single argument which must evaluate to a symbol.
|
||||
The result is the symbol that is the parent of it.
|
||||
)`),
|
||||
|
|
|
@ -36,6 +36,7 @@ isOut k
|
|||
isOverrideFunction k
|
||||
isPOD k
|
||||
isRef k
|
||||
isReturnOnStack k
|
||||
isSame k
|
||||
isScalar k
|
||||
isStaticArray k
|
||||
|
@ -44,4 +45,5 @@ isTemplate k
|
|||
isUnsigned k
|
||||
isVirtualFunction k
|
||||
isVirtualMethod k
|
||||
isZeroInit k
|
||||
parent k
|
||||
|
|
Loading…
Reference in New Issue