From: Alexey Bataev Date: Fri, 19 Jul 2013 03:13:43 +0000 (+0000) Subject: OpenMP: basic support for #pragma omp parallel X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4fa7eab771ab8212e1058bd1a91061ff120c8fbb;p=clang OpenMP: basic support for #pragma omp parallel git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186647 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index aa4b46f8df..ce98b06573 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -2062,7 +2062,11 @@ enum CXCursorKind { */ CXCursor_DeclStmt = 231, - CXCursor_LastStmt = CXCursor_DeclStmt, + /** \brief OpenMP parallel directive. + */ + CXCursor_OMPParallelDirective = 232, + + CXCursor_LastStmt = CXCursor_OMPParallelDirective, /** * \brief Cursor that represents the translation unit itself. diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 6af9e55b83..1b7d5200e5 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -27,6 +27,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -417,6 +418,10 @@ private: bool TraverseDeclContextHelper(DeclContext *DC); bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseVarHelper(VarDecl *D); + bool TraverseOMPClause(OMPClause *C); +#define OPENMP_CLAUSE(Name, Class) \ + bool Visit##Class(Class *C); +#include "clang/Basic/OpenMPKinds.def" struct EnqueueJob { Stmt *S; @@ -2298,6 +2303,48 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { }) // Traverse OpenCL: AsType, Convert. DEF_TRAVERSE_STMT(AsTypeExpr, { }) +// OpenMP directives. +DEF_TRAVERSE_STMT(OMPParallelDirective, { + ArrayRef Clauses = S->clauses(); + for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) + if (!TraverseOMPClause(*I)) return false; +}) + +// OpenMP clauses. +template +bool RecursiveASTVisitor::TraverseOMPClause(OMPClause *C) { + if (!C) return true; + switch (C->getClauseKind()) { +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: \ + return getDerived().Visit##Class(static_cast(C)); +#include "clang/Basic/OpenMPKinds.def" + default: break; + } + return true; +} + +template +bool RecursiveASTVisitor::VisitOMPDefaultClause(OMPDefaultClause *C) { + return true; +} + +#define PROCESS_OMP_CLAUSE_LIST(Class, Node) \ + for (OMPVarList::varlist_iterator I = Node->varlist_begin(), \ + E = Node->varlist_end(); \ + I != E; ++I) \ + TraverseStmt(*I); + +template +bool RecursiveASTVisitor::VisitOMPPrivateClause( + OMPPrivateClause *C) { + PROCESS_OMP_CLAUSE_LIST(OMPPrivateClause, C) + return true; +} + +#undef PROCESS_OMP_CLAUSE_LIST + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm diff --git a/include/clang/AST/StmtOpenMP.h b/include/clang/AST/StmtOpenMP.h new file mode 100644 index 0000000000..34f582dadc --- /dev/null +++ b/include/clang/AST/StmtOpenMP.h @@ -0,0 +1,410 @@ +//===- StmtOpenMP.h - Classes for OpenMP directives and clauses --*- C++ -*-===// +// +// 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 defines OpenMP AST classes for executable directives and +/// clauses. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTOPENMP_H +#define LLVM_CLANG_AST_STMTOPENMP_H + +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Stmt.h" + +namespace clang { + +//===----------------------------------------------------------------------===// +// AST classes for clauses. +//===----------------------------------------------------------------------===// + +/// \brief This is a basic class for representing single OpenMP clause. +/// +class OMPClause { + /// \brief Starting location of the clause (the clause keyword). + SourceLocation StartLoc; + /// \brief Ending location of the clause. + SourceLocation EndLoc; + /// \brief Kind of the clause. + OpenMPClauseKind Kind; +protected: + OMPClause(OpenMPClauseKind K, SourceLocation StartLoc, SourceLocation EndLoc) + : StartLoc(StartLoc), EndLoc(EndLoc), Kind(K) {} + +public: + + /// \brief Returns the starting location of the clause. + SourceLocation getLocStart() const { return StartLoc; } + /// \brief Returns the ending location of the clause. + SourceLocation getLocEnd() const { return EndLoc; } + + /// \brief Sets the starting location of the clause. + void setLocStart(SourceLocation Loc) { StartLoc = Loc; } + /// \brief Sets the ending location of the clause. + void setLocEnd(SourceLocation Loc) { EndLoc = Loc; } + + /// \brief Returns kind of OpenMP clause (private, shared, reduction, etc.). + OpenMPClauseKind getClauseKind() const { return Kind; } + + bool isImplicit() const { return StartLoc.isInvalid();} + + StmtRange children(); + ConstStmtRange children() const { + return const_cast(this)->children(); + } + static bool classof(const OMPClause *T) { + return true; + } +}; + +/// \brief This represents clauses with the list of variables like 'private', +/// 'firstprivate', 'copyin', 'shared', or 'reduction' clauses in the +/// '#pragma omp ...' directives. +template +class OMPVarList { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief Number of variables in the list. + unsigned NumVars; +protected: + /// \brief Fetches list of variables associated with this clause. + llvm::MutableArrayRef getVarRefs() { + return llvm::MutableArrayRef( + reinterpret_cast(static_cast(this) + 1), + NumVars); + } + + /// \brief Sets the list of variables for this clause. + void setVarRefs(ArrayRef VL) { + assert(VL.size() == NumVars && + "Number of variables is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), + reinterpret_cast(static_cast(this) + 1)); + } + + /// \brief Build clause with number of variables \a N. + /// + /// \param N Number of the variables in the clause. + /// + OMPVarList(SourceLocation LParenLoc, unsigned N) + : LParenLoc(LParenLoc), NumVars(N) { } +public: + 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; } + varlist_iterator varlist_begin() { return getVarRefs().begin(); } + varlist_iterator varlist_end() { return getVarRefs().end(); } + varlist_const_iterator varlist_begin() const { return getVarRefs().begin(); } + varlist_const_iterator varlist_end() const { return getVarRefs().end(); } + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Fetches list of all variables in the clause. + ArrayRef getVarRefs() const { + return ArrayRef( + reinterpret_cast(static_cast(this) + 1), + NumVars); + } +}; + +/// \brief This represents 'default' clause in the '#pragma omp ...' directive. +/// +/// \code +/// #pragma omp parallel default(shared) +/// \endcode +/// In this example directive '#pragma omp parallel' has simple 'default' +/// clause with kind 'shared'. +/// +class OMPDefaultClause : public OMPClause { + friend class OMPClauseReader; + /// \brief Location of '('. + SourceLocation LParenLoc; + /// \brief A kind of the 'default' clause. + OpenMPDefaultClauseKind Kind; + /// \brief Start location of the kind in source code. + SourceLocation KindKwLoc; + + /// \brief Set kind of the clauses. + /// + /// \param K Argument of clause. + /// + void setDefaultKind(OpenMPDefaultClauseKind K) { Kind = K; } + + /// \brief Set argument location. + /// + /// \param KLoc Argument location. + /// + void setDefaultKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; } +public: + /// \brief Build 'default' clause with argument \a A ('none' or 'shared'). + /// + /// \param A Argument of the clause ('none' or 'shared'). + /// \param ALoc Starting location of the argument. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// + OMPDefaultClause(OpenMPDefaultClauseKind A, SourceLocation ALoc, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc) + : OMPClause(OMPC_default, StartLoc, EndLoc), LParenLoc(LParenLoc), + Kind(A), KindKwLoc(ALoc) { } + + /// \brief Build an empty clause. + /// + OMPDefaultClause() + : OMPClause(OMPC_default, SourceLocation(), SourceLocation()), + LParenLoc(SourceLocation()), Kind(OMPC_DEFAULT_unknown), + KindKwLoc(SourceLocation()) { } + + /// \brief Sets the location of '('. + void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; } + /// \brief Returns the location of '('. + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Returns kind of the clause. + OpenMPDefaultClauseKind getDefaultKind() const { return Kind; } + + /// \brief Returns location of clause kind. + SourceLocation getDefaultKindKwLoc() const { return KindKwLoc; } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_default; + } + + StmtRange children() { + return StmtRange(); + } +}; + +/// \brief This represents clause 'private' in the '#pragma omp ...' directives. +/// +/// \code +/// #pragma omp parallel private(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'private' +/// with the variables 'a' and 'b'. +/// +class OMPPrivateClause : public OMPClause, public OMPVarList { + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPPrivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPClause(OMPC_private, StartLoc, EndLoc), + OMPVarList(LParenLoc, N) { } + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPPrivateClause(unsigned N) + : OMPClause(OMPC_private, SourceLocation(), SourceLocation()), + OMPVarList(SourceLocation(), N) { } +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPPrivateClause *Create(ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef VL); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPPrivateClause *CreateEmpty(ASTContext &C, unsigned N); + + StmtRange children() { + return StmtRange(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_private; + } +}; + +//===----------------------------------------------------------------------===// +// AST classes for directives. +//===----------------------------------------------------------------------===// + +/// \brief This is a basic class for representing single OpenMP executable +/// directive. +/// +class OMPExecutableDirective : public Stmt { + friend class ASTStmtReader; + /// \brief Kind of the directive. + OpenMPDirectiveKind Kind; + /// \brief Starting location of the directive (directive keyword). + SourceLocation StartLoc; + /// \brief Ending location of the directive. + SourceLocation EndLoc; + /// \brief Pointer to the list of clauses. + llvm::MutableArrayRef Clauses; + /// \brief Associated statement (if any) and expressions. + llvm::MutableArrayRef StmtAndExpressions; +protected: + /// \brief Build instance of directive of class \a K. + /// + /// \param SC Statement class. + /// \param K Kind of OpenMP directive. + /// \brief StartLoc Starting location of the directive (directive keyword). + /// \param EndLocL Ending location of the directive. + /// \param Clauses A list of clauses. + /// + template + OMPExecutableDirective(const T *, StmtClass SC, OpenMPDirectiveKind K, + SourceLocation StartLoc, SourceLocation EndLoc, + unsigned NumClauses, unsigned NumberOfExpressions) + : Stmt(SC), Kind(K), StartLoc(StartLoc), EndLoc(EndLoc), + Clauses(reinterpret_cast(static_cast(this) + 1), + NumClauses), + StmtAndExpressions(reinterpret_cast(Clauses.end()), + NumberOfExpressions) { } + + /// \brief Sets the list of variables for this clause. + /// + /// \param Clauses The list of clauses for the directive. + /// + void setClauses(ArrayRef Clauses); + + /// \brief Set the associated statement for the directive. + /// + /// /param S Associated statement. + /// + void setAssociatedStmt(Stmt *S) { + StmtAndExpressions[0] = S; + } + +public: + /// \brief Returns starting location of directive kind. + SourceLocation getLocStart() const { return StartLoc; } + /// \brief Returns ending location of directive. + SourceLocation getLocEnd() const { return EndLoc; } + + /// \brief Set starting location of directive kind. + /// + /// \param Loc New starting location of directive. + /// + void setLocStart(SourceLocation Loc) { StartLoc = Loc; } + /// \brief Set ending location of directive. + /// + /// \param Loc New ending location of directive. + /// + void setLocEnd(SourceLocation Loc) { EndLoc = Loc; } + + /// \brief Get number of clauses. + unsigned getNumClauses() const { return Clauses.size(); } + + /// \brief Returns specified clause. + /// + /// \param i Number of clause. + /// + OMPClause *getClause(unsigned i) const { + assert(i < Clauses.size() && "index out of bound!"); + return Clauses[i]; + } + + /// \brief Returns statement associated with the directive. + Stmt *getAssociatedStmt() const { + return StmtAndExpressions[0]; + } + + OpenMPDirectiveKind getDirectiveKind() const { return Kind; } + + static bool classof(const Stmt *S) { + return S->getStmtClass() >= firstOMPExecutableDirectiveConstant && + S->getStmtClass() <= lastOMPExecutableDirectiveConstant; + } + + child_range children() { + return child_range(StmtAndExpressions.begin(), StmtAndExpressions.end()); + } + + ArrayRef clauses() { return Clauses; } + + ArrayRef clauses() const { return Clauses; } +}; + +/// \brief This represents '#pragma omp parallel' directive. +/// +/// \code +/// #pragma omp parallel private(a,b) reduction(+: c,d) +/// \endcode +/// In this example directive '#pragma omp parallel' has clauses 'private' +/// with the variables 'a' and 'b' and 'reduction' with operator '+' and +/// variables 'c' and 'd'. +/// +class OMPParallelDirective : public OMPExecutableDirective { + /// \brief Build directive with the given start and end location. + /// + /// \brief StartLoc Starting location of the directive (directive keyword). + /// \param EndLoc Ending Location of the directive. + /// + OMPParallelDirective(SourceLocation StartLoc, SourceLocation EndLoc, + unsigned N) + : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel, + StartLoc, EndLoc, N, 1) { } + + /// \brief Build an empty directive. + /// + /// \param N Number of clauses. + /// + explicit OMPParallelDirective(unsigned N) + : OMPExecutableDirective(this, OMPParallelDirectiveClass, OMPD_parallel, + SourceLocation(), SourceLocation(), N, 1) { } +public: + /// \brief Creates directive with a list of \a Clauses. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the directive kind. + /// \param EndLoc Ending Location of the directive. + /// \param Clauses List of clauses. + /// \param AssociatedStmt Statement associated with the directive. + /// + static OMPParallelDirective *Create(ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt); + + /// \brief Creates an empty directive with the place for \a N clauses. + /// + /// \param C AST context. + /// \param N The number of clauses. + /// + static OMPParallelDirective *CreateEmpty(ASTContext &C, unsigned N, + EmptyShell); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OMPParallelDirectiveClass; + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/AST/StmtVisitor.h b/include/clang/AST/StmtVisitor.h index 38c4c0220e..c71af38b61 100644 --- a/include/clang/AST/StmtVisitor.h +++ b/include/clang/AST/StmtVisitor.h @@ -18,6 +18,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" namespace clang { @@ -184,6 +185,41 @@ template class ConstStmtVisitor : public StmtVisitorBase {}; +/// \brief This class implements a simple visitor for OMPClause +/// subclasses. +template class Ptr, typename RetTy> +class OMPClauseVisitorBase { +public: +#define PTR(CLASS) typename Ptr::type +#define DISPATCH(CLASS) \ + return static_cast(this)->Visit##CLASS(static_cast(S)) + +#define OPENMP_CLAUSE(Name, Class) \ + RetTy Visit ## Class (PTR(Class) S) { DISPATCH(Class); } +#include "clang/Basic/OpenMPKinds.def" + + RetTy Visit(PTR(OMPClause) S) { + // Top switch clause: visit each OMPClause. + switch (S->getClauseKind()) { + default: llvm_unreachable("Unknown clause kind!"); +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_ ## Name : return Visit ## Class(static_cast(S)); +#include "clang/Basic/OpenMPKinds.def" + } + } + // Base case, ignore it. :) + RetTy VisitOMPClause(PTR(OMPClause) Node) { return RetTy(); } +#undef PTR +#undef DISPATCH +}; + +template +class OMPClauseVisitor : + public OMPClauseVisitorBase {}; +template +class ConstOMPClauseVisitor : + public OMPClauseVisitorBase {}; + } // end namespace clang #endif diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 6fb0b97212..b99b0373ca 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -837,6 +837,16 @@ 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">; +def err_omp_expected_punc : Error < + "expected ',' or ')' in %select{'#pragma omp %1'|'%1' clause}0">; +def err_omp_unknown_clause : Error < + "expected OpenMP clause for directive '#pragma omp %0' or end of directive">; +def err_omp_unexpected_clause : Error < + "unexpected OpenMP clause '%0' in directive '#pragma omp %1'">; +def err_omp_more_one_clause : Error < + "directive '#pragma omp %0' cannot contain more than one '%1' clause">; } // end of Parse Issue category. let CategoryName = "Modules Issue" in { diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 7bbd25b934..4bd26d8322 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6485,13 +6485,25 @@ def err_omp_expected_var_arg_suggest : Error< 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">; + "arguments of '#pragma omp %0' cannot be of reference type %1">; def err_omp_var_scope : Error< "'#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 %q1">; def err_omp_var_thread_local : Error< "variable %0 cannot be threadprivate because it is thread-local">; +def err_omp_private_incomplete_type : Error< + "a private variable with incomplete type %0">; +def err_omp_directive_nonblock : Error< + "directive '#pragma omp %0' bound to nonblock statement">; +def err_omp_unexpected_clause_value : Error < + "expected %0 in OpenMP clause '%1'">; +def err_omp_expected_var_name : Error < + "expected variable name">; +def err_omp_required_method : Error < + "%0 variable must have an accessible, unambiguous %select{default constructor|copy constructor|copy assignment operator|'%2'|destructor}1">; +def err_omp_clause_ref_type_arg : Error< + "arguments of OpenMP clause '%0' cannot be of reference type %1">; def err_omp_threadprivate_incomplete_type : Error< "threadprivate variable with incomplete type %0">; } // end of OpenMP category diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def index f968977f64..4e15cfec4d 100644 --- a/include/clang/Basic/OpenMPKinds.def +++ b/include/clang/Basic/OpenMPKinds.def @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// /// \file -/// \brief This file defines the list of supported OpenMP directives and +/// \brief This file defines the list of supported OpenMP directives and /// clauses. /// //===----------------------------------------------------------------------===// @@ -15,9 +15,34 @@ #ifndef OPENMP_DIRECTIVE # define OPENMP_DIRECTIVE(Name) #endif +#ifndef OPENMP_CLAUSE +# define OPENMP_CLAUSE(Name, Class) +#endif +#ifndef OPENMP_PARALLEL_CLAUSE +# define OPENMP_PARALLEL_CLAUSE(Name) +#endif +#ifndef OPENMP_DEFAULT_KIND +# define OPENMP_DEFAULT_KIND(Name) +#endif // OpenMP directives. OPENMP_DIRECTIVE(threadprivate) OPENMP_DIRECTIVE(parallel) +OPENMP_DIRECTIVE(task) + +// OpenMP clauses. +OPENMP_CLAUSE(default, OMPDefaultClause) +OPENMP_CLAUSE(private, OMPPrivateClause) + +// Clauses allowed for OpenMP directives. +OPENMP_PARALLEL_CLAUSE(default) +OPENMP_PARALLEL_CLAUSE(private) + +// Static attributes for 'default' clause. +OPENMP_DEFAULT_KIND(none) +OPENMP_DEFAULT_KIND(shared) +#undef OPENMP_DEFAULT_KIND #undef OPENMP_DIRECTIVE +#undef OPENMP_CLAUSE +#undef OPENMP_PARALLEL_CLAUSE diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h index c90e9a0a76..5b4573124f 100644 --- a/include/clang/Basic/OpenMPKinds.h +++ b/include/clang/Basic/OpenMPKinds.h @@ -28,9 +28,37 @@ enum OpenMPDirectiveKind { NUM_OPENMP_DIRECTIVES }; +/// \brief OpenMP clauses. +enum OpenMPClauseKind { + OMPC_unknown = 0, +#define OPENMP_CLAUSE(Name, Class) \ + OMPC_##Name, +#include "clang/Basic/OpenMPKinds.def" + OMPC_threadprivate, + NUM_OPENMP_CLAUSES +}; + +/// \brief OpenMP attributes for 'default' clause. +enum OpenMPDefaultClauseKind { + OMPC_DEFAULT_unknown = 0, +#define OPENMP_DEFAULT_KIND(Name) \ + OMPC_DEFAULT_##Name, +#include "clang/Basic/OpenMPKinds.def" + NUM_OPENMP_DEFAULT_KINDS +}; + OpenMPDirectiveKind getOpenMPDirectiveKind(llvm::StringRef Str); const char *getOpenMPDirectiveName(OpenMPDirectiveKind Kind); +OpenMPClauseKind getOpenMPClauseKind(llvm::StringRef Str); +const char *getOpenMPClauseName(OpenMPClauseKind Kind); + +unsigned getOpenMPSimpleClauseType(OpenMPClauseKind Kind, llvm::StringRef Str); +const char *getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, unsigned Type); + +bool isAllowedClauseForDirective(OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind); + } #endif diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index a9c6259405..0da9b34028 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -175,3 +175,7 @@ def MSDependentExistsStmt : Stmt; // OpenCL Extensions. def AsTypeExpr : DStmt; + +// OpenMP Directives. +def OMPExecutableDirective : Stmt<1>; +def OMPParallelDirective : DStmt; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index b376597e1b..d4c867d89c 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -45,6 +45,7 @@ namespace clang { class InMessageExpressionRAIIObject; class PoisonSEHIdentifiersRAIIObject; class VersionTuple; + class OMPClause; /// Parser - This implements a parser for the C family of languages. After /// parsing units of the grammar, productions are invoked to handle whatever has @@ -2155,6 +2156,32 @@ private: bool ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, SmallVectorImpl &VarList, bool AllowScopeSpecifier); + /// \brief Parses declarative or executable directive. + StmtResult ParseOpenMPDeclarativeOrExecutableDirective(); + /// \brief Parses clause of kind \a CKind for directive of a kind \a Kind. + /// + /// \param DKind Kind of current directive. + /// \param CKind Kind of current clause. + /// \param FirstClause true, if this is the first clause of a kind \a CKind + /// in current directive. + /// + OMPClause *ParseOpenMPClause(OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind, bool FirstClause); + /// \brief Parses clause with a single expression of a kind \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPSingleExprClause(OpenMPClauseKind Kind); + /// \brief Parses simple clause of a kind \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPSimpleClause(OpenMPClauseKind Kind); + /// \brief Parses clause with the list of variables of a kind \a Kind. + /// + /// \param Kind Kind of current clause. + /// + OMPClause *ParseOpenMPVarListClause(OpenMPClauseKind Kind); public: bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, bool AllowDestructorName, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 835151aa98..6501e52fe0 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -23,9 +23,11 @@ #include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" @@ -4807,6 +4809,9 @@ public: const PartialDiagnostic &PDiag, QualType objectType = QualType()); AccessResult CheckFriendAccess(NamedDecl *D); + AccessResult CheckMemberAccess(SourceLocation UseLoc, + CXXRecordDecl *NamingClass, + NamedDecl *D); AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, Expr *ArgExpr, @@ -6781,6 +6786,42 @@ public: SourceLocation Loc, ArrayRef VarList); + StmtResult ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, + ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed '\#pragma omp parallel' after parsing + /// of the associated statement. + StmtResult ActOnOpenMPParallelDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, + unsigned Argument, + SourceLocation ArgumentLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'default' clause. + OMPClause *ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, + SourceLocation KindLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + + OMPClause *ActOnOpenMPVarListClause(OpenMPClauseKind Kind, + ArrayRef Vars, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief Called on well-formed 'private' clause. + OMPClause *ActOnOpenMPPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); + /// \brief The kind of conversion being performed. enum CheckedConversionKind { /// \brief An implicit conversion. diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index ec05cc216b..7b954302a1 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1054,7 +1054,7 @@ namespace clang { DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, /// \brief An ImportDecl recording a module import. DECL_IMPORT, - /// \brief A OMPThreadPrivateDecl record. + /// \brief An OMPThreadPrivateDecl record. DECL_OMP_THREADPRIVATE, /// \brief An EmptyDecl record. DECL_EMPTY @@ -1319,7 +1319,10 @@ namespace clang { STMT_SEH_EXCEPT, // SEHExceptStmt STMT_SEH_FINALLY, // SEHFinallyStmt STMT_SEH_TRY, // SEHTryStmt - + + // OpenMP drectives + STMT_OMP_PARALLEL_DIRECTIVE, + // ARC EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr diff --git a/lib/AST/DeclOpenMP.cpp b/lib/AST/DeclOpenMP.cpp index 522caefe3b..0d195f7462 100644 --- a/lib/AST/DeclOpenMP.cpp +++ b/lib/AST/DeclOpenMP.cpp @@ -58,3 +58,4 @@ void OMPThreadPrivateDecl::setVars(ArrayRef VL) { Expr **Vars = reinterpret_cast(this + 1); std::copy(VL.begin(), VL.end(), Vars); } + diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index d9d79f4ccc..6a39996cac 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetInfo.h" @@ -1118,3 +1119,54 @@ bool CapturedStmt::capturesVariable(const VarDecl *Var) const { return false; } + +OMPPrivateClause *OMPPrivateClause::Create(ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef VL) { + void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * VL.size(), + llvm::alignOf()); + OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc, + EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPPrivateClause *OMPPrivateClause::CreateEmpty(ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(sizeof(OMPPrivateClause) + sizeof(Expr *) * N, + llvm::alignOf()); + return new (Mem) OMPPrivateClause(N); +} + +void OMPExecutableDirective::setClauses(ArrayRef Clauses) { + assert(Clauses.size() == this->Clauses.size() && + "Number of clauses is not the same as the preallocated buffer"); + std::copy(Clauses.begin(), Clauses.end(), this->Clauses.begin()); +} + +OMPParallelDirective *OMPParallelDirective::Create( + ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + Stmt *AssociatedStmt) { + void *Mem = C.Allocate(sizeof(OMPParallelDirective) + + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *), + llvm::alignOf()); + OMPParallelDirective *Dir = new (Mem) OMPParallelDirective(StartLoc, EndLoc, + Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPParallelDirective *OMPParallelDirective::CreateEmpty(ASTContext &C, + unsigned N, + EmptyShell) { + void *Mem = C.Allocate(sizeof(OMPParallelDirective) + + sizeof(OMPClause *) * N + sizeof(Stmt *), + llvm::alignOf()); + return new (Mem) OMPParallelDirective(N); +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index d635802390..c1732cdfd1 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -579,6 +579,67 @@ void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) { OS << "\n"; } +//===----------------------------------------------------------------------===// +// OpenMP clauses printing methods +//===----------------------------------------------------------------------===// + +namespace { +class OMPClausePrinter : public OMPClauseVisitor { + raw_ostream &OS; +public: + OMPClausePrinter(raw_ostream &OS) : OS(OS) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" +}; + +void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) { + OS << "default(" + << getOpenMPSimpleClauseTypeName(OMPC_default, Node->getDefaultKind()) + << ")"; +} + +#define PROCESS_OMP_CLAUSE_LIST(Class, Node, StartSym) \ + for (OMPVarList::varlist_iterator I = Node->varlist_begin(), \ + E = Node->varlist_end(); \ + I != E; ++I) \ + OS << (I == Node->varlist_begin() ? StartSym : ',') \ + << *cast(cast(*I)->getDecl()); + +void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) { + if (!Node->varlist_empty()) { + OS << "private"; + PROCESS_OMP_CLAUSE_LIST(OMPPrivateClause, Node, '(') + OS << ")"; + } +} + +#undef PROCESS_OMP_CLAUSE_LIST +} + +//===----------------------------------------------------------------------===// +// OpenMP directives printing methods +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) { + Indent() << "#pragma omp parallel "; + + OMPClausePrinter Printer(OS); + ArrayRef Clauses = Node->clauses(); + for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) + if (*I && !(*I)->isImplicit()) { + Printer.Visit(*I); + OS << ' '; + } + OS << "\n"; + if (Node->getAssociatedStmt()) { + assert(isa(Node->getAssociatedStmt()) && + "Expected captured statement!"); + Stmt *CS = cast(Node->getAssociatedStmt())->getCapturedStmt(); + PrintStmt(CS); + } +} //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 391c1e60ab..a626f68aa5 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -252,6 +252,40 @@ StmtProfiler::VisitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt *S) { VisitStmt(S); } +namespace { +class OMPClauseProfiler : public ConstOMPClauseVisitor { + StmtProfiler *Profiler; +public: + OMPClauseProfiler(StmtProfiler *P) : Profiler(P) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(const Class *C); +#include "clang/Basic/OpenMPKinds.def" +}; + +void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { } +#define PROCESS_OMP_CLAUSE_LIST(Class, Node) \ + for (OMPVarList::varlist_const_iterator I = Node->varlist_begin(), \ + E = Node->varlist_end(); \ + I != E; ++I) \ + Profiler->VisitStmt(*I); + +void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { + PROCESS_OMP_CLAUSE_LIST(OMPPrivateClause, C) +} +#undef PROCESS_OMP_CLAUSE_LIST +} + +void +StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { + VisitStmt(S); + OMPClauseProfiler P(this); + ArrayRef Clauses = S->clauses(); + for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) + if (*I) + P.Visit(*I); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index b90fbc7a7c..8f2d74d6fa 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -36,9 +36,94 @@ const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { #define OPENMP_DIRECTIVE(Name) \ case OMPD_##Name : return #Name; #include "clang/Basic/OpenMPKinds.def" - default: + case NUM_OPENMP_DIRECTIVES: break; } llvm_unreachable("Invalid OpenMP directive kind"); } +OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) { + return llvm::StringSwitch(Str) +#define OPENMP_CLAUSE(Name, Class) \ + .Case(#Name, OMPC_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_unknown); +} + +const char *clang::getOpenMPClauseName(OpenMPClauseKind Kind) { + assert(Kind < NUM_OPENMP_CLAUSES); + switch (Kind) { + case OMPC_unknown: + return "unknown"; +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name : return #Name; +#include "clang/Basic/OpenMPKinds.def" + case OMPC_threadprivate: + return "threadprivate or thread local"; + case NUM_OPENMP_CLAUSES: + break; + } + llvm_unreachable("Invalid OpenMP clause kind"); +} + +unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, + StringRef Str) { + switch (Kind) { + case OMPC_default: + return llvm::StringSwitch(Str) +#define OPENMP_DEFAULT_KIND(Name) \ + .Case(#Name, OMPC_DEFAULT_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_DEFAULT_unknown); + case OMPC_unknown: + case OMPC_threadprivate: + case OMPC_private: + case NUM_OPENMP_CLAUSES: + break; + } + llvm_unreachable("Invalid OpenMP simple clause kind"); +} + +const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, + unsigned Type) { + switch (Kind) { + case OMPC_default: + switch (Type) { + case OMPC_DEFAULT_unknown: + return "unknown"; +#define OPENMP_DEFAULT_KIND(Name) \ + case OMPC_DEFAULT_##Name : return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'default' clause type"); + case OMPC_unknown: + case OMPC_threadprivate: + case OMPC_private: + case NUM_OPENMP_CLAUSES: + break; + } + llvm_unreachable("Invalid OpenMP simple clause kind"); +} + +bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind) { + assert(DKind < NUM_OPENMP_DIRECTIVES); + assert(CKind < NUM_OPENMP_CLAUSES); + switch (DKind) { + case OMPD_parallel: + switch (CKind) { +#define OPENMP_PARALLEL_CLAUSE(Name) \ + case OMPC_##Name: return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; + case OMPD_unknown: + case OMPD_threadprivate: + case OMPD_task: + case NUM_OPENMP_DIRECTIVES: + break; + } + return false; +} diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index 8ee919754b..6c7bd88c0c 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -75,6 +75,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::SEHExceptStmtClass: case Stmt::SEHFinallyStmtClass: case Stmt::MSDependentExistsStmtClass: + case Stmt::OMPParallelDirectiveClass: llvm_unreachable("invalid statement class to emit generically"); case Stmt::NullStmtClass: case Stmt::CompoundStmtClass: diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp index e192ae2e23..2f6be9e787 100644 --- a/lib/Parse/ParseOpenMP.cpp +++ b/lib/Parse/ParseOpenMP.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ASTConsumer.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Sema/Scope.h" @@ -57,7 +58,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; - default: + case OMPD_parallel: + case OMPD_task: + case NUM_OPENMP_DIRECTIVES: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); break; @@ -66,6 +69,111 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { return DeclGroupPtrTy(); } +/// \brief Parsing of declarative or executable OpenMP directives. +/// +/// threadprivate-directive: +/// annot_pragma_openmp 'threadprivate' simple-variable-list +/// annot_pragma_openmp_end +/// +/// parallel-directive: +/// annot_pragma_openmp 'parallel' {clause} annot_pragma_openmp_end +/// +StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() { + assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + SmallVector Identifiers; + SmallVector Clauses; + SmallVector, NUM_OPENMP_CLAUSES> + FirstClauses(NUM_OPENMP_CLAUSES); + const unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope; + SourceLocation Loc = ConsumeToken(), EndLoc; + OpenMPDirectiveKind DKind = Tok.isAnnotation() ? + OMPD_unknown : + getOpenMPDirectiveKind(PP.getSpelling(Tok)); + StmtResult Directive = StmtError(); + + switch (DKind) { + case OMPD_threadprivate: + ConsumeToken(); + if (!ParseOpenMPSimpleVarList(OMPD_threadprivate, Identifiers, false)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_threadprivate); + SkipUntil(tok::annot_pragma_openmp_end, false, true); + } + DeclGroupPtrTy Res = + Actions.ActOnOpenMPThreadprivateDirective(Loc, + Identifiers); + Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); + } + SkipUntil(tok::annot_pragma_openmp_end, false); + break; + case OMPD_parallel: { + ConsumeToken(); + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + OpenMPClauseKind CKind = Tok.isAnnotation() ? + OMPC_unknown : + getOpenMPClauseKind(PP.getSpelling(Tok)); + OMPClause *Clause = ParseOpenMPClause(DKind, CKind, + !FirstClauses[CKind].getInt()); + FirstClauses[CKind].setInt(true); + if (Clause) { + FirstClauses[CKind].setPointer(Clause); + Clauses.push_back(Clause); + } + + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + } + // End location of the directive. + EndLoc = Tok.getLocation(); + // Consume final annot_pragma_openmp_end. + ConsumeToken(); + + StmtResult AssociatedStmt; + bool CreateDirective = true; + ParseScope OMPDirectiveScope(this, ScopeFlags); + { + // The body is a block scope like in Lambdas and Blocks. + Sema::CompoundScopeRAII CompoundScope(Actions); + Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default, 1); + Actions.ActOnStartOfCompoundStmt(); + // Parse statement + AssociatedStmt = ParseStatement(); + Actions.ActOnFinishOfCompoundStmt(); + if (!AssociatedStmt.isUsable()) { + Actions.ActOnCapturedRegionError(); + CreateDirective = false; + } else { + AssociatedStmt = Actions.ActOnCapturedRegionEnd(AssociatedStmt.take()); + CreateDirective = AssociatedStmt.isUsable(); + } + } + if (CreateDirective) + Directive = Actions.ActOnOpenMPExecutableDirective(DKind, Clauses, + AssociatedStmt.take(), + Loc, EndLoc); + + // Exit scope. + OMPDirectiveScope.Exit(); + } + break; + case OMPD_unknown: + Diag(Tok, diag::err_omp_unknown_directive); + SkipUntil(tok::annot_pragma_openmp_end, false); + break; + case OMPD_task: + case NUM_OPENMP_DIRECTIVES: + Diag(Tok, diag::err_omp_unexpected_directive) + << getOpenMPDirectiveName(DKind); + SkipUntil(tok::annot_pragma_openmp_end, false); + break; + } + return Directive; +} + /// \brief Parses list of simple variables for '#pragma omp threadprivate' /// directive. /// @@ -78,9 +186,10 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, VarList.clear(); // Parse '('. 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; + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(Kind))) + return true; + bool IsCorrect = true; bool NoIdentIsFound = true; // Read tokens while ')' or annot_pragma_openmp_end is not found. @@ -128,8 +237,130 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, } // Parse ')'. - IsCorrect = ((LParen || Tok.is(tok::r_paren)) && !T.consumeClose()) - && IsCorrect; + IsCorrect = !T.consumeClose() && IsCorrect; return !IsCorrect && VarList.empty(); } + +/// \brief Parsing of OpenMP clauses. +/// +/// clause: +/// default-clause|private-clause +/// +OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, + OpenMPClauseKind CKind, bool FirstClause) { + OMPClause *Clause = 0; + bool ErrorFound = false; + // Check if clause is allowed for the given directive. + if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) { + Diag(Tok, diag::err_omp_unexpected_clause) + << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + ErrorFound = true; + } + + switch (CKind) { + case OMPC_default: + // OpenMP [2.9.3.1, Restrictions] + // Only a single default clause may be specified on a parallel or task + // directive. + if (!FirstClause) { + Diag(Tok, diag::err_omp_more_one_clause) + << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind); + } + + Clause = ParseOpenMPSimpleClause(CKind); + break; + case OMPC_private: + Clause = ParseOpenMPVarListClause(CKind); + break; + case OMPC_unknown: + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(DKind); + SkipUntil(tok::annot_pragma_openmp_end, false, true); + break; + case OMPC_threadprivate: + case NUM_OPENMP_CLAUSES: + Diag(Tok, diag::err_omp_unexpected_clause) + << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); + SkipUntil(tok::comma, tok::annot_pragma_openmp_end, false, true); + break; + } + return ErrorFound ? 0 : Clause; +} + +/// \brief Parsing of simple OpenMP clauses like 'default'. +/// +/// default-clause: +/// 'default' '(' 'none' | 'shared' ') +/// +OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind))) + return 0; + + unsigned Type = Tok.isAnnotation() ? + OMPC_DEFAULT_unknown : + getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + SourceLocation TypeLoc = Tok.getLocation(); + if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && + Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + + // Parse ')'. + T.consumeClose(); + + return Actions.ActOnOpenMPSimpleClause(Kind, Type, TypeLoc, LOpen, Loc, + Tok.getLocation()); +} + +/// \brief Parsing of OpenMP clause 'private', 'firstprivate', +/// 'shared', 'copyin', or 'reduction'. +/// +/// private-clause: +/// 'private' '(' list ')' +/// +OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) { + SourceLocation Loc = Tok.getLocation(); + SourceLocation LOpen = ConsumeToken(); + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPClauseName(Kind))) + return 0; + + SmallVector Vars; + bool IsComma = true; + while (IsComma || (Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end))) { + // Parse variable + ExprResult VarExpr = ParseAssignmentExpression(); + if (VarExpr.isUsable()) { + Vars.push_back(VarExpr.take()); + } else { + SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end, + false, true); + } + // Skip ',' if any + IsComma = Tok.is(tok::comma); + if (IsComma) { + ConsumeToken(); + } else if (Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::err_omp_expected_punc) + << 1 << getOpenMPClauseName(Kind); + } + } + + // Parse ')'. + T.consumeClose(); + if (Vars.empty()) + return 0; + + return Actions.ActOnOpenMPVarListClause(Kind, Vars, Loc, LOpen, + Tok.getLocation()); +} + diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 749fec3026..b03891082f 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -306,9 +306,8 @@ Retry: return HandlePragmaCaptured(); case tok::annot_pragma_openmp: - SourceLocation DeclStart = Tok.getLocation(); - DeclGroupPtrTy Res = ParseOpenMPDeclarativeDirective(); - return Actions.ActOnDeclStmt(Res, DeclStart, Tok.getLocation()); + return ParseOpenMPDeclarativeOrExecutableDirective(); + } // If we reached this code, the statement must end in a semicolon. diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index a99992748d..020787b39a 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1710,6 +1710,21 @@ Sema::AccessResult Sema::CheckAllocationAccess(SourceLocation OpLoc, return CheckAccess(*this, OpLoc, Entity); } +/// \brief Checks access to a member. +Sema::AccessResult Sema::CheckMemberAccess(SourceLocation UseLoc, + CXXRecordDecl *NamingClass, + NamedDecl *D) { + if (!getLangOpts().AccessControl || + !NamingClass || + D->getAccess() == AS_public) + return AR_accessible; + + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(D, D->getAccess()), QualType()); + + return CheckAccess(*this, UseLoc, Entity); +} + /// Checks access to an overloaded member operator, including /// conversion operators. Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 4953d2d14e..993eaba86e 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -14,10 +14,17 @@ #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 { @@ -165,7 +172,8 @@ 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); + << getOpenMPDirectiveName(OMPD_threadprivate) + << VD->getType(); bool IsDecl = VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : @@ -191,3 +199,215 @@ OMPThreadPrivateDecl *Sema::CheckOMPThreadPrivateDecl( Loc, Vars); } +StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, + ArrayRef 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 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(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 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 VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector Vars; + for (ArrayRef::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + if (*I && isa(*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(*I); + if (!DE || !isa(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) + << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast(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( + 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); +} + diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 5b4716f5be..ef8049af84 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -24,6 +24,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" @@ -313,6 +314,16 @@ public: /// \returns the transformed statement. StmtResult TransformStmt(Stmt *S); + /// \brief Transform the given statement. + /// + /// By default, this routine transforms a statement by delegating to the + /// appropriate TransformOMPXXXClause function to transform a specific kind + /// of clause. Subclasses may override this function to transform statements + /// using some other mechanism. + /// + /// \returns the transformed OpenMP clause. + OMPClause *TransformOMPClause(OMPClause *S); + /// \brief Transform the given expression. /// /// By default, this routine transforms an expression by delegating to the @@ -594,6 +605,10 @@ public: #define ABSTRACT_STMT(Stmt) #include "clang/AST/StmtNodes.inc" +#define OPENMP_CLAUSE(Name, Class) \ + OMPClause *Transform ## Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" + /// \brief Build a new pointer type given its pointee type. /// /// By default, performs semantic analysis when building the pointer type. @@ -1255,6 +1270,43 @@ public: return getSema().BuildObjCAtThrowStmt(AtLoc, Operand); } + /// \brief Build a new OpenMP parallel directive. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + StmtResult RebuildOMPParallelDirective(ArrayRef Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPParallelDirective(Clauses, AStmt, + StartLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'default' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDefaultClause(OpenMPDefaultClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPDefaultClause(Kind, KindKwLoc, + StartLoc, LParenLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'private' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPPrivateClause(ArrayRef VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + /// \brief Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -2600,6 +2652,23 @@ StmtResult TreeTransform::TransformStmt(Stmt *S) { return SemaRef.Owned(S); } +template +OMPClause *TreeTransform::TransformOMPClause(OMPClause *S) { + if (!S) + return S; + + switch (S->getClauseKind()) { + default: break; + // Transform individual clause nodes +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_ ## Name : \ + return getDerived().Transform ## Class(cast(S)); +#include "clang/Basic/OpenMPKinds.def" + } + + return S; +} + template ExprResult TreeTransform::TransformExpr(Expr *E) { @@ -6178,6 +6247,67 @@ TreeTransform::TransformSEHHandler(Stmt *Handler) { return getDerived().TransformSEHExceptStmt(cast(Handler)); } +template +StmtResult +TreeTransform::TransformOMPParallelDirective(OMPParallelDirective *D) { + // Transform the clauses + llvm::SmallVector TClauses; + ArrayRef Clauses = D->clauses(); + TClauses.reserve(Clauses.size()); + for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) { + if (*I) { + OMPClause *Clause = getDerived().TransformOMPClause(*I); + if (!Clause) + return StmtError(); + TClauses.push_back(Clause); + } + else { + TClauses.push_back(0); + } + } + if (!D->getAssociatedStmt()) + return StmtError(); + StmtResult AssociatedStmt = + getDerived().TransformStmt(D->getAssociatedStmt()); + if (AssociatedStmt.isInvalid()) + return StmtError(); + + return getDerived().RebuildOMPParallelDirective(TClauses, + AssociatedStmt.take(), + D->getLocStart(), + D->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPDefaultClause(OMPDefaultClause *C) { + return getDerived().RebuildOMPDefaultClause(C->getDefaultKind(), + C->getDefaultKindKwLoc(), + C->getLocStart(), + C->getLParenLoc(), + C->getLocEnd()); +} + +template +OMPClause * +TreeTransform::TransformOMPPrivateClause(OMPPrivateClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (OMPVarList::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPPrivateClause(Vars, + C->getLocStart(), + C->getLParenLoc(), + C->getLocEnd()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 2f5dee8282..113b12ff59 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -25,6 +25,7 @@ using namespace clang::serialization; namespace clang { class ASTStmtReader : public StmtVisitor { + friend class OMPClauseReader; typedef ASTReader::RecordData RecordData; ASTReader &Reader; @@ -382,6 +383,7 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); + ++Idx; S->setCapturedDecl(ReadDeclAs(Record, Idx)); S->setCapturedRegionKind(static_cast(Record[Idx++])); S->setCapturedRecordDecl(ReadDeclAs(Record, Idx)); @@ -1655,6 +1657,81 @@ void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) { E->SrcExpr = Reader.ReadSubExpr(); } +//===----------------------------------------------------------------------===// +// OpenMP Clauses. +//===----------------------------------------------------------------------===// + +namespace clang { +class OMPClauseReader : public OMPClauseVisitor { + ASTStmtReader *Reader; + ASTContext &Context; + const ASTReader::RecordData &Record; + unsigned &Idx; +public: + OMPClauseReader(ASTStmtReader *R, ASTContext &C, + const ASTReader::RecordData &Record, unsigned &Idx) + : Reader(R), Context(C), Record(Record), Idx(Idx) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" + OMPClause *readClause(); +}; +} + +OMPClause *OMPClauseReader::readClause() { + OMPClause *C; + switch (Record[Idx++]) { + case OMPC_default: + C = new (Context) OMPDefaultClause(); + break; + case OMPC_private: + C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]); + break; + } + Visit(C); + C->setLocStart(Reader->ReadSourceLocation(Record, Idx)); + C->setLocEnd(Reader->ReadSourceLocation(Record, Idx)); + + return C; +} + +void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) { + C->setDefaultKind( + static_cast(Record[Idx++])); + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + C->setDefaultKindKwLoc(Reader->ReadSourceLocation(Record, Idx)); +} + +void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + unsigned NumVars = C->varlist_size(); + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setVarRefs(Vars); +} + +//===----------------------------------------------------------------------===// +// OpenMP Directives. +//===----------------------------------------------------------------------===// +void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) { + VisitStmt(E); + ++Idx; + E->setLocStart(ReadSourceLocation(Record, Idx)); + E->setLocEnd(ReadSourceLocation(Record, Idx)); + OMPClauseReader ClauseReader(this, Reader.getContext(), Record, Idx); + SmallVector Clauses; + for (unsigned i = 0; i < E->getNumClauses(); ++i) + Clauses.push_back(ClauseReader.readClause()); + E->setClauses(Clauses); + E->setAssociatedStmt(Reader.ReadSubStmt()); +} + +void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) { + VisitOMPExecutableDirective(D); +} + //===----------------------------------------------------------------------===// // ASTReader Implementation //===----------------------------------------------------------------------===// @@ -1821,7 +1898,7 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case STMT_CAPTURED: S = CapturedStmt::CreateDeserialized(Context, - Record[ASTStmtReader::NumExprFields]); + Record[ASTStmtReader::NumStmtFields]); break; case EXPR_PREDEFINED: @@ -2121,6 +2198,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { DeclarationNameInfo(), 0); break; + case STMT_OMP_PARALLEL_DIRECTIVE: + S = + OMPParallelDirective::CreateEmpty(Context, + Record[ASTStmtReader::NumStmtFields], + Empty); + break; case EXPR_CXX_OPERATOR_CALL: S = new (Context) CXXOperatorCallExpr(Context, Empty); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 4b01a218f5..8d47158f94 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -26,7 +26,9 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace clang { + class ASTStmtWriter : public StmtVisitor { + friend class OMPClauseWriter; ASTWriter &Writer; ASTWriter::RecordData &Record; @@ -1658,6 +1660,66 @@ void ASTStmtWriter::VisitSEHTryStmt(SEHTryStmt *S) { Code = serialization::STMT_SEH_TRY; } +//===----------------------------------------------------------------------===// +// OpenMP Clauses. +//===----------------------------------------------------------------------===// + +namespace clang { +class OMPClauseWriter : public OMPClauseVisitor { + ASTStmtWriter *Writer; + ASTWriter::RecordData &Record; +public: + OMPClauseWriter(ASTStmtWriter *W, ASTWriter::RecordData &Record) + : Writer(W), Record(Record) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" + void writeClause(OMPClause *C); +}; +} + +void OMPClauseWriter::writeClause(OMPClause *C) { + Record.push_back(C->getClauseKind()); + Visit(C); + Writer->Writer.AddSourceLocation(C->getLocStart(), Record); + Writer->Writer.AddSourceLocation(C->getLocEnd(), Record); +} + +void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) { + Record.push_back(C->getDefaultKind()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + Writer->Writer.AddSourceLocation(C->getDefaultKindKwLoc(), Record); +} + +void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { + Record.push_back(C->varlist_size()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + for (OMPVarList::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer->Writer.AddStmt(*I); +} + +//===----------------------------------------------------------------------===// +// OpenMP Directives. +//===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) { + VisitStmt(E); + Record.push_back(E->getNumClauses()); + Writer.AddSourceLocation(E->getLocStart(), Record); + Writer.AddSourceLocation(E->getLocEnd(), Record); + OMPClauseWriter ClauseWriter(this, Record); + for (unsigned i = 0; i < E->getNumClauses(); ++i) { + ClauseWriter.writeClause(E->getClause(i)); + } + Writer.AddStmt(E->getAssociatedStmt()); +} + +void ASTStmtWriter::VisitOMPParallelDirective(OMPParallelDirective *D) { + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_PARALLEL_DIRECTIVE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 74ffa1c9af..d42291da9c 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -665,6 +665,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::WhileStmtClass: case Expr::MSDependentExistsStmtClass: case Stmt::CapturedStmtClass: + case Stmt::OMPParallelDirectiveClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); case Stmt::ObjCSubscriptRefExprClass: diff --git a/test/OpenMP/parallel_ast_print.cpp b/test/OpenMP/parallel_ast_print.cpp new file mode 100644 index 0000000000..44108e7ec2 --- /dev/null +++ b/test/OpenMP/parallel_ast_print.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print | FileCheck %s +// expected-no-diagnostics + +#ifndef HEADER +#define HEADER + +void foo() {} + +int main (int argc, char **argv) { + int b = argc, c, d, e, f, g; + static int a; +// CHECK: static int a; +#pragma omp parallel +// CHECK-NEXT: #pragma omp parallel + a=2; +// CHECK-NEXT: a = 2; +#pragma omp parallel default(none), private(argc,b) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) + foo(); +// CHECK-NEXT: foo(); + return (0); +} + +#endif diff --git a/test/OpenMP/parallel_default_messages.cpp b/test/OpenMP/parallel_default_messages.cpp new file mode 100644 index 0000000000..e5e2572110 --- /dev/null +++ b/test/OpenMP/parallel_default_messages.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 -o - %s + +void foo(); + +int main(int argc, char **argv) { + #pragma omp parallel default // expected-error {{expected '(' after 'default'}} + #pragma omp parallel default ( // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel default () // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + #pragma omp parallel default (none // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel default (shared), default(shared) // expected-error {{directive '#pragma omp parallel' cannot contain more than one 'default' clause}} + #pragma omp parallel default (x) // expected-error {{expected 'none' or 'shared' in OpenMP clause 'default'}} + foo(); + + return 0; +} diff --git a/test/OpenMP/parallel_private_messages.cpp b/test/OpenMP/parallel_private_messages.cpp new file mode 100644 index 0000000000..e64fac8003 --- /dev/null +++ b/test/OpenMP/parallel_private_messages.cpp @@ -0,0 +1,69 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + static float S2s; +}; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } +}; +const S3 c; +const S3 ca[5]; +extern const int f; +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} +public: + S5(int v):a(v) { } +}; + +int main(int argc, char **argv) { + const int d = 5; + const int da[5] = { 0 }; + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); // expected-note {{'g' defined here}} + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp parallel private // expected-error {{expected '(' after 'private'}} + #pragma omp parallel private ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel private () // expected-error {{expected expression}} + #pragma omp parallel private (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel private (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel private (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp parallel private (argc argv) // expected-error {{expected ',' or ')' in 'private' clause}} + #pragma omp parallel private (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel private (a, b, c, d, f) // expected-error {{a private variable with incomplete type 'S1'}} + #pragma omp parallel private (argv[1]) // expected-error {{expected variable name}} + #pragma omp parallel private(ba) + #pragma omp parallel private(ca) + #pragma omp parallel private(da) + #pragma omp parallel private(S2::S2s) + #pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} + foo(); + #pragma omp parallel private(i) + #pragma omp parallel private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type 'int &'}} + foo(); + + return 0; +} diff --git a/test/OpenMP/threadprivate_ast_print.cpp b/test/OpenMP/threadprivate_ast_print.cpp index deb829e926..ddf488250a 100644 --- a/test/OpenMP/threadprivate_ast_print.cpp +++ b/test/OpenMP/threadprivate_ast_print.cpp @@ -1,6 +1,11 @@ // RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t +// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -ast-print // expected-no-diagnostics +#ifndef HEADER +#define HEADER + struct St{ int a; }; @@ -41,3 +46,5 @@ int main () { a=2; return (foo()); } + +#endif diff --git a/test/OpenMP/threadprivate_messages.cpp b/test/OpenMP/threadprivate_messages.cpp index 1bfba6d864..bfa596db34 100644 --- a/test/OpenMP/threadprivate_messages.cpp +++ b/test/OpenMP/threadprivate_messages.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -ferror-limit 100 %s -#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} expected-error {{expected identifier}} +#pragma omp threadprivate // expected-error {{expected '(' after 'threadprivate'}} #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}} @@ -24,7 +24,7 @@ int foo() { // expected-note {{declared here}} return (a); } -#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} expected-error {{'#pragma omp threadprivate' must precede all references to variable 'a'}} +#pragma omp threadprivate a // expected-error {{expected '(' after 'threadprivate'}} #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)) // 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; @@ -44,7 +44,7 @@ extern IncompleteSt e; #pragma omp threadprivate (e) // expected-error {{threadprivate variable with incomplete type 'IncompleteSt'}} int &f = a; // expected-note {{'f' defined here}} -#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type}} +#pragma omp threadprivate (f) // expected-error {{arguments of '#pragma omp threadprivate' cannot be of reference type 'int &'}} class Class { private: diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index ae131af333..9f6300a114 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -1802,6 +1802,7 @@ public: } }; class EnqueueVisitor : public ConstStmtVisitor { + friend class OMPClauseEnqueue; VisitorWorkList &WL; CXCursor Parent; public: @@ -1853,6 +1854,8 @@ public: void VisitPseudoObjectExpr(const PseudoObjectExpr *E); void VisitOpaqueValueExpr(const OpaqueValueExpr *E); void VisitLambdaExpr(const LambdaExpr *E); + void VisitOMPExecutableDirective(const OMPExecutableDirective *D); + void VisitOMPParallelDirective(const OMPParallelDirective *D); private: void AddDeclarationNameInfo(const Stmt *S); @@ -1863,6 +1866,7 @@ private: void AddDecl(const Decl *D, bool isFirst = true); void AddTypeLoc(TypeSourceInfo *TI); void EnqueueChildren(const Stmt *S); + void EnqueueChildren(const OMPClause *S); }; } // end anonyous namespace @@ -1911,6 +1915,39 @@ void EnqueueVisitor::EnqueueChildren(const Stmt *S) { VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); std::reverse(I, E); } +namespace { +class OMPClauseEnqueue : public ConstOMPClauseVisitor { + EnqueueVisitor *Visitor; +public: + OMPClauseEnqueue(EnqueueVisitor *Visitor) : Visitor(Visitor) { } +#define OPENMP_CLAUSE(Name, Class) \ + void Visit##Class(const Class *C); +#include "clang/Basic/OpenMPKinds.def" +}; + +void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { } +#define PROCESS_OMP_CLAUSE_LIST(Class, Node) \ + for (OMPVarList::varlist_const_iterator I = Node->varlist_begin(), \ + E = Node->varlist_end(); \ + I != E; ++I) \ + Visitor->AddStmt(*I); + +void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) { + PROCESS_OMP_CLAUSE_LIST(OMPPrivateClause, C) +} +#undef PROCESS_OMP_CLAUSE_LIST +} +void EnqueueVisitor::EnqueueChildren(const OMPClause *S) { + unsigned size = WL.size(); + OMPClauseEnqueue Visitor(this); + Visitor.Visit(S); + if (size == WL.size()) + return; + // Now reverse the entries we just added. This will match the DFS + // ordering performed by the worklist. + VisitorWorkList::iterator I = WL.begin() + size, E = WL.end(); + std::reverse(I, E); +} void EnqueueVisitor::VisitAddrLabelExpr(const AddrLabelExpr *E) { WL.push_back(LabelRefVisit(E->getLabel(), E->getLabelLoc(), Parent)); } @@ -2189,6 +2226,19 @@ void EnqueueVisitor::VisitPseudoObjectExpr(const PseudoObjectExpr *E) { Visit(E->getSyntacticForm()); } +void EnqueueVisitor::VisitOMPExecutableDirective( + const OMPExecutableDirective *D) { + EnqueueChildren(D); + for (ArrayRef::iterator I = D->clauses().begin(), + E = D->clauses().end(); + I != E; ++I) + EnqueueChildren(*I); +} + +void EnqueueVisitor::VisitOMPParallelDirective(const OMPParallelDirective *D) { + VisitOMPExecutableDirective(D); +} + void CursorVisitor::EnqueueWorkList(VisitorWorkList &WL, const Stmt *S) { EnqueueVisitor(WL, MakeCXCursor(S, StmtParent, TU,RegionOfInterest)).Visit(S); } @@ -3766,6 +3816,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return cxstring::createRef("CXXAccessSpecifier"); case CXCursor_ModuleImportDecl: return cxstring::createRef("ModuleImport"); + case CXCursor_OMPParallelDirective: + return cxstring::createRef("OMPParallelDirective"); } llvm_unreachable("Unhandled CXCursorKind"); diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 2be0d8294b..df39504787 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -505,6 +505,10 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent, case Stmt::MSDependentExistsStmtClass: K = CXCursor_UnexposedStmt; break; + case Stmt::OMPParallelDirectiveClass: + K = CXCursor_OMPParallelDirective; + break; + } CXCursor C = { K, 0, { Parent, S, TU } }; diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h index c61f6cdb2c..2668db5479 100644 --- a/tools/libclang/RecursiveASTVisitor.h +++ b/tools/libclang/RecursiveASTVisitor.h @@ -27,6 +27,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenMP.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -404,6 +405,10 @@ private: bool TraverseDeclContextHelper(DeclContext *DC); bool TraverseFunctionHelper(FunctionDecl *D); bool TraverseVarHelper(VarDecl *D); + bool TraverseOMPClause(OMPClause *C); +#define OPENMP_CLAUSE(Name, Class) \ + bool Visit##Class(Class *C); +#include "clang/Basic/OpenMPKinds.def" typedef SmallVector StmtsTy; typedef SmallVector QueuesTy; @@ -2202,6 +2207,47 @@ DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { }) // Traverse OpenCL: AsType, Convert. DEF_TRAVERSE_STMT(AsTypeExpr, { }) +// OpenMP directives. +DEF_TRAVERSE_STMT(OMPParallelDirective, { + ArrayRef Clauses = S->clauses(); + for (ArrayRef::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) + if (!TraverseOMPClause(*I)) return false; +}) + +// OpenMP clauses. +template +bool RecursiveASTVisitor::TraverseOMPClause(OMPClause *C) { + if (!C) return true; + switch (C->getClauseKind()) { +#define OPENMP_CLAUSE(Name, Class) \ + case OMPC_##Name: \ + return getDerived().Visit##Class(static_cast(C)); +#include "clang/Basic/OpenMPKinds.def" + default: break; + } + return true; +} + +template +bool RecursiveASTVisitor::VisitOMPDefaultClause(OMPDefaultClause *C) { + return true; +} + +#define PROCESS_OMP_CLAUSE_LIST(Class, Node) \ + for (OMPVarList::varlist_iterator I = Node->varlist_begin(), \ + E = Node->varlist_end(); \ + I != E; ++I) \ + TraverseStmt(*I); + +template +bool RecursiveASTVisitor::VisitOMPPrivateClause(OMPPrivateClause *C) { + PROCESS_OMP_CLAUSE_LIST(OMPPrivateClause, C) + return true; +} + +#undef PROCESS_OMP_CLAUSE_LIST + // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods // returning decls or qualtypes or nestednamespecifier -- though I'm