aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Driver/RewriteObjC.cpp3
-rw-r--r--include/clang/AST/Expr.h13
-rw-r--r--include/clang/AST/TypeOrdering.h33
-rw-r--r--include/clang/Basic/DiagnosticKinds.def2
-rw-r--r--lib/AST/Expr.cpp20
-rw-r--r--lib/AST/StmtSerialization.cpp4
-rw-r--r--lib/Sema/Sema.cpp10
-rw-r--r--lib/Sema/Sema.h19
-rw-r--r--lib/Sema/SemaDecl.cpp3
-rw-r--r--lib/Sema/SemaDeclCXX.cpp6
-rw-r--r--lib/Sema/SemaExpr.cpp136
-rw-r--r--lib/Sema/SemaOverload.cpp585
-rw-r--r--lib/Sema/SemaOverload.h12
-rw-r--r--test/SemaCXX/overloaded-builtin-operators.cpp66
14 files changed, 837 insertions, 75 deletions
diff --git a/Driver/RewriteObjC.cpp b/Driver/RewriteObjC.cpp
index 9d78c42d02..65e8841ec7 100644
--- a/Driver/RewriteObjC.cpp
+++ b/Driver/RewriteObjC.cpp
@@ -1519,7 +1519,8 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl(
// Now, we cast the reference to a pointer to the objc_msgSend type.
QualType pToFunc = Context->getPointerType(msgSendType);
- ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE);
+ ImplicitCastExpr *ICE = new ImplicitCastExpr(pToFunc, DRE,
+ /*isLvalue=*/false);
const FunctionType *FT = msgSendType->getAsFunctionType();
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index efab1a14e1..6fe205cd08 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -834,14 +834,23 @@ public:
/// (*f)(), float->double, short->int, etc.
///
class ImplicitCastExpr : public CastExpr {
+ /// LvalueCast - Whether this cast produces an lvalue.
+ bool LvalueCast;
+
public:
- ImplicitCastExpr(QualType ty, Expr *op) :
- CastExpr(ImplicitCastExprClass, ty, op) {}
+ ImplicitCastExpr(QualType ty, Expr *op, bool Lvalue) :
+ CastExpr(ImplicitCastExprClass, ty, op), LvalueCast(Lvalue) {}
virtual SourceRange getSourceRange() const {
return getSubExpr()->getSourceRange();
}
+ /// isLvalueCast - Whether this cast produces an lvalue.
+ bool isLvalueCast() const { return LvalueCast; }
+
+ /// setLvalueCast - Set whether this cast produces an lvalue.
+ void setLvalueCast(bool Lvalue) { LvalueCast = Lvalue; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == ImplicitCastExprClass;
}
diff --git a/include/clang/AST/TypeOrdering.h b/include/clang/AST/TypeOrdering.h
index a21655b580..a23ca75ff0 100644
--- a/include/clang/AST/TypeOrdering.h
+++ b/include/clang/AST/TypeOrdering.h
@@ -7,9 +7,9 @@
//
//===----------------------------------------------------------------------===//
//
-// This file provides a function object that gives a total ordering
-// on QualType values, so that they can be sorted, used in std::maps
-// and std::sets, and so on.
+// This file provides a function objects and specializations that
+// allow QualType values to be sorted, used in std::maps, std::sets,
+// llvm::DenseMaps, and llvm::DenseSets.
//
//===----------------------------------------------------------------------===//
@@ -17,6 +17,7 @@
#define LLVM_CLANG_TYPE_ORDERING_H
#include "clang/AST/Type.h"
+#include "llvm/ADT/DenseMap.h"
#include <functional>
namespace clang {
@@ -31,4 +32,30 @@ struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> {
}
+namespace llvm {
+ template<> struct DenseMapInfo<clang::QualType> {
+ static inline clang::QualType getEmptyKey() { return clang::QualType(); }
+
+ static inline clang::QualType getTombstoneKey() {
+ using clang::QualType;
+ return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1));
+ }
+
+ static unsigned getHashValue(clang::QualType Val) {
+ return (unsigned)Val.getAsOpaquePtr();
+ }
+
+ static bool isEqual(clang::QualType LHS, clang::QualType RHS) {
+ return LHS == RHS;
+ }
+
+ static bool isPod() {
+ // QualType isn't *technically* a POD type. However, we can get
+ // away with calling it a POD type since its copy constructor,
+ // copy assignment operator, and destructor are all trivial.
+ return true;
+ }
+ };
+}
+
#endif
diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def
index 8d821e4362..451e8de630 100644
--- a/include/clang/Basic/DiagnosticKinds.def
+++ b/include/clang/Basic/DiagnosticKinds.def
@@ -867,6 +867,8 @@ DIAG(err_ovl_ambiguous_call, ERROR,
"call to '%0' is ambiguous; candidates are:")
DIAG(err_ovl_candidate, NOTE,
"candidate function")
+DIAG(err_ovl_builtin_candidate, NOTE,
+ "built-in candidate function '%0'")
DIAG(err_ovl_no_viable_function_in_init, ERROR,
"no matching constructor for initialization of '%0'.")
DIAG(err_ovl_no_viable_function_in_init_with_cands, ERROR,
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index fbb225613f..c54fc40ecb 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -389,8 +389,28 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Extension)
return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(Ctx); // GNU.
break;
+ case ImplicitCastExprClass:
+ return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid
+ : LV_InvalidExpression;
case ParenExprClass: // C99 6.5.1p5
return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx);
+ case BinaryOperatorClass:
+ case CompoundAssignOperatorClass: {
+ const BinaryOperator *BinOp = cast<BinaryOperator>(this);
+ if (BinOp->isAssignmentOp()) {
+ if (Ctx.getLangOptions().CPlusPlus)
+ // C++ [expr.ass]p1:
+ // The result of an assignment operation [...] is an lvalue.
+ return LV_Valid;
+ else
+ // C99 6.5.16:
+ // An assignment expression [...] is not an lvalue.
+ return LV_InvalidExpression;
+ } else
+ return LV_InvalidExpression;
+
+ break;
+ }
case CallExprClass: {
// C++ [expr.call]p10:
// A function call is an lvalue if and only if the result type
diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp
index f71b88b46f..667f597b8a 100644
--- a/lib/AST/StmtSerialization.cpp
+++ b/lib/AST/StmtSerialization.cpp
@@ -662,12 +662,14 @@ ImaginaryLiteral* ImaginaryLiteral::CreateImpl(Deserializer& D, ASTContext& C) {
void ImplicitCastExpr::EmitImpl(Serializer& S) const {
S.Emit(getType());
S.EmitOwnedPtr(getSubExpr());
+ S.Emit(LvalueCast);
}
ImplicitCastExpr* ImplicitCastExpr::CreateImpl(Deserializer& D, ASTContext& C) {
QualType t = QualType::ReadVal(D);
Expr* Op = D.ReadOwnedPtr<Expr>(C);
- return new ImplicitCastExpr(t,Op);
+ bool isLvalue = D.ReadBool();
+ return new ImplicitCastExpr(t,Op,isLvalue);
}
void IndirectGotoStmt::EmitImpl(Serializer& S) const {
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 9c8d0c8bcb..b78336b6cd 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -124,7 +124,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer)
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
-void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty) {
+ /// If isLvalue, the result of the cast is an lvalue.
+void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) {
QualType ExprTy = Context.getCanonicalType(Expr->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
@@ -143,10 +144,11 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty) {
}
}
- if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr))
+ if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
ImpCast->setType(Ty);
- else
- Expr = new ImplicitCastExpr(Ty, Expr);
+ ImpCast->setLvalueCast(isLvalue);
+ } else
+ Expr = new ImplicitCastExpr(Ty, Expr, isLvalue);
}
void Sema::DeleteExpr(ExprTy *E) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 7cd507a0aa..5b66694e04 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -435,6 +435,12 @@ public:
void AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
+ void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet);
+ void AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,
+ Expr **Args,
+ OverloadCandidateSet& CandidateSet);
void AddOverloadCandidates(const OverloadedFunctionDecl *Ovl,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
@@ -1052,16 +1058,13 @@ public:
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit
/// cast. If there is already an implicit cast, merge into the existing one.
- void ImpCastExprToType(Expr *&Expr, QualType Type);
+ /// If isLvalue, the result of the cast is an lvalue.
+ void ImpCastExprToType(Expr *&Expr, QualType Type, bool isLvalue = false);
// UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts
// functions and arrays to their respective pointers (C99 6.3.2.1).
Expr *UsualUnaryConversions(Expr *&expr);
- // UsualUnaryConversionType - Same as UsualUnaryConversions, but works
- // on types instead of expressions
- QualType UsualUnaryConversionType(QualType Ty);
-
// DefaultFunctionArrayConversion - converts functions and arrays
// to their respective pointers (C99 6.3.2.1).
void DefaultFunctionArrayConversion(Expr *&expr);
@@ -1079,6 +1082,12 @@ public:
QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr,
bool isCompAssign = false);
+ /// UsualArithmeticConversionsType - handles the various conversions
+ /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9)
+ /// and returns the result type of that conversion.
+ QualType UsualArithmeticConversionsType(QualType lhs, QualType rhs);
+
+
/// AssignConvertType - All of the 'assignment' semantic checks return this
/// enum to indicate whether the assignment was allowed. These checks are
/// done for simple assignments, as well as initialization, return from
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index fc412a605e..aaceb4f559 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3021,7 +3021,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX,
ECD->setInitVal(InitVal);
// Adjust the Expr initializer and type.
- ECD->setInitExpr(new ImplicitCastExpr(NewTy, ECD->getInitExpr()));
+ ECD->setInitExpr(new ImplicitCastExpr(NewTy, ECD->getInitExpr(),
+ /*isLvalue=*/false));
ECD->setType(NewTy);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 2f43e5fa9e..128df11385 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1597,7 +1597,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
// Perform the conversion.
// FIXME: Binding to a subobject of the lvalue is going to require
// more AST annotation than this.
- ImpCastExprToType(Init, T1);
+ ImpCastExprToType(Init, T1, /*isLvalue=*/true);
}
}
@@ -1656,7 +1656,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
// Perform the conversion.
// FIXME: Binding to a subobject of the lvalue is going to require
// more AST annotation than this.
- ImpCastExprToType(Init, T1);
+ ImpCastExprToType(Init, T1, /*isLvalue=*/true);
}
break;
@@ -1741,7 +1741,7 @@ Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
} else {
// FIXME: Binding to a subobject of the rvalue is going to require
// more AST annotation than this.
- ImpCastExprToType(Init, T1);
+ ImpCastExprToType(Init, T1, /*isLvalue=*/true);
}
return false;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 92efa68cc4..21bf990fba 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -99,13 +99,47 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
UsualUnaryConversions(lhsExpr);
UsualUnaryConversions(rhsExpr);
}
+
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType lhs =
Context.getCanonicalType(lhsExpr->getType()).getUnqualifiedType();
QualType rhs =
Context.getCanonicalType(rhsExpr->getType()).getUnqualifiedType();
-
+
+ // If both types are identical, no conversion is needed.
+ if (lhs == rhs)
+ return lhs;
+
+ // If either side is a non-arithmetic type (e.g. a pointer), we are done.
+ // The caller can deal with this (e.g. pointer + int).
+ if (!lhs->isArithmeticType() || !rhs->isArithmeticType())
+ return lhs;
+
+ QualType destType = UsualArithmeticConversionsType(lhs, rhs);
+ if (!isCompAssign) {
+ ImpCastExprToType(lhsExpr, destType);
+ ImpCastExprToType(rhsExpr, destType);
+ }
+ return destType;
+}
+
+QualType Sema::UsualArithmeticConversionsType(QualType lhs, QualType rhs) {
+ // Perform the usual unary conversions. We do this early so that
+ // integral promotions to "int" can allow us to exit early, in the
+ // lhs == rhs check. Also, for conversion purposes, we ignore any
+ // qualifiers. For example, "const float" and "float" are
+ // equivalent.
+ if (lhs->isPromotableIntegerType())
+ lhs = Context.IntTy;
+ else
+ lhs = Context.getCanonicalType(lhs).getUnqualifiedType();
+
+ if (rhs->isPromotableIntegerType())
+ rhs = Context.IntTy;
+ else
+ rhs = Context.getCanonicalType(rhs).getUnqualifiedType();
+
// If both types are identical, no conversion is needed.
if (lhs == rhs)
return lhs;
@@ -122,12 +156,10 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
// if we have an integer operand, the result is the complex type.
if (rhs->isIntegerType() || rhs->isComplexIntegerType()) {
// convert the rhs to the lhs complex type.
- if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
return lhs;
}
if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
// convert the lhs to the rhs complex type.
- if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs);
return rhs;
}
// This handles complex/complex, complex/float, or float/complex.
@@ -144,24 +176,16 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (result > 0) { // The left side is bigger, convert rhs.
rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs);
- if (!isCompAssign)
- ImpCastExprToType(rhsExpr, rhs);
} else if (result < 0) { // The right side is bigger, convert lhs.
lhs = Context.getFloatingTypeOfSizeWithinDomain(rhs, lhs);
- if (!isCompAssign)
- ImpCastExprToType(lhsExpr, lhs);
}
// At this point, lhs and rhs have the same rank/size. Now, make sure the
// domains match. This is a requirement for our implementation, C99
// does not require this promotion.
if (lhs != rhs) { // Domains don't match, we have complex/float mix.
if (lhs->isRealFloatingType()) { // handle "double, _Complex double".
- if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs);
return rhs;
} else { // handle "_Complex double, double".
- if (!isCompAssign)
- ImpCastExprToType(rhsExpr, lhs);
return lhs;
}
}
@@ -172,12 +196,10 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
// if we have an integer operand, the result is the real floating type.
if (rhs->isIntegerType() || rhs->isComplexIntegerType()) {
// convert rhs to the lhs floating point type.
- if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
return lhs;
}
if (lhs->isIntegerType() || lhs->isComplexIntegerType()) {
// convert lhs to the rhs floating point type.
- if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs);
return rhs;
}
// We have two real floating types, float/complex combos were handled above.
@@ -185,14 +207,12 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
int result = Context.getFloatingTypeOrder(lhs, rhs);
if (result > 0) { // convert the rhs
- if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
return lhs;
}
if (result < 0) { // convert the lhs
- if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs); // convert the lhs
return rhs;
}
- assert(0 && "Sema::UsualArithmeticConversions(): illegal float comparison");
+ assert(0 && "Sema::UsualArithmeticConversionsType(): illegal float comparison");
}
if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) {
// Handle GCC complex int extension.
@@ -203,19 +223,14 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (Context.getIntegerTypeOrder(lhsComplexInt->getElementType(),
rhsComplexInt->getElementType()) >= 0) {
// convert the rhs
- if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
return lhs;
}
- if (!isCompAssign)
- ImpCastExprToType(lhsExpr, rhs); // convert the lhs
return rhs;
} else if (lhsComplexInt && rhs->isIntegerType()) {
// convert the rhs to the lhs complex type.
- if (!isCompAssign) ImpCastExprToType(rhsExpr, lhs);
return lhs;
} else if (rhsComplexInt && lhs->isIntegerType()) {
// convert the lhs to the rhs complex type.
- if (!isCompAssign) ImpCastExprToType(lhsExpr, rhs);
return rhs;
}
}
@@ -244,10 +259,6 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
// to the signed type.
destType = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
}
- if (!isCompAssign) {
- ImpCastExprToType(lhsExpr, destType);
- ImpCastExprToType(rhsExpr, destType);
- }
return destType;
}
@@ -2765,6 +2776,14 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
if (getLangOptions().CPlusPlus &&
(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);
+ }
+
// C++ [over.binary]p1:
// A binary operator shall be implemented either by a non-static
// member function (9.3) with one parameter or by a non-member
@@ -2809,40 +2828,57 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
= dyn_cast_or_null<OverloadedFunctionDecl>(D))
AddOverloadCandidates(Ovl, Args, 2, CandidateSet);
- // FIXME: Add builtin overload candidates (C++ [over.built]).
+ // Add builtin overload candidates (C++ [over.built]).
+ AddBuiltinBinaryOperatorCandidates(OverOp, Args, CandidateSet);
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
switch (BestViableFunction(CandidateSet, Best)) {
case OR_Success: {
- // FIXME: We might find a built-in candidate here.
+ // We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
- // Convert the arguments.
- // FIXME: Conversion will be different for member operators.
- if (PerformCopyInitialization(lhs, FnDecl->getParamDecl(0)->getType(),
- "passing") ||
- PerformCopyInitialization(rhs, FnDecl->getParamDecl(1)->getType(),
- "passing"))
- return true;
-
- // Determine the result type
- QualType ResultTy
- = FnDecl->getType()->getAsFunctionType()->getResultType();
- ResultTy = ResultTy.getNonReferenceType();
-
- // Build the actual expression node.
- // FIXME: We lose the fact that we have a function here!
- if (Opc > BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign)
- return new CompoundAssignOperator(lhs, rhs, Opc, ResultTy, ResultTy,
- TokLoc);
- else
- return new BinaryOperator(lhs, rhs, Opc, ResultTy, TokLoc);
+ if (FnDecl) {
+ // We matched an overloaded operator. Build a call to that
+ // operator.
+
+ // Convert the arguments.
+ // FIXME: Conversion will be different for member operators.
+ if (PerformCopyInitialization(lhs, FnDecl->getParamDecl(0)->getType(),
+ "passing") ||
+ PerformCopyInitialization(rhs, FnDecl->getParamDecl(1)->getType(),
+ "passing"))
+ return true;
+
+ // Determine the result type
+ QualType ResultTy
+ = FnDecl->getType()->getAsFunctionType()->getResultType();
+ ResultTy = ResultTy.getNonReferenceType();
+
+ // Build the actual expression node.
+ // FIXME: We lose the fact that we have a function here!
+ if (Opc > BinaryOperator::Assign && Opc <= BinaryOperator::OrAssign)
+ return new CompoundAssignOperator(lhs, rhs, Opc, ResultTy, ResultTy,
+ TokLoc);
+ else
+ return new BinaryOperator(lhs, rhs, Opc, 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 (PerformCopyInitialization(lhs, Best->BuiltinTypes.ParamTypes[0],
+ "passing") ||
+ PerformCopyInitialization(rhs, Best->BuiltinTypes.ParamTypes[1],
+ "passing"))
+ return true;
+
+ break;
+ }
}
case OR_No_Viable_Function:
// No viable function; fall through to handling this as a
- // built-in operator.
+ // built-in operator, which will produce an error message for us.
break;
case OR_Ambiguous:
@@ -2854,7 +2890,9 @@ Action::ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
return true;
}
- // There was no viable overloaded operator; fall through.
+ // 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.
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index b60e55492b..9229fa35d2 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -14,8 +14,11 @@
#include "Sema.h"
#include "SemaInherit.h"
#include "clang/Basic/Diagnostic.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/TypeOrdering.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
@@ -413,6 +416,7 @@ Sema::IsStandardConversion(Expr* From, QualType ToType,
return false;
// Standard conversions (C++ [conv])
+ SCS.setAsIdentityConversion();
SCS.Deprecated = false;
SCS.FromTypePtr = FromType.getAsOpaquePtr();
SCS.CopyConstructor = 0;
@@ -1530,7 +1534,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
DeclRefExpr ConversionRef(Conversion, Conversion->getType(),
SourceLocation());
ImplicitCastExpr ConversionFn(Context.getPointerType(Conversion->getType()),
- &ConversionRef);
+ &ConversionRef, false);
CallExpr Call(&ConversionFn, 0, 0,
Conversion->getConversionType().getNonReferenceType(),
SourceLocation());
@@ -1550,6 +1554,562 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
}
}
+/// AddBuiltinCandidate - Add a candidate for a built-in
+/// operator. ResultTy and ParamTys are the result and parameter types
+/// of the built-in candidate, respectively. Args and NumArgs are the
+/// arguments being passed to the candidate.
+void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet) {
+ // Add this candidate
+ CandidateSet.push_back(OverloadCandidate());
+ OverloadCandidate& Candidate = CandidateSet.back();
+ Candidate.Function = 0;
+ Candidate.BuiltinTypes.ResultTy = ResultTy;
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
+ Candidate.BuiltinTypes.ParamTypes[ArgIdx] = ParamTys[ArgIdx];
+
+ // Determine the implicit conversion sequences for each of the
+ // arguments.
+ Candidate.Viable = true;
+ Candidate.Conversions.resize(NumArgs);
+ for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx) {
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx], false);
+ if (Candidate.Conversions[ArgIdx].ConversionKind
+ == ImplicitConversionSequence::BadConversion)
+ Candidate.Viable = false;
+ }
+}
+
+/// BuiltinCandidateTypeSet - A set of types that will be used for the
+/// candidate operator functions for built-in operators (C++
+/// [over.built]). The types are separated into pointer types and
+/// enumeration types.
+class BuiltinCandidateTypeSet {
+ /// TypeSet - A set of types.
+ typedef llvm::DenseSet<QualType> TypeSet;
+
+ /// PointerTypes - The set of pointer types that will be used in the
+ /// built-in candidates.
+ TypeSet PointerTypes;
+
+ /// EnumerationTypes - The set of enumeration types that will be
+ /// used in the built-in candidates.
+ TypeSet EnumerationTypes;
+
+ /// Context - The AST context in which we will build the type sets.
+ ASTContext &Context;
+
+ bool AddWithMoreQualifiedTypeVariants(QualType Ty);
+
+public:
+ /// iterator - Iterates through the types that are part of the set.
+ typedef TypeSet::iterator iterator;
+
+ BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { }
+
+ void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions = true);
+
+ /// pointer_begin - First pointer type found;
+ iterator pointer_begin() { return PointerTypes.begin(); }
+
+ /// pointer_end - Last pointer type found;
+ iterator pointer_end() { return PointerTypes.end(); }
+
+ /// enumeration_begin - First enumeration type found;
+ iterator enumeration_begin() { return EnumerationTypes.begin(); }
+
+ /// enumeration_end - Last enumeration type found;
+ iterator enumeration_end() { return EnumerationTypes.end(); }
+};
+
+/// AddWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to
+/// the set of pointer types along with any more-qualified variants of
+/// that type. For example, if @p Ty is "int const *", this routine
+/// will add "int const *", "int const volatile *", "int const
+/// restrict *", and "int const volatile restrict *" to the set of
+/// pointer types. Returns true if the add of @p Ty itself succeeded,
+/// false otherwise.
+bool BuiltinCandidateTypeSet::AddWithMoreQualifiedTypeVariants(QualType Ty) {
+ // Insert this type.
+ if (!PointerTypes.insert(Ty).second)
+ return false;
+
+ if (const PointerType *PointerTy = Ty->getAsPointerType()) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+ // FIXME: Optimize this so that we don't keep trying to add the same types.
+
+ // FIXME: Do we have to add CVR qualifiers at *all* levels to deal
+ // with all pointer conversions that don't cast away constness?
+ if (!PointeeTy.isConstQualified())
+ AddWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withConst()));
+ if (!PointeeTy.isVolatileQualified())
+ AddWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withVolatile()));
+ if (!PointeeTy.isRestrictQualified())
+ AddWithMoreQualifiedTypeVariants
+ (Context.getPointerType(PointeeTy.withRestrict()));
+ }
+
+ return true;
+}
+
+/// AddTypesConvertedFrom - Add each of the types to which the type @p
+/// Ty can be implicit converted to the given set of @p Types. We're
+/// primarily interested in pointer types, enumeration types,
+void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
+ bool AllowUserConversions) {
+ // Only deal with canonical types.
+ Ty = Context.getCanonicalType(Ty);
+
+ // Look through reference types; they aren't part of the type of an
+ // expression for the purposes of conversions.
+ if (const ReferenceType *RefTy = Ty->getAsReferenceType())
+ Ty = RefTy->getPointeeType();
+
+ // We don't care about qualifiers on the type.
+ Ty = Ty.getUnqualifiedType();
+
+ if (const PointerType *PointerTy = Ty->getAsPointerType()) {
+ QualType PointeeTy = PointerTy->getPointeeType();
+
+ // Insert our type, and its more-qualified variants, into the set
+ // of types.
+ if (!AddWithMoreQualifiedTypeVariants(Ty))
+ return;
+
+ // Add 'cv void*' to our set of types.
+ if (!Ty->isVoidType()) {
+ QualType QualVoid
+ = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+ AddWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid));
+ }
+
+ // If this is a pointer to a class type, add pointers to its bases
+ // (with the same level of cv-qualification as the original
+ // derived class, of course).
+ if (const RecordType *PointeeRec = PointeeTy->getAsRecordType()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(PointeeRec->getDecl());
+ for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin();
+ Base != ClassDecl->bases_end(); ++Base) {
+ QualType BaseTy = Context.getCanonicalType(Base->getType());
+ BaseTy = BaseTy.getQualifiedType(PointeeTy.getCVRQualifiers());
+
+ // Add the pointer type, recursively, so that we get all of
+ // the indirect base classes, too.
+ AddTypesConvertedFrom(Context.getPointerType(BaseTy), false);
+ }
+ }
+ } else if (Ty->isEnumeralType()) {
+ EnumerationTypes.insert(Ty);
+ } else if (AllowUserConversions) {
+ if (const RecordType *TyRec = Ty->getAsRecordType()) {
+ CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
+ // FIXME: Visit conversion functions in the base classes, too.
+ OverloadedFunctionDecl *Conversions
+ = ClassDecl->getConversionFunctions();
+ for (OverloadedFunctionDecl::function_iterator Func
+ = Conversions->function_begin();
+ Func != Conversions->function_end(); ++Func) {
+ CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
+ AddTypesConvertedFrom(Conv->getConversionType(), false);
+ }
+ }
+ }
+}
+
+/// AddBuiltinCandidates - Add the appropriate built-in operator
+/// overloads to the candidate set (C++ [over.built]), based on the
+/// operator @p Op and the arguments given. For example, if the
+/// operator is a binary '+', this routine might add
+/// "int operator+(int, int)"
+/// to cover integer addition.
+void
+Sema::AddBuiltinBinaryOperatorCandidates(OverloadedOperatorKind Op,
+ Expr **Args,
+ OverloadCandidateSet& CandidateSet) {
+ // The set of "promoted arithmetic types", which are the arithmetic
+ // types are that preserved by promotion (C++ [over.built]p2). Note
+ // that the first few of these types are the promoted integral
+ // types; these types need to be first.
+ // FIXME: What about complex?
+ const unsigned FirstIntegralType = 0;
+ const unsigned LastIntegralType = 13;
+ const unsigned FirstPromotedIntegralType = 7,
+ LastPromotedIntegralType = 13;
+ const unsigned FirstPromotedArithmeticType = 7,
+ LastPromotedArithmeticType = 16;
+ const unsigned NumArithmeticTypes = 16;
+ QualType ArithmeticTypes[NumArithmeticTypes] = {
+ Context.BoolTy, Context.CharTy, Context.WCharTy,
+ Context.SignedCharTy, Context.ShortTy,
+ Context.UnsignedCharTy, Context.UnsignedShortTy,
+ Context.IntTy, Context.LongTy, Context.LongLongTy,
+ Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy,
+ Context.FloatTy, Context.DoubleTy, Context.LongDoubleTy
+ };
+
+ // Find all of the types that the arguments can convert to, but only
+ // if the operator we're looking at has built-in operator candidates
+ // that make use of these types.
+ BuiltinCandidateTypeSet CandidateTypes(Context);
+ if (Op == OO_Less || Op == OO_Greater || Op == OO_LessEqual ||
+ Op == OO_GreaterEqual || Op == OO_EqualEqual || Op == OO_ExclaimEqual ||
+ Op == OO_Plus || Op == OO_Minus || Op == OO_Equal ||
+ Op == OO_PlusEqual || Op == OO_MinusEqual || Op == OO_Subscript ||
+ Op == OO_ArrowStar) {
+ for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx)
+ CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType());
+ }
+
+ bool isComparison = false;
+ switch (Op) {
+ case OO_None:
+ case NUM_OVERLOADED_OPERATORS:
+ assert(false && "Expected an overloaded operator");
+ break;
+
+ case OO_New:
+ case OO_Delete:
+ case OO_Array_New:
+ case OO_Array_Delete:
+ case OO_Tilde:
+ case OO_Exclaim:
+ case OO_PlusPlus:
+ case OO_MinusMinus:
+ case OO_Arrow:
+ case OO_Call:
+ assert(false && "Expected a binary operator");
+ break;
+
+ case OO_Comma:
+ // C++ [over.match.oper]p3:
+ // -- For the operator ',', the unary operator '&', or the