From bb3d7862139498e41fbf79fb0267027bd3b518b2 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 26 Mar 2010 02:38:37 +0000 Subject: [PATCH] Reinstate change to non-type template arguments of integral type, so that we extend/truncate then correct the sign to convert the non-type template argument to the template parameter's type. Previously, we reported an error when the non-type template argument was out of range; now we just warn. llvm-svn: 99600 --- .../clang/Basic/DiagnosticSemaKinds.td | 14 ++--- clang/lib/Sema/SemaTemplate.cpp | 57 ++++++++++--------- .../CXX/temp/temp.fct.spec/temp.deduct/p9.cpp | 6 ++ clang/test/SemaTemplate/temp_arg_nontype.cpp | 10 ++-- 4 files changed, 47 insertions(+), 40 deletions(-) create mode 100644 clang/test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 4b14595892e8..c6f20247fa84 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1207,12 +1207,12 @@ def err_template_arg_not_ice : Error< def err_template_arg_not_convertible : Error< "non-type template argument of type %0 cannot be converted to a value " "of type %1">; -def err_template_arg_negative : Error< - "non-type template argument provides negative value '%0' for unsigned " - "template parameter of type %1">; -def err_template_arg_too_large : Error< - "non-type template argument value '%0' is too large for template " - "parameter of type %1">; +def warn_template_arg_negative : Warning< + "non-type template argument with value '%0' converted to '%1' for unsigned " + "template parameter of type %2">; +def warn_template_arg_too_large : Warning< + "non-type template argument value '%0' truncated to '%1' for " + "template parameter of type %2">; def err_template_arg_no_ref_bind : Error< "non-type template parameter of reference type %0 cannot bind to template " "argument of type %1">; @@ -1379,7 +1379,7 @@ def note_default_function_arg_instantiation_here : Note< "for '%0' required here">; def note_explicit_template_arg_substitution_here : Note< "while substituting explicitly-specified template arguments into function " - "template %f, here">; + "template %0, here">; def note_function_template_deduction_instantiation_here : Note< "while substituting deduced template arguments into function template %0, " "here">; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 5a1bec927c4f..ba9e3c7df9d3 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2554,38 +2554,39 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, IntegerType = Context.getCanonicalType(Enum->getDecl()->getIntegerType()); if (!Arg->isValueDependent()) { - // Check that an unsigned parameter does not receive a negative - // value. - if (IntegerType->isUnsignedIntegerType() - && (Value.isSigned() && Value.isNegative())) { - Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_negative) - << Value.toString(10) << Param->getType() - << Arg->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - // Check that we don't overflow the template parameter type. + llvm::APSInt OldValue = Value; + + // Coerce the template argument's value to the value it will have + // based on the template parameter's type. unsigned AllowedBits = Context.getTypeSize(IntegerType); - unsigned RequiredBits; - if (IntegerType->isUnsignedIntegerType()) - RequiredBits = Value.getActiveBits(); - else if (Value.isUnsigned()) - RequiredBits = Value.getActiveBits() + 1; - else - RequiredBits = Value.getMinSignedBits(); - if (RequiredBits > AllowedBits) { - Diag(Arg->getSourceRange().getBegin(), - diag::err_template_arg_too_large) - << Value.toString(10) << Param->getType() - << Arg->getSourceRange(); - Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - if (Value.getBitWidth() != AllowedBits) Value.extOrTrunc(AllowedBits); Value.setIsSigned(IntegerType->isSignedIntegerType()); + + // Complain if an unsigned parameter received a negative value. + if (IntegerType->isUnsignedIntegerType() + && (OldValue.isSigned() && OldValue.isNegative())) { + Diag(Arg->getSourceRange().getBegin(), diag::warn_template_arg_negative) + << OldValue.toString(10) << Value.toString(10) << Param->getType() + << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + } + + // Complain if we overflowed the template parameter's type. + unsigned RequiredBits; + if (IntegerType->isUnsignedIntegerType()) + RequiredBits = OldValue.getActiveBits(); + else if (OldValue.isUnsigned()) + RequiredBits = OldValue.getActiveBits() + 1; + else + RequiredBits = OldValue.getMinSignedBits(); + if (RequiredBits > AllowedBits) { + Diag(Arg->getSourceRange().getBegin(), + diag::warn_template_arg_too_large) + << OldValue.toString(10) << Value.toString(10) << Param->getType() + << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + } } // Add the value of this argument to the list of converted diff --git a/clang/test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp new file mode 100644 index 000000000000..634da7d1c267 --- /dev/null +++ b/clang/test/CXX/temp/temp.fct.spec/temp.deduct/p9.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template int f(int); // expected-note 2{{candidate}} +template int f(int); // expected-note 2{{candidate}} +int i1 = f<1>(0); // expected-error{{ambiguous}} +int i2 = f<1000>(0); // expected-error{{ambiguous}} diff --git a/clang/test/SemaTemplate/temp_arg_nontype.cpp b/clang/test/SemaTemplate/temp_arg_nontype.cpp index 9c20f2a0eb1e..d077a3593061 100644 --- a/clang/test/SemaTemplate/temp_arg_nontype.cpp +++ b/clang/test/SemaTemplate/temp_arg_nontype.cpp @@ -97,21 +97,21 @@ template struct Overflow; // expected-note{{template parameter Overflow<5> *overflow1; // okay Overflow<255> *overflow2; // okay -Overflow<256> *overflow3; // expected-error{{non-type template argument value '256' is too large for template parameter of type 'unsigned char'}} +Overflow<256> *overflow3; // expected-warning{{non-type template argument value '256' truncated to '0' for template parameter of type 'unsigned char'}} template struct Signedness; // expected-note{{template parameter is declared here}} Signedness<10> *signedness1; // okay -Signedness<-10> *signedness2; // expected-error{{non-type template argument provides negative value '-10' for unsigned template parameter of type 'unsigned int'}} +Signedness<-10> *signedness2; // expected-warning{{non-type template argument with value '-10' converted to '4294967286' for unsigned template parameter of type 'unsigned int'}} template struct SignedOverflow; // expected-note 3 {{template parameter is declared here}} SignedOverflow<1> *signedoverflow1; SignedOverflow<-1> *signedoverflow2; SignedOverflow<-128> *signedoverflow3; -SignedOverflow<-129> *signedoverflow4; // expected-error{{non-type template argument value '-129' is too large for template parameter of type 'signed char'}} +SignedOverflow<-129> *signedoverflow4; // expected-warning{{non-type template argument value '-129' truncated to '127' for template parameter of type 'signed char'}} SignedOverflow<127> *signedoverflow5; -SignedOverflow<128> *signedoverflow6; // expected-error{{non-type template argument value '128' is too large for template parameter of type 'signed char'}} -SignedOverflow<(unsigned char)128> *signedoverflow7; // expected-error{{non-type template argument value '128' is too large for template parameter of type 'signed char'}} +SignedOverflow<128> *signedoverflow6; // expected-warning{{non-type template argument value '128' truncated to '-128' for template parameter of type 'signed char'}} +SignedOverflow<(unsigned char)128> *signedoverflow7; // expected-warning{{non-type template argument value '128' truncated to '-128' for template parameter of type 'signed char'}} // Check canonicalization of template arguments. template struct FuncPtr0;