https://github.com/ykhatav updated https://github.com/llvm/llvm-project/pull/212307
>From 15554886936818af13a7e44cd247ddb6ee7912ab Mon Sep 17 00:00:00 2001 From: "Khatavkar, Yashasvi" <[email protected]> Date: Mon, 27 Jul 2026 10:29:02 -0700 Subject: [PATCH 1/6] Validate prefer_type fr()/attr() arguments in append_args clause --- clang/lib/Parse/ParseOpenMP.cpp | 5 +- clang/lib/Sema/SemaOpenMP.cpp | 90 +++++++++++-------- ...riant_append_args_prefer_type_messages.cpp | 59 ++++++++++++ 3 files changed, 114 insertions(+), 40 deletions(-) create mode 100644 clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index dd2dc60a99156..6b218b8ce84c8 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3765,8 +3765,9 @@ bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo, bool IsTargetSync = false; while (Tok.is(tok::identifier)) { - // Currently prefer_type is only allowed with 'init' and it must be first. - bool PreferTypeAllowed = Kind == OMPC_init && InteropInfo.Prefs.empty() && + // prefer_type is allowed with 'init' and 'append_args' and must be first. + bool PreferTypeAllowed = (Kind == OMPC_init || Kind == OMPC_append_args) && + InteropInfo.Prefs.empty() && !IsTarget && !IsTargetSync; if (Tok.getIdentifierInfo()->isStr("target")) { // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 76bb0d38d428f..fc46ac7273f32 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -7842,6 +7842,49 @@ SemaOpenMP::checkOpenMPDeclareVariantFunction(SemaOpenMP::DeclGroupPtrTy DG, return std::make_pair(FD, cast<Expr>(DRE)); } +/// Check prefer_type fr()/attr() arguments in an OMPInteropInfo for validity. +/// Returns true if all arguments are valid; emits a diagnostic and returns +/// false on the first invalid argument. +static bool checkPreferTypeArgs(SemaOpenMP &S, const OMPInteropInfo &Info) { + for (const OMPInteropPref &P : Info.Prefs) { + const Expr *E = P.Fr; + if (!E) { + assert(Info.HasPreferAttrs && "null Fr requires OMP 6.0 syntax"); + } else if (!E->isValueDependent() && !E->isTypeDependent() && + !E->isInstantiationDependent() && + !E->containsUnexpandedParameterPack()) { + if (!E->isIntegerConstantExpr(S.getASTContext()) && + !isa<StringLiteral>(E)) { + S.Diag(E->getExprLoc(), diag::err_omp_interop_prefer_type); + return false; + } + } + for (const Expr *A : P.Attrs) { + if (A->isValueDependent() || A->isTypeDependent() || + A->isInstantiationDependent() || + A->containsUnexpandedParameterPack()) + continue; + const auto *SL = dyn_cast<StringLiteral>(A); + if (!SL) { + S.Diag(A->getExprLoc(), diag::err_omp_interop_attr_not_string); + return false; + } + if (!SL->getString().starts_with("ompx_")) { + S.Diag(A->getExprLoc(), + diag::err_omp_interop_attr_missing_ompx_prefix) + << SL->getString(); + return false; + } + if (SL->getString().contains(',')) { + S.Diag(A->getExprLoc(), diag::err_omp_interop_attr_contains_comma) + << SL->getString(); + return false; + } + } + } + return true; +} + void SemaOpenMP::ActOnOpenMPDeclareVariantDirective( FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI, ArrayRef<Expr *> AdjustArgsNothing, @@ -7921,6 +7964,13 @@ void SemaOpenMP::ActOnOpenMPDeclareVariantDirective( } } + // OpenMP 6.0 [16.1.3] Check prefer_type fr()/attr() arguments in + // append_args. + for (const OMPInteropInfo &Info : AppendArgs) { + if (!checkPreferTypeArgs(*this, Info)) + return; + } + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( getASTContext(), VariantRef, &TI, const_cast<Expr **>(AdjustArgsNothing.data()), AdjustArgsNothing.size(), @@ -19086,44 +19136,8 @@ OMPClause *SemaOpenMP::ActOnOpenMPInitClause( if (!isValidInteropVariable(SemaRef, InteropVar, VarLoc, OMPC_init)) return nullptr; - // Check prefer_type values. fr() arguments are either string literals or - // constant integral expressions; null Fr is only valid in OMP 6.0. - // attr() arguments must be ext-string-literals with the 'ompx_' prefix - // (OpenMP 6.0 spec, section 16.1.3). - for (const OMPInteropPref &P : InteropInfo.Prefs) { - const Expr *E = P.Fr; - if (!E) { - assert(InteropInfo.HasPreferAttrs && "null Fr requires OMP 6.0 syntax"); - } else if (!E->isValueDependent() && !E->isTypeDependent() && - !E->isInstantiationDependent() && - !E->containsUnexpandedParameterPack()) { - if (!E->isIntegerConstantExpr(getASTContext()) && - !isa<StringLiteral>(E)) { - Diag(E->getExprLoc(), diag::err_omp_interop_prefer_type); - return nullptr; - } - } - for (const Expr *A : P.Attrs) { - if (A->isValueDependent() || A->isTypeDependent() || - A->isInstantiationDependent() || A->containsUnexpandedParameterPack()) - continue; - const auto *SL = dyn_cast<StringLiteral>(A); - if (!SL) { - Diag(A->getExprLoc(), diag::err_omp_interop_attr_not_string); - return nullptr; - } - if (!SL->getString().starts_with("ompx_")) { - Diag(A->getExprLoc(), diag::err_omp_interop_attr_missing_ompx_prefix) - << SL->getString(); - return nullptr; - } - if (SL->getString().contains(',')) { - Diag(A->getExprLoc(), diag::err_omp_interop_attr_contains_comma) - << SL->getString(); - return nullptr; - } - } - } + if (!checkPreferTypeArgs(*this, InteropInfo)) + return nullptr; return OMPInitClause::Create(getASTContext(), InteropVar, InteropInfo, StartLoc, LParenLoc, VarLoc, EndLoc); diff --git a/clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp b/clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp new file mode 100644 index 0000000000000..0fb9566faf3a3 --- /dev/null +++ b/clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=60 -std=c++11 -o - %s + +typedef void *omp_interop_t; + +void foo_v1(float *A, float *B, omp_interop_t IOp); + +// expected-error@+2 {{prefer_list item must be a string literal or constant integral expression}} +#pragma omp declare variant(foo_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr(1.0)}), target)) +void foo_fr_float(float *A, float *B) {} + +void bar_v1(float *A, omp_interop_t IOp); + +// expected-error@+2 {{attr() argument must be a string literal}} +#pragma omp declare variant(bar_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr(1)}), target)) +void bar_attr_int(float *A) {} + +void baz_v1(float *A, omp_interop_t IOp); + +// expected-error@+2 {{attr() argument 'cuda_prop' must start with the 'ompx_' prefix}} +#pragma omp declare variant(baz_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr("cuda_prop")}), target)) +void baz_attr_no_prefix(float *A) {} + +void qux_v1(float *A, omp_interop_t IOp); + +// expected-error@+2 {{attr() argument 'ompx_a,b' must not contain a comma}} +#pragma omp declare variant(qux_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr("ompx_a,b")}), target)) +void qux_attr_comma(float *A) {} + +// Valid cases -- no diagnostics expected. +void valid_v1(float *A, omp_interop_t IOp); + +#pragma omp declare variant(valid_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr("cuda")}), target)) +void valid_fr_string(float *A) {} + +void valid_v2(float *A, omp_interop_t IOp); + +#pragma omp declare variant(valid_v2) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr(1)}), target)) +void valid_fr_int(float *A) {} + +void valid_v3(float *A, omp_interop_t IOp); + +#pragma omp declare variant(valid_v3) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr("ompx_myattr")}), target)) +void valid_attr(float *A) {} + +// Template case: fr() argument becomes invalid at instantiation. +template <typename T> +void tmpl_v1(T *A, omp_interop_t IOp); + +// expected-error@+2 {{prefer_list item must be a string literal or constant integral expression}} +#pragma omp declare variant(tmpl_v1<int>) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr(1.5)}), target)) +void tmpl_fr_invalid(int *A) {} >From 0f1069f81eb594a7947d5d02e2fca61c6e5580a9 Mon Sep 17 00:00:00 2001 From: "Khatavkar, Yashasvi" <[email protected]> Date: Mon, 27 Jul 2026 11:37:10 -0700 Subject: [PATCH 2/6] Fix formatting --- clang/lib/Parse/ParseOpenMP.cpp | 4 ++-- clang/lib/Sema/SemaOpenMP.cpp | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 6b218b8ce84c8..ab46d81402d7d 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3767,8 +3767,8 @@ bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo, while (Tok.is(tok::identifier)) { // prefer_type is allowed with 'init' and 'append_args' and must be first. bool PreferTypeAllowed = (Kind == OMPC_init || Kind == OMPC_append_args) && - InteropInfo.Prefs.empty() && - !IsTarget && !IsTargetSync; + InteropInfo.Prefs.empty() && !IsTarget && + !IsTargetSync; if (Tok.getIdentifierInfo()->isStr("target")) { // OpenMP 5.1 [2.15.1, interop Construct, Restrictions] // Each interop-type may be specified on an action-clause at most diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index fc46ac7273f32..15b4969f1f3a9 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -7861,8 +7861,7 @@ static bool checkPreferTypeArgs(SemaOpenMP &S, const OMPInteropInfo &Info) { } for (const Expr *A : P.Attrs) { if (A->isValueDependent() || A->isTypeDependent() || - A->isInstantiationDependent() || - A->containsUnexpandedParameterPack()) + A->isInstantiationDependent() || A->containsUnexpandedParameterPack()) continue; const auto *SL = dyn_cast<StringLiteral>(A); if (!SL) { @@ -7870,8 +7869,7 @@ static bool checkPreferTypeArgs(SemaOpenMP &S, const OMPInteropInfo &Info) { return false; } if (!SL->getString().starts_with("ompx_")) { - S.Diag(A->getExprLoc(), - diag::err_omp_interop_attr_missing_ompx_prefix) + S.Diag(A->getExprLoc(), diag::err_omp_interop_attr_missing_ompx_prefix) << SL->getString(); return false; } >From 10cfffe38d7d37ca99cc1b20925959c30ab41115 Mon Sep 17 00:00:00 2001 From: "Khatavkar, Yashasvi" <[email protected]> Date: Wed, 29 Jul 2026 10:11:11 -0700 Subject: [PATCH 3/6] Address review comments --- clang/lib/Sema/SemaOpenMP.cpp | 28 +++++++------ ...riant_append_args_prefer_type_messages.cpp | 39 +++++++++++++++++++ 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 15b4969f1f3a9..4d723cde7de7d 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -7842,17 +7842,21 @@ SemaOpenMP::checkOpenMPDeclareVariantFunction(SemaOpenMP::DeclGroupPtrTy DG, return std::make_pair(FD, cast<Expr>(DRE)); } -/// Check prefer_type fr()/attr() arguments in an OMPInteropInfo for validity. -/// Returns true if all arguments are valid; emits a diagnostic and returns -/// false on the first invalid argument. +/// Validate prefer_type fr() and attr() arguments in an OMPInteropInfo. +/// fr() must be a string literal or constant integer expression. +/// attr() must be a string literal starting with "ompx_" and containing no commas. +/// Returns true if valid; emits diagnostic and returns false on first error. static bool checkPreferTypeArgs(SemaOpenMP &S, const OMPInteropInfo &Info) { + auto isDependent = [](const Expr *E) { + return E->isValueDependent() || E->isTypeDependent() || + E->isInstantiationDependent() || + E->containsUnexpandedParameterPack(); + }; for (const OMPInteropPref &P : Info.Prefs) { const Expr *E = P.Fr; if (!E) { assert(Info.HasPreferAttrs && "null Fr requires OMP 6.0 syntax"); - } else if (!E->isValueDependent() && !E->isTypeDependent() && - !E->isInstantiationDependent() && - !E->containsUnexpandedParameterPack()) { + } else if (!isDependent(E)) { if (!E->isIntegerConstantExpr(S.getASTContext()) && !isa<StringLiteral>(E)) { S.Diag(E->getExprLoc(), diag::err_omp_interop_prefer_type); @@ -7860,22 +7864,22 @@ static bool checkPreferTypeArgs(SemaOpenMP &S, const OMPInteropInfo &Info) { } } for (const Expr *A : P.Attrs) { - if (A->isValueDependent() || A->isTypeDependent() || - A->isInstantiationDependent() || A->containsUnexpandedParameterPack()) + if (isDependent(A)) continue; const auto *SL = dyn_cast<StringLiteral>(A); if (!SL) { S.Diag(A->getExprLoc(), diag::err_omp_interop_attr_not_string); return false; } - if (!SL->getString().starts_with("ompx_")) { + StringRef Str = SL->getString(); + if (!Str.starts_with("ompx_")) { S.Diag(A->getExprLoc(), diag::err_omp_interop_attr_missing_ompx_prefix) - << SL->getString(); + << Str; return false; } - if (SL->getString().contains(',')) { + if (Str.contains(',')) { S.Diag(A->getExprLoc(), diag::err_omp_interop_attr_contains_comma) - << SL->getString(); + << Str; return false; } } diff --git a/clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp b/clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp index 0fb9566faf3a3..7c514a1e24395 100644 --- a/clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp +++ b/clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp @@ -30,6 +30,21 @@ void qux_v1(float *A, omp_interop_t IOp); append_args(interop(prefer_type({attr("ompx_a,b")}), target)) void qux_attr_comma(float *A) {} +// Edge cases for attr() and fr(). +void edge_v1(float *A, omp_interop_t IOp); + +// expected-error@+2 {{attr() argument 'ompx_a,b,c' must not contain a comma}} +#pragma omp declare variant(edge_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr("ompx_a,b,c")}), target)) +void edge_attr_multi_commas(float *A) {} + +void edge_v2(float *A, omp_interop_t IOp); + +// expected-error@+2 {{attr() argument '' must start with the 'ompx_' prefix}} +#pragma omp declare variant(edge_v2) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr("")}), target)) +void edge_attr_empty(float *A) {} + // Valid cases -- no diagnostics expected. void valid_v1(float *A, omp_interop_t IOp); @@ -49,6 +64,30 @@ void valid_v3(float *A, omp_interop_t IOp); append_args(interop(prefer_type({attr("ompx_myattr")}), target)) void valid_attr(float *A) {} +void valid_v4(float *A, omp_interop_t IOp); + +#pragma omp declare variant(valid_v4) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr("ompx_prop")}), target)) +void valid_attr_only(float *A) {} + +void valid_v5(float *A, omp_interop_t IOp); + +#pragma omp declare variant(valid_v5) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr(1), attr("ompx_prop")}), target)) +void valid_combined(float *A) {} + +void valid_v6(float *A, omp_interop_t IOp); + +#pragma omp declare variant(valid_v6) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr("ompx_")}), target)) +void valid_attr_prefix_only(float *A) {} + +void valid_v7(float *A, omp_interop_t IOp); + +#pragma omp declare variant(valid_v7) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr("")}), target)) +void valid_fr_empty_string(float *A) {} + // Template case: fr() argument becomes invalid at instantiation. template <typename T> void tmpl_v1(T *A, omp_interop_t IOp); >From 61910553632373f7f52e4e40b59235f6e69fb81f Mon Sep 17 00:00:00 2001 From: "Khatavkar, Yashasvi" <[email protected]> Date: Wed, 29 Jul 2026 13:08:36 -0700 Subject: [PATCH 4/6] Apply clang-format --- clang/lib/Sema/SemaOpenMP.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 4d723cde7de7d..51164744b345a 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -7844,8 +7844,9 @@ SemaOpenMP::checkOpenMPDeclareVariantFunction(SemaOpenMP::DeclGroupPtrTy DG, /// Validate prefer_type fr() and attr() arguments in an OMPInteropInfo. /// fr() must be a string literal or constant integer expression. -/// attr() must be a string literal starting with "ompx_" and containing no commas. -/// Returns true if valid; emits diagnostic and returns false on first error. +/// attr() must be a string literal starting with "ompx_" and containing no +/// commas. Returns true if valid; emits diagnostic and returns false on first +/// error. static bool checkPreferTypeArgs(SemaOpenMP &S, const OMPInteropInfo &Info) { auto isDependent = [](const Expr *E) { return E->isValueDependent() || E->isTypeDependent() || >From abfece960f19dbcf9d4eea242f7507ab28a930bb Mon Sep 17 00:00:00 2001 From: "Khatavkar, Yashasvi" <[email protected]> Date: Tue, 4 Aug 2026 11:45:27 -0700 Subject: [PATCH 5/6] Add missing template instantiation and PCH code --- clang/lib/AST/AttrImpl.cpp | 35 +++++++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 21 ++++- ...iant_append_args_prefer_type_ast_print.cpp | 79 +++++++++++++++++++ clang/utils/TableGen/ClangAttrEmitter.cpp | 53 ++++++++++++- 4 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 clang/test/OpenMP/declare_variant_append_args_prefer_type_ast_print.cpp diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp index cfd47e82b04b5..4fd7549e08468 100644 --- a/clang/lib/AST/AttrImpl.cpp +++ b/clang/lib/AST/AttrImpl.cpp @@ -233,11 +233,44 @@ void OMPDeclareVariantAttr::printPrettyPragma( OS << ")"; } - auto PrintInteropInfo = [&OS](OMPInteropInfo *Begin, OMPInteropInfo *End) { + auto PrintInteropInfo = [&OS, &Policy](OMPInteropInfo *Begin, + OMPInteropInfo *End) { for (OMPInteropInfo *I = Begin; I != End; ++I) { if (I != Begin) OS << ", "; OS << "interop("; + if (!I->Prefs.empty()) { + OS << "prefer_type("; + if (I->HasPreferAttrs) { + StringRef Sep = ""; + for (const auto &P : I->Prefs) { + OS << Sep << "{"; + if (P.Fr) { + OS << "fr("; + P.Fr->printPretty(OS, nullptr, Policy); + OS << ")"; + } + for (Expr *A : P.Attrs) { + if (P.Fr) + OS << ","; + OS << "attr("; + A->printPretty(OS, nullptr, Policy); + OS << ")"; + } + OS << "}"; + Sep = ","; + } + } else { + StringRef Sep = ""; + for (const auto &P : I->Prefs) { + OS << Sep; + if (P.Fr) + P.Fr->printPretty(OS, nullptr, Policy); + Sep = ","; + } + } + OS << "),"; + } OS << getInteropTypeString(I); OS << ")"; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index f1f97ca125f46..9eece865e9c11 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -578,8 +578,25 @@ static void instantiateOMPDeclareVariantAttr( NeedDeviceAddrExprs.push_back(ER.get()); } for (OMPInteropInfo &II : Attr.appendArgs()) { - // When prefer_type is implemented for append_args handle them here too. - AppendArgs.emplace_back(II.IsTarget, II.IsTargetSync); + OMPInteropInfo Info(II.IsTarget, II.IsTargetSync); + Info.HasPreferAttrs = II.HasPreferAttrs; + for (const OMPInteropPref &P : II.Prefs) { + Expr *SubstFr = nullptr; + if (P.Fr) { + ExprResult ER = Subst(P.Fr); + if (ER.isInvalid()) + continue; + SubstFr = ER.get(); + } + llvm::SmallVector<Expr *, 2> SubstAttrs; + for (Expr *A : P.Attrs) { + ExprResult ER = Subst(A); + if (!ER.isInvalid()) + SubstAttrs.push_back(ER.get()); + } + Info.Prefs.emplace_back(SubstFr, std::move(SubstAttrs)); + } + AppendArgs.push_back(Info); } S.OpenMP().ActOnOpenMPDeclareVariantDirective( diff --git a/clang/test/OpenMP/declare_variant_append_args_prefer_type_ast_print.cpp b/clang/test/OpenMP/declare_variant_append_args_prefer_type_ast_print.cpp new file mode 100644 index 0000000000000..b8ffe7c23d516 --- /dev/null +++ b/clang/test/OpenMP/declare_variant_append_args_prefer_type_ast_print.cpp @@ -0,0 +1,79 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \ +// RUN: -x c++ -std=c++14 -fsyntax-only -verify %s + +// expected-no-diagnostics + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \ +// RUN: -x c++ -std=c++14 -ast-print %s | FileCheck %s --check-prefix=PRINT + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \ +// RUN: -x c++ -std=c++14 -emit-pch -o %t %s + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \ +// RUN: -x c++ -std=c++14 -include-pch %t -ast-print %s \ +// RUN: | FileCheck %s --check-prefix=PRINT + +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60 \ +// RUN: -x c++ -std=c++14 -ast-dump %s \ +// RUN: | FileCheck %s --check-prefix=DUMP + +#ifndef HEADER +#define HEADER + +typedef void *omp_interop_t; + +// Basic append_args with prefer_type (non-template). +void foo_v1(float *A, omp_interop_t IOp); + +// PRINT: #pragma omp declare variant(foo_v1) match(construct={dispatch}) append_args(interop(prefer_type({fr("cuda")}),target)) +#pragma omp declare variant(foo_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr("cuda")}), target)) +void foo(float *A) {} + +// append_args with prefer_type containing fr() + attr(). +void bar_v1(float *A, omp_interop_t IOp); + +// PRINT: #pragma omp declare variant(bar_v1) match(construct={dispatch}) append_args(interop(prefer_type({fr("sycl"),attr("ompx_gpu")}),targetsync)) +#pragma omp declare variant(bar_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr("sycl"), attr("ompx_gpu")}), targetsync)) +void bar(float *A) {} + +// Template: prefer_type with integer expression in fr(). +template <typename T> +void tmpl_v1(T *A, omp_interop_t IOp); + +template <typename T> +void tmpl_bar(T *A); + +// PRINT: #pragma omp declare variant(tmpl_v1<int>) match(construct={dispatch}) append_args(interop(prefer_type({fr(1)}),target)) +#pragma omp declare variant(tmpl_v1<int>) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr(1)}), target)) +void tmpl_bar(int *A) {} + +// Template with dependent expression in fr(). +template <int N> +void dep_v1(float *A, omp_interop_t IOp); + +template <int N> +void dep_bar(float *A); + +// PRINT: #pragma omp declare variant(dep_v1<N>) match(construct={dispatch}) append_args(interop(prefer_type({fr(N)}),target)) +#pragma omp declare variant(dep_v1<N>) match(construct={dispatch}) \ + append_args(interop(prefer_type({fr(N)}), target)) +template <int N> +void dep_bar(float *A) {} + +// DUMP: FunctionDecl{{.*}}dep_bar 'void (float *)' explicit_instantiation_definition +// DUMP: OMPDeclareVariantAttr +// DUMP: IntegerLiteral{{.*}}'int' 4 +template void dep_bar<4>(float *); + +// Multiple prefer_type entries with attr() only. +void multi_v1(float *A, omp_interop_t IOp); + +// PRINT: #pragma omp declare variant(multi_v1) match(construct={dispatch}) append_args(interop(prefer_type({attr("ompx_propA")},{fr(2),attr("ompx_propB")}),target)) +#pragma omp declare variant(multi_v1) match(construct={dispatch}) \ + append_args(interop(prefer_type({attr("ompx_propA")}, {fr(2), attr("ompx_propB")}), target)) +void multi(float *A) {} + +#endif // HEADER diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 5987cb4a0f16b..a875f7f44c00d 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -905,8 +905,21 @@ namespace { OS << "I != E; ++I) {\n"; OS << " bool IsTarget = Record.readBool();\n"; OS << " bool IsTargetSync = Record.readBool();\n"; - OS << " " << getLowerName() - << ".emplace_back(IsTarget, IsTargetSync);\n"; + OS << " OMPInteropInfo Info(IsTarget, IsTargetSync);\n"; + OS << " Info.HasPreferAttrs = Record.readBool();\n"; + OS << " unsigned prefsSize = Record.readInt();\n"; + OS << " Info.Prefs.reserve(prefsSize);\n"; + OS << " for (unsigned J = 0; J < prefsSize; ++J) {\n"; + OS << " bool hasFr = Record.readBool();\n"; + OS << " Expr *Fr = hasFr ? Record.readExpr() : nullptr;\n"; + OS << " unsigned attrsSize = Record.readInt();\n"; + OS << " llvm::SmallVector<Expr *, 2> Attrs;\n"; + OS << " Attrs.reserve(attrsSize);\n"; + OS << " for (unsigned K = 0; K < attrsSize; ++K)\n"; + OS << " Attrs.push_back(Record.readExpr());\n"; + OS << " Info.Prefs.emplace_back(Fr, std::move(Attrs));\n"; + OS << " }\n"; + OS << " " << getLowerName() << ".push_back(Info);\n"; OS << " }\n"; } @@ -917,6 +930,42 @@ namespace { << getLowerName() << "_end(); I != E; ++I) {\n"; OS << " Record.writeBool(I->IsTarget);\n"; OS << " Record.writeBool(I->IsTargetSync);\n"; + OS << " Record.writeBool(I->HasPreferAttrs);\n"; + OS << " Record.push_back(I->Prefs.size());\n"; + OS << " for (auto &P : I->Prefs) {\n"; + OS << " Record.writeBool(P.Fr != nullptr);\n"; + OS << " if (P.Fr) Record.AddStmt(P.Fr);\n"; + OS << " Record.push_back(P.Attrs.size());\n"; + OS << " for (Expr *A : P.Attrs) Record.AddStmt(A);\n"; + OS << " }\n"; + OS << " }\n"; + } + + void writeASTVisitorTraversal(raw_ostream &OS) const override { + OS << " {\n"; + OS << " OMPInteropInfo *I = A->" << getLowerName() << "_begin();\n"; + OS << " " << getType() << " *E = A->" << getLowerName() + << "_end();\n"; + OS << " for (; I != E; ++I) {\n"; + OS << " for (auto &P : I->Prefs) {\n"; + OS << " if (P.Fr && !getDerived().TraverseStmt(P.Fr))\n"; + OS << " return false;\n"; + OS << " for (Expr *A : P.Attrs)\n"; + OS << " if (!getDerived().TraverseStmt(A))\n"; + OS << " return false;\n"; + OS << " }\n"; + OS << " }\n"; + OS << " }\n"; + } + + void writeDumpChildren(raw_ostream &OS) const override { + OS << " for (" << getAttrName() << "Attr::" << getLowerName() + << "_iterator I = SA->" << getLowerName() << "_begin(), E = SA->" + << getLowerName() << "_end(); I != E; ++I) {\n"; + OS << " for (auto &P : I->Prefs) {\n"; + OS << " if (P.Fr) Visit(P.Fr);\n"; + OS << " for (Expr *A : P.Attrs) Visit(A);\n"; + OS << " }\n"; OS << " }\n"; } }; >From f5a68295dd7e43c1504a559047794f6a4ba11a98 Mon Sep 17 00:00:00 2001 From: "Khatavkar, Yashasvi" <[email protected]> Date: Tue, 4 Aug 2026 11:57:51 -0700 Subject: [PATCH 6/6] Fix formatting --- clang/utils/TableGen/ClangAttrEmitter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index a875f7f44c00d..65a65f90969dd 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -944,8 +944,7 @@ namespace { void writeASTVisitorTraversal(raw_ostream &OS) const override { OS << " {\n"; OS << " OMPInteropInfo *I = A->" << getLowerName() << "_begin();\n"; - OS << " " << getType() << " *E = A->" << getLowerName() - << "_end();\n"; + OS << " " << getType() << " *E = A->" << getLowerName() << "_end();\n"; OS << " for (; I != E; ++I) {\n"; OS << " for (auto &P : I->Prefs) {\n"; OS << " if (P.Fr && !getDerived().TraverseStmt(P.Fr))\n"; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
