[clang] dd29759 - [Clang][OpenMP] Validate prefer_type fr()/attr() arguments in append_args clause (#212307)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 10 06:48:21 PDT 2026
Author: ykhatav
Date: 2026-08-10T09:48:16-04:00
New Revision: dd297590de15d5a9a287425d74c67abb46bf9136
URL: https://github.com/llvm/llvm-project/commit/dd297590de15d5a9a287425d74c67abb46bf9136
DIFF: https://github.com/llvm/llvm-project/commit/dd297590de15d5a9a287425d74c67abb46bf9136.diff
LOG: [Clang][OpenMP] Validate prefer_type fr()/attr() arguments in append_args clause (#212307)
The OpenMP 6.0 spec states that append_args(interop(...)) accepts the
same modifier-specification-list as the init clause, which includes
prefer_type. However, the parser rejected prefer_type in append_args,
and the semantic validation for fr()/attr() arguments was only performed
for the init clause. This patch allows prefer_type in the parser for
append_args and adds the corresponding semantic validation of
fr()/attr() arguments to ActOnOpenMPDeclareVariantDirective.
Added:
clang/test/OpenMP/declare_variant_append_args_prefer_type_ast_print.cpp
clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp
Modified:
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/lib/AST/AttrImpl.cpp
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/utils/TableGen/ClangAttrEmitter.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 2672bfb2952c8..6a48d74079f4e 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1722,6 +1722,8 @@ def err_omp_expected_fr_or_attr_selector : Error<
"expected 'fr' or 'attr' selector in 'prefer_type'">;
def err_omp_expected_pref_spec : Error<
"expected preference-specification in 'prefer_type'">;
+def err_omp_append_args_prefer_type_60 : Error<
+ "'prefer_type' in 'append_args' requires OpenMP version 6.0 or later">;
def err_expected_sequence_or_directive : Error<
"expected an OpenMP 'directive' or 'sequence' attribute argument">;
def ext_omp_attributes : ExtWarn<
diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp
index cfd47e82b04b5..7272ad0de9a2c 100644
--- a/clang/lib/AST/AttrImpl.cpp
+++ b/clang/lib/AST/AttrImpl.cpp
@@ -233,11 +233,46 @@ 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 << ")";
+ }
+ bool NeedSep = P.Fr != nullptr;
+ for (Expr *A : P.Attrs) {
+ if (NeedSep)
+ OS << ",";
+ OS << "attr(";
+ A->printPretty(OS, nullptr, Policy);
+ OS << ")";
+ NeedSep = true;
+ }
+ 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/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 6b4a6017669b2..f466b01975ac5 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -3767,9 +3767,10 @@ 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() &&
- !IsTarget && !IsTargetSync;
+ // 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]
// Each interop-type may be specified on an action-clause at most
@@ -3785,6 +3786,10 @@ bool Parser::ParseOMPInteropInfo(OMPInteropInfo &InteropInfo,
ConsumeToken();
} else if (Tok.getIdentifierInfo()->isStr("prefer_type") &&
PreferTypeAllowed) {
+ if (Kind == OMPC_append_args && getLangOpts().OpenMP < 60) {
+ Diag(Tok, diag::err_omp_append_args_prefer_type_60);
+ HasError = true;
+ }
ConsumeToken();
BalancedDelimiterTracker PT(*this, tok::l_paren,
tok::annot_pragma_openmp_end);
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 76bb0d38d428f..51164744b345a 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -7842,6 +7842,52 @@ SemaOpenMP::checkOpenMPDeclareVariantFunction(SemaOpenMP::DeclGroupPtrTy DG,
return std::make_pair(FD, cast<Expr>(DRE));
}
+/// 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 (!isDependent(E)) {
+ 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 (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;
+ }
+ StringRef Str = SL->getString();
+ if (!Str.starts_with("ompx_")) {
+ S.Diag(A->getExprLoc(), diag::err_omp_interop_attr_missing_ompx_prefix)
+ << Str;
+ return false;
+ }
+ if (Str.contains(',')) {
+ S.Diag(A->getExprLoc(), diag::err_omp_interop_attr_contains_comma)
+ << Str;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
void SemaOpenMP::ActOnOpenMPDeclareVariantDirective(
FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI,
ArrayRef<Expr *> AdjustArgsNothing,
@@ -7921,6 +7967,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 +19139,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/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/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..7c514a1e24395
--- /dev/null
+++ b/clang/test/OpenMP/declare_variant_append_args_prefer_type_messages.cpp
@@ -0,0 +1,98 @@
+// 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 at +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 at +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 at +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 at +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) {}
+
+// Edge cases for attr() and fr().
+void edge_v1(float *A, omp_interop_t IOp);
+
+// expected-error at +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 at +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);
+
+#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) {}
+
+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);
+
+// expected-error at +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) {}
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 5987cb4a0f16b..65a65f90969dd 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,41 @@ 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";
}
};
More information about the cfe-commits
mailing list