From a913e872d6e7044ae77e55c45ab3ea5304eb7262 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Mon, 25 Nov 2019 16:25:27 -0500 Subject: [PATCH] [OPENMP]Fix PR44133: crash on lambda reductions in templates. Need to perform the instantiation of the combiner/initializer even if the resulting type is not dependent, if the construct is defined in templates in some cases. --- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 83 ++++++++++++------- ...declare_reduction_codegen_in_templates.cpp | 43 ++++++++++ 2 files changed, 94 insertions(+), 32 deletions(-) create mode 100644 clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 63777d5272b7..a2fd8a92dd61 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3067,6 +3067,17 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( } else { SubstReductionType = D->getType(); } + Expr *Combiner = D->getCombiner(); + Expr *Init = D->getInitializer(); + const bool CombinerRequiresInstantiation = + Combiner && + (Combiner->isValueDependent() || Combiner->isInstantiationDependent() || + Combiner->isTypeDependent() || + Combiner->containsUnexpandedParameterPack()); + const bool InitRequiresInstantiation = + Init && + (Init->isValueDependent() || Init->isInstantiationDependent() || + Init->isTypeDependent() || Init->containsUnexpandedParameterPack()); if (SubstReductionType.isNull()) return nullptr; bool IsCorrect = !SubstReductionType.isNull(); @@ -3084,11 +3095,12 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( PrevDeclInScope); auto *NewDRD = cast(DRD.get().getSingleDecl()); SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD); - if (!RequiresInstantiation) { - if (Expr *Combiner = D->getCombiner()) { + if (!RequiresInstantiation && !CombinerRequiresInstantiation && + !InitRequiresInstantiation) { + if (Combiner) { NewDRD->setCombinerData(D->getCombinerIn(), D->getCombinerOut()); NewDRD->setCombiner(Combiner); - if (Expr *Init = D->getInitializer()) { + if (Init) { NewDRD->setInitializerData(D->getInitOrig(), D->getInitPriv()); NewDRD->setInitializer(Init, D->getInitializerKind()); } @@ -3100,22 +3112,32 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( Expr *SubstCombiner = nullptr; Expr *SubstInitializer = nullptr; // Combiners instantiation sequence. - if (D->getCombiner()) { - SemaRef.ActOnOpenMPDeclareReductionCombinerStart( - /*S=*/nullptr, NewDRD); - SemaRef.CurrentInstantiationScope->InstantiatedLocal( - cast(D->getCombinerIn())->getDecl(), - cast(NewDRD->getCombinerIn())->getDecl()); - SemaRef.CurrentInstantiationScope->InstantiatedLocal( - cast(D->getCombinerOut())->getDecl(), - cast(NewDRD->getCombinerOut())->getDecl()); - auto *ThisContext = dyn_cast_or_null(Owner); - Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(), - ThisContext); - SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get(); - SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner); - // Initializers instantiation sequence. - if (D->getInitializer()) { + if (Combiner) { + if (!CombinerRequiresInstantiation) { + NewDRD->setCombinerData(D->getCombinerIn(), D->getCombinerOut()); + NewDRD->setCombiner(Combiner); + } else { + SemaRef.ActOnOpenMPDeclareReductionCombinerStart( + /*S=*/nullptr, NewDRD); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + cast(D->getCombinerIn())->getDecl(), + cast(NewDRD->getCombinerIn())->getDecl()); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + cast(D->getCombinerOut())->getDecl(), + cast(NewDRD->getCombinerOut())->getDecl()); + auto *ThisContext = dyn_cast_or_null(Owner); + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(), + ThisContext); + SubstCombiner = SemaRef.SubstExpr(Combiner, TemplateArgs).get(); + SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner); + } + } + // Initializers instantiation sequence. + if (Init) { + if (!InitRequiresInstantiation) { + NewDRD->setInitializerData(D->getInitOrig(), D->getInitPriv()); + NewDRD->setInitializer(Init, D->getInitializerKind()); + } else { VarDecl *OmpPrivParm = SemaRef.ActOnOpenMPDeclareReductionInitializerStart( /*S=*/nullptr, NewDRD); @@ -3126,8 +3148,7 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( cast(D->getInitPriv())->getDecl(), cast(NewDRD->getInitPriv())->getDecl()); if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) { - SubstInitializer = - SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get(); + SubstInitializer = SemaRef.SubstExpr(Init, TemplateArgs).get(); } else { auto *OldPrivParm = cast(cast(D->getInitPriv())->getDecl()); @@ -3139,19 +3160,17 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( SemaRef.ActOnOpenMPDeclareReductionInitializerEnd( NewDRD, SubstInitializer, OmpPrivParm); } - IsCorrect = - IsCorrect && SubstCombiner && - (!D->getInitializer() || - (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit && - SubstInitializer) || - (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit && - !SubstInitializer && !SubstInitializer)); - } else { - IsCorrect = false; } + IsCorrect = IsCorrect && (!CombinerRequiresInstantiation || SubstCombiner) && + (!InitRequiresInstantiation || + (!Init || + (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit && + SubstInitializer) || + (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit && + !SubstInitializer))); - (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD, - IsCorrect); + (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd( + /*S=*/nullptr, DRD, IsCorrect && !D->isInvalidDecl()); return NewDRD; } diff --git a/clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp b/clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp new file mode 100644 index 000000000000..0409c0219144 --- /dev/null +++ b/clang/test/OpenMP/declare_reduction_codegen_in_templates.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++17 -emit-llvm %s -triple x86_64-linux -fexceptions -fcxx-exceptions -o - -femit-all-decls -disable-llvm-passes | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++17 -triple x86_64-linux -fexceptions -fcxx-exceptions -emit-pch -o %t %s -femit-all-decls -disable-llvm-passes +// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-linux -fexceptions -fcxx-exceptions -std=c++17 -include-pch %t -verify %s -emit-llvm -o - -femit-all-decls -disable-llvm-passes | FileCheck %s + +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++17 -emit-llvm %s -triple x86_64-linux -fexceptions -fcxx-exceptions -o - -femit-all-decls -disable-llvm-passes | FileCheck --check-prefix SIMD-ONLY0 %s +// RUN: %clang_cc1 -fopenmp-simd -x c++ -std=c++17 -triple x86_64-linux -fexceptions -fcxx-exceptions -emit-pch -o %t %s -femit-all-decls -disable-llvm-passes +// RUN: %clang_cc1 -fopenmp-simd -x c++ -triple x86_64-linux -fexceptions -fcxx-exceptions -std=c++17 -include-pch %t -verify %s -emit-llvm -o - -femit-all-decls -disable-llvm-passes | FileCheck --check-prefix SIMD-ONLY0 %s +// SIMD-ONLY0-NOT: {{__kmpc|__tgt}} +// expected-no-diagnostics + +// CHECK: call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* @{{.+}}, i32 1, void (i32*, i32*, ...)* bitcast (void (i32*, i32*, [[STD_D:%.+]]*)* [[OUTLINED:@.+]] to void (i32*, i32*, ...)*), [[STD_D]]* %{{.+}}) + +// CHECK: define internal void [[OUTLINED]](i32* noalias %{{.+}}, i32* noalias %{{.+}}, [[STD_D]]* {{.+}}) +// CHECK: call i32 @__kmpc_reduce_nowait(%struct.ident_t* + +#ifndef HEADER +#define HEADER + +typedef long unsigned a; +namespace std { +template class initializer_list { + const int *b; + a c; +}; +template class d {}; +template class f { +public: + f(initializer_list); +}; +} // namespace std +template void foo(g, h) { + std::d i; +#pragma omp declare reduction(j : std::d : []{}()) +#pragma omp parallel reduction(j : i) + ; +} +void k() { + std::f l{}; + std::f m{2}; + foo(l, m); +} + +#endif // HEADER