Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Protection trait #856

Merged
merged 2 commits into from over 1 year ago

10 participants

Adam D. Ruppe Martin Nowak Andrei Alexandrescu Andrej Mitrovic Brad Roberts Hara Kenji David Nadlinger Daniel Murphy Damian Ziemba Walter Bright
src/traits.c
... ...
@@ -206,6 +206,36 @@ static int fptraits(void *param, FuncDeclaration *f)
206 206
         StringExp *se = new StringExp(loc, s->ident->toChars());
207 207
         return se->semantic(sc);
208 208
     }
  209
+    else if (ident == Id::getProtection)
  210
+    {
  211
+
  212
+        if (dim != 1)
  213
+            goto Ldimerror;
  214
+        PROT protection = PROTundefined;
  215
+        Object *o = args->tdata()[0];
2
Daniel Murphy Collaborator
yebblies added a note April 01, 2012

Walter will get mad if you use tdata!

(Finally looking at this again!) What should it be? Most the other code uses this same member. (I started this by copying the " else if (ident == Id::identifier)" branch)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/traits.c
... ...
@@ -206,6 +206,36 @@ static int fptraits(void *param, FuncDeclaration *f)
206 206
         StringExp *se = new StringExp(loc, s->ident->toChars());
207 207
         return se->semantic(sc);
208 208
     }
  209
+    else if (ident == Id::getProtection)
  210
+    {
  211
+
  212
+        if (dim != 1)
  213
+            goto Ldimerror;
  214
+        PROT protection = PROTundefined;
  215
+        Object *o = args->tdata()[0];
  216
+        DotVarExp* d = dynamic_cast<DotVarExp*>(o);
3
Daniel Murphy Collaborator
yebblies added a note April 01, 2012

Don't use rtti, use the methods in Object (something like isExpression/isType) to get an Expression, then check e->op == TOKdotid before doing a c-style cast.

Daniel Murphy Collaborator
yebblies added a note April 01, 2012

Also, things other than DotVarExps should work with getProtection. VarExp, SymbolExp, etc.

Object doesn't have an isExpression method. Is there another way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/traits.c
((13 lines not shown))
  218
+        {
  219
+            Declaration *s = d->var->isDeclaration();
  220
+            if (s)
  221
+            {
  222
+                protection = s->prot();
  223
+            }
  224
+        }
  225
+        const char* protName =
  226
+              protection == PROTundefined ? ""
  227
+	    : protection == PROTnone      ? "none"
  228
+	    : protection == PROTprivate   ? "private"
  229
+	    : protection == PROTpackage   ? "package"
  230
+	    : protection == PROTprotected ? "protected"
  231
+	    : protection == PROTpublic    ? "public"
  232
+	    : protection == PROTexport    ? "export"
  233
+	    : (assert(0), ""); // unknown
4
Daniel Murphy Collaborator
yebblies added a note April 01, 2012

This should probably be a switch... and should possibly assert on 'none' as well as unknown, I think these should be replaced by the time they reach here?

Martin Nowak Collaborator

Protection to chars is already duplicated in JSON and HdrGen,
you might want to merge them, see MartinNowak@f3513e6.

Hara Kenji Collaborator
9rnsr added a note September 29, 2012

@adamdruppe , at least stop using hard tab.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/traits.c
... ...
@@ -206,6 +206,36 @@ static int fptraits(void *param, FuncDeclaration *f)
206 206
         StringExp *se = new StringExp(loc, s->ident->toChars());
207 207
         return se->semantic(sc);
208 208
     }
  209
+    else if (ident == Id::getProtection)
  210
+    {
  211
+
  212
+        if (dim != 1)
  213
+            goto Ldimerror;
2
Martin Nowak Collaborator

How about returning a tuple, so this can be used with multiple symbols?

I don't think that's needed because you can always just call it multiple times. I don't think any the other traits work that way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Martin Nowak
Collaborator

ping

Adam D. Ruppe
Andrei Alexandrescu
Owner

This is a useful trait. Ping @adamdruppe.

Adam D. Ruppe

I went through and added some comments a while ago about details... I don't know how to solve all the comments' concerns myself.

Adam D. Ruppe

I just pushed up some new code. I think this covers all the bases - both kinds of dot expressions and, of course, symbols. I also updated the style to match dmd git.

There's still the duplication of the protection names though. I just wanted to do one thing at a time though, we could DRY that in a separate little pull.

Andrej Mitrovic
Collaborator

Considering we have the ParameterStorageClass/FunctionAttribute enums I think we should also introduce a getProtection template in std.traits which would return an enum. Internally it could do string comparisons via __traits(getProtection).

Adam D. Ruppe

Yeah, that'd be easy enough, though we'll sadly have to find names other that "public" etc. thanks to keywords. Ugh. But the phobos change can happen after the compiler is updated.

Andrej Mitrovic
Collaborator

Yup. I typically use uppercase names to avoid clashes. ParameterStorageClass uses underscores, maybe we should use that for consistency.

Andrej Mitrovic
Collaborator

Btw this pull will fix an undiscovered bug in std.typecons:

module inter;

interface Inter
{
    protected void test();
}
module test;

import inter;
import std.typecons;

void main()
{
    auto o = new BlackHole!Inter;
    o.test();  // works, o.test was declared public
}

BlackHole will be able to set the right protection attribute and disallow the above from compiling. I'd imagine this pull will be welcome for these sorts of templates that deal with classes.

Andrei Alexandrescu
Owner

Great. Could you please file that so we keep track of it? Thanks!

Adam D. Ruppe

Hmm, the autotester is saying a test fails, but it works on my box, and I don't think my changes here could be responsible anyway.

http://d.puremagic.com/test-results/pull-history.ghtml?repoid=1&pullid=856

It looks like it was passing until last night though, and I haven't changed anything.... is this something I should worry about?

Brad Roberts
Owner

The master is broken, so it's not shocking that all pulls on top of that are also broken. It doesn't happen often, but when it does, it's annoying. Glare at @WalterBright for checking in broken code.

src/traits.c
((8 lines not shown))
  213
+        Object *o = (*args)[0];
  214
+        Dsymbol *s = getDsymbol(o);
  215
+        if(!s)
  216
+        {
  217
+            // it might also be a trait getMember or something,
  218
+            // which returns a dot expression rather than a symbol
  219
+            if(o->dyncast() == DYNCAST_EXPRESSION)
  220
+            {
  221
+                Expression* e = (Expression*) o;
  222
+
  223
+                if (e->op == TOKdotvar)
  224
+                {
  225
+                        DotVarExp *dv = (DotVarExp *)e;
  226
+                        s = dv->var->isDeclaration();
  227
+                }
  228
+                else if (e->op == TOKvar)
2
Hara Kenji Collaborator
9rnsr added a note September 29, 2012

This is redundant code, because getDsymbol catches TOKvar.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
test/compilable/traitprot.d
((1 lines not shown))
  1
+class Test {
  2
+    public int a;
  3
+    private int b;
  4
+    export string c;
  5
+    protected int d;
  6
+    package void e() {}
  7
+}
  8
+
  9
+void main() {
  10
+    Test t;
  11
+    static assert(__traits(getProtection, __traits(getMember, t, "a")) == "public");
  12
+    static assert(__traits(getProtection, __traits(getMember, t, "b")) == "private");
  13
+    static assert(__traits(getProtection, __traits(getMember, t, "c")) == "export");
  14
+    static assert(__traits(getProtection, __traits(getMember, t, "d")) == "protected");
  15
+    static assert(__traits(getProtection, __traits(getMember, t, "e")) == "package");
  16
+}
2
Hara Kenji Collaborator
9rnsr added a note September 29, 2012

You should move this test to test/runnable/traits.d, it's a module for the __traits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
test/runnable/traits.d
... ...
@@ -764,6 +764,31 @@ void test7858()
764 764
     static assert(__traits(isSame, C.sfunc, __traits(getOverloads, C, "sfunc")[0]));    // NG
765 765
 }
766 766
 
  767
+void getProtection() {
1
Hara Kenji Collaborator
9rnsr added a note September 29, 2012

Please insert separator comment between each tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
test/runnable/traits.d
((13 lines not shown))
  776
+
  777
+    Test t;
  778
+    // should work both directly and through getMember
  779
+    static assert(__traits(getProtection, t.a) == "public");
  780
+    static assert(__traits(getProtection, t.b) == "private");
  781
+    static assert(__traits(getProtection, t.c) == "export");
  782
+    static assert(__traits(getProtection, t.d) == "protected");
  783
+    static assert(__traits(getProtection, t.e) == "package");
  784
+
  785
+    static assert(__traits(getProtection, __traits(getMember, t, "a")) == "public");
  786
+    static assert(__traits(getProtection, __traits(getMember, t, "b")) == "private");
  787
+    static assert(__traits(getProtection, __traits(getMember, t, "c")) == "export");
  788
+    static assert(__traits(getProtection, __traits(getMember, t, "d")) == "protected");
  789
+    static assert(__traits(getProtection, __traits(getMember, t, "e")) == "package");
  790
+}
  791
+
2
Hara Kenji Collaborator
9rnsr added a note September 29, 2012

More exhaustive test I think.

private   struct TestProt1 {}
package   struct TestProt2 {}
protected struct TestProt3 {}
public    struct TestProt4 {}
export    struct TestProt5 {}

void getProtection()
{
    class Test
    {
        private   { int va; void fa(){} }
        package   { int vb; void fb(){} }
        protected { int vc; void fc(){} }
        public    { int vd; void fd(){} }
        export    { int ve; void fe(){} }
    }
    Test t;

    // TOKvar and VarDeclaration
    static assert(__traits(getProtection, Test.va) == "private");
    static assert(__traits(getProtection, Test.vb) == "package");
    static assert(__traits(getProtection, Test.vc) == "protected");
    static assert(__traits(getProtection, Test.vd) == "public");
    static assert(__traits(getProtection, Test.ve) == "export");

    // TOKdotvar and VarDeclaration
    static assert(__traits(getProtection, t.va) == "private");
    static assert(__traits(getProtection, t.vb) == "package");
    static assert(__traits(getProtection, t.vc) == "protected");
    static assert(__traits(getProtection, t.vd) == "public");
    static assert(__traits(getProtection, t.ve) == "export");

    // TOKvar and FuncDeclaration
    static assert(__traits(getProtection, Test.fa) == "private");
    static assert(__traits(getProtection, Test.fb) == "package");
    static assert(__traits(getProtection, Test.fc) == "protected");
    static assert(__traits(getProtection, Test.fd) == "public");
    static assert(__traits(getProtection, Test.fe) == "export");

    // TOKdotvar and FuncDeclaration
    static assert(__traits(getProtection, t.fa) == "private");
    static assert(__traits(getProtection, t.fb) == "package");
    static assert(__traits(getProtection, t.fc) == "protected");
    static assert(__traits(getProtection, t.fd) == "public");
    static assert(__traits(getProtection, t.fe) == "export");

    // TOKtype
    static assert(__traits(getProtection, TestProt1) == "private");
    static assert(__traits(getProtection, TestProt2) == "package");
    static assert(__traits(getProtection, TestProt3) == "protected");
    static assert(__traits(getProtection, TestProt4) == "public");
    static assert(__traits(getProtection, TestProt5) == "export");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Hara Kenji
Collaborator

OK, now implementation looks good to me.
But, this is a language enhancement, and there is another pull request #952 for the design of protection traits feature.
So I can't merge this in my authority.
@WalterBright and @andralex , I'd like to assign this to you!

David Nadlinger
Collaborator

Maybe squash the commits together?

Adam D. Ruppe
Adam D. Ruppe

eh i tried it and think got some success, but it was complaining about merge conflicts and rejected non-fast-forward and other stuff. But it still builds so I'm gonna leave it here.

Damian Ziemba

@adamdruppe if you are on IRC I can help you with it

Adam D. Ruppe
Adam D. Ruppe

I read some more about the git rebase and think I got it right this time. The diff looks clean now... we should be good to go.

src/traits.c
... ...
@@ -206,6 +206,59 @@ Expression *TraitsExp::semantic(Scope *sc)
206 206
         StringExp *se = new StringExp(loc, s->ident->toChars());
207 207
         return se->semantic(sc);
208 208
     }
  209
+    else if (ident == Id::getProtection)
  210
+    {
  211
+        if (dim != 1)
  212
+            goto Ldimerror;
  213
+        Object *o = (*args)[0];
  214
+        Dsymbol *s = getDsymbol(o);
  215
+        if(!s)
  216
+        {
  217
+            // it might also be a trait getMember or something,
  218
+            // which returns a dot expression rather than a symbol
  219
+            if(o->dyncast() == DYNCAST_EXPRESSION)
  220
+            {
  221
+                Expression* e = (Expression*) o;
1
Daniel Murphy Collaborator
yebblies added a note October 10, 2012

Expression* e = (Expression*) o;
->
Expression *e = (Expression *)o;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/traits.c
((15 lines not shown))
  220
+            {
  221
+                Expression* e = (Expression*) o;
  222
+
  223
+                if (e->op == TOKdotvar)
  224
+                {
  225
+                        DotVarExp *dv = (DotVarExp *)e;
  226
+                        s = dv->var->isDeclaration();
  227
+                }
  228
+            }
  229
+        }        
  230
+        if(!s)
  231
+        {
  232
+            bool gagError = false;
  233
+            if(o->dyncast() == DYNCAST_EXPRESSION)
  234
+            {
  235
+                Expression* e = (Expression*) o;
1
Daniel Murphy Collaborator
yebblies added a note October 10, 2012

Same here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/traits.c
((28 lines not shown))
  233
+            if(o->dyncast() == DYNCAST_EXPRESSION)
  234
+            {
  235
+                Expression* e = (Expression*) o;
  236
+                if(e->op == TOKerror)
  237
+                    gagError = true;
  238
+            }
  239
+
  240
+            if(!gagError)
  241
+                error("argument %s has no protection", o->toChars());
  242
+
  243
+            goto Lfalse;
  244
+        }
  245
+
  246
+        PROT protection = s->prot();
  247
+
  248
+        const char* protName =
2
Daniel Murphy Collaborator
yebblies added a note October 10, 2012

I suspect this would be much nicer as a switch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/traits.c
((38 lines not shown))
  243
+            goto Lfalse;
  244
+        }
  245
+
  246
+        PROT protection = s->prot();
  247
+
  248
+        const char* protName =
  249
+              protection == PROTundefined ? ""
  250
+            : protection == PROTnone      ? "none"
  251
+            : protection == PROTprivate   ? "private"
  252
+            : protection == PROTpackage   ? "package"
  253
+            : protection == PROTprotected ? "protected"
  254
+            : protection == PROTpublic    ? "public"
  255
+            : protection == PROTexport    ? "export"
  256
+            : (assert(0), ""); // unknown
  257
+
  258
+        StringExp *se = new StringExp(loc, (char*) protName);
1
Daniel Murphy Collaborator
yebblies added a note October 10, 2012

char*
char *

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Adam D. Ruppe

We now have two commits: one is the protection trait, all changes squashed into one, and the other is removing some duplication on the protection names, by moving json.c's impl into a global area.

This should cover everyone's concerns.

Adam D. Ruppe

Any chance we can get this pulled for the next release?

Walter Bright WalterBright merged commit 913b485 into from November 10, 2012
Walter Bright WalterBright closed this November 10, 2012
Walter Bright WalterBright referenced this pull request from a commit November 10, 2012
Walter Bright fix D2 pull #856 931d305
Walter Bright WalterBright referenced this pull request from a commit November 10, 2012
Walter Bright fix D2 pull #856 b940d6d
Deleted user Unknown referenced this pull request from a commit December 24, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Deleted user Unknown referenced this pull request from a commit December 25, 2013
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
15  src/attrib.c
@@ -683,17 +683,10 @@ void ProtDeclaration::protectionToCBuffer(OutBuffer *buf, enum PROT protection)
683 683
 {
684 684
     const char *p;
685 685
 
686  
-    switch (protection)
687  
-    {
688  
-        case PROTprivate:       p = "private";          break;
689  
-        case PROTpackage:       p = "package";          break;
690  
-        case PROTprotected:     p = "protected";        break;
691  
-        case PROTpublic:        p = "public";           break;
692  
-        case PROTexport:        p = "export";           break;
693  
-        default:
694  
-            assert(0);
695  
-            break;
696  
-    }
  686
+    p = Pprotectionnames[protection];
  687
+
  688
+    assert(p);
  689
+
697 690
     buf->writestring(p);
698 691
     buf->writeByte(' ');
699 692
 }
9  src/doc.c
@@ -553,15 +553,8 @@ void ScopeDsymbol::emitMemberComments(Scope *sc)
553 553
 
554 554
 void emitProtection(OutBuffer *buf, PROT prot)
555 555
 {
556  
-    const char *p;
  556
+    const char *p = Pprotectionnames[prot];
557 557
 
558  
-    switch (prot)
559  
-    {
560  
-        case PROTpackage:       p = "package";   break;
561  
-        case PROTprotected:     p = "protected"; break;
562  
-        case PROTexport:        p = "export";    break;
563  
-        default:                p = NULL;        break;
564  
-    }
565 558
     if (p)
566 559
         buf->printf("%s ", p);
567 560
 }
3  src/dsymbol.h
@@ -96,6 +96,9 @@ enum PROT
96 96
     PROTexport,
97 97
 };
98 98
 
  99
+// this is used for printing the protection in json, traits, docs, etc.
  100
+static const char* Pprotectionnames[] = {NULL, "none", "private", "package", "protected", "public", "export"};
  101
+
99 102
 /* State of symbol in winding its way through the passes of the compiler
100 103
  */
101 104
 enum PASS
1  src/idgen.c
@@ -322,6 +322,7 @@ Msgtable msgtable[] =
322 322
     { "isLazy" },
323 323
     { "hasMember" },
324 324
     { "identifier" },
  325
+    { "getProtection" },
325 326
     { "parent" },
326 327
     { "getMember" },
327 328
     { "getOverloads" },
1  src/json.c
@@ -44,7 +44,6 @@ const char Ptype[] = "type";
44 44
 const char Pcomment[] = "comment";
45 45
 const char Pmembers[] = "members";
46 46
 const char Pprotection[] = "protection";
47  
-const char* Pprotectionnames[] = {NULL, "none", "private", "package", "protected", "public", "export"};
48 47
 
49 48
 void JsonRemoveComma(OutBuffer *buf);
50 49
 
45  src/traits.c
@@ -206,6 +206,51 @@ Expression *TraitsExp::semantic(Scope *sc)
206 206
         StringExp *se = new StringExp(loc, s->ident->toChars());
207 207
         return se->semantic(sc);
208 208
     }
  209
+    else if (ident == Id::getProtection)
  210
+    {
  211
+        if (dim != 1)
  212
+            goto Ldimerror;
  213
+        Object *o = (*args)[0];
  214
+        Dsymbol *s = getDsymbol(o);
  215
+        if(!s)
  216
+        {
  217
+            // it might also be a trait getMember or something,
  218
+            // which returns a dot expression rather than a symbol
  219
+            if(o->dyncast() == DYNCAST_EXPRESSION)
  220
+            {
  221
+                Expression *e = (Expression *) o;
  222
+
  223
+                if (e->op == TOKdotvar)
  224
+                {
  225
+                        DotVarExp *dv = (DotVarExp *)e;
  226
+                        s = dv->var->isDeclaration();
  227
+                }
  228
+            }
  229
+        }        
  230
+        if(!s)
  231
+        {
  232
+            bool gagError = false;
  233
+            if(o->dyncast() == DYNCAST_EXPRESSION)
  234
+            {
  235
+                Expression *e = (Expression *) o;
  236
+                if(e->op == TOKerror)
  237
+                    gagError = true;
  238
+            }
  239
+
  240
+            if(!gagError)
  241
+                error("argument %s has no protection", o->toChars());
  242
+
  243
+            goto Lfalse;
  244
+        }
  245
+
  246
+        PROT protection = s->prot();
  247
+
  248
+        const char *protName = Pprotectionnames[protection];
  249
+
  250
+        StringExp *se = new StringExp(loc, (char *) protName);
  251
+        return se->semantic(sc);
  252
+    }
  253
+
209 254
     else if (ident == Id::parent)
210 255
     {
211 256
         if (dim != 1)
69  test/runnable/traits.d
@@ -729,6 +729,75 @@ void test7608()
729 729
 
730 730
 /********************************************************/
731 731
 
  732
+private   struct TestProt1 {}
  733
+package   struct TestProt2 {}
  734
+protected struct TestProt3 {}
  735
+public    struct TestProt4 {}
  736
+export    struct TestProt5 {}
  737
+
  738
+void getProtection()
  739
+{
  740
+    class Test
  741
+    {
  742
+        private   { int va; void fa(){} }
  743
+        package   { int vb; void fb(){} }
  744
+        protected { int vc; void fc(){} }
  745
+        public    { int vd; void fd(){} }
  746
+        export    { int ve; void fe(){} }
  747
+    }
  748
+    Test t;
  749
+
  750
+    // TOKvar and VarDeclaration
  751
+    static assert(__traits(getProtection, Test.va) == "private");
  752
+    static assert(__traits(getProtection, Test.vb) == "package");
  753
+    static assert(__traits(getProtection, Test.vc) == "protected");
  754
+    static assert(__traits(getProtection, Test.vd) == "public");
  755
+    static assert(__traits(getProtection, Test.ve) == "export");
  756
+
  757
+    // TOKdotvar and VarDeclaration
  758
+    static assert(__traits(getProtection, t.va) == "private");
  759
+    static assert(__traits(getProtection, t.vb) == "package");
  760
+    static assert(__traits(getProtection, t.vc) == "protected");
  761
+    static assert(__traits(getProtection, t.vd) == "public");
  762
+    static assert(__traits(getProtection, t.ve) == "export");
  763
+
  764
+    // TOKvar and FuncDeclaration
  765
+    static assert(__traits(getProtection, Test.fa) == "private");
  766
+    static assert(__traits(getProtection, Test.fb) == "package");
  767
+    static assert(__traits(getProtection, Test.fc) == "protected");
  768
+    static assert(__traits(getProtection, Test.fd) == "public");
  769
+    static assert(__traits(getProtection, Test.fe) == "export");
  770
+
  771
+    // TOKdotvar and FuncDeclaration
  772
+    static assert(__traits(getProtection, t.fa) == "private");
  773
+    static assert(__traits(getProtection, t.fb) == "package");
  774
+    static assert(__traits(getProtection, t.fc) == "protected");
  775
+    static assert(__traits(getProtection, t.fd) == "public");
  776
+    static assert(__traits(getProtection, t.fe) == "export");
  777
+
  778
+    // TOKtype
  779
+    static assert(__traits(getProtection, TestProt1) == "private");
  780
+    static assert(__traits(getProtection, TestProt2) == "package");
  781
+    static assert(__traits(getProtection, TestProt3) == "protected");
  782
+    static assert(__traits(getProtection, TestProt4) == "public");
  783
+    static assert(__traits(getProtection, TestProt5) == "export");
  784
+
  785
+    // This specific pattern is important to ensure it always works
  786
+    // through reflection, however that becomes implemented
  787
+    static assert(__traits(getProtection, __traits(getMember, t, "va")) == "private");
  788
+    static assert(__traits(getProtection, __traits(getMember, t, "vb")) == "package");
  789
+    static assert(__traits(getProtection, __traits(getMember, t, "vc")) == "protected");
  790
+    static assert(__traits(getProtection, __traits(getMember, t, "vd")) == "public");
  791
+    static assert(__traits(getProtection, __traits(getMember, t, "ve")) == "export");
  792
+    static assert(__traits(getProtection, __traits(getMember, t, "fa")) == "private");
  793
+    static assert(__traits(getProtection, __traits(getMember, t, "fb")) == "package");
  794
+    static assert(__traits(getProtection, __traits(getMember, t, "fc")) == "protected");
  795
+    static assert(__traits(getProtection, __traits(getMember, t, "fd")) == "public");
  796
+    static assert(__traits(getProtection, __traits(getMember, t, "fe")) == "export");
  797
+}
  798
+
  799
+/********************************************************/
  800
+
732 801
 int main()
733 802
 {
734 803
     test1();
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.