forked from OSchip/llvm-project
Implement dereferencing of pointers-to-member.
llvm-svn: 63983
This commit is contained in:
parent
ad41b83816
commit
112a976616
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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!";
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue