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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59643 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp
index 2a85f64..2ee113f 100644
--- a/Driver/PrintParserCallbacks.cpp
+++ b/Driver/PrintParserCallbacks.cpp
@@ -441,8 +441,9 @@
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;
}
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 7178543..d662529 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -513,7 +513,8 @@
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;
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index a179af8..0614020 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -412,6 +412,11 @@
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;
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 5f36f0b..74b0715 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -672,7 +672,8 @@
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);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index b10a98f..983fa30 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -652,8 +652,9 @@
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,
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c780372..a780012 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -861,10 +861,93 @@
}
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 @@
// 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);
diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp
index 29d721c..41509f9 100644
--- a/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -113,5 +113,9 @@
int volatile *vip2 = +vip;
int i1 = +sr;
int i2 = -sr;
+
+ // C++ [over.built]p13:
+ int volatile &ivr2 = vip[17];
+ int const &icr2 = 17[cip];
}
diff --git a/test/SemaCXX/overloaded-operator.cpp b/test/SemaCXX/overloaded-operator.cpp
index 2948656..1eb86bd 100644
--- a/test/SemaCXX/overloaded-operator.cpp
+++ b/test/SemaCXX/overloaded-operator.cpp
@@ -97,3 +97,27 @@
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);
+}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 7c51fb3..6db2840 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -981,7 +981,7 @@
<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>