From 0a29a05f029afce490db12f9fc00c3129fa8b701 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 26 Mar 2010 05:50:28 +0000 Subject: [PATCH] When deducing an integral template argument for a non-type template parameter, keep the integral value exactly as it was in the source code rather than trying to convert it to the type of the non-type template parameter (which may still be dependent!). The value will then be converted to the appropriate type once we check the resulting template arguments. Fixes PR6707. llvm-svn: 99611 --- clang/lib/Sema/SemaTemplateDeduction.cpp | 67 +++++++++++++----------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 3a8ed5089426..ed3e3c4c22eb 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -48,6 +48,27 @@ namespace clang { using namespace clang; +/// \brief Compare two APSInts, extending and switching the sign as +/// necessary to compare their values regardless of underlying type. +static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { + if (Y.getBitWidth() > X.getBitWidth()) + X.extend(Y.getBitWidth()); + else if (Y.getBitWidth() < X.getBitWidth()) + Y.extend(X.getBitWidth()); + + // If there is a signedness mismatch, correct it. + if (X.isSigned() != Y.isSigned()) { + // If the signed value is negative, then the values cannot be the same. + if ((Y.isSigned() && Y.isNegative()) || (X.isSigned() && X.isNegative())) + return false; + + Y.setIsSigned(true); + X.setIsSigned(true); + } + + return X == Y; +} + static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, @@ -74,47 +95,30 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, - llvm::APSInt Value, + llvm::APSInt Value, QualType ValueType, Sema::TemplateDeductionInfo &Info, llvm::SmallVectorImpl &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); if (Deduced[NTTP->getIndex()].isNull()) { - QualType T = NTTP->getType(); - - // FIXME: Make sure we didn't overflow our data type! - unsigned AllowedBits = S.Context.getTypeSize(T); - if (Value.getBitWidth() != AllowedBits) - Value.extOrTrunc(AllowedBits); - Value.setIsSigned(T->isSignedIntegerType()); - - Deduced[NTTP->getIndex()] = TemplateArgument(Value, T); + Deduced[NTTP->getIndex()] = TemplateArgument(Value, ValueType); return Sema::TDK_Success; } - assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral); - - // If the template argument was previously deduced to a negative value, - // then our deduction fails. - const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral(); - if (PrevValuePtr->isNegative()) { + if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(Value, NTTP->getType()); - return Sema::TDK_Inconsistent; + Info.SecondArg = TemplateArgument(Value, ValueType); + return Sema::TDK_Inconsistent; } - llvm::APSInt PrevValue = *PrevValuePtr; - if (Value.getBitWidth() > PrevValue.getBitWidth()) - PrevValue.zext(Value.getBitWidth()); - else if (Value.getBitWidth() < PrevValue.getBitWidth()) - Value.zext(PrevValue.getBitWidth()); - - if (Value != PrevValue) { + // Extent the smaller of the two values. + llvm::APSInt PrevValue = *Deduced[NTTP->getIndex()].getAsIntegral(); + if (!hasSameExtendedValue(PrevValue, Value)) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = TemplateArgument(Value, NTTP->getType()); + Info.SecondArg = TemplateArgument(Value, ValueType); return Sema::TDK_Inconsistent; } @@ -137,8 +141,7 @@ DeduceNonTypeTemplateArgument(Sema &S, "Expression template argument must be type- or value-dependent."); if (Deduced[NTTP->getIndex()].isNull()) { - // FIXME: Clone the Value? - Deduced[NTTP->getIndex()] = TemplateArgument(Value); + Deduced[NTTP->getIndex()] = TemplateArgument(Value->Retain()); return Sema::TDK_Success; } @@ -569,7 +572,8 @@ DeduceTemplateArguments(Sema &S, if (const ConstantArrayType *ConstantArrayArg = dyn_cast(ArrayArg)) { llvm::APSInt Size(ConstantArrayArg->getSize()); - return DeduceNonTypeTemplateArgument(S, NTTP, Size, + return DeduceNonTypeTemplateArgument(S, NTTP, Size, + S.Context.getSizeType(), Info, Deduced); } if (const DependentSizedArrayType *DependentArrayArg @@ -816,8 +820,7 @@ DeduceTemplateArguments(Sema &S, case TemplateArgument::Integral: if (Arg.getKind() == TemplateArgument::Integral) { - // FIXME: Zero extension + sign checking here? - if (*Param.getAsIntegral() == *Arg.getAsIntegral()) + if (hasSameExtendedValue(*Param.getAsIntegral(), *Arg.getAsIntegral())) return Sema::TDK_Success; Info.FirstArg = Param; @@ -840,9 +843,9 @@ DeduceTemplateArguments(Sema &S, if (NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Param.getAsExpr())) { if (Arg.getKind() == TemplateArgument::Integral) - // FIXME: Sign problems here return DeduceNonTypeTemplateArgument(S, NTTP, *Arg.getAsIntegral(), + Arg.getIntegralType(), Info, Deduced); if (Arg.getKind() == TemplateArgument::Expression) return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(),