[flang-commits] [flang] d869939 - [OPENMP51]Initial parsing/sema for append_args clause for 'declare variant'
Mike Rice via flang-commits
flang-commits at lists.llvm.org
Mon Oct 25 09:43:20 PDT 2021
Author: Mike Rice
Date: 2021-10-25T09:38:50-07:00
New Revision: d8699391a431af5730fe36ac4b05840020c42203
URL: https://github.com/llvm/llvm-project/commit/d8699391a431af5730fe36ac4b05840020c42203
DIFF: https://github.com/llvm/llvm-project/commit/d8699391a431af5730fe36ac4b05840020c42203.diff
LOG: [OPENMP51]Initial parsing/sema for append_args clause for 'declare variant'
Adds initial parsing and sema for the 'append_args' clause.
Note that an AST clause is not created as it instead adds its values
to the OMPDeclareVariantAttr.
Differential Revision: https://reviews.llvm.org/D111854
Added:
Modified:
clang/include/clang/Basic/Attr.td
clang/include/clang/Basic/DiagnosticParseKinds.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Parse/Parser.h
clang/include/clang/Sema/Sema.h
clang/lib/AST/AttrImpl.cpp
clang/lib/Basic/OpenMPKinds.cpp
clang/lib/CodeGen/CGStmtOpenMP.cpp
clang/lib/Parse/ParseOpenMP.cpp
clang/lib/Sema/SemaOpenMP.cpp
clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
clang/test/OpenMP/declare_variant_clauses_ast_print.cpp
clang/test/OpenMP/declare_variant_clauses_messages.cpp
clang/test/OpenMP/declare_variant_messages.cpp
flang/lib/Semantics/check-omp-structure.cpp
llvm/include/llvm/Frontend/OpenMP/OMP.td
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index f58217f8f44a..31ca7d21b902 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3692,7 +3692,10 @@ def OMPDeclareVariant : InheritableAttr {
ExprArgument<"VariantFuncRef">,
OMPTraitInfoArgument<"TraitInfos">,
VariadicExprArgument<"AdjustArgsNothing">,
- VariadicExprArgument<"AdjustArgsNeedDevicePtr">
+ VariadicExprArgument<"AdjustArgsNeedDevicePtr">,
+ VariadicEnumArgument<"AppendArgs", "InteropType",
+ ["target", "targetsync", "target,targetsync"],
+ ["Target", "TargetSync", "Target_TargetSync"]>
];
let AdditionalMembers = [{
OMPTraitInfo &getTraitInfo() { return *traitInfos; }
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 367da91afbae..297e974c6488 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1359,9 +1359,11 @@ def err_omp_mapper_illegal_identifier : Error<
"illegal OpenMP user-defined mapper identifier">;
def err_omp_mapper_expected_declarator : Error<
"expected declarator on 'omp declare mapper' directive">;
+def err_omp_unexpected_append_op : Error<
+ "unexpected operation specified in 'append_args' clause, expected 'interop'">;
def err_omp_declare_variant_wrong_clause : Error<
- "expected %select{'match'|'match' or 'adjust_args'}0 clause on "
- "'omp declare variant' directive">;
+ "expected %select{'match'|'match', 'adjust_args', or 'append_args'}0 clause "
+ "on 'omp declare variant' directive">;
def err_omp_declare_variant_duplicate_nested_trait : Error<
"nested OpenMP context selector contains duplicated trait '%0'"
" in selector '%1' and set '%2' with
diff erent score">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7cee98c8a64c..370ccd01ee8e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10747,9 +10747,14 @@ def err_omp_declare_variant_
diff : Error<
"function with '#pragma omp declare variant' has a
diff erent %select{calling convention"
"|return type|constexpr specification|inline specification|storage class|"
"linkage}0">;
+def err_omp_declare_variant_prototype_required : Error<
+ "function with '#pragma omp declare variant' must have a prototype when "
+ "'append_args' is used">;
+def err_omp_interop_type_not_found : Error<
+ "'omp_interop_t' must be defined when 'append_args' clause is used; include <omp.h>">;
def err_omp_declare_variant_incompat_types : Error<
- "variant in '#pragma omp declare variant' with type %0 is incompatible with type %1"
- >;
+ "variant in '#pragma omp declare variant' with type %0 is incompatible with"
+ " type %1%select{| with appended arguments}2">;
def warn_omp_declare_variant_marked_as_declare_variant : Warning<
"variant function in '#pragma omp declare variant' is itself marked as '#pragma omp declare variant'"
>, InGroup<SourceUsesOpenMP>;
@@ -10818,6 +10823,8 @@ def err_omp_adjust_arg_multiple_clauses : Error<
"'adjust_arg' argument %0 used in multiple clauses">;
def err_omp_clause_requires_dispatch_construct : Error<
"'%0' clause requires 'dispatch' context selector">;
+def err_omp_append_args_with_varargs : Error<
+ "'append_args' is not allowed with varargs functions">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 62c0a0d4c0a8..92a703b42173 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -3205,6 +3205,10 @@ class Parser : public CodeCompletionHandler {
/// Parses OpenMP context selectors.
bool parseOMPContextSelectors(SourceLocation Loc, OMPTraitInfo &TI);
+ /// Parse an 'append_args' clause for '#pragma omp declare variant'.
+ bool parseOpenMPAppendArgs(
+ SmallVectorImpl<OMPDeclareVariantAttr::InteropType> &InterOpTypes);
+
/// Parse a `match` clause for an '#pragma omp declare variant'. Return true
/// if there was an error.
bool parseOMPDeclareVariantMatchClause(SourceLocation Loc, OMPTraitInfo &TI,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4d5f9919ce9e..c3d7c14f53d3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -10964,11 +10964,14 @@ class Sema final {
/// \param VariantRef Expression that references the variant function, which
/// must be used instead of the original one, specified in \p DG.
/// \param TI The trait info object representing the match clause.
+ /// \param NumAppendArgs The number of omp_interop_t arguments to account for
+ /// in checking.
/// \returns None, if the function/variant function are not compatible with
/// the pragma, pair of original function/variant ref expression otherwise.
Optional<std::pair<FunctionDecl *, Expr *>>
checkOpenMPDeclareVariantFunction(DeclGroupPtrTy DG, Expr *VariantRef,
- OMPTraitInfo &TI, SourceRange SR);
+ OMPTraitInfo &TI, unsigned NumAppendArgs,
+ SourceRange SR);
/// Called on well-formed '\#pragma omp declare variant' after parsing of
/// the associated method/function.
@@ -10977,10 +10980,19 @@ class Sema final {
/// \param VariantRef Expression that references the variant function, which
/// must be used instead of the original one, specified in \p DG.
/// \param TI The context traits associated with the function variant.
+ /// \param AdjustArgsNothing The list of 'nothing' arguments.
+ /// \param AdjustArgsNeedDevicePtr The list of 'need_device_ptr' arguments.
+ /// \param AppendArgs The list of 'append_args' arguments.
+ /// \param AdjustArgsLoc The Location of an 'adjust_args' clause.
+ /// \param AppendArgsLoc The Location of an 'append_args' clause.
+ /// \param SR The SourceRange of the 'declare variant' directive.
void ActOnOpenMPDeclareVariantDirective(
FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI,
ArrayRef<Expr *> AdjustArgsNothing,
- ArrayRef<Expr *> AdjustArgsNeedDevicePtr, SourceRange SR);
+ ArrayRef<Expr *> AdjustArgsNeedDevicePtr,
+ ArrayRef<OMPDeclareVariantAttr::InteropType> AppendArgs,
+ SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc,
+ SourceRange SR);
OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
Expr *Expr,
diff --git a/clang/lib/AST/AttrImpl.cpp b/clang/lib/AST/AttrImpl.cpp
index e7b9828b4e34..a3b46752c511 100644
--- a/clang/lib/AST/AttrImpl.cpp
+++ b/clang/lib/AST/AttrImpl.cpp
@@ -214,6 +214,21 @@ void OMPDeclareVariantAttr::printPrettyPragma(
PrintExprs(adjustArgsNeedDevicePtr_begin(), adjustArgsNeedDevicePtr_end());
OS << ")";
}
+
+ auto PrintInteropTypes = [&OS](InteropType *Begin, InteropType *End) {
+ for (InteropType *I = Begin; I != End; ++I) {
+ if (I != Begin)
+ OS << ", ";
+ OS << "interop(";
+ OS << ConvertInteropTypeToStr(*I);
+ OS << ")";
+ }
+ };
+ if (appendArgs_size()) {
+ OS << " append_args(";
+ PrintInteropTypes(appendArgs_begin(), appendArgs_end());
+ OS << ")";
+ }
}
#include "clang/AST/AttrImpl.inc"
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 4c209fb9cf6f..d9ddb7ea0fc3 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -191,6 +191,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, StringRef Str,
case OMPC_uses_allocators:
case OMPC_affinity:
case OMPC_when:
+ case OMPC_append_args:
break;
default:
break;
@@ -445,6 +446,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_uses_allocators:
case OMPC_affinity:
case OMPC_when:
+ case OMPC_append_args:
break;
default:
break;
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 8ae45cae2d43..a3b509f91414 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -5990,6 +5990,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_filter:
case OMPC_when:
case OMPC_adjust_args:
+ case OMPC_append_args:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 68683b0f2bd9..d38e088a4706 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -1404,6 +1404,8 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
OMPTraitInfo &TI = ASTCtx.getNewOMPTraitInfo();
SmallVector<Expr *, 6> AdjustNothing;
SmallVector<Expr *, 6> AdjustNeedDevicePtr;
+ SmallVector<OMPDeclareVariantAttr::InteropType, 3> AppendArgs;
+ SourceLocation AdjustArgsLoc, AppendArgsLoc;
// At least one clause is required.
if (Tok.is(tok::annot_pragma_openmp_end)) {
@@ -1428,6 +1430,7 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
IsError = parseOMPDeclareVariantMatchClause(Loc, TI, ParentTI);
break;
case OMPC_adjust_args: {
+ AdjustArgsLoc = Tok.getLocation();
ConsumeToken();
Parser::OpenMPVarListDataTy Data;
SmallVector<Expr *> Vars;
@@ -1440,6 +1443,19 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
Vars);
break;
}
+ case OMPC_append_args:
+ if (!AppendArgs.empty()) {
+ Diag(AppendArgsLoc, diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(OMPD_declare_variant)
+ << getOpenMPClauseName(CKind) << 0;
+ IsError = true;
+ }
+ if (!IsError) {
+ AppendArgsLoc = Tok.getLocation();
+ ConsumeToken();
+ IsError = parseOpenMPAppendArgs(AppendArgs);
+ }
+ break;
default:
llvm_unreachable("Unexpected clause for declare variant.");
}
@@ -1458,18 +1474,106 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr,
Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
Actions.checkOpenMPDeclareVariantFunction(
- Ptr, AssociatedFunction.get(), TI,
+ Ptr, AssociatedFunction.get(), TI, AppendArgs.size(),
SourceRange(Loc, Tok.getLocation()));
if (DeclVarData && !TI.Sets.empty())
Actions.ActOnOpenMPDeclareVariantDirective(
DeclVarData->first, DeclVarData->second, TI, AdjustNothing,
- AdjustNeedDevicePtr, SourceRange(Loc, Tok.getLocation()));
+ AdjustNeedDevicePtr, AppendArgs, AdjustArgsLoc, AppendArgsLoc,
+ SourceRange(Loc, Tok.getLocation()));
// Skip the last annot_pragma_openmp_end.
(void)ConsumeAnnotationToken();
}
+/// Parse a list of interop-types. These are 'target' and 'targetsync'. Both
+/// are allowed but duplication of either is not meaningful.
+static Optional<OMPDeclareVariantAttr::InteropType>
+parseInteropTypeList(Parser &P) {
+ const Token &Tok = P.getCurToken();
+ bool HasError = false;
+ bool IsTarget = false;
+ bool IsTargetSync = false;
+
+ while (Tok.is(tok::identifier)) {
+ 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
+ // once.
+ if (IsTarget)
+ P.Diag(Tok, diag::warn_omp_more_one_interop_type) << "target";
+ IsTarget = true;
+ } else if (Tok.getIdentifierInfo()->isStr("targetsync")) {
+ if (IsTargetSync)
+ P.Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync";
+ IsTargetSync = true;
+ } else {
+ HasError = true;
+ P.Diag(Tok, diag::err_omp_expected_interop_type);
+ }
+ P.ConsumeToken();
+
+ if (!Tok.is(tok::comma))
+ break;
+ P.ConsumeToken();
+ }
+ if (HasError)
+ return None;
+
+ if (!IsTarget && !IsTargetSync) {
+ P.Diag(Tok, diag::err_omp_expected_interop_type);
+ return None;
+ }
+
+ // As of OpenMP 5.1,there are two interop-types, "target" and
+ // "targetsync". Either or both are allowed for a single interop.
+ if (IsTarget && IsTargetSync)
+ return OMPDeclareVariantAttr::Target_TargetSync;
+ if (IsTarget)
+ return OMPDeclareVariantAttr::Target;
+ return OMPDeclareVariantAttr::TargetSync;
+}
+
+bool Parser::parseOpenMPAppendArgs(
+ SmallVectorImpl<OMPDeclareVariantAttr::InteropType> &InterOpTypes) {
+ bool HasError = false;
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after,
+ getOpenMPClauseName(OMPC_append_args).data()))
+ return true;
+
+ // Parse the list of append-ops, each is;
+ // interop(interop-type[,interop-type]...)
+ while (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("interop")) {
+ ConsumeToken();
+ BalancedDelimiterTracker IT(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ if (IT.expectAndConsume(diag::err_expected_lparen_after, "interop"))
+ return true;
+
+ // Parse the interop-types.
+ if (Optional<OMPDeclareVariantAttr::InteropType> IType =
+ parseInteropTypeList(*this))
+ InterOpTypes.push_back(IType.getValue());
+ else
+ HasError = true;
+
+ IT.consumeClose();
+ if (Tok.is(tok::comma))
+ ConsumeToken();
+ }
+ if (!HasError && InterOpTypes.empty()) {
+ HasError = true;
+ Diag(Tok.getLocation(), diag::err_omp_unexpected_append_op);
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ }
+ HasError = T.consumeClose() || HasError;
+ return HasError;
+}
+
bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc,
OMPTraitInfo &TI,
OMPTraitInfo *ParentTI) {
@@ -3342,36 +3446,15 @@ OMPClause *Parser::ParseOpenMPInteropClause(OpenMPClauseKind Kind,
}
// Parse the interop-types.
- bool HasError = false;
- while (Tok.is(tok::identifier)) {
- if (PP.getSpelling(Tok) == "target") {
- // OpenMP 5.1 [2.15.1, interop Construct, Restrictions]
- // Each interop-type may be specified on an action-clause at most
- // once.
- if (IsTarget)
- Diag(Tok, diag::warn_omp_more_one_interop_type) << "target";
- IsTarget = true;
- } else if (PP.getSpelling(Tok) == "targetsync") {
- if (IsTargetSync)
- Diag(Tok, diag::warn_omp_more_one_interop_type) << "targetsync";
- IsTargetSync = true;
- } else {
- HasError = true;
- Diag(Tok, diag::err_omp_expected_interop_type);
- }
- ConsumeToken();
-
- if (!Tok.is(tok::comma))
- break;
- ConsumeToken();
+ if (Optional<OMPDeclareVariantAttr::InteropType> IType =
+ parseInteropTypeList(*this)) {
+ IsTarget = IType != OMPDeclareVariantAttr::TargetSync;
+ IsTargetSync = IType != OMPDeclareVariantAttr::Target;
+ if (Tok.isNot(tok::colon))
+ Diag(Tok, diag::warn_pragma_expected_colon) << "interop types";
}
- if (!HasError && !IsTarget && !IsTargetSync)
- Diag(Tok, diag::err_omp_expected_interop_type);
-
if (Tok.is(tok::colon))
ConsumeToken();
- else if (IsTarget || IsTargetSync)
- Diag(Tok, diag::warn_pragma_expected_colon) << "interop types";
}
// Parse the variable.
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index ccd17fc5102d..3ee913206457 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6803,7 +6803,8 @@ void Sema::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(
auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit(
Context, VariantFuncRef, DVScope.TI,
/*NothingArgs=*/nullptr, /*NothingArgsSize=*/0,
- /*NeedDevicePtrArgs=*/nullptr, /*NeedDevicePtrArgsSize=*/0);
+ /*NeedDevicePtrArgs=*/nullptr, /*NeedDevicePtrArgsSize=*/0,
+ /*AppendArgs=*/nullptr, /*AppendArgsSize=*/0);
for (FunctionDecl *BaseFD : Bases)
BaseFD->addAttr(OMPDeclareVariantA);
}
@@ -6917,6 +6918,7 @@ ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
Optional<std::pair<FunctionDecl *, Expr *>>
Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
Expr *VariantRef, OMPTraitInfo &TI,
+ unsigned NumAppendArgs,
SourceRange SR) {
if (!DG || DG.get().isNull())
return None;
@@ -7004,6 +7006,39 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions))
return None;
+ QualType AdjustedFnType = FD->getType();
+ if (NumAppendArgs) {
+ if (isa<FunctionNoProtoType>(FD->getType())) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_prototype_required)
+ << SR;
+ return None;
+ }
+ // Adjust the function type to account for an extra omp_interop_t for each
+ // specified in the append_args clause.
+ const TypeDecl *TD = nullptr;
+ LookupResult Result(*this, &Context.Idents.get("omp_interop_t"),
+ SR.getBegin(), Sema::LookupOrdinaryName);
+ if (LookupName(Result, getCurScope())) {
+ NamedDecl *ND = Result.getFoundDecl();
+ TD = dyn_cast_or_null<TypeDecl>(ND);
+ }
+ if (!TD) {
+ Diag(SR.getBegin(), diag::err_omp_interop_type_not_found) << SR;
+ return None;
+ }
+ QualType InteropType = QualType(TD->getTypeForDecl(), 0);
+ auto *PTy = cast<FunctionProtoType>(FD->getType());
+ if (PTy->isVariadic()) {
+ Diag(FD->getLocation(), diag::err_omp_append_args_with_varargs) << SR;
+ return None;
+ }
+ llvm::SmallVector<QualType, 8> Params;
+ Params.append(PTy->param_type_begin(), PTy->param_type_end());
+ Params.insert(Params.end(), NumAppendArgs, InteropType);
+ AdjustedFnType = Context.getFunctionType(PTy->getReturnType(), Params,
+ PTy->getExtProtoInfo());
+ }
+
// Convert VariantRef expression to the type of the original function to
// resolve possible conflicts.
ExprResult VariantRefCast = VariantRef;
@@ -7013,7 +7048,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
if (Method && !Method->isStatic()) {
const Type *ClassType =
Context.getTypeDeclType(Method->getParent()).getTypePtr();
- FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType);
+ FnPtrType = Context.getMemberPointerType(AdjustedFnType, ClassType);
ExprResult ER;
{
// Build adrr_of unary op to correctly handle type checks for member
@@ -7029,7 +7064,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
}
VariantRef = ER.get();
} else {
- FnPtrType = Context.getPointerType(FD->getType());
+ FnPtrType = Context.getPointerType(AdjustedFnType);
}
QualType VarianPtrType = Context.getPointerType(VariantRef->getType());
if (VarianPtrType.getUnqualifiedType() != FnPtrType.getUnqualifiedType()) {
@@ -7044,7 +7079,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
diag::err_omp_declare_variant_incompat_types)
<< VariantRef->getType()
<< ((Method && !Method->isStatic()) ? FnPtrType : FD->getType())
- << VariantRef->getSourceRange();
+ << (NumAppendArgs ? 1 : 0) << VariantRef->getSourceRange();
return None;
}
VariantRefCast = PerformImplicitConversion(
@@ -7086,11 +7121,12 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
// Check if function types are compatible in C.
if (!LangOpts.CPlusPlus) {
QualType NewType =
- Context.mergeFunctionTypes(FD->getType(), NewFD->getType());
+ Context.mergeFunctionTypes(AdjustedFnType, NewFD->getType());
if (NewType.isNull()) {
Diag(VariantRef->getExprLoc(),
diag::err_omp_declare_variant_incompat_types)
- << NewFD->getType() << FD->getType() << VariantRef->getSourceRange();
+ << NewFD->getType() << FD->getType() << (NumAppendArgs ? 1 : 0)
+ << VariantRef->getSourceRange();
return None;
}
if (NewType->isFunctionProtoType()) {
@@ -7179,7 +7215,10 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
void Sema::ActOnOpenMPDeclareVariantDirective(
FunctionDecl *FD, Expr *VariantRef, OMPTraitInfo &TI,
ArrayRef<Expr *> AdjustArgsNothing,
- ArrayRef<Expr *> AdjustArgsNeedDevicePtr, SourceRange SR) {
+ ArrayRef<Expr *> AdjustArgsNeedDevicePtr,
+ ArrayRef<OMPDeclareVariantAttr::InteropType> AppendArgs,
+ SourceLocation AdjustArgsLoc, SourceLocation AppendArgsLoc,
+ SourceRange SR) {
// OpenMP 5.1 [2.3.5, declare variant directive, Restrictions]
// An adjust_args clause or append_args clause can only be specified if the
@@ -7190,15 +7229,18 @@ void Sema::ActOnOpenMPDeclareVariantDirective(
llvm::append_range(AllAdjustArgs, AdjustArgsNothing);
llvm::append_range(AllAdjustArgs, AdjustArgsNeedDevicePtr);
- if (!AllAdjustArgs.empty()) {
+ if (!AllAdjustArgs.empty() || !AppendArgs.empty()) {
VariantMatchInfo VMI;
TI.getAsVariantMatchInfo(Context, VMI);
if (!llvm::is_contained(
VMI.ConstructTraits,
llvm::omp::TraitProperty::construct_dispatch_dispatch)) {
- Diag(AllAdjustArgs[0]->getExprLoc(),
- diag::err_omp_clause_requires_dispatch_construct)
- << getOpenMPClauseName(OMPC_adjust_args);
+ if (!AllAdjustArgs.empty())
+ Diag(AdjustArgsLoc, diag::err_omp_clause_requires_dispatch_construct)
+ << getOpenMPClauseName(OMPC_adjust_args);
+ if (!AppendArgs.empty())
+ Diag(AppendArgsLoc, diag::err_omp_clause_requires_dispatch_construct)
+ << getOpenMPClauseName(OMPC_append_args);
return;
}
}
@@ -7235,7 +7277,9 @@ void Sema::ActOnOpenMPDeclareVariantDirective(
Context, VariantRef, &TI, const_cast<Expr **>(AdjustArgsNothing.data()),
AdjustArgsNothing.size(),
const_cast<Expr **>(AdjustArgsNeedDevicePtr.data()),
- AdjustArgsNeedDevicePtr.size(), SR);
+ AdjustArgsNeedDevicePtr.size(),
+ const_cast<OMPDeclareVariantAttr::InteropType *>(AppendArgs.data()),
+ AppendArgs.size(), SR);
FD->addAttr(NewAttr);
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 5ddac3c98c25..7142e6ae56bb 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -441,6 +441,7 @@ static void instantiateOMPDeclareVariantAttr(
// begin declare variant` (which use implicit attributes).
Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData =
S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), E, TI,
+ Attr.appendArgs_size(),
Attr.getRange());
if (!DeclVarData)
@@ -483,6 +484,8 @@ static void instantiateOMPDeclareVariantAttr(
SmallVector<Expr *, 8> NothingExprs;
SmallVector<Expr *, 8> NeedDevicePtrExprs;
+ SmallVector<OMPDeclareVariantAttr::InteropType, 8> AppendArgs;
+
for (Expr *E : Attr.adjustArgsNothing()) {
ExprResult ER = Subst(E);
if (ER.isInvalid())
@@ -495,8 +498,12 @@ static void instantiateOMPDeclareVariantAttr(
continue;
NeedDevicePtrExprs.push_back(ER.get());
}
- S.ActOnOpenMPDeclareVariantDirective(FD, E, TI, NothingExprs,
- NeedDevicePtrExprs, Attr.getRange());
+ for (auto A : Attr.appendArgs())
+ AppendArgs.push_back(A);
+
+ S.ActOnOpenMPDeclareVariantDirective(
+ FD, E, TI, NothingExprs, NeedDevicePtrExprs, AppendArgs, SourceLocation(),
+ SourceLocation(), Attr.getRange());
}
static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
diff --git a/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp b/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp
index 2644842651dd..9d3785c2f16b 100644
--- a/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp
+++ b/clang/test/OpenMP/declare_variant_clauses_ast_print.cpp
@@ -104,4 +104,82 @@ void func()
Foo(A, B);
}
+typedef void *omp_interop_t;
+
+void bar_v1(float* F1, float *F2, omp_interop_t);
+void bar_v2(float* F1, float *F2, omp_interop_t, omp_interop_t);
+
+//PRINT: #pragma omp declare variant(bar_v1) match(construct={dispatch}) append_args(interop(target,targetsync))
+//DUMP: FunctionDecl{{.*}}bar1 'void (float *, float *)'
+//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} Target_TargetSync
+//DUMP: DeclRefExpr{{.*}}bar_v1
+#pragma omp declare variant(bar_v1) match(construct={dispatch}) \
+ append_args(interop(target,targetsync))
+void bar1(float *FF1, float *FF2) { return; }
+
+//PRINT: #pragma omp declare variant(bar_v1) match(construct={dispatch}) append_args(interop(targetsync))
+//DUMP: FunctionDecl{{.*}}bar2 'void (float *, float *)'
+//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} TargetSync
+//DUMP: DeclRefExpr{{.*}}bar_v1
+#pragma omp declare variant(bar_v1) match(construct={dispatch}) \
+ append_args(interop(targetsync))
+void bar2(float *FF1, float *FF2) { return; }
+
+//PRINT: #pragma omp declare variant(bar_v1) match(construct={dispatch}) append_args(interop(target))
+//DUMP: FunctionDecl{{.*}}bar3 'void (float *, float *)'
+//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} Target
+//DUMP: DeclRefExpr{{.*}}bar_v1
+#pragma omp declare variant(bar_v1) match(construct={dispatch}) \
+ append_args(interop(target))
+void bar3(float *FF1, float *FF2) { return; }
+
+//PRINT: #pragma omp declare variant(bar_v2) match(construct={dispatch}) append_args(interop(target), interop(targetsync))
+//DUMP: FunctionDecl{{.*}}bar4 'void (float *, float *)'
+//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} Target TargetSync
+//DUMP: DeclRefExpr{{.*}}bar_v2
+#pragma omp declare variant(bar_v2) match(construct={dispatch}) \
+ append_args(interop(target), interop(targetsync))
+void bar4(float *FF1, float *FF2) { return; }
+
+//PRINT: #pragma omp declare variant(bar_v2) match(construct={dispatch}) append_args(interop(targetsync), interop(target))
+//DUMP: FunctionDecl{{.*}}bar5 'void (float *, float *)'
+//DUMP: OMPDeclareVariantAttr{{.*}}construct={dispatch} TargetSync Target
+//DUMP: DeclRefExpr{{.*}}bar_v2
+#pragma omp declare variant(bar_v2) match(construct={dispatch}) \
+ append_args(interop(targetsync), interop(target))
+void bar5(float *FF1, float *FF2) { return; }
+
+//PRINT: class A {
+//DUMP: CXXRecordDecl{{.*}}class A definition
+class A {
+public:
+ void memberfoo_v1(float *A, float *B, int *I, omp_interop_t IOp);
+ //PRINT: #pragma omp declare variant(memberfoo_v1) match(construct={dispatch}) append_args(interop(target))
+ //DUMP: CXXMethodDecl{{.*}}memberbar 'void (float *, float *, int *)'
+ //DUMP: OMPDeclareVariantAttr{{.*}}Implicit construct={dispatch} Target
+ //DUMP: DeclRefExpr{{.*}}'memberfoo_v1' 'void (float *, float *, int *, omp_interop_t)'
+ #pragma omp declare variant(memberfoo_v1) match(construct={dispatch}) \
+ append_args(interop(target))
+ void memberbar(float *A, float *B, int *I) { return; }
+
+ static void smemberfoo_v1(float *A, float *B, int *I, omp_interop_t IOp);
+ //PRINT: #pragma omp declare variant(smemberfoo_v1) match(construct={dispatch}) append_args(interop(target))
+ //DUMP: CXXMethodDecl{{.*}}smemberbar 'void (float *, float *, int *)' static
+ //DUMP: OMPDeclareVariantAttr{{.*}}Implicit construct={dispatch} Target
+ //DUMP: DeclRefExpr{{.*}}'smemberfoo_v1' 'void (float *, float *, int *, omp_interop_t)'
+ #pragma omp declare variant(smemberfoo_v1) match(construct={dispatch}) \
+ append_args(interop(target))
+ static void smemberbar(float *A, float *B, int *I) { return; }
+};
+
+template <typename T> void templatefoo_v1(const T& t, omp_interop_t I);
+template <typename T> void templatebar(const T& t) {}
+
+//PRINT: #pragma omp declare variant(templatefoo_v1<int>) match(construct={dispatch}) append_args(interop(target))
+//DUMP: FunctionDecl{{.*}}templatebar 'void (const int &)'
+//DUMP: OMPDeclareVariantAttr{{.*}}Implicit construct={dispatch} Target
+//DUMP: DeclRefExpr{{.*}}'templatefoo_v1' 'void (const int &, omp_interop_t)'
+#pragma omp declare variant(templatefoo_v1<int>) match(construct={dispatch}) \
+ append_args(interop(target))
+void templatebar(const int &t) {}
#endif // HEADER
diff --git a/clang/test/OpenMP/declare_variant_clauses_messages.cpp b/clang/test/OpenMP/declare_variant_clauses_messages.cpp
index 6d68e68b02a0..648a1c1201c4 100644
--- a/clang/test/OpenMP/declare_variant_clauses_messages.cpp
+++ b/clang/test/OpenMP/declare_variant_clauses_messages.cpp
@@ -1,14 +1,107 @@
// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -DOMP51 -std=c++11 -o - %s
-
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -DOMP51 -std=c++11 \
+// RUN: -DNO_INTEROP_T_DEF -o - %s
// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 -DOMP50 -std=c++11 -o - %s
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -DOMP51 -DC -x c -o - %s
+
+#ifdef NO_INTEROP_T_DEF
+void foo_v1(float *, void *);
+// expected-error at +1 {{'omp_interop_t' must be defined when 'append_args' clause is used; include <omp.h>}}
+#pragma omp declare variant(foo_v1) append_args(interop(target)) \
+ match(construct={dispatch})
+void foo_v1(float *);
+#else
+typedef void *omp_interop_t;
int Other;
+#ifdef OMP51
+#ifdef __cplusplus
+class A {
+public:
+ void memberfoo_v0(float *A, float *B, int *I);
+ void memberfoo_v1(float *A, float *B, int *I, omp_interop_t IOp);
+
+ // expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (A::*)(float *, float *, int *)' is incompatible with type 'void (A::*)(float *, float *, int *, omp_interop_t)' with appended arguments}}
+ #pragma omp declare variant(memberfoo_v0) match(construct={dispatch}) \
+ append_args(interop(target))
+
+ // expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (A::*)(float *, float *, int *, omp_interop_t)' is incompatible with type 'void (A::*)(float *, float *, int *, omp_interop_t, omp_interop_t)' with appended arguments}}
+ #pragma omp declare variant(memberfoo_v1) match(construct={dispatch}) \
+ append_args(interop(target),interop(target))
+ void memberbar(float *A, float *B, int *I) { return; }
+
+ static void smemberfoo_v0(float *A, float *B, int *I);
+ static void smemberfoo_v1(float *A, float *B, int *I, omp_interop_t IOp);
+
+ // expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *)' is incompatible with type 'void (float *, float *, int *)' with appended arguments}}
+ #pragma omp declare variant(smemberfoo_v0) match(construct={dispatch}) \
+ append_args(interop(target))
+
+ // expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *, omp_interop_t)' (aka 'void (float *, float *, int *, void *)') is incompatible with type 'void (float *, float *, int *)' with appended arguments}}
+ #pragma omp declare variant(smemberfoo_v1) match(construct={dispatch}) \
+ append_args(interop(target),interop(target))
+ static void smemberbar(float *A, float *B, int *I) { return; }
+
+ virtual void vmemberfoo_v0(float *A, float *B, int *I);
+ virtual void vmemberfoo_v1(float *A, float *B, int *I, omp_interop_t IOp);
+
+ // expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (A::*)(float *, float *, int *)' is incompatible with type 'void (A::*)(float *, float *, int *, omp_interop_t)' with appended arguments}}
+ #pragma omp declare variant(vmemberfoo_v0) match(construct={dispatch}) \
+ append_args(interop(target))
+
+ #pragma omp declare variant(vmemberfoo_v1) match(construct={dispatch}) \
+ append_args(interop(target))
+
+ // expected-error at +1 {{'#pragma omp declare variant' does not support virtual functions}}
+ virtual void vmemberbar(float *A, float *B, int *I) { return; }
+
+ virtual void pvmemberfoo_v0(float *A, float *B, int *I) = 0;
+ virtual void pvmemberfoo_v1(float *A, float *B, int *I, omp_interop_t IOp) = 0;
+
+ // expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (A::*)(float *, float *, int *)' is incompatible with type 'void (A::*)(float *, float *, int *, omp_interop_t)' with appended arguments}}
+ #pragma omp declare variant(pvmemberfoo_v0) match(construct={dispatch}) \
+ append_args(interop(target))
+
+ #pragma omp declare variant(pvmemberfoo_v1) match(construct={dispatch}) \
+ append_args(interop(target))
+
+ // expected-error at +1 {{'#pragma omp declare variant' does not support virtual functions}}
+ virtual void pvmemberbar(float *A, float *B, int *I) = 0;
+};
+
+template <typename T> void templatefoo_v0(const T& t);
+template <typename T> void templatefoo_v1(const T& t, omp_interop_t I);
+template <typename T> void templatebar(const T& t) {}
+
+// expected-error at +1 {{variant in '#pragma omp declare variant' with type '<overloaded function type>' is incompatible with type 'void (const int &)' with appended arguments}}
+#pragma omp declare variant(templatefoo_v0<int>) match(construct={dispatch}) \
+ append_args(interop(target))
+
+// expected-error at +1 {{variant in '#pragma omp declare variant' with type '<overloaded function type>' is incompatible with type 'void (const int &)' with appended arguments}}
+#pragma omp declare variant(templatefoo_v1<int>) match(construct={dispatch}) \
+ append_args(interop(target),interop(target))
+void templatebar(const int &t) {}
+#endif // __cplusplus
+#endif // OMP51
+
void foo_v1(float *AAA, float *BBB, int *I) { return; }
void foo_v2(float *AAA, float *BBB, int *I) { return; }
void foo_v3(float *AAA, float *BBB, int *I) { return; }
+void foo_v4(float *AAA, float *BBB, int *I, omp_interop_t IOp) { return; }
#ifdef OMP51
+void vararg_foo(const char *fmt, omp_interop_t it, ...);
+// expected-error at +3 {{'append_args' is not allowed with varargs functions}}
+#pragma omp declare variant(vararg_foo) match(construct={dispatch}) \
+ append_args(interop(target))
+void vararg_bar(const char *fmt, ...) { return; }
+
+// expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (const char *, omp_interop_t, ...)' (aka 'void (const char *, void *, ...)') is incompatible with type 'void (const char *)' with appended arguments}}
+#pragma omp declare variant(vararg_foo) match(construct={dispatch}) \
+ append_args(interop(target))
+void vararg_bar2(const char *fmt) { return; }
+
// expected-error at +3 {{'adjust_arg' argument 'AAA' used in multiple clauses}}
#pragma omp declare variant(foo_v1) \
match(construct={dispatch}, device={arch(arm)}) \
@@ -36,12 +129,79 @@ void foo_v3(float *AAA, float *BBB, int *I) { return; }
// expected-error at +2 {{'adjust_args' clause requires 'dispatch' context selector}}
#pragma omp declare variant(foo_v3) \
adjust_args(nothing:BBB) match(device={arch(ppc)})
+
+// expected-error at +1 {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
+#pragma omp declare variant(foo_v1)
+
+// expected-error at +1 {{expected 'match', 'adjust_args', or 'append_args' clause on 'omp declare variant' directive}}
+#pragma omp declare variant(foo_v1) other
+
+// expected-error at +2 {{unexpected operation specified in 'append_args' clause, expected 'interop'}}
+#pragma omp declare variant(foo_v1) match(construct={dispatch}) \
+ append_args(foobar(target))
+
+// expected-error at +2 {{directive '#pragma omp declare variant' cannot contain more than one 'append_args' clause}}
+#pragma omp declare variant(foo_v1) match(construct={dispatch}) \
+ append_args(interop(target)) \
+ append_args(interop(targetsync))
+
+// expected-error at +2 {{'append_args' clause requires 'dispatch' context selector}}
+#pragma omp declare variant(foo_v4) \
+ append_args(interop(target)) match(construct={target})
+
+// expected-error at +2 {{'append_args' clause requires 'dispatch' context selector}}
+#pragma omp declare variant(foo_v4) \
+ match(construct={target}) append_args(interop(target))
+
+// expected-warning at +2 {{interop type 'target' cannot be specified more than once}}
+#pragma omp declare variant(foo_v4) match(construct={dispatch}) \
+ append_args(interop(target,target))
+
+// expected-warning at +2 {{interop type 'targetsync' cannot be specified more than once}}
+#pragma omp declare variant(foo_v4) match(construct={dispatch}) \
+ append_args(interop(targetsync,targetsync))
+
+// expected-error at +2 {{expected interop type: 'target' and/or 'targetsync'}}
+#pragma omp declare variant(foo_v4) match(construct={dispatch}) \
+ append_args(interop())
+
+// expected-error at +2 {{expected interop type: 'target' and/or 'targetsync'}}
+#pragma omp declare variant(foo_v4) match(construct={dispatch}) \
+ append_args(interop(somethingelse))
+
+// expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *)' is incompatible with type 'void (float *, float *, int *)' with appended arguments}}
+#pragma omp declare variant(foo_v1) match(construct={dispatch}) \
+ append_args(interop(target))
+
+// expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *)' is incompatible with type 'void (float *, float *, int *)' with appended arguments}}
+#pragma omp declare variant(foo_v1) match(construct={dispatch}) \
+ append_args(interop(target),interop(targetsync))
+
+// expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *, omp_interop_t)' (aka 'void (float *, float *, int *, void *)') is incompatible with type 'void (float *, float *, int *)' with appended arguments}}
+#pragma omp declare variant(foo_v4) match(construct={dispatch}) \
+ append_args(interop(target),interop(targetsync))
+
+// expected-error at +1 {{variant in '#pragma omp declare variant' with type 'void (float *, float *, int *, omp_interop_t)' (aka 'void (float *, float *, int *, void *)') is incompatible with type 'void (float *, float *, int *)'}}
+#pragma omp declare variant(foo_v4) match(construct={dispatch})
+
#endif // OMP51
#ifdef OMP50
// expected-error at +2 {{expected 'match' clause on 'omp declare variant' directive}}
#pragma omp declare variant(foo_v1) \
adjust_args(need_device_ptr:AAA) match(device={arch(arm)})
+// expected-error at +2 {{expected 'match' clause on 'omp declare variant' directive}}
+#pragma omp declare variant(foo_v1) \
+ append_args(interop(target)) match(device={arch(arm)})
#endif // OMP50
void foo(float *AAA, float *BBB, int *I) { return; }
+#endif // NO_INTEROP_T_DEF
+
+#ifdef C
+void c_variant(omp_interop_t);
+// expected-error at +3 {{function with '#pragma omp declare variant' must have a prototype when 'append_args' is used}}
+#pragma omp declare variant(foo_v1) \
+ append_args(interop(target)) match(construct={dispatch})
+void c_base() {}
+#endif
diff --git a/clang/test/OpenMP/declare_variant_messages.cpp b/clang/test/OpenMP/declare_variant_messages.cpp
index b5091dda4fd1..9671df189e31 100644
--- a/clang/test/OpenMP/declare_variant_messages.cpp
+++ b/clang/test/OpenMP/declare_variant_messages.cpp
@@ -278,6 +278,12 @@ struct SpecialFuncs {
void baz();
void bar();
void bar(int);
+ virtual void car();
+ virtual void dar() = 0;
+
+#pragma omp declare variant(SpecialFuncs::car) match(construct={dispatch}) // expected-error {{'#pragma omp declare variant' does not support virtual functions}}
+#pragma omp declare variant(SpecialFuncs::dar) match(construct={dispatch}) // expected-error {{'#pragma omp declare variant' does not support virtual functions}}
+
#pragma omp declare variant(SpecialFuncs::baz) match(implementation = {}) // expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'vendor' 'extension' 'unified_address' 'unified_shared_memory' 'reverse_offload' 'dynamic_allocators' 'atomic_default_mem_order'}} expected-note {{the ignored selector spans until here}}
#pragma omp declare variant(SpecialFuncs::bar) match(xxx = {}) // expected-warning {{'xxx' is not a valid context set in a `declare variant`; set ignored}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}}
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 5e17f7a3b977..d173d679d440 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1478,6 +1478,7 @@ CHECK_SIMPLE_CLAUSE(Nocontext, OMPC_nocontext)
CHECK_SIMPLE_CLAUSE(Filter, OMPC_filter)
CHECK_SIMPLE_CLAUSE(When, OMPC_when)
CHECK_SIMPLE_CLAUSE(AdjustArgs, OMPC_adjust_args)
+CHECK_SIMPLE_CLAUSE(AppendArgs, OMPC_append_args)
CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize)
CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks)
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 67b97d2a64ba..551ed6915162 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -315,6 +315,7 @@ def OMPC_Uniform : Clause<"uniform"> {
def OMPC_DeviceType : Clause<"device_type"> {}
def OMPC_Match : Clause<"match"> {}
def OMPC_AdjustArgs : Clause<"adjust_args"> { }
+def OMPC_AppendArgs : Clause<"append_args"> { }
def OMPC_Depobj : Clause<"depobj"> {
let clangClass = "OMPDepobjClause";
let isImplicit = true;
@@ -1520,7 +1521,8 @@ def OMP_DeclareVariant : Directive<"declare variant"> {
VersionedClause<OMPC_Match>
];
let allowedExclusiveClauses = [
- VersionedClause<OMPC_AdjustArgs, 51>
+ VersionedClause<OMPC_AdjustArgs, 51>,
+ VersionedClause<OMPC_AppendArgs, 51>
];
}
def OMP_MasterTaskloop : Directive<"master taskloop"> {
More information about the flang-commits
mailing list