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
