From 6f6f3b4baf5504ffbc7c0476a4eddc74ddd8859d Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Mon, 13 May 2013 04:18:18 +0000 Subject: [PATCH] OpenMP threadprivate with qualified names. llvm-svn: 181683 --- clang/include/clang/AST/DeclOpenMP.h | 26 +- .../clang/Basic/DiagnosticParseKinds.td | 5 +- .../clang/Basic/DiagnosticSemaKinds.td | 18 +- clang/include/clang/Parse/Parser.h | 11 +- clang/include/clang/Sema/Sema.h | 17 +- clang/lib/AST/DeclOpenMP.cpp | 10 +- clang/lib/AST/DeclPrinter.cpp | 4 +- clang/lib/Basic/OpenMPKinds.cpp | 3 +- clang/lib/Parse/ParseOpenMP.cpp | 95 ++++--- clang/lib/Parse/Parser.cpp | 5 +- clang/lib/Parse/RAIIObjectsForParser.h | 7 +- clang/lib/Sema/SemaOpenMP.cpp | 250 +++++++++--------- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 +- clang/lib/Serialization/ASTReaderDecl.cpp | 4 +- clang/test/OpenMP/predefined_macro.c | 1 - clang/test/OpenMP/threadprivate_messages.cpp | 52 ++-- 16 files changed, 282 insertions(+), 234 deletions(-) diff --git a/clang/include/clang/AST/DeclOpenMP.h b/clang/include/clang/AST/DeclOpenMP.h index ca92040c3286..42fe907aa174 100644 --- a/clang/include/clang/AST/DeclOpenMP.h +++ b/clang/include/clang/AST/DeclOpenMP.h @@ -1,4 +1,4 @@ -//===--- OpenMP.h - Classes for representing OpenMP directives ---*- C++ -*-===// +//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief This file defines OpenMP nodes. +/// \brief This file defines OpenMP nodes for declarative directives. /// //===----------------------------------------------------------------------===// @@ -20,8 +20,6 @@ namespace clang { -class DeclRefExpr; - /// \brief This represents '#pragma omp threadprivate ...' directive. /// For example, in the following, both 'a' and 'A::b' are threadprivate: /// @@ -43,29 +41,29 @@ class OMPThreadPrivateDecl : public Decl { OMPThreadPrivateDecl(Kind DK, DeclContext *DC, SourceLocation L) : Decl(DK, DC, L), NumVars(0) { } - ArrayRef getVars() const { - return ArrayRef( - reinterpret_cast(this + 1), + ArrayRef getVars() const { + return ArrayRef( + reinterpret_cast(this + 1), NumVars); } - llvm::MutableArrayRef getVars() { - return llvm::MutableArrayRef( - reinterpret_cast(this + 1), + llvm::MutableArrayRef getVars() { + return llvm::MutableArrayRef( + reinterpret_cast(this + 1), NumVars); } - void setVars(ArrayRef VL); + void setVars(ArrayRef VL); public: static OMPThreadPrivateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ArrayRef VL); + ArrayRef VL); static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, unsigned ID, unsigned N); - typedef llvm::MutableArrayRef::iterator varlist_iterator; - typedef ArrayRef::iterator varlist_const_iterator; + typedef llvm::MutableArrayRef::iterator varlist_iterator; + typedef ArrayRef::iterator varlist_const_iterator; unsigned varlist_size() const { return NumVars; } bool varlist_empty() const { return NumVars == 0; } diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index e001bd46a230..a4b8d1810c82 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -819,13 +819,14 @@ def err_seh___finally_block : Error< def warn_pragma_omp_ignored : Warning < "unexpected '#pragma omp ...' in program">, InGroup, DefaultIgnore; def warn_omp_extra_tokens_at_eol : Warning < - "extra tokens at end of '#pragma omp %0' are ignored">, + "extra tokens at the end of '#pragma omp %0' are ignored">, InGroup; def err_omp_unknown_directive : Error < "expected an OpenMP directive">; def err_omp_unexpected_directive : Error < "unexpected OpenMP directive '#pragma omp %0'">; - +def err_omp_expected_var : Error < + "expected '#pragma omp %0' argument to be a variable name">; } // end of Parse Issue category. let CategoryName = "Modules Issue" in { diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 18d5796ea14c..c2728820d434 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6336,24 +6336,26 @@ def err_wrong_sampler_addressspace: Error< "sampler type cannot be used with the __local and __global address space qualifiers">; def err_opencl_global_invalid_addr_space : Error< "global variables must have a constant address space qualifier">; - + +} // end of sema category + +let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg_suggest : Error< "%0 is not a global variable, static local variable or static data member%select{|; did you mean %2?}1">; def err_omp_global_var_arg : Error< "arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">; def err_omp_ref_type_arg : Error< - "arguments of '#pragma omp %0' cannot be of reference type %1">; + "arguments of '#pragma omp %0' cannot be of reference type">; def err_omp_var_scope : Error< - "'#pragma omp %0' must appear in the scope of the %1 variable declaration">; + "'#pragma omp %0' must appear in the scope of the %q1 variable declaration">; def err_omp_var_used : Error< - "'#pragma omp %0' must precede all references to variable %1">; + "'#pragma omp %0' must precede all references to variable %q1">; def err_omp_var_thread_local : Error< "variable %0 cannot be threadprivate because it is thread-local">; -def err_omp_incomplete_type : Error< - "a threadprivate variable must not have incomplete type %0">; - -} // end of sema category +def err_omp_threadprivate_incomplete_type : Error< + "threadprivate variable with incomplete type %0">; +} // end of OpenMP category let CategoryName = "Related Result Type Issue" in { // Objective-C related result type compatibility diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 72acacf5ae61..1a1d6d2ae1a4 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2138,9 +2138,18 @@ private: //===--------------------------------------------------------------------===// // OpenMP: Directives and clauses. + /// \brief Parses declarative OpenMP directives. DeclGroupPtrTy ParseOpenMPDeclarativeDirective(); + /// \brief Parses simple list of variables. + /// + /// \param Kind Kind of the directive. + /// \param [out] VarList List of referenced variables. + /// \param AllowScopeSpecifier true, if the variables can have fully + /// qualified names. + /// bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, - SmallVectorImpl &IdList); + SmallVectorImpl &VarList, + bool AllowScopeSpecifier); public: bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 78152313c871..c2300e977e86 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -6682,16 +6682,19 @@ public: unsigned SpellingListIndex, bool IsPackExpansion); // OpenMP directives and clauses. - + /// \brief Called on correct id-expression from the '#pragma omp + /// threadprivate'. + ExprResult ActOnOpenMPIdExpression(Scope *CurScope, + CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id); /// \brief Called on well-formed '#pragma omp threadprivate'. DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( - SourceLocation Loc, - Scope *CurScope, - ArrayRef IdList); - /// \brief Build a new OpenMPThreadPrivateDecl and check its correctness. + SourceLocation Loc, + ArrayRef VarList); + // \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness. OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl( - SourceLocation Loc, - ArrayRef VarList); + SourceLocation Loc, + ArrayRef VarList); /// \brief The kind of conversion being performed. enum CheckedConversionKind { diff --git a/clang/lib/AST/DeclOpenMP.cpp b/clang/lib/AST/DeclOpenMP.cpp index c0d10a0f418c..522caefe3bdd 100644 --- a/clang/lib/AST/DeclOpenMP.cpp +++ b/clang/lib/AST/DeclOpenMP.cpp @@ -28,9 +28,9 @@ void OMPThreadPrivateDecl::anchor() { } OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - ArrayRef VL) { + ArrayRef VL) { unsigned Size = sizeof(OMPThreadPrivateDecl) + - (VL.size() * sizeof(DeclRefExpr *)); + (VL.size() * sizeof(Expr *)); void *Mem = C.Allocate(Size, llvm::alignOf()); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -43,7 +43,7 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C, OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, unsigned ID, unsigned N) { - unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(DeclRefExpr *)); + unsigned Size = sizeof(OMPThreadPrivateDecl) + (N * sizeof(Expr *)); void *Mem = AllocateDeserializedDecl(C, ID, Size); OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate, @@ -52,9 +52,9 @@ OMPThreadPrivateDecl *OMPThreadPrivateDecl::CreateDeserialized(ASTContext &C, return D; } -void OMPThreadPrivateDecl::setVars(ArrayRef VL) { +void OMPThreadPrivateDecl::setVars(ArrayRef VL) { assert(VL.size() == NumVars && "Number of variables is not the same as the preallocated buffer"); - DeclRefExpr **Vars = reinterpret_cast(this + 1); + Expr **Vars = reinterpret_cast(this + 1); std::copy(VL.begin(), VL.end(), Vars); } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index d47972bc6130..1c9fd2d5f610 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1180,9 +1180,9 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { if (!D->varlist_empty()) { for (OMPThreadPrivateDecl::varlist_iterator I = D->varlist_begin(), E = D->varlist_end(); - I != E; ++I) { + I != E; ++I) { Out << (I == D->varlist_begin() ? '(' : ',') - << *cast((*I)->getDecl()); + << *cast(cast(*I)->getDecl()); } Out << ")"; } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 835908d2a1b5..b90fbc7a7c70 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -32,7 +32,7 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { assert(Kind < NUM_OPENMP_DIRECTIVES); switch (Kind) { case OMPD_unknown: - return ("unknown"); + return "unknown"; #define OPENMP_DIRECTIVE(Name) \ case OMPD_##Name : return #Name; #include "clang/Basic/OpenMPKinds.def" @@ -41,3 +41,4 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { } llvm_unreachable("Invalid OpenMP directive kind"); } + diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 507a6b1bcd87..e192ae2e2349 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -12,8 +12,10 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" -#include "clang/Parse/Parser.h" #include "clang/Parse/ParseDiagnostic.h" +#include "clang/Parse/Parser.h" +#include "clang/Sema/Scope.h" +#include "llvm/ADT/PointerIntPair.h" #include "RAIIObjectsForParser.h" using namespace clang; @@ -21,22 +23,24 @@ using namespace clang; // OpenMP declarative directives. //===----------------------------------------------------------------------===// -/// \brief Parses OpenMP declarative directive -/// threadprivate-directive -/// annot_pragma_openmp threadprivate simple-variable-list +/// \brief Parsing of declarative OpenMP directives. +/// +/// threadprivate-directive: +/// annot_pragma_openmp 'threadprivate' simple-variable-list /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); SourceLocation Loc = ConsumeToken(); - SmallVector Identifiers; - OpenMPDirectiveKind Kind = Tok.isAnnotation() ? - OMPD_unknown : - getOpenMPDirectiveKind(PP.getSpelling(Tok)); - switch(Kind) { + SmallVector Identifiers; + OpenMPDirectiveKind DKind = Tok.isAnnotation() ? + OMPD_unknown : + getOpenMPDirectiveKind(PP.getSpelling(Tok)); + + switch (DKind) { case OMPD_threadprivate: ConsumeToken(); - if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers)) { + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, true)) { // The last seen token is annot_pragma_openmp_end - need to check for // extra tokens. if (Tok.isNot(tok::annot_pragma_openmp_end)) { @@ -44,9 +48,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { << getOpenMPDirectiveName(OMPD_threadprivate); SkipUntil(tok::annot_pragma_openmp_end, false, true); } + // Skip the last annot_pragma_openmp_end. ConsumeToken(); return Actions.ActOnOpenMPThreadprivateDirective(Loc, - getCurScope(), Identifiers); } break; @@ -55,7 +59,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { break; default: Diag(Tok, diag::err_omp_unexpected_directive) - << getOpenMPDirectiveName(Kind); + << getOpenMPDirectiveName(DKind); break; } SkipUntil(tok::annot_pragma_openmp_end, false); @@ -63,56 +67,69 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { } /// \brief Parses list of simple variables for '#pragma omp threadprivate' -/// directive -/// simple-variable-list: -/// ( unqualified-id {, unqualified-id} ) annot_pragma_openmp_end +/// directive. /// -bool Parser::ParseOpenMPSimpleVarList( - OpenMPDirectiveKind Kind, - SmallVectorImpl &IdList) { +/// simple-variable-list: +/// '(' id-expression {, id-expression} ')' +/// +bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, + SmallVectorImpl &VarList, + bool AllowScopeSpecifier) { + VarList.clear(); // Parse '('. - bool IsCorrect = true; - BalancedDelimiterTracker T(*this, tok::l_paren); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(Kind))) { - SkipUntil(tok::annot_pragma_openmp_end, false, true); - return false; - } + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + bool LParen = !T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(Kind)); + bool IsCorrect = LParen; + bool NoIdentIsFound = true; // Read tokens while ')' or annot_pragma_openmp_end is not found. - do { + while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)) { CXXScopeSpec SS; SourceLocation TemplateKWLoc; UnqualifiedId Name; // Read var name. Token PrevTok = Tok; + NoIdentIsFound = false; - if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), - TemplateKWLoc, Name)) { + if (AllowScopeSpecifier && getLangOpts().CPlusPlus && + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, false, true); - } - else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && - Tok.isNot(tok::annot_pragma_openmp_end)) { + } else if (ParseUnqualifiedId(SS, false, false, false, ParsedType(), + TemplateKWLoc, Name)) { IsCorrect = false; SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, false, true); - Diag(PrevTok.getLocation(), diag::err_expected_unqualified_id) - << getLangOpts().CPlusPlus + } else if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + IsCorrect = false; + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + false, true); + Diag(PrevTok.getLocation(), diag::err_expected_ident) << SourceRange(PrevTok.getLocation(), PrevTokLocation); } else { - IdList.push_back(Actions.GetNameFromUnqualifiedId(Name)); + DeclarationNameInfo NameInfo = Actions.GetNameFromUnqualifiedId(Name); + ExprResult Res = Actions.ActOnOpenMPIdExpression(getCurScope(), SS, + NameInfo); + if (Res.isUsable()) + VarList.push_back(Res.take()); } // Consume ','. if (Tok.is(tok::comma)) { ConsumeToken(); } - } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end)); - - if (IsCorrect || Tok.is(tok::r_paren)) { - IsCorrect = !T.consumeClose() && IsCorrect; } - return !IsCorrect && IdList.empty(); + if (NoIdentIsFound) { + Diag(Tok, diag::err_expected_ident); + IsCorrect = false; + } + + // Parse ')'. + IsCorrect = ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose()) + && IsCorrect; + + return !IsCorrect && VarList.empty(); } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 2117df45f3aa..a5371f9e6122 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1897,7 +1897,7 @@ bool BalancedDelimiterTracker::diagnoseOverflow() { P.Diag(P.Tok, diag::err_bracket_depth_exceeded) << P.getLangOpts().BracketDepth; P.Diag(P.Tok, diag::note_bracket_depth); - P.SkipUntil(tok::eof); + P.SkipUntil(tok::eof, FinalToken); return true; } @@ -1927,7 +1927,8 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() { } P.Diag(P.Tok, DID); P.Diag(LOpen, diag::note_matching) << LHSName; - if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true)) + if (P.SkipUntil(Close, FinalToken, /*StopAtSemi*/ true, /*DontConsume*/ true) + && P.Tok.is(Close)) LClose = P.ConsumeAnyToken(); return true; } diff --git a/clang/lib/Parse/RAIIObjectsForParser.h b/clang/lib/Parse/RAIIObjectsForParser.h index 213950a6db92..f68a2e09fe91 100644 --- a/clang/lib/Parse/RAIIObjectsForParser.h +++ b/clang/lib/Parse/RAIIObjectsForParser.h @@ -358,7 +358,7 @@ namespace clang { /// pair, such as braces { ... } or parentheses ( ... ). class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { Parser& P; - tok::TokenKind Kind, Close; + tok::TokenKind Kind, Close, FinalToken; SourceLocation (Parser::*Consumer)(); SourceLocation LOpen, LClose; @@ -377,9 +377,10 @@ namespace clang { bool diagnoseMissingClose(); public: - BalancedDelimiterTracker(Parser& p, tok::TokenKind k) + BalancedDelimiterTracker(Parser& p, tok::TokenKind k, + tok::TokenKind FinalToken = tok::semi) : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), - P(p), Kind(k) + P(p), Kind(k), FinalToken(FinalToken) { switch (Kind) { default: llvm_unreachable("Unexpected balanced token"); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c815d4f9abc7..4953d2d14e7a 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// \file /// \brief This file implements semantic analysis for OpenMP directives and -/// clauses +/// clauses. /// //===----------------------------------------------------------------------===// @@ -22,117 +22,121 @@ using namespace clang; namespace { - class VarDeclFilterCCC : public CorrectionCandidateCallback { - private: - Sema &Actions; - public: - VarDeclFilterCCC(Sema &S) : Actions(S) { } - virtual bool ValidateCandidate(const TypoCorrection &Candidate) { - NamedDecl *ND = Candidate.getCorrectionDecl(); - if (VarDecl *VD = dyn_cast_or_null(ND)) { - return VD->hasGlobalStorage() && - Actions.isDeclInScope(ND, Actions.getCurLexicalContext(), - Actions.getCurScope()); - } - return false; - } - }; -} -Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( - SourceLocation Loc, - Scope *CurScope, - ArrayRef IdList) { - SmallVector Vars; - for (ArrayRef::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(); - } else { - if (!(VD = Lookup.getAsSingle())) { - Diag(I->getLoc(), diag::err_omp_expected_var_arg_suggest) - << I->getName() << 0; - Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); - continue; - } +class VarDeclFilterCCC : public CorrectionCandidateCallback { +private: + Sema &Actions; +public: + VarDeclFilterCCC(Sema &S) : Actions(S) { } + virtual bool ValidateCandidate(const TypoCorrection &Candidate) { + NamedDecl *ND = Candidate.getCorrectionDecl(); + if (VarDecl *VD = dyn_cast_or_null(ND)) { + return VD->hasGlobalStorage() && + Actions.isDeclInScope(ND, Actions.getCurLexicalContext(), + Actions.getCurScope()); } - - // OpenMP [2.9.2, Syntax, C/C++] - // Variables must be file-scope, namespace-scope, or static block-scope. - if (!VD->hasGlobalStorage()) { - Diag(I->getLoc(), diag::err_omp_global_var_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) - << !VD->isStaticLocal(); - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; - continue; - } - - // OpenMP [2.9.2, Restrictions, C/C++, p.2] - // A threadprivate directive for file-scope variables must appear outside - // any definition or declaration. - // OpenMP [2.9.2, Restrictions, C/C++, p.3] - // A threadprivate directive for static class member variables must appear - // in the class definition, in the same scope in which the member - // variables are declared. - // OpenMP [2.9.2, Restrictions, C/C++, p.4] - // A threadprivate directive for namespace-scope variables must appear - // outside any definition or declaration other than the namespace - // definition itself. - // OpenMP [2.9.2, Restrictions, C/C++, p.6] - // A threadprivate directive for static block-scope variables must appear - // in the scope of the variable and not in a nested scope. - NamedDecl *ND = cast(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(BuildDeclRefExpr(VD, - ExprType, - VK_RValue, - I->getLoc()).take()); - Vars.push_back(Var); + return false; } - if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, Vars)) { +}; +} + +ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, + CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id) { + LookupResult Lookup(*this, Id, LookupOrdinaryName); + LookupParsedName(Lookup, CurScope, &ScopeSpec, true); + + if (Lookup.isAmbiguous()) + return ExprError(); + + VarDecl *VD; + if (!Lookup.isSingleResult()) { + VarDeclFilterCCC Validator(*this); + TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope, + 0, Validator); + std::string CorrectedStr = Corrected.getAsString(getLangOpts()); + std::string CorrectedQuotedStr = Corrected.getQuoted(getLangOpts()); + if (Lookup.empty()) { + if (Corrected.isResolved()) { + Diag(Id.getLoc(), diag::err_undeclared_var_use_suggest) + << Id.getName() << CorrectedQuotedStr + << FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr); + } else { + Diag(Id.getLoc(), diag::err_undeclared_var_use) + << Id.getName(); + } + } else { + Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest) + << Id.getName() << Corrected.isResolved() << CorrectedQuotedStr + << FixItHint::CreateReplacement(Id.getLoc(), CorrectedStr); + } + if (!Corrected.isResolved()) return ExprError(); + VD = Corrected.getCorrectionDeclAs(); + } else { + if (!(VD = Lookup.getAsSingle())) { + Diag(Id.getLoc(), diag::err_omp_expected_var_arg_suggest) + << Id.getName() << 0; + Diag(Lookup.getFoundDecl()->getLocation(), diag::note_declared_at); + return ExprError(); + } + } + Lookup.suppressDiagnostics(); + + // OpenMP [2.9.2, Syntax, C/C++] + // Variables must be file-scope, namespace-scope, or static block-scope. + if (!VD->hasGlobalStorage()) { + Diag(Id.getLoc(), diag::err_omp_global_var_arg) + << getOpenMPDirectiveName(OMPD_threadprivate) + << !VD->isStaticLocal(); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; + return ExprError(); + } + + // OpenMP [2.9.2, Restrictions, C/C++, p.2] + // A threadprivate directive for file-scope variables must appear outside + // any definition or declaration. + // OpenMP [2.9.2, Restrictions, C/C++, p.3] + // A threadprivate directive for static class member variables must appear + // in the class definition, in the same scope in which the member + // variables are declared. + // OpenMP [2.9.2, Restrictions, C/C++, p.4] + // A threadprivate directive for namespace-scope variables must appear + // outside any definition or declaration other than the namespace + // definition itself. + // OpenMP [2.9.2, Restrictions, C/C++, p.6] + // A threadprivate directive for static block-scope variables must appear + // in the scope of the variable and not in a nested scope. + NamedDecl *ND = cast(VD); + if (!isDeclInScope(ND, getCurLexicalContext(), CurScope)) { + Diag(Id.getLoc(), diag::err_omp_var_scope) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; + return ExprError(); + } + + // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] + // A threadprivate directive must lexically precede all references to any + // of the variables in its list. + if (VD->isUsed()) { + Diag(Id.getLoc(), diag::err_omp_var_used) + << getOpenMPDirectiveName(OMPD_threadprivate) << VD; + return ExprError(); + } + + QualType ExprType = VD->getType().getNonReferenceType(); + ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_RValue, Id.getLoc()); + return DE; +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( + SourceLocation Loc, + ArrayRef VarList) { + if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) { CurContext->addDecl(D); return DeclGroupPtrTy::make(DeclGroupRef(D)); } @@ -141,18 +145,19 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPThreadprivateDirective( OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( SourceLocation Loc, - ArrayRef VarList) { - SmallVector Vars; - for (ArrayRef::iterator I = VarList.begin(), + ArrayRef VarList) { + SmallVector Vars; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { - VarDecl *VD = cast((*I)->getDecl()); - SourceLocation ILoc = (*I)->getLocation(); + DeclRefExpr *DE = cast(*I); + VarDecl *VD = cast(DE->getDecl()); + SourceLocation ILoc = DE->getExprLoc(); // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have an incomplete type. if (RequireCompleteType(ILoc, VD->getType(), - diag::err_omp_incomplete_type)) { + diag::err_omp_threadprivate_incomplete_type)) { continue; } @@ -160,15 +165,21 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( // A threadprivate variable must not have a reference type. if (VD->getType()->isReferenceType()) { Diag(ILoc, diag::err_omp_ref_type_arg) - << getOpenMPDirectiveName(OMPD_threadprivate) << VD->getType(); - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + << getOpenMPDirectiveName(OMPD_threadprivate); + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; continue; } // Check if this is a TLS variable. if (VD->getTLSKind()) { Diag(ILoc, diag::err_omp_var_thread_local) << VD; - Diag(VD->getLocation(), diag::note_forward_declaration) << VD; + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; continue; } @@ -179,3 +190,4 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( getCurLexicalContext(), Loc, Vars); } + diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 42e1757bcbe8..ff59cdcbc424 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2231,13 +2231,13 @@ Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( OMPThreadPrivateDecl *D) { - SmallVector Vars; - for (ArrayRef::iterator I = D->varlist_begin(), - E = D->varlist_end(); + SmallVector Vars; + for (ArrayRef::iterator I = D->varlist_begin(), + E = D->varlist_end(); I != E; ++I) { Expr *Var = SemaRef.SubstExpr(*I, TemplateArgs).take(); assert(isa(Var) && "threadprivate arg is not a DeclRefExpr"); - Vars.push_back(cast(Var)); + Vars.push_back(Var); } OMPThreadPrivateDecl *TD = diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index e3f9f43a3b7b..b117b733a4b1 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1644,10 +1644,10 @@ void ASTDeclReader::mergeRedeclarable(Redeclarable *D, void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { VisitDecl(D); unsigned NumVars = D->varlist_size(); - SmallVector Vars; + SmallVector Vars; Vars.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) { - Vars.push_back(cast(Reader.ReadExpr(F))); + Vars.push_back(Reader.ReadExpr(F)); } D->setVars(Vars); } diff --git a/clang/test/OpenMP/predefined_macro.c b/clang/test/OpenMP/predefined_macro.c index cf6c0cc61188..3a8118620962 100644 --- a/clang/test/OpenMP/predefined_macro.c +++ b/clang/test/OpenMP/predefined_macro.c @@ -31,4 +31,3 @@ #error "_OPENMP macro is defined without -fopenmp option" #endif // _OPENMP #endif // FOPENMP - diff --git a/clang/test/OpenMP/threadprivate_messages.cpp b/clang/test/OpenMP/threadprivate_messages.cpp index 0c448b2ef27e..1bfba6d8643c 100644 --- a/clang/test/OpenMP/threadprivate_messages.cpp +++ b/clang/test/OpenMP/threadprivate_messages.cpp @@ -1,8 +1,8 @@ // RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s -#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} -#pragma omp threadprivate( // expected-error {{expected unqualified-id}} -#pragma omp threadprivate() // expected-error {{expected unqualified-id}} +#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} expected-error {{expected identifier}} +#pragma omp threadprivate( // expected-error {{expected identifier}} expected-error {{expected ')'}} expected-note {{to match this '('}} +#pragma omp threadprivate() // expected-error {{expected identifier}} #pragma omp threadprivate(1) // expected-error {{expected unqualified-id}} struct CompleteSt{ int a; @@ -11,27 +11,27 @@ struct CompleteSt{ struct CompleteSt1{ #pragma omp threadprivate(1) // expected-error {{expected unqualified-id}} int a; -} d; // expected-note {{forward declaration of 'd'}} +} d; // expected-note {{'d' defined here}} -int a; // expected-note {{forward declaration of 'a'}} +int a; // expected-note {{'a' defined here}} #pragma omp threadprivate(a) #pragma omp threadprivate(u) // expected-error {{use of undeclared identifier 'u'}} #pragma omp threadprivate(d, a) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} int foo() { // expected-note {{declared here}} static int l; -#pragma omp threadprivate(l)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}} +#pragma omp threadprivate(l)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} return (a); } -#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} +#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} #pragma omp threadprivate(d // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} -#pragma omp threadprivate(d)) +#pragma omp threadprivate(d)) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} int x, y; -#pragma omp threadprivate(x)) // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}} -#pragma omp threadprivate(y)), // expected-warning {{extra tokens at end of '#pragma omp threadprivate' are ignored}} +#pragma omp threadprivate(x)) // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} +#pragma omp threadprivate(y)), // expected-warning {{extra tokens at the end of '#pragma omp threadprivate' are ignored}} #pragma omp threadprivate(a,d) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd'}} -#pragma omp threadprivate(d.a) // expected-error {{expected unqualified-id}} +#pragma omp threadprivate(d.a) // expected-error {{expected identifier}} #pragma omp threadprivate((float)a) // expected-error {{expected unqualified-id}} int foa; #pragma omp threadprivate(faa) // expected-error {{use of undeclared identifier 'faa'; did you mean 'foa'?}} @@ -41,31 +41,31 @@ int foa; struct IncompleteSt; // expected-note {{forward declaration of 'IncompleteSt'}} extern IncompleteSt e; -#pragma omp threadprivate (e) // expected-error {{a threadprivate variable must not have incomplete type 'IncompleteSt'}} +#pragma omp threadprivate (e) // expected-error {{threadprivate variable with incomplete type 'IncompleteSt'}} -int &f = a; // expected-note {{forward declaration of 'f'}} -#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type 'int &'}} +int &f = a; // expected-note {{'f' defined here}} +#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type}} class Class { private: int a; // expected-note {{declared here}} - static int b; + static int b; // expected-note {{'b' declared here}} Class() : a(0){} public: Class (int aaa) : a(aaa) {} #pragma omp threadprivate (b, a) // expected-error {{'a' is not a global variable, static local variable or static data member}} } g(10); #pragma omp threadprivate (b) // expected-error {{use of undeclared identifier 'b'}} -#pragma omp threadprivate (Class::b) // expected-error {{expected unqualified-id}} +#pragma omp threadprivate (Class::b) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'Class::b' variable declaration}} #pragma omp threadprivate (g) namespace ns { - int m; + int m; // expected-note 2 {{'m' defined here}} #pragma omp threadprivate (m) } #pragma omp threadprivate (m) // expected-error {{use of undeclared identifier 'm'}} -#pragma omp threadprivate (ns::m) // expected-error {{expected unqualified-id}} -#pragma omp threadprivate (ns:m) // expected-error {{expected unqualified-id}} +#pragma omp threadprivate (ns::m) // expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'ns::m' variable declaration}} +#pragma omp threadprivate (ns:m) // expected-error {{unexpected ':' in nested name specifier; did you mean '::'?}} expected-error {{'#pragma omp threadprivate' must appear in the scope of the 'ns::m' variable declaration}} const int h = 12; const volatile int i = 10; @@ -84,26 +84,30 @@ class TempClass { }; #pragma omp threadprivate (s) // expected-error {{use of undeclared identifier 's'}} -static __thread int t; // expected-note {{forward declaration of 't'}} +static __thread int t; // expected-note {{'t' defined here}} #pragma omp threadprivate (t) // expected-error {{variable 't' cannot be threadprivate because it is thread-local}} int o; // expected-note {{candidate found by name lookup is 'o'}} +#pragma omp threadprivate (o) namespace { int o; // expected-note {{candidate found by name lookup is '::o'}} +#pragma omp threadprivate (o) +#pragma omp threadprivate (o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable '::o'}} } #pragma omp threadprivate (o) // expected-error {{reference to 'o' is ambiguous}} +#pragma omp threadprivate (::o) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'o'}} -int main(int argc, char **argv) { // expected-note {{forward declaration of 'argc'}} +int main(int argc, char **argv) { // expected-note {{'argc' defined here}} - int x, y = argc; // expected-note {{forward declaration of 'y'}} + int x, y = argc; // expected-note {{'y' defined here}} static double d1; static double d2; - static double d3; // expected-note {{forward declaration of 'd3'}} + static double d3; // expected-note {{'d3' defined here}} d.a = a; d2++; ; -#pragma omp threadprivate(argc+y) // expected-error {{expected unqualified-id}} +#pragma omp threadprivate(argc+y) // expected-error {{expected identifier}} #pragma omp threadprivate(argc,y) // expected-error 2 {{arguments of '#pragma omp threadprivate' must have static storage duration}} #pragma omp threadprivate(d2) // expected-error {{'#pragma omp threadprivate' must precede all references to variable 'd2'}} #pragma omp threadprivate(d1)