/// Parses clauses for 'declare simd' directive.
/// clause:
/// 'inbranch' | 'notinbranch'
-static void parseDeclareSimdClauses(Parser &P,
- OMPDeclareSimdDeclAttr::BranchStateTy &BS) {
+/// 'simdlen' '('<expr> ')'
+static bool parseDeclareSimdClauses(Parser &P,
+ OMPDeclareSimdDeclAttr::BranchStateTy &BS,
+ ExprResult &SimdLen) {
SourceRange BSRange;
const Token &Tok = P.getCurToken();
+ bool IsError = false;
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
if (Tok.isNot(tok::identifier))
break;
OMPDeclareSimdDeclAttr::BranchStateTy Out;
- StringRef TokName = Tok.getIdentifierInfo()->getName();
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ StringRef ClauseName = II->getName();
// Parse 'inranch|notinbranch' clauses.
- if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(TokName, Out)) {
+ if (OMPDeclareSimdDeclAttr::ConvertStrToBranchStateTy(ClauseName, Out)) {
if (BS != OMPDeclareSimdDeclAttr::BS_Undefined && BS != Out) {
P.Diag(Tok, diag::err_omp_declare_simd_inbranch_notinbranch)
- << TokName << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS)
- << BSRange;
+ << ClauseName
+ << OMPDeclareSimdDeclAttr::ConvertBranchStateTyToStr(BS) << BSRange;
+ IsError = true;
}
BS = Out;
BSRange = SourceRange(Tok.getLocation(), Tok.getEndLoc());
+ P.ConsumeToken();
+ } else if (ClauseName.equals("simdlen")) {
+ if (SimdLen.isUsable()) {
+ P.Diag(Tok, diag::err_omp_more_one_clause)
+ << getOpenMPDirectiveName(OMPD_declare_simd) << ClauseName << 0;
+ IsError = true;
+ }
+ P.ConsumeToken();
+ SourceLocation RLoc;
+ SimdLen = P.ParseOpenMPParensExpr(ClauseName, RLoc);
+ if (SimdLen.isInvalid())
+ IsError = true;
} else
// TODO: add parsing of other clauses.
break;
- P.ConsumeToken();
// Skip ',' if any.
if (Tok.is(tok::comma))
P.ConsumeToken();
}
+ return IsError;
+}
+
+namespace {
+/// RAII that recreates function context for correct parsing of clauses of
+/// 'declare simd' construct.
+/// OpenMP, 2.8.2 declare simd Construct
+/// The expressions appearing in the clauses of this directive are evaluated in
+/// the scope of the arguments of the function declaration or definition.
+class FNContextRAII final {
+ Parser &P;
+ Sema::CXXThisScopeRAII *ThisScope;
+ Parser::ParseScope *TempScope;
+ Parser::ParseScope *FnScope;
+ bool HasTemplateScope = false;
+ bool HasFunScope = false;
+ FNContextRAII() = delete;
+ FNContextRAII(const FNContextRAII &) = delete;
+ FNContextRAII &operator=(const FNContextRAII &) = delete;
+
+public:
+ FNContextRAII(Parser &P, Parser::DeclGroupPtrTy Ptr) : P(P) {
+ Decl *D = *Ptr.get().begin();
+ NamedDecl *ND = dyn_cast<NamedDecl>(D);
+ RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext());
+ Sema &Actions = P.getActions();
+
+ // Allow 'this' within late-parsed attributes.
+ ThisScope = new Sema::CXXThisScopeRAII(Actions, RD, /*TypeQuals=*/0,
+ ND && ND->isCXXInstanceMember());
+
+ // If the Decl is templatized, add template parameters to scope.
+ HasTemplateScope = D->isTemplateDecl();
+ TempScope =
+ new Parser::ParseScope(&P, Scope::TemplateParamScope, HasTemplateScope);
+ if (HasTemplateScope)
+ Actions.ActOnReenterTemplateScope(Actions.getCurScope(), D);
+
+ // If the Decl is on a function, add function parameters to the scope.
+ HasFunScope = D->isFunctionOrFunctionTemplate();
+ FnScope = new Parser::ParseScope(&P, Scope::FnScope | Scope::DeclScope,
+ HasFunScope);
+ if (HasFunScope)
+ Actions.ActOnReenterFunctionContext(Actions.getCurScope(), D);
+ }
+ ~FNContextRAII() {
+ if (HasFunScope) {
+ P.getActions().ActOnExitFunctionContext();
+ FnScope->Exit(); // Pop scope, and remove Decls from IdResolver
+ }
+ if (HasTemplateScope)
+ TempScope->Exit();
+ delete FnScope;
+ delete TempScope;
+ delete ThisScope;
+ }
+};
+} // namespace
+
+/// Parse clauses for '#pragma omp declare simd'.
+Parser::DeclGroupPtrTy
+Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr,
+ CachedTokens &Toks, SourceLocation Loc) {
+ PP.EnterToken(Tok);
+ PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true);
+ // Consume the previously pushed token.
+ ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);
+
+ FNContextRAII FnContext(*this, Ptr);
+ OMPDeclareSimdDeclAttr::BranchStateTy BS =
+ OMPDeclareSimdDeclAttr::BS_Undefined;
+ ExprResult Simdlen;
+ bool IsError = parseDeclareSimdClauses(*this, BS, Simdlen);
+ // 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_simd);
+ while (Tok.isNot(tok::annot_pragma_openmp_end))
+ ConsumeAnyToken();
+ }
+ // Skip the last annot_pragma_openmp_end.
+ SourceLocation EndLoc = ConsumeToken();
+ if (!IsError)
+ return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS, Simdlen.get(),
+ SourceRange(Loc, EndLoc));
+ return Ptr;
}
/// \brief Parsing of declarative OpenMP directives.
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SourceLocation Loc = ConsumeToken();
- SmallVector<Expr *, 5> Identifiers;
+ SmallVector<Expr *, 4> Identifiers;
auto DKind = ParseOpenMPDirectiveKind(*this);
switch (DKind) {
// { #pragma omp declare simd }
// <function-declaration-or-definition>
//
-
ConsumeToken();
- OMPDeclareSimdDeclAttr::BranchStateTy BS =
- OMPDeclareSimdDeclAttr::BS_Undefined;
- parseDeclareSimdClauses(*this, BS);
-
- // 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_simd);
- while (Tok.isNot(tok::annot_pragma_openmp_end))
- ConsumeAnyToken();
- }
- // Skip the last annot_pragma_openmp_end.
- SourceLocation EndLoc = ConsumeToken();
+ CachedTokens Toks;
+ ConsumeAndStoreUntil(tok::annot_pragma_openmp_end, Toks,
+ /*StopAtSemi=*/false, /*ConsumeFinalToken=*/true);
DeclGroupPtrTy Ptr;
if (Tok.is(tok::annot_pragma_openmp))
Diag(Loc, diag::err_omp_decl_in_declare_simd);
return DeclGroupPtrTy();
}
-
- return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS,
- SourceRange(Loc, EndLoc));
+ return ParseOMPDeclareSimdClauses(Ptr, Toks, Loc);
}
case OMPD_declare_target: {
SourceLocation DTLoc = ConsumeAnyToken();
return ErrorFound ? nullptr : Clause;
}
+/// Parses simple expression in parens for single-expression clauses of OpenMP
+/// constructs.
+/// \param RLoc Returned location of right paren.
+ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
+ SourceLocation &RLoc) {
+ 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));
+ ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
+ Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc);
+
+ // Parse ')'.
+ T.consumeClose();
+
+ RLoc = T.getCloseLocation();
+ return Val;
+}
+
/// \brief Parsing of OpenMP clauses with single expressions like 'final',
/// 'collapse', 'safelen', 'num_threads', 'simdlen', 'num_teams',
/// 'thread_limit', 'simdlen', 'priority', 'grainsize', 'num_tasks' or 'hint'.
///
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind) {
SourceLocation Loc = ConsumeToken();
+ SourceLocation LLoc = Tok.getLocation();
+ SourceLocation RLoc;
- BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
- if (T.expectAndConsume(diag::err_expected_lparen_after,
- getOpenMPClauseName(Kind)))
- return nullptr;
-
- SourceLocation ELoc = Tok.getLocation();
- ExprResult LHS(ParseCastExpression(false, false, NotTypeCast));
- ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional));
- Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc);
-
- // Parse ')'.
- T.consumeClose();
+ ExprResult Val = ParseOpenMPParensExpr(getOpenMPClauseName(Kind), RLoc);
if (Val.isInvalid())
return nullptr;
- return Actions.ActOnOpenMPSingleExprClause(
- Kind, Val.get(), Loc, T.getOpenLocation(), T.getCloseLocation());
+ return Actions.ActOnOpenMPSingleExprClause(Kind, Val.get(), Loc, LLoc, RLoc);
}
/// \brief Parsing of simple OpenMP clauses like 'default' or 'proc_bind'.
// expected-error@+1 {{single declaration is expected after 'declare simd' directive}}
#pragma omp declare simd
+// expected-note@+1 {{declared here}}
int b, c;
-#pragma omp declare simd
+// expected-error@+1 {{'C' does not refer to a value}}
+#pragma omp declare simd simdlen(C)
+// expected-note@+1 {{declared here}}
template <class C>
void h(C *hp, C *hp2, C *hq, C *lin) {
b = 0;
#pragma omp declare simd notinbranch notinbranch
#pragma omp declare simd inbranch inbranch notinbranch // expected-error {{unexpected 'notinbranch' clause, 'inbranch' is specified already}}
#pragma omp declare simd notinbranch notinbranch inbranch // expected-error {{unexpected 'inbranch' clause, 'notinbranch' is specified already}}
+// expected-note@+2 {{read of non-const variable 'b' is not allowed in a constant expression}}
+// expected-error@+1 {{expression is not an integral constant expression}}
+#pragma omp declare simd simdlen(b)
+// expected-error@+1 {{directive '#pragma omp declare simd' cannot contain more than one 'simdlen' clause}}
+#pragma omp declare simd simdlen(32) simdlen(c)
+// expected-error@+1 {{expected '(' after 'simdlen'}}
+#pragma omp declare simd simdlen
+// expected-note@+3 {{to match this '('}}
+// expected-error@+2 {{expected ')'}}
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd simdlen(
+// expected-error@+2 {{expected '(' after 'simdlen'}}
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd simdlen(), simdlen
+// expected-error@+1 2 {{expected expression}}
+#pragma omp declare simd simdlen(), simdlen()
+// expected-warning@+3 {{extra tokens at the end of '#pragma omp declare simd' are ignored}}
+// expected-error@+2 {{expected '(' after 'simdlen'}}
+// expected-error@+1 {{expected expression}}
+#pragma omp declare simd simdlen() simdlen)
void foo();
+// expected-error@+1 {{argument to 'simdlen' clause must be a strictly positive integer value}}
+#pragma omp declare simd simdlen(N)
+template<int N>
+void foo() {}
+
+void test() {
+ // expected-note@+1 {{in instantiation of function template specialization 'foo<-3>' requested here}}
+ foo<-3>();
+}
+
template <class T>
struct St {
// expected-error@+2 {{function declaration is expected after 'declare simd' directive}}