https://github.com/akash-manna-sky created 
https://github.com/llvm/llvm-project/pull/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!


>From b642d5eacdb063e45c956d7c2975eb412884e7b8 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Tue, 6 Oct 2026 11:03:36 +0530
Subject: [PATCH] [Clang][OpenMP] Fix crash on failed type substitution in
 declare reduction/mapper

Fixes #223366

When a template containing `#pragma omp declare reduction` is
instantiated, `VisitOMPDeclareReductionDecl` substitutes the reduction
type and hands the result to `ActOnOpenMPDeclareReductionType`. It never
checked whether the substitution worked. If it failed, `SubstType` had
already reported the error and returned a null type, which then tripped
`assert(ParsedType.isUsable())`. `-fms-compatibility` is incidental in
the report: it only makes the undeclared `baz` a dependent name that is
looked up at instantiation time, and plain `typename T::type` with
`T = int` crashes the same way. `VisitOMPDeclareMapperDecl` had the same
code, and there a build without assertions dereferenced the null type.

Both visitors now check the substituted type and return before calling
into `SemaOpenMP` when it is null. The error has already been emitted,
so no new diagnostic is added, and the declaration is dropped the same
way as when the instantiated type is rejected, for example for being a
reference type.
---
 clang/docs/ReleaseNotes.md                    |  2 ++
 .../lib/Sema/SemaTemplateInstantiateDecl.cpp  | 16 +++++++-----
 clang/test/OpenMP/declare_mapper_messages.cpp | 20 +++++++++++++++
 .../OpenMP/declare_reduction_messages.cpp     | 16 ++++++++++++
 .../OpenMP/declare_reduction_ms_compat.cpp    | 25 +++++++++++++++++++
 5 files changed, 73 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/OpenMP/declare_reduction_ms_compat.cpp

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 7ec126a065ae5..a7683d7532475 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -588,6 +588,8 @@ features cannot lower the translation-unit ABI level;
 - 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 5e72f05c863a0..eaa82623eb6b6 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4569,10 +4569,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();
   }
@@ -4661,10 +4663,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 f2101786f6ce0..cf9c339bc44ae 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 f91d952dfa14f..3d49a5d57cdda 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 0000000000000..96bacfa3f7aec
--- /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