forked from OSchip/llvm-project
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. llvm-svn: 66923
This commit is contained in:
parent
71144973f3
commit
1baf54e1aa
|
@ -1245,6 +1245,14 @@ public:
|
||||||
/// corresponds to, e.g. "<<=".
|
/// corresponds to, e.g. "<<=".
|
||||||
static const char *getOpcodeStr(Opcode Op);
|
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.
|
/// predicates to categorize the respective opcodes.
|
||||||
bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; }
|
bool isMultiplicativeOp() const { return Opc >= Mul && Opc <= Rem; }
|
||||||
bool isAdditiveOp() const { return Opc == Add || Opc == Sub; }
|
bool isAdditiveOp() const { return Opc == Add || Opc == Sub; }
|
||||||
|
|
|
@ -40,14 +40,19 @@ namespace clang {
|
||||||
/// function templates that were found by name lookup at template
|
/// function templates that were found by name lookup at template
|
||||||
/// definition time.
|
/// definition time.
|
||||||
class CXXOperatorCallExpr : public CallExpr {
|
class CXXOperatorCallExpr : public CallExpr {
|
||||||
|
/// \brief The overloaded operator.
|
||||||
|
OverloadedOperatorKind Operator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CXXOperatorCallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs,
|
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
|
||||||
QualType t, SourceLocation operatorloc)
|
Expr **args, unsigned numargs, QualType t,
|
||||||
: CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc){}
|
SourceLocation operatorloc)
|
||||||
|
: CallExpr(C, CXXOperatorCallExprClass, fn, args, numargs, t, operatorloc),
|
||||||
|
Operator(Op) {}
|
||||||
|
|
||||||
/// getOperator - Returns the kind of overloaded operator that this
|
/// getOperator - Returns the kind of overloaded operator that this
|
||||||
/// expression refers to.
|
/// expression refers to.
|
||||||
OverloadedOperatorKind getOperator() const;
|
OverloadedOperatorKind getOperator() const { return Operator; }
|
||||||
|
|
||||||
/// getOperatorLoc - Returns the location of the operator symbol in
|
/// getOperatorLoc - Returns the location of the operator symbol in
|
||||||
/// the expression. When @c getOperator()==OO_Call, this is the
|
/// the expression. When @c getOperator()==OO_Call, this is the
|
||||||
|
|
|
@ -361,7 +361,7 @@ public:
|
||||||
/// that its definition somehow depends on a template parameter
|
/// that its definition somehow depends on a template parameter
|
||||||
/// (C++ [temp.dep.type]).
|
/// (C++ [temp.dep.type]).
|
||||||
bool isDependentType() const { return Dependent; }
|
bool isDependentType() const { return Dependent; }
|
||||||
bool isOverloadType() const; // C++ overloaded function
|
bool isOverloadableType() const;
|
||||||
|
|
||||||
/// hasPointerRepresentation - Whether this type is represented
|
/// hasPointerRepresentation - Whether this type is represented
|
||||||
/// natively as a pointer; this includes pointers, references, block
|
/// natively as a pointer; this includes pointers, references, block
|
||||||
|
@ -1860,8 +1860,10 @@ inline bool Type::isSpecificBuiltinType(unsigned K) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Type::isOverloadType() const {
|
/// \brief Determines whether this is a type for which one can define
|
||||||
return isSpecificBuiltinType(BuiltinType::Overload);
|
/// an overloaded operator.
|
||||||
|
inline bool Type::isOverloadableType() const {
|
||||||
|
return isDependentType() || isRecordType() || isEnumeralType();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Type::hasPointerRepresentation() const {
|
inline bool Type::hasPointerRepresentation() const {
|
||||||
|
|
|
@ -227,6 +227,68 @@ const char *BinaryOperator::getOpcodeStr(Opcode Op) {
|
||||||
return "";
|
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,
|
InitListExpr::InitListExpr(SourceLocation lbraceloc,
|
||||||
Expr **initExprs, unsigned numInits,
|
Expr **initExprs, unsigned numInits,
|
||||||
SourceLocation rbraceloc)
|
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 {
|
SourceRange CXXOperatorCallExpr::getSourceRange() const {
|
||||||
OverloadedOperatorKind Kind = getOperator();
|
OverloadedOperatorKind Kind = getOperator();
|
||||||
if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
|
if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) {
|
||||||
|
|
|
@ -523,10 +523,18 @@ public:
|
||||||
OR_Deleted ///< Overload resoltuion refers to a deleted function.
|
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,
|
void AddOverloadCandidate(FunctionDecl *Function,
|
||||||
Expr **Args, unsigned NumArgs,
|
Expr **Args, unsigned NumArgs,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
bool SuppressUserConversions = false);
|
bool SuppressUserConversions = false);
|
||||||
|
void AddFunctionCandidates(const FunctionSet &Functions,
|
||||||
|
Expr **Args, unsigned NumArgs,
|
||||||
|
OverloadCandidateSet& CandidateSet,
|
||||||
|
bool SuppressUserConversions = false);
|
||||||
void AddMethodCandidate(CXXMethodDecl *Method,
|
void AddMethodCandidate(CXXMethodDecl *Method,
|
||||||
Expr *Object, Expr **Args, unsigned NumArgs,
|
Expr *Object, Expr **Args, unsigned NumArgs,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
|
@ -538,7 +546,12 @@ public:
|
||||||
const FunctionProtoType *Proto,
|
const FunctionProtoType *Proto,
|
||||||
Expr *Object, Expr **Args, unsigned NumArgs,
|
Expr *Object, Expr **Args, unsigned NumArgs,
|
||||||
OverloadCandidateSet& CandidateSet);
|
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,
|
SourceLocation OpLoc,
|
||||||
Expr **Args, unsigned NumArgs,
|
Expr **Args, unsigned NumArgs,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
|
@ -572,6 +585,12 @@ public:
|
||||||
SourceLocation *CommaLocs,
|
SourceLocation *CommaLocs,
|
||||||
SourceLocation RParenLoc,
|
SourceLocation RParenLoc,
|
||||||
bool &ArgumentDependentLookup);
|
bool &ArgumentDependentLookup);
|
||||||
|
|
||||||
|
OwningExprResult CreateOverloadedBinOp(SourceLocation OpLoc,
|
||||||
|
unsigned Opc,
|
||||||
|
FunctionSet &Functions,
|
||||||
|
Expr *LHS, Expr *RHS);
|
||||||
|
|
||||||
ExprResult
|
ExprResult
|
||||||
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
|
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
|
||||||
SourceLocation LParenLoc, Expr **Args,
|
SourceLocation LParenLoc, Expr **Args,
|
||||||
|
@ -930,10 +949,6 @@ public:
|
||||||
bool AllowBuiltinCreation = true,
|
bool AllowBuiltinCreation = true,
|
||||||
SourceLocation Loc = SourceLocation());
|
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,
|
void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S,
|
||||||
QualType T1, QualType T2,
|
QualType T1, QualType T2,
|
||||||
FunctionSet &Functions);
|
FunctionSet &Functions);
|
||||||
|
|
|
@ -1694,7 +1694,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
|
||||||
// If the initializer is the address of an overloaded function, try
|
// If the initializer is the address of an overloaded function, try
|
||||||
// to resolve the overloaded function. If all goes well, T2 is the
|
// to resolve the overloaded function. If all goes well, T2 is the
|
||||||
// type of the resulting function.
|
// type of the resulting function.
|
||||||
if (T2->isOverloadType()) {
|
if (Context.getCanonicalType(T2) == Context.OverloadTy) {
|
||||||
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
|
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType,
|
||||||
ICS != 0);
|
ICS != 0);
|
||||||
if (Fn) {
|
if (Fn) {
|
||||||
|
|
|
@ -1324,8 +1324,7 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
||||||
|
|
||||||
// Build the candidate set for overloading
|
// Build the candidate set for overloading
|
||||||
OverloadCandidateSet CandidateSet;
|
OverloadCandidateSet CandidateSet;
|
||||||
if (AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet))
|
AddOperatorCandidates(OverOp, S, OpLoc, Args, 2, CandidateSet);
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
// Perform overload resolution.
|
// Perform overload resolution.
|
||||||
OverloadCandidateSet::iterator Best;
|
OverloadCandidateSet::iterator Best;
|
||||||
|
@ -1361,8 +1360,9 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
||||||
UsualUnaryConversions(FnExpr);
|
UsualUnaryConversions(FnExpr);
|
||||||
|
|
||||||
Input.release();
|
Input.release();
|
||||||
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, Args, 2,
|
return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
|
||||||
ResultTy, OpLoc));
|
Args, 2, ResultTy,
|
||||||
|
OpLoc));
|
||||||
} else {
|
} else {
|
||||||
// We matched a built-in operator. Convert the arguments, then
|
// We matched a built-in operator. Convert the arguments, then
|
||||||
// break out so that we will build the appropriate built-in
|
// 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.
|
// to the candidate set.
|
||||||
OverloadCandidateSet CandidateSet;
|
OverloadCandidateSet CandidateSet;
|
||||||
Expr *Args[2] = { LHSExp, RHSExp };
|
Expr *Args[2] = { LHSExp, RHSExp };
|
||||||
if (AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
|
AddOperatorCandidates(OO_Subscript, S, LLoc, Args, 2, CandidateSet,
|
||||||
SourceRange(LLoc, RLoc)))
|
SourceRange(LLoc, RLoc));
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
// Perform overload resolution.
|
// Perform overload resolution.
|
||||||
OverloadCandidateSet::iterator Best;
|
OverloadCandidateSet::iterator Best;
|
||||||
|
@ -1469,7 +1468,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
|
||||||
|
|
||||||
Base.release();
|
Base.release();
|
||||||
Idx.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));
|
ResultTy, LLoc));
|
||||||
} else {
|
} else {
|
||||||
// We matched a built-in operator. Convert the arguments, then
|
// We matched a built-in operator. Convert the arguments, then
|
||||||
|
@ -3977,32 +3977,6 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||||
CompTy, 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.
|
// Binary Operators. 'Tok' is the token for the operator.
|
||||||
Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
|
Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
|
||||||
tok::TokenKind Kind,
|
tok::TokenKind Kind,
|
||||||
|
@ -4013,139 +3987,27 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
|
||||||
assert((lhs != 0) && "ActOnBinOp(): missing left expression");
|
assert((lhs != 0) && "ActOnBinOp(): missing left expression");
|
||||||
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
|
assert((rhs != 0) && "ActOnBinOp(): missing right expression");
|
||||||
|
|
||||||
// If either expression is type-dependent, just build the AST.
|
if (getLangOptions().CPlusPlus &&
|
||||||
if (lhs->isTypeDependent() || rhs->isTypeDependent()) {
|
(lhs->getType()->isOverloadableType() ||
|
||||||
// .* cannot be overloaded.
|
rhs->getType()->isOverloadableType())) {
|
||||||
if (Opc == BinaryOperator::PtrMemD)
|
// Find all of the overloaded operators visible from this
|
||||||
return Owned(new (Context) BinaryOperator(lhs, rhs, Opc,
|
// point. We perform both an operator-name lookup from the local
|
||||||
Context.DependentTy, TokLoc));
|
// scope and an argument-dependent lookup based on the types of
|
||||||
|
// the arguments.
|
||||||
// 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.
|
|
||||||
FunctionSet Functions;
|
FunctionSet Functions;
|
||||||
OverloadedOperatorKind OverOp = getOverloadedOperator(Opc);
|
OverloadedOperatorKind OverOp = BinaryOperator::getOverloadedOperator(Opc);
|
||||||
|
if (OverOp != OO_None) {
|
||||||
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
|
LookupOverloadedOperatorName(OverOp, S, lhs->getType(), rhs->getType(),
|
||||||
Functions);
|
Functions);
|
||||||
Expr *Args[2] = { lhs, rhs };
|
Expr *Args[2] = { lhs, rhs };
|
||||||
DeclarationName OpName
|
DeclarationName OpName
|
||||||
= Context.DeclarationNames.getCXXOperatorName(OverOp);
|
= Context.DeclarationNames.getCXXOperatorName(OverOp);
|
||||||
ArgumentDependentLookup(OpName, Args, 2, Functions);
|
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 &&
|
// Build the (potentially-overloaded, potentially-dependent)
|
||||||
(lhs->getType()->isRecordType() || lhs->getType()->isEnumeralType() ||
|
// binary operation.
|
||||||
rhs->getType()->isRecordType() || rhs->getType()->isEnumeralType())) {
|
return CreateOverloadedBinOp(TokLoc, Opc, Functions, 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()->isRecordType() || lhs->getType()->isEnumeralType())) {
|
|
||||||
return CreateBuiltinBinOp(TokLoc, Opc, lhs, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 a built-in binary operation.
|
// 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])
|
// Add the appropriate overloaded operators (C++ [over.match.oper])
|
||||||
// to the candidate set.
|
// to the candidate set.
|
||||||
OverloadCandidateSet CandidateSet;
|
OverloadCandidateSet CandidateSet;
|
||||||
if (OverOp != OO_None &&
|
if (OverOp != OO_None)
|
||||||
AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet))
|
AddOperatorCandidates(OverOp, S, OpLoc, &Input, 1, CandidateSet);
|
||||||
return ExprError();
|
|
||||||
|
|
||||||
// Perform overload resolution.
|
// Perform overload resolution.
|
||||||
OverloadCandidateSet::iterator Best;
|
OverloadCandidateSet::iterator Best;
|
||||||
|
@ -4216,8 +4077,9 @@ Action::OwningExprResult Sema::ActOnUnaryOp(Scope *S, SourceLocation OpLoc,
|
||||||
UsualUnaryConversions(FnExpr);
|
UsualUnaryConversions(FnExpr);
|
||||||
|
|
||||||
input.release();
|
input.release();
|
||||||
return Owned(new (Context) CXXOperatorCallExpr(Context, FnExpr, &Input,
|
return Owned(new (Context) CXXOperatorCallExpr(Context, OverOp, FnExpr,
|
||||||
1, ResultTy, OpLoc));
|
&Input, 1, ResultTy,
|
||||||
|
OpLoc));
|
||||||
} else {
|
} else {
|
||||||
// We matched a built-in operator. Convert the arguments, then
|
// We matched a built-in operator. Convert the arguments, then
|
||||||
// break out so that we will build the appropriate built-in
|
// break out so that we will build the appropriate built-in
|
||||||
|
|
|
@ -800,7 +800,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ICK_Function_To_Pointer:
|
case ICK_Function_To_Pointer:
|
||||||
if (FromType->isOverloadType()) {
|
if (Context.getCanonicalType(FromType) == Context.OverloadTy) {
|
||||||
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
|
FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true);
|
||||||
if (!Fn)
|
if (!Fn)
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -468,7 +468,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
|
||||||
Expr::isLvalueResult argIsLvalue = From->isLvalue(Context);
|
Expr::isLvalueResult argIsLvalue = From->isLvalue(Context);
|
||||||
if (argIsLvalue == Expr::LV_Valid &&
|
if (argIsLvalue == Expr::LV_Valid &&
|
||||||
!FromType->isFunctionType() && !FromType->isArrayType() &&
|
!FromType->isFunctionType() && !FromType->isArrayType() &&
|
||||||
!FromType->isOverloadType()) {
|
Context.getCanonicalType(FromType) != Context.OverloadTy) {
|
||||||
SCS.First = ICK_Lvalue_To_Rvalue;
|
SCS.First = ICK_Lvalue_To_Rvalue;
|
||||||
|
|
||||||
// If T is a non-class type, the type of the rvalue is the
|
// 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
|
/// AddMethodCandidate - Adds the given C++ member function to the set
|
||||||
/// of candidate functions, using the given function call arguments
|
/// of candidate functions, using the given function call arguments
|
||||||
/// and the object argument (@c Object). For example, in a call
|
/// and the object argument (@c Object). For example, in a call
|
||||||
|
@ -2308,13 +2321,39 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AddOperatorCandidates - Add the overloaded operator candidates for
|
// FIXME: This will eventually be removed, once we've migrated all of
|
||||||
/// the operator Op that was used in an operator expression such as "x
|
// the operator overloading logic over to the scheme used by binary
|
||||||
/// Op y". S is the scope in which the expression occurred (used for
|
// operators, which works for template instantiation.
|
||||||
/// name lookup of the operator), Args/NumArgs provides the operator
|
void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
|
||||||
/// arguments, and CandidateSet will store the added overload
|
SourceLocation OpLoc,
|
||||||
/// candidates. (C++ [over.match.oper]).
|
Expr **Args, unsigned NumArgs,
|
||||||
bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
|
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,
|
SourceLocation OpLoc,
|
||||||
Expr **Args, unsigned NumArgs,
|
Expr **Args, unsigned NumArgs,
|
||||||
OverloadCandidateSet& CandidateSet,
|
OverloadCandidateSet& CandidateSet,
|
||||||
|
@ -2338,6 +2377,7 @@ bool Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
|
||||||
// result of the qualified lookup of T1::operator@
|
// result of the qualified lookup of T1::operator@
|
||||||
// (13.3.1.1.1); otherwise, the set of member candidates is
|
// (13.3.1.1.1); otherwise, the set of member candidates is
|
||||||
// empty.
|
// empty.
|
||||||
|
// FIXME: Lookup in base classes, too!
|
||||||
if (const RecordType *T1Rec = T1->getAsRecordType()) {
|
if (const RecordType *T1Rec = T1->getAsRecordType()) {
|
||||||
DeclContext::lookup_const_iterator Oper, OperEnd;
|
DeclContext::lookup_const_iterator Oper, OperEnd;
|
||||||
for (llvm::tie(Oper, OperEnd) = T1Rec->getDecl()->lookup(OpName);
|
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,
|
Args+1, NumArgs - 1, CandidateSet,
|
||||||
/*SuppressUserConversions=*/false);
|
/*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
|
/// AddBuiltinCandidate - Add a candidate for a built-in
|
||||||
|
@ -3615,6 +3623,161 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
|
||||||
return 0;
|
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
|
/// BuildCallToMemberFunction - Build a call to a member
|
||||||
/// function. MemExpr is the expression that refers to the member
|
/// function. MemExpr is the expression that refers to the member
|
||||||
/// function (and includes the object parameter), Args/NumArgs are the
|
/// function (and includes the object parameter), Args/NumArgs are the
|
||||||
|
@ -3870,8 +4033,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
|
||||||
// owned.
|
// owned.
|
||||||
QualType ResultTy = Method->getResultType().getNonReferenceType();
|
QualType ResultTy = Method->getResultType().getNonReferenceType();
|
||||||
ExprOwningPtr<CXXOperatorCallExpr>
|
ExprOwningPtr<CXXOperatorCallExpr>
|
||||||
TheCall(this, new (Context) CXXOperatorCallExpr(Context, NewFn, MethodArgs,
|
TheCall(this, new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn,
|
||||||
NumArgs + 1,
|
MethodArgs, NumArgs + 1,
|
||||||
ResultTy, RParenLoc));
|
ResultTy, RParenLoc));
|
||||||
delete [] MethodArgs;
|
delete [] MethodArgs;
|
||||||
|
|
||||||
|
@ -3989,7 +4152,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
|
||||||
Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(),
|
Expr *FnExpr = new (Context) DeclRefExpr(Method, Method->getType(),
|
||||||
SourceLocation());
|
SourceLocation());
|
||||||
UsualUnaryConversions(FnExpr);
|
UsualUnaryConversions(FnExpr);
|
||||||
Base = new (Context) CXXOperatorCallExpr(Context, FnExpr, &Base, 1,
|
Base = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr, &Base, 1,
|
||||||
Method->getResultType().getNonReferenceType(),
|
Method->getResultType().getNonReferenceType(),
|
||||||
OpLoc);
|
OpLoc);
|
||||||
return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow,
|
return ActOnMemberReferenceExpr(S, ExprArg(*this, Base), OpLoc, tok::arrow,
|
||||||
|
|
|
@ -648,9 +648,11 @@ TemplateExprInstantiator::VisitBinaryOperator(BinaryOperator *E) {
|
||||||
|
|
||||||
Sema::OwningExprResult
|
Sema::OwningExprResult
|
||||||
TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
|
TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
|
||||||
// FIXME: HACK HACK HACK. This is so utterly and completely wrong
|
// FIXME: Only handles binary operators at the moment.
|
||||||
// that I don't want to explain it here. I'll just fix it tomorrow
|
|
||||||
// instead.
|
// 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));
|
Sema::OwningExprResult LHS = Visit(E->getArg(0));
|
||||||
if (LHS.isInvalid())
|
if (LHS.isInvalid())
|
||||||
return SemaRef.ExprError();
|
return SemaRef.ExprError();
|
||||||
|
@ -659,11 +661,56 @@ TemplateExprInstantiator::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
|
||||||
if (RHS.isInvalid())
|
if (RHS.isInvalid())
|
||||||
return SemaRef.ExprError();
|
return SemaRef.ExprError();
|
||||||
|
|
||||||
Sema::OwningExprResult Result
|
Expr *lhs = (Expr *)LHS.get(), *rhs = (Expr *)RHS.get();
|
||||||
= SemaRef.CreateBuiltinBinOp(E->getOperatorLoc(),
|
Expr *Args[2] = { lhs, rhs };
|
||||||
BinaryOperator::Add,
|
|
||||||
(Expr *)LHS.get(),
|
if (!E->isTypeDependent()) {
|
||||||
(Expr *)RHS.get());
|
// 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())
|
if (Result.isInvalid())
|
||||||
return SemaRef.ExprError();
|
return SemaRef.ExprError();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue