OpenMP threadprivate with qualified names.

llvm-svn: 181683
This commit is contained in:
Alexey Bataev 2013-05-13 04:18:18 +00:00
parent bc60196951
commit 6f6f3b4baf
16 changed files with 282 additions and 234 deletions

View File

@ -1,4 +1,4 @@
//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===//
//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file defines OpenMP nodes.
/// \brief This file defines OpenMP nodes for declarative directives.
///
//===----------------------------------------------------------------------===//
@ -20,8 +20,6 @@
namespace clang {
class DeclRefExpr;
/// \brief This represents '#pragma omp threadprivate ...' directive.
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
///
@ -43,29 +41,29 @@ class OMPThreadPrivateDecl : public Decl {
OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) :
Decl(DK, DC, L), NumVars(0) { }
ArrayRef<const DeclRefExpr *> getVars() const {
return ArrayRef<const DeclRefExpr *>(
reinterpret_cast<const DeclRefExpr * const *>(this + 1),
ArrayRef<const Expr *> getVars() const {
return ArrayRef<const Expr *>(
reinterpret_cast<const Expr * const *>(this + 1),
NumVars);
}
llvm::MutableArrayRef<DeclRefExpr *> getVars() {
return llvm::MutableArrayRef<DeclRefExpr *>(
reinterpret_cast<DeclRefExpr **>(this + 1),
llvm::MutableArrayRef<Expr *> getVars() {
return llvm::MutableArrayRef<Expr *>(
reinterpret_cast<Expr **>(this + 1),
NumVars);
}
void setVars(ArrayRef<DeclRefExpr *> VL);
void setVars(ArrayRef<Expr *> VL);
public:
static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
ArrayRef<DeclRefExpr *> VL);
ArrayRef<Expr *> VL);
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
unsigned ID, unsigned N);
typedef llvm::MutableArrayRef<DeclRefExpr *>::iterator varlist_iterator;
typedef ArrayRef<const DeclRefExpr *>::iterator varlist_const_iterator;
typedef llvm::MutableArrayRef<Expr *>::iterator varlist_iterator;
typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
unsigned varlist_size() const { return NumVars; }
bool varlist_empty() const { return NumVars == 0; }

View File

@ -819,13 +819,14 @@ def err_seh___finally_block : Error<
def warn_pragma_omp_ignored : Warning <
"unexpected '#pragma omp ...' in program">, InGroup<SourceUsesOpenMP>, DefaultIgnore;
def warn_omp_extra_tokens_at_eol : Warning <
"extra tokens at end of '#pragma omp %0' are ignored">,
"extra tokens at the end of '#pragma omp %0' are ignored">,
InGroup<ExtraTokens>;
def err_omp_unknown_directive : Error <
"expected an OpenMP directive">;
def err_omp_unexpected_directive : Error <
"unexpected OpenMP directive '#pragma omp %0'">;
def err_omp_expected_var : Error <
"expected '#pragma omp %0' argument to be a variable name">;
} // end of Parse Issue category.
let CategoryName = "Modules Issue" in {

View File

@ -6336,24 +6336,26 @@ def err_wrong_sampler_addressspace: Error<
"sampler type cannot be used with the __local and __global address space qualifiers">;
def err_opencl_global_invalid_addr_space : Error<
"global variables must have a constant address space qualifier">;
} // end of sema category
let CategoryName = "OpenMP Issue" in {
// OpenMP support.
def err_omp_expected_var_arg_suggest : Error<
"%0 is not a global variable, static local variable or static data member%select{|; did you mean %2?}1">;
def err_omp_global_var_arg : Error<
"arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">;
def err_omp_ref_type_arg : Error<
"arguments of '#pragma omp %0' cannot be of reference type %1">;
"arguments of '#pragma omp %0' cannot be of reference type">;
def err_omp_var_scope : Error<
"'#pragma omp %0' must appear in the scope of the %1 variable declaration">;
"'#pragma omp %0' must appear in the scope of the %q1 variable declaration">;
def err_omp_var_used : Error<
"'#pragma omp %0' must precede all references to variable %1">;
"'#pragma omp %0' must precede all references to variable %q1">;
def err_omp_var_thread_local : Error<
"variable %0 cannot be threadprivate because it is thread-local">;
def err_omp_incomplete_type : Error<
"a threadprivate variable must not have incomplete type %0">;
} // end of sema category
def err_omp_threadprivate_incomplete_type : Error<
"threadprivate variable with incomplete type %0">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {
// Objective-C related result type compatibility

View File

@ -2138,9 +2138,18 @@ private:
//===--------------------------------------------------------------------===//
// OpenMP: Directives and clauses.
/// \brief Parses declarative OpenMP directives.
DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
/// \brief Parses simple list of variables.
///
/// \param Kind Kind of the directive.
/// \param [out] VarList List of referenced variables.
/// \param AllowScopeSpecifier true, if the variables can have fully
/// qualified names.
///
bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
SmallVectorImpl<DeclarationNameInfo> &IdList);
SmallVectorImpl<Expr *> &VarList,
bool AllowScopeSpecifier);
public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,

View File

@ -6682,16 +6682,19 @@ public:
unsigned SpellingListIndex, bool IsPackExpansion);
// OpenMP directives and clauses.
/// \brief Called on correct id-expression from the '#pragma omp
/// threadprivate'.
ExprResult ActOnOpenMPIdExpression(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
const DeclarationNameInfo &Id);
/// \brief Called on well-formed '#pragma omp threadprivate'.
DeclGroupPtrTy ActOnOpenMPThreadprivateDirective(
SourceLocation Loc,
Scope *CurScope,
ArrayRef<DeclarationNameInfo> IdList);
/// \brief Build a new OpenMPThreadPrivateDecl and check its correctness.
SourceLocation Loc,
ArrayRef<Expr *> VarList);
// \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness.
OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(
SourceLocation Loc,
ArrayRef<DeclRefExpr *> VarList);
SourceLocation Loc,
ArrayRef<Expr *> VarList);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {

View File

@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { }
OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
ArrayRef<DeclRefExpr *> VL) {
ArrayRef<Expr *> VL) {
unsigned Size = sizeof(OMPThreadPrivateDecl) +
(VL.size() * sizeof(DeclRefExpr *));
(VL.size() * sizeof(Expr *));
void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned N) {
unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *));
void *Mem = AllocateDeserializedDecl(C, ID, Size);
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@ -52,9 +52,9 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
return D;
}
void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
assert(VL.size() == NumVars &&
"Number of variables is not the same as the preallocated buffer");
DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
Expr **Vars = reinterpret_cast<Expr **>(this + 1);
std::copy(VL.begin(), VL.end(), Vars);
}

View File

@ -1180,9 +1180,9 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
if (!D->varlist_empty()) {
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
I != E; ++I) {
I != E; ++I) {
Out << (I == D->varlist_begin() ? '(' : ',')
<< *cast<NamedDecl>((*I)->getDecl());
<< *cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
}
Out << ")";
}

View File

@ -32,7 +32,7 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
assert(Kind < NUM_OPENMP_DIRECTIVES);
switch (Kind) {
case OMPD_unknown:
return ("unknown");
return "unknown";
#define OPENMP_DIRECTIVE(Name) \
case OMPD_##Name : return #Name;
#include "clang/Basic/OpenMPKinds.def"
@ -41,3 +41,4 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
}
llvm_unreachable("Invalid OpenMP directive kind");
}

View File

@ -12,8 +12,10 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTConsumer.h"
#include "clang/Parse/Parser.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;
@ -21,22 +23,24 @@ using namespace clang;
// OpenMP declarative directives.
//===----------------------------------------------------------------------===//
/// \brief Parses OpenMP declarative directive
/// threadprivate-directive
/// annot_pragma_openmp threadprivate simple-variable-list
/// \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!");
SourceLocation Loc = ConsumeToken();
SmallVector<DeclarationNameInfo, 5> Identifiers;
OpenMPDirectiveKind Kind = Tok.isAnnotation() ?
OMPD_unknown :
getOpenMPDirectiveKind(PP.getSpelling(Tok));
switch(Kind) {
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)) {
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)) {
@ -44,9 +48,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
<< getOpenMPDirectiveName(OMPD_threadprivate);
SkipUntil(tok::annot_pragma_openmp_end, false, true);
}
// Skip the last annot_pragma_openmp_end.
ConsumeToken();
return Actions.ActOnOpenMPThreadprivateDirective(Loc,
getCurScope(),
Identifiers);
}
break;
@ -55,7 +59,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
break;
default:
Diag(Tok, diag::err_omp_unexpected_directive)
<< getOpenMPDirectiveName(Kind);
<< getOpenMPDirectiveName(DKind);
break;
}
SkipUntil(tok::annot_pragma_openmp_end, false);
@ -63,56 +67,69 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() {
}
/// \brief Parses list of simple variables for '#pragma omp threadprivate'
/// directive
/// simple-variable-list:
/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end
/// directive.
///
bool Parser::ParseOpenMPSimpleVarList(
OpenMPDirectiveKind Kind,
SmallVectorImpl<DeclarationNameInfo> &IdList) {
/// simple-variable-list:
/// '(' id-expression {, id-expression} ')'
///
bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
SmallVectorImpl<Expr *> &VarList,
bool AllowScopeSpecifier) {
VarList.clear();
// Parse '('.
bool IsCorrect = true;
BalancedDelimiterTracker T(*this, tok::l_paren);
if (T.expectAndConsume(diag::err_expected_lparen_after,
getOpenMPDirectiveName(Kind))) {
SkipUntil(tok::annot_pragma_openmp_end, false, true);
return false;
}
BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
bool LParen = !T.expectAndConsume(diag::err_expected_lparen_after,
getOpenMPDirectiveName(Kind));
bool IsCorrect = LParen;
bool NoIdentIsFound = true;
// Read tokens while ')' or annot_pragma_openmp_end is not found.
do {
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 (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
TemplateKWLoc, Name)) {
if (AllowScopeSpecifier && getLangOpts().CPlusPlus &&
ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
false, true);
}
else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) &&
Tok.isNot(tok::annot_pragma_openmp_end)) {
} else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
TemplateKWLoc, Name)) {
IsCorrect = false;
SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
false, true);
Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id)
<< getLangOpts().CPlusPlus
} 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,
false, true);
Diag(PrevTok.getLocation(), diag::err_expected_ident)
<< SourceRange(PrevTok.getLocation(), PrevTokLocation);
} else {
IdList.push_back(Actions.GetNameFromUnqualifiedId(Name));
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();
}
} while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
if (IsCorrect || Tok.is(tok::r_paren)) {
IsCorrect = !T.consumeClose() && IsCorrect;
}
return !IsCorrect && IdList.empty();
if (NoIdentIsFound) {
Diag(Tok, diag::err_expected_ident);
IsCorrect = false;
}
// Parse ')'.
IsCorrect = ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose())
&& IsCorrect;
return !IsCorrect && VarList.empty();
}

View File

@ -1897,7 +1897,7 @@ bool BalancedDelimiterTracker::diagnoseOverflow() {
P.Diag(P.Tok, diag::err_bracket_depth_exceeded)
<< P.getLangOpts().BracketDepth;
P.Diag(P.Tok, diag::note_bracket_depth);
P.SkipUntil(tok::eof);
P.SkipUntil(tok::eof, FinalToken);
return true;
}
@ -1927,7 +1927,8 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() {
}
P.Diag(P.Tok, DID);
P.Diag(LOpen, diag::note_matching) << LHSName;
if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true))
if (P.SkipUntil(Close, FinalToken, /*StopAtSemi*/ true, /*DontConsume*/ true)
&& P.Tok.is(Close))
LClose = P.ConsumeAnyToken();
return true;
}

View File

@ -358,7 +358,7 @@ namespace clang {
/// pair, such as braces { ... } or parentheses ( ... ).
class BalancedDelimiterTracker : public GreaterThanIsOperatorScope {
Parser& P;
tok::TokenKind Kind, Close;
tok::TokenKind Kind, Close, FinalToken;
SourceLocation (Parser::*Consumer)();
SourceLocation LOpen, LClose;
@ -377,9 +377,10 @@ namespace clang {
bool diagnoseMissingClose();
public:
BalancedDelimiterTracker(Parser& p, tok::TokenKind k)
BalancedDelimiterTracker(Parser& p, tok::TokenKind k,
tok::TokenKind FinalToken = tok::semi)
: GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true),
P(p), Kind(k)
P(p), Kind(k), FinalToken(FinalToken)
{
switch (Kind) {
default: llvm_unreachable("Unexpected balanced token");

View File

@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
/// \file
/// \brief This file implements semantic analysis for OpenMP directives and
/// clauses
/// clauses.
///
//===----------------------------------------------------------------------===//
@ -22,117 +22,121 @@ using namespace clang;
namespace {
class VarDeclFilterCCC : public CorrectionCandidateCallback {
private:
Sema &Actions;
public:
VarDeclFilterCCC(Sema &S) : Actions(S) { }
virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
NamedDecl *ND = Candidate.getCorrectionDecl();
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {
return VD->hasGlobalStorage() &&
Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
Actions.getCurScope());
}
return false;
}
};
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
SourceLocation Loc,
Scope *CurScope,
ArrayRef<DeclarationNameInfo> IdList) {
SmallVector<DeclRefExpr *, 5> Vars;
for (ArrayRef<DeclarationNameInfo>::iterator I = IdList.begin(),
E = IdList.end();
I != E; ++I) {
LookupResult Lookup(*this, *I, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, NULL, true);
if (Lookup.isAmbiguous())
continue;
VarDecl *VD;
if (!Lookup.isSingleResult()) {
VarDeclFilterCCC Validator(*this);
TypoCorrection Corrected = CorrectTypo(*I, LookupOrdinaryName, CurScope,
0, Validator);
std::string CorrectedStr = Corrected.getAsString(getLangOpts());
std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
if (Lookup.empty()) {
if (Corrected.isResolved()) {
Diag(I->getLoc(), diag::err_undeclared_var_use_suggest)
<< I->getName() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
} else {
Diag(I->getLoc(), diag::err_undeclared_var_use)
<< I->getName();
}
} else {
Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
<< I->getName() << Corrected.isResolved() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(I->getLoc(), CorrectedStr);
}
if (!Corrected.isResolved()) continue;
VD = Corrected.getCorrectionDeclAs<VarDecl>();
} else {
if (!(VD = Lookup.getAsSingle<VarDecl>())) {
Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest)
<< I->getName() << 0;
Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
continue;
}
class VarDeclFilterCCC : public CorrectionCandidateCallback {
private:
Sema &Actions;
public:
VarDeclFilterCCC(Sema &S) : Actions(S) { }
virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
NamedDecl *ND = Candidate.getCorrectionDecl();
if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) {
return VD->hasGlobalStorage() &&
Actions.isDeclInScope(ND, Actions.getCurLexicalContext(),
Actions.getCurScope());
}
// OpenMP [2.9.2, Syntax, C/C++]
// Variables must be file-scope, namespace-scope, or static block-scope.
if (!VD->hasGlobalStorage()) {
Diag(I->getLoc(), diag::err_omp_global_var_arg)
<< getOpenMPDirectiveName(OMPD_threadprivate)
<< !VD->isStaticLocal();
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
continue;
}
// OpenMP [2.9.2, Restrictions, C/C++, p.2]
// A threadprivate directive for file-scope variables must appear outside
// any definition or declaration.
// OpenMP [2.9.2, Restrictions, C/C++, p.3]
// A threadprivate directive for static class member variables must appear
// in the class definition, in the same scope in which the member
// variables are declared.
// OpenMP [2.9.2, Restrictions, C/C++, p.4]
// A threadprivate directive for namespace-scope variables must appear
// outside any definition or declaration other than the namespace
// definition itself.
// OpenMP [2.9.2, Restrictions, C/C++, p.6]
// A threadprivate directive for static block-scope variables must appear
// in the scope of the variable and not in a nested scope.
NamedDecl *ND = cast<NamedDecl>(VD);
if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
Diag(I->getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
continue;
}
// OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
// A threadprivate directive must lexically precede all references to any
// of the variables in its list.
if (VD->isUsed()) {
Diag(I->getLoc(), diag::err_omp_var_used)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
continue;
}
QualType ExprType = VD->getType().getNonReferenceType();
DeclRefExpr *Var = cast<DeclRefExpr>(BuildDeclRefExpr(VD,
ExprType,
VK_RValue,
I->getLoc()).take());
Vars.push_back(Var);
return false;
}
if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) {
};
}
ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
const DeclarationNameInfo &Id) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
if (Lookup.isAmbiguous())
return ExprError();
VarDecl *VD;
if (!Lookup.isSingleResult()) {
VarDeclFilterCCC Validator(*this);
TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
0, Validator);
std::string CorrectedStr = Corrected.getAsString(getLangOpts());
std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts());
if (Lookup.empty()) {
if (Corrected.isResolved()) {
Diag(Id.getLoc(), diag::err_undeclared_var_use_suggest)
<< Id.getName() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr);
} else {
Diag(Id.getLoc(), diag::err_undeclared_var_use)
<< Id.getName();
}
} else {
Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest)
<< Id.getName() << Corrected.isResolved() << CorrectedQuotedStr
<< FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr);
}
if (!Corrected.isResolved()) return ExprError();
VD = Corrected.getCorrectionDeclAs<VarDecl>();
} else {
if (!(VD = Lookup.getAsSingle<VarDecl>())) {
Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest)
<< Id.getName() << 0;
Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at);
return ExprError();
}
}
Lookup.suppressDiagnostics();
// OpenMP [2.9.2, Syntax, C/C++]
// Variables must be file-scope, namespace-scope, or static block-scope.
if (!VD->hasGlobalStorage()) {
Diag(Id.getLoc(), diag::err_omp_global_var_arg)
<< getOpenMPDirectiveName(OMPD_threadprivate)
<< !VD->isStaticLocal();
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.2]
// A threadprivate directive for file-scope variables must appear outside
// any definition or declaration.
// OpenMP [2.9.2, Restrictions, C/C++, p.3]
// A threadprivate directive for static class member variables must appear
// in the class definition, in the same scope in which the member
// variables are declared.
// OpenMP [2.9.2, Restrictions, C/C++, p.4]
// A threadprivate directive for namespace-scope variables must appear
// outside any definition or declaration other than the namespace
// definition itself.
// OpenMP [2.9.2, Restrictions, C/C++, p.6]
// A threadprivate directive for static block-scope variables must appear
// in the scope of the variable and not in a nested scope.
NamedDecl *ND = cast<NamedDecl>(VD);
if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
diag::note_defined_here) << VD;
return ExprError();
}
// OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
// A threadprivate directive must lexically precede all references to any
// of the variables in its list.
if (VD->isUsed()) {
Diag(Id.getLoc(), diag::err_omp_var_used)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD;
return ExprError();
}
QualType ExprType = VD->getType().getNonReferenceType();
ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc());
return DE;
}
Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
SourceLocation Loc,
ArrayRef<Expr *> VarList) {
if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
@ -141,18 +145,19 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective(
OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
SourceLocation Loc,
ArrayRef<DeclRefExpr *> VarList) {
SmallVector<DeclRefExpr *, 5> Vars;
for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(),
ArrayRef<Expr *> VarList) {
SmallVector<Expr *, 8> Vars;
for (ArrayRef<Expr *>::iterator I = VarList.begin(),
E = VarList.end();
I != E; ++I) {
VarDecl *VD = cast<VarDecl>((*I)->getDecl());
SourceLocation ILoc = (*I)->getLocation();
DeclRefExpr *DE = cast<DeclRefExpr>(*I);
VarDecl *VD = cast<VarDecl>(DE->getDecl());
SourceLocation ILoc = DE->getExprLoc();
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
// A threadprivate variable must not have an incomplete type.
if (RequireCompleteType(ILoc, VD->getType(),
diag::err_omp_incomplete_type)) {
diag::err_omp_threadprivate_incomplete_type)) {
continue;
}
@ -160,15 +165,21 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
// A threadprivate variable must not have a reference type.
if (VD->getType()->isReferenceType()) {
Diag(ILoc, diag::err_omp_ref_type_arg)
<< getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType();
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
<< getOpenMPDirectiveName(OMPD_threadprivate);
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
diag::note_defined_here) << VD;
continue;
}
// Check if this is a TLS variable.
if (VD->getTLSKind()) {
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
VarDecl::DeclarationOnly;
Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl :
diag::note_defined_here) << VD;
continue;
}
@ -179,3 +190,4 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
getCurLexicalContext(),
Loc, Vars);
}

View File

@ -2231,13 +2231,13 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
OMPThreadPrivateDecl *D) {
SmallVector<DeclRefExpr *, 5> Vars;
for (ArrayRef<DeclRefExpr *>::iterator I = D->varlist_begin(),
E = D->varlist_end();
SmallVector<Expr *, 5> Vars;
for (ArrayRef<Expr *>::iterator I = D->varlist_begin(),
E = D->varlist_end();
I != E; ++I) {
Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take();
assert(isa<DeclRefExpr>(Var) && "threadprivate arg is not a DeclRefExpr");
Vars.push_back(cast<DeclRefExpr>(Var));
Vars.push_back(Var);
}
OMPThreadPrivateDecl *TD =

View File

@ -1644,10 +1644,10 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
VisitDecl(D);
unsigned NumVars = D->varlist_size();
SmallVector<DeclRefExpr *, 16> Vars;
SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i) {
Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F)));
Vars.push_back(Reader.ReadExpr(F));
}
D->setVars(Vars);
}

View File

@ -31,4 +31,3 @@
#error "_OPENMP macro is defined without -fopenmp option"
#endif // _OPENMP
#endif // FOPENMP

View File

@ -1,8 +1,8 @@
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s
#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}}
#pragma omp threadprivate( // expected-error {{expected unqualified-id}}
#pragma omp threadprivate() // expected-error {{expected unqualified-id}}
#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} expected-error {{expected identifier}}
#pragma omp threadprivate( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp threadprivate() // expected-error {{expected identifier}}
#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
struct CompleteSt{
int a;
@ -11,27 +11,27 @@ struct CompleteSt{
struct CompleteSt1{
#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
int a;
} d; // expected-note {{forward declaration of 'd'}}
} d; // expected-note {{'d' defined here}}
int a; // expected-note {{forward declaration of 'a'}}
int a; // expected-note {{'a' defined here}}
#pragma omp threadprivate(a)
#pragma omp threadprivate(u) // expected-error {{use of undeclared identifier 'u'}}
#pragma omp threadprivate(d, a) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}}
int foo() { // expected-note {{declared here}}
static int l;
#pragma omp threadprivate(l)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(l)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
return (a);
}
#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}}
#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}}
#pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
#pragma omp threadprivate(d))
#pragma omp threadprivate(d)) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
int x, y;
#pragma omp threadprivate(x)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(y)), // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(x)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(y)), // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}}
#pragma omp threadprivate(a,d) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}}
#pragma omp threadprivate(d.a) // expected-error {{expected unqualified-id}}
#pragma omp threadprivate(d.a) // expected-error {{expected identifier}}
#pragma omp threadprivate((float)a) // expected-error {{expected unqualified-id}}
int foa;
#pragma omp threadprivate(faa) // expected-error {{use of undeclared identifier 'faa'; did you mean 'foa'?}}
@ -41,31 +41,31 @@ int foa;
struct IncompleteSt; // expected-note {{forward declaration of 'IncompleteSt'}}
extern IncompleteSt e;
#pragma omp threadprivate (e) // expected-error {{a threadprivate variable must not have incomplete type 'IncompleteSt'}}
#pragma omp threadprivate (e) // expected-error {{threadprivate variable with incomplete type 'IncompleteSt'}}
int &f = a; // expected-note {{forward declaration of 'f'}}
#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type 'int &'}}
int &f = a; // expected-note {{'f' defined here}}
#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type}}
class Class {
private:
int a; // expected-note {{declared here}}
static int b;
static int b; // expected-note {{'b' declared here}}
Class() : a(0){}
public:
Class (int aaa) : a(aaa) {}
#pragma omp threadprivate (b, a) // expected-error {{'a' is not a global variable, static local variable or static data member}}
} g(10);
#pragma omp threadprivate (b) // expected-error {{use of undeclared identifier 'b'}}
#pragma omp threadprivate (Class::b) // expected-error {{expected unqualified-id}}
#pragma omp threadprivate (Class::b) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'Class::b' variable declaration}}
#pragma omp threadprivate (g)
namespace ns {
int m;
int m; // expected-note 2 {{'m' defined here}}
#pragma omp threadprivate (m)
}
#pragma omp threadprivate (m) // expected-error {{use of undeclared identifier 'm'}}
#pragma omp threadprivate (ns::m) // expected-error {{expected unqualified-id}}
#pragma omp threadprivate (ns:m) // expected-error {{expected unqualified-id}}
#pragma omp threadprivate (ns::m) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'ns::m' variable declaration}}
#pragma omp threadprivate (ns:m) // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}} expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'ns::m' variable declaration}}
const int h = 12;
const volatile int i = 10;
@ -84,26 +84,30 @@ class TempClass {
};
#pragma omp threadprivate (s) // expected-error {{use of undeclared identifier 's'}}
static __thread int t; // expected-note {{forward declaration of 't'}}
static __thread int t; // expected-note {{'t' defined here}}
#pragma omp threadprivate (t) // expected-error {{variable 't' cannot be threadprivate because it is thread-local}}
int o; // expected-note {{candidate found by name lookup is 'o'}}
#pragma omp threadprivate (o)
namespace {
int o; // expected-note {{candidate found by name lookup is '<anonymous namespace>::o'}}
#pragma omp threadprivate (o)
#pragma omp threadprivate (o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable '<anonymous namespace>::o'}}
}
#pragma omp threadprivate (o) // expected-error {{reference to 'o' is ambiguous}}
#pragma omp threadprivate (::o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'o'}}
int main(int argc, char **argv) { // expected-note {{forward declaration of 'argc'}}
int main(int argc, char **argv) { // expected-note {{'argc' defined here}}
int x, y = argc; // expected-note {{forward declaration of 'y'}}
int x, y = argc; // expected-note {{'y' defined here}}
static double d1;
static double d2;
static double d3; // expected-note {{forward declaration of 'd3'}}
static double d3; // expected-note {{'d3' defined here}}
d.a = a;
d2++;
;
#pragma omp threadprivate(argc+y) // expected-error {{expected unqualified-id}}
#pragma omp threadprivate(argc+y) // expected-error {{expected identifier}}
#pragma omp threadprivate(argc,y) // expected-error 2 {{arguments of '#pragma omp threadprivate' must have static storage duration}}
#pragma omp threadprivate(d2) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd2'}}
#pragma omp threadprivate(d1)