[clang] 795f679 - [Sema] Don't treat a non-null template argument as if it were null.

Eli Friedman via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 19 14:42:24 PDT 2022


Author: Eli Friedman
Date: 2022-10-19T14:40:52-07:00
New Revision: 795f67934d38c2c080aa65f5244dcbdccdbd1154

URL: https://github.com/llvm/llvm-project/commit/795f67934d38c2c080aa65f5244dcbdccdbd1154
DIFF: https://github.com/llvm/llvm-project/commit/795f67934d38c2c080aa65f5244dcbdccdbd1154.diff

LOG: [Sema] Don't treat a non-null template argument as if it were null.

The way this code checks whether a pointer is null is wrong for other
reasons; it doesn't actually check whether a null pointer constant is a
"constant" in the C++ standard sense.  But this fix at least makes sure
we don't treat a non-null pointer as if it were null.

Fixes https://github.com/llvm/llvm-project/issues/57883

Differential Revision: https://reviews.llvm.org/D134928

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaTemplate.cpp
    clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
    clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 60f6562cee67c..c33798e16e0dc 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -252,6 +252,9 @@ Bug Fixes
   `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
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 605128ee36bc0..f8fe9555f8c02 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5027,6 +5027,8 @@ def err_template_arg_not_pointer_to_member_form : Error<
 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 
diff erent 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<

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 551e0c3cf3b07..f6627c9bc53c3 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -6506,7 +6506,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
   //   - 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.
@@ -6524,6 +6524,16 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param,
     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)) {

diff  --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
index 97167eb596997..e28753c3d668c 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1-11.cpp
@@ -4,7 +4,7 @@ namespace std {
   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;
 };
 
@@ -28,6 +28,7 @@ IP<nonconst_np> ip5; // expected-error{{non-type template argument of type 'std:
 // 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}}
 

diff  --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
index 41a627071f0e6..a17720c9267cc 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -176,7 +176,7 @@ namespace addr_of_obj_or_func {
 //   -- 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}} \
@@ -194,6 +194,13 @@ namespace bad_args {
   // cxx17-error at -5 {{non-type template argument is not a constant expression}}
   // expected-note at -6 {{read of non-constexpr variable 'iptr' is not allowed in a constant expression}}
 #endif
+  X0<(int*)1> x0c;
+  // precxx17-error at -1 {{non-type template argument '(int *)1' is invalid}}
+  // cxx17-error at -2 {{non-type template argument is not a constant expression}}
+  // cxx17-note at -3 {{reinterpret_cast}}
+  X0<__builtin_constant_p(0) ? (int*)1 : (int*)1> x0d;
+  // precxx17-error at -1 {{non-type template argument '(int *)1' is invalid}}
+  // cxx17-error at -2 {{non-type template argument refers to subobject '(int *)1'}}
 }
 #endif // CPP11ONLY
 


        


More information about the cfe-commits mailing list