OpenMP threadprivate directive parsing and semantic analysis

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177705 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt
index 4636a09..e92f767 100644
--- a/lib/Sema/CMakeLists.txt
+++ b/lib/Sema/CMakeLists.txt
@@ -38,6 +38,7 @@
   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 0000000..b8acb2d
--- /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 d7ab7fd..55725b6 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -2183,6 +2183,23 @@
   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);