forked from OSchip/llvm-project
Support overloading of the subscript operator[], including support for
built-in operator candidates. Test overloading of '&' and ','. In C++, a comma expression is an lvalue if its right-hand subexpression is an lvalue. Update Expr::isLvalue accordingly. llvm-svn: 59643
This commit is contained in:
parent
0f09564ffc
commit
40412acc02
|
@ -441,8 +441,9 @@ namespace {
|
|||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
||||
ExprTy *Idx, SourceLocation RLoc) {
|
||||
virtual ExprResult ActOnArraySubscriptExpr(Scope *S, ExprTy *Base,
|
||||
SourceLocation LLoc, ExprTy *Idx,
|
||||
SourceLocation RLoc) {
|
||||
llvm::cout << __FUNCTION__ << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -513,7 +513,8 @@ public:
|
|||
tok::TokenKind Kind, ExprTy *Input) {
|
||||
return 0;
|
||||
}
|
||||
virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
||||
virtual ExprResult ActOnArraySubscriptExpr(Scope *S,
|
||||
ExprTy *Base, SourceLocation LLoc,
|
||||
ExprTy *Idx, SourceLocation RLoc) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -412,6 +412,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
|
|||
case BinaryOperatorClass:
|
||||
case CompoundAssignOperatorClass: {
|
||||
const BinaryOperator *BinOp = cast<BinaryOperator>(this);
|
||||
|
||||
if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.comma]p1
|
||||
BinOp->getOpcode() == BinaryOperator::Comma)
|
||||
return BinOp->getRHS()->isLvalue(Ctx);
|
||||
|
||||
if (!BinOp->isAssignmentOp())
|
||||
return LV_InvalidExpression;
|
||||
|
||||
|
|
|
@ -672,7 +672,8 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
|||
SourceLocation RLoc = Tok.getLocation();
|
||||
|
||||
if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square))
|
||||
LHS = Actions.ActOnArraySubscriptExpr(LHS.Val, Loc, Idx.Val, RLoc);
|
||||
LHS = Actions.ActOnArraySubscriptExpr(CurScope, LHS.Val, Loc,
|
||||
Idx.Val, RLoc);
|
||||
else
|
||||
LHS = ExprResult(true);
|
||||
|
||||
|
|
|
@ -652,8 +652,9 @@ public:
|
|||
virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
||||
tok::TokenKind Kind, ExprTy *Input);
|
||||
|
||||
virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
||||
ExprTy *Idx, SourceLocation RLoc);
|
||||
virtual ExprResult ActOnArraySubscriptExpr(Scope *S, ExprTy *Base,
|
||||
SourceLocation LLoc, ExprTy *Idx,
|
||||
SourceLocation RLoc);
|
||||
virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
|
||||
tok::TokenKind OpKind,
|
||||
SourceLocation MemberLoc,
|
||||
|
|
|
@ -861,10 +861,93 @@ Action::ExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
|||
}
|
||||
|
||||
Action::ExprResult Sema::
|
||||
ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
||||
ActOnArraySubscriptExpr(Scope *S, ExprTy *Base, SourceLocation LLoc,
|
||||
ExprTy *Idx, SourceLocation RLoc) {
|
||||
Expr *LHSExp = static_cast<Expr*>(Base), *RHSExp = static_cast<Expr*>(Idx);
|
||||
|
||||
if (getLangOptions().CPlusPlus &&
|
||||
LHSExp->getType()->isRecordType() ||
|
||||
LHSExp->getType()->isEnumeralType() ||
|
||||
RHSExp->getType()->isRecordType() ||
|
||||
RHSExp->getType()->isRecordType()) {
|
||||
// Add the appropriate overloaded operators (C++ [over.match.oper])
|
||||
// to the candidate set.
|
||||
OverloadCandidateSet CandidateSet;
|
||||
Expr *Args[2] = { LHSExp, RHSExp };
|
||||
AddOperatorCandidates(OO_Subscript, S, Args, 2, CandidateSet);
|
||||
|
||||
// Perform overload resolution.
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (BestViableFunction(CandidateSet, Best)) {
|
||||
case OR_Success: {
|
||||
// We found a built-in operator or an overloaded operator.
|
||||
FunctionDecl *FnDecl = Best->Function;
|
||||
|
||||
if (FnDecl) {
|
||||
// We matched an overloaded operator. Build a call to that
|
||||
// operator.
|
||||
|
||||
// Convert the arguments.
|
||||
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
|
||||
if (PerformObjectArgumentInitialization(LHSExp, Method) ||
|
||||
PerformCopyInitialization(RHSExp,
|
||||
FnDecl->getParamDecl(0)->getType(),
|
||||
"passing"))
|
||||
return true;
|
||||
} else {
|
||||
// Convert the arguments.
|
||||
if (PerformCopyInitialization(LHSExp,
|
||||
FnDecl->getParamDecl(0)->getType(),
|
||||
"passing") ||
|
||||
PerformCopyInitialization(RHSExp,
|
||||
FnDecl->getParamDecl(1)->getType(),
|
||||
"passing"))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine the result type
|
||||
QualType ResultTy
|
||||
= FnDecl->getType()->getAsFunctionType()->getResultType();
|
||||
ResultTy = ResultTy.getNonReferenceType();
|
||||
|
||||
// Build the actual expression node.
|
||||
Expr *FnExpr = new DeclRefExpr(FnDecl, FnDecl->getType(),
|
||||
SourceLocation());
|
||||
UsualUnaryConversions(FnExpr);
|
||||
|
||||
return new CXXOperatorCallExpr(FnExpr, Args, 2, ResultTy, LLoc);
|
||||
} else {
|
||||
// We matched a built-in operator. Convert the arguments, then
|
||||
// break out so that we will build the appropriate built-in
|
||||
// operator node.
|
||||
if (PerformCopyInitialization(LHSExp, Best->BuiltinTypes.ParamTypes[0],
|
||||
"passing") ||
|
||||
PerformCopyInitialization(RHSExp, Best->BuiltinTypes.ParamTypes[1],
|
||||
"passing"))
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case OR_No_Viable_Function:
|
||||
// No viable function; fall through to handling this as a
|
||||
// built-in operator, which will produce an error message for us.
|
||||
break;
|
||||
|
||||
case OR_Ambiguous:
|
||||
Diag(LLoc, diag::err_ovl_ambiguous_oper)
|
||||
<< "[]"
|
||||
<< LHSExp->getSourceRange() << RHSExp->getSourceRange();
|
||||
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Either we found no viable overloaded operator or we matched a
|
||||
// built-in operator. In either case, fall through to trying to
|
||||
// build a built-in operation.
|
||||
}
|
||||
|
||||
// Perform default conversions.
|
||||
DefaultFunctionArrayConversion(LHSExp);
|
||||
DefaultFunctionArrayConversion(RHSExp);
|
||||
|
@ -3009,7 +3092,6 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
|
|||
// built-in operator. In either case, fall through to trying to
|
||||
// build a built-in operation.
|
||||
}
|
||||
|
||||
|
||||
// Build a built-in binary operation.
|
||||
return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
|
||||
|
|
|
@ -113,5 +113,9 @@ void test_with_ptrs(VolatileIntPtr vip, ConstIntPtr cip, ShortRef sr,
|
|||
int volatile *vip2 = +vip;
|
||||
int i1 = +sr;
|
||||
int i2 = -sr;
|
||||
|
||||
// C++ [over.built]p13:
|
||||
int volatile &ivr2 = vip[17];
|
||||
int const &icr2 = 17[cip];
|
||||
}
|
||||
|
||||
|
|
|
@ -97,3 +97,27 @@ void test_smartptr(SmartPtr ptr, const SmartPtr cptr) {
|
|||
int &ir = *ptr;
|
||||
// FIXME: reinstate long &lr = *cptr;
|
||||
}
|
||||
|
||||
|
||||
struct ArrayLike {
|
||||
int& operator[](int);
|
||||
};
|
||||
|
||||
void test_arraylike(ArrayLike a) {
|
||||
int& ir = a[17];
|
||||
}
|
||||
|
||||
struct SmartRef {
|
||||
int* operator&();
|
||||
};
|
||||
|
||||
void test_smartref(SmartRef r) {
|
||||
int* ip = &r;
|
||||
}
|
||||
|
||||
bool& operator,(X, Y);
|
||||
|
||||
void test_comma(X x, Y y) {
|
||||
bool& b1 = (x, y);
|
||||
X& xr = (x, x);
|
||||
}
|
||||
|
|
|
@ -981,7 +981,7 @@ welcome!</p>
|
|||
<td> 13.5.5 [over.sub]</td>
|
||||
<td class="na" align="center">N/A</td>
|
||||
<td class="advanced" align="center"></td>
|
||||
<td class="basic" align="center"></td>
|
||||
<td class="advanced" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
|
Loading…
Reference in New Issue