Author: Akash Manna
Date: 2026-10-31T04:02:06Z
New Revision: 3c6f58a02d1594adaa9144f7553331f2fb78872f

URL: 
https://github.com/llvm/llvm-project/commit/3c6f58a02d1594adaa9144f7553331f2fb78872f
DIFF: 
https://github.com/llvm/llvm-project/commit/3c6f58a02d1594adaa9144f7553331f2fb78872f.diff

LOG: [Clang][OpenMP] Fix crash on failed type substitution in declare 
reduction/mapper (#230059)

Fixes #223366

`VisitOMPDeclareReductionDecl` passed the substituted reduction type to
`ActOnOpenMPDeclareReductionType` without checking it, so a failed
substitution (null type) hit `assert(ParsedType.isUsable())`.
`-fms-compatibility` is not needed: `typename T::type` with `T = int`
crashes too. `declare mapper` had the same bug.

Both visitors now return early when the substituted type is null. The
error is already reported by `SubstType`.

I used AI tools for assistance!

Added: 
    clang/test/OpenMP/declare_reduction_ms_compat.cpp

Modified: 
    clang/docs/ReleaseNotes.md
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/test/OpenMP/declare_mapper_messages.cpp
    clang/test/OpenMP/declare_reduction_messages.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index f2cc86bf9ccc23..54a4f6fde79d27 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -799,6 +799,8 @@ documentation](CIR/index.md) for more information regarding 
ClangIR's status and
 - Fixed a crash when an OpenMP `copyprivate` clause names a non-static data 
member that is not private in the
   enclosing context, which is now diagnosed, a data member inside a member 
function template, or a structured
   binding. (#GH217893)
+- Fixed a crash when template argument substitution fails in the type of an 
OpenMP `declare reduction` or
+  `declare mapper` directive. (#GH223366)
 - Fixed an assertion failure when a variable implicitly mapped by an OpenMP 
`target` directive has a class type
   (such as `std::map`) whose mapper lookup instantiates a class template 
specialization. (#GH154704)
 - Fixed a bug where repeated #imports of modular headers in non-modular 
compilation were translated to #pragma clang module import. (#GH216924)

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp 
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ea154b2bbf4507..65c011024ce802 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4600,10 +4600,12 @@ Decl 
*TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
       D->getType()->containsUnexpandedParameterPack();
   QualType SubstReductionType;
   if (RequiresInstantiation) {
+    QualType T = SemaRef.SubstType(D->getType(), TemplateArgs, 
D->getLocation(),
+                                   DeclarationName());
+    if (T.isNull())
+      return nullptr;
     SubstReductionType = SemaRef.OpenMP().ActOnOpenMPDeclareReductionType(
-        D->getLocation(),
-        ParsedType::make(SemaRef.SubstType(
-            D->getType(), TemplateArgs, D->getLocation(), DeclarationName())));
+        D->getLocation(), ParsedType::make(T));
   } else {
     SubstReductionType = D->getType();
   }
@@ -4692,10 +4694,12 @@ 
TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) {
   QualType SubstMapperTy;
   DeclarationName VN = D->getVarName();
   if (RequiresInstantiation) {
+    QualType T =
+        SemaRef.SubstType(D->getType(), TemplateArgs, D->getLocation(), VN);
+    if (T.isNull())
+      return nullptr;
     SubstMapperTy = SemaRef.OpenMP().ActOnOpenMPDeclareMapperType(
-        D->getLocation(),
-        ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs,
-                                           D->getLocation(), VN)));
+        D->getLocation(), ParsedType::make(T));
   } else {
     SubstMapperTy = D->getType();
   }

diff  --git a/clang/test/OpenMP/declare_mapper_messages.cpp 
b/clang/test/OpenMP/declare_mapper_messages.cpp
index f2101786f6ce02..cf9c339bc44ae7 100644
--- a/clang/test/OpenMP/declare_mapper_messages.cpp
+++ b/clang/test/OpenMP/declare_mapper_messages.cpp
@@ -121,3 +121,23 @@ int fun(int arg) {
   }
   return arg;
 }
+
+#if __cplusplus >= 201103L
+namespace GH223366 {
+struct HasType {
+  typedef int type;
+};
+
+template <typename T> using Vec = vec;
+
+template <typename T>
+void f() {
+#pragma omp declare mapper(id : Vec<typename T::type> v) map(v.len) // 
expected-error {{type 'int' cannot be used prior to '::' because it has no 
members}}
+}
+
+void g() {
+  f<HasType>();
+  f<int>(); // expected-note {{in instantiation of function template 
specialization 'GH223366::f<int>' requested here}}
+}
+}
+#endif

diff  --git a/clang/test/OpenMP/declare_reduction_messages.cpp 
b/clang/test/OpenMP/declare_reduction_messages.cpp
index f91d952dfa14fb..3d49a5d57cddae 100644
--- a/clang/test/OpenMP/declare_reduction_messages.cpp
+++ b/clang/test/OpenMP/declare_reduction_messages.cpp
@@ -167,3 +167,19 @@ struct S
 #pragma omp declare reduction (bar : S<1> : omp_out.foo(omp_in))
 
 #endif
+
+namespace GH223366 {
+struct HasType {
+  typedef int type;
+};
+
+template <typename T>
+void f() {
+#pragma omp declare reduction(red : typename T::type : omp_out += omp_in) // 
expected-error {{type 'int' cannot be used prior to '::' because it has no 
members}}
+}
+
+void g() {
+  f<HasType>();
+  f<int>(); // expected-note {{in instantiation of function template 
specialization 'GH223366::f<int>' requested here}}
+}
+}

diff  --git a/clang/test/OpenMP/declare_reduction_ms_compat.cpp 
b/clang/test/OpenMP/declare_reduction_ms_compat.cpp
new file mode 100644
index 00000000000000..96bacfa3f7aec7
--- /dev/null
+++ b/clang/test/OpenMP/declare_reduction_ms_compat.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -verify -fopenmp -fms-compatibility %s
+// RUN: %clang_cc1 -verify -fopenmp-simd -fms-compatibility %s
+
+struct foo {};
+struct has_baz {
+  typedef int baz;
+};
+
+template <typename T> struct S : T {
+  virtual void bar() {
+#pragma omp declare reduction(foo : baz : omp_out)
+    // expected-warning@-1 {{use of undeclared identifier 'baz'; unqualified 
lookup into dependent bases of class template 'S' is a Microsoft extension}}
+    // expected-error@-2 {{no type named 'baz' in 'S<foo>'}}
+  }
+};
+
+template <typename T> struct NotInstantiated : T {
+  virtual void bar() {
+#pragma omp declare reduction(foo : baz : omp_out)
+    // expected-warning@-1 {{use of undeclared identifier 'baz'; unqualified 
lookup into dependent bases of class template 'NotInstantiated' is a Microsoft 
extension}}
+  }
+};
+
+S<foo> s; // expected-note {{in instantiation of member function 'S<foo>::bar' 
requested here}}
+S<has_baz> t;


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to