From: Chandler Carruth Date: Sun, 12 Dec 2010 09:59:53 +0000 (+0000) Subject: Clean up the helpers used to compute the usual arithmetic conversions' result X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=38ca8d1298ed1bf4512be920917559766a498916;p=clang Clean up the helpers used to compute the usual arithmetic conversions' result type. Localize all of the logic within a single function rather than spreading it throughout the class. Also fixes a buglet where we failed to check for a RHS arithmetic type wider than the LHS and return its canonical type. I've yet to produce a test case that breaks because of this, but it was spotted by inspection by folks on the IRC channel and is obviously correct now. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@121633 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 99b483ff6e..f89107e08b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -4571,45 +4571,6 @@ class BuiltinOperatorOverloadBuilder { static CanQualType ASTContext::* const ArithmeticTypes[NumArithmeticTypes]; - // Accelerator table for performing the usual arithmetic conversions. - // The rules are basically: - // - if either is floating-point, use the wider floating-point - // - if same signedness, use the higher rank - // - if same size, use unsigned of the higher rank - // - use the larger type - // These rules, together with the axiom that higher ranks are - // never smaller, are sufficient to precompute all of these results - // *except* when dealing with signed types of higher rank. - // (we could precompute SLL x UI for all known platforms, but it's - // better not to make any assumptions). - enum PromT { Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL, Dep=-1 }; - static PromT UsualArithmeticConversionsTypes - [LastPromotedArithmeticType][LastPromotedArithmeticType]; - struct UsualArithmeticConversionsType { - static CanQualType find(ASTContext &C, unsigned L, unsigned R) { - assert(L < LastPromotedArithmeticType); - assert(R < LastPromotedArithmeticType); - signed char Idx = UsualArithmeticConversionsTypes[L][R]; - - // Fast path: the table gives us a concrete answer. - if (Idx != Dep) return C.*ArithmeticTypes[Idx]; - - // Slow path: we need to compare widths. - // An invariant is that the signed type has higher rank. - CanQualType LT = C.*ArithmeticTypes[L], RT = C.*ArithmeticTypes[R]; - unsigned LW = C.getIntWidth(LT), RW = C.getIntWidth(RT); - - // If they're different widths, use the signed type. - if (LW > RW) return LT; - else if (LW > RW) return RT; - - // Otherwise, use the unsigned type of the signed type's rank. - if (L == SL || R == SL) return C.UnsignedLongTy; - assert(L == SLL || R == SLL); - return C.UnsignedLongLongTy; - } - }; - // Common instance state available to all overload candidate addition methods. Sema &S; Expr **Args; @@ -4618,6 +4579,60 @@ class BuiltinOperatorOverloadBuilder { llvm::SmallVectorImpl &CandidateTypes; OverloadCandidateSet &CandidateSet; + /// \brief Gets the canonical type resulting from the usual arithemetic + /// converions for the given arithmetic types. + CanQualType getUsualArithmeticConversions(unsigned L, unsigned R) { + // Accelerator table for performing the usual arithmetic conversions. + // The rules are basically: + // - if either is floating-point, use the wider floating-point + // - if same signedness, use the higher rank + // - if same size, use unsigned of the higher rank + // - use the larger type + // These rules, together with the axiom that higher ranks are + // never smaller, are sufficient to precompute all of these results + // *except* when dealing with signed types of higher rank. + // (we could precompute SLL x UI for all known platforms, but it's + // better not to make any assumptions). + enum PromotedType { + Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL, Dep=-1 + }; + static PromotedType ConversionsTable[LastPromotedArithmeticType] + [LastPromotedArithmeticType] = { + /* Flt*/ { Flt, Dbl, LDbl, Flt, Flt, Flt, Flt, Flt, Flt }, + /* Dbl*/ { Dbl, Dbl, LDbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl }, + /*LDbl*/ { LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl }, + /* SI*/ { Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL }, + /* SL*/ { Flt, Dbl, LDbl, SL, SL, SLL, Dep, UL, ULL }, + /* SLL*/ { Flt, Dbl, LDbl, SLL, SLL, SLL, Dep, Dep, ULL }, + /* UI*/ { Flt, Dbl, LDbl, UI, Dep, Dep, UI, UL, ULL }, + /* UL*/ { Flt, Dbl, LDbl, UL, UL, Dep, UL, UL, ULL }, + /* ULL*/ { Flt, Dbl, LDbl, ULL, ULL, ULL, ULL, ULL, ULL }, + }; + + assert(L < LastPromotedArithmeticType); + assert(R < LastPromotedArithmeticType); + int Idx = ConversionsTable[L][R]; + + // Fast path: the table gives us a concrete answer. + if (Idx != Dep) return S.Context.*ArithmeticTypes[Idx]; + + // Slow path: we need to compare widths. + // An invariant is that the signed type has higher rank. + CanQualType LT = S.Context.*ArithmeticTypes[L], + RT = S.Context.*ArithmeticTypes[R]; + unsigned LW = S.Context.getIntWidth(LT), + RW = S.Context.getIntWidth(RT); + + // If they're different widths, use the signed type. + if (LW > RW) return LT; + else if (LW < RW) return RT; + + // Otherwise, use the unsigned type of the signed type's rank. + if (L == SL || R == SL) return S.Context.UnsignedLongTy; + assert(L == SLL || R == SLL); + return S.Context.UnsignedLongLongTy; + } + /// \brief Helper method to factor out the common pattern of adding overloads /// for '++' and '--' builtin operators. void addPlusPlusMinusMinusStyleOverloads(QualType CandidateTy, @@ -5009,8 +5024,7 @@ public: S.Context.*ArithmeticTypes[Right] }; QualType Result = isComparison ? S.Context.BoolTy - : UsualArithmeticConversionsType::find(S.Context, Left, - Right); + : getUsualArithmeticConversions(Left, Right); S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } } @@ -5062,7 +5076,7 @@ public: S.Context.*ArithmeticTypes[Right] }; QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater) ? LandR[0] - : UsualArithmeticConversionsType::find(S.Context, Left, Right); + : getUsualArithmeticConversions(Left, Right); S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet); } } @@ -5473,31 +5487,6 @@ BuiltinOperatorOverloadBuilder::ArithmeticTypes[NumArithmeticTypes] = { // FIXME: What about complex? }; -// Accelerator table for performing the usual arithmetic conversions. -// The rules are basically: -// - if either is floating-point, use the wider floating-point -// - if same signedness, use the higher rank -// - if same size, use unsigned of the higher rank -// - use the larger type -// These rules, together with the axiom that higher ranks are -// never smaller, are sufficient to precompute all of these results -// *except* when dealing with signed types of higher rank. -// (we could precompute SLL x UI for all known platforms, but it's -// better not to make any assumptions). -BuiltinOperatorOverloadBuilder::PromT -BuiltinOperatorOverloadBuilder::UsualArithmeticConversionsTypes -[LastPromotedArithmeticType][LastPromotedArithmeticType] = { - /* Flt*/ { Flt, Dbl, LDbl, Flt, Flt, Flt, Flt, Flt, Flt }, - /* Dbl*/ { Dbl, Dbl, LDbl, Dbl, Dbl, Dbl, Dbl, Dbl, Dbl }, - /*LDbl*/ { LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl, LDbl }, - /* SI*/ { Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL }, - /* SL*/ { Flt, Dbl, LDbl, SL, SL, SLL, Dep, UL, ULL }, - /* SLL*/ { Flt, Dbl, LDbl, SLL, SLL, SLL, Dep, Dep, ULL }, - /* UI*/ { Flt, Dbl, LDbl, UI, Dep, Dep, UI, UL, ULL }, - /* UL*/ { Flt, Dbl, LDbl, UL, UL, Dep, UL, UL, ULL }, - /* ULL*/ { Flt, Dbl, LDbl, ULL, ULL, ULL, ULL, ULL, ULL } -}; - } // end anonymous namespace /// AddBuiltinOperatorCandidates - Add the appropriate built-in