From 932adb3313f761cb0488934b9191380069610f2a Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Sun, 16 Sep 2018 12:00:20 +0200 Subject: [PATCH] update constants --- constants-gen/pragma.dd | 148 +++++++++++----- constants-gen/traits.dd | 320 ++++++++++++++++++++++------------- src/dcd/common/constants2.d | 306 ++++++++++++++++----------------- tests/tc_traits/expected.txt | 2 + 4 files changed, 462 insertions(+), 314 deletions(-) diff --git a/constants-gen/pragma.dd b/constants-gen/pragma.dd index f90dd74a..9641a12a 100644 --- a/constants-gen/pragma.dd +++ b/constants-gen/pragma.dd @@ -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))) - $(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: + $(P There must be one $(ASSIGNEXPRESSION) and it must evaluate at compile time to 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))) + + $(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.) - $(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. + ) + + $(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.) + + +$(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. - $(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: ----------------- 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) ) diff --git a/constants-gen/traits.dd b/constants-gen/traits.dd index 6357f1bc..5064f974 100644 --- a/constants-gen/traits.dd +++ b/constants-gen/traits.dd @@ -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)) diff --git a/src/dcd/common/constants2.d b/src/dcd/common/constants2.d index 67790534..7a7e8667 100644 --- a/src/dcd/common/constants2.d +++ b/src/dcd/common/constants2.d @@ -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. )`), diff --git a/tests/tc_traits/expected.txt b/tests/tc_traits/expected.txt index 88b5010e..a6c79e43 100644 --- a/tests/tc_traits/expected.txt +++ b/tests/tc_traits/expected.txt @@ -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