diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4330,6 +4330,7 @@ match_none disable_implicit_base allow_templates + bind_to_declaration The match extensions change when the *entire* context selector is considered a match for an OpenMP context. The default is ``all``, with ``none`` no trait in the @@ -4345,8 +4346,9 @@ applied to a definition. If ``allow_templates`` is given, template function definitions are considered as specializations of existing or assumed template declarations with the same name. The template parameters for the base functions -are used to instantiate the specialization. - +are used to instantiate the specialization. If ``bind_to_declartion`` is given, +apply the same variant rules to function declarations. This allows the user to +override declarations with only a function declaration. }]; } diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -960,6 +960,10 @@ TraitProperty::implementation_extension_allow_templates) return true; + if (TIProperty.Kind == + TraitProperty::implementation_extension_bind_to_declaration) + return true; + auto IsMatchExtension = [](OMPTraitProperty &TP) { return (TP.Kind == llvm::omp::TraitProperty::implementation_extension_match_all || diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5868,12 +5868,25 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { D.setFunctionDefinitionKind(FunctionDefinitionKind::Declaration); + + // Check if we are in an `omp begin/end declare variant` scope. Handle this + // declaration only if the `bind_to_declaration` extension is set. + SmallVector Bases; + if (LangOpts.OpenMP && isInOpenMPDeclareVariantScope()) + if (getOMPTraitInfoForSurroundingScope()->isExtensionActive(llvm::omp::TraitProperty:: + implementation_extension_bind_to_declaration)) + ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( + S, D, MultiTemplateParamsArg(), Bases); + Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg()); if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() && Dcl && Dcl->getDeclContext()->isFileContext()) Dcl->setTopLevelDeclInObjCContainer(); + if (!Bases.empty()) + ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(Dcl, Bases); + return Dcl; } diff --git a/clang/test/OpenMP/declare_variant_bind_to_decl.cpp b/clang/test/OpenMP/declare_variant_bind_to_decl.cpp new file mode 100644 --- /dev/null +++ b/clang/test/OpenMP/declare_variant_bind_to_decl.cpp @@ -0,0 +1,34 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple powerpc64le-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() { } + +#pragma omp begin declare variant match( \ + device = {arch(ppc64le, ppc64)}, \ + implementation = {extension(match_any, bind_to_declaration)}) + +void foo(); + +#pragma omp end declare variant + +int main() { + foo(); +} + +#endif +// CHECK-LABEL: define {{[^@]+}}@_Z3foov +// CHECK-SAME: () #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: ret void +// +// +// CHECK-LABEL: define {{[^@]+}}@main +// CHECK-SAME: () #[[ATTR1:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: call void @"_Z74foo$ompvariant$S2$s7$Pppc64le$Pppc64$S3$s9$Pmatch_any$Pbind_to_declarationv"() +// CHECK-NEXT: ret i32 0 +// diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def --- a/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def +++ b/llvm/include/llvm/Frontend/OpenMP/OMPKinds.def @@ -1160,6 +1160,7 @@ __OMP_TRAIT_PROPERTY(implementation, extension, match_none) __OMP_TRAIT_PROPERTY(implementation, extension, disable_implicit_base) __OMP_TRAIT_PROPERTY(implementation, extension, allow_templates) +__OMP_TRAIT_PROPERTY(implementation, extension, bind_to_declaration) __OMP_TRAIT_SET(user)