If a C++ qualified id is followed by a postfix suffix, it is never the direct

operand of an addressof operator, and so we should not treat it as an abstract
member-pointer expression and therefore suppress the implicit member access.

This is really a well-formedness constraint on expressions:  a DeclRefExpr of
a FieldDecl or a non-static CXXMethodDecl (or template thereof, or unresolved
collection thereof) should not be allowed in an arbitrary location in the AST.
Arguably it shouldn't be allowed anywhere and we should have a different expr
node type for this.  But unfortunately we don't have a good way of enforcing
this kind of constraint right now.

llvm-svn: 89578
This commit is contained in:
John McCall 2009-11-22 02:49:43 +00:00
parent 663e0a06b0
commit a9ee325d71
3 changed files with 58 additions and 1 deletions

View File

@ -326,6 +326,24 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
/*ObjectType=*/0,
Name))
return ExprError();
// This is only the direct operand of an & operator if it is not
// followed by a postfix-expression suffix.
if (isAddressOfOperand) {
switch (Tok.getKind()) {
case tok::l_square:
case tok::l_paren:
case tok::arrow:
case tok::period:
case tok::plusplus:
case tok::minusminus:
isAddressOfOperand = false;
break;
default:
break;
}
}
return Actions.ActOnIdExpression(CurScope, SS, Name, Tok.is(tok::l_paren),
isAddressOfOperand);

View File

@ -623,6 +623,9 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
UnqualifiedId &Name,
bool HasTrailingLParen,
bool IsAddressOfOperand) {
assert(!(IsAddressOfOperand && HasTrailingLParen) &&
"cannot be direct & operand and have a trailing lparen");
if (Name.getKind() == UnqualifiedId::IK_TemplateId) {
ASTTemplateArgsPtr TemplateArgsPtr(*this,
Name.TemplateId->getTemplateArgs(),
@ -856,7 +859,7 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
// performance.
if (!ADL) {
bool isAbstractMemberPointer =
(isAddressOfOperand && !HasTrailingLParen && SS && !SS->isEmpty());
(isAddressOfOperand && SS && !SS->isEmpty());
if (!isAbstractMemberPointer && !Lookup.empty() &&
isa<CXXRecordDecl>((*Lookup.begin())->getDeclContext())) {

View File

@ -0,0 +1,36 @@
// RUN: clang-cc -emit-llvm-only %s
// Tests that Sema properly creates member-access expressions for
// these instead of bare FieldDecls.
struct Foo {
int myvalue;
// We have to override these to get something with an lvalue result.
int &operator++(int);
int &operator--(int);
};
struct Test0 {
Foo memfoo;
int memint;
int memarr[10];
Test0 *memptr;
struct MemClass { int a; } memstruct;
int &memfun();
void test() {
int *p;
p = &Test0::memfoo++;
p = &Test0::memfoo--;
p = &Test0::memarr[1];
p = &Test0::memptr->memint;
p = &Test0::memstruct.a;
p = &Test0::memfun();
}
};
void test0() {
Test0 mytest;
mytest.test();
}