aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2009-02-07 00:15:38 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2009-02-07 00:15:38 +0000
commit224605064a4ef87d1c3d35ad1cb363f8b534012b (patch)
treee8a4fd33c2d0cf29e5bf199b46456fde514ff7d9 /lib
parent63b4fe6c118c14707d297f6f879e5e7973b8e6ff (diff)
Implement dereferencing of pointers-to-member.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63983 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/Expr.cpp6
-rw-r--r--lib/Parse/ParseExpr.cpp39
-rw-r--r--lib/Sema/Sema.h14
-rw-r--r--lib/Sema/SemaExpr.cpp88
-rw-r--r--lib/Sema/SemaInherit.h2
-rw-r--r--lib/Sema/SemaLookup.cpp6
6 files changed, 124 insertions, 31 deletions
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;