`Issue 47177 <https://github.com/llvm/llvm-project/issues/47177>`_
`Issue 47179 <https://github.com/llvm/llvm-project/issues/47179>`_
- Fix a crash upon stray coloncolon token in C2x mode.
+- Reject non-type template arguments formed by casting a non-zero integer
+ to a pointer in pre-C++17 modes, instead of treating them as null
+ pointers.
Improvements to Clang's diagnostics
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
def err_template_arg_member_ptr_base_derived_not_supported : Error<
"sorry, non-type template argument of pointer-to-member type %1 that refers "
"to member %q0 of a different class is not supported yet">;
+def err_template_arg_invalid : Error<
+ "non-type template argument '%0' is invalid">;
def ext_template_arg_extra_parens : ExtWarn<
"address non-type template argument cannot be surrounded by parentheses">;
def warn_cxx98_compat_template_arg_extra_parens : Warning<
// - a constant expression that evaluates to a null pointer value (4.10); or
// - a constant expression that evaluates to a null member pointer value
// (4.11); or
- if ((EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) ||
+ if ((EvalResult.Val.isLValue() && EvalResult.Val.isNullPointer()) ||
(EvalResult.Val.isMemberPointer() &&
!EvalResult.Val.getMemberPointerDecl())) {
// If our expression has an appropriate type, we've succeeded.
return NPV_NullPointer;
}
+ if (EvalResult.Val.isLValue() && !EvalResult.Val.getLValueBase()) {
+ // We found a pointer that isn't null, but doesn't refer to an object.
+ // We could just return NPV_NotNullPointer, but we can print a better
+ // message with the information we have here.
+ S.Diag(Arg->getExprLoc(), diag::err_template_arg_invalid)
+ << EvalResult.Val.getAsString(S.Context, ParamType);
+ S.Diag(Param->getLocation(), diag::note_template_param_here);
+ return NPV_Error;
+ }
+
// If we don't have a null pointer value, but we do have a NULL pointer
// constant, suggest a cast to the appropriate type.
if (Arg->isNullPointerConstant(S.Context, Expr::NPC_NeverValueDependent)) {
typedef decltype(nullptr) nullptr_t;
}
-template<int *ip> struct IP { // expected-note 5 {{template parameter is declared here}}
+template<int *ip> struct IP { // expected-note 6 {{template parameter is declared here}}
IP<ip> *ip2;
};
// expected-note{{read of non-constexpr variable 'nonconst_np' is not allowed in a constant expression}}
IP<(float*)0> ip6; // expected-error{{null non-type template argument of type 'float *' does not match template parameter of type 'int *'}}
IP<&tl> ip7; // expected-error{{non-type template argument of type 'int *' is not a constant expression}}
+IP<(int*)1> ip8; // expected-error {{non-type template argument '(int *)1' is invalid}}
IR<tl> ir1; // expected-error{{non-type template argument refers to thread-local object}}
// -- a pointer to member expressed as described in 5.3.1.
namespace bad_args {
- template <int* N> struct X0 { }; // precxx17-note 2{{template parameter is declared here}}
+ template <int* N> struct X0 { }; // precxx17-note 4{{template parameter is declared here}}
int i = 42;
X0<&i + 2> x0a; // precxx17-error{{non-type template argument does not refer to any declaration}} \
cxx17-error {{non-type template argument is not a constant expression}} \
// cxx17-error@-5 {{non-type template argument is not a constant expression}}
// expected-note@-6 {{read of non-constexpr variable 'iptr' is not allowed in a constant expression}}
#endif
+ X0<(int*)1> x0c;
+ // precxx17-error@-1 {{non-type template argument '(int *)1' is invalid}}
+ // cxx17-error@-2 {{non-type template argument is not a constant expression}}
+ // cxx17-note@-3 {{reinterpret_cast}}
+ X0<__builtin_constant_p(0) ? (int*)1 : (int*)1> x0d;
+ // precxx17-error@-1 {{non-type template argument '(int *)1' is invalid}}
+ // cxx17-error@-2 {{non-type template argument refers to subobject '(int *)1'}}
}
#endif // CPP11ONLY