teak-llvm/clang/lib/Parse/ParseOpenMP.cpp
Alp Toker ec543279db Support and use token kinds as diagnostic arguments
Introduce proper facilities to render token spellings using the diagnostic
formatter.

Replaces most of the hard-coded diagnostic messages related to expected tokens,
which all shared the same semantics but had to be multiply defined due to
variations in token order or quote marks.

The associated parser changes are largely mechanical but they expose
commonality in whole chunks of the parser that can now be factored away.

This commit uses C++11 typed enums along with a speculative legacy fallback
until the transition is complete.

Requires corresponding changes in LLVM r197895.

llvm-svn: 197972
2013-12-24 09:48:30 +00:00

383 lines
13 KiB
C++

//===--- ParseOpenMP.cpp - OpenMP directives parsing ----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// \brief This file implements parsing of all OpenMP directives and clauses.
///
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/PointerIntPair.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// OpenMP declarative directives.
//===----------------------------------------------------------------------===//
/// \brief Parsing of declarative OpenMP directives.
///
/// threadprivate-directive:
/// annot_pragma_openmp 'threadprivate' simple-variable-list
///
Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SourceLocation Loc = ConsumeToken();
SmallVector<Expr *, 5> Identifiers;
OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
OMPD_unknown :
getOpenMPDirectiveKind(PP.getSpelling(Tok));
switch (DKind) {
case OMPD_threadprivate:
ConsumeToken();
if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) {
// The last seen token is annot_pragma_openmp_end - 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_threadprivate);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
// Skip the last annot_pragma_openmp_end.
ConsumeToken();
return Actions.ActOnOpenMPThreadprivateDirective(Loc,
Identifiers);
}
break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
case OMPD_parallel:
case OMPD_task:
case NUM_OPENMP_DIRECTIVES:
Diag(Tok, diag::err_omp_unexpected_directive)
<< getOpenMPDirectiveName(DKind);
break;
}
SkipUntil(tok::annot_pragma_openmp_end);
return DeclGroupPtrTy();
}
/// \brief Parsing of declarative or executable OpenMP directives.
///
/// threadprivate-directive:
/// annot_pragma_openmp 'threadprivate' simple-variable-list
/// annot_pragma_openmp_end
///
/// parallel-directive:
/// annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end
///
StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!");
ParenBraceBracketBalancer BalancerRAIIObj(*this);
SmallVector<Expr *, 5> Identifiers;
SmallVector<OMPClause *, 5> Clauses;
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, NUM_OPENMP_CLAUSES>
FirstClauses(NUM_OPENMP_CLAUSES);
const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
Scope::OpenMPDirectiveScope;
SourceLocation Loc = ConsumeToken(), EndLoc;
OpenMPDirectiveKind DKind = Tok.isAnnotation() ?
OMPD_unknown :
getOpenMPDirectiveKind(PP.getSpelling(Tok));
// Name of critical directive.
DeclarationNameInfo DirName;
StmtResult Directive = StmtError();
switch (DKind) {
case OMPD_threadprivate:
ConsumeToken();
if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) {
// The last seen token is annot_pragma_openmp_end - 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_threadprivate);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
}
DeclGroupPtrTy Res =
Actions.ActOnOpenMPThreadprivateDirective(Loc,
Identifiers);
Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation());
}
SkipUntil(tok::annot_pragma_openmp_end);
break;
case OMPD_parallel: {
ConsumeToken();
Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope());
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
OpenMPClauseKind CKind = Tok.isAnnotation() ?
OMPC_unknown :
getOpenMPClauseKind(PP.getSpelling(Tok));
OMPClause *Clause = ParseOpenMPClause(DKind, CKind,
!FirstClauses[CKind].getInt());
FirstClauses[CKind].setInt(true);
if (Clause) {
FirstClauses[CKind].setPointer(Clause);
Clauses.push_back(Clause);
}
// Skip ',' if any.
if (Tok.is(tok::comma))
ConsumeToken();
}
// End location of the directive.
EndLoc = Tok.getLocation();
// Consume final annot_pragma_openmp_end.
ConsumeToken();
StmtResult AssociatedStmt;
bool CreateDirective = true;
ParseScope OMPDirectiveScope(this, ScopeFlags);
{
// The body is a block scope like in Lambdas and Blocks.
Sema::CompoundScopeRAII CompoundScope(Actions);
Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_OpenMP, 1);
Actions.ActOnStartOfCompoundStmt();
// Parse statement
AssociatedStmt = ParseStatement();
Actions.ActOnFinishOfCompoundStmt();
if (!AssociatedStmt.isUsable()) {
Actions.ActOnCapturedRegionError();
CreateDirective = false;
} else {
AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take());
CreateDirective = AssociatedStmt.isUsable();
}
}
if (CreateDirective)
Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses,
AssociatedStmt.take(),
Loc, EndLoc);
// Exit scope.
Actions.EndOpenMPDSABlock(Directive.get());
OMPDirectiveScope.Exit();
}
break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
SkipUntil(tok::annot_pragma_openmp_end);
break;
case OMPD_task:
case NUM_OPENMP_DIRECTIVES:
Diag(Tok, diag::err_omp_unexpected_directive)
<< getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end);
break;
}
return Directive;
}
/// \brief Parses list of simple variables for '#pragma omp threadprivate'
/// directive.
///
/// simple-variable-list:
/// '(' id-expression {, id-expression} ')'
///
bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
SmallVectorImpl<Expr *> &VarList,
bool AllowScopeSpecifier) {
VarList.clear();
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
getOpenMPDirectiveName(Kind)))
return true;
bool IsCorrect = true;
bool NoIdentIsFound = true;
// Read tokens while ')' or annot_pragma_openmp_end is not found.
while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) {
CXXScopeSpec SS;
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
// Read var name.
Token PrevTok = Tok;
NoIdentIsFound = false;
if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
} else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
TemplateKWLoc, Name)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
} else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
Tok.isNot(tok::annot_pragma_openmp_end)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
Diag(PrevTok.getLocation(), diag::err_expected)
<< tok::identifier
<< SourceRange(PrevTok.getLocation(), PrevTokLocation);
} else {
DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name);
ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS,
NameInfo);
if (Res.isUsable())
VarList.push_back(Res.take());
}
// Consume ','.
if (Tok.is(tok::comma)) {
ConsumeToken();
}
}
if (NoIdentIsFound) {
Diag(Tok, diag::err_expected) << tok::identifier;
IsCorrect = false;
}
// Parse ')'.
IsCorrect = !T.consumeClose() && IsCorrect;
return !IsCorrect && VarList.empty();
}
/// \brief Parsing of OpenMP clauses.
///
/// clause:
/// default-clause|private-clause|firstprivate-clause|shared-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
OMPClause *Clause = 0;
bool ErrorFound = false;
// Check if clause is allowed for the given directive.
if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) {
Diag(Tok, diag::err_omp_unexpected_clause)
<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
ErrorFound = true;
}
switch (CKind) {
case OMPC_default:
// OpenMP [2.9.3.1, Restrictions]
// Only a single default clause may be specified on a parallel or task
// directive.
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind);
}
Clause = ParseOpenMPSimpleClause(CKind);
break;
case OMPC_private:
case OMPC_firstprivate:
case OMPC_shared:
Clause = ParseOpenMPVarListClause(CKind);
break;
case OMPC_unknown:
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
<< getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch);
break;
case OMPC_threadprivate:
case NUM_OPENMP_CLAUSES:
Diag(Tok, diag::err_omp_unexpected_clause)
<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
break;
}
return ErrorFound ? 0 : Clause;
}
/// \brief Parsing of simple OpenMP clauses like 'default'.
///
/// default-clause:
/// 'default' '(' 'none' | 'shared' ')
///
OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
SourceLocation LOpen = ConsumeToken();
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
getOpenMPClauseName(Kind)))
return 0;
unsigned Type = Tok.isAnnotation() ?
unsigned(OMPC_DEFAULT_unknown) :
getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok));
SourceLocation TypeLoc = Tok.getLocation();
if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) &&
Tok.isNot(tok::annot_pragma_openmp_end))
ConsumeAnyToken();
// Parse ')'.
T.consumeClose();
return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc,
Tok.getLocation());
}
/// \brief Parsing of OpenMP clause 'private', 'firstprivate',
/// 'shared', 'copyin', or 'reduction'.
///
/// private-clause:
/// 'private' '(' list ')'
/// firstprivate-clause:
/// 'firstprivate' '(' list ')'
/// shared-clause:
/// 'shared' '(' list ')'
///
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
SourceLocation LOpen = ConsumeToken();
// Parse '('.
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
if (T.expectAndConsume(diag::err_expected_lparen_after,
getOpenMPClauseName(Kind)))
return 0;
SmallVector<Expr *, 5> Vars;
bool IsComma = true;
while (IsComma || (Tok.isNot(tok::r_paren) &&
Tok.isNot(tok::annot_pragma_openmp_end))) {
// Parse variable
ExprResult VarExpr = ParseAssignmentExpression();
if (VarExpr.isUsable()) {
Vars.push_back(VarExpr.take());
} else {
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
StopBeforeMatch);
}
// Skip ',' if any
IsComma = Tok.is(tok::comma);
if (IsComma) {
ConsumeToken();
} else if (Tok.isNot(tok::r_paren) &&
Tok.isNot(tok::annot_pragma_openmp_end)) {
Diag(Tok, diag::err_omp_expected_punc)
<< 1 << getOpenMPClauseName(Kind);
}
}
// Parse ')'.
T.consumeClose();
if (Vars.empty())
return 0;
return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen,
Tok.getLocation());
}