diff options
-rw-r--r-- | include/clang/AST/Expr.h | 1 | ||||
-rw-r--r-- | include/clang/AST/StmtVisitor.h | 5 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 6 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 39 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 14 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 88 | ||||
-rw-r--r-- | lib/Sema/SemaInherit.h | 2 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 6 | ||||
-rw-r--r-- | test/SemaCXX/member-pointer.cpp | 25 | ||||
-rw-r--r-- | www/cxx_status.html | 8 |
11 files changed, 164 insertions, 36 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 3884d7dc2b..8cd27c30da 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1085,6 +1085,7 @@ public: enum Opcode { // Operators listed in order of precedence. // Note that additions to this should also update the StmtVisitor class. + PtrMemD, PtrMemI, // [C++ 5.5] Pointer-to-member operators. Mul, Div, Rem, // [C99 6.5.5] Multiplicative operators. Add, Sub, // [C99 6.5.6] Additive operators. Shl, Shr, // [C99 6.5.7] Bitwise shift operators. diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h index 4217de32ac..2b0dd89158 100644 --- a/include/clang/AST/StmtVisitor.h +++ b/include/clang/AST/StmtVisitor.h @@ -35,6 +35,8 @@ public: if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { switch (BinOp->getOpcode()) { default: assert(0 && "Unknown binary operator!"); + case BinaryOperator::PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator); + case BinaryOperator::PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator); case BinaryOperator::Mul: DISPATCH(BinMul, BinaryOperator); case BinaryOperator::Div: DISPATCH(BinDiv, BinaryOperator); case BinaryOperator::Rem: DISPATCH(BinRem, BinaryOperator); @@ -95,7 +97,7 @@ public: case UnaryOperator::Imag: DISPATCH(UnaryImag, UnaryOperator); case UnaryOperator::Extension: DISPATCH(UnaryExtension, UnaryOperator); case UnaryOperator::OffsetOf: DISPATCH(UnaryOffsetOf, UnaryOperator); - } + } } // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. @@ -119,6 +121,7 @@ public: RetTy VisitBin ## NAME(BinaryOperator *S) { \ DISPATCH(BinaryOperator, BinaryOperator); \ } + BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI) BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem) BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl) BINOP_FALLBACK(Shr) diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index f9e0766010..298e0fe272 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -863,6 +863,12 @@ DIAG(err_qualified_catch_declarator, ERROR, "exception declarator cannot be qualified") DIAG(err_early_catch_all, ERROR, "catch-all handler must come last") +DIAG(err_bad_memptr_rhs, ERROR, + "right hand operand to %0 must be a pointer to member of a complete class " + "but is %1") +DIAG(err_bad_memptr_lhs, ERROR, + "left hand operand to ->* must be a %select{|pointer to }0class " + "compatible with the right hand operand, but is %1") DIAG(err_invalid_use_of_function_type, ERROR, "a function type is not allowed here") diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index d627ab03b2..89fdbe31f3 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -496,6 +496,12 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { BinOp->getOpcode() == BinaryOperator::Comma) return BinOp->getRHS()->isLvalue(Ctx); + // C++ [expr.mptr.oper]p6 + if ((BinOp->getOpcode() == BinaryOperator::PtrMemD || + BinOp->getOpcode() == BinaryOperator::PtrMemI) && + !BinOp->getType()->isFunctionType()) + return BinOp->getLHS()->isLvalue(Ctx); + if (!BinOp->isAssignmentOp()) return LV_InvalidExpression; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 597c50c08a..7c0b43923d 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -33,20 +33,21 @@ using namespace clang; /// productions. Low precedences numbers bind more weakly than high numbers. namespace prec { enum Level { - Unknown = 0, // Not binary operator. - Comma = 1, // , - Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= - Conditional = 3, // ? - LogicalOr = 4, // || - LogicalAnd = 5, // && - InclusiveOr = 6, // | - ExclusiveOr = 7, // ^ - And = 8, // & - Equality = 9, // ==, != - Relational = 10, // >=, <=, >, < - Shift = 11, // <<, >> - Additive = 12, // -, + - Multiplicative = 13 // *, /, % + Unknown = 0, // Not binary operator. + Comma = 1, // , + Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= + Conditional = 3, // ? + LogicalOr = 4, // || + LogicalAnd = 5, // && + InclusiveOr = 6, // | + ExclusiveOr = 7, // ^ + And = 8, // & + Equality = 9, // ==, != + Relational = 10, // >=, <=, >, < + Shift = 11, // <<, >> + Additive = 12, // -, + + Multiplicative = 13, // *, /, % + PointerToMember = 14 // .*, ->* }; } @@ -88,6 +89,8 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind) { case tok::percent: case tok::slash: case tok::star: return prec::Multiplicative; + case tok::periodstar: + case tok::arrowstar: return prec::PointerToMember; } } @@ -104,7 +107,13 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind) { /// consistency, we parse the LHS as a conditional-expression, then check for /// l-value-ness in semantic analysis stages. /// +/// pm-expression: [C++ 5.5] +/// cast-expression +/// pm-expression '.*' cast-expression +/// pm-expression '->*' cast-expression +/// /// multiplicative-expression: [C99 6.5.5] +/// Note: in C++, apply pm-expression instead of cast-expression /// cast-expression /// multiplicative-expression '*' cast-expression /// multiplicative-expression '/' cast-expression @@ -270,7 +279,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { // Consume the operator, saving the operator token for error reporting. Token OpToken = Tok; ConsumeToken(); - + // Special case handling for the ternary operator. OwningExprResult TernaryMiddle(Actions, true); if (NextTokPrec == prec::Conditional) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 33b3781200..4878403333 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1788,16 +1788,18 @@ public: bool PerformImplicitConversion(Expr *&From, QualType ToType, const StandardConversionSequence& SCS, const char *Flavor); - + /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). - - /// type checking binary operators (subroutines of ActOnBinOp). + + /// type checking binary operators (subroutines of CreateBuiltinBinOp). inline QualType InvalidOperands(SourceLocation l, Expr *&lex, Expr *&rex); + inline QualType CheckPointerToMemberOperands( // C++ 5.5 + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isIndirect); inline QualType CheckMultiplyDivideOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckRemainderOperands( // C99 6.5.5 - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckAdditionOperands( // C99 6.5.6 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckSubtractionOperands( // C99 6.5.6 @@ -1807,7 +1809,7 @@ public: inline QualType CheckCompareOperands( // C99 6.5.8/9 Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isRelational); inline QualType CheckBitwiseOperands( // C99 6.5.[10...12] - Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); + Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false); inline QualType CheckLogicalOperands( // C99 6.5.[13,14] Expr *&lex, Expr *&rex, SourceLocation OpLoc); // CheckAssignmentOperands is used for both simple and compound assignment. diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 8c8207a39d..3de916fe3c 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "SemaInherit.h" #include "Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" @@ -2701,7 +2702,73 @@ inline QualType Sema::CheckVectorOperands(SourceLocation Loc, Expr *&lex, << lex->getType() << rex->getType() << lex->getSourceRange() << rex->getSourceRange(); return QualType(); -} +} + +inline QualType Sema::CheckPointerToMemberOperands( + Expr *&lex, Expr *&rex, SourceLocation Loc, bool isIndirect) +{ + const char *OpSpelling = isIndirect ? "->*" : ".*"; + // C++ 5.5p2 + // The binary operator .* [p3: ->*] binds its second operand, which shall + // be of type "pointer to member of T" (where T is a completely-defined + // class type) [...] + QualType RType = rex->getType(); + const MemberPointerType *MemPtr = RType->getAsMemberPointerType(); + if (!MemPtr || MemPtr->getClass()->isIncompleteType()) { + Diag(Loc, diag::err_bad_memptr_rhs) + << OpSpelling << RType << rex->getSourceRange(); + return QualType(); + } + QualType Class(MemPtr->getClass(), 0); + + // C++ 5.5p2 + // [...] to its first operand, which shall be of class T or of a class of + // which T is an unambiguous and accessible base class. [p3: a pointer to + // such a class] + QualType LType = lex->getType(); + if (isIndirect) { + if (const PointerType *Ptr = LType->getAsPointerType()) + LType = Ptr->getPointeeType().getNonReferenceType(); + else { + Diag(Loc, diag::err_bad_memptr_lhs) + << 1 << LType << lex->getSourceRange(); + return QualType(); + } + } + + if (Context.getCanonicalType(Class).getUnqualifiedType() != + Context.getCanonicalType(LType).getUnqualifiedType()) { + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/false); + // FIXME: Would it be useful to print full ambiguity paths, + // or is that overkill? + if (!IsDerivedFrom(LType, Class, Paths) || + Paths.isAmbiguous(Context.getCanonicalType(Class))) { + Diag(Loc, diag::err_bad_memptr_lhs) + << (int)isIndirect << lex->getType() << lex->getSourceRange(); + return QualType(); + } + } + + // C++ 5.5p2 + // The result is an object or a function of the type specified by the + // second operand. + // The cv qualifiers are the union of those in the pointer and the left side, + // in accordance with 5.5p5 and 5.2.5. + // FIXME: This returns a dereferenced member function pointer as a normal + // function type. However, the only operation valid on such functions is + // calling them. There's also a GCC extension to get a function pointer to + // the thing, which is another complication, because this type - unlike the + // type that is the result of this expression - takes the class as the first + // argument. + // We probably need a "MemberFunctionClosureType" or something like that. + QualType Result = MemPtr->getPointeeType(); + if (LType.isConstQualified()) + Result.addConst(); + if (LType.isVolatileQualified()) + Result.addVolatile(); + return Result; +} inline QualType Sema::CheckMultiplyDivideOperands( Expr *&lex, Expr *&rex, SourceLocation Loc, bool isCompAssign) @@ -3535,6 +3602,8 @@ static inline BinaryOperator::Opcode ConvertTokenKindToBinaryOpcode( BinaryOperator::Opcode Opc; switch (Kind) { default: assert(0 && "Unknown binop!"); + case tok::periodstar: Opc = BinaryOperator::PtrMemD; break; + case tok::arrowstar: Opc = BinaryOperator::PtrMemI; break; case tok::star: Opc = BinaryOperator::Mul; break; case tok::slash: Opc = BinaryOperator::Div; break; case tok::percent: Opc = BinaryOperator::Rem; break; @@ -3605,7 +3674,12 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BinaryOperator::Assign: ResultTy = CheckAssignmentOperands(lhs, rhs, OpLoc, QualType()); break; - case BinaryOperator::Mul: + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + ResultTy = CheckPointerToMemberOperands(lhs, rhs, OpLoc, + Opc == BinaryOperator::PtrMemI); + break; + case BinaryOperator::Mul: case BinaryOperator::Div: ResultTy = CheckMultiplyDivideOperands(lhs, rhs, OpLoc); break; @@ -3618,7 +3692,7 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BinaryOperator::Sub: ResultTy = CheckSubtractionOperands(lhs, rhs, OpLoc); break; - case BinaryOperator::Shl: + case BinaryOperator::Shl: case BinaryOperator::Shr: ResultTy = CheckShiftOperands(lhs, rhs, OpLoc); break; @@ -3707,11 +3781,11 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, Context.DependentTy, Context.DependentTy, TokLoc)); else - return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, Context.DependentTy, - TokLoc)); + return Owned(new (Context) BinaryOperator(lhs, rhs, Opc, + Context.DependentTy, TokLoc)); } - if (getLangOptions().CPlusPlus && + if (getLangOptions().CPlusPlus && Opc != BinaryOperator::PtrMemD && (lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType() || rhs->getType()->isRecordType() || rhs->getType()->isEnumeralType())) { // If this is one of the assignment operators, we only perform @@ -3724,6 +3798,8 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, // Determine which overloaded operator we're dealing with. static const OverloadedOperatorKind OverOps[] = { + // Overloading .* is not possible. + static_cast<OverloadedOperatorKind>(0), OO_ArrowStar, OO_Star, OO_Slash, OO_Percent, OO_Plus, OO_Minus, OO_LessLess, OO_GreaterGreater, diff --git a/lib/Sema/SemaInherit.h b/lib/Sema/SemaInherit.h index eb169a2982..311c136a0f 100644 --- a/lib/Sema/SemaInherit.h +++ b/lib/Sema/SemaInherit.h @@ -16,6 +16,7 @@ #ifndef LLVM_CLANG_SEMA_INHERIT_H #define LLVM_CLANG_SEMA_INHERIT_H +#include "Sema.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/DeclBase.h" #include "clang/AST/Type.h" @@ -25,7 +26,6 @@ #include <map> namespace clang { - class Sema; class CXXBaseSpecifier; class CXXRecordType; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 78b2626416..ee4c14d0ca 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -610,8 +610,8 @@ Sema::CppLookupName(Scope *S, DeclarationName Name, // using-directives later. for (OutOfLineCtx = Ctx; OutOfLineCtx && !OutOfLineCtx->isFileContext(); OutOfLineCtx = OutOfLineCtx->getParent()) { - if (R = LookupQualifiedName(OutOfLineCtx, Name, NameKind, - RedeclarationOnly)) + if ((R = LookupQualifiedName(OutOfLineCtx, Name, NameKind, + RedeclarationOnly))) return std::make_pair(true, R); } } @@ -638,7 +638,7 @@ Sema::CppLookupName(Scope *S, DeclarationName Name, // context as well as walking through the scopes. LookupResultsTy LookupResults; - assert(!OutOfLineCtx || OutOfLineCtx->isFileContext() && + assert((!OutOfLineCtx || OutOfLineCtx->isFileContext()) && "We should have been looking only at file context here already."); bool LookedInCtx = false; LookupResult Result; diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index 64cfc68c01..7d71b49fca 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -79,3 +79,28 @@ void g() { void (HasMembers::*pmd)() = &HasMembers::d; } + +void h() { + HasMembers hm, *phm = &hm; + + int HasMembers::*pi = &HasMembers::i; + hm.*pi = 0; + int i = phm->*pi; + (void)&(hm.*pi); + (void)&(phm->*pi); + (void)&((&hm)->*pi); // expected-error {{address expression must be an lvalue or a function designator}} + + void (HasMembers::*pf)() = &HasMembers::f; + (hm.*pf)(); + (phm->*pf)(); +} + +struct OverloadsPtrMem +{ + int operator ->*(const char *); +}; + +void i() { + OverloadsPtrMem m; + int foo = m->*"Awesome!"; +} diff --git a/www/cxx_status.html b/www/cxx_status.html index 432e9643af..71bbada508 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -698,11 +698,11 @@ welcome!</p> </tr>
<tr>
<td> 5.5 [expr.mptr.oper]</td>
- <td class="broken"></td>
- <td class="broken"></td>
- <td class="broken"></td>
- <td></td>
+ <td class="complete" align="center">✓</td>
+ <td class="advanced"></td>
+ <td class="advanced"></td>
<td></td>
+ <td>Dereferenced member function pointers have the wrong type.</td>
</tr>
<tr>
<td> 5.6 [expr.mul]</td>
|