Index: cfe/trunk/lib/Sema/SemaOverload.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp +++ cfe/trunk/lib/Sema/SemaOverload.cpp @@ -7615,53 +7615,62 @@ SmallVectorImpl &CandidateTypes; OverloadCandidateSet &CandidateSet; - // Define some constants used to index and iterate over the arithemetic types - // provided via the getArithmeticType() method below. - // The "promoted arithmetic types" are the arithmetic + static constexpr int ArithmeticTypesCap = 24; + SmallVector ArithmeticTypes; + + // Define some indices used to iterate over the arithemetic types in + // ArithmeticTypes. The "promoted arithmetic types" are the arithmetic // types are that preserved by promotion (C++ [over.built]p2). - static const unsigned FirstIntegralType = 4; - static const unsigned LastIntegralType = 21; - static const unsigned FirstPromotedIntegralType = 4, - LastPromotedIntegralType = 12; - static const unsigned FirstPromotedArithmeticType = 0, - LastPromotedArithmeticType = 12; - static const unsigned NumArithmeticTypes = 21; - - /// \brief Get the canonical type for a given arithmetic type index. - CanQualType getArithmeticType(unsigned index) { - assert(index < NumArithmeticTypes); - static CanQualType ASTContext::* const - ArithmeticTypes[NumArithmeticTypes] = { - // Start of promoted types. - &ASTContext::FloatTy, - &ASTContext::DoubleTy, - &ASTContext::LongDoubleTy, - &ASTContext::Float128Ty, - - // Start of integral types. - &ASTContext::IntTy, - &ASTContext::LongTy, - &ASTContext::LongLongTy, - &ASTContext::Int128Ty, - &ASTContext::UnsignedIntTy, - &ASTContext::UnsignedLongTy, - &ASTContext::UnsignedLongLongTy, - &ASTContext::UnsignedInt128Ty, - // End of promoted types. - - &ASTContext::BoolTy, - &ASTContext::CharTy, - &ASTContext::WCharTy, - &ASTContext::Char16Ty, - &ASTContext::Char32Ty, - &ASTContext::SignedCharTy, - &ASTContext::ShortTy, - &ASTContext::UnsignedCharTy, - &ASTContext::UnsignedShortTy, - // End of integral types. - // FIXME: What about complex? What about half? - }; - return S.Context.*ArithmeticTypes[index]; + unsigned FirstIntegralType, + LastIntegralType; + unsigned FirstPromotedIntegralType, + LastPromotedIntegralType; + unsigned FirstPromotedArithmeticType, + LastPromotedArithmeticType; + unsigned NumArithmeticTypes; + + void InitArithmeticTypes() { + // Start of promoted types. + FirstPromotedArithmeticType = 0; + ArithmeticTypes.push_back(S.Context.FloatTy); + ArithmeticTypes.push_back(S.Context.DoubleTy); + ArithmeticTypes.push_back(S.Context.LongDoubleTy); + if (S.Context.getTargetInfo().hasFloat128Type()) + ArithmeticTypes.push_back(S.Context.Float128Ty); + + // Start of integral types. + FirstIntegralType = ArithmeticTypes.size(); + FirstPromotedIntegralType = ArithmeticTypes.size(); + ArithmeticTypes.push_back(S.Context.IntTy); + ArithmeticTypes.push_back(S.Context.LongTy); + ArithmeticTypes.push_back(S.Context.LongLongTy); + if (S.Context.getTargetInfo().hasInt128Type()) + ArithmeticTypes.push_back(S.Context.Int128Ty); + ArithmeticTypes.push_back(S.Context.UnsignedIntTy); + ArithmeticTypes.push_back(S.Context.UnsignedLongTy); + ArithmeticTypes.push_back(S.Context.UnsignedLongLongTy); + if (S.Context.getTargetInfo().hasInt128Type()) + ArithmeticTypes.push_back(S.Context.UnsignedInt128Ty); + LastPromotedIntegralType = ArithmeticTypes.size(); + LastPromotedArithmeticType = ArithmeticTypes.size(); + // End of promoted types. + + ArithmeticTypes.push_back(S.Context.BoolTy); + ArithmeticTypes.push_back(S.Context.CharTy); + ArithmeticTypes.push_back(S.Context.WCharTy); + ArithmeticTypes.push_back(S.Context.Char16Ty); + ArithmeticTypes.push_back(S.Context.Char32Ty); + ArithmeticTypes.push_back(S.Context.SignedCharTy); + ArithmeticTypes.push_back(S.Context.ShortTy); + ArithmeticTypes.push_back(S.Context.UnsignedCharTy); + ArithmeticTypes.push_back(S.Context.UnsignedShortTy); + LastIntegralType = ArithmeticTypes.size(); + NumArithmeticTypes = ArithmeticTypes.size(); + // End of integral types. + // FIXME: What about complex? What about half? + + assert(ArithmeticTypes.size() <= ArithmeticTypesCap && + "Enough inline storage for all arithmetic types."); } /// \brief Helper method to factor out the common pattern of adding overloads @@ -7720,18 +7729,8 @@ HasArithmeticOrEnumeralCandidateType), CandidateTypes(CandidateTypes), CandidateSet(CandidateSet) { - // Validate some of our static helper constants in debug builds. - assert(getArithmeticType(FirstPromotedIntegralType) == S.Context.IntTy && - "Invalid first promoted integral type"); - assert(getArithmeticType(LastPromotedIntegralType - 1) - == S.Context.UnsignedInt128Ty && - "Invalid last promoted integral type"); - assert(getArithmeticType(FirstPromotedArithmeticType) - == S.Context.FloatTy && - "Invalid first promoted arithmetic type"); - assert(getArithmeticType(LastPromotedArithmeticType - 1) - == S.Context.UnsignedInt128Ty && - "Invalid last promoted arithmetic type"); + + InitArithmeticTypes(); } // C++ [over.built]p3: @@ -7758,7 +7757,7 @@ for (unsigned Arith = (Op == OO_PlusPlus? 0 : 1); Arith < NumArithmeticTypes; ++Arith) { addPlusPlusMinusMinusStyleOverloads( - getArithmeticType(Arith), + ArithmeticTypes[Arith], VisibleTypeConversionsQuals.hasVolatile(), VisibleTypeConversionsQuals.hasRestrict()); } @@ -7831,7 +7830,7 @@ for (unsigned Arith = FirstPromotedArithmeticType; Arith < LastPromotedArithmeticType; ++Arith) { - QualType ArithTy = getArithmeticType(Arith); + QualType ArithTy = ArithmeticTypes[Arith]; S.AddBuiltinCandidate(&ArithTy, Args, CandidateSet); } @@ -7871,7 +7870,7 @@ for (unsigned Int = FirstPromotedIntegralType; Int < LastPromotedIntegralType; ++Int) { - QualType IntTy = getArithmeticType(Int); + QualType IntTy = ArithmeticTypes[Int]; S.AddBuiltinCandidate(&IntTy, Args, CandidateSet); } @@ -8099,8 +8098,8 @@ Left < LastPromotedArithmeticType; ++Left) { for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { - QualType LandR[2] = { getArithmeticType(Left), - getArithmeticType(Right) }; + QualType LandR[2] = { ArithmeticTypes[Left], + ArithmeticTypes[Right] }; S.AddBuiltinCandidate(LandR, Args, CandidateSet); } } @@ -8143,8 +8142,8 @@ Left < LastPromotedIntegralType; ++Left) { for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { - QualType LandR[2] = { getArithmeticType(Left), - getArithmeticType(Right) }; + QualType LandR[2] = { ArithmeticTypes[Left], + ArithmeticTypes[Right] }; S.AddBuiltinCandidate(LandR, Args, CandidateSet); } } @@ -8324,18 +8323,18 @@ for (unsigned Right = FirstPromotedArithmeticType; Right < LastPromotedArithmeticType; ++Right) { QualType ParamTypes[2]; - ParamTypes[1] = getArithmeticType(Right); + ParamTypes[1] = ArithmeticTypes[Right]; // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = - S.Context.getLValueReferenceType(getArithmeticType(Left)); + S.Context.getLValueReferenceType(ArithmeticTypes[Left]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). if (VisibleTypeConversionsQuals.hasVolatile()) { ParamTypes[0] = - S.Context.getVolatileType(getArithmeticType(Left)); + S.Context.getVolatileType(ArithmeticTypes[Left]); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssigmentOperator=*/isEqualOp); @@ -8390,15 +8389,15 @@ for (unsigned Right = FirstPromotedIntegralType; Right < LastPromotedIntegralType; ++Right) { QualType ParamTypes[2]; - ParamTypes[1] = getArithmeticType(Right); + ParamTypes[1] = ArithmeticTypes[Right]; // Add this built-in operator as a candidate (VQ is empty). ParamTypes[0] = - S.Context.getLValueReferenceType(getArithmeticType(Left)); + S.Context.getLValueReferenceType(ArithmeticTypes[Left]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet); if (VisibleTypeConversionsQuals.hasVolatile()) { // Add this built-in operator as a candidate (VQ is 'volatile'). - ParamTypes[0] = getArithmeticType(Left); + ParamTypes[0] = ArithmeticTypes[Left]; ParamTypes[0] = S.Context.getVolatileType(ParamTypes[0]); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet); Index: cfe/trunk/test/SemaCXX/microsoft-vs-float128.cpp =================================================================== --- cfe/trunk/test/SemaCXX/microsoft-vs-float128.cpp +++ cfe/trunk/test/SemaCXX/microsoft-vs-float128.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple i686-pc-win32 -fms-compatibility -fms-extensions -fsyntax-only -verify -std=c++11 -DMS %s + +template struct enable_if {}; +template<> struct enable_if { typedef void type; }; + +template struct is_same { static constexpr bool value = false; }; +template struct is_same { static constexpr bool value = true; }; + + + + +struct S { + // The only numeric types S can be converted to is __int128 and __float128. + template ::value || + is_same::value || + is_same::value)>::type> + operator T() { return T(); } +}; + +void f() { +#ifdef MS + // When targeting Win32, __float128 and __int128 do not exist, so the S + // object cannot be converted to anything usable in the expression. + // expected-error@+2{{invalid operands to binary expression ('S' and 'double')}} +#endif + double d = S() + 1.0; +#ifndef MS + // expected-error@-2{{use of overloaded operator '+' is ambiguous}} + // expected-note@-3 36{{built-in candidate operator+}} +#endif +}