summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Bataev <a.bataev@hotmail.com>2013-03-22 06:34:35 +0000
committerAlexey Bataev <a.bataev@hotmail.com>2013-03-22 06:34:35 +0000
commitc640058aa7f224a71ce3b1d2601d84e1b57f82d3 (patch)
tree9b76815ba1471c89d54aee2255d56e0d513c8049
parent9bb4a0c195eda6e034c467a63b9ada2209a6df3f (diff)
downloadclang-c640058aa7f224a71ce3b1d2601d84e1b57f82d3.tar.gz
clang-c640058aa7f224a71ce3b1d2601d84e1b57f82d3.tar.bz2
clang-c640058aa7f224a71ce3b1d2601d84e1b57f82d3.tar.xz
OpenMP threadprivate directive parsing and semantic analysis
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177705 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/DeclOpenMP.h83
-rw-r--r--include/clang/AST/DeclVisitor.h1
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h9
-rw-r--r--include/clang/Basic/DeclNodes.td1
-rw-r--r--include/clang/Basic/DiagnosticGroups.td3
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td13
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td16
-rw-r--r--include/clang/Basic/OpenMPKinds.def23
-rw-r--r--include/clang/Basic/OpenMPKinds.h37
-rw-r--r--include/clang/Basic/TokenKinds.def6
-rw-r--r--include/clang/Parse/Parser.h7
-rw-r--r--include/clang/Sema/Sema.h13
-rw-r--r--include/clang/Sema/Template.h1
-rw-r--r--include/clang/Serialization/ASTBitCodes.h2
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/DeclBase.cpp2
-rw-r--r--lib/AST/DeclOpenMP.cpp60
-rw-r--r--lib/AST/DeclPrinter.cpp21
-rw-r--r--lib/Basic/CMakeLists.txt1
-rw-r--r--lib/Basic/OpenMPKinds.cpp43
-rw-r--r--lib/CodeGen/CGDecl.cpp1
-rw-r--r--lib/Frontend/ASTConsumers.cpp4
-rw-r--r--lib/Parse/CMakeLists.txt1
-rw-r--r--lib/Parse/ParseDeclCXX.cpp5
-rw-r--r--lib/Parse/ParseOpenMP.cpp118
-rw-r--r--lib/Parse/ParsePragma.cpp44
-rw-r--r--lib/Parse/ParsePragma.h15
-rw-r--r--lib/Parse/ParseStmt.cpp5
-rw-r--r--lib/Parse/Parser.cpp10
-rw-r--r--lib/Sema/CMakeLists.txt1
-rw-r--r--lib/Sema/SemaOpenMP.cpp181
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp17
-rw-r--r--lib/Serialization/ASTCommon.cpp1
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp15
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp11
-rw-r--r--test/OpenMP/no_option.c6
-rw-r--r--test/OpenMP/no_option_no_warn.c6
-rw-r--r--test/OpenMP/openmp_common.c9
-rw-r--r--test/OpenMP/option_warn.c5
-rw-r--r--test/OpenMP/predefined_macro.c17
-rw-r--r--test/OpenMP/threadprivate_ast_print.cpp43
-rw-r--r--test/OpenMP/threadprivate_messages.cpp119
-rw-r--r--tools/libclang/CIndex.cpp1
-rw-r--r--tools/libclang/RecursiveASTVisitor.h9
44 files changed, 983 insertions, 4 deletions
diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h
new file mode 100644
index 0000000000..ca92040c32
--- /dev/null
+++ b/include/clang/AST/DeclOpenMP.h
@@ -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
diff --git a/include/clang/AST/DeclVisitor.h b/include/clang/AST/DeclVisitor.h
index 67be74bfdc..4eaae35778 100644
--- a/include/clang/AST/DeclVisitor.h
+++ b/include/clang/AST/DeclVisitor.h
@@ -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 {
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 480263e943..0191964bbf 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -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(
diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td
index ac7ad6fc6a..45742bc665 100644
--- a/include/clang/Basic/DeclNodes.td
+++ b/include/clang/Basic/DeclNodes.td
@@ -74,5 +74,6 @@ def StaticAssert : Decl;
def Block : Decl, DeclContext;
def ClassScopeFunctionSpecialization : Decl;
def Import : Decl;
+def OMPThreadPrivate : Decl;
def Empty : Decl;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 1238e4baa2..398471cc65 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -517,3 +517,6 @@ def ASMOperandWidths : DiagGroup<"asm-operand-widths">;
def ASM : DiagGroup<"asm", [
ASMOperandWidths
]>;
+
+// OpenMP warnings.
+def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 55afaa5455..c834e195b3 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -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 {
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ec06e34471..1bc3dab93e 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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 {
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
new file mode 100644
index 0000000000..f968977f64
--- /dev/null
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -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
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
new file mode 100644
index 0000000000..ef37db00d0
--- /dev/null
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -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
+
diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def
index 6850bd5a52..6064fc1ff9 100644
--- a/include/clang/Basic/TokenKinds.def
+++ b/include/clang/Basic/TokenKinds.def
@@ -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
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 5205105434..1b81f169ba 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -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,
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 370d7d938c..a7ac5a88c7 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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.
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index fd67222f0f..492e5800bd 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -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) {
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 85f88ad007..46380ed8bf 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -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
};
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index 14bbc2f724..e804fe7205 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -22,6 +22,7 @@ add_clang_library(clangAST
DeclFriend.cpp
DeclGroup.cpp
DeclObjC.cpp
+ DeclOpenMP.cpp
DeclPrinter.cpp
DeclTemplate.cpp
DumpXML.cpp
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 0db520e7d6..1e60560485 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -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;
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
new file mode 100644
index 0000000000..c0d10a0f41
--- /dev/null
+++ b/lib/AST/DeclOpenMP.cpp
@@ -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);
+}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index e2a66fb8a7..54fa9ca589 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -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 << ")";
+ }
+}
+
diff --git a/lib/Basic/CMakeLists.txt b/lib/Basic/CMakeLists.txt
index 37efcb1220..324be06ebc 100644
--- a/lib/Basic/CMakeLists.txt
+++ b/lib/Basic/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_library(clangBasic
LangOptions.cpp
Module.cpp
ObjCRuntime.cpp
+ OpenMPKinds.cpp
OperatorPrecedence.cpp
SourceLocation.cpp
SourceManager.cpp
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
new file mode 100644
index 0000000000..24d15ff750
--- /dev/null
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -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");
+}
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 3b33c11b04..a99fe29bda 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -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;
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 936bd2f8a4..4a63d76a73 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -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");
diff --git a/lib/Parse/CMakeLists.txt b/lib/Parse/CMakeLists.txt
index 55e2aebca8..939998ecb1 100644
--- a/lib/Parse/CMakeLists.txt
+++ b/lib/Parse/CMakeLists.txt
@@ -7,6 +7,7 @@ add_clang_library(clangParse
ParseExprCXX.cpp
ParseInit.cpp
ParseObjc.cpp
+ ParseOpenMP.cpp
ParsePragma.cpp
ParseStmt.cpp
ParseTemplate.cpp
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index f040b9bfff..aa2c0f512a 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -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.
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
new file mode 100644
index 0000000000..507a6b1bcd
--- /dev/null
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -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();
+}
diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp
index 641654b221..dc6b3ed4fa 100644
--- a/lib/Parse/ParsePragma.cpp
+++ b/lib/Parse/ParsePragma.cpp
@@ -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);
+}
diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h
index b9a2a251fc..841a60be7b 100644
--- a/lib/Parse/ParsePragma.h
+++ b/lib/Parse/ParsePragma.h
@@ -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
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index 5833fc1e1b..6db47a0157 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -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.
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 24849edd63..1ebba3e67a 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -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(),
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 4636a097fd..e92f767134 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -38,6 +38,7 @@ add_clang_library(clangSema
SemaLambda.cpp
SemaLookup.cpp
SemaObjCProperty.cpp
+ SemaOpenMP.cpp
SemaOverload.cpp
SemaPseudoObject.cpp
SemaStmt.cpp
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
new file mode 100644
index 0000000000..b8acb2d731
--- /dev/null
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -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);
+}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index d7ab7fd842..55725b603e 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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);
diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp
index 3319cc3641..7bbe6b18f9 100644
--- a/lib/Serialization/ASTCommon.cpp
+++ b/lib/Serialization/ASTCommon.cpp
@@ -204,6 +204,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
case Decl::Block:
case Decl::ClassScopeFunctionSpecialization:
case Decl::Import:
+ case Decl::OMPThreadPrivate:
return false;
}
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 504c2e6588..12114336b2 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -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;
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index d8b5b91108..1e1e12ee5a 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -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
//===----------------------------------------------------------------------===//
diff --git a/test/OpenMP/no_option.c b/test/OpenMP/no_option.c
new file mode 100644
index 0000000000..4acc8d0656
--- /dev/null
+++ b/test/OpenMP/no_option.c
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -verify -o - %s
+// expected-no-diagnostics
+
+int a;
+#pragma omp threadprivate(a,b)
+#pragma omp parallel
diff --git a/test/OpenMP/no_option_no_warn.c b/test/OpenMP/no_option_no_warn.c
new file mode 100644
index 0000000000..c989991371
--- /dev/null
+++ b/test/OpenMP/no_option_no_warn.c
@@ -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
diff --git a/test/OpenMP/openmp_common.c b/test/OpenMP/openmp_common.c
new file mode 100644
index 0000000000..ca5d89a662
--- /dev/null
+++ b/test/OpenMP/openmp_common.c
@@ -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}}
+}
diff --git a/test/OpenMP/option_warn.c b/test/OpenMP/option_warn.c
new file mode 100644
index 0000000000..ddec8e113e
--- /dev/null
+++ b/test/OpenMP/option_warn.c
@@ -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
diff --git a/test/OpenMP/predefined_macro.c b/test/OpenMP/predefined_macro.c
index d6ab853c34..cf6c0cc611 100644
--- a/test/OpenMP/predefined_macro.c
+++ b/test/OpenMP/predefined_macro.c
@@ -7,6 +7,23 @@
#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
+#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
diff --git a/test/OpenMP/threadprivate_ast_print.cpp b/test/OpenMP/threadprivate_ast_print.cpp
new file mode 100644
index 0000000000..deb829e926
--- /dev/null
+++ b/test/OpenMP/threadprivate_ast_print.cpp
@@ -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>());
+}
diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp
new file mode 100644
index 0000000000..0c448b2ef2
--- /dev/null
+++ b/test/OpenMP/threadprivate_messages.cpp
@@ -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}}
+}
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index d63f4def29..98891269d7 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -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
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
index 9788c956da..5862e12cd1 100644
--- a/tools/libclang/RecursiveASTVisitor.h
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -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(