diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 2 | ||||
-rw-r--r-- | lib/AST/DeclOpenMP.cpp | 60 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 21 | ||||
-rw-r--r-- | lib/Basic/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Basic/OpenMPKinds.cpp | 43 | ||||
-rw-r--r-- | lib/CodeGen/CGDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/ASTConsumers.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 5 | ||||
-rw-r--r-- | lib/Parse/ParseOpenMP.cpp | 118 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.cpp | 44 | ||||
-rw-r--r-- | lib/Parse/ParsePragma.h | 15 | ||||
-rw-r--r-- | lib/Parse/ParseStmt.cpp | 5 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 10 | ||||
-rw-r--r-- | lib/Sema/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/Sema/SemaOpenMP.cpp | 181 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 17 | ||||
-rw-r--r-- | lib/Serialization/ASTCommon.cpp | 1 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 15 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 11 |
21 files changed, 554 insertions, 3 deletions
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); |