OpenMP threadprivate directive parsing and semantic analysis

llvm-svn: 177705
This commit is contained in:
Alexey Bataev 2013-03-22 06:34:35 +00:00
parent de0beaa8f8
commit a769e07232
44 changed files with 983 additions and 4 deletions

View File

@ -0,0 +1,83 @@
//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===//
//
// 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 defines OpenMP nodes.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_OPENMP_H
#define LLVM_CLANG_AST_OPENMP_H
#include "clang/AST/DeclBase.h"
#include "llvm/ADT/ArrayRef.h"
namespace clang {
class DeclRefExpr;
/// \brief This represents '#pragma omp threadprivate ...' directive.
/// For example, in the following, both 'a' and 'A::b' are threadprivate:
///
/// \code
/// int a;
/// #pragma omp threadprivate(a)
/// struct A {
/// static int b;
/// #pragma omp threadprivate(b)
/// };
/// \endcode
///
class OMPThreadPrivateDecl : public Decl {
friend class ASTDeclReader;
unsigned NumVars;
virtual void anchor();
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),
NumVars);
}
llvm::MutableArrayRef<DeclRefExpr *> getVars() {
return llvm::MutableArrayRef<DeclRefExpr *>(
reinterpret_cast<DeclRefExpr **>(this + 1),
NumVars);
}
void setVars(ArrayRef<DeclRefExpr *> VL);
public:
static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
ArrayRef<DeclRefExpr *> 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;
unsigned varlist_size() const { return NumVars; }
bool varlist_empty() const { return NumVars == 0; }
varlist_iterator varlist_begin() { return getVars().begin(); }
varlist_iterator varlist_end() { return getVars().end(); }
varlist_const_iterator varlist_begin() const { return getVars().begin(); }
varlist_const_iterator varlist_end() const { return getVars().end(); }
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == OMPThreadPrivate; }
};
} // end namespace clang
#endif

View File

@ -17,6 +17,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
namespace clang {

View File

@ -18,6 +18,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@ -1389,6 +1390,14 @@ DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
DEF_TRAVERSE_DECL(UsingShadowDecl, { })
DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
I != E; ++I) {
TRY_TO(TraverseStmt(*I));
}
})
// A helper method for TemplateDecl's children.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(

View File

@ -74,5 +74,6 @@ def StaticAssert : Decl;
def Block : Decl, DeclContext;
def ClassScopeFunctionSpecialization : Decl;
def Import : Decl;
def OMPThreadPrivate : Decl;
def Empty : Decl;

View File

@ -517,3 +517,6 @@ def ASMOperandWidths : DiagGroup<"asm-operand-widths">;
def ASM : DiagGroup<"asm", [
ASMOperandWidths
]>;
// OpenMP warnings.
def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;

View File

@ -772,7 +772,18 @@ def err_seh___except_filter : Error<
def err_seh___finally_block : Error<
"%0 only allowed in __finally block">;
// OpenMP support.
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">,
InGroup<ExtraTokens>;
def err_omp_unknown_directive : Error <
"expected an OpenMP directive">;
def err_omp_unexpected_directive : Error <
"unexpected OpenMP directive '#pragma omp %0'">;
} // end of Parse Issue category.
let CategoryName = "Modules Issue" in {

View File

@ -6195,6 +6195,22 @@ def err_sampler_argument_required : Error<
def err_wrong_sampler_addressspace: Error<
"sampler type cannot be used with the __local and __global address space qualifiers">;
// 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">;
def err_omp_var_scope : Error<
"'#pragma omp %0' must appear in the scope of the %1 variable declaration">;
def err_omp_var_used : Error<
"'#pragma omp %0' must precede all references to variable %1">;
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
let CategoryName = "Related Result Type Issue" in {

View File

@ -0,0 +1,23 @@
//===--- OpenMPKinds.def - OpenMP directives and clauses list ---*- C++ -*-===//
//
// 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 defines the list of supported OpenMP directives and
/// clauses.
///
//===----------------------------------------------------------------------===//
#ifndef OPENMP_DIRECTIVE
# define OPENMP_DIRECTIVE(Name)
#endif
// OpenMP directives.
OPENMP_DIRECTIVE(threadprivate)
OPENMP_DIRECTIVE(parallel)
#undef OPENMP_DIRECTIVE

View File

@ -0,0 +1,37 @@
//===--- OpenMPKinds.h - OpenMP enums ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Defines some OpenMP-specific enums and functions.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_OPENMPKINDS_H
#define LLVM_CLANG_BASIC_OPENMPKINDS_H
#include "clang/Lex/Token.h"
namespace clang {
/// \brief OpenMP directives.
enum OpenMPDirectiveKind {
OMPD_unknown = 0,
#define OPENMP_DIRECTIVE(Name) \
OMPD_##Name,
#include "clang/Basic/OpenMPKinds.def"
NUM_OPENMP_DIRECTIVES
};
OpenMPDirectiveKind getOpenMPDirectiveKind(StringRef Str);
const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind);
}
#endif

View File

@ -646,6 +646,12 @@ ANNOTATION(pragma_fp_contract)
// handles them.
ANNOTATION(pragma_opencl_extension)
// Annotations for OpenMP pragma directives - #pragma omp ...
// The lexer produces these so that they only take effect when the parser
// handles #pragma omp ... directives.
ANNOTATION(pragma_openmp)
ANNOTATION(pragma_openmp_end)
#undef ANNOTATION
#undef TESTING_KEYWORD
#undef OBJC2_AT_KEYWORD

View File

@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_PARSE_PARSER_H
#define LLVM_CLANG_PARSE_PARSER_H
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/OperatorPrecedence.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/CodeCompletionHandler.h"
@ -147,6 +148,7 @@ class Parser : public CodeCompletionHandler {
OwningPtr<PragmaHandler> FPContractHandler;
OwningPtr<PragmaHandler> OpenCLExtensionHandler;
OwningPtr<CommentHandler> CommentSemaHandler;
OwningPtr<PragmaHandler> OpenMPHandler;
/// Whether the '>' token acts as an operator or not. This will be
/// true except when we are parsing an expression within a C++
@ -2104,6 +2106,11 @@ private:
ParsedType ObjectType,
UnqualifiedId &Result);
//===--------------------------------------------------------------------===//
// OpenMP: Directives and clauses.
DeclGroupPtrTy ParseOpenMPDeclarativeDirective();
bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
SmallVectorImpl<DeclarationNameInfo> &IdList);
public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,

View File

@ -132,6 +132,7 @@ namespace clang {
class ObjCMethodDecl;
class ObjCPropertyDecl;
class ObjCProtocolDecl;
class OMPThreadPrivateDecl;
class OverloadCandidateSet;
class OverloadExpr;
class ParenListExpr;
@ -6592,6 +6593,18 @@ public:
void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T,
unsigned SpellingListIndex, bool IsPackExpansion);
// OpenMP directives and clauses.
/// \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.
OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl(
SourceLocation Loc,
ArrayRef<DeclRefExpr *> VarList);
/// \brief The kind of conversion being performed.
enum CheckedConversionKind {
/// \brief An implicit conversion.

View File

@ -430,6 +430,7 @@ namespace clang {
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
Decl *VisitClassScopeFunctionSpecializationDecl(
ClassScopeFunctionSpecializationDecl *D);
Decl *VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *D) {

View File

@ -1036,6 +1036,8 @@ namespace clang {
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
/// \brief An ImportDecl recording a module import.
DECL_IMPORT,
/// \brief A OMPThreadPrivateDecl record.
DECL_OMP_THREADPRIVATE,
/// \brief An EmptyDecl record.
DECL_EMPTY
};

View File

@ -22,6 +22,7 @@ add_clang_library(clangAST
DeclFriend.cpp
DeclGroup.cpp
DeclObjC.cpp
DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
DumpXML.cpp

View File

@ -20,6 +20,7 @@
#include "clang/AST/DeclContextInternals.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/DependentDiagnostic.h"
#include "clang/AST/ExternalASTSource.h"
@ -561,6 +562,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCategory:
case ObjCCategoryImpl:
case Import:
case OMPThreadPrivate:
case Empty:
// Never looked up by name.
return 0;

View File

@ -0,0 +1,60 @@
//===--- DeclOpenMP.cpp - Declaration OpenMP AST Node Implementation ------===//
//
// 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 OMPThreadPrivateDecl class.
///
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/Expr.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// OMPThreadPrivateDecl Implementation.
//===----------------------------------------------------------------------===//
void OMPThreadPrivateDecl::anchor() { }
OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
ArrayRef<DeclRefExpr *> VL) {
unsigned Size = sizeof(OMPThreadPrivateDecl) +
(VL.size() * sizeof(DeclRefExpr *));
void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
DC, L);
D->NumVars = VL.size();
D->setVars(VL);
return D;
}
OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned N) {
unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *));
void *Mem = AllocateDeserializedDecl(C, ID, Size);
OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
0, SourceLocation());
D->NumVars = N;
return D;
}
void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
assert(VL.size() == NumVars &&
"Number of variables is not the same as the preallocated buffer");
DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
std::copy(VL.begin(), VL.end(), Vars);
}

View File

@ -82,6 +82,7 @@ namespace {
void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitUsingDecl(UsingDecl *D);
void VisitUsingShadowDecl(UsingShadowDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
void PrintTemplateParameters(const TemplateParameterList *Params,
const TemplateArgumentList *Args = 0);
@ -291,8 +292,10 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
// FIXME: Need to be able to tell the DeclPrinter when
const char *Terminator = 0;
if (isa<FunctionDecl>(*D) &&
cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
if (isa<OMPThreadPrivateDecl>(*D))
Terminator = 0;
else if (isa<FunctionDecl>(*D) &&
cast<FunctionDecl>(*D)->isThisDeclarationADefinition())
Terminator = 0;
else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody())
Terminator = 0;
@ -1150,3 +1153,17 @@ void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
// ignore
}
void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
Out << "#pragma omp threadprivate";
if (!D->varlist_empty()) {
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
I != E; ++I) {
Out << (I == D->varlist_begin() ? '(' : ',')
<< *cast<NamedDecl>((*I)->getDecl());
}
Out << ")";
}
}

View File

@ -11,6 +11,7 @@ add_clang_library(clangBasic
LangOptions.cpp
Module.cpp
ObjCRuntime.cpp
OpenMPKinds.cpp
OperatorPrecedence.cpp
SourceLocation.cpp
SourceManager.cpp

View File

@ -0,0 +1,43 @@
//===--- OpenMPKinds.cpp - Token Kinds Support ----------------------------===//
//
// 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 the OpenMP enum and support functions.
///
//===----------------------------------------------------------------------===//
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
using namespace clang;
OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) {
return llvm::StringSwitch<OpenMPDirectiveKind>(Str)
#define OPENMP_DIRECTIVE(Name) \
.Case(#Name, OMPD_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPD_unknown);
}
const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) {
assert(Kind < NUM_OPENMP_DIRECTIVES);
switch (Kind) {
case OMPD_unknown:
return ("unknown");
#define OPENMP_DIRECTIVE(Name) \
case OMPD_##Name : return #Name;
#include "clang/Basic/OpenMPKinds.def"
default:
break;
}
llvm_unreachable("Invalid OpenMP directive kind");
}

View File

@ -83,6 +83,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::StaticAssert: // static_assert(X, ""); [C++0x]
case Decl::Label: // __label__ x;
case Decl::Import:
case Decl::OMPThreadPrivate:
case Decl::Empty:
// None of these decls require codegen support.
return;

View File

@ -463,6 +463,10 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "<class template> " << *CTD << '\n';
break;
}
case Decl::OMPThreadPrivate: {
Out << "<omp threadprivate> " << '"' << *I << "\"\n";
break;
}
default:
Out << "DeclKind: " << DK << '"' << *I << "\"\n";
llvm_unreachable("decl unhandled");

View File

@ -7,6 +7,7 @@ add_clang_library(clangParse
ParseExprCXX.cpp
ParseInit.cpp
ParseObjc.cpp
ParseOpenMP.cpp
ParsePragma.cpp
ParseStmt.cpp
ParseTemplate.cpp

View File

@ -2525,6 +2525,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
continue;
}
if (Tok.is(tok::annot_pragma_openmp)) {
ParseOpenMPDeclarativeDirective();
continue;
}
AccessSpecifier AS = getAccessSpecifierIfPresent();
if (AS != AS_none) {
// Current token is a C++ access specifier.

View File

@ -0,0 +1,118 @@
//===--- 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/Parse/Parser.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "RAIIObjectsForParser.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// OpenMP declarative directives.
//===----------------------------------------------------------------------===//
/// \brief Parses OpenMP declarative directive
/// 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) {
case OMPD_threadprivate:
ConsumeToken();
if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) {
// 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, false, true);
}
ConsumeToken();
return Actions.ActOnOpenMPThreadprivateDirective(Loc,
getCurScope(),
Identifiers);
}
break;
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
default:
Diag(Tok, diag::err_omp_unexpected_directive)
<< getOpenMPDirectiveName(Kind);
break;
}
SkipUntil(tok::annot_pragma_openmp_end, false);
return DeclGroupPtrTy();
}
/// \brief Parses list of simple variables for '#pragma omp threadprivate'
/// directive
/// simple-variable-list:
/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end
///
bool Parser::ParseOpenMPSimpleVarList(
OpenMPDirectiveKind Kind,
SmallVectorImpl<DeclarationNameInfo> &IdList) {
// 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;
}
// Read tokens while ')' or annot_pragma_openmp_end is not found.
do {
CXXScopeSpec SS;
SourceLocation TemplateKWLoc;
UnqualifiedId Name;
// Read var name.
Token PrevTok = Tok;
if (ParseUnqualifiedId(SS, false, false, false, ParsedType(),
TemplateKWLoc, Name)) {
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)) {
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
<< SourceRange(PrevTok.getLocation(), PrevTokLocation);
} else {
IdList.push_back(Actions.GetNameFromUnqualifiedId(Name));
}
// 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();
}

View File

@ -718,3 +718,47 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP,
/*OwnsTokens=*/false);
}
/// \brief Handle '#pragma omp ...' when OpenMP is disabled.
///
void
PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &FirstTok) {
if (PP.getDiagnostics().getDiagnosticLevel(diag::warn_pragma_omp_ignored,
FirstTok.getLocation()) !=
DiagnosticsEngine::Ignored) {
PP.Diag(FirstTok, diag::warn_pragma_omp_ignored);
PP.getDiagnostics().setDiagnosticMapping(diag::warn_pragma_omp_ignored,
diag::MAP_IGNORE,
SourceLocation());
}
PP.DiscardUntilEndOfDirective();
}
/// \brief Handle '#pragma omp ...' when OpenMP is enabled.
///
void
PragmaOpenMPHandler::HandlePragma(Preprocessor &PP,
PragmaIntroducerKind Introducer,
Token &FirstTok) {
SmallVector<Token, 16> Pragma;
Token Tok;
Tok.startToken();
Tok.setKind(tok::annot_pragma_openmp);
Tok.setLocation(FirstTok.getLocation());
while (Tok.isNot(tok::eod)) {
Pragma.push_back(Tok);
PP.Lex(Tok);
}
SourceLocation EodLoc = Tok.getLocation();
Tok.startToken();
Tok.setKind(tok::annot_pragma_openmp_end);
Tok.setLocation(EodLoc);
Pragma.push_back(Tok);
Token *Toks = new Token[Pragma.size()];
std::copy(Pragma.begin(), Pragma.end(), Toks);
PP.EnterTokenStream(Toks, Pragma.size(),
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
}

View File

@ -98,7 +98,20 @@ public:
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaNoOpenMPHandler : public PragmaHandler {
public:
PragmaNoOpenMPHandler() : PragmaHandler("omp") { }
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
class PragmaOpenMPHandler : public PragmaHandler {
public:
PragmaOpenMPHandler() : PragmaHandler("omp") { }
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
Token &FirstToken);
};
} // end namespace clang

View File

@ -288,6 +288,11 @@ Retry:
ProhibitAttributes(Attrs);
HandlePragmaOpenCLExtension();
return StmtEmpty();
case tok::annot_pragma_openmp:
SourceLocation DeclStart = Tok.getLocation();
DeclGroupPtrTy Res = ParseOpenMPDeclarativeDirective();
return Actions.ActOnDeclStmt(Res, DeclStart, Tok.getLocation());
}
// If we reached this code, the statement must end in a semicolon.

View File

@ -96,6 +96,11 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
PP.AddPragmaHandler("OPENCL", FPContractHandler.get());
}
if (getLangOpts().OpenMP)
OpenMPHandler.reset(new PragmaOpenMPHandler());
else
OpenMPHandler.reset(new PragmaNoOpenMPHandler());
PP.AddPragmaHandler(OpenMPHandler.get());
CommentSemaHandler.reset(new ActionCommentHandler(actions));
PP.addCommentHandler(CommentSemaHandler.get());
@ -428,6 +433,8 @@ Parser::~Parser() {
OpenCLExtensionHandler.reset();
PP.RemovePragmaHandler("OPENCL", FPContractHandler.get());
}
PP.RemovePragmaHandler(OpenMPHandler.get());
OpenMPHandler.reset();
PP.RemovePragmaHandler("STDC", FPContractHandler.get());
FPContractHandler.reset();
@ -624,6 +631,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs,
case tok::annot_pragma_opencl_extension:
HandlePragmaOpenCLExtension();
return DeclGroupPtrTy();
case tok::annot_pragma_openmp:
ParseOpenMPDeclarativeDirective();
return DeclGroupPtrTy();
case tok::semi:
// Either a C++11 empty-declaration or attribute-declaration.
SingleDecl = Actions.ActOnEmptyDeclaration(getCurScope(),

View File

@ -38,6 +38,7 @@ add_clang_library(clangSema
SemaLambda.cpp
SemaLookup.cpp
SemaObjCProperty.cpp
SemaOpenMP.cpp
SemaOverload.cpp
SemaPseudoObject.cpp
SemaStmt.cpp

View File

@ -0,0 +1,181 @@
//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ----------===//
//
// 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 semantic analysis for OpenMP directives and
/// clauses
///
//===----------------------------------------------------------------------===//
#include "clang/Basic/OpenMPKinds.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Lookup.h"
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;
}
}
// 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);
}
if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) {
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
return DeclGroupPtrTy();
}
OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
SourceLocation Loc,
ArrayRef<DeclRefExpr *> VarList) {
SmallVector<DeclRefExpr *, 5> Vars;
for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(),
E = VarList.end();
I != E; ++I) {
VarDecl *VD = cast<VarDecl>((*I)->getDecl());
SourceLocation ILoc = (*I)->getLocation();
// 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)) {
continue;
}
// OpenMP [2.9.2, Restrictions, C/C++, p.10]
// 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;
continue;
}
// Check if threadspecified is set.
if (VD->isThreadSpecified()) {
Diag(ILoc, diag::err_omp_var_thread_local) << VD;
Diag(VD->getLocation(), diag::note_forward_declaration) << VD;
continue;
}
Vars.push_back(*I);
}
return Vars.empty() ?
0 : OMPThreadPrivateDecl::Create(Context,
getCurLexicalContext(),
Loc, Vars);
}

View File

@ -2183,6 +2183,23 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
return NewFD;
}
Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
OMPThreadPrivateDecl *D) {
SmallVector<DeclRefExpr *, 5> Vars;
for (ArrayRef<DeclRefExpr *>::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));
}
OMPThreadPrivateDecl *TD =
SemaRef.CheckOMPThreadPrivateDecl(D->getLocation(), Vars);
return TD;
}
Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs) {
TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);

View File

@ -204,6 +204,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Block:
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
return false;
}

View File

@ -289,6 +289,7 @@ namespace clang {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
};
}
@ -1626,6 +1627,17 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable<T> *D,
}
}
void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
VisitDecl(D);
unsigned NumVars = D->varlist_size();
SmallVector<DeclRefExpr *, 16> Vars;
Vars.reserve(NumVars);
for (unsigned i = 0; i != NumVars; ++i) {
Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F)));
}
D->setVars(Vars);
}
//===----------------------------------------------------------------------===//
// Attribute Reading
//===----------------------------------------------------------------------===//
@ -2134,6 +2146,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
// locations.
D = ImportDecl::CreateDeserialized(Context, ID, Record.back());
break;
case DECL_OMP_THREADPRIVATE:
D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]);
break;
case DECL_EMPTY:
D = EmptyDecl::CreateDeserialized(Context, ID);
break;

View File

@ -123,6 +123,7 @@ namespace clang {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D);
};
}
@ -1314,6 +1315,16 @@ void ASTDeclWriter::VisitRedeclarable(Redeclarable<T> *D) {
}
void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
Record.push_back(D->varlist_size());
VisitDecl(D);
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
I != E; ++I)
Writer.AddStmt(*I);
Code = serialization::DECL_OMP_THREADPRIVATE;
}
//===----------------------------------------------------------------------===//
// ASTWriter Implementation
//===----------------------------------------------------------------------===//

View File

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -verify -o - %s
// expected-no-diagnostics
int a;
#pragma omp threadprivate(a,b)
#pragma omp parallel

View File

@ -0,0 +1,6 @@
// RUN: %clang_cc1 -verify -Wno-source-uses-openmp -o - %s
// expected-no-diagnostics
int a;
#pragma omp threadprivate(a,b)
#pragma omp parallel

View File

@ -0,0 +1,9 @@
// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s
#pragma omp // expected-error {{expected an OpenMP directive}}
#pragma omp unknown_directive // expected-error {{expected an OpenMP directive}}
void foo() {
#pragma omp // expected-error {{expected an OpenMP directive}}
#pragma omp unknown_directive // expected-error {{expected an OpenMP directive}}
}

View File

@ -0,0 +1,5 @@
// RUN: %clang_cc1 -verify -Wsource-uses-openmp -o - %s
int a;
#pragma omp threadprivate(a,b) // expected-warning {{unexpected '#pragma omp ...' in program}}
#pragma omp parallel

View File

@ -1,3 +1,20 @@
// RUN: %clang_cc1 -fopenmp -verify -DFOPENMP -o - %s
// RUN: %clang_cc1 -verify -o - %s
// expected-no-diagnostics
#ifdef FOPENMP
// -fopenmp option is specified
#ifndef _OPENMP
#error "No _OPENMP macro is defined with -fopenmp option"
#elsif _OPENMP != 201107
#error "_OPENMP has incorrect value"
#endif //_OPENMP
#else
// No -fopenmp option is specified
#ifdef _OPENMP
#error "_OPENMP macro is defined without -fopenmp option"
#endif // _OPENMP
#endif // FOPENMP
// RUN: %clang_cc1 -fopenmp -verify -DFOPENMP -o - %s
// RUN: %clang_cc1 -verify -o - %s
// expected-no-diagnostics

View File

@ -0,0 +1,43 @@
// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
// expected-no-diagnostics
struct St{
int a;
};
struct St1{
int a;
static int b;
// CHECK: static int b;
#pragma omp threadprivate(b)
// CHECK-NEXT: #pragma omp threadprivate(b)
} d;
int a, b;
// CHECK: int a;
// CHECK: int b;
#pragma omp threadprivate(a)
// CHECK-NEXT: #pragma omp threadprivate(a)
#pragma omp threadprivate(d, b)
// CHECK-NEXT: #pragma omp threadprivate(d,b)
template <class T> T foo() {
static T v;
#pragma omp threadprivate(v)
return v;
}
//CHECK: template <class T = int> int foo() {
//CHECK-NEXT: static int v;
//CHECK-NEXT: #pragma omp threadprivate(v)
//CHECK: template <class T> T foo() {
//CHECK-NEXT: static T v;
//CHECK-NEXT: #pragma omp threadprivate(v)
int main () {
static int a;
// CHECK: static int a;
#pragma omp threadprivate(a)
// CHECK-NEXT: #pragma omp threadprivate(a)
a=2;
return (foo<int>());
}

View File

@ -0,0 +1,119 @@
// 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(1) // expected-error {{expected unqualified-id}}
struct CompleteSt{
int a;
};
struct CompleteSt1{
#pragma omp threadprivate(1) // expected-error {{expected unqualified-id}}
int a;
} d; // expected-note {{forward declaration of 'd'}}
int a; // expected-note {{forward declaration of 'a'}}
#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}}
return (a);
}
#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}}
#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))
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(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((float)a) // expected-error {{expected unqualified-id}}
int foa;
#pragma omp threadprivate(faa) // expected-error {{use of undeclared identifier 'faa'; did you mean 'foa'?}}
#pragma omp threadprivate(foo) // expected-error {{'foo' is not a global variable, static local variable or static data member}}
#pragma omp threadprivate (int a=2) // expected-error {{expected unqualified-id}}
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'}}
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 &'}}
class Class {
private:
int a; // expected-note {{declared here}}
static int b;
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 (g)
namespace ns {
int m;
#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}}
const int h = 12;
const volatile int i = 10;
#pragma omp threadprivate (h, i)
template <class T>
class TempClass {
private:
T a;
TempClass() : a(){}
public:
TempClass (T aaa) : a(aaa) {}
static T s;
#pragma omp threadprivate (s)
};
#pragma omp threadprivate (s) // expected-error {{use of undeclared identifier 's'}}
static __thread int t; // expected-note {{forward declaration of 't'}}
#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'}}
namespace {
int o; // expected-note {{candidate found by name lookup is '<anonymous namespace>::o'}}
}
#pragma omp threadprivate (o) // expected-error {{reference to 'o' is ambiguous}}
int main(int argc, char **argv) { // expected-note {{forward declaration of 'argc'}}
int x, y = argc; // expected-note {{forward declaration of 'y'}}
static double d1;
static double d2;
static double d3; // expected-note {{forward declaration of 'd3'}}
d.a = a;
d2++;
;
#pragma omp threadprivate(argc+y) // expected-error {{expected unqualified-id}}
#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)
{
++a;d2=0;
#pragma omp threadprivate(d3) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'd3' variable declaration}}
}
#pragma omp threadprivate(d3)
#pragma omp threadprivate(a) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'a' variable declaration}}
return (y);
#pragma omp threadprivate(d) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'd' variable declaration}}
}

View File

@ -4458,6 +4458,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
case Decl::Label: // FIXME: Is this right??
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
case Decl::OMPThreadPrivate:
return C;
// Declaration kinds that don't make any sense here, but are

View File

@ -18,6 +18,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclFriend.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
@ -1325,6 +1326,14 @@ DEF_TRAVERSE_DECL(UsingDirectiveDecl, {
DEF_TRAVERSE_DECL(UsingShadowDecl, { })
DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, {
for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(),
E = D->varlist_end();
I != E; ++I) {
TRY_TO(TraverseStmt(*I));
}
})
// A helper method for TemplateDecl's children.
template<typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper(