From 7017afac96411f4c30e10b5a7e7e2d73295f2e2d Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Fri, 13 Sep 2019 20:18:17 +0000 Subject: [PATCH] [OPENMP5.0]Add basic support for declare variant directive. Added basic support for declare variant directive and its match clause with user context selector. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@371892 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 11 +- include/clang/Basic/DiagnosticSemaKinds.td | 27 ++- include/clang/Basic/OpenMPKinds.def | 1 + include/clang/Parse/Parser.h | 7 +- include/clang/Sema/Sema.h | 19 ++ lib/Basic/OpenMPKinds.cpp | 5 +- lib/CodeGen/CGOpenMPRuntime.cpp | 5 + lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp | 4 + lib/Parse/ParseOpenMP.cpp | 126 ++++++++++- lib/Sema/SemaDecl.cpp | 160 +++++++------- lib/Sema/SemaOpenMP.cpp | 213 +++++++++++++++++- test/OpenMP/declare_variant_messages.c | 92 ++++++++ test/OpenMP/declare_variant_messages.cpp | 225 ++++++++++++++++++++ 13 files changed, 804 insertions(+), 91 deletions(-) create mode 100644 test/OpenMP/declare_variant_messages.c create mode 100644 test/OpenMP/declare_variant_messages.cpp diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index a8bc1421ce..66c40c0e9e 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -201,6 +201,7 @@ def err_invalid_token_after_declarator_suggest_equal : Error< "invalid %0 at end of declaration; did you mean '='?">; def err_expected_statement : Error<"expected statement">; def err_expected_lparen_after : Error<"expected '(' after '%0'">; +def err_expected_lbrace_after : Error<"expected '{' after '%0'">; def err_expected_rparen_after : Error<"expected ')' after '%0'">; def err_expected_punc : Error<"expected ')' or ',' after '%0'">; def err_expected_less_after : Error<"expected '<' after '%0'">; @@ -1177,8 +1178,8 @@ def err_omp_expected_identifier_for_critical : Error< "expected identifier specifying the name of the 'omp critical' directive">; def err_omp_expected_reduction_identifier : Error< "expected identifier or one of the following operators: '+', '-', '*', '&', '|', '^', '&&', or '||'">; -def err_omp_decl_in_declare_simd : Error< - "function declaration is expected after 'declare simd' directive">; +def err_omp_decl_in_declare_simd_variant : Error< + "function declaration is expected after 'declare %select{simd|variant}0' directive">; def err_omp_unknown_map_type : Error< "incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">; def err_omp_unknown_map_type_modifier : Error< @@ -1199,6 +1200,12 @@ 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_declare_variant_wrong_clause : Error< + "expected '%0' clause on 'omp declare variant' directive">; +def err_omp_declare_variant_no_ctx_selector : Error< + "expected context selector in '%0' clause on 'omp declare variant' directive">; +def err_omp_declare_variant_equal_expected : Error< + "expected '=' after '%0' context selector set name on 'omp declare variant' directive">; def warn_omp_more_one_device_type_clause : Warning< "more than one 'device_type' clause is specified">, InGroup; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 46af14503e..e55095590f 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -9213,10 +9213,10 @@ def err_omp_single_copyprivate_with_nowait : Error< "the 'copyprivate' clause must not be used with the 'nowait' clause">; def note_omp_nowait_clause_here : Note< "'nowait' clause is here">; -def err_omp_single_decl_in_declare_simd : Error< - "single declaration is expected after 'declare simd' directive">; +def err_omp_single_decl_in_declare_simd_variant : Error< + "single declaration is expected after 'declare %select{simd|variant}0' directive">; def err_omp_function_expected : Error< - "'#pragma omp declare simd' can only be applied to functions">; + "'#pragma omp declare %select{simd|variant}0' can only be applied to functions">; def err_omp_wrong_cancel_region : Error< "one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">; def err_omp_parent_cancel_region_nowait : Error< @@ -9408,6 +9408,27 @@ def note_omp_marked_device_type_here : Note<"marked as 'device_type(%0)' here">; def warn_omp_declare_target_after_first_use : Warning< "declaration marked as declare target after first use, it may lead to incorrect results">, InGroup; +def err_omp_declare_variant_incompat_attributes : Error< + "'#pragma omp declare variant' is not compatible with any target-specific attributes">; +def err_omp_declare_variant_after_used : Error< + "'#pragma omp declare variant' cannot be applied for function after first " + "usage">; +def err_omp_declare_variant_noproto : Error< + "function with '#pragma omp declare variant' must have a prototype">; +def note_omp_declare_variant_specified_here : Note< + "'#pragma omp declare variant' for function specified here">; +def err_omp_declare_variant_doesnt_support : Error< + "'#pragma omp declare variant' does not " + "support %select{function templates|virtual functions|" + "deduced return types|constructors|destructors|deleted functions|" + "defaulted functions|constexpr functions|consteval function}0">; +def err_omp_declare_variant_diff : Error< + "function with '#pragma omp declare variant' has a different %select{calling convention" + "|return type|constexpr specification|inline specification|storage class|" + "linkage}0">; +def err_omp_declare_variant_incompat_types : Error< + "variant in '#pragma omp declare variant' with type %0 is incompatible with type %1" + >; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def index 9a9592a762..05ecc3496f 100644 --- a/include/clang/Basic/OpenMPKinds.def +++ b/include/clang/Basic/OpenMPKinds.def @@ -251,6 +251,7 @@ OPENMP_DIRECTIVE_EXT(target_teams_distribute_parallel_for, "target teams distrib OPENMP_DIRECTIVE_EXT(target_teams_distribute_parallel_for_simd, "target teams distribute parallel for simd") OPENMP_DIRECTIVE_EXT(target_teams_distribute_simd, "target teams distribute simd") OPENMP_DIRECTIVE(allocate) +OPENMP_DIRECTIVE_EXT(declare_variant, "declare variant") // OpenMP clauses. OPENMP_CLAUSE(allocator, OMPAllocatorClause) diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 9e6d0f4e6c..5c0a831db6 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -2834,6 +2834,10 @@ private: DeclGroupPtrTy ParseOMPDeclareSimdClauses(DeclGroupPtrTy Ptr, CachedTokens &Toks, SourceLocation Loc); + /// Parse clauses for '#pragma omp declare variant'. + DeclGroupPtrTy ParseOMPDeclareVariantClauses(DeclGroupPtrTy Ptr, + CachedTokens &Toks, + SourceLocation Loc); /// Parse clauses for '#pragma omp declare target'. DeclGroupPtrTy ParseOMPDeclareTargetClauses(); /// Parse '#pragma omp end declare target'. @@ -2927,7 +2931,8 @@ public: /// Parses simple expression in parens for single-expression clauses of OpenMP /// constructs. /// \param RLoc Returned location of right paren. - ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc); + ExprResult ParseOpenMPParensExpr(StringRef ClauseName, SourceLocation &RLoc, + bool IsAddressOfOperand = false); /// Data used for parsing list of variables in OpenMP clauses. struct OpenMPVarListDataTy { diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 59b1d9c3e4..59fc120b7f 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -9090,6 +9090,15 @@ private: SourceRange SrcRange = SourceRange()); public: + /// Checks if the variant/multiversion functions are compatible. + bool areMultiversionVariantFunctionsCompatible( + const FunctionDecl *OldFD, const FunctionDecl *NewFD, + const PartialDiagnostic &NoProtoDiagID, + const PartialDiagnosticAt &NoteCausedDiagIDAt, + const PartialDiagnosticAt &NoSupportDiagIDAt, + const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported, + bool ConstexprSupported); + /// Function tries to capture lambda's captured variables in the OpenMP region /// before the original lambda is captured. void tryCaptureOpenMPLambdas(ValueDecl *V); @@ -9514,6 +9523,16 @@ public: ArrayRef Alignments, ArrayRef Linears, ArrayRef LinModifiers, ArrayRef Steps, SourceRange SR); + /// Called on well-formed '\#pragma omp declare variant' after parsing of + /// the associated method/function. + /// \param DG Function declaration to which declare variant directive is + /// applied to. + /// \param VariantRef Expression that references the variant function, which + /// must be used instead of the original one, specified in \p DG. + DeclGroupPtrTy ActOnOpenMPDeclareVariantDirective(DeclGroupPtrTy DG, + Expr *VariantRef, + SourceRange SR); + OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 761df3b55d..48590277b9 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -606,8 +606,6 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; } break; - case OMPD_declare_simd: - break; case OMPD_cancel: switch (CKind) { #define OPENMP_CANCEL_CLAUSE(Name) \ @@ -849,6 +847,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_variant: break; } return false; @@ -1078,6 +1078,7 @@ void clang::getOpenMPCaptureRegions( case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_requires: + case OMPD_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 99fa0790e9..45833e1139 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -6770,6 +6770,7 @@ emitNumTeamsForTargetDirective(CodeGenFunction &CGF, case OMPD_teams_distribute_parallel_for_simd: case OMPD_target_update: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -7075,6 +7076,7 @@ emitNumThreadsForTargetDirective(CodeGenFunction &CGF, case OMPD_teams_distribute_parallel_for_simd: case OMPD_target_update: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -8826,6 +8828,7 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) { case OMPD_teams_distribute_parallel_for_simd: case OMPD_target_update: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -9583,6 +9586,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S, case OMPD_teams_distribute_parallel_for_simd: case OMPD_target_update: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -10205,6 +10209,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( case OMPD_teams_distribute_parallel_for: case OMPD_teams_distribute_parallel_for_simd: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: diff --git a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp index 09042b92d8..c6c595dcc2 100644 --- a/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ b/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -795,6 +795,7 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx, case OMPD_teams_distribute_parallel_for_simd: case OMPD_target_update: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -865,6 +866,7 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx, case OMPD_teams_distribute_parallel_for_simd: case OMPD_target_update: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -1028,6 +1030,7 @@ static bool hasNestedLightweightDirective(ASTContext &Ctx, case OMPD_teams_distribute_parallel_for_simd: case OMPD_target_update: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: @@ -1104,6 +1107,7 @@ static bool supportsLightweightRuntime(ASTContext &Ctx, case OMPD_teams_distribute_parallel_for_simd: case OMPD_target_update: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_declare_reduction: diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index 6bd96051f9..293660ec4c 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -42,6 +42,7 @@ enum OpenMPDirectiveKindEx { OMPD_teams_distribute_parallel, OMPD_target_teams_distribute_parallel, OMPD_mapper, + OMPD_variant, }; class DeclDirectiveListParserHelper final { @@ -80,6 +81,7 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) { .Case("reduction", OMPD_reduction) .Case("update", OMPD_update) .Case("mapper", OMPD_mapper) + .Case("variant", OMPD_variant) .Default(OMPD_unknown); } @@ -93,6 +95,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { {OMPD_declare, OMPD_mapper, OMPD_declare_mapper}, {OMPD_declare, OMPD_simd, OMPD_declare_simd}, {OMPD_declare, OMPD_target, OMPD_declare_target}, + {OMPD_declare, OMPD_variant, OMPD_declare_variant}, {OMPD_distribute, OMPD_parallel, OMPD_distribute_parallel}, {OMPD_distribute_parallel, OMPD_for, OMPD_distribute_parallel_for}, {OMPD_distribute_parallel_for, OMPD_simd, @@ -752,6 +755,7 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, /*IsReinject*/ true); // Consume the previously pushed token. ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); FNContextRAII FnContext(*this, Ptr); OMPDeclareSimdDeclAttr::BranchStateTy BS = @@ -782,6 +786,107 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, LinModifiers, Steps, SourceRange(Loc, EndLoc)); } +/// Parses clauses for 'declare variant' directive. +/// clause: +/// 'match' '(' +/// '=' '{' '}' +/// ')' +static bool parseDeclareVariantClause(Parser &P) { + Token Tok = P.getCurToken(); + // Parse 'match'. + if (!Tok.is(tok::identifier) || + P.getPreprocessor().getSpelling(Tok).compare("match")) { + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_wrong_clause) + << "match"; + while (!P.SkipUntil(tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + return true; + } + (void)P.ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, "match")) + return true; + // Parse inner context selector. + Tok = P.getCurToken(); + if (!Tok.is(tok::identifier)) { + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_no_ctx_selector) + << "match"; + return true; + } + SmallString<16> Buffer; + StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); + // Parse '='. + (void)P.ConsumeToken(); + Tok = P.getCurToken(); + if (Tok.isNot(tok::equal)) { + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_equal_expected) + << CtxSelectorName; + return true; + } + (void)P.ConsumeToken(); + // Unknown selector - just ignore it completely. + { + // Parse '{'. + BalancedDelimiterTracker TBr(P, tok::l_brace, tok::annot_pragma_openmp_end); + if (TBr.expectAndConsume(diag::err_expected_lbrace_after, "=")) + return true; + while (!P.SkipUntil(tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + // Parse '}'. + (void)TBr.consumeClose(); + } + // Parse ')'. + (void)T.consumeClose(); + // TBD: add parsing of known context selectors. + return false; +} + +/// Parse clauses for '#pragma omp declare variant ( variant-func-id ) clause'. +Parser::DeclGroupPtrTy +Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, + CachedTokens &Toks, SourceLocation Loc) { + PP.EnterToken(Tok, /*IsReinject*/ true); + PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, + /*IsReinject*/ true); + // Consume the previously pushed token. + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + + FNContextRAII FnContext(*this, Ptr); + // Parse function declaration id. + SourceLocation RLoc; + // Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs + // instead of MemberExprs. + ExprResult AssociatedFunction = + ParseOpenMPParensExpr(getOpenMPDirectiveName(OMPD_declare_variant), RLoc, + /*IsAddressOfOperand=*/true); + if (!AssociatedFunction.isUsable()) { + if (!Tok.is(tok::annot_pragma_openmp_end)) + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + // Skip the last annot_pragma_openmp_end. + (void)ConsumeAnnotationToken(); + return Ptr; + } + + bool IsError = parseDeclareVariantClause(*this); + // Need to check for extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_variant); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + // Skip the last annot_pragma_openmp_end. + SourceLocation EndLoc = ConsumeAnnotationToken(); + if (IsError) + return Ptr; + return Actions.ActOnOpenMPDeclareVariantDirective( + Ptr, AssociatedFunction.get(), SourceRange(Loc, EndLoc)); +} + /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. /// /// default-clause: @@ -1103,13 +1208,15 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( } break; } + case OMPD_declare_variant: case OMPD_declare_simd: { // The syntax is: - // { #pragma omp declare simd } + // { #pragma omp declare {simd|variant} } // // - ConsumeToken(); CachedTokens Toks; + Toks.push_back(Tok); + ConsumeToken(); while(Tok.isNot(tok::annot_pragma_openmp_end)) { Toks.push_back(Tok); ConsumeAnyToken(); @@ -1133,10 +1240,15 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( } } if (!Ptr) { - Diag(Loc, diag::err_omp_decl_in_declare_simd); + Diag(Loc, diag::err_omp_decl_in_declare_simd_variant) + << (DKind == OMPD_declare_simd ? 0 : 1); return DeclGroupPtrTy(); } - return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc); + if (DKind == OMPD_declare_simd) + return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc); + assert(DKind == OMPD_declare_variant && + "Expected declare variant directive only"); + return ParseOMPDeclareVariantClauses(Ptr, Toks, Loc); } case OMPD_declare_target: { SourceLocation DTLoc = ConsumeAnyToken(); @@ -1572,6 +1684,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_requires: + case OMPD_declare_variant: Diag(Tok, diag::err_omp_unexpected_directive) << 1 << getOpenMPDirectiveName(DKind); SkipUntil(tok::annot_pragma_openmp_end); @@ -1831,14 +1944,15 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, /// constructs. /// \param RLoc Returned location of right paren. ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, - SourceLocation &RLoc) { + SourceLocation &RLoc, + bool IsAddressOfOperand) { BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, ClauseName.data())) return ExprError(); SourceLocation ELoc = Tok.getLocation(); ExprResult LHS(ParseCastExpression( - /*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, NotTypeCast)); + /*isUnaryExpression=*/false, IsAddressOfOperand, NotTypeCast)); ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 1290c615c0..dfa5647e9d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -9670,10 +9670,13 @@ static bool HasNonMultiVersionAttributes(const FunctionDecl *FD, return false; } -static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, - const FunctionDecl *NewFD, - bool CausesMV, - MultiVersionKind MVType) { +bool Sema::areMultiversionVariantFunctionsCompatible( + const FunctionDecl *OldFD, const FunctionDecl *NewFD, + const PartialDiagnostic &NoProtoDiagID, + const PartialDiagnosticAt &NoteCausedDiagIDAt, + const PartialDiagnosticAt &NoSupportDiagIDAt, + const PartialDiagnosticAt &DiffDiagIDAt, bool TemplatesSupported, + bool ConstexprSupported) { enum DoesntSupport { FuncTemplates = 0, VirtFuncs = 1, @@ -9691,123 +9694,85 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, ConstexprSpec = 2, InlineSpec = 3, StorageClass = 4, - Linkage = 5 + Linkage = 5, }; - bool IsCPUSpecificCPUDispatchMVType = - MVType == MultiVersionKind::CPUDispatch || - MVType == MultiVersionKind::CPUSpecific; - if (OldFD && !OldFD->getType()->getAs()) { - S.Diag(OldFD->getLocation(), diag::err_multiversion_noproto); - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + Diag(OldFD->getLocation(), NoProtoDiagID); + Diag(NoteCausedDiagIDAt.first, NoteCausedDiagIDAt.second); return true; } if (!NewFD->getType()->getAs()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_noproto); - - if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); - if (OldFD) - S.Diag(OldFD->getLocation(), diag::note_previous_declaration); - return true; - } - - // For now, disallow all other attributes. These should be opt-in, but - // an analysis of all of them is a future FIXME. - if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) { - S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs) - << IsCPUSpecificCPUDispatchMVType; - S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); - return true; - } + return Diag(NewFD->getLocation(), NoProtoDiagID); - if (HasNonMultiVersionAttributes(NewFD, MVType)) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs) - << IsCPUSpecificCPUDispatchMVType; - - if (NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << FuncTemplates; + if (!TemplatesSupported && + NewFD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << FuncTemplates; if (const auto *NewCXXFD = dyn_cast(NewFD)) { if (NewCXXFD->isVirtual()) - return S.Diag(NewCXXFD->getLocation(), - diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << VirtFuncs; + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << VirtFuncs; - if (const auto *NewCXXCtor = dyn_cast(NewFD)) - return S.Diag(NewCXXCtor->getLocation(), - diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << Constructors; + if (isa(NewCXXFD)) + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << Constructors; - if (const auto *NewCXXDtor = dyn_cast(NewFD)) - return S.Diag(NewCXXDtor->getLocation(), - diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << Destructors; + if (isa(NewCXXFD)) + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << Destructors; } if (NewFD->isDeleted()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << DeletedFuncs; + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << DeletedFuncs; if (NewFD->isDefaulted()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << DefaultedFuncs; + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << DefaultedFuncs; - if (NewFD->isConstexpr() && (MVType == MultiVersionKind::CPUDispatch || - MVType == MultiVersionKind::CPUSpecific)) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType + if (!ConstexprSupported && NewFD->isConstexpr()) + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs); - QualType NewQType = S.getASTContext().getCanonicalType(NewFD->getType()); + QualType NewQType = Context.getCanonicalType(NewFD->getType()); const auto *NewType = cast(NewQType); QualType NewReturnType = NewType->getReturnType(); if (NewReturnType->isUndeducedType()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_doesnt_support) - << IsCPUSpecificCPUDispatchMVType << DeducedReturn; - - // Only allow transition to MultiVersion if it hasn't been used. - if (OldFD && CausesMV && OldFD->isUsed(false)) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); + return Diag(NoSupportDiagIDAt.first, NoSupportDiagIDAt.second) + << DeducedReturn; // Ensure the return type is identical. if (OldFD) { - QualType OldQType = S.getASTContext().getCanonicalType(OldFD->getType()); + QualType OldQType = Context.getCanonicalType(OldFD->getType()); const auto *OldType = cast(OldQType); FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << CallingConv; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << CallingConv; QualType OldReturnType = OldType->getReturnType(); if (OldReturnType != NewReturnType) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << ReturnType; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << ReturnType; if (OldFD->getConstexprKind() != NewFD->getConstexprKind()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << ConstexprSpec; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << ConstexprSpec; if (OldFD->isInlineSpecified() != NewFD->isInlineSpecified()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << InlineSpec; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << InlineSpec; if (OldFD->getStorageClass() != NewFD->getStorageClass()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << StorageClass; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << StorageClass; if (OldFD->isExternC() != NewFD->isExternC()) - return S.Diag(NewFD->getLocation(), diag::err_multiversion_diff) - << Linkage; + return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << Linkage; - if (S.CheckEquivalentExceptionSpec( + if (CheckEquivalentExceptionSpec( OldFD->getType()->getAs(), OldFD->getLocation(), NewFD->getType()->getAs(), NewFD->getLocation())) return true; @@ -9815,6 +9780,51 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, return false; } +static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD, + const FunctionDecl *NewFD, + bool CausesMV, + MultiVersionKind MVType) { + if (!S.getASTContext().getTargetInfo().supportsMultiVersioning()) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_not_supported); + if (OldFD) + S.Diag(OldFD->getLocation(), diag::note_previous_declaration); + return true; + } + + bool IsCPUSpecificCPUDispatchMVType = + MVType == MultiVersionKind::CPUDispatch || + MVType == MultiVersionKind::CPUSpecific; + + // For now, disallow all other attributes. These should be opt-in, but + // an analysis of all of them is a future FIXME. + if (CausesMV && OldFD && HasNonMultiVersionAttributes(OldFD, MVType)) { + S.Diag(OldFD->getLocation(), diag::err_multiversion_no_other_attrs) + << IsCPUSpecificCPUDispatchMVType; + S.Diag(NewFD->getLocation(), diag::note_multiversioning_caused_here); + return true; + } + + if (HasNonMultiVersionAttributes(NewFD, MVType)) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_no_other_attrs) + << IsCPUSpecificCPUDispatchMVType; + + // Only allow transition to MultiVersion if it hasn't been used. + if (OldFD && CausesMV && OldFD->isUsed(false)) + return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used); + + return S.areMultiversionVariantFunctionsCompatible( + OldFD, NewFD, S.PDiag(diag::err_multiversion_noproto), + PartialDiagnosticAt(NewFD->getLocation(), + S.PDiag(diag::note_multiversioning_caused_here)), + PartialDiagnosticAt(NewFD->getLocation(), + S.PDiag(diag::err_multiversion_doesnt_support) + << IsCPUSpecificCPUDispatchMVType), + PartialDiagnosticAt(NewFD->getLocation(), + S.PDiag(diag::err_multiversion_diff)), + /*TemplatesSupported=*/false, + /*ConstexprSupported=*/!IsCPUSpecificCPUDispatchMVType); +} + /// Check the validity of a multiversion function declaration that is the /// first of its kind. Also sets the multiversion'ness' of the function itself. /// diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index dbf8155d02..97844cd570 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -3447,6 +3447,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_requires: + case OMPD_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -4516,6 +4517,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_requires: + case OMPD_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -4653,8 +4655,10 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( if (!DG || DG.get().isNull()) return DeclGroupPtrTy(); + const int SimdId = 0; if (!DG.get().isSingleDecl()) { - Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd); + Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant) + << SimdId; return DG; } Decl *ADecl = DG.get().getSingleDecl(); @@ -4663,7 +4667,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( auto *FD = dyn_cast(ADecl); if (!FD) { - Diag(ADecl->getLocation(), diag::err_omp_function_expected); + Diag(ADecl->getLocation(), diag::err_omp_function_expected) << SimdId; return DeclGroupPtrTy(); } @@ -4888,6 +4892,204 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( return ConvertDeclToDeclGroup(ADecl); } +Sema::DeclGroupPtrTy +Sema::ActOnOpenMPDeclareVariantDirective(Sema::DeclGroupPtrTy DG, + Expr *VariantRef, SourceRange SR) { + if (!DG || DG.get().isNull()) + return DeclGroupPtrTy(); + + const int VariantId = 1; + // Must be applied only to single decl. + if (!DG.get().isSingleDecl()) { + Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant) + << VariantId << SR; + return DG; + } + Decl *ADecl = DG.get().getSingleDecl(); + if (auto *FTD = dyn_cast(ADecl)) + ADecl = FTD->getTemplatedDecl(); + + // Decl must be a function. + auto *FD = dyn_cast(ADecl); + if (!FD) { + Diag(ADecl->getLocation(), diag::err_omp_function_expected) + << VariantId << SR; + return DeclGroupPtrTy(); + } + + auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) { + return FD->hasAttrs() && + (FD->hasAttr() || FD->hasAttr() || + FD->hasAttr()); + }; + // OpenMP is not compatible with CPU-specific attributes. + if (HasMultiVersionAttributes(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes) + << SR; + return DG; + } + + // Allow #pragma omp declare variant only if the function is not used. + if (FD->isUsed(false)) { + Diag(SR.getBegin(), diag::err_omp_declare_variant_after_used) + << FD->getLocation(); + return DG; + } + + // The VariantRef must point to function. + if (!VariantRef) { + Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId; + return DG; + } + + // Do not check templates, wait until instantiation. + if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() || + VariantRef->containsUnexpandedParameterPack() || + VariantRef->isInstantiationDependent() || FD->isDependentContext()) + return DG; + + // Convert VariantRef expression to the type of the original function to + // resolve possible conflicts. + ExprResult VariantRefCast; + if (LangOpts.CPlusPlus) { + QualType FnPtrType; + auto *Method = dyn_cast(FD); + if (Method && !Method->isStatic()) { + const Type *ClassType = + Context.getTypeDeclType(Method->getParent()).getTypePtr(); + FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType); + ExprResult ER; + { + // Build adrr_of unary op to correctly handle type checks for member + // functions. + Sema::TentativeAnalysisScope Trap(*this); + ER = CreateBuiltinUnaryOp(VariantRef->getBeginLoc(), UO_AddrOf, + VariantRef); + } + if (!ER.isUsable()) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return DG; + } + VariantRef = ER.get(); + } else { + FnPtrType = Context.getPointerType(FD->getType()); + } + ImplicitConversionSequence ICS = + TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(), + /*SuppressUserConversions=*/false, + /*AllowExplicit=*/false, + /*InOverloadResolution=*/false, + /*CStyle=*/false, + /*AllowObjCWritebackConversion=*/false); + if (ICS.isFailure()) { + Diag(VariantRef->getExprLoc(), + diag::err_omp_declare_variant_incompat_types) + << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange(); + return DG; + } + VariantRefCast = PerformImplicitConversion( + VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting); + if (!VariantRefCast.isUsable()) + return DG; + // Drop previously built artificial addr_of unary op for member functions. + if (Method && !Method->isStatic()) { + Expr *PossibleAddrOfVariantRef = VariantRefCast.get(); + if (auto *UO = dyn_cast( + PossibleAddrOfVariantRef->IgnoreImplicit())) + VariantRefCast = UO->getSubExpr(); + } + } else { + VariantRefCast = VariantRef; + } + + ExprResult ER = CheckPlaceholderExpr(VariantRefCast.get()); + if (!ER.isUsable() || + !ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return DG; + } + + // The VariantRef must point to function. + auto *DRE = dyn_cast(ER.get()->IgnoreParenImpCasts()); + if (!DRE) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return DG; + } + auto *NewFD = dyn_cast_or_null(DRE->getDecl()); + if (!NewFD) { + Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected) + << VariantId << VariantRef->getSourceRange(); + return DG; + } + + enum DoesntSupport { + VirtFuncs = 1, + Constructors = 3, + Destructors = 4, + DeletedFuncs = 5, + DefaultedFuncs = 6, + ConstexprFuncs = 7, + ConstevalFuncs = 8, + }; + if (const auto *CXXFD = dyn_cast(FD)) { + if (CXXFD->isVirtual()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << VirtFuncs; + return DG; + } + + if (isa(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << Constructors; + return DG; + } + + if (isa(FD)) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << Destructors; + return DG; + } + } + + if (FD->isDeleted()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << DeletedFuncs; + return DG; + } + + if (FD->isDefaulted()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << DefaultedFuncs; + return DG; + } + + if (FD->isConstexpr()) { + Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support) + << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs); + return DG; + } + + // Check general compatibility. + if (areMultiversionVariantFunctionsCompatible( + FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto), + PartialDiagnosticAt( + SR.getBegin(), + PDiag(diag::note_omp_declare_variant_specified_here) << SR), + PartialDiagnosticAt( + VariantRef->getExprLoc(), + PDiag(diag::err_omp_declare_variant_doesnt_support)), + PartialDiagnosticAt(VariantRef->getExprLoc(), + PDiag(diag::err_omp_declare_variant_diff) + << FD->getLocation()), + /*TemplatesSupported=*/true, /*ConstexprSupported=*/false)) + return DG; + + return DG; +} + StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -9895,6 +10097,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -9963,6 +10166,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -10032,6 +10236,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -10098,6 +10303,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -10165,6 +10371,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -10231,6 +10438,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -10296,6 +10504,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: + case OMPD_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: diff --git a/test/OpenMP/declare_variant_messages.c b/test/OpenMP/declare_variant_messages.c new file mode 100644 index 0000000000..3d8ae66c0c --- /dev/null +++ b/test/OpenMP/declare_variant_messages.c @@ -0,0 +1,92 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c -std=c99 -fms-extensions -Wno-pragma-pack %s + +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp-simd -x c -std=c99 -fms-extensions -Wno-pragma-pack %s + +// expected-error@+1 {{expected an OpenMP directive}} +#pragma omp declare + +int foo(void); + +#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} +#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo // expected-error {{expected ')'}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} +#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} +#pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo) xxx // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo) match // expected-error {{expected '(' after 'match'}} +#pragma omp declare variant(foo) match( // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foo) match() // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foo) match(xxx) // expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}}} +#pragma omp declare variant(foo) match(xxx=) // expected-error {{expected '{' after '='}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foo) match(xxx=yyy) // expected-error {{expected '{' after '='}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foo) match(xxx=yyy}) // expected-error {{expected '{' after '='}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foo) match(xxx={) // expected-error {{expected '}'}} expected-note {{to match this '{'}} +#pragma omp declare variant(foo) match(xxx={}) +#pragma omp declare variant(foo) match(xxx={vvv}) +#pragma omp declare variant(foo) match(xxx={vvv} xxx) // expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo) match(xxx={vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +int bar(void); + +// expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} +#pragma omp declare variant(foo) match(xxx={}) +int a; +// expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} +#pragma omp declare variant(foo) match(xxx={}) +#pragma omp threadprivate(a) +int var; +#pragma omp threadprivate(var) + +// expected-error@+2 {{expected an OpenMP directive}} expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(foo) match(xxx={}) +#pragma omp declare + +// expected-error@+3 {{function declaration is expected after 'declare variant' directive}} +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(foo) match(xxx={}) +#pragma omp declare variant(foo) match(xxx={}) +#pragma options align=packed +int main(); + +// expected-error@+3 {{function declaration is expected after 'declare variant' directive}} +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(foo) match(xxx={}) +#pragma omp declare variant(foo) match(xxx={}) +#pragma init_seg(compiler) +int main(); + +// expected-error@+1 {{single declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(foo) match(xxx={}) +int b, c; + +int no_proto(); + +// expected-error@+3 {{function with '#pragma omp declare variant' must have a prototype}} +// expected-note@+1 {{'#pragma omp declare variant' for function specified here}} +#pragma omp declare variant(no_proto) match(xxx={}) +int no_proto_too(); + +int after_use_variant(void); +int after_use(); +int bar() { + return after_use(); +} + +// expected-error@+1 {{'#pragma omp declare variant' cannot be applied for function after first usage}} +#pragma omp declare variant(after_use_variant) match(xxx={}) +int after_use(void); + +int diff_cc_variant(void); +// expected-error@+1 {{function with '#pragma omp declare variant' has a different calling convention}} +#pragma omp declare variant(diff_cc_variant) match(xxx={}) +__vectorcall int diff_cc(void); + +int diff_ret_variant(void); +// expected-error@+1 {{function with '#pragma omp declare variant' has a different return type}} +#pragma omp declare variant(diff_ret_variant) match(xxx={}) +void diff_ret(void); + +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant diff --git a/test/OpenMP/declare_variant_messages.cpp b/test/OpenMP/declare_variant_messages.cpp new file mode 100644 index 0000000000..42427ea184 --- /dev/null +++ b/test/OpenMP/declare_variant_messages.cpp @@ -0,0 +1,225 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp -x c++ -std=c++14 -fms-extensions -Wno-pragma-pack -fexceptions -fcxx-exceptions %s + +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -verify -fopenmp-simd -x c++ -std=c++14 -fms-extensions -Wno-pragma-pack -fexceptions -fcxx-exceptions %s + +// expected-error@+1 {{expected an OpenMP directive}} +#pragma omp declare + +int foo(); + +template +T foofoo(); + +#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} +#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant(foo // expected-error {{expected ')'}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} +#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} +#pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) xxx // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) match // expected-error {{expected '(' after 'match'}} +#pragma omp declare variant(foofoo ) match( // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) match() // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foofoo ) match(xxx) // expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}}} +#pragma omp declare variant(foofoo ) match(xxx =) // expected-error {{expected '{' after '='}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foofoo ) match(xxx = yyy) // expected-error {{expected '{' after '='}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foofoo ) match(xxx = yyy }) // expected-error {{expected '{' after '='}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foofoo ) match(xxx = {) // expected-error {{expected '}'}} expected-note {{to match this '{'}} +#pragma omp declare variant(foofoo ) match(xxx = {}) +#pragma omp declare variant(foofoo ) match(xxx = {vvv}) +#pragma omp declare variant(foofoo ) match(xxx = {vvv} xxx) // expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +int bar(); + +#pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} +#pragma omp declare variant( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo // expected-error {{expected ')'}} expected-error {{expected 'match' clause on 'omp declare variant' directive}} expected-note {{to match this '('}} +#pragma omp declare variant(x) // expected-error {{use of undeclared identifier 'x'}} +#pragma omp declare variant(foo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) xxx // expected-error {{expected 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) match // expected-error {{expected '(' after 'match'}} +#pragma omp declare variant(foofoo ) match( // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} +#pragma omp declare variant(foofoo ) match() // expected-error {{expected context selector in 'match' clause on 'omp declare variant' directive}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foofoo ) match(xxx) // expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}}} +#pragma omp declare variant(foofoo ) match(xxx =) // expected-error {{expected '{' after '='}} expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +#pragma omp declare variant(foofoo ) match(xxx = {) // expected-error {{expected '}'}} expected-note {{to match this '{'}} +#pragma omp declare variant(foofoo ) match(xxx = {}) +#pragma omp declare variant(foofoo ) match(xxx = {vvv}) +#pragma omp declare variant(foofoo ) match(user = {score() : condition()}) +#pragma omp declare variant(foofoo ) match(user = {score() : condition()}) +#pragma omp declare variant(foofoo ) match(user = {condition()}) +#pragma omp declare variant(foofoo ) match(user = {condition()}) +#pragma omp declare variant(foofoo ) match(xxx = {vvv} xxx) // expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp declare variant(foofoo ) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} +template +T barbar(); + +// expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} +#pragma omp declare variant(barbar ) match(xxx = {}) +int a; +// expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} +#pragma omp declare variant(barbar ) match(xxx = {}) +#pragma omp threadprivate(a) +int var; +#pragma omp threadprivate(var) + +// expected-error@+2 {{expected an OpenMP directive}} expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(barbar ) match(xxx = {}) +#pragma omp declare + +// expected-error@+3 {{function declaration is expected after 'declare variant' directive}} +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(barbar ) match(xxx = {}) +#pragma omp declare variant(barbar ) match(xxx = {}) +#pragma options align = packed +int main(); + +// expected-error@+3 {{function declaration is expected after 'declare variant' directive}} +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(barbar ) match(xxx = {}) +#pragma omp declare variant(barbar ) match(xxx = {}) +#pragma init_seg(compiler) +int main(); + +// expected-error@+1 {{single declaration is expected after 'declare variant' directive}} +#pragma omp declare variant(barbar ) match(xxx = {}) +int b, c; + +// expected-error@+1 {{'C' does not refer to a value}} +#pragma omp declare variant(C) match(xxx = {}) +// expected-note@+1 {{declared here}} +template +void h(C *hp, C *hp2, C *hq, C *lin) { + b = 0; +} + +// expected-error@+1 {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'void (*)(int *, int *, int *, int *)'}} +#pragma omp declare variant(barbar ) match(xxx = {}) +template <> +void h(int *hp, int *hp2, int *hq, int *lin) { + h((float *)hp, (float *)hp2, (float *)hq, (float *)lin); +} + +int after_use_variant(void); +int after_use(); +int bar() { + return after_use(); +} + +// expected-error@+1 {{'#pragma omp declare variant' cannot be applied for function after first usage}} +#pragma omp declare variant(after_use_variant) match(xxx = {}) +int after_use(void); + +int fn(); +int fn(int); +#pragma omp declare variant(fn) match(xxx = {}) +int overload(void); + +int fn1(); +int fn1(int); +// expected-error@+1 {{variant in '#pragma omp declare variant' with type '' is incompatible with type 'int (*)(float)'}} +#pragma omp declare variant(fn1) match(xxx = {}) +int overload1(float); + +int fn_constexpr_variant(); +// expected-error@+2 {{'#pragma omp declare variant' does not support constexpr functions}} +#pragma omp declare variant(fn_constexpr_variant) match(xxx = {}) +constexpr int fn_constexpr(); + +constexpr int fn_constexpr_variant1(); +// expected-error@+1 {{'#pragma omp declare variant' does not support constexpr functions}} +#pragma omp declare variant(fn_constexpr_variant1) match(xxx = {}) +int fn_constexpr1(); + +int fn_sc_variant(); +// expected-error@+1 {{function with '#pragma omp declare variant' has a different storage class}} +#pragma omp declare variant(fn_sc_variant) match(xxx = {}) +static int fn_sc(); + +static int fn_sc_variant1(); +// expected-error@+1 {{function with '#pragma omp declare variant' has a different storage class}} +#pragma omp declare variant(fn_sc_variant1) match(xxx = {}) +int fn_sc1(); + +int fn_inline_variant(); +// expected-error@+1 {{function with '#pragma omp declare variant' has a different inline specification}} +#pragma omp declare variant(fn_inline_variant) match(xxx = {}) +inline int fn_inline(); + +inline int fn_inline_variant1(); +// expected-error@+1 {{function with '#pragma omp declare variant' has a different inline specification}} +#pragma omp declare variant(fn_inline_variant1) match(xxx = {}) +int fn_inline1(); + +int fn_linkage_variant(); +extern "C" { +// expected-error@+1 {{function with '#pragma omp declare variant' has a different linkage}} +#pragma omp declare variant(fn_linkage_variant) match(xxx = {}) +int fn_linkage(); +} + +extern "C" int fn_linkage_variant1(); +// expected-error@+1 {{function with '#pragma omp declare variant' has a different linkage}} +#pragma omp declare variant(fn_linkage_variant1) match(xxx = {}) +int fn_linkage1(); + +auto fn_deduced_variant() { return 0; } +#pragma omp declare variant(fn_deduced_variant) match(xxx = {}) +int fn_deduced(); + +int fn_deduced_variant1(); +#pragma omp declare variant(fn_deduced_variant1) match(xxx = {}) +auto fn_deduced1() { return 0; } + +auto fn_deduced_variant2() { return 0; } +// expected-error@+1 {{variant in '#pragma omp declare variant' with type 'int ()' is incompatible with type 'float (*)()'}} +#pragma omp declare variant(fn_deduced_variant2) match(xxx = {}) +float fn_deduced2(); + +// expected-error@+1 {{exception specification in declaration does not match previous declaration}} +int fn_except_variant() noexcept(true); +// expected-note@+2 {{previous declaration is here}} +#pragma omp declare variant(fn_except_variant) match(xxx = {}) +int fn_except() noexcept(false); + +// expected-error@+1 {{exception specification in declaration does not match previous declaration}} +int fn_except_variant1() noexcept(false); +// expected-note@+2 {{previous declaration is here}} +#pragma omp declare variant(fn_except_variant1) match(xxx = {}) +int fn_except1() noexcept(true); + +struct SpecialFuncs { + void vd(); + // expected-error@+2 {{'#pragma omp declare variant' does not support constructors}} +#pragma omp declare variant(SpecialFuncs::vd) match(xxx = {}) + SpecialFuncs(); + // expected-error@+2 {{'#pragma omp declare variant' does not support destructors}} +#pragma omp declare variant(SpecialFuncs::vd) match(xxx = {}) + ~SpecialFuncs(); + + void baz(); + void bar(); + void bar(int); +#pragma omp declare variant(SpecialFuncs::baz) match(xxx = {}) +#pragma omp declare variant(SpecialFuncs::bar) match(xxx = {}) + void foo1(); + SpecialFuncs& foo(const SpecialFuncs&); + SpecialFuncs& bar(SpecialFuncs&&); + // expected-error@+2 {{'#pragma omp declare variant' does not support defaulted functions}} +#pragma omp declare variant(SpecialFuncs::foo) match(xxx = {}) + SpecialFuncs& operator=(const SpecialFuncs&) = default; + // expected-error@+2 {{'#pragma omp declare variant' does not support deleted functions}} +#pragma omp declare variant(SpecialFuncs::bar) match(xxx = {}) + SpecialFuncs& operator=(SpecialFuncs&&) = delete; +}; + +namespace N { +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant +} // namespace N +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant +// expected-error@+1 {{function declaration is expected after 'declare variant' directive}} +#pragma omp declare variant -- 2.40.0