[cfe-commits] r66923 - in /cfe/trunk: include/clang/AST/Expr.h include/clang/AST/ExprCXX.h include/clang/AST/Type.h lib/AST/Expr.cpp lib/AST/ExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplateInstantiate.cpp
Douglas Gregor
dgregor at apple.com
Fri Mar 13 11:40:32 PDT 2009
Author: dgregor
Date: Fri Mar 13 13:40:31 2009
New Revision: 66923
URL: http://llvm.org/viewvc/llvm-project?rev=66923&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Expr.h
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/AST/Expr.cpp
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Fri Mar 13 13:40:31 2009
@@ -1245,6 +1245,14 @@
/// 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; }
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Mar 13 13:40:31 2009
@@ -40,14 +40,19 @@
/// 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
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Fri Mar 13 13:40:31 2009
@@ -361,7 +361,7 @@
/// 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 @@
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 {
Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Mar 13 13:40:31 2009
@@ -227,6 +227,68 @@
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)
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Fri Mar 13 13:40:31 2009
@@ -160,27 +160,6 @@
}
}
-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) {
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Mar 13 13:40:31 2009
@@ -523,10 +523,18 @@
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 @@
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 @@
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 @@
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);
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Fri Mar 13 13:40:31 2009
@@ -1694,7 +1694,7 @@
// 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) {
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Mar 13 13:40:31 2009
@@ -1324,8 +1324,7 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 @@
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);
- }
-
- // 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;
- }
+ 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);
}
- 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 @@
// 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 @@
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
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Mar 13 13:40:31 2009
@@ -800,7 +800,7 @@
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;
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Fri Mar 13 13:40:31 2009
@@ -468,7 +468,7 @@
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 @@
}
}
+/// \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 @@
}
}
-/// 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 @@
// 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 @@
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 @@
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 @@
// 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 @@
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,
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=66923&r1=66922&r2=66923&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Fri Mar 13 13:40:31 2009
@@ -648,9 +648,11 @@
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 @@
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();
More information about the cfe-commits
mailing list