forked from OSchip/llvm-project
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. llvm-svn: 121633
This commit is contained in:
parent
5659c0c480
commit
3b35b78dd0
|
@ -4571,6 +4571,17 @@ class BuiltinOperatorOverloadBuilder {
|
||||||
|
|
||||||
static CanQualType ASTContext::* const ArithmeticTypes[NumArithmeticTypes];
|
static CanQualType ASTContext::* const ArithmeticTypes[NumArithmeticTypes];
|
||||||
|
|
||||||
|
// Common instance state available to all overload candidate addition methods.
|
||||||
|
Sema &S;
|
||||||
|
Expr **Args;
|
||||||
|
unsigned NumArgs;
|
||||||
|
Qualifiers VisibleTypeConversionsQuals;
|
||||||
|
llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &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.
|
// Accelerator table for performing the usual arithmetic conversions.
|
||||||
// The rules are basically:
|
// The rules are basically:
|
||||||
// - if either is floating-point, use the wider floating-point
|
// - if either is floating-point, use the wider floating-point
|
||||||
|
@ -4582,41 +4593,45 @@ class BuiltinOperatorOverloadBuilder {
|
||||||
// *except* when dealing with signed types of higher rank.
|
// *except* when dealing with signed types of higher rank.
|
||||||
// (we could precompute SLL x UI for all known platforms, but it's
|
// (we could precompute SLL x UI for all known platforms, but it's
|
||||||
// better not to make any assumptions).
|
// better not to make any assumptions).
|
||||||
enum PromT { Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL, Dep=-1 };
|
enum PromotedType {
|
||||||
static PromT UsualArithmeticConversionsTypes
|
Flt, Dbl, LDbl, SI, SL, SLL, UI, UL, ULL, Dep=-1
|
||||||
[LastPromotedArithmeticType][LastPromotedArithmeticType];
|
};
|
||||||
struct UsualArithmeticConversionsType {
|
static PromotedType ConversionsTable[LastPromotedArithmeticType]
|
||||||
static CanQualType find(ASTContext &C, unsigned L, unsigned R) {
|
[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(L < LastPromotedArithmeticType);
|
||||||
assert(R < LastPromotedArithmeticType);
|
assert(R < LastPromotedArithmeticType);
|
||||||
signed char Idx = UsualArithmeticConversionsTypes[L][R];
|
int Idx = ConversionsTable[L][R];
|
||||||
|
|
||||||
// Fast path: the table gives us a concrete answer.
|
// Fast path: the table gives us a concrete answer.
|
||||||
if (Idx != Dep) return C.*ArithmeticTypes[Idx];
|
if (Idx != Dep) return S.Context.*ArithmeticTypes[Idx];
|
||||||
|
|
||||||
// Slow path: we need to compare widths.
|
// Slow path: we need to compare widths.
|
||||||
// An invariant is that the signed type has higher rank.
|
// An invariant is that the signed type has higher rank.
|
||||||
CanQualType LT = C.*ArithmeticTypes[L], RT = C.*ArithmeticTypes[R];
|
CanQualType LT = S.Context.*ArithmeticTypes[L],
|
||||||
unsigned LW = C.getIntWidth(LT), RW = C.getIntWidth(RT);
|
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 they're different widths, use the signed type.
|
||||||
if (LW > RW) return LT;
|
if (LW > RW) return LT;
|
||||||
else if (LW > RW) return RT;
|
else if (LW < RW) return RT;
|
||||||
|
|
||||||
// Otherwise, use the unsigned type of the signed type's rank.
|
// Otherwise, use the unsigned type of the signed type's rank.
|
||||||
if (L == SL || R == SL) return C.UnsignedLongTy;
|
if (L == SL || R == SL) return S.Context.UnsignedLongTy;
|
||||||
assert(L == SLL || R == SLL);
|
assert(L == SLL || R == SLL);
|
||||||
return C.UnsignedLongLongTy;
|
return S.Context.UnsignedLongLongTy;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// Common instance state available to all overload candidate addition methods.
|
|
||||||
Sema &S;
|
|
||||||
Expr **Args;
|
|
||||||
unsigned NumArgs;
|
|
||||||
Qualifiers VisibleTypeConversionsQuals;
|
|
||||||
llvm::SmallVectorImpl<BuiltinCandidateTypeSet> &CandidateTypes;
|
|
||||||
OverloadCandidateSet &CandidateSet;
|
|
||||||
|
|
||||||
/// \brief Helper method to factor out the common pattern of adding overloads
|
/// \brief Helper method to factor out the common pattern of adding overloads
|
||||||
/// for '++' and '--' builtin operators.
|
/// for '++' and '--' builtin operators.
|
||||||
|
@ -5009,8 +5024,7 @@ public:
|
||||||
S.Context.*ArithmeticTypes[Right] };
|
S.Context.*ArithmeticTypes[Right] };
|
||||||
QualType Result =
|
QualType Result =
|
||||||
isComparison ? S.Context.BoolTy
|
isComparison ? S.Context.BoolTy
|
||||||
: UsualArithmeticConversionsType::find(S.Context, Left,
|
: getUsualArithmeticConversions(Left, Right);
|
||||||
Right);
|
|
||||||
S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
|
S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5062,7 +5076,7 @@ public:
|
||||||
S.Context.*ArithmeticTypes[Right] };
|
S.Context.*ArithmeticTypes[Right] };
|
||||||
QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
|
QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
|
||||||
? LandR[0]
|
? LandR[0]
|
||||||
: UsualArithmeticConversionsType::find(S.Context, Left, Right);
|
: getUsualArithmeticConversions(Left, Right);
|
||||||
S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
|
S.AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5473,31 +5487,6 @@ BuiltinOperatorOverloadBuilder::ArithmeticTypes[NumArithmeticTypes] = {
|
||||||
// FIXME: What about complex?
|
// 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
|
} // end anonymous namespace
|
||||||
|
|
||||||
/// AddBuiltinOperatorCandidates - Add the appropriate built-in
|
/// AddBuiltinOperatorCandidates - Add the appropriate built-in
|
||||||
|
|
Loading…
Reference in New Issue