Refactor the way we handle operator overloading and template

instantiation for binary operators. This change moves most of the
operator-overloading code from the parser action ActOnBinOp to a new,
parser-independent semantic checking routine CreateOverloadedBinOp. 

Of particular importance is the fact that CreateOverloadedBinOp does
*not* perform any name lookup based on the current parsing context (it
doesn't take a Scope*), since it has to be usable during template
instantiation, when there is no scope information. Rather, it takes a
pre-computed set of functions that are visible from the context or via
argument-dependent lookup, and adds to that set any member operators
and built-in operator candidates. The set of functions is computed in
the parser action ActOnBinOp based on the current context (both
operator name lookup and argument-dependent lookup). Within a
template, the set computed by ActOnBinOp is saved within the
type-dependent AST node and is augmented with the results of
argument-dependent name lookup at instantiation time (see
TemplateExprInstantiator::VisitCXXOperatorCallExpr).

Sadly, we can't fully test this yet. I'll follow up with template
instantiation for sizeof so that the real fun can begin.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66923 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-03-13 18:40:31 +00:00
Родитель 13135a6171
Коммит 063daf6e19
11 изменённых файлов: 398 добавлений и 255 удалений

Просмотреть файл

@ -1245,6 +1245,14 @@ public:
/// corresponds to, e.g. "<<=".
static const char *getOpcodeStr(Opcode Op);
/// \brief Retrieve the binary opcode that corresponds to the given
/// overloaded operator.
static Opcode getOverloadedOpcode(OverloadedOperatorKind OO);
/// \brief Retrieve the overloaded operator kind that corresponds to
/// the given binary opcode.
static OverloadedOperatorKind getOverloadedOperator(Opcode Opc);
/// predicates to categorize the respective opcodes.
bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; }
bool isAdditiveOp() const { return Opc == Add || Opc == Sub; }

Просмотреть файл

@ -40,14 +40,19 @@ namespace clang {
/// function templates that were found by name lookup at template
/// definition time.
class CXXOperatorCallExpr : public CallExpr {
/// \brief The overloaded operator.
OverloadedOperatorKind Operator;
public:
CXXOperatorCallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
QualType t, SourceLocation operatorloc)
: CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc){}
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
Expr **args, unsigned numargs, QualType t,
SourceLocation operatorloc)
: CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc),
Operator(Op) {}
/// getOperator - Returns the kind of overloaded operator that this
/// expression refers to.
OverloadedOperatorKind getOperator() const;
OverloadedOperatorKind getOperator() const { return Operator; }
/// getOperatorLoc - Returns the location of the operator symbol in
/// the expression. When @c getOperator()==OO_Call, this is the

Просмотреть файл

@ -361,7 +361,7 @@ public:
/// that its definition somehow depends on a template parameter
/// (C++ [temp.dep.type]).
bool isDependentType() const { return Dependent; }
bool isOverloadType() const; // C++ overloaded function
bool isOverloadableType() const;
/// hasPointerRepresentation - Whether this type is represented
/// natively as a pointer; this includes pointers, references, block
@ -1860,8 +1860,10 @@ inline bool Type::isSpecificBuiltinType(unsigned K) const {
return false;
}
inline bool Type::isOverloadType() const {
return isSpecificBuiltinType(BuiltinType::Overload);
/// \brief Determines whether this is a type for which one can define
/// an overloaded operator.
inline bool Type::isOverloadableType() const {
return isDependentType() || isRecordType() || isEnumeralType();
}
inline bool Type::hasPointerRepresentation() const {

Просмотреть файл

@ -227,6 +227,68 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
return "";
}
BinaryOperator::Opcode
BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
switch (OO) {
case OO_Plus: return Add;
case OO_Minus: return Sub;
case OO_Star: return Mul;
case OO_Slash: return Div;
case OO_Percent: return Rem;
case OO_Caret: return Xor;
case OO_Amp: return And;
case OO_Pipe: return Or;
case OO_Equal: return Assign;
case OO_Less: return LT;
case OO_Greater: return GT;
case OO_PlusEqual: return AddAssign;
case OO_MinusEqual: return SubAssign;
case OO_StarEqual: return MulAssign;
case OO_SlashEqual: return DivAssign;
case OO_PercentEqual: return RemAssign;
case OO_CaretEqual: return XorAssign;
case OO_AmpEqual: return AndAssign;
case OO_PipeEqual: return OrAssign;
case OO_LessLess: return Shl;
case OO_GreaterGreater: return Shr;
case OO_LessLessEqual: return ShlAssign;
case OO_GreaterGreaterEqual: return ShrAssign;
case OO_EqualEqual: return EQ;
case OO_ExclaimEqual: return NE;
case OO_LessEqual: return LE;
case OO_GreaterEqual: return GE;
case OO_AmpAmp: return LAnd;
case OO_PipePipe: return LOr;
case OO_Comma: return Comma;
case OO_ArrowStar: return PtrMemI;
default: assert(false && "Not an overloadable binary operator");
}
}
OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
static const OverloadedOperatorKind OverOps[] = {
/* .* Cannot be overloaded */OO_None, OO_ArrowStar,
OO_Star, OO_Slash, OO_Percent,
OO_Plus, OO_Minus,
OO_LessLess, OO_GreaterGreater,
OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
OO_EqualEqual, OO_ExclaimEqual,
OO_Amp,
OO_Caret,
OO_Pipe,
OO_AmpAmp,
OO_PipePipe,
OO_Equal, OO_StarEqual,
OO_SlashEqual, OO_PercentEqual,
OO_PlusEqual, OO_MinusEqual,
OO_LessLessEqual, OO_GreaterGreaterEqual,
OO_AmpEqual, OO_CaretEqual,
OO_PipeEqual,
OO_Comma
};
return OverOps[Opc];
}
InitListExpr::InitListExpr(SourceLocation lbraceloc,
Expr **initExprs, unsigned numInits,
SourceLocation rbraceloc)

Просмотреть файл

@ -160,27 +160,6 @@ bool UnaryTypeTraitExpr::EvaluateTrait() const {
}
}
OverloadedOperatorKind CXXOperatorCallExpr::getOperator() const {
// All simple function calls (e.g. func()) are implicitly cast to pointer to
// function. As a result, we try and obtain the DeclRefExpr from the
// ImplicitCastExpr.
const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee());
if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()).
return OO_None;
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
if (!DRE)
return OO_None;
if (const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
return FDecl->getDeclName().getCXXOverloadedOperator();
else if (const OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(DRE->getDecl()))
return Ovl->getDeclName().getCXXOverloadedOperator();
else
return OO_None;
}
SourceRange CXXOperatorCallExpr::getSourceRange() const {
OverloadedOperatorKind Kind = getOperator();
if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {

Просмотреть файл

@ -523,10 +523,18 @@ public:
OR_Deleted ///< Overload resoltuion refers to a deleted function.
};
typedef llvm::SmallPtrSet<FunctionDecl *, 16> FunctionSet;
typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
void AddOverloadCandidate(FunctionDecl *Function,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddFunctionCandidates(const FunctionSet &Functions,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false);
void AddMethodCandidate(CXXMethodDecl *Method,
Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@ -538,11 +546,16 @@ public:
const FunctionProtoType *Proto,
Expr *Object, Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet);
bool AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
void AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
SourceLocation OpLoc,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange = SourceRange());
void AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange = SourceRange());
void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@ -572,6 +585,12 @@ public:
SourceLocation *CommaLocs,
SourceLocation RParenLoc,
bool &ArgumentDependentLookup);
OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
unsigned Opc,
FunctionSet &Functions,
Expr *LHS, Expr *RHS);
ExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
SourceLocation LParenLoc, Expr **Args,
@ -930,10 +949,6 @@ public:
bool AllowBuiltinCreation = true,
SourceLocation Loc = SourceLocation());
typedef llvm::SmallPtrSet<FunctionDecl *, 16> FunctionSet;
typedef llvm::SmallPtrSet<NamespaceDecl *, 16> AssociatedNamespaceSet;
typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet;
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
QualType T1, QualType T2,
FunctionSet &Functions);

Просмотреть файл

@ -1694,7 +1694,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
// If the initializer is the address of an overloaded function, try
// to resolve the overloaded function. If all goes well, T2 is the
// type of the resulting function.
if (T2->isOverloadType()) {
if (Context.getCanonicalType(T2) == Context.OverloadTy) {
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
ICS != 0);
if (Fn) {

Просмотреть файл

@ -1324,8 +1324,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
// Build the candidate set for overloading
OverloadCandidateSet CandidateSet;
if (AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet))
return ExprError();
AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet);
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
@ -1361,8 +1360,9 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
UsualUnaryConversions(FnExpr);
Input.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
ResultTy, OpLoc));
return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
Args, 2, ResultTy,
OpLoc));
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in
@ -1424,9 +1424,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
// to the candidate set.
OverloadCandidateSet CandidateSet;
Expr *Args[2] = { LHSExp, RHSExp };
if (AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
SourceRange(LLoc, RLoc)))
return ExprError();
AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
SourceRange(LLoc, RLoc));
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
@ -1469,7 +1468,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
Base.release();
Idx.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript,
FnExpr, Args, 2,
ResultTy, LLoc));
} else {
// We matched a built-in operator. Convert the arguments, then
@ -3977,32 +3977,6 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
CompTy, OpLoc));
}
static OverloadedOperatorKind
getOverloadedOperator(BinaryOperator::Opcode Opc) {
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,
OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
OO_EqualEqual, OO_ExclaimEqual,
OO_Amp,
OO_Caret,
OO_Pipe,
OO_AmpAmp,
OO_PipePipe,
OO_Equal, OO_StarEqual,
OO_SlashEqual, OO_PercentEqual,
OO_PlusEqual, OO_MinusEqual,
OO_LessLessEqual, OO_GreaterGreaterEqual,
OO_AmpEqual, OO_CaretEqual,
OO_PipeEqual,
OO_Comma
};
return OverOps[Opc];
}
// Binary Operators. 'Tok' is the token for the operator.
Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
tok::TokenKind Kind,
@ -4013,139 +3987,27 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
assert((lhs != 0) && "ActOnBinOp(): missing left expression");
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
// If either expression is type-dependent, just build the AST.
if (lhs->isTypeDependent() || rhs->isTypeDependent()) {
// .* cannot be overloaded.
if (Opc == BinaryOperator::PtrMemD)
return Owned(new (Context) BinaryOperator(lhs, rhs, Opc,
Context.DependentTy, TokLoc));
// Find all of the overloaded operators visible from the template
// definition. We perform both an operator-name lookup from the
// local scope and an argument-dependent lookup based on the types
// of the arguments.
if (getLangOptions().CPlusPlus &&
(lhs->getType()->isOverloadableType() ||
rhs->getType()->isOverloadableType())) {
// Find all of the overloaded operators visible from this
// point. We perform both an operator-name lookup from the local
// scope and an argument-dependent lookup based on the types of
// the arguments.
FunctionSet Functions;
OverloadedOperatorKind OverOp = getOverloadedOperator(Opc);
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
Functions);
Expr *Args[2] = { lhs, rhs };
DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, Args, 2, Functions);
OverloadedFunctionDecl *Overloads
= OverloadedFunctionDecl::Create(Context, CurContext, OpName);
for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func)
Overloads->addOverload(*Func);
DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
TokLoc, false, false);
return Owned(new (Context) CXXOperatorCallExpr(Context, Fn,
Args, 2,
Context.DependentTy,
TokLoc));
}
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
// overload resolution if the left-hand side is a class or
// enumeration type (C++ [expr.ass]p3).
if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign &&
!(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType())) {
return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
if (OverOp != OO_None) {
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
Functions);
Expr *Args[2] = { lhs, rhs };
DeclarationName OpName
= Context.DeclarationNames.getCXXOperatorName(OverOp);
ArgumentDependentLookup(OpName, Args, 2, Functions);
}
// Determine which overloaded operator we're dealing with.
// Add the appropriate overloaded operators (C++ [over.match.oper])
// to the candidate set.
OverloadCandidateSet CandidateSet;
OverloadedOperatorKind OverOp = getOverloadedOperator(Opc);
Expr *Args[2] = { lhs, rhs };
if (AddOperatorCandidates(OverOp, S, TokLoc, Args, 2, CandidateSet))
return ExprError();
// 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(lhs, Method) ||
PerformCopyInitialization(rhs, FnDecl->getParamDecl(0)->getType(),
"passing"))
return ExprError();
} else {
// Convert the arguments.
if (PerformCopyInitialization(lhs, FnDecl->getParamDecl(0)->getType(),
"passing") ||
PerformCopyInitialization(rhs, FnDecl->getParamDecl(1)->getType(),
"passing"))
return ExprError();
}
// Determine the result type
QualType ResultTy
= FnDecl->getType()->getAsFunctionType()->getResultType();
ResultTy = ResultTy.getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
SourceLocation());
UsualUnaryConversions(FnExpr);
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
ResultTy, TokLoc));
} 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 (PerformImplicitConversion(lhs, Best->BuiltinTypes.ParamTypes[0],
Best->Conversions[0], "passing") ||
PerformImplicitConversion(rhs, Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], "passing"))
return ExprError();
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(TokLoc, diag::err_ovl_ambiguous_oper)
<< BinaryOperator::getOpcodeStr(Opc)
<< lhs->getSourceRange() << rhs->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return ExprError();
case OR_Deleted:
Diag(TokLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< BinaryOperator::getOpcodeStr(Opc)
<< lhs->getSourceRange() << rhs->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return ExprError();
}
// 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.
// Build the (potentially-overloaded, potentially-dependent)
// binary operation.
return CreateOverloadedBinOp(TokLoc, Opc, Functions, lhs, rhs);
}
// Build a built-in binary operation.
@ -4178,9 +4040,8 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
// Add the appropriate overloaded operators (C++ [over.match.oper])
// to the candidate set.
OverloadCandidateSet CandidateSet;
if (OverOp != OO_None &&
AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet))
return ExprError();
if (OverOp != OO_None)
AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet);
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
@ -4216,8 +4077,9 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
UsualUnaryConversions(FnExpr);
input.release();
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, &Input,
1, ResultTy, OpLoc));
return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
&Input, 1, ResultTy,
OpLoc));
} else {
// We matched a built-in operator. Convert the arguments, then
// break out so that we will build the appropriate built-in

Просмотреть файл

@ -800,7 +800,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
break;
case ICK_Function_To_Pointer:
if (FromType->isOverloadType()) {
if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
if (!Fn)
return true;

Просмотреть файл

@ -468,7 +468,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
Expr::isLvalueResult argIsLvalue = From->isLvalue(Context);
if (argIsLvalue == Expr::LV_Valid &&
!FromType->isFunctionType() && !FromType->isArrayType() &&
!FromType->isOverloadType()) {
Context.getCanonicalType(FromType) != Context.OverloadTy) {
SCS.First = ICK_Lvalue_To_Rvalue;
// If T is a non-class type, the type of the rvalue is the
@ -2064,6 +2064,19 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
}
}
/// \brief Add all of the function declarations in the given function set to
/// the overload canddiate set.
void Sema::AddFunctionCandidates(const FunctionSet &Functions,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions) {
for (FunctionSet::const_iterator F = Functions.begin(),
FEnd = Functions.end();
F != FEnd; ++F)
AddOverloadCandidate(*F, Args, NumArgs, CandidateSet,
SuppressUserConversions);
}
/// AddMethodCandidate - Adds the given C++ member function to the set
/// of candidate functions, using the given function call arguments
/// and the object argument (@c Object). For example, in a call
@ -2308,17 +2321,43 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
}
}
/// AddOperatorCandidates - Add the overloaded operator candidates for
/// the operator Op that was used in an operator expression such as "x
/// Op y". S is the scope in which the expression occurred (used for
/// name lookup of the operator), Args/NumArgs provides the operator
/// arguments, and CandidateSet will store the added overload
/// candidates. (C++ [over.match.oper]).
bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
// FIXME: This will eventually be removed, once we've migrated all of
// the operator overloading logic over to the scheme used by binary
// operators, which works for template instantiation.
void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
SourceLocation OpLoc,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange) {
FunctionSet Functions;
QualType T1 = Args[0]->getType();
QualType T2;
if (NumArgs > 1)
T2 = Args[1]->getType();
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
LookupOverloadedOperatorName(Op, S, T1, T2, Functions);
ArgumentDependentLookup(OpName, Args, NumArgs, Functions);
AddFunctionCandidates(Functions, Args, NumArgs, CandidateSet);
AddMemberOperatorCandidates(Op, OpLoc, Args, NumArgs, CandidateSet, OpRange);
AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet);
}
/// \brief Add overload candidates for overloaded operators that are
/// member functions.
///
/// Add the overloaded operator candidates that are member functions
/// for the operator Op that was used in an operator expression such
/// as "x Op y". , Args/NumArgs provides the operator arguments, and
/// CandidateSet will store the added overload candidates. (C++
/// [over.match.oper]).
void Sema::AddMemberOperatorCandidates(OverloadedOperatorKind Op,
SourceLocation OpLoc,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
SourceRange OpRange) {
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
// C++ [over.match.oper]p3:
@ -2338,6 +2377,7 @@ bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
// result of the qualified lookup of T1::operator@
// (13.3.1.1.1); otherwise, the set of member candidates is
// empty.
// FIXME: Lookup in base classes, too!
if (const RecordType *T1Rec = T1->getAsRecordType()) {
DeclContext::lookup_const_iterator Oper, OperEnd;
for (llvm::tie(Oper, OperEnd) = T1Rec->getDecl()->lookup(OpName);
@ -2346,38 +2386,6 @@ bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
Args+1, NumArgs - 1, CandidateSet,
/*SuppressUserConversions=*/false);
}
FunctionSet Functions;
// -- The set of non-member candidates is the result of the
// unqualified lookup of operator@ in the context of the
// expression according to the usual rules for name lookup in
// unqualified function calls (3.4.2) except that all member
// functions are ignored. However, if no operand has a class
// type, only those non-member functions in the lookup set
// that have a first parameter of type T1 or “reference to
// (possibly cv-qualified) T1”, when T1 is an enumeration
// type, or (if there is a right operand) a second parameter
// of type T2 or “reference to (possibly cv-qualified) T2”,
// when T2 is an enumeration type, are candidate functions.
LookupOverloadedOperatorName(Op, S, T1, T2, Functions);
// Since the set of non-member candidates corresponds to
// *unqualified* lookup of the operator name, we also perform
// argument-dependent lookup (C++ [basic.lookup.argdep]).
ArgumentDependentLookup(OpName, Args, NumArgs, Functions);
// Add all of the functions found via operator name lookup and
// argument-dependent lookup to the candidate set.
for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func)
AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
// Add builtin overload candidates (C++ [over.built]).
AddBuiltinOperatorCandidates(Op, Args, NumArgs, CandidateSet);
return false;
}
/// AddBuiltinCandidate - Add a candidate for a built-in
@ -3615,6 +3623,161 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
return 0;
}
/// \brief Create a binary operation that may resolve to an overloaded
/// operator.
///
/// \param OpLoc The location of the operator itself (e.g., '+').
///
/// \param OpcIn The BinaryOperator::Opcode that describes this
/// operator.
///
/// \param Functions The set of non-member functions that will be
/// considered by overload resolution. The caller needs to build this
/// set based on the context using, e.g.,
/// LookupOverloadedOperatorName() and ArgumentDependentLookup(). This
/// set should not contain any member functions; those will be added
/// by CreateOverloadedBinOp().
///
/// \param LHS Left-hand argument.
/// \param RHS Right-hand argument.
Sema::OwningExprResult
Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
unsigned OpcIn,
FunctionSet &Functions,
Expr *LHS, Expr *RHS) {
OverloadCandidateSet CandidateSet;
Expr *Args[2] = { LHS, RHS };
BinaryOperator::Opcode Opc = static_cast<BinaryOperator::Opcode>(OpcIn);
OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc);
DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op);
// If either side is type-dependent, create an appropriate dependent
// expression.
if (LHS->isTypeDependent() || RHS->isTypeDependent()) {
// .* cannot be overloaded.
if (Opc == BinaryOperator::PtrMemD)
return Owned(new (Context) BinaryOperator(LHS, RHS, Opc,
Context.DependentTy, OpLoc));
OverloadedFunctionDecl *Overloads
= OverloadedFunctionDecl::Create(Context, CurContext, OpName);
for (FunctionSet::iterator Func = Functions.begin(),
FuncEnd = Functions.end();
Func != FuncEnd; ++Func)
Overloads->addOverload(*Func);
DeclRefExpr *Fn = new (Context) DeclRefExpr(Overloads, Context.OverloadTy,
OpLoc, false, false);
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn,
Args, 2,
Context.DependentTy,
OpLoc));
}
// If this is the .* operator, which is not overloadable, just
// create a built-in binary operator.
if (Opc == BinaryOperator::PtrMemD)
return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
// If this is one of the assignment operators, we only perform
// overload resolution if the left-hand side is a class or
// enumeration type (C++ [expr.ass]p3).
if (Opc >= BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign &&
!LHS->getType()->isOverloadableType())
return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
// Add the candidates from the given function set.
AddFunctionCandidates(Functions, Args, 2, CandidateSet, false);
// Add operator candidates that are member functions.
AddMemberOperatorCandidates(Op, OpLoc, Args, 2, CandidateSet);
// Add builtin operator candidates.
AddBuiltinOperatorCandidates(Op, 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(LHS, Method) ||
PerformCopyInitialization(RHS, FnDecl->getParamDecl(0)->getType(),
"passing"))
return ExprError();
} else {
// Convert the arguments.
if (PerformCopyInitialization(LHS, FnDecl->getParamDecl(0)->getType(),
"passing") ||
PerformCopyInitialization(RHS, FnDecl->getParamDecl(1)->getType(),
"passing"))
return ExprError();
}
// Determine the result type
QualType ResultTy
= FnDecl->getType()->getAsFunctionType()->getResultType();
ResultTy = ResultTy.getNonReferenceType();
// Build the actual expression node.
Expr *FnExpr = new (Context) DeclRefExpr(FnDecl, FnDecl->getType(),
SourceLocation());
UsualUnaryConversions(FnExpr);
return Owned(new (Context) CXXOperatorCallExpr(Context, Op, FnExpr,
Args, 2, ResultTy,
OpLoc));
} 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 (PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
Best->Conversions[0], "passing") ||
PerformImplicitConversion(RHS, Best->BuiltinTypes.ParamTypes[1],
Best->Conversions[1], "passing"))
return ExprError();
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(OpLoc, diag::err_ovl_ambiguous_oper)
<< BinaryOperator::getOpcodeStr(Opc)
<< LHS->getSourceRange() << RHS->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return ExprError();
case OR_Deleted:
Diag(OpLoc, diag::err_ovl_deleted_oper)
<< Best->Function->isDeleted()
<< BinaryOperator::getOpcodeStr(Opc)
<< LHS->getSourceRange() << RHS->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/true);
return ExprError();
}
// Either we found no viable overloaded operator or we matched a
// built-in operator. In either case, try to build a built-in
// operation.
return CreateBuiltinBinOp(OpLoc, Opc, LHS, RHS);
}
/// BuildCallToMemberFunction - Build a call to a member
/// function. MemExpr is the expression that refers to the member
/// function (and includes the object parameter), Args/NumArgs are the
@ -3870,8 +4033,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// owned.
QualType ResultTy = Method->getResultType().getNonReferenceType();
ExprOwningPtr<CXXOperatorCallExpr>
TheCall(this, new (Context) CXXOperatorCallExpr(Context, NewFn, MethodArgs,
NumArgs + 1,
TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn,
MethodArgs, NumArgs + 1,
ResultTy, RParenLoc));
delete [] MethodArgs;
@ -3989,7 +4152,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(),
SourceLocation());
UsualUnaryConversions(FnExpr);
Base = new (Context) CXXOperatorCallExpr(Context, FnExpr, &Base, 1,
Base = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1,
Method->getResultType().getNonReferenceType(),
OpLoc);
return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow,

Просмотреть файл

@ -648,9 +648,11 @@ TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) {
Sema::OwningExprResult
TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
// FIXME: HACK HACK HACK. This is so utterly and completely wrong
// that I don't want to explain it here. I'll just fix it tomorrow
// instead.
// FIXME: Only handles binary operators at the moment.
// FIXME: Can we optimize this further if neither the left- nor the
// right-hand sides are type-dependent? It depends on whether we
// need to perform ADL again
Sema::OwningExprResult LHS = Visit(E->getArg(0));
if (LHS.isInvalid())
return SemaRef.ExprError();
@ -659,11 +661,56 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
if (RHS.isInvalid())
return SemaRef.ExprError();
Sema::OwningExprResult Result
= SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(),
BinaryOperator::Add,
(Expr *)LHS.get(),
(Expr *)RHS.get());
Expr *lhs = (Expr *)LHS.get(), *rhs = (Expr *)RHS.get();
Expr *Args[2] = { lhs, rhs };
if (!E->isTypeDependent()) {
// Since our original expression was not type-dependent, we do not
// perform lookup again at instantiation time (C++ [temp.dep]p1).
// Instead, we just build the new overloaded operator call
// expression.
LHS.release();
RHS.release();
return SemaRef.Owned(new (SemaRef.Context) CXXOperatorCallExpr(
SemaRef.Context,
E->getOperator(),
E->getCallee(),
Args, 2, E->getType(),
E->getOperatorLoc()));
}
BinaryOperator::Opcode Opc =
BinaryOperator::getOverloadedOpcode(E->getOperator());
Sema::OwningExprResult Result(SemaRef);
if (!lhs->getType()->isOverloadableType() &&
!rhs->getType()->isOverloadableType()) {
// Neither LHS nor RHS is an overloadable type, so try create a
// built-in binary operation.
Result = SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(), Opc,
lhs, rhs);
} else {
// Compute the set of functions that were found at template
// definition time.
Sema::FunctionSet Functions;
DeclRefExpr *DRE = cast<DeclRefExpr>(E->getCallee());
OverloadedFunctionDecl *Overloads
= cast<OverloadedFunctionDecl>(DRE->getDecl());
for (OverloadedFunctionDecl::function_iterator
F = Overloads->function_begin(),
FEnd = Overloads->function_end();
F != FEnd; ++F)
Functions.insert(*F);
// Add any functions found via argument-dependent lookup.
DeclarationName OpName
= SemaRef.Context.DeclarationNames.getCXXOperatorName(E->getOperator());
SemaRef.ArgumentDependentLookup(OpName, Args, 2, Functions);
// Create the overloaded operator.
Result = SemaRef.CreateOverloadedBinOp(E->getOperatorLoc(), Opc,
Functions, lhs, rhs);
}
if (Result.isInvalid())
return SemaRef.ExprError();