diff --git a/include/clang/AST/DeclOpenMP.h b/include/clang/AST/DeclOpenMP.h new file mode 100644 index 0000000000000000000000000000000000000000..ca92040c3286d9e8f6e71bc370cf408c03ae76e6 --- /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 67be74bfdc0415579036de0b05d05dce7650ddae..4eaae35778b9376bb972bf538e7c704a6f5b7f28 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 480263e943879b8c4b1ce73c44a68094a0bdb967..0191964bbfe7fcf0857795b26a7def6b0514f2b6 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 ac7ad6fc6a7921c29d2c193a98788f19b9aa7ef4..45742bc6655a1adc1f5911e499567ec8cf8c3d09 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 1238e4baa2fd722f39881dbede801005122df715..398471cc655e2257ff4d13d86f56af905563d8ac 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 55afaa54552658d1933910f32eb119ef5817de63..c834e195b3a95e6fe8452c63bd278618dac40581 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 ec06e34471426390a7443ad40e4f8f4f643d3359..1bc3dab93ee5acae42486324d1319c2208830f9b 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 0000000000000000000000000000000000000000..f968977f64bcd13a70b69e4f7f98d6266689ea28 --- /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 0000000000000000000000000000000000000000..ef37db00d02629b5a9643795e2c376402988cc0c --- /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 6850bd5a528a3a5eb5e7a1463ca5c118fbb8a9f2..6064fc1ff96687407cdf0ea7fe77be2c87e5f866 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 5205105434aca83d0e988e0a9329d8ff1fe6a6b8..1b81f169ba98bd476419a4bc5122ed0fd758241f 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 370d7d938c0682b65c025ff791c6c05d43b9fec0..a7ac5a88c78c5f9251e1f5e03fda1d07d3c7ff76 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 fd67222f0f8e8ad44fb749def00b59b39a0a6954..492e5800bdad6e53a7da5a04202b9ee56b307cda 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 85f88ad00726763fa73cb2f33af0f5b31e87a4d9..46380ed8bf173f74d120a5e90224e7e61cee352f 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 14bbc2f72447ecbd7d45ab4e441de1023a8aabf3..e804fe7205582972a0cdfdf9a0db9511f53aa42c 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 0db520e7d63b1a31eba11c4a5b2087c2b07dc312..1e6056048535ff4a0f70b907e8cc827ac53e095b 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 0000000000000000000000000000000000000000..c0d10a0f418c647a52fc60b9c7b4b0b35397e2b7 --- /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 e2a66fb8a74a0434ef20bb012f6653d4dc92a3f8..54fa9ca5890f98d10e19309a4df509e721e446bb 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 37efcb1220ee3c6b2c85a05a9c7da573690b5d98..324be06ebc379a84801914ea034cc84f4e14e5fd 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 0000000000000000000000000000000000000000..24d15ff7503b8395ddfbcc25ee38ab254b50bf31 --- /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 3b33c11b046e2e15e03e63c70240f02f40e36b98..a99fe29bdad3d53fade18748812a3f0b2234a807 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 936bd2f8a4e5d55427283f7edfab681d36bed845..4a63d76a73e3f9402542dccbefca22d0157907f8 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 55e2aebca8707adf605ffa4eb53cbf65a523b0f6..939998ecb1af939509c58888b74784842f783fc1 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 f040b9bfff66f10a604aac75af919be7df87a8ab..aa2c0f512afc1c66b61616fe5df549d3c8441f3f 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 0000000000000000000000000000000000000000..507a6b1bcd8727b4893ba9b222369cbdd70bfb52 --- /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 641654b221aea89dd81a9e554d881a4289e1c838..dc6b3ed4fa9816f226d13b4187cf92ce6131c23b 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 b9a2a251fcd43d69e404c3bede7bf94696a33bc4..841a60be7ba181e14d8b3af066f5381b767b529f 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 5833fc1e1ba0eb17f142f37a465d1bf293a4a8c0..6db47a01571241b714c33dc05fcc066e47b6e7ac 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 24849edd63bb6ec4963ebf46fcd9b6cfd47b8e52..1ebba3e67a82463f007b24f5d17b0b377345a4c6 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 4636a097fde127abae2b23ebf5dd0dde1d741e5d..e92f76713422cbc506d8c701456940a092e335e6 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 0000000000000000000000000000000000000000..b8acb2d7310eb49c905e2fde6c807affeb7902d2 --- /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 d7ab7fd84297b64bcdf1fddb71160c723b10504f..55725b603e9c9b96c94aa46f76d5cad2fdb32e59 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 3319cc36412dcbe7f5e1e744f04a8616a9b51563..7bbe6b18f91a3a1bd463b5c4f2673abdbcc5043c 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 504c2e6588b8b266ec6511b9e6fbbef422cfb261..12114336b21c640558e34fde495b3bfa1150dd0b 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 d8b5b9110846c8401252dd2ef8bcd86c88042dc6..1e1e12ee5ac72a095bfbc5c00e81cfc8df887b30 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 0000000000000000000000000000000000000000..4acc8d0656b3963bb77b9e0d4e5d897518894e5b --- /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 0000000000000000000000000000000000000000..c989991371f4f0b91ac8e7b3a6a6a62e326c44d4 --- /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 0000000000000000000000000000000000000000..ca5d89a6629be9933dea8b9207b759501eaaab07 --- /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 0000000000000000000000000000000000000000..ddec8e113e77b6136c8746980ce23e93cc8dfc5e --- /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 d6ab853c340b0656332bedfcd477e9d1451e1e1d..cf6c0cc611880a6a7cff5317a57c248261c426e3 100644 --- a/test/OpenMP/predefined_macro.c +++ b/test/OpenMP/predefined_macro.c @@ -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 diff --git a/test/OpenMP/threadprivate_ast_print.cpp b/test/OpenMP/threadprivate_ast_print.cpp new file mode 100644 index 0000000000000000000000000000000000000000..deb829e92673e2b5ce5329bc216563fc1252b787 --- /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 0000000000000000000000000000000000000000..0c448b2ef27e261a2d8512a2f9b7b9381bbd1966 --- /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 d63f4def29b06d1a3442e49a255c755864be5a26..98891269d74598c3aa25da7991fe309609af8a71 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 9788c956da029df1e96d72c54d68eb01ac605173..5862e12cd1bbc2aacb3d1107c2cdbcd3bb11d18c 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(