diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-02-07 00:15:38 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-02-07 00:15:38 +0000 |
commit | 112a9766164c8f5124a380b7069428f42e4db25b (patch) | |
tree | 590ecdb80f47c586baa908e96ada2aa558a97cd0 /clang/lib/Sema | |
parent | ad41b838167411ddf3d1aeb43ce3436d95834e39 (diff) | |
download | bcm5719-llvm-112a9766164c8f5124a380b7069428f42e4db25b.tar.gz bcm5719-llvm-112a9766164c8f5124a380b7069428f42e4db25b.zip |
Implement dereferencing of pointers-to-member.
llvm-svn: 63983
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Sema.h | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 88 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInherit.h | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 6 |
4 files changed, 94 insertions, 16 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 33b37812009..4878403333a 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 8c8207a39d6..3de916fe3cd 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaInherit.h b/clang/lib/Sema/SemaInherit.h index eb169a2982b..311c136a0ff 100644 --- a/clang/lib/Sema/SemaInherit.h +++ b/clang/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/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 78b26264162..ee4c14d0ca4 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/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; |