Introduce a specific representation for the ambiguous implicit conversion
sequence. Lots of small relevant changes. Fixes some serious problems with
ambiguous conversions; also possibly improves associated diagnostics.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93214 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 3613d60..78fa05b 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -149,6 +149,15 @@
/// conversions.
CXXConstructorDecl *CopyConstructor;
+ void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
+ void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+ QualType getFromType() const {
+ return QualType::getFromOpaquePtr(FromTypePtr);
+ }
+ QualType getToType() const {
+ return QualType::getFromOpaquePtr(ToTypePtr);
+ }
+
void setAsIdentityConversion();
ImplicitConversionRank getRank() const;
bool isPointerConversionToBool() const;
@@ -190,6 +199,48 @@
void DebugPrint() const;
};
+ /// Represents an ambiguous user-defined conversion sequence.
+ struct AmbiguousConversionSequence {
+ typedef llvm::SmallVector<FunctionDecl*, 4> ConversionSet;
+
+ void *FromTypePtr;
+ void *ToTypePtr;
+ char Buffer[sizeof(ConversionSet)];
+
+ QualType getFromType() const {
+ return QualType::getFromOpaquePtr(FromTypePtr);
+ }
+ QualType getToType() const {
+ return QualType::getFromOpaquePtr(ToTypePtr);
+ }
+ void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); }
+ void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); }
+
+ ConversionSet &conversions() {
+ return *reinterpret_cast<ConversionSet*>(Buffer);
+ }
+
+ const ConversionSet &conversions() const {
+ return *reinterpret_cast<const ConversionSet*>(Buffer);
+ }
+
+ void addConversion(FunctionDecl *D) {
+ conversions().push_back(D);
+ }
+
+ typedef ConversionSet::iterator iterator;
+ iterator begin() { return conversions().begin(); }
+ iterator end() { return conversions().end(); }
+
+ typedef ConversionSet::const_iterator const_iterator;
+ const_iterator begin() const { return conversions().begin(); }
+ const_iterator end() const { return conversions().end(); }
+
+ void construct();
+ void destruct();
+ void copyFrom(const AmbiguousConversionSequence &);
+ };
+
/// ImplicitConversionSequence - Represents an implicit conversion
/// sequence, which may be a standard conversion sequence
/// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2),
@@ -197,18 +248,26 @@
struct ImplicitConversionSequence {
/// Kind - The kind of implicit conversion sequence. BadConversion
/// specifies that there is no conversion from the source type to
- /// the target type. The enumerator values are ordered such that
- /// better implicit conversions have smaller values.
+ /// the target type. AmbiguousConversion represents the unique
+ /// ambiguous conversion (C++0x [over.best.ics]p10).
enum Kind {
StandardConversion = 0,
UserDefinedConversion,
+ AmbiguousConversion,
EllipsisConversion,
BadConversion
};
+ private:
/// ConversionKind - The kind of implicit conversion sequence.
Kind ConversionKind;
+ void setKind(Kind K) {
+ if (isAmbiguous()) Ambiguous.destruct();
+ ConversionKind = K;
+ }
+
+ public:
union {
/// When ConversionKind == StandardConversion, provides the
/// details of the standard conversion sequence.
@@ -217,12 +276,54 @@
/// When ConversionKind == UserDefinedConversion, provides the
/// details of the user-defined conversion sequence.
UserDefinedConversionSequence UserDefined;
+
+ /// When ConversionKind == AmbiguousConversion, provides the
+ /// details of the ambiguous conversion.
+ AmbiguousConversionSequence Ambiguous;
};
+
+ ImplicitConversionSequence() : ConversionKind(BadConversion) {}
+ ~ImplicitConversionSequence() {
+ if (isAmbiguous()) Ambiguous.destruct();
+ }
+ ImplicitConversionSequence(const ImplicitConversionSequence &Other)
+ : ConversionKind(Other.ConversionKind)
+ {
+ switch (ConversionKind) {
+ case StandardConversion: Standard = Other.Standard; break;
+ case UserDefinedConversion: UserDefined = Other.UserDefined; break;
+ case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break;
+ case EllipsisConversion: break;
+ case BadConversion: break;
+ }
+ }
+
+ ImplicitConversionSequence &
+ operator=(const ImplicitConversionSequence &Other) {
+ if (isAmbiguous()) Ambiguous.destruct();
+ new (this) ImplicitConversionSequence(Other);
+ return *this;
+ }
- /// When ConversionKind == BadConversion due to multiple conversion
- /// functions, this will list those functions.
- llvm::SmallVector<FunctionDecl*, 4> ConversionFunctionSet;
-
+ Kind getKind() const { return ConversionKind; }
+ bool isBad() const { return ConversionKind == BadConversion; }
+ bool isStandard() const { return ConversionKind == StandardConversion; }
+ bool isEllipsis() const { return ConversionKind == EllipsisConversion; }
+ bool isAmbiguous() const { return ConversionKind == AmbiguousConversion; }
+ bool isUserDefined() const {
+ return ConversionKind == UserDefinedConversion;
+ }
+
+ void setBad() { setKind(BadConversion); }
+ void setStandard() { setKind(StandardConversion); }
+ void setEllipsis() { setKind(EllipsisConversion); }
+ void setUserDefined() { setKind(UserDefinedConversion); }
+ void setAmbiguous() {
+ if (isAmbiguous()) return;
+ ConversionKind = AmbiguousConversion;
+ Ambiguous.construct();
+ }
+
// The result of a comparison between implicit conversion
// sequences. Use Sema::CompareImplicitConversionSequences to
// actually perform the comparison.
@@ -280,6 +381,16 @@
/// after the call to the overload candidate to convert the result
/// of calling the conversion function to the required type.
StandardConversionSequence FinalConversion;
+
+ /// hasAmbiguousConversion - Returns whether this overload
+ /// candidate requires an ambiguous conversion or not.
+ bool hasAmbiguousConversion() const {
+ for (llvm::SmallVectorImpl<ImplicitConversionSequence>::const_iterator
+ I = Conversions.begin(), E = Conversions.end(); I != E; ++I) {
+ if (I->isAmbiguous()) return true;
+ }
+ return false;
+ }
};
/// OverloadCandidateSet - A set of overload candidates, used in C++