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:
Douglas Gregor 2008-11-19 17:17:41 +00:00
parent 0f09564ffc
commit 40412acc02
9 changed files with 128 additions and 9 deletions

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -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];
}

View File

@ -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);
}

View File

@ -981,7 +981,7 @@ welcome!</p>
<td>&nbsp;&nbsp;&nbsp;&nbsp;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>