//===--- 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/DeclCXX.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.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; } }; } 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)); } return DeclGroupPtrTy(); } OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( SourceLocation Loc, ArrayRef<Expr *> VarList) { SmallVector<Expr *, 8> Vars; for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { 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_threadprivate_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(); 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; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } Vars.push_back(*I); } return Vars.empty() ? 0 : OMPThreadPrivateDecl::Create(Context, getCurLexicalContext(), Loc, Vars); } StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { StmtResult Res = StmtError(); switch (Kind) { case OMPD_parallel: Res = ActOnOpenMPParallelDirective(Clauses, AStmt, StartLoc, EndLoc); break; case OMPD_threadprivate: case OMPD_task: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: case NUM_OPENMP_DIRECTIVES: llvm_unreachable("Unknown OpenMP directive"); } return Res; } StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { getCurFunction()->setHasBranchProtectedScope(); return Owned(OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt)); } OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { OMPClause *Res = 0; switch (Kind) { case OMPC_default: Res = ActOnOpenMPDefaultClause( static_cast<OpenMPDefaultClauseKind>(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_private: case OMPC_threadprivate: case OMPC_unknown: case NUM_OPENMP_CLAUSES: llvm_unreachable("Clause is not allowed."); } return Res; } OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { if (Kind == OMPC_DEFAULT_unknown) { std::string Values; std::string Sep(NUM_OPENMP_DEFAULT_KINDS > 1 ? ", " : ""); for (unsigned i = OMPC_DEFAULT_unknown + 1; i < NUM_OPENMP_DEFAULT_KINDS; ++i) { Values += "'"; Values += getOpenMPSimpleClauseTypeName(OMPC_default, i); Values += "'"; switch (i) { case NUM_OPENMP_DEFAULT_KINDS - 2: Values += " or "; break; case NUM_OPENMP_DEFAULT_KINDS - 1: break; default: Values += Sep; break; } } Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) << Values << getOpenMPClauseName(OMPC_default); return 0; } return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { OMPClause *Res = 0; switch (Kind) { case OMPC_private: Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_default: case OMPC_threadprivate: case OMPC_unknown: case NUM_OPENMP_CLAUSES: llvm_unreachable("Clause is not allowed."); } return Res; } OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); I != E; ++I) { if (*I && isa<DependentScopeDeclRefExpr>(*I)) { // It will be analyzed later. Vars.push_back(*I); continue; } SourceLocation ELoc = (*I)->getExprLoc(); // OpenMP [2.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I); if (!DE || !isa<VarDecl>(DE->getDecl())) { Diag(ELoc, diag::err_omp_expected_var_name) << (*I)->getSourceRange(); continue; } Decl *D = DE->getDecl(); VarDecl *VD = cast<VarDecl>(D); QualType Type = VD->getType(); if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_private_incomplete_type)) { continue; } if (Type->isReferenceType()) { Diag(ELoc, diag::err_omp_clause_ref_type_arg) << getOpenMPClauseName(OMPC_private) << Type; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; continue; } // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accesible, unambiguous default constructor for the // class type. while (Type.getNonReferenceType()->isArrayType()) { Type = cast<ArrayType>( Type.getNonReferenceType().getTypePtr())->getElementType(); } CXXRecordDecl *RD = getLangOpts().CPlusPlus ? Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; if (RD) { CXXConstructorDecl *CD = LookupDefaultConstructor(RD); PartialDiagnostic PD = PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); if (!CD || CheckConstructorAccess(ELoc, CD, InitializedEntity::InitializeTemporary(Type), CD->getAccess(), PD) == AR_inaccessible || CD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_private) << 0; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, CD); DiagnoseUseOfDecl(CD, ELoc); CXXDestructorDecl *DD = RD->getDestructor(); if (DD) { if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || DD->isDeleted()) { Diag(ELoc, diag::err_omp_required_method) << getOpenMPClauseName(OMPC_private) << 4; bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) << VD; Diag(RD->getLocation(), diag::note_previous_decl) << RD; continue; } MarkFunctionReferenced(ELoc, DD); DiagnoseUseOfDecl(DD, ELoc); } } Vars.push_back(DE); } if (Vars.empty()) return 0; return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); }