From: Sebastian Redl Date: Tue, 3 Feb 2009 20:19:35 +0000 (+0000) Subject: Allow taking the address of data members, resulting in a member pointer. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ebc07d57be9e0722b4b9c66625e1fca43dcc2ee0;p=clang Allow taking the address of data members, resulting in a member pointer. Pointers to functions don't work yet, and pointers to overloaded functions even less. Also, far too much illegal code is accepted. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63655 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp index 9178fcb6fc..90cdf45270 100644 --- a/Driver/PrintParserCallbacks.cpp +++ b/Driver/PrintParserCallbacks.cpp @@ -447,7 +447,8 @@ namespace { virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, bool HasTrailingLParen, - const CXXScopeSpec *SS) { + const CXXScopeSpec *SS, + bool isAddressOfOperand) { llvm::cout << __FUNCTION__ << "\n"; return ExprEmpty(); } @@ -455,7 +456,8 @@ namespace { virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr( Scope *S, SourceLocation OperatorLoc, OverloadedOperatorKind Op, - bool HasTrailingLParen, const CXXScopeSpec &SS) { + bool HasTrailingLParen, const CXXScopeSpec &SS, + bool isAddressOfOperand) { llvm::cout << __FUNCTION__ << "\n"; return ExprEmpty(); } @@ -463,7 +465,7 @@ namespace { virtual OwningExprResult ActOnCXXConversionFunctionExpr( Scope *S, SourceLocation OperatorLoc, TypeTy *Type, bool HasTrailingLParen, - const CXXScopeSpec &SS) { + const CXXScopeSpec &SS,bool isAddressOfOperand) { llvm::cout << __FUNCTION__ << "\n"; return ExprEmpty(); } diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 3daf2d553e..ffbb346380 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -551,7 +551,8 @@ public: virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, bool HasTrailingLParen, - const CXXScopeSpec *SS = 0) { + const CXXScopeSpec *SS = 0, + bool isAddressOfOperand = false){ return ExprEmpty(); } @@ -563,7 +564,8 @@ public: virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr( Scope *S, SourceLocation OperatorLoc, OverloadedOperatorKind Op, - bool HasTrailingLParen, const CXXScopeSpec &SS) { + bool HasTrailingLParen, const CXXScopeSpec &SS, + bool isAddressOfOperand = false) { return ExprEmpty(); } @@ -575,7 +577,8 @@ public: virtual OwningExprResult ActOnCXXConversionFunctionExpr( Scope *S, SourceLocation OperatorLoc, TypeTy *Type, bool HasTrailingLParen, - const CXXScopeSpec &SS) { + const CXXScopeSpec &SS, + bool isAddressOfOperand = false) { return ExprEmpty(); } diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index d7c957fc47..e19100dc10 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -572,7 +572,8 @@ private: OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec); - OwningExprResult ParseCastExpression(bool isUnaryExpression); + OwningExprResult ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand = false); OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS); OwningExprResult ParseSizeofAlignofExpression(); OwningExprResult ParseBuiltinPrimaryExpression(); @@ -609,7 +610,7 @@ private: //===--------------------------------------------------------------------===// // C++ Expressions - OwningExprResult ParseCXXIdExpression(); + OwningExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); /// ParseOptionalCXXScopeSpecifier - Parse global scope or /// nested-name-specifier if present. Returns true if a nested-name-specifier diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index c4df632cc8..64c4c31fc4 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -345,7 +345,9 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { } /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is -/// true, parse a unary-expression. +/// true, parse a unary-expression. isAddressOfOperand exists because an +/// id-expression that is the operand of address-of gets special treatment +/// due to member pointers. /// /// cast-expression: [C99 6.5.4] /// unary-expression @@ -451,7 +453,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { /// [GNU] binary-type-trait: /// '__is_base_of' [TODO] /// -Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) { +Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand) { OwningExprResult Res(Actions); tok::TokenKind SavedKind = Tok.getKind(); @@ -522,7 +525,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) { if (getLang().CPlusPlus) { // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) - return ParseCastExpression(isUnaryExpression); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); } // Consume the identifier so that we can see if it is followed by a '('. @@ -570,7 +573,15 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) { Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move_arg(Res)); return move(Res); } - case tok::amp: // unary-expression: '&' cast-expression + case tok::amp: { // unary-expression: '&' cast-expression + // Special treatment because of member pointers + SourceLocation SavedLoc = ConsumeToken(); + Res = ParseCastExpression(false, true); + if (!Res.isInvalid()) + Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move_arg(Res)); + return move(Res); + } + case tok::star: // unary-expression: '*' cast-expression case tok::plus: // unary-expression: '+' cast-expression case tok::minus: // unary-expression: '-' cast-expression @@ -662,15 +673,15 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) { case tok::annot_cxxscope: // [C++] id-expression: qualified-id case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id // template-id - Res = ParseCXXIdExpression(); + Res = ParseCXXIdExpression(isAddressOfOperand); return ParsePostfixExpressionSuffix(move(Res)); case tok::coloncolon: { // ::foo::bar -> global qualified name etc. If TryAnnotateTypeOrScopeToken // annotates the token, tail recurse. if (TryAnnotateTypeOrScopeToken()) - return ParseCastExpression(isUnaryExpression); - + return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + // ::new -> [C++] new-expression // ::delete -> [C++] delete-expression SourceLocation CCLoc = ConsumeToken(); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index f434cfb1f7..1efa274083 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -131,7 +131,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) { /// That way Sema can handle and report similar errors for namespaces and the /// global scope. /// -Parser::OwningExprResult Parser::ParseCXXIdExpression() { +/// The isAddressOfOperand parameter indicates that this id-expression is a +/// direct operand of the address-of operator. This is, besides member contexts, +/// the only place where a qualified-id naming a non-static class member may +/// appear. +/// +Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // qualified-id: // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id // '::' unqualified-id @@ -154,18 +159,20 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression() { // Consume the identifier so that we can see if it is followed by a '('. IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation L = ConsumeToken(); - return Actions.ActOnIdentifierExpr(CurScope, L, II, - Tok.is(tok::l_paren), &SS); + return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren), + &SS, isAddressOfOperand); } case tok::kw_operator: { SourceLocation OperatorLoc = Tok.getLocation(); if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) return Actions.ActOnCXXOperatorFunctionIdExpr( - CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS); + CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS, + isAddressOfOperand); if (TypeTy *Type = ParseConversionFunctionId()) return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type, - Tok.is(tok::l_paren), SS); + Tok.is(tok::l_paren), SS, + isAddressOfOperand); // We already complained about a bad conversion-function-id, // above. diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0969cd0387..6360dcc44f 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1030,17 +1030,20 @@ public: virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, bool HasTrailingLParen, - const CXXScopeSpec *SS = 0); + const CXXScopeSpec *SS = 0, + bool isAddressOfOperand = false); virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc, OverloadedOperatorKind Op, bool HasTrailingLParen, - const CXXScopeSpec &SS); + const CXXScopeSpec &SS, + bool isAddressOfOperand); virtual OwningExprResult ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc, TypeTy *Ty, bool HasTrailingLParen, - const CXXScopeSpec &SS); + const CXXScopeSpec &SS, + bool isAddressOfOperand); DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, bool TypeDependent, bool ValueDependent, const CXXScopeSpec *SS = 0); @@ -1053,7 +1056,8 @@ public: DeclarationName Name, bool HasTrailingLParen, const CXXScopeSpec *SS, - bool ForceResolution = false); + bool ForceResolution = false, + bool isAddressOfOperand = false); virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ddd5349c15..36107e88dd 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -363,16 +363,19 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock, Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc, IdentifierInfo &II, bool HasTrailingLParen, - const CXXScopeSpec *SS) { - return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS); + const CXXScopeSpec *SS, + bool isAddressOfOperand) { + return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS, + /*ForceResolution*/false, isAddressOfOperand); } /// BuildDeclRefExpr - Build either a DeclRefExpr or a /// QualifiedDeclRefExpr based on whether or not SS is a /// nested-name-specifier. -DeclRefExpr *Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, - bool TypeDependent, bool ValueDependent, - const CXXScopeSpec *SS) { +DeclRefExpr * +Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc, + bool TypeDependent, bool ValueDependent, + const CXXScopeSpec *SS) { if (SS && !SS->isEmpty()) return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent, SS->getRange().getBegin()); @@ -535,10 +538,16 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, /// If ForceResolution is true, then we will attempt to resolve the /// name even if it looks like a dependent name. This option is off by /// default. +/// +/// isAddressOfOperand means that this expression is the direct operand +/// of an address-of operator. This matters because this is the only +/// situation where a qualified name referencing a non-static member may +/// appear outside a member function of this class. Sema::OwningExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, DeclarationName Name, bool HasTrailingLParen, - const CXXScopeSpec *SS, bool ForceResolution) { + const CXXScopeSpec *SS, bool ForceResolution, + bool isAddressOfOperand) { if (S->getTemplateParamParent() && Name.getAsIdentifierInfo() && HasTrailingLParen && !SS && !ForceResolution) { // We've seen something of the form @@ -554,11 +563,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, } // Could be enum-constant, value decl, instance variable, etc. - Decl *D = 0; if (SS && SS->isInvalid()) return ExprError(); LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName); + Decl *D = 0; if (Lookup.isAmbiguous()) { DiagnoseAmbiguousLookup(Lookup, Name, Loc, SS && SS->isSet() ? SS->getRange() @@ -618,6 +627,41 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, } } + // If this is an expression of the form &Class::member, don't build an + // implicit member ref, because we want a pointer to the member in general, + // not any specific instance's member. + if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) { + NamedDecl *ND = dyn_cast(D); + DeclContext *DC = static_cast(SS->getScopeRep()); + if (ND && isa(DC)) { + QualType DType; + if (FieldDecl *FD = dyn_cast(D)) { + DType = FD->getType().getNonReferenceType(); + } else if (CXXMethodDecl *Method = dyn_cast(D)) { + DType = Method->getType(); + } else if (isa(D)) { + DType = Context.OverloadTy; + } + // Could be an inner type. That's diagnosed below, so ignore it here. + if (!DType.isNull()) { + // The pointer is type- and value-dependent if it points into something + // dependent. + bool Dependent = false; + for (; DC; DC = DC->getParent()) { + // FIXME: could stop early at namespace scope. + if (DC->isRecord()) { + CXXRecordDecl *Record = cast(DC); + if (Context.getTypeDeclType(Record)->isDependentType()) { + Dependent = true; + break; + } + } + } + return Owned(BuildDeclRefExpr(ND, DType, Loc, Dependent, Dependent,SS)); + } + } + } + // We may have found a field within an anonymous union or struct // (C++ [class.union]). if (FieldDecl *FD = dyn_cast(D)) @@ -3428,6 +3472,14 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) { return Context.OverloadTy; } else if (isa(dcl)) { // Okay: we can take the address of a field. + // Could be a pointer to member, though, if there is an explicit + // scope qualifier for the class. + if (isa(op)) { + DeclContext *Ctx = dcl->getDeclContext(); + if (Ctx && Ctx->isRecord()) + return Context.getMemberPointerType(op->getType(), + Context.getTypeDeclType(cast(Ctx)).getTypePtr()); + } } else if (isa(dcl)) { // Okay: we can take the address of a function. } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 3c8184d24d..e9dbc849b0 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -28,13 +28,14 @@ using namespace clang; Sema::OwningExprResult Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc, TypeTy *Ty, bool HasTrailingLParen, - const CXXScopeSpec &SS) { + const CXXScopeSpec &SS, + bool isAddressOfOperand) { QualType ConvType = QualType::getFromOpaquePtr(Ty); QualType ConvTypeCanon = Context.getCanonicalType(ConvType); DeclarationName ConvName = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon); return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen, - &SS); + &SS, /*ForceRes*/false, isAddressOfOperand); } /// ActOnCXXOperatorFunctionIdExpr - Parse a C++ overloaded operator @@ -46,9 +47,11 @@ Sema::OwningExprResult Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc, OverloadedOperatorKind Op, bool HasTrailingLParen, - const CXXScopeSpec &SS) { + const CXXScopeSpec &SS, + bool isAddressOfOperand) { DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op); - return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS); + return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS, + /*ForceRes*/false, isAddressOfOperand); } /// ActOnCXXTypeidOfType - Parse typeid( type-id ). diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index 31973c1257..450fdba367 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -40,3 +40,23 @@ void f() { // Conversion to member of base. pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}} } + +struct HasMembers +{ + int i; + void f(); +}; + +namespace Fake +{ + int i; + void f(); +} + +void g() { + int HasMembers::*pmi = &HasMembers::i; + int *pni = &Fake::i; + + // FIXME: Test the member function, too. + void (*pnf)() = &Fake::f; +}