зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
5cb93b8bf0
Коммит
337c6b9f5d
|
@ -441,8 +441,9 @@ namespace {
|
||||||
llvm::cout << __FUNCTION__ << "\n";
|
llvm::cout << __FUNCTION__ << "\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
virtual ExprResult ActOnArraySubscriptExpr(Scope *S, ExprTy *Base,
|
||||||
ExprTy *Idx, SourceLocation RLoc) {
|
SourceLocation LLoc, ExprTy *Idx,
|
||||||
|
SourceLocation RLoc) {
|
||||||
llvm::cout << __FUNCTION__ << "\n";
|
llvm::cout << __FUNCTION__ << "\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -513,7 +513,8 @@ public:
|
||||||
tok::TokenKind Kind, ExprTy *Input) {
|
tok::TokenKind Kind, ExprTy *Input) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
virtual ExprResult ActOnArraySubscriptExpr(Scope *S,
|
||||||
|
ExprTy *Base, SourceLocation LLoc,
|
||||||
ExprTy *Idx, SourceLocation RLoc) {
|
ExprTy *Idx, SourceLocation RLoc) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -412,6 +412,11 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
|
||||||
case BinaryOperatorClass:
|
case BinaryOperatorClass:
|
||||||
case CompoundAssignOperatorClass: {
|
case CompoundAssignOperatorClass: {
|
||||||
const BinaryOperator *BinOp = cast<BinaryOperator>(this);
|
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())
|
if (!BinOp->isAssignmentOp())
|
||||||
return LV_InvalidExpression;
|
return LV_InvalidExpression;
|
||||||
|
|
||||||
|
|
|
@ -672,7 +672,8 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
|
||||||
SourceLocation RLoc = Tok.getLocation();
|
SourceLocation RLoc = Tok.getLocation();
|
||||||
|
|
||||||
if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square))
|
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
|
else
|
||||||
LHS = ExprResult(true);
|
LHS = ExprResult(true);
|
||||||
|
|
||||||
|
|
|
@ -652,8 +652,9 @@ public:
|
||||||
virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
virtual ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
||||||
tok::TokenKind Kind, ExprTy *Input);
|
tok::TokenKind Kind, ExprTy *Input);
|
||||||
|
|
||||||
virtual ExprResult ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
virtual ExprResult ActOnArraySubscriptExpr(Scope *S, ExprTy *Base,
|
||||||
ExprTy *Idx, SourceLocation RLoc);
|
SourceLocation LLoc, ExprTy *Idx,
|
||||||
|
SourceLocation RLoc);
|
||||||
virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
|
virtual ExprResult ActOnMemberReferenceExpr(ExprTy *Base,SourceLocation OpLoc,
|
||||||
tok::TokenKind OpKind,
|
tok::TokenKind OpKind,
|
||||||
SourceLocation MemberLoc,
|
SourceLocation MemberLoc,
|
||||||
|
|
|
@ -861,10 +861,93 @@ Action::ExprResult Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
||||||
}
|
}
|
||||||
|
|
||||||
Action::ExprResult Sema::
|
Action::ExprResult Sema::
|
||||||
ActOnArraySubscriptExpr(ExprTy *Base, SourceLocation LLoc,
|
ActOnArraySubscriptExpr(Scope *S, ExprTy *Base, SourceLocation LLoc,
|
||||||
ExprTy *Idx, SourceLocation RLoc) {
|
ExprTy *Idx, SourceLocation RLoc) {
|
||||||
Expr *LHSExp = static_cast<Expr*>(Base), *RHSExp = static_cast<Expr*>(Idx);
|
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.
|
// Perform default conversions.
|
||||||
DefaultFunctionArrayConversion(LHSExp);
|
DefaultFunctionArrayConversion(LHSExp);
|
||||||
DefaultFunctionArrayConversion(RHSExp);
|
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
|
// built-in operator. In either case, fall through to trying to
|
||||||
// build a built-in operation.
|
// build a built-in operation.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Build a built-in binary operation.
|
// Build a built-in binary operation.
|
||||||
return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
|
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 volatile *vip2 = +vip;
|
||||||
int i1 = +sr;
|
int i1 = +sr;
|
||||||
int i2 = -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;
|
int &ir = *ptr;
|
||||||
// FIXME: reinstate long &lr = *cptr;
|
// 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> 13.5.5 [over.sub]</td>
|
||||||
<td class="na" align="center">N/A</td>
|
<td class="na" align="center">N/A</td>
|
||||||
<td class="advanced" align="center"></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 class="broken" align="center"></td>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче