aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOverload.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-01-14 15:45:31 +0000
committerDouglas Gregor <dgregor@apple.com>2009-01-14 15:45:31 +0000
commit09f41cf63f4df0bf4e98ee473e44e9a95b68f0ff (patch)
treef1ffb0328649ff895b883f38966dee5e95262a89 /lib/Sema/SemaOverload.cpp
parentbe63802d1efe52697f49aafea49a5028b30b0aff (diff)
Introduce support for C++0x explicit conversion operators (N2437)
Small cleanup in the handling of user-defined conversions. Also, implement an optimization when constructing a call. We avoid recomputing implicit conversion sequences and instead use those conversion sequences that we computed as part of overload resolution. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62231 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaOverload.cpp')
-rw-r--r--lib/Sema/SemaOverload.cpp94
1 files changed, 71 insertions, 23 deletions
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index d74a5d54b9..fca1556028 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -361,15 +361,18 @@ Sema::IsOverload(FunctionDecl *New, Decl* OldD,
///
/// If @p SuppressUserConversions, then user-defined conversions are
/// not permitted.
+/// If @p AllowExplicit, then explicit user-defined conversions are
+/// permitted.
ImplicitConversionSequence
Sema::TryImplicitConversion(Expr* From, QualType ToType,
- bool SuppressUserConversions)
+ bool SuppressUserConversions,
+ bool AllowExplict)
{
ImplicitConversionSequence ICS;
if (IsStandardConversion(From, ToType, ICS.Standard))
ICS.ConversionKind = ImplicitConversionSequence::StandardConversion;
else if (!SuppressUserConversions &&
- IsUserDefinedConversion(From, ToType, ICS.UserDefined)) {
+ IsUserDefinedConversion(From, ToType, ICS.UserDefined, AllowExplict)) {
ICS.ConversionKind = ImplicitConversionSequence::UserDefinedConversion;
// C++ [over.ics.user]p4:
// A conversion of an expression of class type to the same class
@@ -1097,9 +1100,12 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType)
/// exists, User will contain the user-defined conversion sequence
/// that performs such a conversion and this routine will return
/// true. Otherwise, this routine returns false and User is
-/// unspecified.
+/// unspecified. AllowExplicit is true if the conversion should
+/// consider C++0x "explicit" conversion functions as well as
+/// non-explicit conversion functions (C++0x [class.conv.fct]p2).
bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
- UserDefinedConversionSequence& User)
+ UserDefinedConversionSequence& User,
+ bool AllowExplicit)
{
OverloadCandidateSet CandidateSet;
if (const CXXRecordType *ToRecordType
@@ -1137,7 +1143,8 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
- AddConversionCandidate(Conv, From, ToType, CandidateSet);
+ if (AllowExplicit || !Conv->isExplicit())
+ AddConversionCandidate(Conv, From, ToType, CandidateSet);
}
}
@@ -1748,6 +1755,24 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, CXXMethodDecl *Method) {
return false;
}
+/// TryContextuallyConvertToBool - Attempt to contextually convert the
+/// expression From to bool (C++0x [conv]p3).
+ImplicitConversionSequence Sema::TryContextuallyConvertToBool(Expr *From) {
+ return TryImplicitConversion(From, Context.BoolTy, false, true);
+}
+
+/// PerformContextuallyConvertToBool - Perform a contextual conversion
+/// of the expression From to bool (C++0x [conv]p3).
+bool Sema::PerformContextuallyConvertToBool(Expr *&From) {
+ ImplicitConversionSequence ICS = TryContextuallyConvertToBool(From);
+ if (!PerformImplicitConversion(From, Context.BoolTy, ICS, "converting"))
+ return false;
+
+ return Diag(From->getSourceRange().getBegin(),
+ diag::err_typecheck_bool_condition)
+ << From->getType() << From->getSourceRange();
+}
+
/// AddOverloadCandidate - Adds the given function to the set of
/// candidate functions, using the given function call arguments. If
/// @p SuppressUserConversions, then don't allow user-defined
@@ -2201,11 +2226,14 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S,
/// of the built-in candidate, respectively. Args and NumArgs are the
/// arguments being passed to the candidate. IsAssignmentOperator
/// should be true when this built-in candidate is an assignment
-/// operator.
+/// operator. NumContextualBoolArguments is the number of arguments
+/// (at the beginning of the argument list) that will be contextually
+/// converted to bool.
void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
Expr **Args, unsigned NumArgs,
OverloadCandidateSet& CandidateSet,
- bool IsAssignmentOperator) {
+ bool IsAssignmentOperator,
+ unsigned NumContextualBoolArguments) {
// Add this candidate
CandidateSet.push_back(OverloadCandidate());
OverloadCandidate& Candidate = CandidateSet.back();
@@ -2233,9 +2261,15 @@ void Sema::AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys,
// conversions, since that is the only way that initialization of
// a reference to a non-class type can occur from something that
// is not of the same type.
- Candidate.Conversions[ArgIdx]
- = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
- ArgIdx == 0 && IsAssignmentOperator);
+ if (ArgIdx < NumContextualBoolArguments) {
+ assert(ParamTys[ArgIdx] == Context.BoolTy &&
+ "Contextual conversion to bool requires bool type");
+ Candidate.Conversions[ArgIdx] = TryContextuallyConvertToBool(Args[ArgIdx]);
+ } else {
+ Candidate.Conversions[ArgIdx]
+ = TryCopyInitialization(Args[ArgIdx], ParamTys[ArgIdx],
+ ArgIdx == 0 && IsAssignmentOperator);
+ }
if (Candidate.Conversions[ArgIdx].ConversionKind
== ImplicitConversionSequence::BadConversion) {
Candidate.Viable = false;
@@ -2309,7 +2343,8 @@ public:
BuiltinCandidateTypeSet(ASTContext &Context) : Context(Context) { }
- void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions = true);
+ void AddTypesConvertedFrom(QualType Ty, bool AllowUserConversions,
+ bool AllowExplicitConversions);
/// pointer_begin - First pointer type found;
iterator pointer_begin() { return PointerTypes.begin(); }
@@ -2358,9 +2393,15 @@ bool BuiltinCandidateTypeSet::AddWithMoreQualifiedTypeVariants(QualType Ty) {
/// 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) {
+/// primarily interested in pointer types and enumeration types.
+/// AllowUserConversions is true if we should look at the conversion
+/// functions of a class type, and AllowExplicitConversions if we
+/// should also include the explicit conversion functions of a class
+/// type.
+void
+BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
+ bool AllowUserConversions,
+ bool AllowExplicitConversions) {
// Only deal with canonical types.
Ty = Context.getCanonicalType(Ty);
@@ -2399,7 +2440,7 @@ void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
// Add the pointer type, recursively, so that we get all of
// the indirect base classes, too.
- AddTypesConvertedFrom(Context.getPointerType(BaseTy), false);
+ AddTypesConvertedFrom(Context.getPointerType(BaseTy), false, false);
}
}
} else if (Ty->isEnumeralType()) {
@@ -2414,7 +2455,8 @@ void BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
= Conversions->function_begin();
Func != Conversions->function_end(); ++Func) {
CXXConversionDecl *Conv = cast<CXXConversionDecl>(*Func);
- AddTypesConvertedFrom(Conv->getConversionType(), false);
+ if (AllowExplicitConversions || !Conv->isExplicit())
+ AddTypesConvertedFrom(Conv->getConversionType(), false, false);
}
}
}
@@ -2461,7 +2503,11 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
Op == OO_ArrowStar || Op == OO_PlusPlus || Op == OO_MinusMinus ||
(Op == OO_Star && NumArgs == 1)) {
for (unsigned ArgIdx = 0; ArgIdx < NumArgs; ++ArgIdx)
- CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType());
+ CandidateTypes.AddTypesConvertedFrom(Args[ArgIdx]->getType(),
+ true,
+ (Op == OO_Exclaim ||
+ Op == OO_AmpAmp ||
+ Op == OO_PipePipe));
}
bool isComparison = false;
@@ -2811,14 +2857,14 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
ParamTypes[0] = Context.getReferenceType(*Enum);
ParamTypes[1] = *Enum;
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssignmentOperator=*/true);
+ /*IsAssignmentOperator=*/false);
if (!Context.getCanonicalType(*Enum).isVolatileQualified()) {
// volatile T& operator=(volatile T&, T)
ParamTypes[0] = Context.getReferenceType((*Enum).withVolatile());
ParamTypes[1] = *Enum;
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet,
- /*IsAssignmentOperator=*/true);
+ /*IsAssignmentOperator=*/false);
}
}
// Fall through.
@@ -2919,8 +2965,6 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
ParamTypes[1] = ArithmeticTypes[Right];
// Add this built-in operator as a candidate (VQ is empty).
- // FIXME: We should be caching these declarations somewhere,
- // rather than re-building them every time.
ParamTypes[0] = Context.getReferenceType(ArithmeticTypes[Left]);
AddBuiltinCandidate(ParamTypes[0], ParamTypes, Args, 2, CandidateSet);
@@ -2942,7 +2986,9 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// bool operator&&(bool, bool); [BELOW]
// bool operator||(bool, bool); [BELOW]
QualType ParamTy = Context.BoolTy;
- AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet);
+ AddBuiltinCandidate(ParamTy, &ParamTy, Args, 1, CandidateSet,
+ /*IsAssignmentOperator=*/false,
+ /*NumContextualBoolArguments=*/1);
break;
}
@@ -2956,7 +3002,9 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
// bool operator&&(bool, bool);
// bool operator||(bool, bool);
QualType ParamTypes[2] = { Context.BoolTy, Context.BoolTy };
- AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet);
+ AddBuiltinCandidate(Context.BoolTy, ParamTypes, Args, 2, CandidateSet,
+ /*IsAssignmentOperator=*/false,
+ /*NumContextualBoolArguments=*/2);
break;
}