Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -4085,6 +4085,24 @@ struct ASTBase
}
}

extern (C++) class TypeTraits : Type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs an entry in visitor.d, too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If i do so i get a conflict with the entry in transitivevisitor.d

{
TraitsExp exp;
Loc loc;

extern (D) this(Loc loc, TraitsExp exp)
{
super(Tident);
this.loc = loc;
this.exp = exp;
}

override void accept(Visitor v)
{
v.visit(this);
}
}

extern (C++) final class TypeIdentifier : TypeQualified
{
Identifier ident;
Expand Down
1 change: 1 addition & 0 deletions src/dmd/dmangle.d
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ private immutable char[TMAX] mangleChar =
Tslice : '@',
Treturn : '@',
Tvector : '@',
Ttraits : '@',
];

unittest
Expand Down
6 changes: 6 additions & 0 deletions src/dmd/hdrgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,12 @@ public:
buf.writestring(t.dstring);
}

override void visit(TypeTraits t)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A similar visit method should be added in the ParseTimeTransitiveVisitor [1] otherwise the tree traversal will be truncated.

[1] https://github.com/dlang/dmd/blob/master/src/dmd/transitivevisitor.d

{
//printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
visit(t.exp);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need test case

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How is tested hdrgen ?

}

override void visit(TypeVector t)
{
//printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod);
Expand Down
38 changes: 38 additions & 0 deletions src/dmd/mtype.d
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ enum ENUMTY : int
Tvector,
Tint128,
Tuns128,
TTraits,
TMAX,
}

Expand Down Expand Up @@ -381,6 +382,7 @@ alias Tnull = ENUMTY.Tnull;
alias Tvector = ENUMTY.Tvector;
alias Tint128 = ENUMTY.Tint128;
alias Tuns128 = ENUMTY.Tuns128;
alias Ttraits = ENUMTY.TTraits;
alias TMAX = ENUMTY.TMAX;

alias TY = ubyte;
Expand Down Expand Up @@ -512,6 +514,7 @@ extern (C++) abstract class Type : RootObject
sizeTy[Terror] = __traits(classInstanceSize, TypeError);
sizeTy[Tnull] = __traits(classInstanceSize, TypeNull);
sizeTy[Tvector] = __traits(classInstanceSize, TypeVector);
sizeTy[Ttraits] = __traits(classInstanceSize, TypeTraits);
return sizeTy;
}();

Expand Down Expand Up @@ -5240,6 +5243,41 @@ extern (C++) final class TypeDelegate : TypeNext
}
}

/**
* This is a shell containing a TraitsExp that can be
* either resolved to a type or to a symbol.
*
* The point is to allow AliasDeclarationY to use `__traits(getMember)`
* directly (VS using a library helper in the past).
*/
extern (C++) final class TypeTraits : Type
{
Loc loc;

/// The expression to resolve as type or symbol.
TraitsExp exp;

final extern (D) this(Loc loc, TraitsExp exp)
{
super(Ttraits);
this.loc = loc;
this.exp = exp;
}

final override Type syntaxCopy()
{
TraitsExp te = cast(TraitsExp) exp.syntaxCopy();
TypeTraits tt = new TypeTraits(loc, te);
tt.mod = mod;
return tt;
}

override void accept(Visitor v)
{
v.visit(this);
}
}

/***********************************************************
*/
extern (C++) abstract class TypeQualified : Type
Expand Down
33 changes: 33 additions & 0 deletions src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ final class Parser(AST) : Lexer
case TOK.union_:
case TOK.class_:
case TOK.interface_:
case TOK.traits:
Ldeclaration:
a = parseDeclarations(false, pAttrs, pAttrs.comment);
if (a && a.dim)
Expand Down Expand Up @@ -3495,6 +3496,28 @@ final class Parser(AST) : Lexer
t = parseVector();
break;

case TOK.traits:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also needs entry in isBasicType(), parseMixin(), parseStatement(), parsePrimaryExp() and parseUnaryExp(). Basically, just look at where TOK.typeof_ appears, which is very similar.

{
AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp();
if (!te)
{
// error already emitted while parsing primary
t = new AST.TypeError;
}
else if (te.ident != Id.getMember)
{
// even if this is not a grammar error, it's not worth continuing.
error("invalid `__traits`, only `getMember` can be aliased and not `%s`",
te.ident.toChars);
t = new AST.TypeError;
}
else
{
t = new AST.TypeTraits(loc, te);
}
break;
}

case TOK.const_:
// const(type)
nextToken();
Expand Down Expand Up @@ -6502,6 +6525,16 @@ final class Parser(AST) : Lexer
goto Lfalse;
goto L3;

case TOK.traits:
// __traits(getMember
t = peek(t);
if (t.value != TOK.leftParentheses)
goto Lfalse;
t = peek(t);
if (t.value != TOK.identifier || t.ident != Id.getMember)
goto Lfalse;
break;

case TOK.const_:
case TOK.immutable_:
case TOK.shared_:
Expand Down
1 change: 1 addition & 0 deletions src/dmd/parsetimevisitor.d
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ public:
void visit(AST.TypeStruct t) { visit(cast(AST.Type)t); }
void visit(AST.TypeNext t) { visit(cast(AST.Type)t); }
void visit(AST.TypeQualified t) { visit(cast(AST.Type)t); }
void visit(AST.TypeTraits t) { visit(cast(AST.Type)t); }

// TypeNext
void visit(AST.TypeReference t) { visit(cast(AST.TypeNext)t); }
Expand Down
1 change: 1 addition & 0 deletions src/dmd/strictvisitor.d
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ extern(C++) class StrictVisitor(AST) : ParseTimeVisitor!AST
override void visit(AST.TypeAArray) { assert(0); }
override void visit(AST.TypeSArray) { assert(0); }
override void visit(AST.TypeQualified) { assert(0); }
override void visit(AST.TypeTraits) { assert(0); }
override void visit(AST.TypeIdentifier) { assert(0); }
override void visit(AST.TypeReturn) { assert(0); }
override void visit(AST.TypeTypeof) { assert(0); }
Expand Down
5 changes: 5 additions & 0 deletions src/dmd/transitivevisitor.d
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,11 @@ package mixin template ParseVisitMethods(AST)
t.upr.accept(this);
}

override void visit(AST.TypeTraits t)
{
t.exp.accept(this);
}

// Miscellaneous
//========================================================

Expand Down
15 changes: 15 additions & 0 deletions src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1307,6 +1307,21 @@ private extern (C++) final class TypeSemanticVisitor : Visitor
result = t;
}

override void visit(TypeTraits mtype)
{
import dmd.traits : semanticTraits;
import dmd.dtemplate : getType;

result = null;
if (Expression e = semanticTraits(mtype.exp, sc))
if (Type t = getType(e))
result = t.addMod(mtype.mod);
//if (result) printf("TypeTraits found to be %s\n".ptr, result.toChars);
if (result is null)
mtype.error(loc, "`%s` cannot be resolved to a valid type",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely need a test case for this

mtype.toChars());
}

override void visit(TypeReturn mtype)
{
//printf("TypeReturn::semantic() %s\n", toChars());
Expand Down
9 changes: 9 additions & 0 deletions test/fail_compilation/e7804_1.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
TEST_OUTPUT:
---
fail_compilation/e7804_1.d(9): Error: invalid `__traits`, only `getMember` can be aliased and not `farfelu`
---
*/
module e7804_1;

__traits(farfelu, Aggr, "member") a;
32 changes: 32 additions & 0 deletions test/runnable/e7804.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module e7804;

struct Bar {static struct B{}}
alias BarB = __traits(getMember, Bar, "B");
static assert(is(BarB == Bar.B));
static assert(is(const(__traits(getMember, Bar, "B")) == const(Bar.B)));


struct Foo {alias MyInt = int;}
alias FooInt = __traits(getMember, Foo, "MyInt");
static immutable FooInt fi = 42;
static assert(fi == 42);


enum __traits(getMember, Foo, "MyInt") a0 = 12;
static assert(is(typeof(a0) == int));
static assert(a0 == 12);


const __traits(getMember, Foo, "MyInt") a1 = 46;
static this(){assert(a1 == 46);}


__traits(getMember, Foo, "MyInt") a2 = 78;
static this(){assert(a2 == 78);}


const(__traits(getMember, Foo, "MyInt")) a3 = 63;
static this(){assert(a3 == 63);}


void main(){}