Skip to content

Commit

Permalink
fix Issue 16495 - __traits(fullyQualifedName) instead of std.traits.f…
Browse files Browse the repository at this point in the history
…ullyQualifiedName (#14711)
  • Loading branch information
WalterBright authored Jan 22, 2023
1 parent ca5bca0 commit 2e196ae
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 1 deletion.
1 change: 1 addition & 0 deletions compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -8692,6 +8692,7 @@ struct Id final
static Identifier* isLazy;
static Identifier* hasMember;
static Identifier* identifier;
static Identifier* fullyQualifiedName;
static Identifier* getProtection;
static Identifier* getVisibility;
static Identifier* parent;
Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,7 @@ immutable Msgtable[] msgtable =
{ "isLazy" },
{ "hasMember" },
{ "identifier" },
{ "fullyQualifiedName" },
{ "getProtection" },
{ "getVisibility" },
{ "parent" },
Expand Down
39 changes: 38 additions & 1 deletion compiler/src/dmd/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,42 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
auto se = new StringExp(e.loc, id.toString());
return se.expressionSemantic(sc);
}
if (e.ident == Id.fullyQualifiedName) // https://dlang.org/spec/traits.html#fullyQualifiedName
{
if (dim != 1)
return dimError(1);

Scope* sc2 = sc.push();
sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
sc2.pop();
if (!ok)
return ErrorExp.get();

const(char)[] fqn;
auto o = (*e.args)[0];
if (auto s = getDsymbolWithoutExpCtx(o))
{
if (s.semanticRun == PASS.initial)
s.dsymbolSemantic(null);

fqn = s.toPrettyChars().toDString();
}
else if (auto t = getType(o))
{
fqn = t.toPrettyChars(true).toDString();
}
else
{
if (!isError(o))
e.error("argument `%s` has no identifier", o.toChars());
return ErrorExp.get();
}
assert(fqn);
auto se = new StringExp(e.loc, fqn);
return se.expressionSemantic(sc);

}
if (e.ident == Id.getProtection || e.ident == Id.getVisibility)
{
if (dim != 1)
Expand Down Expand Up @@ -2208,7 +2244,7 @@ private void traitNotFound(TraitsExp e)
initialized = true; // lazy initialization

// All possible traits
__gshared Identifier*[58] idents =
__gshared Identifier*[59] idents =
[
&Id.isAbstractClass,
&Id.isArithmetic,
Expand Down Expand Up @@ -2238,6 +2274,7 @@ private void traitNotFound(TraitsExp e)
&Id.isReturnOnStack,
&Id.hasMember,
&Id.identifier,
&Id.fullyQualifiedName,
&Id.getProtection,
&Id.getVisibility,
&Id.parent,
Expand Down
117 changes: 117 additions & 0 deletions compiler/test/compilable/test16495.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// https://issues.dlang.org/show_bug.cgi?id=16495

void types()
{
static assert(__traits(fullyQualifiedName, string) == "string");
static assert(__traits(fullyQualifiedName, wstring) == "wstring");
static assert(__traits(fullyQualifiedName, dstring) == "dstring");
static assert(__traits(fullyQualifiedName, typeof(null)) == "typeof(null)");
static assert(__traits(fullyQualifiedName, void) == "void");
static assert(__traits(fullyQualifiedName, const(void)) == "const(void)");
static assert(__traits(fullyQualifiedName, shared(void)) == "shared(void)");
static assert(__traits(fullyQualifiedName, shared const(void)) == "shared(const(void))");
static assert(__traits(fullyQualifiedName, shared inout(void)) == "shared(inout(void))");
static assert(__traits(fullyQualifiedName, shared inout const(void)) == "shared(inout(const(void)))");
static assert(__traits(fullyQualifiedName, inout(void)) == "inout(void)");
static assert(__traits(fullyQualifiedName, inout const(void)) == "inout(const(void))");
static assert(__traits(fullyQualifiedName, immutable(void)) == "immutable(void)");
}

struct QualifiedNameTests
{
struct Inner
{
bool value;
}

ref const(Inner[string]) func( ref Inner var1, lazy scope string var2 );
ref const(Inner[string]) retfunc( return ref Inner var1 );
Inner inoutFunc(inout Inner) inout;
shared(const(Inner[string])[]) data;
const Inner delegate(double, string) @safe nothrow deleg;
inout(int) delegate(inout int) inout inoutDeleg;
Inner function(out double, string) funcPtr;
extern(C) Inner function(double, string) cFuncPtr;

extern(C) void cVarArg(int, ...);
void dVarArg(...);
void dVarArg2(int, ...);
void typesafeVarArg(int[] ...);

Inner[] array;
Inner[16] sarray;
Inner[Inner] aarray;
const(Inner[const(Inner)]) qualAarray;

shared(immutable(Inner) delegate(ref double, scope string) const shared @trusted nothrow) attrDeleg;

struct Data(T) { int x; }
void tfunc(T...)(T args) {}

template Inst(alias A) { int x; }

class Test12309(T, int x, string s) {}
}

void symbols()
{
alias qnTests = QualifiedNameTests;
enum prefix = "test16495.QualifiedNameTests.";
static assert(__traits(fullyQualifiedName, qnTests.Inner) == prefix ~ "Inner");
static assert(__traits(fullyQualifiedName, qnTests.func) == prefix ~ "func");

static assert(__traits(fullyQualifiedName, qnTests.Data!int) == prefix ~ "Data!int.Data");
static assert(__traits(fullyQualifiedName, qnTests.Data!int.x) == prefix ~ "Data!int.Data.x");
static assert(__traits(fullyQualifiedName, qnTests.tfunc!(int[])) == prefix ~ "tfunc!(int[]).tfunc");
static assert(__traits(fullyQualifiedName, qnTests.Inst!(Object)) == prefix ~ "Inst!(Object)");
static assert(__traits(fullyQualifiedName, qnTests.Inst!(Object).x) == prefix ~ "Inst!(Object).x");
static assert(__traits(fullyQualifiedName, qnTests.Test12309!(int, 10, "str"))
== prefix ~ "Test12309!(int, 10, \"str\").Test12309");
}

void names()
{
enum prefix = "test16495.QualifiedNameTests";
enum xx = prefix ~ ".Inner";
with (QualifiedNameTests)
{
// Basic qualified name
static assert(__traits(fullyQualifiedName, Inner) == xx);

// Array types
static assert(__traits(fullyQualifiedName, typeof(array)) == xx ~ "[]");
static assert(__traits(fullyQualifiedName, typeof(sarray)) == xx ~ "[16]");
static assert(__traits(fullyQualifiedName, typeof(aarray)) == xx ~ "[" ~ xx ~ "]");

// qualified key for AA
static assert(__traits(fullyQualifiedName, typeof(qualAarray)) == "const(" ~ xx ~ "[const(" ~ xx ~ ")])");

// Qualified composed data types
static assert(__traits(fullyQualifiedName, typeof(data)) == "shared(const(" ~ xx ~ "[string])[])");

// Function types + function attributes
static assert(__traits(fullyQualifiedName, typeof(func)) == "ref const(" ~ xx ~ "[string])(ref " ~ xx ~ ", lazy scope string)");
static assert(__traits(fullyQualifiedName, typeof(retfunc)) == "ref const(" ~ xx ~ "[string])(return ref " ~ xx ~ ")");
static assert(__traits(fullyQualifiedName, typeof(inoutFunc)) == "inout "~xx~"(inout("~xx~"))");
static assert(__traits(fullyQualifiedName, typeof(deleg)) == "const(" ~ xx ~ " delegate(double, string) nothrow @safe)");
static assert(__traits(fullyQualifiedName, typeof(inoutDeleg)) == "inout(int) delegate(inout(int)) inout");
static assert(__traits(fullyQualifiedName, typeof(funcPtr)) == "" ~ xx ~ " function(out double, string)");
static assert(__traits(fullyQualifiedName, typeof(cFuncPtr)) == "extern (C) " ~ xx ~ " function(double, string)");

// Delegate type with qualified function type
static assert(__traits(fullyQualifiedName, typeof(attrDeleg)) == "shared(immutable(" ~ xx ~ ") "~
"delegate(ref double, scope string) shared const nothrow @trusted)");

// Variable argument function types
static assert(__traits(fullyQualifiedName, typeof(cVarArg)) == "extern (C) void(int, ...)");
static assert(__traits(fullyQualifiedName, typeof(dVarArg)) == "void(...)");
static assert(__traits(fullyQualifiedName, typeof(dVarArg2)) == "void(int, ...)");
static assert(__traits(fullyQualifiedName, typeof(typesafeVarArg)) == "void(int[]...)");

// SIMD vector
static if (is(__vector(float[4])))
{
static assert(__traits(fullyQualifiedName, __vector(float[4])) == "__vector(float[4])");
}
}
}
18 changes: 18 additions & 0 deletions compiler/test/fail_compilation/test16495.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/* TEST_OUTPUT:
---
fail_compilation/test16495.d(12): Error: undefined identifier `q`
fail_compilation/test16495.d(17): Error: expected 1 arguments for `fullyQualifiedName` but had 0
---
*/

// https://issues.dlang.org/show_bug.cgi?id=16495

void test1()
{
auto m = __traits(fullyQualifiedName, q);
}

void test2()
{
auto n = __traits(fullyQualifiedName);
}

0 comments on commit 2e196ae

Please sign in to comment.