From ef440caa0d55f6add3fdf23a55ebaa5e98ded541 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Tue, 8 Oct 2019 17:47:52 +0000 Subject: [PATCH] [OPENMP50]Do not allow multiple same context traits in the same context selector. According to OpenMP 5.0, 2.3.2 Context Selectors, Restrictions, each trait-selector-name can only be specified once. Added check for this restriction. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@374093 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 5 +++ lib/Parse/ParseOpenMP.cpp | 41 +++++++++++++++------ test/OpenMP/declare_variant_ast_print.c | 6 ++- test/OpenMP/declare_variant_ast_print.cpp | 6 +-- test/OpenMP/declare_variant_messages.c | 6 +-- test/OpenMP/declare_variant_messages.cpp | 12 +++--- 6 files changed, 50 insertions(+), 26 deletions(-) diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index c0b488d305..48ef1fb369 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -1215,6 +1215,11 @@ def err_omp_declare_variant_ctx_set_mutiple_use : Error< "context selector set '%0' is used already in the same 'omp declare variant' directive">; def note_omp_declare_variant_ctx_set_used_here : Note< "previously context selector set '%0' used here">; +def err_omp_expected_comma_brace : Error<"expected '}' or ',' after '%0'">; +def err_omp_declare_variant_ctx_mutiple_use : Error< + "context trait selector '%0' is used already in the same '%1' context selector set of 'omp declare variant' directive">; +def note_omp_declare_variant_ctx_used_here : Note< + "previously context trait selector '%0' used here">; def warn_omp_more_one_device_type_clause : Warning< "more than one 'device_type' clause is specified">, InGroup; diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index e487e0ab65..f667b83b58 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -815,7 +815,7 @@ static ExprResult parseContextScore(Parser &P) { /// 'vendor' '(' [ 'score' '(' ')' ':' ] { ',' } /// ')' static void parseImplementationSelector( - Parser &P, SourceLocation Loc, + Parser &P, SourceLocation Loc, llvm::StringMap &UsedCtx, llvm::function_ref Callback) { @@ -832,6 +832,15 @@ static void parseImplementationSelector( } SmallString<16> Buffer; StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); + auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); + if (!Res.second) { + // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions. + // Each trait-selector-name can only be specified once. + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use) + << CtxSelectorName << "implementation"; + P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) + << CtxSelectorName; + } OMPDeclareVariantAttr::CtxSelectorType CSKind = OMPDeclareVariantAttr::CtxUnknown; (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorType(CtxSelectorName, @@ -932,17 +941,25 @@ bool Parser::parseOpenMPContextSelectors( OMPDeclareVariantAttr::CtxSetUnknown; (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorSetType( CtxSelectorSetName, CSSKind); - switch (CSSKind) { - case OMPDeclareVariantAttr::CtxSetImplementation: - parseImplementationSelector(*this, Loc, Callback); - break; - case OMPDeclareVariantAttr::CtxSetUnknown: - // Skip until either '}', ')', or end of directive. - while (!SkipUntil(tok::r_brace, tok::r_paren, - tok::annot_pragma_openmp_end, StopBeforeMatch)) - ; - break; - } + llvm::StringMap UsedCtx; + do { + switch (CSSKind) { + case OMPDeclareVariantAttr::CtxSetImplementation: + parseImplementationSelector(*this, Loc, UsedCtx, Callback); + break; + case OMPDeclareVariantAttr::CtxSetUnknown: + // Skip until either '}', ')', or end of directive. + while (!SkipUntil(tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + break; + } + const Token PrevTok = Tok; + if (!TryConsumeToken(tok::comma) && Tok.isNot(tok::r_brace)) + Diag(Tok, diag::err_omp_expected_comma_brace) + << (PrevTok.isAnnotation() ? "context selector trait" + : PP.getSpelling(PrevTok)); + } while (Tok.is(tok::identifier)); // Parse '}'. (void)TBr.consumeClose(); } diff --git a/test/OpenMP/declare_variant_ast_print.c b/test/OpenMP/declare_variant_ast_print.c index 0174c07aeb..7f359e07b7 100644 --- a/test/OpenMP/declare_variant_ast_print.c +++ b/test/OpenMP/declare_variant_ast_print.c @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -x c -std=c99 -ast-print %s -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -x c -std=c99 -ast-print %s -o - -Wno-openmp-clauses | FileCheck %s -// RUN: %clang_cc1 -verify -fopenmp-simd -x c -std=c99 -ast-print %s -o - | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp-simd -x c -std=c99 -ast-print %s -o - -Wno-openmp-clauses | FileCheck %s // expected-no-diagnostics @@ -9,6 +9,7 @@ int foo(void); #pragma omp declare variant(foo) match(xxx={}, yyy={ccc}) #pragma omp declare variant(foo) match(xxx={vvv}) #pragma omp declare variant(foo) match(implementation={vendor(llvm)}) +#pragma omp declare variant(foo) match(implementation={vendor(llvm), xxx}) #pragma omp declare variant(foo) match(implementation={vendor(unknown)}) #pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm, xxx)}) int bar(void); @@ -18,4 +19,5 @@ int bar(void); // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(score(5):xxx)}) // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(unknown)}) // CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(llvm)}) +// CHECK-NEXT: #pragma omp declare variant(foo) match(implementation={vendor(llvm)}) // CHECK-NEXT: int bar(); diff --git a/test/OpenMP/declare_variant_ast_print.cpp b/test/OpenMP/declare_variant_ast_print.cpp index 879014b613..7b3b9ccd7b 100644 --- a/test/OpenMP/declare_variant_ast_print.cpp +++ b/test/OpenMP/declare_variant_ast_print.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++14 -fexceptions -fcxx-exceptions %s -ast-print -o - -Wno-source-uses-openmp | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++14 -fexceptions -fcxx-exceptions %s -ast-print -o - -Wno-source-uses-openmp -Wno-openmp-clauses | FileCheck %s -// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++14 -fexceptions -fcxx-exceptions %s -ast-print -o - -Wno-source-uses-openmp | FileCheck %s +// RUN: %clang_cc1 -verify -fopenmp-simd -x c++ -std=c++14 -fexceptions -fcxx-exceptions %s -ast-print -o - -Wno-source-uses-openmp -Wno-openmp-clauses | FileCheck %s // expected-no-diagnostics @@ -23,7 +23,7 @@ T foofoo() { return T(); } // CHECK-NEXT: int bar(); #pragma omp declare variant(foofoo ) match(xxx = {}) #pragma omp declare variant(foofoo ) match(xxx = {vvv}) -#pragma omp declare variant(foofoo ) match(implementation={vendor(llvm)}) +#pragma omp declare variant(foofoo ) match(implementation={vendor(llvm), xxx}) #pragma omp declare variant(foofoo ) match(implementation={vendor(unknown)}) #pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm)}) int bar(); diff --git a/test/OpenMP/declare_variant_messages.c b/test/OpenMP/declare_variant_messages.c index c6737f5cb1..21541cbbac 100644 --- a/test/OpenMP/declare_variant_messages.c +++ b/test/OpenMP/declare_variant_messages.c @@ -21,9 +21,9 @@ int foo(void); #pragma omp declare variant(foo) match(xxx=) // expected-error {{expected '{' after '='}} #pragma omp declare variant(foo) match(xxx=yyy) // expected-error {{expected '{' after '='}} #pragma omp declare variant(foo) match(xxx=yyy}) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foo) match(xxx={) // expected-error {{expected '}'}} expected-note {{to match this '{'}} +#pragma omp declare variant(foo) match(xxx={) // expected-error {{expected '}' or ',' after ')'}} 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, vvv}) #pragma omp declare variant(foo) match(xxx={vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-error {{context selector set 'xxx' is used already in the same 'omp declare variant' directive}} expected-note {{previously context selector set 'xxx' used here}} #pragma omp declare variant(foo) match(xxx={vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} #pragma omp declare variant(foo) match(implementation={xxx}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}} @@ -34,7 +34,7 @@ int foo(void); #pragma omp declare variant(foo) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} #pragma omp declare variant(foo) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} #pragma omp declare variant(foo) match(implementation={vendor(score(foo()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integer constant expression}} -#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm)}) +#pragma omp declare variant(foo) match(implementation={vendor(score(5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}} int bar(void); // expected-error@+2 {{'#pragma omp declare variant' can only be applied to functions}} diff --git a/test/OpenMP/declare_variant_messages.cpp b/test/OpenMP/declare_variant_messages.cpp index e986cd6b80..2265c34738 100644 --- a/test/OpenMP/declare_variant_messages.cpp +++ b/test/OpenMP/declare_variant_messages.cpp @@ -24,9 +24,9 @@ T foofoo(); // expected-note 2 {{declared here}} #pragma omp declare variant(foofoo ) match(xxx =) // expected-error {{expected '{' after '='}} #pragma omp declare variant(foofoo ) match(xxx = yyy) // expected-error {{expected '{' after '='}} #pragma omp declare variant(foofoo ) match(xxx = yyy }) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foofoo ) match(xxx = {) // expected-error {{expected '}'}} expected-note {{to match this '{'}} +#pragma omp declare variant(foofoo ) match(xxx = {) // expected-error {{expected '}' or ',' after ')'}} 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, vvv}) #pragma omp declare variant(foofoo ) match(xxx = {vvv} xxx) // expected-error {{expected ','}} expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} expected-error {{context selector set 'xxx' is used already in the same 'omp declare variant' directive}} expected-note {{previously context selector set 'xxx' used here}} #pragma omp declare variant(foofoo ) match(xxx = {vvv}) xxx // expected-warning {{extra tokens at the end of '#pragma omp declare variant' are ignored}} #pragma omp declare variant(foofoo ) match(implementation={xxx}) // expected-warning {{unknown context selector in 'implementation' context selector set of 'omp declare variant' directive, ignored}} @@ -37,7 +37,7 @@ T foofoo(); // expected-note 2 {{declared here}} #pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} #pragma omp declare variant(foofoo ) match(implementation={vendor(score(2 ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} #pragma omp declare variant(foofoo ) match(implementation={vendor(score(foofoo ()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integral constant expression}} expected-note {{non-constexpr function 'foofoo' cannot be used in a constant expression}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm)}) +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}} int bar(); #pragma omp declare variant // expected-error {{expected '(' after 'declare variant'}} @@ -53,9 +53,9 @@ int bar(); #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(xxx) // expected-error {{expected '=' after 'xxx' context selector set name on 'omp declare variant' directive}} #pragma omp declare variant(foofoo ) match(xxx =) // expected-error {{expected '{' after '='}} -#pragma omp declare variant(foofoo ) match(xxx = {) // expected-error {{expected '}'}} expected-note {{to match this '{'}} +#pragma omp declare variant(foofoo ) match(xxx = {) // expected-error {{expected '}' or ',' after ')'}} 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, 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()}) @@ -66,7 +66,7 @@ int bar(); #pragma omp declare variant(foofoo ) match(implementation={vendor(score( ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error {{expected ')'}} expected-error {{use of undeclared identifier 'ibm'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note {{to match this '('}} #pragma omp declare variant(foofoo ) match(implementation={vendor(score(C ibm)}) // expected-error {{expected ')' or ',' after 'vendor name'}} expected-error 2 {{expected ')'}} expected-error {{expected vendor identifier in 'vendor' context selector of 'implementation' selector set of 'omp declare variant' directive}} expected-warning {{missing ':' after context selector score clause - ignoring}} expected-note 2 {{to match this '('}} #pragma omp declare variant(foofoo ) match(implementation={vendor(score(foofoo ()) ibm)}) // expected-warning {{missing ':' after context selector score clause - ignoring}} expected-error {{expression is not an integral constant expression}} expected-note {{non-constexpr function 'foofoo' cannot be used in a constant expression}} -#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C+5): ibm)}) +#pragma omp declare variant(foofoo ) match(implementation={vendor(score(C+5): ibm), vendor(llvm)}) // expected-error {{context trait selector 'vendor' is used already in the same 'implementation' context selector set of 'omp declare variant' directive}} expected-note {{previously context trait selector 'vendor' used here}} template T barbar(); -- 2.50.1