OpenMP threadprivate with qualified names.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181683 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp
index c0d10a0..522caef 100644
--- a/lib/AST/DeclOpenMP.cpp
+++ b/lib/AST/DeclOpenMP.cpp
@@ -28,9 +28,9 @@
 OMPThreadPrivateDecl *OMPThreadPrivateDecl::Create(ASTContext &C,
                                                    DeclContext *DC,
                                                    SourceLocation L,
-                                                   ArrayRef<DeclRefExpr *> VL) {
+                                                   ArrayRef<Expr *> VL) {
   unsigned Size = sizeof(OMPThreadPrivateDecl) +
-                  (VL.size() * sizeof(DeclRefExpr *));
+                  (VL.size() * sizeof(Expr *));
 
   void *Mem = C.Allocate(Size, llvm::alignOf<OMPThreadPrivateDecl>());
   OMPThreadPrivateDecl *D = new (Mem) OMPThreadPrivateDecl(OMPThreadPrivate,
@@ -43,7 +43,7 @@
 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 @@
   return D;
 }
 
-void OMPThreadPrivateDecl::setVars(ArrayRef<DeclRefExpr *> VL) {
+void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) {
   assert(VL.size() == NumVars &&
          "Number of variables is not the same as the preallocated buffer");
-  DeclRefExpr **Vars = reinterpret_cast<DeclRefExpr **>(this + 1);
+  Expr **Vars = reinterpret_cast<Expr **>(this + 1);
   std::copy(VL.begin(), VL.end(), Vars);
 }
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d47972b..1c9fd2d 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -1180,9 +1180,9 @@
   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<NamedDecl>((*I)->getDecl());
+          << *cast<NamedDecl>(cast<DeclRefExpr>(*I)->getDecl());
     }
     Out << ")";
   }
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 835908d..b90fbc7 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -32,7 +32,7 @@
   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 @@
   }
   llvm_unreachable("Invalid OpenMP directive kind");
 }
+
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index 507a6b1..e192ae2 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/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 @@
 // 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<DeclarationNameInfo, 5> Identifiers;
-  OpenMPDirectiveKind Kind = Tok.isAnnotation() ?
-                                 OMPD_unknown :
-                                 getOpenMPDirectiveKind(PP.getSpelling(Tok));
-  switch(Kind) {
+  SmallVector<Expr *, 5> 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 @@
           << 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 @@
     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 @@
 }
 
 /// \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<DeclarationNameInfo> &IdList) {
+///   simple-variable-list:
+///         '(' id-expression {, id-expression} ')'
+///
+bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
+                                      SmallVectorImpl<Expr *> &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/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 2117df4..a5371f9 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -1897,7 +1897,7 @@
   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 @@
   }
   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/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h
index 213950a..f68a2e0 100644
--- a/lib/Parse/RAIIObjectsForParser.h
+++ b/lib/Parse/RAIIObjectsForParser.h
@@ -358,7 +358,7 @@
   /// 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 @@
     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/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index c815d4f..4953d2d 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/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 @@
 
 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;
-      }
+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());
     }
-
-    // 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);
+    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<VarDecl>();
+  } else {
+    if (!(VD = Lookup.getAsSingle<VarDecl>())) {
+      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<NamedDecl>(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<Expr *> VarList) {
+  if (OMPThreadPrivateDecl *D = CheckOMPThreadPrivateDecl(Loc, VarList)) {
     CurContext->addDecl(D);
     return DeclGroupPtrTy::make(DeclGroupRef(D));
   }
@@ -141,18 +145,19 @@
 
 OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl(
                                  SourceLocation Loc,
-                                 ArrayRef<DeclRefExpr *> VarList) {
-  SmallVector<DeclRefExpr *, 5> Vars;
-  for (ArrayRef<DeclRefExpr *>::iterator I = VarList.begin(),
+                                 ArrayRef<Expr *> VarList) {
+  SmallVector<Expr *, 8> Vars;
+  for (ArrayRef<Expr *>::iterator I = VarList.begin(),
                                          E = VarList.end();
        I != E; ++I) {
-    VarDecl *VD = cast<VarDecl>((*I)->getDecl());
-    SourceLocation ILoc = (*I)->getLocation();
+    DeclRefExpr *DE = cast<DeclRefExpr>(*I);
+    VarDecl *VD = cast<VarDecl>(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 @@
     //   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 @@
                                                getCurLexicalContext(),
                                                Loc, Vars);
 }
+
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 42e1757..ff59cdc 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2231,13 +2231,13 @@
 
 Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
                                      OMPThreadPrivateDecl *D) {
-  SmallVector<DeclRefExpr *, 5> Vars;
-  for (ArrayRef<DeclRefExpr *>::iterator I = D->varlist_begin(),
-                                         E = D->varlist_end();
+  SmallVector<Expr *, 5> Vars;
+  for (ArrayRef<Expr *>::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));
+    Vars.push_back(Var);
   }
 
   OMPThreadPrivateDecl *TD =
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index e3f9f43..b117b73 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1644,10 +1644,10 @@
 void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) {
   VisitDecl(D);
   unsigned NumVars = D->varlist_size();
-  SmallVector<DeclRefExpr *, 16> Vars;
+  SmallVector<Expr *, 16> Vars;
   Vars.reserve(NumVars);
   for (unsigned i = 0; i != NumVars; ++i) {
-    Vars.push_back(cast<DeclRefExpr>(Reader.ReadExpr(F)));
+    Vars.push_back(Reader.ReadExpr(F));
   }
   D->setVars(Vars);
 }