forked from OSchip/llvm-project
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
This commit is contained in:
parent
00a620c61e
commit
bb3d786213
|
@ -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">;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||
|
||||
template <int> int f(int); // expected-note 2{{candidate}}
|
||||
template <signed char> int f(int); // expected-note 2{{candidate}}
|
||||
int i1 = f<1>(0); // expected-error{{ambiguous}}
|
||||
int i2 = f<1000>(0); // expected-error{{ambiguous}}
|
|
@ -97,21 +97,21 @@ template<unsigned char C> 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<unsigned> 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<signed char C> 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<int (*)(int, int)> struct FuncPtr0;
|
||||
|
|
Loading…
Reference in New Issue