Taking the address of an Objective-C @selector expression

Objective-C @selector expressions yield an rvalue. However, Clang (trunk, r234313) allows taking the address of such an expression:

$ cat t.m
void f() {
     @selector(AMethod);
     &@selector(AMethod);
}

$ clang --version
clang version 3.7.0 (trunk 234313)
Target: x86_64-unknown-linux-gnu
Thread model: posix

$ clang -w -c t.m; echo $?
0

Gcc (4.8.0) rejects:
$ gcc -c t.m
t.m: In function ‘main’:
t.m:5:20: error: lvalue required as unary ‘&’ operand
      printf("%p\n", &@selector(AMethod));
                     ^

I presume acceptance is a Clang bug. Any dissenters?

Tom.

Objective-C @selector expressions yield an rvalue. However, Clang
(trunk, r234313) allows taking the address of such an expression:

$ cat t.m
void f() {
     @selector(AMethod);
     &@selector(AMethod);
}

$ clang --version
clang version 3.7.0 (trunk 234313)
Target: x86_64-unknown-linux-gnu
Thread model: posix

$ clang -w -c t.m; echo $?
0

Gcc (4.8.0) rejects:
$ gcc -c t.m
t.m: In function ‘main’:
t.m:5:20: error: lvalue required as unary ‘&’ operand
      printf("%p\n", &@selector(AMethod));
                     ^

I presume acceptance is a Clang bug. Any dissenters?

Looks like it's intentional, but only to match an older GCC: https://llvm.org/bugs/show_bug.cgi?id=7390

I agree with you, I think it should yeild an rvalue. Having it as a non-const lvalue allows for this kind of weirdness:

   *&@selector(AMethod) = @selector(BMethod);

which seems 'wrong' in the same way that this is:

   @selector(AMethod) = @selector(BMethod);

It seems GCC was fixed in the opposite direction since PR7390. Do you happen to know when that happened?

Cheers,

Jon

Objective-C @selector expressions yield an rvalue. However, Clang
(trunk, r234313) allows taking the address of such an expression:

$ cat t.m
void f() {
     @selector(AMethod);
     &@selector(AMethod);
}

$ clang --version
clang version 3.7.0 (trunk 234313)
Target: x86_64-unknown-linux-gnu
Thread model: posix

$ clang -w -c t.m; echo $?
0

Gcc (4.8.0) rejects:
$ gcc -c t.m
t.m: In function ‘main’:
t.m:5:20: error: lvalue required as unary ‘&’ operand
      printf("%p\n", &@selector(AMethod));
                     ^

Oops, clearly I was not consistent in my test file. That should have been:

$ gcc -c t.m
t.m: In function ‘f’:
t.m:3:5: error: lvalue required as unary ‘&’ operand
      &@selector(AMethod);
      ^

I presume acceptance is a Clang bug. Any dissenters?

Looks like it's intentional, but only to match an older GCC:
https://llvm.org/bugs/show_bug.cgi?id=7390

Ah, thanks for digging that up!

I agree with you, I think it should yeild an rvalue.

The Clang AST still considers it an rvalue even though the parser allows the & operator to be used.

<clang>/include/clang/AST/ExprObjC.h:
  400 ObjCSelectorExpr(QualType T, Selector selInfo,
  401 SourceLocation at, SourceLocation rp)
  402 : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false,
  403 false, false),
  404 SelName(selInfo), AtLoc(at), RParenLoc(rp){}

Note the VK_RValue passed to the base class constructor.

> Having it as a

non-const lvalue allows for this kind of weirdness:

   *&@selector(AMethod) = @selector(BMethod);

which seems 'wrong' in the same way that this is:

   @selector(AMethod) = @selector(BMethod);

Clang (trunk, r234313) thankfully rejects both of those:

$ cat t.m
void f() {
     @selector(AMethod) = @selector(AMethod);
     &@selector(AMethod) = @selector(AMethod);
}

$ clang -c t.m
t.m:2:24: error: expression is not assignable
     @selector(AMethod) = @selector(AMethod);
     ~~~~~~~~~~~~~~~~~~ ^
t.m:3:25: error: expression is not assignable
     &@selector(AMethod) = @selector(AMethod);
     ~~~~~~~~~~~~~~~~~~~ ^
2 errors generated.

It seems GCC was fixed in the opposite direction since PR7390. Do you
happen to know when that happened?

No, I don't. I wasn't aware that gcc previously allowed this syntax.

Tom.

Objective-C @selector expressions yield an rvalue. However, Clang
(trunk, r234313) allows taking the address of such an expression:

$ cat t.m
void f() {
     @selector(AMethod);
     &@selector(AMethod);
}

$ clang --version
clang version 3.7.0 (trunk 234313)
Target: x86_64-unknown-linux-gnu
Thread model: posix

$ clang -w -c t.m; echo $?
0

Gcc (4.8.0) rejects:
$ gcc -c t.m
t.m: In function ‘main’:
t.m:5:20: error: lvalue required as unary ‘&’ operand
      printf("%p\n", &@selector(AMethod));
                     ^

Oops, clearly I was not consistent in my test file. That should have been:

$ gcc -c t.m
t.m: In function ‘f’:
t.m:3:5: error: lvalue required as unary ‘&’ operand
      &@selector(AMethod);
      ^

I presume acceptance is a Clang bug. Any dissenters?

Looks like it's intentional, but only to match an older GCC:
https://llvm.org/bugs/show_bug.cgi?id=7390

Ah, thanks for digging that up!

I agree with you, I think it should yeild an rvalue.

The Clang AST still considers it an rvalue even though the parser allows
the & operator to be used.

In CodeGen, sometimes it's an LValue, other times it's an RValue.

<clang>/include/clang/AST/ExprObjC.h:
  400 ObjCSelectorExpr(QualType T, Selector selInfo,
  401 SourceLocation at, SourceLocation rp)
  402 : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary,
false, false,
  403 false, false),
  404 SelName(selInfo), AtLoc(at), RParenLoc(rp){}

Note the VK_RValue passed to the base class constructor.

> Having it as a

non-const lvalue allows for this kind of weirdness:

   *&@selector(AMethod) = @selector(BMethod);

which seems 'wrong' in the same way that this is:

   @selector(AMethod) = @selector(BMethod);

Clang (trunk, r234313) thankfully rejects both of those:

$ cat t.m
void f() {
     @selector(AMethod) = @selector(AMethod);
     &@selector(AMethod) = @selector(AMethod);
}

$ clang -c t.m
t.m:2:24: error: expression is not assignable
     @selector(AMethod) = @selector(AMethod);
     ~~~~~~~~~~~~~~~~~~ ^
t.m:3:25: error: expression is not assignable
     &@selector(AMethod) = @selector(AMethod);
     ~~~~~~~~~~~~~~~~~~~ ^

I can't think of any place where it makes sense to assign to the address of something (aside from operator&() in c++).

Note that my first example had a '*' deref in it, whereas t.m does not.

Jon

Ugh, of course; carelessness on my part. I confirmed that the assignment is not rejected in your case.

Tom.