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/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 =